diff --git a/UniversalCodePatcher.Tests/CSharpModuleTests.cs b/UniversalCodePatcher.Tests/CSharpModuleTests.cs index 868beb5..bf73187 100644 --- a/UniversalCodePatcher.Tests/CSharpModuleTests.cs +++ b/UniversalCodePatcher.Tests/CSharpModuleTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; +using System.Text; using UniversalCodePatcher.Modules.CSharpModule; using UniversalCodePatcher.Models; @@ -37,6 +38,19 @@ public class Data { } }"; + + private static string GenerateClass(string name, params string[] members) + { + var sb = new StringBuilder(); + sb.AppendLine("namespace Generated {"); + sb.AppendLine($" public class {name} {{"); + foreach (var m in members) + sb.AppendLine($" {m}"); + sb.AppendLine(" }"); + sb.AppendLine("}"); + return sb.ToString(); + } + [TestMethod] public void AnalyzeCode_ExtractsElements() { @@ -201,5 +215,209 @@ public void ApplyPatch_AddAttribute_ChangeVisibility() Assert.IsTrue(r2.ModifiedCode.Contains("[System.Obsolete]")); Assert.IsTrue(r2.ModifiedCode.Contains("private int X")); } + + + [TestMethod] + public void SymbolMatches_NegativePatterns() + { + var module = new CSharpModule(); + module.Initialize(null); + + var wildcardRule = new PatchRule + { + PatchType = PatchType.Delete, + TargetPattern = "*.Foo*", + TargetLanguage = "CSharp", + TargetElementType = CodeElementType.Method + }; + Assert.IsFalse(module.CanApplyPatch(PatternSample, wildcardRule, "CSharp")); + + var regexRule = new PatchRule + { + PatchType = PatchType.Delete, + TargetPattern = "/Non.*Exist/", + TargetLanguage = "CSharp", + TargetElementType = CodeElementType.Method + }; + Assert.IsFalse(module.CanApplyPatch(PatternSample, regexRule, "CSharp")); + } + + [TestMethod] + public void ApplyPatch_InsertBefore_NoMatch() + { + var code = GenerateClass("Neg", "public int A;", "public void Do() {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var rule = new PatchRule + { + PatchType = PatchType.InsertBefore, + TargetPattern = "B", + TargetElementType = CodeElementType.Field, + TargetLanguage = "CSharp", + NewContent = "public int B;" + }; + + var result = module.ApplyPatch(code, rule, "CSharp"); + Assert.IsFalse(result.Success); + Assert.AreEqual(code, result.ModifiedCode); + Assert.IsTrue(result.Errors.Any()); + } + + [TestMethod] + public void ApplyPatch_InsertAfter_NoMatch() + { + var code = GenerateClass("Neg", "public int A;", "public void Do() {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var rule = new PatchRule + { + PatchType = PatchType.InsertAfter, + TargetPattern = "Missing", + TargetElementType = CodeElementType.Method, + TargetLanguage = "CSharp", + NewContent = "public void Done() {}" + }; + + var result = module.ApplyPatch(code, rule, "CSharp"); + Assert.IsFalse(result.Success); + Assert.AreEqual(code, result.ModifiedCode); + Assert.IsTrue(result.Errors.Any()); + } + + [TestMethod] + public void ApplyPatch_ChangeSignature_NoMatch() + { + var code = GenerateClass("Neg", "public int A;", "public void Do(int x) {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var rule = new PatchRule + { + PatchType = PatchType.ChangeSignature, + TargetPattern = "Unknown", + TargetElementType = CodeElementType.Method, + TargetLanguage = "CSharp", + NewContent = "public void Do(int x, int y)" + }; + + var result = module.ApplyPatch(code, rule, "CSharp"); + Assert.IsFalse(result.Success); + Assert.AreEqual(code, result.ModifiedCode); + Assert.IsTrue(result.Errors.Any()); + } + + [TestMethod] + public void ApplyPatch_AddAttribute_NoMatch() + { + var code = GenerateClass("Neg", "public int A;", "public void Do() {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var rule = new PatchRule + { + PatchType = PatchType.AddAttribute, + TargetPattern = "MissingClass", + TargetElementType = CodeElementType.Class, + TargetLanguage = "CSharp", + NewContent = "System.Obsolete" + }; + + var result = module.ApplyPatch(code, rule, "CSharp"); + Assert.IsFalse(result.Success); + Assert.AreEqual(code, result.ModifiedCode); + Assert.IsTrue(result.Errors.Any()); + } + + [TestMethod] + public void ApplyPatch_ChangeVisibility_NoMatch() + { + var code = GenerateClass("Neg", "public int A;", "public void Do() {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var rule = new PatchRule + { + PatchType = PatchType.ChangeVisibility, + TargetPattern = "B", + TargetElementType = CodeElementType.Field, + TargetLanguage = "CSharp", + NewContent = "private" + }; + + var result = module.ApplyPatch(code, rule, "CSharp"); + Assert.IsFalse(result.Success); + Assert.AreEqual(code, result.ModifiedCode); + Assert.IsTrue(result.Errors.Any()); + } + + [TestMethod] + public void Integration_MultipleSequentialPatches() + { + var code = GenerateClass("Integration", "public int X;", "public void Do(int v) {}"); + var module = new CSharpModule(); + module.Initialize(null); + + var beforeRule = new PatchRule + { + PatchType = PatchType.InsertBefore, + TargetPattern = "X", + TargetElementType = CodeElementType.Field, + TargetLanguage = "CSharp", + NewContent = "public int Y;" + }; + var afterRule = new PatchRule + { + PatchType = PatchType.InsertAfter, + TargetPattern = "Do", + TargetElementType = CodeElementType.Method, + TargetLanguage = "CSharp", + NewContent = "public void Done() {}" + }; + var sigRule = new PatchRule + { + PatchType = PatchType.ChangeSignature, + TargetPattern = "Do", + TargetElementType = CodeElementType.Method, + TargetLanguage = "CSharp", + NewContent = "public void Do(int v, string name)" + }; + var attrRule = new PatchRule + { + PatchType = PatchType.AddAttribute, + TargetPattern = "Integration", + TargetElementType = CodeElementType.Class, + TargetLanguage = "CSharp", + NewContent = "System.Obsolete" + }; + var visRule = new PatchRule + { + PatchType = PatchType.ChangeVisibility, + TargetPattern = "X", + TargetElementType = CodeElementType.Field, + TargetLanguage = "CSharp", + NewContent = "private" + }; + + var r1 = module.ApplyPatch(code, beforeRule, "CSharp"); + Assert.IsTrue(r1.Success, string.Join(";", r1.Errors)); + var r2 = module.ApplyPatch(r1.ModifiedCode, afterRule, "CSharp"); + Assert.IsTrue(r2.Success, string.Join(";", r2.Errors)); + var r3 = module.ApplyPatch(r2.ModifiedCode, sigRule, "CSharp"); + Assert.IsTrue(r3.Success, string.Join(";", r3.Errors)); + var r4 = module.ApplyPatch(r3.ModifiedCode, attrRule, "CSharp"); + Assert.IsTrue(r4.Success, string.Join(";", r4.Errors)); + var r5 = module.ApplyPatch(r4.ModifiedCode, visRule, "CSharp"); + Assert.IsTrue(r5.Success, string.Join(";", r5.Errors)); + + var finalCode = r5.ModifiedCode; + Assert.IsTrue(finalCode.Contains("[System.Obsolete]")); + Assert.IsTrue(finalCode.Contains("public int Y")); + Assert.IsTrue(finalCode.Contains("private int X")); + Assert.IsTrue(finalCode.Contains("void Done()")); + Assert.IsTrue(finalCode.Contains("Do(int v, string name)")); + } + } }