Skip to content

Commit

Permalink
JSON serialization refactoring and optimization (#1506)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomatosalat0 authored Mar 21, 2023
1 parent 590232c commit 675815c
Show file tree
Hide file tree
Showing 3 changed files with 505 additions and 170 deletions.
147 changes: 147 additions & 0 deletions Jint.Tests/Runtime/JsonSerializerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using Jint.Native;
using Jint.Native.Json;

namespace Jint.Tests.Runtime
{
public class JsonSerializerTests
{
[Fact]
public void CanStringifyBasicTypes()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

Assert.Equal("null", serializer.Serialize(JsValue.Null).ToString());
Assert.Equal("true", serializer.Serialize(JsBoolean.True).ToString());
Assert.Equal("false", serializer.Serialize(JsBoolean.False).ToString());
Assert.Equal("\"\"", serializer.Serialize(new JsString("")).ToString());
Assert.Equal("\"abc\"", serializer.Serialize(new JsString("abc")).ToString());
Assert.Equal("1", serializer.Serialize(new JsNumber(1)).ToString());
Assert.Equal("0.5", serializer.Serialize(new JsNumber(0.5)).ToString());
Assert.Equal("{}", serializer.Serialize(new JsObject(engine)).ToString());
Assert.Equal("[]", serializer.Serialize(new JsArray(engine)).ToString());

Assert.Same(JsValue.Undefined, serializer.Serialize(JsValue.Undefined));
}

[Fact]
public void EmptyObjectHasNoLineBreakWithSpaceDefined()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);
Assert.Equal("{}", serializer.Serialize(new JsObject(engine), JsValue.Undefined, new JsString(" ")).ToString());
}

[Fact]
public void EmptyArrayHasNoLineBreakWithSpaceDefined()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);
Assert.Equal("[]", serializer.Serialize(new JsArray(engine), JsValue.Undefined, new JsString(" ")).ToString());
}

[Fact]
public void StringCharactersGetEscaped()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

string actual = serializer.Serialize(new JsString("\"\\\t\r\n\f\r\b\ud834")).ToString();
Assert.Equal("\"\\\"\\\\\\t\\r\\n\\f\\r\\b\\ud834\"", actual);
}

[Fact]
public void JsonStringOutputIsIndentedWhenSpacerDefined()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsObject instance = new JsObject(engine);
instance["a"] = "b";
instance["b"] = 2;
instance["c"] = new JsArray(engine, new JsValue[] { new JsNumber(4), new JsNumber(5), new JsNumber(6) });
instance["d"] = true;

string actual = serializer.Serialize(instance, JsValue.Undefined, new JsNumber(2)).ToString();
Assert.Equal("{\n \"a\": \"b\",\n \"b\": 2,\n \"c\": [\n 4,\n 5,\n 6\n ],\n \"d\": true\n}", actual);
}

[Fact]
public void JsonStringOutputIsCompactWithoutSpacer()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsObject instance = new JsObject(engine);
instance["a"] = "b";
instance["b"] = 2;
instance["c"] = new JsArray(engine, new JsValue[] { new JsNumber(4), new JsNumber(5), new JsNumber(6) });
instance["d"] = true;

string actual = serializer.Serialize(instance, JsValue.Undefined, JsValue.Undefined).ToString();
Assert.Equal("{\"a\":\"b\",\"b\":2,\"c\":[4,5,6],\"d\":true}", actual);
}

[Fact]
public void ArrayWithUndefinedWillBeNull()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsArray array = new JsArray(engine, new JsValue[] { JsValue.Undefined, new JsNumber(42) });
string actual = serializer.Serialize(array, JsValue.Undefined, JsValue.Undefined).ToString();
Assert.Equal("[null,42]", actual);
}

[Fact]
public void ObjectPropertyWithUndefinedWillBeSkipped()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsObject instance = new JsObject(engine);
instance["a"] = JsValue.Undefined;
instance["b"] = 42;
string actual = serializer.Serialize(instance, JsValue.Undefined, JsValue.Undefined).ToString();
Assert.Equal("{\"b\":42}", actual);
}

[Fact]
public void NonStringObjectKeyWillSerializedAsString()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsObject instance = new JsObject(engine);
instance[JsValue.Undefined] = 10;
instance[JsValue.Null] = 21;
instance[new JsNumber(10)] = 42;
string actual = serializer.Serialize(instance, JsValue.Undefined, JsValue.Undefined).ToString();
Assert.Equal("{\"10\":42,\"undefined\":10,\"null\":21}", actual);
}

[Fact]
public void InfinityAndNaNGetsSerializedAsNull()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);
JsArray array = new JsArray(engine, new JsValue[] { JsNumber.DoubleNegativeInfinity, JsNumber.DoublePositiveInfinity, JsNumber.DoubleNaN });
string actual = serializer.Serialize(array, JsValue.Undefined, JsValue.Undefined).ToString();
Assert.Equal("[null,null,null]", actual);
}

[Fact]
public void ArrayAsReplacedDictatesPropertiesToSerializer()
{
using var engine = new Engine();
var serializer = new JsonSerializer(engine);

JsObject instance = new JsObject(engine);
instance["a"] = 21;
instance["b"] = 42;
JsValue replacer = new JsArray(engine, new JsValue[] { new JsString("b"), new JsString("z") });
string actual = serializer.Serialize(instance, replacer, JsValue.Undefined).ToString();
Assert.Equal("{\"b\":42}", actual);
}
}
}
Loading

0 comments on commit 675815c

Please sign in to comment.