using System; using System.Linq; using MarketAlly.IronJava.Core.AST; using MarketAlly.IronJava.Core.AST.Comparison; using MarketAlly.IronJava.Core.AST.Nodes; using MarketAlly.IronJava.Core.AST.Query; using MarketAlly.IronJava.Core.AST.Transformation; using MarketAlly.IronJava.Core.Serialization; using Xunit; namespace MarketAlly.IronJava.Tests { public class Phase3Tests { private static SourceRange CreateLocation() => new( new SourceLocation(1, 1, 0, 0), new SourceLocation(1, 1, 0, 0) ); [Fact] public void JsonSerializationWorks() { // Arrange var location = CreateLocation(); var method = new MethodDeclaration( location, "testMethod", Modifiers.Public | Modifiers.Static, new List(), new PrimitiveType(location, PrimitiveTypeKind.Void), new List(), new List { new Parameter( location, new PrimitiveType(location, PrimitiveTypeKind.Int), "param1", false, false, new List() ) }, new List(), new BlockStatement(location, new List()), null ); var serializer = new AstJsonSerializer(indented: false); // Act var json = serializer.Serialize(method); // Assert Assert.Contains("\"nodeType\":\"MethodDeclaration\"", json); Assert.Contains("\"name\":\"testMethod\"", json); Assert.Contains("\"modifiers\":[\"public\",\"static\"]", json); Assert.Contains("\"parameters\"", json); Assert.Contains("\"param1\"", json); } [Fact] public void AstQueryFindAllWorks() { // Arrange var location = CreateLocation(); var compilation = CreateSampleCompilationUnit(); // Act var methods = compilation.FindAll().ToList(); var fields = compilation.FindAll().ToList(); var classes = compilation.FindAll().ToList(); // Assert Assert.Equal(2, methods.Count); Assert.Single(fields); Assert.Single(classes); } [Fact] public void AstQueryWhereWorks() { // Arrange var compilation = CreateSampleCompilationUnit(); // Act var publicMethods = compilation .Where(m => m.Modifiers.IsPublic()) .ToList(); var staticFields = compilation .Where(f => f.Modifiers.IsStatic()) .ToList(); // Assert Assert.Single(publicMethods); Assert.Equal("main", publicMethods[0].Name); Assert.Empty(staticFields); } [Fact] public void AstQueryBuilderWorks() { // Arrange var compilation = CreateSampleCompilationUnit(); // Act var result = compilation .Query() .WithName("main") .WithModifier(Modifiers.Public) .WithModifier(Modifiers.Static) .ExecuteFirst(); // Assert Assert.NotNull(result); Assert.Equal("main", result.Name); } [Fact] public void AstPatternMatchingWorks() { // Arrange var compilation = CreateSampleCompilationUnit(); var methods = compilation.FindAll().ToList(); // Act & Assert Assert.True(methods[0].IsMainMethod()); // main method Assert.False(methods[1].IsGetter()); // helper method } [Fact] public void AstTransformationRenameWorks() { // Arrange var location = CreateLocation(); var original = new IdentifierExpression(location, "oldName"); var transformer = new IdentifierRenamer("oldName", "newName"); // Act var transformed = original.Accept(transformer) as IdentifierExpression; // Assert Assert.NotNull(transformed); Assert.Equal("newName", transformed.Name); } [Fact] public void AstTransformationModifierWorks() { // Arrange var compilation = CreateSampleCompilationUnit(); var transformer = ModifierTransformer.AddModifier(Modifiers.Final); // Act var transformed = compilation.Accept(transformer) as CompilationUnit; var transformedClass = transformed?.Types[0] as ClassDeclaration; // Assert Assert.NotNull(transformedClass); Assert.True(transformedClass.Modifiers.IsFinal()); } [Fact] public void AstEqualityComparerWorks() { // Arrange var location1 = CreateLocation(); var location2 = new SourceRange( new SourceLocation(2, 2, 10, 0), new SourceLocation(2, 2, 10, 0) ); var expr1 = new IdentifierExpression(location1, "test"); var expr2 = new IdentifierExpression(location1, "test"); var expr3 = new IdentifierExpression(location2, "test"); var expr4 = new IdentifierExpression(location1, "different"); var comparer = new AstEqualityComparer(ignoreLocation: true); // Act & Assert Assert.True(comparer.Equals(expr1, expr2)); Assert.True(comparer.Equals(expr1, expr3)); // Different location, but ignored Assert.False(comparer.Equals(expr1, expr4)); // Different name } [Fact] public void AstDifferWorks() { // Arrange var location = CreateLocation(); var original = new BlockStatement(location, new List { new ExpressionStatement(location, new IdentifierExpression(location, "a")), new ExpressionStatement(location, new IdentifierExpression(location, "b")) }); var modified = new BlockStatement(location, new List { new ExpressionStatement(location, new IdentifierExpression(location, "a")), new ExpressionStatement(location, new IdentifierExpression(location, "c")), // Changed new ExpressionStatement(location, new IdentifierExpression(location, "d")) // Added }); var differ = new AstDiffer(); // Act var diff = differ.ComputeDiff(original, modified); // Assert Assert.False(diff.IsEmpty); // The differ detects: // 1. Modification of the second ExpressionStatement (b -> c) // 2. Modification of the IdentifierExpression inside it (b -> c) // 3. Addition of the third ExpressionStatement (d) // 4. Addition of the IdentifierExpression inside it (d) // 5. Addition of the fourth statement's expression // Total = 5 changes when comparing deeply Assert.Equal(5, diff.TotalChanges); } [Fact] public void TransformationBuilderWorks() { // Arrange var location = CreateLocation(); var classDecl = new ClassDeclaration( location, "TestClass", Modifiers.Public, new List(), new List(), null, new List(), new List { new FieldDeclaration( location, Modifiers.Private, new List(), new PrimitiveType(location, PrimitiveTypeKind.Int), new List { new VariableDeclarator(location, "oldField", 0, null) }, null ) }, new List(), null, false ); var builder = new TransformationBuilder() .AddModifier(Modifiers.Final) .RenameIdentifier("oldField", "newField"); // Act var transformed = builder.Transform(classDecl) as ClassDeclaration; // Assert Assert.NotNull(transformed); Assert.True(transformed.Modifiers.IsFinal()); var field = transformed.Members[0] as FieldDeclaration; Assert.NotNull(field); Assert.Equal("newField", field.Variables[0].Name); } [Fact] public void ComplexQueryScenario() { // Arrange var compilation = CreateComplexCompilationUnit(); // Act // Find all public static methods in classes that implement Serializable var query = compilation .QueryClasses() .Where(c => c.Interfaces.Any(i => (i as ClassOrInterfaceType)?.Name == "Serializable")) .Execute() .SelectMany(c => c.Members.OfType()) .Where(m => m.Modifiers.IsPublic() && m.Modifiers.IsStatic()) .ToList(); // Assert Assert.Single(query); Assert.Equal("serialize", query[0].Name); } private CompilationUnit CreateSampleCompilationUnit() { var location = CreateLocation(); var mainMethod = new MethodDeclaration( location, "main", Modifiers.Public | Modifiers.Static, new List(), new PrimitiveType(location, PrimitiveTypeKind.Void), new List(), new List { new Parameter( location, new ArrayType(location, new ClassOrInterfaceType(location, "String", null, new List(), new List()), 1), "args", false, false, new List() ) }, new List(), new BlockStatement(location, new List()), null ); var helperMethod = new MethodDeclaration( location, "helper", Modifiers.Private, new List(), new PrimitiveType(location, PrimitiveTypeKind.Void), new List(), new List(), new List(), new BlockStatement(location, new List()), null ); var field = new FieldDeclaration( location, Modifiers.Private, new List(), new PrimitiveType(location, PrimitiveTypeKind.Int), new List { new VariableDeclarator(location, "count", 0, null) }, null ); var testClass = new ClassDeclaration( location, "TestClass", Modifiers.Public, new List(), new List(), null, new List(), new List { mainMethod, helperMethod, field }, new List(), null, false ); return new CompilationUnit( location, null, new List(), new List { testClass } ); } private CompilationUnit CreateComplexCompilationUnit() { var location = CreateLocation(); var serializableInterface = new ClassOrInterfaceType( location, "Serializable", null, new List(), new List() ); var serializeMethod = new MethodDeclaration( location, "serialize", Modifiers.Public | Modifiers.Static, new List(), new PrimitiveType(location, PrimitiveTypeKind.Void), new List(), new List(), new List(), null, null ); var dataClass = new ClassDeclaration( location, "DataClass", Modifiers.Public, new List(), new List(), null, new List { serializableInterface }, new List { serializeMethod }, new List(), null, false ); return new CompilationUnit( location, null, new List(), new List { dataClass } ); } } }