From 7583d4f618f51f5f53993659f18bcd4080b31ddc Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Wed, 5 Feb 2025 09:05:55 +0000 Subject: [PATCH 1/6] Added initial assertione methods for moduledef --- src/DistIL.Testing/DistIL.Testing.csproj | 28 +++++++++++++++++++ src/DistIL.Testing/ModuleAssertions.cs | 35 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/DistIL.Testing/DistIL.Testing.csproj create mode 100644 src/DistIL.Testing/ModuleAssertions.cs diff --git a/src/DistIL.Testing/DistIL.Testing.csproj b/src/DistIL.Testing/DistIL.Testing.csproj new file mode 100644 index 0000000..6a94274 --- /dev/null +++ b/src/DistIL.Testing/DistIL.Testing.csproj @@ -0,0 +1,28 @@ + + + + true + DistIL.Testing + Testing suite for DistIL + + true + + CS1591;CS1573 + + true + snupkg + + true + true + + + + + + + + + + + + diff --git a/src/DistIL.Testing/ModuleAssertions.cs b/src/DistIL.Testing/ModuleAssertions.cs new file mode 100644 index 0000000..df45e93 --- /dev/null +++ b/src/DistIL.Testing/ModuleAssertions.cs @@ -0,0 +1,35 @@ +using DistIL.AsmIO; + +using Shouldly; + +namespace DistIL.Testing; + +[ShouldlyMethods] +public static class ModuleAssertions +{ + public static void ShouldHaveName(this ModuleDef module, string name) + { + module.AsmName.Name.ShouldBe(name); + } + + public static void ShouldHaveVersion(this ModuleDef module, Version version) + { + module.AsmName.Version.ShouldBe(version); + } + + public static void ShouldHaveCustomAttribute(this ModuleDef module, string fullname, bool forAssembly = true) + { + module.GetCustomAttribs(forAssembly).Any(ca => $"{ca.Type.Namespace}.{ca.Type.Name}" == fullname).ShouldBeTrue(); + } + + public static void ShouldHaveCustomAttribute(this ModuleDef module, bool forAssembly = true) + where TAttribute : Attribute + { + module.ShouldHaveCustomAttribute(typeof(TAttribute)!.FullName!, forAssembly); + } + + public static void ShouldContainType(this ModuleDef module, string ns, string name, bool includeExports = true) + { + module.FindType(ns, name, includeExports, throwIfNotFound: true).ShouldNotBeNull(); + } +} From d6695cbe361cf7c01b7fcb0501017f941bd92824 Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Wed, 5 Feb 2025 09:35:29 +0000 Subject: [PATCH 2/6] Added Assertions For Entities --- src/DistIL.Testing/ModuleEntityAssertions.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/DistIL.Testing/ModuleEntityAssertions.cs diff --git a/src/DistIL.Testing/ModuleEntityAssertions.cs b/src/DistIL.Testing/ModuleEntityAssertions.cs new file mode 100644 index 0000000..6c80a40 --- /dev/null +++ b/src/DistIL.Testing/ModuleEntityAssertions.cs @@ -0,0 +1,20 @@ +using DistIL.AsmIO; + +using Shouldly; + +namespace DistIL.Testing; + +[ShouldlyMethods] +public static class ModuleEntityAssertions +{ + public static void ShouldHaveCustomAttribute(this ModuleEntity entity, string fullname) + { + entity.GetCustomAttribs(true).Any(ca => $"{ca.Type.Namespace}.{ca.Type.Name}" == fullname).ShouldBeTrue(); + } + + public static void ShouldHaveCustomAttribute(this ModuleEntity entity) + where TAttribute : Attribute + { + entity.ShouldHaveCustomAttribute(typeof(TAttribute)!.FullName!); + } +} \ No newline at end of file From 40525b09ac82b6b1f0e7a38a0d725e48ea51e16c Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Wed, 5 Feb 2025 09:35:53 +0000 Subject: [PATCH 3/6] Added more assertions --- src/DistIL.Testing/ModuleAssertions.cs | 11 +++ src/DistIL.Testing/TypeAssertions.cs | 108 +++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/DistIL.Testing/TypeAssertions.cs diff --git a/src/DistIL.Testing/ModuleAssertions.cs b/src/DistIL.Testing/ModuleAssertions.cs index df45e93..1fe4391 100644 --- a/src/DistIL.Testing/ModuleAssertions.cs +++ b/src/DistIL.Testing/ModuleAssertions.cs @@ -32,4 +32,15 @@ public static void ShouldContainType(this ModuleDef module, string ns, string na { module.FindType(ns, name, includeExports, throwIfNotFound: true).ShouldNotBeNull(); } + + public static void ShouldNotContainType(this ModuleDef module, string ns, string name, bool includeExports = true) + { + module.FindType(ns, name, includeExports, throwIfNotFound: false).ShouldBeNull(); + } + + public static void ShouldTargetRuntimeVersion(this ModuleDef module, string version) + { + module.GetCustomAttribs(true).FirstOrDefault(a => a.Type.Namespace == "System.Runtime.Versioning" && a.Type.Name == "TargetFrameworkAttribute")? + .Args[0].ShouldBe(".NETCoreApp,Version=v" + version); + } } diff --git a/src/DistIL.Testing/TypeAssertions.cs b/src/DistIL.Testing/TypeAssertions.cs new file mode 100644 index 0000000..3c75d46 --- /dev/null +++ b/src/DistIL.Testing/TypeAssertions.cs @@ -0,0 +1,108 @@ +using System.Reflection; + +using DistIL.AsmIO; + +using Shouldly; + +namespace DistIL.Testing; + +[ShouldlyMethods] +public static class TypeAssertions +{ + public static void ShouldHaveName(this TypeDef type, string name) + { + type.Name.ShouldBe(name); + } + + public static void ShouldHaveNamespace(this TypeDef type, string ns) + { + type.Namespace.ShouldBe(ns); + } + + public static void ShouldHaveBaseType(this TypeDef type, string ns, string name) + { + type.BaseType.ShouldNotBeNull(); + type.BaseType!.Namespace.ShouldBe(ns); + type.BaseType!.Name.ShouldBe(name); + } + + public static void ShouldBeEnum(this TypeDef type) + { + type.IsEnum.ShouldBeTrue(); + } + + public static void ShouldBeClass(this TypeDef type) + { + type.IsClass.ShouldBeTrue(); + } + + public static void ShouldBeInterface(this TypeDef type) + { + type.IsInterface.ShouldBeTrue(); + } + + public static void ShouldBeValueType(this TypeDef type) + { + type.IsValueType.ShouldBeTrue(); + } + + public static void ShouldBeAbstract(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.Abstract).ShouldBeTrue(); + } + + public static void ShouldBeSealed(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.Sealed).ShouldBeTrue(); + } + + public static void ShouldBePublic(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.Public).ShouldBeTrue(); + } + + public static void ShouldBePrivate(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.NotPublic).ShouldBeTrue(); + } + + public static void ShouldBeInternal(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.NestedAssembly).ShouldBeTrue(); + } + + public static void ShouldBeProtected(this TypeDef type) + { + type.Attribs.HasFlag(TypeAttributes.NestedFamily).ShouldBeTrue(); + } + + public static void ShouldImplement(this TypeDef type, string ns, string name) + { + type.Interfaces.ShouldContain(i => i.Namespace == ns && i.Name == name); + } + + public static void ShouldImplement(this TypeDef type) + { + type.Interfaces.ShouldContain(i => i.Namespace == typeof(T).Namespace && i.Name == typeof(T).Name); + } + + public static void ShouldHaveField(this TypeDef type, string name, string fieldType) + { + type.Fields.ShouldContain(f => f.Name == name && f.Type.Namespace == fieldType); + } + + public static void ShouldHaveProperty(this TypeDef type, string name) + { + type.Properties.ShouldContain(p => p.Name == name); + } + + public static void ShouldHaveMethod(this TypeDef type, string name) + { + type.Methods.ShouldContain(m => m.Name == name); + } + + public static void ShouldHaveMethod(this TypeDef type, string name, string returnType) + { + type.Methods.ShouldContain(m => m.Name == name && m.ReturnType.Namespace == returnType); + } +} From 31b408ccbcd2a9cab70c732d4ec0da34b1c10316 Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Wed, 5 Feb 2025 12:22:17 +0000 Subject: [PATCH 4/6] Add more assertions --- DistIL.sln | 9 +++++++++ src/DistIL.Testing/TypeAssertions.cs | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/DistIL.sln b/DistIL.sln index 86cb745..d2870a3 100644 --- a/DistIL.sln +++ b/DistIL.sln @@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PracticeTests", "tests\Prac EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "tests\Benchmarks\Benchmarks.csproj", "{3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A01909E9-4D4F-45C9-83C3-420F935E993A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistIL.Testing", "src\DistIL.Testing\DistIL.Testing.csproj", "{D3E25BCB-E6EC-436A-8BA1-269BFB248764}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,6 +51,10 @@ Global {3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F}.Release|Any CPU.Build.0 = Release|Any CPU + {D3E25BCB-E6EC-436A-8BA1-269BFB248764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3E25BCB-E6EC-436A-8BA1-269BFB248764}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3E25BCB-E6EC-436A-8BA1-269BFB248764}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3E25BCB-E6EC-436A-8BA1-269BFB248764}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -57,5 +65,6 @@ Global GlobalSection(NestedProjects) = preSolution {E83F916A-91B0-4252-80A4-5074CA09B7AB} = {9241028A-5061-46F3-BFE5-14DF6987C6E3} {3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F} = {9241028A-5061-46F3-BFE5-14DF6987C6E3} + {D3E25BCB-E6EC-436A-8BA1-269BFB248764} = {A01909E9-4D4F-45C9-83C3-420F935E993A} EndGlobalSection EndGlobal diff --git a/src/DistIL.Testing/TypeAssertions.cs b/src/DistIL.Testing/TypeAssertions.cs index 3c75d46..9b3a187 100644 --- a/src/DistIL.Testing/TypeAssertions.cs +++ b/src/DistIL.Testing/TypeAssertions.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using DistIL.AsmIO; @@ -31,6 +32,12 @@ public static void ShouldBeEnum(this TypeDef type) type.IsEnum.ShouldBeTrue(); } + public static void ShouldBeEnumWithFlags(this TypeDef type) + { + type.IsEnum.ShouldBeTrue(); + type.HasCustomAttrib(typeof(FlagsAttribute)); + } + public static void ShouldBeClass(this TypeDef type) { type.IsClass.ShouldBeTrue(); @@ -104,5 +111,5 @@ public static void ShouldHaveMethod(this TypeDef type, string name) public static void ShouldHaveMethod(this TypeDef type, string name, string returnType) { type.Methods.ShouldContain(m => m.Name == name && m.ReturnType.Namespace == returnType); - } + } } From 1ae14fc4fc44c988f7ec4ba1ed6d8fe0750b893f Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Wed, 5 Feb 2025 15:29:43 +0100 Subject: [PATCH 5/6] Cleanup --- DistIL.sln | 3 --- 1 file changed, 3 deletions(-) diff --git a/DistIL.sln b/DistIL.sln index d2870a3..5244d34 100644 --- a/DistIL.sln +++ b/DistIL.sln @@ -17,8 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PracticeTests", "tests\Prac EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "tests\Benchmarks\Benchmarks.csproj", "{3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A01909E9-4D4F-45C9-83C3-420F935E993A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistIL.Testing", "src\DistIL.Testing\DistIL.Testing.csproj", "{D3E25BCB-E6EC-436A-8BA1-269BFB248764}" EndProject Global @@ -65,6 +63,5 @@ Global GlobalSection(NestedProjects) = preSolution {E83F916A-91B0-4252-80A4-5074CA09B7AB} = {9241028A-5061-46F3-BFE5-14DF6987C6E3} {3CE5B206-AEC2-4A18-9ECF-8DAF17CB893F} = {9241028A-5061-46F3-BFE5-14DF6987C6E3} - {D3E25BCB-E6EC-436A-8BA1-269BFB248764} = {A01909E9-4D4F-45C9-83C3-420F935E993A} EndGlobalSection EndGlobal From 65e60e2d92822a5b9371648bb5f5a95e5ad79bb5 Mon Sep 17 00:00:00 2001 From: Chris Anders Date: Thu, 6 Feb 2025 18:41:04 +0100 Subject: [PATCH 6/6] Added more assertion --- src/DistIL.Testing/TypeAssertions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/DistIL.Testing/TypeAssertions.cs b/src/DistIL.Testing/TypeAssertions.cs index 9b3a187..f3d5e0b 100644 --- a/src/DistIL.Testing/TypeAssertions.cs +++ b/src/DistIL.Testing/TypeAssertions.cs @@ -112,4 +112,9 @@ public static void ShouldHaveMethod(this TypeDef type, string name, string retur { type.Methods.ShouldContain(m => m.Name == name && m.ReturnType.Namespace == returnType); } + + public static void ShouldHaveEvent(this TypeDef type, string name) + { + type.Events.ShouldContain(e => e.Name == name); + } }