diff --git a/TestData/Integration/xslt/compiled/sample-inline-cs-auto-instrument.xslt b/TestData/Integration/xslt/compiled/sample-inline-cs-auto-instrument.xslt index 065ba19..1c47c09 100644 --- a/TestData/Integration/xslt/compiled/sample-inline-cs-auto-instrument.xslt +++ b/TestData/Integration/xslt/compiled/sample-inline-cs-auto-instrument.xslt @@ -9,6 +9,49 @@ using System; using System.Globalization; public class MathHelper { + // Private fields + private int counter = 0; + private string prefix = "Result: "; + private double multiplier = 2.5; + private int[] cachedValues = new int[] { 10, 20, 30, 40, 50 }; + + // Methods using private variables + public int IncrementCounter() { + counter++; + return counter; + } + + public int GetCounterValue() { + return counter; + } + + public string GetPrefixedMessage(string message) { + string result = prefix + message; + return result; + } + + public double ApplyMultiplier(double value) { + double result = value * multiplier; + return result; + } + + public int GetCachedValue(int index) { + if (index >= 0 && index < cachedValues.Length) { + int value = cachedValues[index]; + return value; + } + return -1; + } + + public int SumCachedValues() { + int sum = 0; + for (int i = 0; i < cachedValues.Length; i++) { + sum += cachedValues[i]; + } + return sum; + } + + // Integer operations public int Add(int a, int b) { return a + b; } @@ -21,6 +64,142 @@ public class MathHelper { public string FormatNumber(int num) { return num.ToString("N0", CultureInfo.InvariantCulture); } + + // Double operations + public double AddDouble(double a, double b) { + double result = a + b; + return result; + } + + public double DivideDouble(double a, double b) { + if (b == 0) return 0; + return a / b; + } + + public string FormatDouble(double num) { + return num.ToString("F2", CultureInfo.InvariantCulture); + } + + // Decimal operations + public decimal AddDecimal(decimal a, decimal b) { + decimal result = a + b; + return result; + } + + public decimal MultiplyDecimal(decimal a, decimal b) { + return a * b; + } + + public string FormatCurrency(decimal amount) { + return amount.ToString("C2", CultureInfo.InvariantCulture); + } + + // DateTime operations + public string GetCurrentDate() { + DateTime now = DateTime.Now; + return now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); + } + + public string FormatDate(int year, int month, int day) { + DateTime date = new DateTime(year, month, day); + return date.ToString("MMMM dd, yyyy", CultureInfo.InvariantCulture); + } + + public int GetDaysDifference(int year1, int month1, int day1, int year2, int month2, int day2) { + DateTime date1 = new DateTime(year1, month1, day1); + DateTime date2 = new DateTime(year2, month2, day2); + TimeSpan diff = date2 - date1; + return diff.Days; + } + + // String operations + public string ConcatStrings(string a, string b) { + string result = a + " " + b; + return result; + } + + public string ToUpperCase(string text) { + return text.ToUpper(); + } + + public string ReverseString(string text) { + char[] charArray = text.ToCharArray(); + Array.Reverse(charArray); + return new string(charArray); + } + + public int GetStringLength(string text) { + return text.Length; + } + + // Array operations + public int SumArray(int count) { + int[] numbers = new int[count]; + for (int i = 0; i < count; i++) { + numbers[i] = i + 1; + } + + int sum = 0; + for (int i = 0; i < numbers.Length; i++) { + sum += numbers[i]; + } + return sum; + } + + public string JoinStringArray() { + string[] words = new string[] { "XSLT", "Debugger", "Test" }; + string result = ""; + for (int i = 0; i < words.Length; i++) { + if (i > 0) result += " "; + result += words[i]; + } + return result; + } + + public double AverageDoubles(int count) { + double[] values = new double[count]; + for (int i = 0; i < count; i++) { + values[i] = (i + 1) * 1.5; + } + + double sum = 0; + for (int i = 0; i < values.Length; i++) { + sum += values[i]; + } + double average = sum / values.Length; + return average; + } + + public int FindMaxInArray(int size) { + int[] numbers = new int[size]; + for (int i = 0; i < size; i++) { + numbers[i] = (i * 7) % 100; + } + + int max = numbers[0]; + for (int i = 1; i < numbers.Length; i++) { + if (numbers[i] > max) { + max = numbers[i]; + } + } + return max; + } + + public string ReverseArray(int count) { + int[] numbers = new int[count]; + for (int i = 0; i < count; i++) { + numbers[i] = i + 1; + } + + Array.Reverse(numbers); + + string result = ""; + for (int i = 0; i < numbers.Length; i++) { + if (i > 0) result += ","; + result += numbers[i].ToString(); + } + return result; + } } ]]> @@ -32,9 +211,49 @@ public class MathHelper {

C# Method Auto-Instrumentation Test

+ +

Private Field Access

+

Increment counter (1st call):

+

Increment counter (2nd call):

+

Increment counter (3rd call):

+

Get counter value:

+

Prefixed message:

+

Apply multiplier to 10:

+

Cached value at index 2:

+

Sum of cached values:

+ +

Integer Operations

Add 5 + 3 =

Multiply 4 * 7 =

Formatted:

+ +

Double Operations

+

Add 3.14 + 2.86 =

+

Divide 10.5 / 2.5 =

+

Formatted Double:

+ +

Decimal Operations

+

Add Decimal 10.50 + 20.75 =

+

Multiply Decimal 5.5 * 2 =

+

Currency:

+ +

DateTime Operations

+

Current Date:

+

Formatted Date:

+

Days between 2025-01-01 and 2025-12-31:

+ +

String Operations

+

Concat:

+

Uppercase:

+

Reverse:

+

Length of 'Testing':

+ +

Array Operations

+

Sum of array [1,2,3,4,5]:

+

Join string array:

+

Average of doubles [1.5, 3.0, 4.5, 6.0]:

+

Max in array (size 10):

+

Reverse array [1,2,3,4,5,6]:

diff --git a/XsltDebugger.ConsoleTest/ProgramUsingEngineType.cs b/XsltDebugger.ConsoleTest/ProgramUsingEngineType.cs index e43f422..7a5aac0 100644 --- a/XsltDebugger.ConsoleTest/ProgramUsingEngineType.cs +++ b/XsltDebugger.ConsoleTest/ProgramUsingEngineType.cs @@ -70,8 +70,8 @@ static async Task Main(string[] args) } // Enable debugging with log level - XsltEngineManager.SetDebugFlags(debug: true, LogLevel.TraceAll); - Console.WriteLine(" >> Debugging ENABLED (TraceAll)\n"); + XsltEngineManager.SetDebugFlags(debug: true, LogLevel.Log); + Console.WriteLine(" >> Debugging ENABLED (Log)\n"); // Set breakpoint - detect which file and set appropriate line var fullStylesheetPath = Path.GetFullPath(stylesheetPath); diff --git a/XsltDebugger.DebugAdapter/README.md b/XsltDebugger.DebugAdapter/README.md index 3d7e8b1..91635e6 100644 --- a/XsltDebugger.DebugAdapter/README.md +++ b/XsltDebugger.DebugAdapter/README.md @@ -19,7 +19,7 @@ The debug adapter implements the Debug Adapter Protocol (DAP) to enable debuggin - **`Program.cs`**: Entry point for the debug adapter - **`XsltDebugSession.cs`**: Main DAP session handler - **`CompiledEngine.cs`**: XSLT 1.0 engine with inline C# support -- **`SaxonEngine.cs`**: XSLT 2.0/3.0 engine using Saxon .NET +- **`SaxonEngine.cs`**: XSLT 1.0/2.0/3.0 engine using Saxon .NET - **`XsltInstrumenter.cs`**: Injects debugging hooks into XSLT stylesheets ### Features @@ -31,7 +31,7 @@ The debug adapter implements the Debug Adapter Protocol (DAP) to enable debuggin - **Inline C# Scripting**: Compile and execute inline C# code in XSLT via `msxsl:script` - **Multiple Engines**: - Compiled engine for XSLT 1.0 with inline C# support - - Saxon .NET engine for XSLT 2.0/3.0 support + - Saxon .NET engine for XSLT 1.0/2.0/3.0 support - **Instrumentation**: Dynamic XSLT modification for debug hooks ## Building @@ -73,7 +73,7 @@ dotnet test ../XsltDebugger.Tests/XsltDebugger.Tests.csproj ## Dependencies - **Microsoft.CSharp**: For Roslyn C# compilation (inline scripts) -- **SaxonHE10Net31Api**: Saxon .NET XSLT 2.0/3.0 processor (community IKVM build) +- **SaxonHE10Net31Api**: Saxon .NET XSLT 1.0/2.0/3.0 processor (community IKVM build) - **System.Xml**: For XSLT 1.0 processing ## Protocol Support diff --git a/XsltDebugger.Tests/CompiledEngineIntegrationTests.cs b/XsltDebugger.Tests/CompiledEngineIntegrationTests.cs index f43ee68..38e6289 100644 --- a/XsltDebugger.Tests/CompiledEngineIntegrationTests.cs +++ b/XsltDebugger.Tests/CompiledEngineIntegrationTests.cs @@ -229,27 +229,95 @@ void OnOutput(string message) snapshot = outputLog.ToList(); } - // Verify instrumentation occurred - snapshot.Should().Contain(message => message.Contains("Instrumented 3 inline C# method(s)", StringComparison.OrdinalIgnoreCase), - "should report instrumenting 3 C# methods"); - - // Verify Add method logging + // Verify instrumentation occurred for all methods + snapshot.Should().Contain(message => message.Contains("Instrumented ", StringComparison.Ordinal) && message.Contains(" inline C# method(s)", StringComparison.Ordinal), + "should report instrumenting multiple C# methods"); + + // Verify private field access methods + snapshot.Should().Contain(message => message.Contains("[inline] [IncrementCounter:", StringComparison.Ordinal), + "should log IncrementCounter method"); + snapshot.Should().Contain(message => message.Contains("[inline] [GetCounterValue:", StringComparison.Ordinal), + "should log GetCounterValue method"); + snapshot.Should().Contain(message => message.Contains("[inline] [GetPrefixedMessage:", StringComparison.Ordinal) && message.Contains("args = { message = Hello }"), + "should log GetPrefixedMessage method with args"); + snapshot.Should().Contain(message => message.Contains("[inline] [ApplyMultiplier:", StringComparison.Ordinal), + "should log ApplyMultiplier method"); + snapshot.Should().Contain(message => message.Contains("[inline] [GetCachedValue:", StringComparison.Ordinal) && message.Contains("args = { index = 2 }"), + "should log GetCachedValue method with index parameter"); + snapshot.Should().Contain(message => message.Contains("[inline] [SumCachedValues:", StringComparison.Ordinal), + "should log SumCachedValues method"); + + // Verify integer operations snapshot.Should().Contain(message => message.Contains("[inline] [Add:", StringComparison.Ordinal) && message.Contains("args = { a = 5, b = 3 }"), "should log Add method entry with parameters"); snapshot.Should().Contain(message => message.Contains("[inline] [Add:", StringComparison.Ordinal) && message.Contains("return = 8"), "should log Add method return value"); - - // Verify Multiply method logging snapshot.Should().Contain(message => message.Contains("[inline] [Multiply:", StringComparison.Ordinal) && message.Contains("args = { a = 4, b = 7 }"), "should log Multiply method entry with parameters"); snapshot.Should().Contain(message => message.Contains("[inline] [Multiply:", StringComparison.Ordinal) && message.Contains("return = 28"), "should log Multiply method return value"); - - // Verify FormatNumber method logging snapshot.Should().Contain(message => message.Contains("[inline] [FormatNumber:", StringComparison.Ordinal) && message.Contains("args = { num = 1000000 }"), "should log FormatNumber method entry with parameters"); - snapshot.Should().Contain(message => message.Contains("[inline] [FormatNumber:", StringComparison.Ordinal) && message.Contains("return = 1,000,000"), - "should log FormatNumber method return value"); + + // Verify double operations + snapshot.Should().Contain(message => message.Contains("[inline] [AddDouble:", StringComparison.Ordinal) && message.Contains("args = { a = 3.14, b = 2.86 }"), + "should log AddDouble method with double parameters"); + snapshot.Should().Contain(message => message.Contains("[inline] [DivideDouble:", StringComparison.Ordinal) && message.Contains("args = { a = 10.5, b = 2.5 }"), + "should log DivideDouble method with double parameters"); + snapshot.Should().Contain(message => message.Contains("[inline] [FormatDouble:", StringComparison.Ordinal) && message.Contains("args = { num = 123.456 }"), + "should log FormatDouble method"); + + // Verify decimal operations + snapshot.Should().Contain(message => message.Contains("[inline] [AddDecimal:", StringComparison.Ordinal), + "should log AddDecimal method"); + snapshot.Should().Contain(message => message.Contains("[inline] [MultiplyDecimal:", StringComparison.Ordinal), + "should log MultiplyDecimal method"); + snapshot.Should().Contain(message => message.Contains("[inline] [FormatCurrency:", StringComparison.Ordinal), + "should log FormatCurrency method"); + + // Verify DateTime operations + snapshot.Should().Contain(message => message.Contains("[inline] [GetCurrentDate:", StringComparison.Ordinal), + "should log GetCurrentDate method"); + snapshot.Should().Contain(message => message.Contains("[inline] [FormatDate:", StringComparison.Ordinal) && message.Contains("args = { year = 2025, month = 11, day = 1 }"), + "should log FormatDate method with parameters"); + snapshot.Should().Contain(message => message.Contains("[inline] [GetDaysDifference:", StringComparison.Ordinal), + "should log GetDaysDifference method"); + + // Verify string operations + snapshot.Should().Contain(message => message.Contains("[inline] [ConcatStrings:", StringComparison.Ordinal) && message.Contains("args = { a = Hello, b = World }"), + "should log ConcatStrings method with string parameters"); + snapshot.Should().Contain(message => message.Contains("[inline] [ToUpperCase:", StringComparison.Ordinal) && message.Contains("args = { text = xslt debugger }"), + "should log ToUpperCase method"); + snapshot.Should().Contain(message => message.Contains("[inline] [ReverseString:", StringComparison.Ordinal) && message.Contains("args = { text = XSLT }"), + "should log ReverseString method"); + snapshot.Should().Contain(message => message.Contains("[inline] [GetStringLength:", StringComparison.Ordinal) && message.Contains("args = { text = Testing }"), + "should log GetStringLength method"); + + // Verify array operations + snapshot.Should().Contain(message => message.Contains("[inline] [SumArray:", StringComparison.Ordinal) && message.Contains("args = { count = 5 }"), + "should log SumArray method"); + snapshot.Should().Contain(message => message.Contains("[inline] [JoinStringArray:", StringComparison.Ordinal), + "should log JoinStringArray method"); + snapshot.Should().Contain(message => message.Contains("[inline] [AverageDoubles:", StringComparison.Ordinal) && message.Contains("args = { count = 4 }"), + "should log AverageDoubles method"); + snapshot.Should().Contain(message => message.Contains("[inline] [FindMaxInArray:", StringComparison.Ordinal) && message.Contains("args = { size = 10 }"), + "should log FindMaxInArray method"); + snapshot.Should().Contain(message => message.Contains("[inline] [ReverseArray:", StringComparison.Ordinal) && message.Contains("args = { count = 6 }"), + "should log ReverseArray method"); + + // Verify output file was created + var stylesheetDir = Path.GetDirectoryName(fullStylesheetPath) ?? throw new InvalidOperationException("Unable to determine stylesheet directory."); + var outDir = Path.Combine(stylesheetDir, "out"); + var outFile = Path.Combine(outDir, $"{Path.GetFileNameWithoutExtension(fullStylesheetPath)}.out.xml"); + + File.Exists(outFile).Should().BeTrue("compiled engine should write transformation results to disk"); + var output = await File.ReadAllTextAsync(outFile); + output.Should().Contain("Auto-Instrumentation Test"); + output.Should().Contain("Result: Hello"); + output.Should().Contain("25"); + output.Should().Contain("XSLT DEBUGGER"); + + TryDeleteOutput(outFile, outDir); } finally { diff --git a/XsltDebugger.sln b/XsltDebugger.sln index 219d24a..e13e2c4 100644 --- a/XsltDebugger.sln +++ b/XsltDebugger.sln @@ -4,6 +4,10 @@ VisualStudioVersion = 17.5.2.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XsltDebugger.DebugAdapter", "XsltDebugger.DebugAdapter\XsltDebugger.DebugAdapter.csproj", "{09C15C57-552E-CC57-443F-3ED1FE119949}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XsltDebugger.Tests", "XsltDebugger.Tests\XsltDebugger.Tests.csproj", "{A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XsltDebugger.ConsoleTest", "XsltDebugger.ConsoleTest\XsltDebugger.ConsoleTest.csproj", "{B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -14,6 +18,14 @@ Global {09C15C57-552E-CC57-443F-3ED1FE119949}.Debug|Any CPU.Build.0 = Debug|Any CPU {09C15C57-552E-CC57-443F-3ED1FE119949}.Release|Any CPU.ActiveCfg = Release|Any CPU {09C15C57-552E-CC57-443F-3ED1FE119949}.Release|Any CPU.Build.0 = Release|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.Build.0 = Release|Any CPU + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/package.json b/package.json index 865ed71..af6cb32 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "xsltdebugger-darwin", - "displayName": "XSLT Debugger for macOS-arm64", + "name": "xsltdebugger", + "displayName": "XSLT Debugger", "description": "A VS Code extension for debugging XSLT using a .NET Debug Adapter.", "version": "1.0.0", "publisher": "DanielJonathan", "repository": { "type": "git", - "url": "https://github.com/imdj360/XsltDebugger.git" + "url": "https://github.com/imdj360/VSCodeXsltDebugger.git" }, "engines": { "vscode": "^1.105.0" @@ -60,7 +60,7 @@ ], "enumDescriptions": [ "XSLT 1.0 engine with inline C# support", - "Saxon.NET engine for XSLT 2.0/3.0", + "Saxon.NET engine for XSLT 1.0/2.0/3.0", "Alias for saxonnet" ], "default": "compiled",