Files
irongo/tests/IronGo.Tests/SerializationTests/JsonSerializationTests.cs
2025-07-23 00:47:04 -04:00

253 lines
6.8 KiB
C#

using FluentAssertions;
using MarketAlly.IronGo;
using MarketAlly.IronGo.AST;
using MarketAlly.IronGo.Serialization;
using System.Text.Json;
using Xunit;
namespace MarketAlly.IronGo.Tests.SerializationTests;
public class JsonSerializationTests
{
[Fact]
public void ToJson_ShouldSerializeSimpleAST()
{
// Arrange
const string source = @"
package main
func hello() {
println(""Hello, World!"")
}";
var ast = IronGoParser.Parse(source);
// Act
var json = ast.ToJson();
// Assert
json.Should().NotBeNullOrWhiteSpace();
json.Should().Contain("\"Type\": \"SourceFile\"");
json.Should().Contain("\"Package\":");
json.Should().Contain("\"Name\": \"main\"");
json.Should().Contain("\"Declarations\":");
json.Should().Contain("\"Type\": \"FunctionDeclaration\"");
json.Should().Contain("\"Name\": \"hello\"");
}
[Fact]
public void ToJsonCompact_ShouldProduceCompactJson()
{
// Arrange
const string source = "package main";
var ast = IronGoParser.Parse(source);
// Act
var compact = ast.ToJsonCompact();
var pretty = ast.ToJsonPretty();
// Assert
compact.Should().NotContain("\n");
compact.Should().NotContain(" ");
pretty.Should().Contain("\n");
pretty.Should().Contain(" ");
compact.Length.Should().BeLessThan(pretty.Length);
}
[Fact]
public void SerializeExpression_ShouldHandleComplexExpressions()
{
// Arrange
const string source = @"
package main
func test() {
result := (a + b) * c / d
}";
var ast = IronGoParser.Parse(source);
var function = ast.Declarations[0] as FunctionDeclaration;
var statement = function!.Body!.Statements[0] as ShortVariableDeclaration;
var expression = statement!.Values[0];
// Act
var json = expression.ToJson();
var doc = JsonDocument.Parse(json);
// Assert
doc.RootElement.GetProperty("Type").GetString().Should().Be("BinaryExpression");
doc.RootElement.GetProperty("Operator").GetString().Should().Be("Divide");
doc.RootElement.GetProperty("Left").GetProperty("Type").GetString().Should().Be("BinaryExpression");
}
[Fact]
public void SerializeTypes_ShouldHandleAllTypeVariants()
{
// Arrange
const string source = @"
package main
type (
Int int
Ptr *int
Slice []string
Array [10]byte
Map map[string]int
Chan chan int
Func func(int) error
Struct struct { X, Y int }
Interface interface { Method() }
)";
var ast = IronGoParser.Parse(source);
// Act
var json = ast.ToJson();
// Assert
json.Should().Contain("\"Type\": \"IdentifierType\"");
json.Should().Contain("\"Type\": \"PointerType\"");
json.Should().Contain("\"Type\": \"SliceType\"");
json.Should().Contain("\"Type\": \"ArrayType\"");
json.Should().Contain("\"Type\": \"MapType\"");
json.Should().Contain("\"Type\": \"ChannelType\"");
json.Should().Contain("\"Type\": \"FunctionType\"");
json.Should().Contain("\"Type\": \"StructType\"");
json.Should().Contain("\"Type\": \"InterfaceType\"");
}
[Fact]
public void SerializeStatements_ShouldHandleAllStatementTypes()
{
// Arrange
const string source = @"
package main
func test() {
x := 10
var y int
if x > 5 { }
for i := 0; i < 10; i++ { }
switch x { case 1: }
defer cleanup()
go process()
return x
break
continue
}";
var ast = IronGoParser.Parse(source);
var function = ast.Declarations[0] as FunctionDeclaration;
// Act
var json = function!.Body!.ToJson();
// Assert
json.Should().Contain("\"Type\": \"ShortVariableDeclaration\"");
json.Should().Contain("\"Type\": \"DeclarationStatement\"");
json.Should().Contain("\"Type\": \"IfStatement\"");
json.Should().Contain("\"Type\": \"ForStatement\"");
json.Should().Contain("\"Type\": \"SwitchStatement\"");
json.Should().Contain("\"Type\": \"DeferStatement\"");
json.Should().Contain("\"Type\": \"GoStatement\"");
json.Should().Contain("\"Type\": \"ReturnStatement\"");
json.Should().Contain("\"Type\": \"BranchStatement\"");
}
[Fact]
public void SerializeLiterals_ShouldPreserveValues()
{
// Arrange
const string source = @"
package main
func test() {
s := ""hello""
i := 42
f := 3.14
b := true
r := 'x'
}";
var ast = IronGoParser.Parse(source);
// Act
var json = ast.ToJson();
var doc = JsonDocument.Parse(json);
// Assert
json.Should().Contain("\"Value\": \"hello\"");
json.Should().Contain("\"Value\": \"42\"");
json.Should().Contain("\"Value\": \"3.14\"");
json.Should().Contain("\"Value\": \"true\"");
json.Should().Contain("\"Value\": \"x\"");
}
[Fact]
public void SerializePosition_ShouldIncludePositionInfo()
{
// Arrange
const string source = "package main";
var ast = IronGoParser.Parse(source);
// Act
var json = ast.Package!.ToJson();
var doc = JsonDocument.Parse(json);
// Assert
doc.RootElement.TryGetProperty("Start", out _).Should().BeTrue();
doc.RootElement.TryGetProperty("End", out _).Should().BeTrue();
var start = doc.RootElement.GetProperty("Start");
start.GetProperty("Line").GetInt32().Should().Be(1);
start.GetProperty("Column").GetInt32().Should().Be(1);
}
[Fact]
public void SerializeComments_ShouldIncludeComments()
{
// Arrange
const string source = @"
package main
// HelloWorld prints a greeting
func HelloWorld() {
// Print to stdout
println(""Hello, World!"")
}";
var ast = IronGoParser.Parse(source);
var function = ast.Declarations[0] as FunctionDeclaration;
// Act
var json = function!.ToJson();
// Assert
// Comments would be included if properly parsed
json.Should().Contain("HelloWorld");
}
[Fact]
public void RoundTrip_ShouldProduceSameJson()
{
// Arrange
const string source = @"
package main
import ""fmt""
func main() {
fmt.Println(""test"")
}";
// Act
var ast1 = IronGoParser.Parse(source);
var json1 = ast1.ToJson();
var ast2 = IronGoParser.Parse(source);
var json2 = ast2.ToJson();
// Assert
json1.Should().Be(json2);
}
}