Skip to content

Commit 8997b7e

Browse files
committed
Add unit tests for multiple attributes
1 parent 8e75139 commit 8997b7e

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests/Test_UsePartialPropertyForObservablePropertyCodeFixer.cs

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,4 +767,232 @@ public void M()
767767

768768
await test.RunAsync();
769769
}
770+
771+
[TestMethod]
772+
public async Task SimpleFields_WithMultipleAttributes_SingleProperty()
773+
{
774+
string original = """
775+
using System;
776+
using CommunityToolkit.Mvvm.ComponentModel;
777+
778+
public partial class Class1 : ObservableObject
779+
{
780+
[ObservableProperty, NotifyPropertyChangedFor("Age")] private string name = String.Empty;
781+
}
782+
""";
783+
784+
string @fixed = """
785+
using System;
786+
using CommunityToolkit.Mvvm.ComponentModel;
787+
788+
public partial class Class1 : ObservableObject
789+
{
790+
[ObservableProperty, NotifyPropertyChangedFor("Age")]
791+
public partial string Name { get; set; } = String.Empty;
792+
}
793+
""";
794+
795+
CSharpCodeFixTest test = new(LanguageVersion.Preview)
796+
{
797+
TestCode = original,
798+
FixedCode = @fixed,
799+
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
800+
};
801+
802+
test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
803+
test.ExpectedDiagnostics.AddRange(new[]
804+
{
805+
// /0/Test0.cs(6,74): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
806+
CSharpCodeFixVerifier.Diagnostic().WithSpan(6, 74, 6, 78).WithArguments("Class1", "name"),
807+
});
808+
809+
test.FixedState.ExpectedDiagnostics.AddRange(new[]
810+
{
811+
// /0/Test0.cs(7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
812+
DiagnosticResult.CompilerError("CS8050").WithSpan(7, 27, 7, 31),
813+
814+
// /0/Test0.cs(7,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
815+
DiagnosticResult.CompilerError("CS9248").WithSpan(7, 27, 7, 31).WithArguments("Class1.Name"),
816+
});
817+
818+
await test.RunAsync();
819+
}
820+
821+
// See https://github.com/CommunityToolkit/dotnet/issues/1007
822+
[TestMethod]
823+
public async Task SimpleFields_WithMultipleAttributes_WithNoBlankLines()
824+
{
825+
string original = """
826+
using System;
827+
using CommunityToolkit.Mvvm.ComponentModel;
828+
829+
public partial class Class1 : ObservableObject
830+
{
831+
[ObservableProperty, NotifyPropertyChangedFor("Age")] private string name = String.Empty;
832+
[ObservableProperty] private int age;
833+
}
834+
""";
835+
836+
string @fixed = """
837+
using System;
838+
using CommunityToolkit.Mvvm.ComponentModel;
839+
840+
public partial class Class1 : ObservableObject
841+
{
842+
[ObservableProperty, NotifyPropertyChangedFor("Age")]
843+
public partial string Name { get; set; } = String.Empty;
844+
845+
[ObservableProperty]
846+
public partial int Age { get; set; }
847+
}
848+
""";
849+
850+
CSharpCodeFixTest test = new(LanguageVersion.Preview)
851+
{
852+
TestCode = original,
853+
FixedCode = @fixed,
854+
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
855+
};
856+
857+
test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
858+
test.ExpectedDiagnostics.AddRange(new[]
859+
{
860+
// /0/Test0.cs(6,74): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
861+
CSharpCodeFixVerifier.Diagnostic().WithSpan(6, 74, 6, 78).WithArguments("Class1", "name"),
862+
863+
// /0/Test0.cs(7,38): info MVVMTK0042: The field Class1.age using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
864+
CSharpCodeFixVerifier.Diagnostic().WithSpan(7, 38, 7, 41).WithArguments("Class1", "age"),
865+
});
866+
867+
test.FixedState.ExpectedDiagnostics.AddRange(new[]
868+
{
869+
// /0/Test0.cs(7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
870+
DiagnosticResult.CompilerError("CS8050").WithSpan(7, 27, 7, 31),
871+
872+
// /0/Test0.cs(7,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
873+
DiagnosticResult.CompilerError("CS9248").WithSpan(7, 27, 7, 31).WithArguments("Class1.Name"),
874+
875+
// /0/Test0.cs(10,24): error CS9248: Partial property 'Class1.Age' must have an implementation part.
876+
DiagnosticResult.CompilerError("CS9248").WithSpan(10, 24, 10, 27).WithArguments("Class1.Age"),
877+
});
878+
879+
await test.RunAsync();
880+
}
881+
882+
[TestMethod]
883+
public async Task SimpleFields_WithMultipleAttributes_WithMixedBuckets_1()
884+
{
885+
string original = """
886+
using System;
887+
using System.ComponentModel.DataAnnotations;
888+
using CommunityToolkit.Mvvm.ComponentModel;
889+
890+
public partial class Class1 : ObservableObject
891+
{
892+
// Leading trivia
893+
[ObservableProperty, NotifyPropertyChangedFor("A"), Display]
894+
[NotifyPropertyChangedFor("B")]
895+
private string _name;
896+
}
897+
""";
898+
899+
string @fixed = """
900+
using System;
901+
using System.ComponentModel.DataAnnotations;
902+
using CommunityToolkit.Mvvm.ComponentModel;
903+
904+
public partial class Class1 : ObservableObject
905+
{
906+
// Leading trivia
907+
[ObservableProperty, NotifyPropertyChangedFor("A"), Display]
908+
[NotifyPropertyChangedFor("B")]
909+
public partial string Name { get; set; }
910+
}
911+
""";
912+
913+
CSharpCodeFixTest test = new(LanguageVersion.Preview)
914+
{
915+
TestCode = original,
916+
FixedCode = @fixed,
917+
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
918+
};
919+
920+
test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
921+
test.ExpectedDiagnostics.AddRange(new[]
922+
{
923+
// /0/Test0.cs(10,20): info MVVMTK0042: The field Class1._name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
924+
CSharpCodeFixVerifier.Diagnostic().WithSpan(10, 20, 10, 25).WithArguments("Class1", "_name"),
925+
});
926+
927+
test.FixedState.ExpectedDiagnostics.AddRange(new[]
928+
{
929+
// /0/Test0.cs(10,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
930+
DiagnosticResult.CompilerError("CS9248").WithSpan(10, 27, 10, 31).WithArguments("Class1.Name"),
931+
});
932+
933+
await test.RunAsync();
934+
}
935+
936+
[TestMethod]
937+
public async Task SimpleFields_WithMultipleAttributes_WithMixedBuckets_2()
938+
{
939+
string original = """
940+
using System;
941+
using System.ComponentModel.DataAnnotations;
942+
using CommunityToolkit.Mvvm.ComponentModel;
943+
944+
public partial class Class1 : ObservableObject
945+
{
946+
// Leading trivia
947+
[NotifyPropertyChangedFor("B")]
948+
[ObservableProperty, NotifyPropertyChangedFor("A"), Display, Test]
949+
[NotifyPropertyChangedFor("C")]
950+
[property: UIHint("name"), Test]
951+
private string name;
952+
}
953+
954+
public class TestAttribute : Attribute;
955+
""";
956+
957+
string @fixed = """
958+
using System;
959+
using System.ComponentModel.DataAnnotations;
960+
using CommunityToolkit.Mvvm.ComponentModel;
961+
962+
public partial class Class1 : ObservableObject
963+
{
964+
// Leading trivia
965+
[NotifyPropertyChangedFor("B")]
966+
[ObservableProperty, NotifyPropertyChangedFor("A"), Display]
967+
[field: Test]
968+
[NotifyPropertyChangedFor("C")]
969+
[UIHint("name"), Test]
970+
public partial string Name { get; set; }
971+
}
972+
973+
public class TestAttribute : Attribute;
974+
""";
975+
976+
CSharpCodeFixTest test = new(LanguageVersion.Preview)
977+
{
978+
TestCode = original,
979+
FixedCode = @fixed,
980+
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
981+
};
982+
983+
test.TestState.AdditionalReferences.Add(typeof(ObservableObject).Assembly);
984+
test.ExpectedDiagnostics.AddRange(new[]
985+
{
986+
// /0/Test0.cs(12,20): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
987+
CSharpCodeFixVerifier.Diagnostic().WithSpan(12, 20, 12, 24).WithArguments("Class1", "name"),
988+
});
989+
990+
test.FixedState.ExpectedDiagnostics.AddRange(new[]
991+
{
992+
// /0/Test0.cs(13,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
993+
DiagnosticResult.CompilerError("CS9248").WithSpan(13, 27, 13, 31).WithArguments("Class1.Name"),
994+
});
995+
996+
await test.RunAsync();
997+
}
770998
}

0 commit comments

Comments
 (0)