Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ private void ThrowMultipleAttributesException(string attributeName)
throw new TypeInspectionException(errorMessage);
}

[DoesNotReturn]
private void ThrowMultipleClassAttributesException(string attributeName)
{
// Note: even if the given attribute has AllowMultiple = false, we can
// still reach here if a derived attribute authored by the user re-defines AttributeUsage
string errorMessage = string.Format(
CultureInfo.CurrentCulture,
Resource.UTA_MultipleAttributesOnTestClass,
Parent.ClassType.FullName,
attributeName);
throw new TypeInspectionException(errorMessage);
}

/// <summary>
/// Execute test without timeout.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,23 +174,60 @@ private TestMethodAttribute GetTestMethodAttribute()
}

/// <summary>
/// Gets the number of retries this test method should make in case of failure.
/// Resolves the retry attribute that applies to this test method, considering both
/// method-level and class-level <see cref="RetryBaseAttribute"/> attributes.
/// </summary>
/// <remarks>
/// A method-level retry attribute fully overrides any class-level retry attribute.
/// Class-level retry attributes are always validated (even when the method has its own
/// retry) so that misuse on the test class is reported regardless of method overrides.
/// </remarks>
/// <returns>
/// The number of retries, which is always greater than or equal to 1.
/// If RetryAttribute is not present, returns 1.
/// The resolved <see cref="RetryBaseAttribute"/>, or <see langword="null"/> if neither
/// the method nor the declaring class is decorated.
/// </returns>
private RetryBaseAttribute? GetRetryAttribute()
{
Attribute[] attributes = PlatformServiceProvider.Instance.ReflectionOperations.GetCustomAttributesCached(MethodInfo);
RetryBaseAttribute? methodRetry = GetSingleRetryAttribute(
PlatformServiceProvider.Instance.ReflectionOperations.GetCustomAttributesCached(MethodInfo),
RetryAttributeScope.Method);

// Always scan the class as well so a misuse there (multiple class-level retry
// attributes) is reported even when the method has its own retry override.
RetryBaseAttribute? classRetry = GetSingleRetryAttribute(
PlatformServiceProvider.Instance.ReflectionOperations.GetCustomAttributesCached(Parent.ClassType),
RetryAttributeScope.Class);

// Method-level retry fully overrides class-level retry when present.
return methodRetry ?? classRetry;
Comment thread
Evangelink marked this conversation as resolved.
}

Comment thread
Evangelink marked this conversation as resolved.
/// <summary>
/// Returns the single <see cref="RetryBaseAttribute"/> found in <paramref name="attributes"/>,
/// or <see langword="null"/> if none is present.
/// </summary>
/// <param name="attributes">The attribute set to scan (method-level or class-level).</param>
/// <param name="scope">Indicates whether <paramref name="attributes"/> comes from a method or a class; only used to pick the right error message when more than one retry attribute is found.</param>
/// <exception cref="ObjectModel.TypeInspectionException">
/// Thrown when <paramref name="attributes"/> contains more than one <see cref="RetryBaseAttribute"/>.
/// </exception>
private RetryBaseAttribute? GetSingleRetryAttribute(Attribute[] attributes, RetryAttributeScope scope)
{
RetryBaseAttribute? result = null;
foreach (Attribute attribute in attributes)
{
if (attribute is RetryBaseAttribute retryAttribute)
{
if (result is not null)
{
ThrowMultipleAttributesException(nameof(RetryBaseAttribute));
if (scope == RetryAttributeScope.Class)
{
ThrowMultipleClassAttributesException(nameof(RetryBaseAttribute));
}
else
{
ThrowMultipleAttributesException(nameof(RetryBaseAttribute));
}
}

result = retryAttribute;
Expand All @@ -199,4 +236,10 @@ private TestMethodAttribute GetTestMethodAttribute()

return result;
}

private enum RetryAttributeScope
{
Method,
Class,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ but received {4} argument(s), with types '{5}'.</value>
<data name="UTA_MultipleAttributesOnTestMethod" xml:space="preserve">
<value>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</value>
</data>
<data name="UTA_MultipleAttributesOnTestClass" xml:space="preserve">
<value>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</value>
</data>
<data name="UTA_NoTestResult" xml:space="preserve">
<value>Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ byl však přijat tento počet argumentů: {4} s typy {5}.</target>
<target state="translated">Metoda {0}.{1} neexistuje.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">Testovací metoda {0}.{1} má definovaných více atributů odvozených od atributu {2}. Povolený je jenom jeden takový atribut.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ aber empfing {4} Argument(e) mit den Typen „{5}“.</target>
<target state="translated">Die Methode "{0}.{1}" ist nicht vorhanden.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">Für die Testmethode „{0}.{1}“ sind mehrere Attribute definiert, die von „{2}“ abgeleitet sind. Nur ein einziges solches Attribut ist zulässig.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ pero recibió {4} argumentos, con los tipos '{5}'.</target>
<target state="translated">El método {0}.{1} no existe.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">El método de prueba '{0}.{1}' tiene varios atributos derivados de '{2}' definidos en él. Solo se permite un atributo de este tipo.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ mais a reçu {4} argument(s), avec les types « {5} ».</target>
<target state="translated">La méthode {0}.{1} n'existe pas.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">La méthode de test « {0}.{1} » possède plusieurs attributs dérivés de « {2} » qui lui sont définis. Un seul attribut de ce type est autorisé.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ ma ha ricevuto {4} argomenti, con tipi '{5}'.</target>
<target state="translated">Il metodo {0}.{1} non esiste.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">Il metodo di test '{0}.{1}' contiene più attributi derivati da '{2}' definito in esso. È consentito solo uno di tali attributi.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ but received {4} argument(s), with types '{5}'.</source>
<target state="translated">メソッド {0}.{1} は存在しません。</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">テスト メソッド '{0}.{1}' には、 '{2}' から派生した属性が複数定義されています。このような属性は 1 つしか許可されません。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ but received {4} argument(s), with types '{5}'.</source>
<target state="translated">{0}.{1} 메서드가 없습니다.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">테스트 메서드 '{0}.{1}'에 {2}에서 파생된 여러 특성이 정의되어 있습니다. 이러한 특성은 하나만 허용됩니다.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ ale odebrał argumenty {4} z typami „{5}”.</target>
<target state="translated">Metoda {0}.{1} nie istnieje.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">Metoda testowa "{0}.{1}” ma zdefiniowanych wiele atrybutów pochodzących z „{2}”. Dozwolony jest tylko jeden taki atrybut.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ mas {4} argumentos recebidos, com tipos '{5}'.</target>
<target state="translated">O método {0}.{1} não existe.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">O método de teste '{0}.{1}' tem várias características derivadas de '{2}' definidas nele. Apenas uma dessas características tem permissão.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ but received {4} argument(s), with types '{5}'.</source>
<target state="translated">Метод {0}.{1} не существует.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">У метода тестирования "{0}.{1}" есть несколько атрибутов, производных от заданного в нем "{2}". Допускается только один такой атрибут.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ ancak, '{5}' türünde {4} bağımsız değişken aldı.</target>
<target state="translated">{0}.{1} metodu yok.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">“{0}.{1}” test yöntemi, üzerinde tanımlanan “{2}” öğesinden türetilmiş birden fazla öznitelik içeriyor. Bu türde yalnızca bir tane özniteliğe izin verilir.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ but received {4} argument(s), with types '{5}'.</source>
<target state="translated">方法 {0}.{1} 不存在。</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">测试方法“{0}.{1}”具有多个在其上定义的“{2}”的派生属性。仅允许一个此类属性。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ but received {4} argument(s), with types '{5}'.</source>
<target state="translated">方法 {0}.{1} 不存在。</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestClass">
<source>The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</source>
<target state="new">The test class '{0}' has multiple attributes derived from '{1}' defined on it. Only one such attribute is allowed.</target>
<note />
</trans-unit>
<trans-unit id="UTA_MultipleAttributesOnTestMethod">
<source>The test method '{0}.{1}' has multiple attributes derived from '{2}' defined on it. Only one such attribute is allowed.</source>
<target state="translated">測試方法 '{0}.{1}' 具有多個衍生自 '{2}' 的屬性根據其定義。只允許一個此類屬性。</target>
Expand Down
4 changes: 2 additions & 2 deletions src/Analyzers/MSTest.Analyzers/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -583,10 +583,10 @@ The type declaring these methods should also respect the following rules:
<value>Do not duplicate 'DataRow' attributes. This is usually a copy/paste error. The attribute indices are '{0}' and '{1}'.</value>
</data>
<data name="UseRetryWithTestMethodTitle" xml:space="preserve">
<value>Use retry attribute on test method</value>
<value>Use retry attribute on test method or test class</value>
</data>
<data name="UseRetryWithTestMethodMessageFormat" xml:space="preserve">
<value>An attribute that derives from 'RetryBaseAttribute' can be specified only on a test method</value>
<value>An attribute that derives from 'RetryBaseAttribute' can be specified only on a test method or a test class</value>
</data>
<data name="PreferTestMethodOverDataTestMethodAnalyzerTitle" xml:space="preserve">
<value>Prefer 'TestMethod' over 'DataTestMethod'</value>
Expand Down
Loading