Files
ironjava/IronJava.Tests/AstQueryAndTransformationTests.cs
Dave Friedel 5439aeb081 Resolved build errors
1. Fixed constructor calls in AstTransformer.cs by adding missing nestedTypes parameter
  2. Fixed constructor calls in AstJsonSerializer.cs by adding logic to deserialize nestedTypes
  3. Fixed constructor calls in AstBuilder.cs by adding empty nestedTypes lists and correct parameters
  4. Fixed test files by updating ClassDeclaration constructors with proper parameters
2025-07-23 05:24:18 -04:00

413 lines
14 KiB
C#

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<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Void),
new List<TypeParameter>(),
new List<Parameter>
{
new Parameter(
location,
new PrimitiveType(location, PrimitiveTypeKind.Int),
"param1",
false,
false,
new List<Annotation>()
)
},
new List<TypeReference>(),
new BlockStatement(location, new List<Statement>()),
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<MethodDeclaration>().ToList();
var fields = compilation.FindAll<FieldDeclaration>().ToList();
var classes = compilation.FindAll<ClassDeclaration>().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<MethodDeclaration>(m => m.Modifiers.IsPublic())
.ToList();
var staticFields = compilation
.Where<FieldDeclaration>(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<MethodDeclaration>()
.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<MethodDeclaration>().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<Statement>
{
new ExpressionStatement(location, new IdentifierExpression(location, "a")),
new ExpressionStatement(location, new IdentifierExpression(location, "b"))
});
var modified = new BlockStatement(location, new List<Statement>
{
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<Annotation>(),
new List<TypeParameter>(),
null,
new List<TypeReference>(),
new List<MemberDeclaration>
{
new FieldDeclaration(
location,
Modifiers.Private,
new List<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Int),
new List<VariableDeclarator>
{
new VariableDeclarator(location, "oldField", 0, null)
},
null
)
},
new List<TypeDeclaration>(),
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<MethodDeclaration>())
.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<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Void),
new List<TypeParameter>(),
new List<Parameter>
{
new Parameter(
location,
new ArrayType(location,
new ClassOrInterfaceType(location, "String", null, new List<TypeArgument>(), new List<Annotation>()),
1),
"args",
false,
false,
new List<Annotation>()
)
},
new List<TypeReference>(),
new BlockStatement(location, new List<Statement>()),
null
);
var helperMethod = new MethodDeclaration(
location,
"helper",
Modifiers.Private,
new List<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Void),
new List<TypeParameter>(),
new List<Parameter>(),
new List<TypeReference>(),
new BlockStatement(location, new List<Statement>()),
null
);
var field = new FieldDeclaration(
location,
Modifiers.Private,
new List<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Int),
new List<VariableDeclarator>
{
new VariableDeclarator(location, "count", 0, null)
},
null
);
var testClass = new ClassDeclaration(
location,
"TestClass",
Modifiers.Public,
new List<Annotation>(),
new List<TypeParameter>(),
null,
new List<TypeReference>(),
new List<MemberDeclaration> { mainMethod, helperMethod, field },
new List<TypeDeclaration>(),
null,
false
);
return new CompilationUnit(
location,
null,
new List<ImportDeclaration>(),
new List<TypeDeclaration> { testClass }
);
}
private CompilationUnit CreateComplexCompilationUnit()
{
var location = CreateLocation();
var serializableInterface = new ClassOrInterfaceType(
location,
"Serializable",
null,
new List<TypeArgument>(),
new List<Annotation>()
);
var serializeMethod = new MethodDeclaration(
location,
"serialize",
Modifiers.Public | Modifiers.Static,
new List<Annotation>(),
new PrimitiveType(location, PrimitiveTypeKind.Void),
new List<TypeParameter>(),
new List<Parameter>(),
new List<TypeReference>(),
null,
null
);
var dataClass = new ClassDeclaration(
location,
"DataClass",
Modifiers.Public,
new List<Annotation>(),
new List<TypeParameter>(),
null,
new List<TypeReference> { serializableInterface },
new List<MemberDeclaration> { serializeMethod },
new List<TypeDeclaration>(),
null,
false
);
return new CompilationUnit(
location,
null,
new List<ImportDeclaration>(),
new List<TypeDeclaration> { dataClass }
);
}
}
}