diff --git a/Kr3/Kr3.sln b/Kr3/Kr3.sln new file mode 100644 index 0000000..d6690e4 --- /dev/null +++ b/Kr3/Kr3.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33403.182 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kr3", "Kr3\Kr3.csproj", "{5B9C8390-F227-4F23-81BA-AB1885C1DF32}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsReflector", "TestsReflector\TestsReflector.csproj", "{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Release|Any CPU.Build.0 = Release|Any CPU + {15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B0556365-C55B-4AF6-8ACA-ACBA1E439626} + EndGlobalSection +EndGlobal diff --git a/Kr3/Kr3/Kr3.csproj b/Kr3/Kr3/Kr3.csproj new file mode 100644 index 0000000..424caff --- /dev/null +++ b/Kr3/Kr3/Kr3.csproj @@ -0,0 +1,11 @@ + + + + Exe + net7.0 + enable + enable + Library + + + diff --git a/Kr3/Kr3/Reflector.cs b/Kr3/Kr3/Reflector.cs new file mode 100644 index 0000000..0f90818 --- /dev/null +++ b/Kr3/Kr3/Reflector.cs @@ -0,0 +1,249 @@ +using System.Linq.Expressions; +using System.Reflection; + +namespace Kr3; + +public class Reflector +{ + private readonly string filePath; + + public Reflector(string filePath) => this.filePath = filePath; + + private static string GetVisibilityFromClass(Type someClass) + { + if (someClass.IsNestedPrivate) + { + return "private "; + } + else if (someClass.IsNestedPublic) + { + return "public "; + } + else if (someClass.IsNestedFamily) + { + return "protected "; + } + else if (someClass.IsNestedAssembly) + { + return "internal "; + } + return ""; + } + + private static string GetStaticOrNotFromClass(Type someClass) + { + return someClass.IsAbstract && someClass.IsSealed ? "static " : ""; + } + + private static string GetVisibilityFromField(FieldInfo someField) + { + if (someField.IsPrivate) + { + return "private "; + } + else if (someField.IsPublic) + { + return "public "; + } + else if (someField.IsFamily) + { + return "protected "; + } + else if (someField.IsAssembly) + { + return "internal "; + } + return ""; + } + + private static string GetStaticOrNotFromField(FieldInfo someField) + { + return someField.IsStatic ? "static " : ""; + } + + private static string GetStaticOrNotFromMethod(MethodInfo someMethod) + { + return someMethod.IsStatic ? "static " : ""; + } + + private static string GetVisibilityFromMethod(MethodInfo someMethod) + { + if (someMethod.IsPrivate) + { + return "private "; + } + else if (someMethod.IsPublic) + { + return "public "; + } + else if (someMethod.IsFamily) + { + return "protected "; + } + else if (someMethod.IsAssembly) + { + return "internal "; + } + return ""; + } + + private static string GetVisibilityFromConstructor(ConstructorInfo constructorInfo) + { + if (constructorInfo.IsPrivate) + { + return "private "; + } + else if (constructorInfo.IsPublic) + { + return "public "; + } + else if (constructorInfo.IsFamily) + { + return "protected "; + } + else if (constructorInfo.IsAssembly) + { + return "internal "; + } + return ""; + } + + private void WriteParameters(StreamWriter writer, ParameterInfo[] parameters) + { + var first = true; + foreach (var parameter in parameters) + { + if (first) + { + writer.Write($"{parameter.ParameterType} {parameter.Name}"); + first = false; + } + else + { + writer.Write($" ,{parameter.Name}"); + } + } + } + + public void PrintStructure(Type someClass) + { + string className = someClass.Name; + string file = $"{filePath}\\{className}.cs"; + + using var writer = new StreamWriter(file); + + var visibility = GetVisibilityFromClass(someClass); + var staticOrNotStatic = GetStaticOrNotFromClass(someClass); + var interfaces = someClass.GetInterfaces(); + if (interfaces.Length == 0) + { + writer.WriteLine($"{visibility}{staticOrNotStatic}class {className}"); + } + else + { + writer.Write($"{visibility}{staticOrNotStatic}class {className} : "); + var first = true; + foreach (var element in interfaces) + { + if (first) + { + writer.Write($"{element.Name}"); + first = false; + } + else + { + writer.Write($" : {element.Name}"); + } + } + writer.WriteLine(); + } + writer.WriteLine("{"); + + var constructors = someClass.GetConstructors(); + foreach (var constructor in constructors) + { + writer.Write($"\t{GetVisibilityFromConstructor(constructor)}{className}("); + WriteParameters(writer, constructor.GetParameters()); + writer.WriteLine(") {}"); + } + var fields = someClass.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); + foreach (var field in fields) + { + writer.WriteLine($"\t{GetVisibilityFromField(field)}{GetStaticOrNotFromField(field)}{field};"); + } + + var methods = someClass.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); + foreach (var method in methods) + { + writer.Write($"\t{GetVisibilityFromMethod(method)}{GetStaticOrNotFromMethod(method)}{method.Name} ("); + WriteParameters(writer, method.GetParameters()); + writer.WriteLine(") {throw new OperationCanceledException()}"); + } + + var nestedClasses = someClass.GetNestedTypes(); + foreach (var nestedClass in nestedClasses) + { + PrintStructure(nestedClass); + } + + writer.WriteLine("}"); + } + + private static bool CheckIfThereIsMethodFromOneClassInAnother(MethodInfo[] methodsB, MethodInfo methodA) + { + var methodB = methodsB.FirstOrDefault(m => m.Name == methodA.Name && m.GetParameters(). + Select(p => p.ParameterType).SequenceEqual(methodA.GetParameters().Select(p => p.ParameterType))); + return methodB != null; + } + + private static void WriteDifferentMethods(StreamWriter writer, + MethodInfo[] methodsFirst, MethodInfo[] methodsSecond) + { + foreach (var methodA in methodsFirst) + { + if (!CheckIfThereIsMethodFromOneClassInAnother(methodsSecond, methodA)) + { + writer.Write($"{methodA.Name}\n"); + } + } + } + private static void WriteDifferentFields(StreamWriter writer, + FieldInfo[] fieldsFirst, FieldInfo[] fieldsSecond) + { + foreach (var fieldA in fieldsFirst) + { + if (!CheckIfThereIsFieldFromOneClassInAnother(fieldsSecond, fieldA)) + { + writer.Write($"{fieldA.Name}\n"); + } + } + } + + private static bool CheckIfThereIsFieldFromOneClassInAnother(FieldInfo[] fieldsB, FieldInfo fieldA) + { + var fieldB = fieldsB.FirstOrDefault(f => f.Name == fieldA.Name && f.FieldType == fieldA.FieldType); + return fieldB != null; + } + + public void DiffClasses(Type a, Type b) + { + string file = $"{filePath}/difference.txt"; + + using var writer = new StreamWriter(file); + + WriteDifferentFields(writer, a.GetFields(), b.GetFields()); + WriteDifferentFields(writer, b.GetFields(), a.GetFields()); + WriteDifferentMethods(writer, a.GetMethods(), b.GetMethods()); + WriteDifferentMethods(writer, b.GetMethods(), a.GetMethods()); + + var nestedClassesA = a.GetNestedTypes(); + var nestedClassesB = b.GetNestedTypes(); + foreach (var nestedClassA in nestedClassesA) + { + foreach (var nestedClassB in nestedClassesB) + { + DiffClasses(nestedClassA, nestedClassB); + } + } + } +} \ No newline at end of file diff --git a/Kr3/TestsReflector/AnotherSum.cs b/Kr3/TestsReflector/AnotherSum.cs new file mode 100644 index 0000000..358739b --- /dev/null +++ b/Kr3/TestsReflector/AnotherSum.cs @@ -0,0 +1,16 @@ +namespace TestsReflector; + +public class AnotherSum +{ + private int val; + + public AnotherSum(int value) + { + val = value; + } + + public void AddToSum(int num) + { + val += num; + } +} diff --git a/Kr3/TestsReflector/TestClassSum.cs b/Kr3/TestsReflector/TestClassSum.cs new file mode 100644 index 0000000..534758b --- /dev/null +++ b/Kr3/TestsReflector/TestClassSum.cs @@ -0,0 +1,16 @@ +namespace TestsReflector; + +public class TestClassSum +{ + private int val; + + public TestClassSum(int value) + { + val = value; + } + + public void Add(int num) + { + val += num; + } +} \ No newline at end of file diff --git a/Kr3/TestsReflector/TestsReflector.cs b/Kr3/TestsReflector/TestsReflector.cs new file mode 100644 index 0000000..46a071b --- /dev/null +++ b/Kr3/TestsReflector/TestsReflector.cs @@ -0,0 +1,54 @@ +namespace TestsReflector; + +using Kr3; +using System.Net.WebSockets; + +public class Tests +{ + [Test] + public void TestWithTestPrintStructure() + { + var sum = new TestClassSum(0); + var typeSum = sum.GetType(); + var reflector = new Reflector(Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests")); + reflector.PrintStructure(typeSum); + using var reader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "CheckTestClassSum.cs"))); + var linesForCheck = reader.ReadToEnd().Split('\n'); + using var anotherReader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "TestClassSum.cs"))); + var linesFromReflector = anotherReader.ReadToEnd().Split('\r'); + + var arrayStringsWithoutSpecialSymbols = new string[linesFromReflector.Length]; + + var i = 0; + foreach (var line in linesFromReflector) + { + var newLine = line.Replace("\n", ""); + arrayStringsWithoutSpecialSymbols[i] = newLine; + i++; + } + + i = 0; + var j = 0; + while (i < linesForCheck.Length || j < arrayStringsWithoutSpecialSymbols.Length) + { + Assert.That(linesForCheck[i], Is.EqualTo(arrayStringsWithoutSpecialSymbols[j])); + ++i; + ++j; + } + } + + [Test] + public void TestWithTestClassDiffClasses() + { + var sum = new TestClassSum(0); + var typeSum = sum.GetType(); + var anotherSum = new AnotherSum(0); + var typeAnotherSum= anotherSum.GetType(); + var reflector = new Reflector(Path.Combine(TestContext.CurrentContext.TestDirectory,"forTests")); + reflector.DiffClasses(typeSum, typeAnotherSum); + using var reader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "difference.txt"))); + var lines = reader.ReadToEnd().Split('\n'); + Assert.That(lines[0], Is.EqualTo("Add")); + Assert.That(lines[1], Is.EqualTo("AddToSum")); + } +} \ No newline at end of file diff --git a/Kr3/TestsReflector/TestsReflector.csproj b/Kr3/TestsReflector/TestsReflector.csproj new file mode 100644 index 0000000..d1d73f9 --- /dev/null +++ b/Kr3/TestsReflector/TestsReflector.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + + + + + + + diff --git a/Kr3/TestsReflector/Usings.cs b/Kr3/TestsReflector/Usings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/Kr3/TestsReflector/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/Kr3/TestsReflector/bin/Debug/net7.0/forTests/CheckTestClassSum.cs b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/CheckTestClassSum.cs new file mode 100644 index 0000000..ed4710f --- /dev/null +++ b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/CheckTestClassSum.cs @@ -0,0 +1,6 @@ +class TestClassSum +{ + public TestClassSum(System.Int32 value) {} + private Int32 val; + public Add (System.Int32 num) {throw new OperationCanceledException()} +} diff --git a/Kr3/TestsReflector/bin/Debug/net7.0/forTests/TestClassSum.cs b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/TestClassSum.cs new file mode 100644 index 0000000..ed4710f --- /dev/null +++ b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/TestClassSum.cs @@ -0,0 +1,6 @@ +class TestClassSum +{ + public TestClassSum(System.Int32 value) {} + private Int32 val; + public Add (System.Int32 num) {throw new OperationCanceledException()} +} diff --git a/Kr3/TestsReflector/bin/Debug/net7.0/forTests/difference.txt b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/difference.txt new file mode 100644 index 0000000..f247286 --- /dev/null +++ b/Kr3/TestsReflector/bin/Debug/net7.0/forTests/difference.txt @@ -0,0 +1,2 @@ +Add +AddToSum