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
413 lines
14 KiB
C#
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 }
|
|
);
|
|
}
|
|
}
|
|
} |