public void When_field_in_nested_class_is_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace TestSystem { public class Outer { private class Inner { public int? Value; } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("F:TestSystem.Outer.Inner.Value") .CanBeNull())) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_base_property_inherits_item_annotation_from_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable).Namespace) .InGlobalScope(@" namespace N { public interface I { [ItemNotNull] IEnumerable P { get; set; } } public class B : I { public virtual IEnumerable P { get; set; } } public class C : B { public override IEnumerable P { get; set; } } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_attributes_are_public_in_external_assembly_it_must_add_namespace_import() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .WithoutNullabilityAttributes() .WithReferenceToExternalAssemblyFor(@" using System; namespace OtherAssembly { public class NotNullAttribute : Attribute { } public class CanBeNullAttribute : Attribute { } public class ItemNotNullAttribute : Attribute { } public class ItemCanBeNullAttribute : Attribute { } }") .InGlobalScope(@" class C { <annotate/> int? [|f|]; } ") .ExpectingImportForNamespace("OtherAssembly") .Build(); // Act and assert VerifyNullabilityFix(source, CreateMessageForField("f")); }
When_parameter_in_implicit_interface_implementation_is_effectively_annotated_through_annotation_on_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" interface I { void M([ItemNotNull] IEnumerable<string> p); } class C : I { // implicitly inherits decoration from interface void I.M(IEnumerable<string> p) { } // requires explicit decoration public void M([ItemNotNull] IEnumerable<string> p) { } // unrelated overload public void M([ItemNotNull] IEnumerable<object> p) { } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_property_in_base_class_is_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" class B { [ItemNotNull] public virtual IEnumerable<string> P { get; set; } } class D1 : B { } class D2 : D1 { // implicitly inherits decoration from base class public override IEnumerable<string> P { get; set; } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_deriving_constructed_arrays_from_externally_annotated_class_with_open_array_types_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" public abstract class B<T> { public abstract T[] P { get; } public abstract T[] M(T[] p, int i); } public class D : B<string> { public override string[] P { get { throw new NotImplementedException(); } } public override string[] M(string[] p, int i) { throw new NotImplementedException(); } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("P:B`1.P") .NotNull()) .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:B`1.M(`0[],System.Int32)") .NotNull() .WithParameter(new ExternalAnnotationParameterBuilder() .Named("p") .NotNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_indexer_parameter_in_base_class_is_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" abstract class B { public abstract int this[[ItemNotNull] IEnumerable<string> p] { get; set; } } abstract class D1 : B { } class D2 : D1 { // implicitly inherits decoration from base class public override int this[IEnumerable<string> p] { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_override_breaks_inheritance_it_must_be_reported_and_fixed() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" namespace N { public class B { [ItemNotNull] public virtual IEnumerable<int?> M() { throw new NotImplementedException(); } } public class C : B { <annotate/> public new IEnumerable<int?> [|M|]() { throw new NotImplementedException(); } } } ") .Build(); // Act and assert VerifyNullabilityFix(source, CreateMessageForMethod("M")); }
public void When_parameter_in_base_class_is_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { class B { public virtual void M(string p) { } } class D1 : B { } class D2 : D1 { // implicitly inherits decoration from base class public override void M(string p) { } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:N.B.M(System.String)") .WithParameter(new ExternalAnnotationParameterBuilder() .Named("p") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_return_value_in_base_class_is_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IList <>).Namespace) .InGlobalScope(@" class B { [ItemNotNull] public virtual IList<string> M() { throw new NotImplementedException(); } } class D1 : B { } class D2 : D1 { // implicitly inherits decoration from base class public override IList<string> M() { throw new NotImplementedException(); } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_return_value_in_implicit_interface_is_not_annotated_with_explicit_interface_it_must_be_reported_and_fixed() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IList <>).Namespace) .InGlobalScope(@" interface I { [ItemNotNull] IList<string> M(); } class C : I { // implicitly inherits decoration from interface IList<string> I.M() { throw new NotImplementedException(); } <annotate/> public IList<string> [|M|]() { throw new NotImplementedException(); } } ") .Build(); // Act and assert VerifyNullabilityFix(source, CreateMessageForMethod("M")); }
public void When_method_is_lambda_named_by_compiler_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" class C1 { private void Test() { C2.M( () => // no syntax exists to decorate this lambda expression { throw new NotImplementedException(); }); } } public class C2 { public static void M([ItemNotNull] Func<IEnumerable<int?>> callback) { } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_generic_parameters_in_method_of_generic_class_are_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace SystemCollections { public class Dictionary<TKey, TValue> { public void Add(TKey key, TValue value) { throw new NotImplementedException(); } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:SystemCollections.Dictionary`2.Add(`0,`1)") .WithParameter(new ExternalAnnotationParameterBuilder() .Named("key") .CanBeNull()) .WithParameter(new ExternalAnnotationParameterBuilder() .Named("value") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_variable_length_parameter_in_method_is_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace TestSystem { public class StringFormatter { public static string Format(IFormatProvider provider, string format, params object[] args) { throw new NotImplementedException(); } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named( "M:TestSystem.StringFormatter.Format(System.IFormatProvider,System.String,System.Object[])") .NotNull() .WithParameter(new ExternalAnnotationParameterBuilder() .Named("provider") .CanBeNull()) .WithParameter(new ExternalAnnotationParameterBuilder() .Named("format") .CanBeNull()) .WithParameter(new ExternalAnnotationParameterBuilder() .Named("args") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_return_value_in_implicit_interface_is_annotated_with_externally_annotated_explicit_interface_it_must_be_skipped () { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { interface I { string M(); } class C : I { // implicitly inherits decoration from interface string I.M() { throw new NotImplementedException(); } // requires explicit decoration [NotNull] public string M() { throw new NotImplementedException(); } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:N.I.M") .CanBeNull())) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_indexer_parameter_in_implicit_interface_implementation_is_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { interface I { int this[string p] { get; set; } } class C : I { // implicitly inherits decoration from interface public int this[string p] { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("P:N.I.Item(System.String)") .WithParameter(new ExternalAnnotationParameterBuilder() .Named("p") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_base_method_inherits_annotation_from_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { public interface I { [NotNull] string M(); } public class B : I { public virtual string M() { throw new NotImplementedException(); } } public class C : B { public override string M() { throw new NotImplementedException(); } } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_parameter_in_implicit_interface_implementation_is_not_externally_annotated_it_must_be_reported_and_fixed() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { interface I { void M(string p); } class C : I { // implicitly inherits decoration from interface void I.M(string p) { } public void M(<annotate/> string [|p|]) { } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:N.I.M(System.String)") .WithParameter(new ExternalAnnotationParameterBuilder() .Named("p") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityFix(source, CreateMessageForParameter("p")); }
When_parameter_in_nongeneric_class_that_derives_from_generic_base_class_that_implements_annotated_generic_interface_it_must_be_skipped () { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" public interface IErrorDemoInterface<T> { void DoSomething([NotNull] T text); } public class ErrorDemoBase<T> : IErrorDemoInterface<T> { public virtual void DoSomething(T text) { } } public class ErrorDemo : ErrorDemoBase<string> { public override void DoSomething(string text) { } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_parameter_in_implicit_interface_implementation_is_effectively_annotated_through_external_annotation_on_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { interface I { void M(string p); } class C : I { // implicitly inherits decoration from interface void I.M(string p) { } // requires explicit decoration public void M([NotNull] string p) { } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:N.I.M(System.String)") .WithParameter(new ExternalAnnotationParameterBuilder() .Named("p") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_parameter_in_implicit_interface_implementation_is_not_annotated_it_must_be_reported_and_fixed() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" interface I { void M([ItemNotNull] IEnumerable<string> p); } class C : I { // implicitly inherits decoration from interface void I.M(IEnumerable<string> p) { } public void M(<annotate/> IEnumerable<string> [|p|]) { } // unrelated overload public void M([ItemNotNull] IEnumerable<object> p) { } } ") .Build(); // Act and assert VerifyNullabilityFix(source, CreateMessageForParameter("p")); }
public void When_method_is_anonymous_named_by_compiler_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" class C1 { private void Test() { C2.M(delegate // no syntax exists to decorate this anonymous method { throw new NotImplementedException(); }); } } public class C2 { public static void M([NotNull] Func<int?> callback) { } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_base_parameter_inherits_item_annotation_from_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(List <>).Namespace) .InGlobalScope(@" namespace N { public interface I { void M([ItemNotNull] List<string> p); } public class B : I { public virtual void M(List<string> p) { } } public class C : B { public override void M(List<string> p) { } } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_return_value_in_base_class_is_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" namespace N { class B { public virtual string M() { throw new NotImplementedException(); } } class D1 : B { } class D2 : D1 { // implicitly inherits decoration from base class public override string M() { throw new NotImplementedException(); } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named("M:N.B.M") .NotNull())) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_property_in_implicit_interface_is_not_annotated_with_explicit_interface_it_must_be_reported_and_fixed() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" interface I { [ItemNotNull] IEnumerable<string> P { get; set; } } class C : I { // implicitly inherits decoration from interface IEnumerable<string> I.P { get; set; } <annotate/> public IEnumerable<string> [|P|] { get; set; } } ") .Build(); // Act and assert VerifyNullabilityFix(source); }
When_return_value_in_implicit_interface_is_not_annotated_with_explicit_interface_it_must_be_reported_and_fixed () { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" interface I { [NotNull] string M(); } class C : I { // implicitly inherits decoration from interface string I.M() { throw new NotImplementedException(); } <annotate/> public string [|M|]() { throw new NotImplementedException(); } } ") .Build(); // Act and assert VerifyNullabilityFix(source); }
public void When_override_breaks_inheritance_it_must_be_reported() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" namespace N { public class B { [ItemNotNull] public virtual IEnumerable<int?> P { get; set; } } public class C : B { <annotate/> public new IEnumerable<int?> [|P|] { get; set; } } } ") .Build(); // Act and assert VerifyNullabilityFix(source); }
public void When_return_value_in_implicit_interface_is_annotated_with_explicit_interface_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .InGlobalScope(@" interface I { [NotNull] string M(); } class C : I { // implicitly inherits decoration from interface string I.M() { throw new NotImplementedException(); } // requires explicit decoration [NotNull] public string M() { throw new NotImplementedException(); } } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
public void When_attributes_are_internal_in_external_assembly_they_must_not_be_found() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .WithoutNullabilityAttributes() .WithReferenceToExternalAssemblyFor(@" using System; namespace OtherAssembly { internal class NotNullAttribute : Attribute { } internal class CanBeNullAttribute : Attribute { } internal class ItemNotNullAttribute : Attribute { } internal class ItemCanBeNullAttribute : Attribute { } }") .InGlobalScope(@" class C { int? f; } ") .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }
When_generic_parameters_in_generic_method_of_nongeneric_class_are_externally_annotated_it_must_be_skipped() { // Arrange ParsedSourceCode source = new ClassSourceCodeBuilder() .Using(typeof(IEnumerable <>).Namespace) .InGlobalScope(@" namespace SystemCollections { public static class Enumerable { public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector) { throw new NotImplementedException(); } } } ") .ExternallyAnnotated(new ExternalAnnotationsBuilder() .IncludingMember(new ExternalAnnotationFragmentBuilder() .Named( "M:SystemCollections.Enumerable.SelectMany``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.Collections.Generic.IEnumerable{``1}})") .NotNull() .WithParameter(new ExternalAnnotationParameterBuilder() .Named("source") .CanBeNull()) .WithParameter(new ExternalAnnotationParameterBuilder() .Named("selector") .CanBeNull()))) .Build(); // Act and assert VerifyNullabilityDiagnostic(source); }