diff --git a/MyNUnit/MyNUnit.sln b/MyNUnit/MyNUnit.sln new file mode 100644 index 0000000..ae4a8b0 --- /dev/null +++ b/MyNUnit/MyNUnit.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33403.182 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyNUnit", "MyNUnit\MyNUnit.csproj", "{8A4A83AC-5456-4F54-9183-B053A0C05926}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestMyNUnit", "TestMyNUnit\TestMyNUnit.csproj", "{9508BABD-7DF4-4B36-B442-020EB706C229}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectForTest", "ProjectForTest\ProjectForTest.csproj", "{F9103AED-6C96-471A-9431-4F2E37A33EC9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A4A83AC-5456-4F54-9183-B053A0C05926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A4A83AC-5456-4F54-9183-B053A0C05926}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A4A83AC-5456-4F54-9183-B053A0C05926}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A4A83AC-5456-4F54-9183-B053A0C05926}.Release|Any CPU.Build.0 = Release|Any CPU + {9508BABD-7DF4-4B36-B442-020EB706C229}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9508BABD-7DF4-4B36-B442-020EB706C229}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9508BABD-7DF4-4B36-B442-020EB706C229}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9508BABD-7DF4-4B36-B442-020EB706C229}.Release|Any CPU.Build.0 = Release|Any CPU + {F9103AED-6C96-471A-9431-4F2E37A33EC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9103AED-6C96-471A-9431-4F2E37A33EC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9103AED-6C96-471A-9431-4F2E37A33EC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9103AED-6C96-471A-9431-4F2E37A33EC9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {97E09C33-070C-4D39-BDE1-D7C045292CC6} + EndGlobalSection +EndGlobal diff --git a/MyNUnit/MyNUnit/ApplicationForTests.cs b/MyNUnit/MyNUnit/ApplicationForTests.cs new file mode 100644 index 0000000..3aa3483 --- /dev/null +++ b/MyNUnit/MyNUnit/ApplicationForTests.cs @@ -0,0 +1,158 @@ +using System.Diagnostics; +using System.Reflection; + +using MyNUnit.Atributes; + +namespace MyNUnit; + +public class ApplicationForTests +{ + public readonly List listOfResults = new(); + private readonly object locker = new(); + + public ApplicationForTests(Assembly assembly) + { + var classes = assembly.GetExportedTypes() + .Where(t => t.IsClass) + .Where(t => t.GetMethods() + .Where(m => m.GetCustomAttributes(true) + .Any(a => a is TestAttribute)) + .Any()); + + Parallel.ForEach(classes, StartTests); + } + + private static MethodInfo[]? GetMethodsByAtributeAndClass(Type _class, Type atribute) + { + return _class.GetMethods() + .Where(m => m.GetCustomAttributes(atribute, false).Length > 0) + .ToArray(); + } + + private static void WorkWithClassMethods(Type _class, Type atribute) + { + var methods = GetMethodsByAtributeAndClass(_class, atribute); + LaunchMethods(_class, methods); + } + + private void WorkWithTestMethods(Type _class) + { + var instance = Activator.CreateInstance(_class); + var methodsBefore = GetMethodsByAtributeAndClass(_class, typeof(BeforeAttribute)); + var methodsAfter = GetMethodsByAtributeAndClass(_class, typeof(AfterAttribute)); + var methods = _class.GetMethods(); + foreach(var method in methods) + { + if (method.IsDefined(typeof(TestAttribute), true)) + { + RunMethodsBeforeAndAfter(methodsBefore, instance); + RunMethod(_class, method); + RunMethodsBeforeAndAfter(methodsAfter, instance); + } + } + } + private void StartTests(Type _class) + { + WorkWithClassMethods(_class, typeof(BeforeClassAttribute)); + WorkWithTestMethods(_class); + WorkWithClassMethods(_class, typeof(AfterClassAttribute)); + } + + private static void LaunchMethods(Type _class, MethodInfo[]? methods) + { + if (_class == null || methods == null) + { + throw new NullReferenceException(); + } + + foreach (var method in methods) + { + if (!method.IsStatic) + { + throw new InvalidOperationException(); + } + + method.Invoke(null, null); + } + } + + private static void RunMethodsBeforeAndAfter(MethodInfo[]? methods, object? instance) + { + if (instance == null || methods == null) + { + throw new NullReferenceException(); + } + foreach(var method in methods) + { + method.Invoke(instance, null); + } + } + + private void RunMethod(object? instance, MethodInfo? method) + { + if (instance == null || method == null || locker == null) + { + throw new InvalidOperationException(); + } + + var atribute = Attribute.GetCustomAttribute(method, typeof(TestAttribute)); + + if (atribute == null) + { + throw new InvalidOperationException(); + } + + var testAttribute = (TestAttribute)atribute; + + if (testAttribute.Ignored != null) + { + lock (locker) + { + listOfResults.Add(new ResultsTests(method.Name, 0, ResultsTests.Status.Ignored)); + } + return; + } + + var stopWatch = new Stopwatch(); + + try + { + stopWatch.Start(); + method.Invoke(instance, null); + stopWatch.Stop(); + lock (locker) + { + if (testAttribute != null && testAttribute.Expected != null) + { + listOfResults.Add(new ResultsTests(method.Name, stopWatch.ElapsedMilliseconds, ResultsTests.Status.Failed)); + } + else + { + listOfResults.Add(new ResultsTests(method.Name, stopWatch.ElapsedMilliseconds, ResultsTests.Status.Passed)); + } + } + } + catch(Exception ex) + { + stopWatch.Stop(); + var exceptionType = ex.GetType(); + + if (testAttribute != null && testAttribute.Expected != null && testAttribute.Expected.IsAssignableFrom(exceptionType) || + (ex.InnerException != null && testAttribute != null && testAttribute.Expected != null && testAttribute.Expected.IsAssignableFrom(ex.InnerException.GetType()))) + { + lock (locker) + { + listOfResults.Add(new ResultsTests(method.Name, stopWatch.ElapsedMilliseconds, ex, ResultsTests.Status.Passed)); + } + } + else + { + lock (locker) + { + listOfResults.Add(new ResultsTests(method.Name, stopWatch.ElapsedMilliseconds, ex, ResultsTests.Status.Failed)); + } + } + } + } + +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Attributes/AfterAttribute.cs b/MyNUnit/MyNUnit/Attributes/AfterAttribute.cs new file mode 100644 index 0000000..a8b4ebb --- /dev/null +++ b/MyNUnit/MyNUnit/Attributes/AfterAttribute.cs @@ -0,0 +1,14 @@ +namespace MyNUnit.Atributes; + +[AttributeUsage(AttributeTargets.Method)] +public class AfterAttribute : Attribute +{ + public AfterAttribute() { } + + + [AfterAttribute] + public void Method() + { + ; + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Attributes/AfterClassAttribute.cs b/MyNUnit/MyNUnit/Attributes/AfterClassAttribute.cs new file mode 100644 index 0000000..3ff1eac --- /dev/null +++ b/MyNUnit/MyNUnit/Attributes/AfterClassAttribute.cs @@ -0,0 +1,7 @@ +namespace MyNUnit.Atributes; + +[AttributeUsage(AttributeTargets.Method)] +public class AfterClassAttribute : Attribute +{ + public AfterClassAttribute() { } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Attributes/BeforeAttribute.cs b/MyNUnit/MyNUnit/Attributes/BeforeAttribute.cs new file mode 100644 index 0000000..fe780ea --- /dev/null +++ b/MyNUnit/MyNUnit/Attributes/BeforeAttribute.cs @@ -0,0 +1,14 @@ +namespace MyNUnit.Atributes; + +[AttributeUsage(AttributeTargets.Method)] +public class BeforeAttribute : Attribute +{ + public BeforeAttribute() { } + + + [BeforeAttribute] + public void Method() + { + ; + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Attributes/BeforeClassAttribute.cs b/MyNUnit/MyNUnit/Attributes/BeforeClassAttribute.cs new file mode 100644 index 0000000..993eb25 --- /dev/null +++ b/MyNUnit/MyNUnit/Attributes/BeforeClassAttribute.cs @@ -0,0 +1,7 @@ +namespace MyNUnit.Atributes; + +[AttributeUsage(AttributeTargets.Method)] +public class BeforeClassAttribute : Attribute +{ + public BeforeClassAttribute() { } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Attributes/TestAttribute.cs b/MyNUnit/MyNUnit/Attributes/TestAttribute.cs new file mode 100644 index 0000000..6e86626 --- /dev/null +++ b/MyNUnit/MyNUnit/Attributes/TestAttribute.cs @@ -0,0 +1,27 @@ +namespace MyNUnit.Atributes; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class TestAttribute : Attribute +{ + public TestAttribute() { } + + public TestAttribute(Type? expected) + { + Expected = expected; + } + + public TestAttribute(string ignored) + { + Ignored = ignored; + } + + public TestAttribute(Type? expected, string? ignored) + { + Expected = expected; + Ignored = ignored; + } + + public Type? Expected { get; set; } + + public string? Ignored { get; set; } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/MyNUnit.csproj b/MyNUnit/MyNUnit/MyNUnit.csproj new file mode 100644 index 0000000..dc2bb05 --- /dev/null +++ b/MyNUnit/MyNUnit/MyNUnit.csproj @@ -0,0 +1,10 @@ + + + + Library + net7.0 + enable + enable + + + diff --git a/MyNUnit/MyNUnit/ResultsTests.cs b/MyNUnit/MyNUnit/ResultsTests.cs new file mode 100644 index 0000000..0d979b8 --- /dev/null +++ b/MyNUnit/MyNUnit/ResultsTests.cs @@ -0,0 +1,36 @@ +using static MyNUnit.ApplicationForTests; + +namespace MyNUnit; + +public class ResultsTests +{ + public enum Status + { + Passed, + Failed, + Ignored + } + + public string Name { get; } + + public long WorkTime { get; } + + public Exception? ReasonFail { get; } + + public Status StatusTest { get; } + + public ResultsTests(string name, long workTime, Exception reasonFail, Status statusTest) + { + Name = name; + WorkTime = workTime; + ReasonFail = reasonFail; + StatusTest = statusTest; + } + + public ResultsTests(string name, long workTime, Status statusTest) + { + Name = name; + WorkTime = workTime; + StatusTest = statusTest; + } +} diff --git a/MyNUnit/ProjectForTest/ClassForTests.cs b/MyNUnit/ProjectForTest/ClassForTests.cs new file mode 100644 index 0000000..ccd98a3 --- /dev/null +++ b/MyNUnit/ProjectForTest/ClassForTests.cs @@ -0,0 +1,62 @@ +namespace ProjectForTest; + +using MyNUnit.Atributes; + +public class ClassForTests +{ + public static int counter = 0; + + [TestAttribute(Expected = typeof(IndexOutOfRangeException))] + public void InvalidMethod() + { + throw new NotImplementedException(); + } + + [TestAttribute(Expected = typeof(FileNotFoundException))] + public int CorrectMethod() + { + throw new FileNotFoundException(); + } + + [BeforeClassAttribute] + public static void BeforeClass() + { + counter += 1; + } + + [AfterClassAttribute] + public static void AfterClass() + { + counter += 1; + } + + [AfterAttribute] + public void BeforeMethod() + { + counter += 1; + } + + [BeforeAttribute] + public void AfterMethod() + { + counter += 1; + } + + [TestAttribute(Ignored = "Ignore")] + public void IgnoreTest() + { + ; + } + + [TestAttribute(Expected = typeof(InvalidCastException))] + public void OneMoreCorrectMethod() + { + throw new InvalidCastException(); + } + + [TestAttribute(Expected = typeof(InvalidOperationException))] + public void OneMoreIncorrectMethod() + { + throw new InvalidProgramException(); + } +} \ No newline at end of file diff --git a/MyNUnit/ProjectForTest/ProjectForTest.csproj b/MyNUnit/ProjectForTest/ProjectForTest.csproj new file mode 100644 index 0000000..776293d --- /dev/null +++ b/MyNUnit/ProjectForTest/ProjectForTest.csproj @@ -0,0 +1,14 @@ + + + + Library + net7.0 + enable + enable + + + + + + + diff --git a/MyNUnit/TestMyNUnit/TestMyNUnit.csproj b/MyNUnit/TestMyNUnit/TestMyNUnit.csproj new file mode 100644 index 0000000..1859717 --- /dev/null +++ b/MyNUnit/TestMyNUnit/TestMyNUnit.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + + + + + + + + diff --git a/MyNUnit/TestMyNUnit/Usings.cs b/MyNUnit/TestMyNUnit/Usings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/MyNUnit/TestMyNUnit/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/MyNUnit/TestMyNUnit/dll/ProjectForTest.dll b/MyNUnit/TestMyNUnit/dll/ProjectForTest.dll new file mode 100644 index 0000000..205d8ff Binary files /dev/null and b/MyNUnit/TestMyNUnit/dll/ProjectForTest.dll differ