Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4cec1c6a20 | |||
| 76a8e350e6 | |||
| d3c6e34350 | |||
| 8382f7f9ea | |||
| 5e6b51506e | |||
| 79183c8b68 | |||
| 18f2fd0b7a | |||
| 9d4c2c170d | |||
| fb58fa8109 | |||
| 00664880fb | |||
| 814800200f | |||
| 2f81aaa73c | |||
| c3f3049174 | |||
| 09bdde310d | |||
| d02a598035 | |||
| 180a5f0065 | |||
| 53a947db75 | |||
| 6782200917 | |||
| 47f20e03e8 | |||
| 73ab9292e7 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -27,3 +27,5 @@ obj/
|
||||
_ReSharper*/
|
||||
*.userprefs
|
||||
*.nupkg
|
||||
/.vs/*
|
||||
/packages/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2017 Valeriano Alfonso Rodriguez
|
||||
Copyright (c) 2016-2020 Valeriano Alfonso Rodriguez
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
16
README.md
16
README.md
@@ -5,23 +5,23 @@
|
||||
### VAR.Json
|
||||
Add the resulting assembly as reference in your projects, and this line on code:
|
||||
|
||||
using VAR.Json;
|
||||
using VAR.Json;
|
||||
|
||||
Parse any string with JSON content:
|
||||
|
||||
var jsonParser = new JsonParser();
|
||||
object result = jsonParser("{\"Test\": 1}");
|
||||
|
||||
var jsonParser = new JsonParser();
|
||||
object result = jsonParser("{\"Test\": 1}");
|
||||
|
||||
Serialize any object to JSON:
|
||||
|
||||
var jsonWriter = new JsonWriter();
|
||||
string jsonText = jsonWriter(new List<int>{1, 2, 3, 4});
|
||||
|
||||
var jsonWriter = new JsonWriter();
|
||||
string jsonText = jsonWriter(new List<int>{1, 2, 3, 4});
|
||||
|
||||
## Building
|
||||
A Visual Studio 2015 solutions are provided. Simply, click build on the IDE.
|
||||
|
||||
A .nuget package can be build using:
|
||||
VAR.Json\Build.NuGet.cmd
|
||||
VAR.Json\Build.NuGet.cmd
|
||||
|
||||
## Contributing
|
||||
1. Fork it!
|
||||
|
||||
479
VAR.Json.Tests/JsonParser_Tests.cs
Normal file
479
VAR.Json.Tests/JsonParser_Tests.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace VAR.Json.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class JsonParser_Tests
|
||||
{
|
||||
#region Parse
|
||||
|
||||
public class SwallowObject
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Number { get; set; }
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__SwallowObject()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
SwallowObject result = parser.Parse(@"{""Text"": ""AAAA"", ""Number"": 42}") as SwallowObject;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual("AAAA", result.Text);
|
||||
Assert.AreEqual(42, result.Number);
|
||||
}
|
||||
|
||||
public class DeeperObject_L1
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public SwallowObject Object { get; set; }
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__DeeperObject_L1()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
parser.KnownTypes.Add(typeof(DeeperObject_L1));
|
||||
DeeperObject_L1 result = parser.Parse(@"{""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}") as DeeperObject_L1;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual("Thing", result.Name);
|
||||
Assert.AreEqual("AAAA", result.Object.Text);
|
||||
Assert.AreEqual(42, result.Object.Number);
|
||||
}
|
||||
|
||||
public class DeeperObject_L2
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public DeeperObject_L1 Object { get; set; }
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__DeeperObject_L2()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
parser.KnownTypes.Add(typeof(DeeperObject_L1));
|
||||
parser.KnownTypes.Add(typeof(DeeperObject_L2));
|
||||
DeeperObject_L2 result = parser.Parse(@"{""Count"": 1, ""Object"": {""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}}") as DeeperObject_L2;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("Thing", result.Object.Name);
|
||||
Assert.AreEqual("AAAA", result.Object.Object.Text);
|
||||
Assert.AreEqual(42, result.Object.Object.Number);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__SwallowObjectArray()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
List<SwallowObject> result = parser.Parse(@"[{""Text"": ""AAAA"", ""Number"": 42}]") as List<SwallowObject>;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("AAAA", result[0].Text);
|
||||
Assert.AreEqual(42, result[0].Number);
|
||||
}
|
||||
|
||||
public class DeeperObjectArray_L1
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public List<SwallowObject> Array { get; set; }
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__DeeperObjectArray_L1()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
|
||||
DeeperObjectArray_L1 result = parser.Parse(@"{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}") as DeeperObjectArray_L1;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("AAAA", result.Array[0].Text);
|
||||
Assert.AreEqual(42, result.Array[0].Number);
|
||||
}
|
||||
|
||||
public class DeeperObjectArray_L2
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<DeeperObjectArray_L1> Objects { get; set; }
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__DeeperObjectArray_L2()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
parser.KnownTypes.Add(typeof(SwallowObject));
|
||||
parser.KnownTypes.Add(typeof(DeeperObjectArray_L1));
|
||||
parser.KnownTypes.Add(typeof(DeeperObjectArray_L2));
|
||||
DeeperObjectArray_L2 result = parser.Parse(@"{""Name"": ""Thing"", ""Objects"": [{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}]}") as DeeperObjectArray_L2;
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
Assert.AreEqual("Thing", result.Name);
|
||||
Assert.AreEqual(1, result.Objects[0].Count);
|
||||
Assert.AreEqual("AAAA", result.Objects[0].Array[0].Text);
|
||||
Assert.AreEqual(42, result.Objects[0].Array[0].Number);
|
||||
}
|
||||
|
||||
#endregion Parse
|
||||
|
||||
#region Validity tests
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail01()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"""A JSON payload should be an object or array, not a string.""");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail02()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Unclosed array""");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail03()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{unquoted_key: ""keys must be quoted""}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail04()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""extra comma"",]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail05()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""double extra comma"",,]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail06()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[ , ""<-- missing value""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail07()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Comma after the close""],");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail08()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Extra close""]]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail09()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Extra comma"": true,}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail10()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Extra value after close"": true} ""misplaced quoted value""");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail11()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Illegal expression"": 1 + 2}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail12()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Illegal invocation"": alert()}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail13()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Numbers cannot have leading zeroes"": 013}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail14()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Numbers cannot be hex"": 0x14}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail15()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Illegal backslash escape: \x15""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail16()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[\naked]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail17()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Illegal backslash escape: \017""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail18()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[[[[[[[[[[[[[[[[[[[[""Too deep""]]]]]]]]]]]]]]]]]]]]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail19()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Missing colon"" null}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail20()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Double colon"":: null}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail21()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Comma instead of colon"", null}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail22()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Colon instead of comma"": false]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail23()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""Bad value"", truth]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail24()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"['single quote']");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail25()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"["" tab character in string ""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail26()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""tab\ character\ in\ string\ ""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail27()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""line
|
||||
break""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail28()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""line\
|
||||
break""]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail29()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[0e]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail30()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[0e+]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail31()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[0e+-1]");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail32()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{""Comma instead if closing brace"": true,");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Fail33()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[""mismatch""}");
|
||||
Assert.AreEqual(true, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Pass01()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[
|
||||
""JSON Test Pattern pass1"",
|
||||
{""object with 1 member"":[""array with 1 element""]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
""integer"": 1234567890,
|
||||
""real"": -9876.543210,
|
||||
""e"": 0.123456789e-12,
|
||||
""E"": 1.234567890E+34,
|
||||
"""": 23456789012E66,
|
||||
""zero"": 0,
|
||||
""one"": 1,
|
||||
""space"": "" "",
|
||||
""quote"": ""\"""",
|
||||
""backslash"": ""\\"",
|
||||
""controls"": ""\b\f\n\r\t"",
|
||||
""slash"": ""/ & \/"",
|
||||
""alpha"": ""abcdefghijklmnopqrstuvwyz"",
|
||||
""ALPHA"": ""ABCDEFGHIJKLMNOPQRSTUVWYZ"",
|
||||
""digit"": ""0123456789"",
|
||||
""0123456789"": ""digit"",
|
||||
""special"": ""`1~!@#$%^&*()_+-={':[,]}|;.</>?"",
|
||||
""hex"": ""\u0123\u4567\u89AB\uCDEF\uabcd\uef4A"",
|
||||
""true"": true,
|
||||
""false"": false,
|
||||
""null"": null,
|
||||
""array"":[ ],
|
||||
""object"":{ },
|
||||
""address"": ""50 St. James Street"",
|
||||
""url"": ""http://www.JSON.org/"",
|
||||
""comment"": ""// /* <!-- --"",
|
||||
""# -- --> */"": "" "",
|
||||
"" s p a c e d "" :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],""compact"":[1,2,3,4,5,6,7],
|
||||
""jsontext"": ""{\""object with 1 member\"":[\""array with 1 element\""]}"",
|
||||
""quotes"": """ \u0022 %22 0x22 034 """,
|
||||
""\/\\\""\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?""
|
||||
: ""A key can be any string""
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,""rosebud""]");
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Pass02()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"[[[[[[[[[[[[[[[[[[[""Not too deep""]]]]]]]]]]]]]]]]]]]");
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void Parse__Validity_Pass03()
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result = parser.Parse(@"{
|
||||
""JSON Test Pattern pass3"": {
|
||||
""The outermost value"": ""must be an object or array."",
|
||||
""In this test"": ""It is an object.""
|
||||
}
|
||||
}
|
||||
");
|
||||
Assert.AreEqual(false, parser.Tainted);
|
||||
}
|
||||
|
||||
#endregion Validity tests
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace VAR.Json.Tests
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// http://www.json.org/JSON_checker/
|
||||
|
||||
string currentPath = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||
currentPath = FindPath(currentPath, "tests");
|
||||
|
||||
// Test all files
|
||||
string[] files;
|
||||
files = Directory.GetFiles(currentPath, "*.json");
|
||||
foreach (string file in files)
|
||||
{
|
||||
TestFile(file);
|
||||
}
|
||||
|
||||
Console.Read();
|
||||
}
|
||||
|
||||
private static void TestFile(string fileName)
|
||||
{
|
||||
string testName = Path.GetFileNameWithoutExtension(fileName);
|
||||
string fileContent = File.ReadAllText(fileName, Encoding.UTF8);
|
||||
if (testName.StartsWith("fail"))
|
||||
{
|
||||
TestFailCase(testName, fileContent);
|
||||
}
|
||||
if (testName.StartsWith("pass"))
|
||||
{
|
||||
TestPassCase(testName, fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestFailCase(string testName, string fileContent)
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = parser.Parse(fileContent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OutputFailure(testName, fileContent, ex);
|
||||
return;
|
||||
}
|
||||
if (parser.Tainted == false)
|
||||
{
|
||||
OutputFailure(testName, fileContent, result);
|
||||
return;
|
||||
}
|
||||
Console.Out.WriteLine("OK! {0}", testName);
|
||||
}
|
||||
|
||||
private static void TestPassCase(string testName, string fileContent)
|
||||
{
|
||||
JsonParser parser = new JsonParser();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = parser.Parse(fileContent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OutputFailure(testName, fileContent, ex);
|
||||
return;
|
||||
}
|
||||
if (parser.Tainted)
|
||||
{
|
||||
OutputFailure(testName, fileContent, result);
|
||||
return;
|
||||
}
|
||||
Console.Out.WriteLine("OK! {0}", testName);
|
||||
}
|
||||
|
||||
private static void OutputFailure(string testName, string fileContent, object obj)
|
||||
{
|
||||
Console.Out.WriteLine("Failure! {0}", testName);
|
||||
Console.Out.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
Console.Out.WriteLine("Content:\n{0}", fileContent);
|
||||
Console.Out.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
if (obj is Exception)
|
||||
{
|
||||
Exception ex = obj as Exception;
|
||||
Console.Out.WriteLine("Ex.Message: {0}", ex.Message);
|
||||
Console.Out.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
Console.Out.WriteLine("Ex.Stacktrace:\n{0}", ex.StackTrace);
|
||||
Console.Out.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
}
|
||||
if (obj != null && (obj is Exception) == false)
|
||||
{
|
||||
JsonWriter writter = new JsonWriter(true);
|
||||
Console.Out.WriteLine("Parsed:\n{0}", writter.Write(obj));
|
||||
Console.Out.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindPath(string currentPath, string directory)
|
||||
{
|
||||
do
|
||||
{
|
||||
string testPath = Path.Combine(currentPath, directory);
|
||||
if (Directory.Exists(testPath))
|
||||
{
|
||||
currentPath = testPath;
|
||||
Console.Out.WriteLine(testPath);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DirectoryInfo dirInfo = Directory.GetParent(currentPath);
|
||||
if (dirInfo == null)
|
||||
{
|
||||
throw new Exception(string.Format("FindPath: Directory {0} not found", directory));
|
||||
}
|
||||
currentPath = dirInfo.ToString();
|
||||
}
|
||||
} while (string.IsNullOrEmpty(currentPath) == false);
|
||||
return currentPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("VAR.Json.Tests")]
|
||||
[assembly: AssemblyDescription("Json Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("VAR")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("VAR.Json.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © VAR 2016")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("576297b8-423d-4533-b75a-f186ccff0d2a")]
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b92ac920-87d7-46de-afd8-d9c5eff7debe")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{576297B8-423D-4533-B75A-F186CCFF0D2A}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<ProjectGuid>{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>VAR.Json.Tests</RootNamespace>
|
||||
<AssemblyName>VAR.Json.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
@@ -24,7 +31,6 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@@ -33,58 +39,63 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<Otherwise />
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="JsonParser_Tests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="tests\fail01.json" />
|
||||
<None Include="tests\fail10.json" />
|
||||
<None Include="tests\fail11.json" />
|
||||
<None Include="tests\fail12.json" />
|
||||
<None Include="tests\fail13.json" />
|
||||
<None Include="tests\fail14.json" />
|
||||
<None Include="tests\fail15.json" />
|
||||
<None Include="tests\fail16.json" />
|
||||
<None Include="tests\fail17.json" />
|
||||
<None Include="tests\fail18.json" />
|
||||
<None Include="tests\fail19.json" />
|
||||
<None Include="tests\fail02.json" />
|
||||
<None Include="tests\fail20.json" />
|
||||
<None Include="tests\fail21.json" />
|
||||
<None Include="tests\fail22.json" />
|
||||
<None Include="tests\fail23.json" />
|
||||
<None Include="tests\fail24.json" />
|
||||
<None Include="tests\fail25.json" />
|
||||
<None Include="tests\fail26.json" />
|
||||
<None Include="tests\fail27.json" />
|
||||
<None Include="tests\fail28.json" />
|
||||
<None Include="tests\fail29.json" />
|
||||
<None Include="tests\fail03.json" />
|
||||
<None Include="tests\fail30.json" />
|
||||
<None Include="tests\fail31.json" />
|
||||
<None Include="tests\fail32.json" />
|
||||
<None Include="tests\fail33.json" />
|
||||
<None Include="tests\fail04.json" />
|
||||
<None Include="tests\fail05.json" />
|
||||
<None Include="tests\fail06.json" />
|
||||
<None Include="tests\fail07.json" />
|
||||
<None Include="tests\fail08.json" />
|
||||
<None Include="tests\fail09.json" />
|
||||
<None Include="tests\pass01.json" />
|
||||
<None Include="tests\pass02.json" />
|
||||
<None Include="tests\pass03.json" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VAR.Json\VAR.Json.csproj">
|
||||
<Project>{28b3f937-145c-4fd4-a75b-a25ea4cc0428}</Project>
|
||||
<Project>{28B3F937-145C-4FD4-A75B-A25EA4CC0428}</Project>
|
||||
<Name>VAR.Json</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
5
VAR.Json.Tests/packages.config
Normal file
5
VAR.Json.Tests/packages.config
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MSTest.TestAdapter" version="2.1.1" targetFramework="net461" />
|
||||
<package id="MSTest.TestFramework" version="2.1.1" targetFramework="net461" />
|
||||
</packages>
|
||||
@@ -1 +0,0 @@
|
||||
"A JSON payload should be an object or array, not a string."
|
||||
@@ -1 +0,0 @@
|
||||
["Unclosed array"
|
||||
@@ -1 +0,0 @@
|
||||
{unquoted_key: "keys must be quoted"}
|
||||
@@ -1 +0,0 @@
|
||||
["extra comma",]
|
||||
@@ -1 +0,0 @@
|
||||
["double extra comma",,]
|
||||
@@ -1 +0,0 @@
|
||||
[ , "<-- missing value"]
|
||||
@@ -1 +0,0 @@
|
||||
["Comma after the close"],
|
||||
@@ -1 +0,0 @@
|
||||
["Extra close"]]
|
||||
@@ -1 +0,0 @@
|
||||
{"Extra comma": true,}
|
||||
@@ -1 +0,0 @@
|
||||
{"Extra value after close": true} "misplaced quoted value"
|
||||
@@ -1 +0,0 @@
|
||||
{"Illegal expression": 1 + 2}
|
||||
@@ -1 +0,0 @@
|
||||
{"Illegal invocation": alert()}
|
||||
@@ -1 +0,0 @@
|
||||
{"Numbers cannot have leading zeroes": 013}
|
||||
@@ -1 +0,0 @@
|
||||
{"Numbers cannot be hex": 0x14}
|
||||
@@ -1 +0,0 @@
|
||||
["Illegal backslash escape: \x15"]
|
||||
@@ -1 +0,0 @@
|
||||
[\naked]
|
||||
@@ -1 +0,0 @@
|
||||
["Illegal backslash escape: \017"]
|
||||
@@ -1 +0,0 @@
|
||||
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
||||
@@ -1 +0,0 @@
|
||||
{"Missing colon" null}
|
||||
@@ -1 +0,0 @@
|
||||
{"Double colon":: null}
|
||||
@@ -1 +0,0 @@
|
||||
{"Comma instead of colon", null}
|
||||
@@ -1 +0,0 @@
|
||||
["Colon instead of comma": false]
|
||||
@@ -1 +0,0 @@
|
||||
["Bad value", truth]
|
||||
@@ -1 +0,0 @@
|
||||
['single quote']
|
||||
@@ -1 +0,0 @@
|
||||
[" tab character in string "]
|
||||
@@ -1 +0,0 @@
|
||||
["tab\ character\ in\ string\ "]
|
||||
@@ -1,2 +0,0 @@
|
||||
["line
|
||||
break"]
|
||||
@@ -1,2 +0,0 @@
|
||||
["line\
|
||||
break"]
|
||||
@@ -1 +0,0 @@
|
||||
[0e]
|
||||
@@ -1 +0,0 @@
|
||||
[0e+]
|
||||
@@ -1 +0,0 @@
|
||||
[0e+-1]
|
||||
@@ -1 +0,0 @@
|
||||
{"Comma instead if closing brace": true,
|
||||
@@ -1 +0,0 @@
|
||||
["mismatch"}
|
||||
@@ -1,58 +0,0 @@
|
||||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
||||
@@ -1 +0,0 @@
|
||||
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"JSON Test Pattern pass3": {
|
||||
"The outermost value": "must be an object or array.",
|
||||
"In this test": "It is an object."
|
||||
}
|
||||
}
|
||||
19
VAR.Json.sln
19
VAR.Json.sln
@@ -1,18 +1,18 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30330.147
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.Json", "VAR.Json\VAR.Json.csproj", "{28B3F937-145C-4FD4-A75B-A25EA4CC0428}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.Json.Tests", "VAR.Json.Tests\VAR.Json.Tests.csproj", "{576297B8-423D-4533-B75A-F186CCFF0D2A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notes", "Notes", "{4C23A421-5348-48F1-8B67-A4D43E616FDE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
LICENSE.txt = LICENSE.txt
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.Json.Tests", "VAR.Json.Tests\VAR.Json.Tests.csproj", "{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -23,12 +23,15 @@ Global
|
||||
{28B3F937-145C-4FD4-A75B-A25EA4CC0428}.Debug|Any CPU.Build.0 = Debug .Net 4.6.1|Any CPU
|
||||
{28B3F937-145C-4FD4-A75B-A25EA4CC0428}.Release|Any CPU.ActiveCfg = Release .Net 4.6.1|Any CPU
|
||||
{28B3F937-145C-4FD4-A75B-A25EA4CC0428}.Release|Any CPU.Build.0 = Release .Net 4.6.1|Any CPU
|
||||
{576297B8-423D-4533-B75A-F186CCFF0D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{576297B8-423D-4533-B75A-F186CCFF0D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{576297B8-423D-4533-B75A-F186CCFF0D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{576297B8-423D-4533-B75A-F186CCFF0D2A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B92AC920-87D7-46DE-AFD8-D9C5EFF7DEBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B9700B54-1919-4B81-B123-D4D3DE74124A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace VAR.Json
|
||||
private ParserContext _ctx;
|
||||
private bool _tainted = false;
|
||||
|
||||
private List<Type> _knownTypes = new List<Type>();
|
||||
private readonly List<Type> _knownTypes = new List<Type>();
|
||||
|
||||
#endregion Declarations
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace VAR.Json
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static Dictionary<Type, PropertyInfo[]> _dictProperties = new Dictionary<Type, PropertyInfo[]>();
|
||||
private static readonly Dictionary<Type, PropertyInfo[]> _dictProperties = new Dictionary<Type, PropertyInfo[]>();
|
||||
|
||||
private PropertyInfo[] Type_GetProperties(Type type)
|
||||
{
|
||||
@@ -92,7 +92,14 @@ namespace VAR.Json
|
||||
}
|
||||
else
|
||||
{
|
||||
valueDest = Convert.ChangeType(obj[prop.Name], effectiveType);
|
||||
try
|
||||
{
|
||||
valueDest = Convert.ChangeType(obj[prop.Name], effectiveType);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prop.SetValue(newObj, valueDest, null);
|
||||
}
|
||||
@@ -115,7 +122,12 @@ namespace VAR.Json
|
||||
}
|
||||
if (bestMatch != null)
|
||||
{
|
||||
return ConvertToType(obj, bestMatch);
|
||||
try
|
||||
{
|
||||
object newObj = ConvertToType(obj, bestMatch);
|
||||
return newObj;
|
||||
}
|
||||
catch (Exception) { } /* Nom Nom */
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@@ -416,7 +428,7 @@ namespace VAR.Json
|
||||
}
|
||||
}
|
||||
|
||||
private List<object> ParseArray(int recursiveCount = 1)
|
||||
private object ParseArray(int recursiveCount = 1)
|
||||
{
|
||||
// StrictRules: Mark as tainted when MaxRecursiveCount is exceeded
|
||||
if (recursiveCount >= MaxRecursiveCount) { _tainted = true; }
|
||||
@@ -424,6 +436,9 @@ namespace VAR.Json
|
||||
bool correct = false;
|
||||
char c = _ctx.SkipWhite();
|
||||
List<object> array = new List<object>();
|
||||
Type arrayContentType = null;
|
||||
bool hasSameType = true;
|
||||
bool hasNulls = false;
|
||||
if (c == '[')
|
||||
{
|
||||
_ctx.Next();
|
||||
@@ -452,19 +467,44 @@ namespace VAR.Json
|
||||
{
|
||||
// StrictRules: Mark as tainted when unexpected value on array
|
||||
if (expectValue == false) { _tainted = true; }
|
||||
|
||||
array.Add(ParseValue(recursiveCount + 1));
|
||||
object value = ParseValue(recursiveCount + 1);
|
||||
array.Add(value);
|
||||
expectValue = false;
|
||||
|
||||
if (hasSameType)
|
||||
{
|
||||
Type valueType = value?.GetType();
|
||||
if (valueType == null) { hasNulls = true; }
|
||||
if (arrayContentType == null || arrayContentType == valueType)
|
||||
{
|
||||
arrayContentType = valueType;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasSameType = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!_ctx.AtEnd());
|
||||
if (correct == false)
|
||||
{
|
||||
_tainted = true;
|
||||
}
|
||||
return array;
|
||||
object result = array;
|
||||
bool isNullableType = arrayContentType?.IsClass == true;
|
||||
if (hasSameType && arrayContentType != null && (isNullableType == true || (isNullableType == false && hasNulls == false)))
|
||||
{
|
||||
var enumerableType = typeof(System.Linq.Enumerable);
|
||||
var castMethod = enumerableType.GetMethod("Cast").MakeGenericMethod(arrayContentType);
|
||||
var toListMethod = enumerableType.GetMethod("ToList").MakeGenericMethod(arrayContentType);
|
||||
IEnumerable<object> itemsToCast = array;
|
||||
var castedItems = castMethod.Invoke(null, new[] { itemsToCast });
|
||||
result = toListMethod.Invoke(null, new[] { castedItems });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Dictionary<string, object> ParseObject(int recursiveCount = 1)
|
||||
private object ParseObject(int recursiveCount = 1)
|
||||
{
|
||||
// StrictRules: Mark as tainted when MaxRecursiveCount is exceeded
|
||||
if (recursiveCount >= MaxRecursiveCount) { _tainted = true; }
|
||||
@@ -497,14 +537,14 @@ namespace VAR.Json
|
||||
else if (c == ',')
|
||||
{
|
||||
_ctx.Next();
|
||||
c = _ctx.SkipWhite();
|
||||
_ctx.SkipWhite();
|
||||
expectedKey = true;
|
||||
expectedValue = false;
|
||||
}
|
||||
else if (c == '}')
|
||||
{
|
||||
// StrictRules: Mark as tainted on unexpected end of object
|
||||
if(expectedValue == true || expectedKey == true)
|
||||
if (expectedValue == true || expectedKey == true)
|
||||
{
|
||||
_tainted = true;
|
||||
}
|
||||
@@ -517,7 +557,7 @@ namespace VAR.Json
|
||||
if (expectedKey != false)
|
||||
{
|
||||
attributeName = ParseString(true);
|
||||
c = _ctx.SkipWhite();
|
||||
_ctx.SkipWhite();
|
||||
expectedKey = false;
|
||||
expectedValue = true;
|
||||
}
|
||||
@@ -533,13 +573,14 @@ namespace VAR.Json
|
||||
{
|
||||
_tainted = true;
|
||||
}
|
||||
return obj;
|
||||
object result = TryConvertToTypes(obj);
|
||||
return result;
|
||||
}
|
||||
|
||||
private object ParseValue(int recusiveCount = 1)
|
||||
{
|
||||
object token = null;
|
||||
char c = _ctx.SkipWhite();
|
||||
object token;
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
@@ -551,10 +592,9 @@ namespace VAR.Json
|
||||
_tainted = true;
|
||||
token = ParseSingleQuotedString();
|
||||
break;
|
||||
|
||||
|
||||
case '{':
|
||||
Dictionary<string, object> obj = ParseObject(recusiveCount);
|
||||
token = TryConvertToTypes(obj);
|
||||
token = ParseObject(recusiveCount);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
@@ -597,28 +637,6 @@ namespace VAR.Json
|
||||
return token;
|
||||
}
|
||||
|
||||
private string CleanIdentifier(string input)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
i = input.Length - 1;
|
||||
if (i < 0)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
c = input[i];
|
||||
while (char.IsLetter(c) || char.IsDigit(c) || c == '_')
|
||||
{
|
||||
i--;
|
||||
if (i < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
c = input[i];
|
||||
}
|
||||
return input.Substring(i + 1);
|
||||
}
|
||||
|
||||
#endregion Private methods
|
||||
|
||||
#region Public methods
|
||||
@@ -648,6 +666,19 @@ namespace VAR.Json
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonParser _currentInstance = null;
|
||||
|
||||
public static object ParseText(string text, params Type[] knownTypes)
|
||||
{
|
||||
if (_currentInstance == null)
|
||||
{
|
||||
_currentInstance = new JsonParser();
|
||||
}
|
||||
_currentInstance.KnownTypes.Clear();
|
||||
_currentInstance.KnownTypes.AddRange(knownTypes);
|
||||
return _currentInstance.Parse(text);
|
||||
}
|
||||
|
||||
#endregion Public methods
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,79 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace VAR.Json
|
||||
{
|
||||
public class JsonWriterConfiguration
|
||||
{
|
||||
private bool _indent;
|
||||
public bool Indent { get { return _indent; } }
|
||||
|
||||
private bool _useTabForIndent;
|
||||
public bool UseTabForIndent { get { return _useTabForIndent; } }
|
||||
|
||||
private int _indentChars;
|
||||
public int IndentChars { get { return _indentChars; } }
|
||||
|
||||
private int _indentThresold;
|
||||
public int IndentThresold { get { return _indentThresold; } }
|
||||
|
||||
public JsonWriterConfiguration(
|
||||
bool indent = false,
|
||||
bool useTabForIndent = false,
|
||||
int indentChars = 4,
|
||||
int indentThresold = 3)
|
||||
{
|
||||
_indent = indent;
|
||||
_useTabForIndent = useTabForIndent;
|
||||
_indentChars = indentChars;
|
||||
_indentThresold = indentThresold;
|
||||
}
|
||||
|
||||
public bool Equals(JsonWriterConfiguration other)
|
||||
{
|
||||
return
|
||||
other.Indent == Indent &&
|
||||
other.UseTabForIndent == UseTabForIndent &&
|
||||
other.IndentChars == IndentChars &&
|
||||
other.IndentThresold == IndentThresold &&
|
||||
true;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (other is JsonWriterConfiguration)
|
||||
{
|
||||
return Equals(other as JsonWriterConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _indent.GetHashCode() ^ _useTabForIndent.GetHashCode() ^ _indentChars.GetHashCode() ^ _indentThresold.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonWriter
|
||||
{
|
||||
#region Declarations
|
||||
|
||||
private bool _indent = false;
|
||||
private bool _useTabForIndent = false;
|
||||
private int _indentChars = 4;
|
||||
private int _indentThresold = 3;
|
||||
private JsonWriterConfiguration _config = null;
|
||||
|
||||
#endregion Declarations
|
||||
|
||||
#region Creator
|
||||
|
||||
public JsonWriter()
|
||||
public JsonWriter(JsonWriterConfiguration config = null)
|
||||
{
|
||||
}
|
||||
|
||||
public JsonWriter(int indentChars)
|
||||
{
|
||||
_indent = true;
|
||||
_indentChars = indentChars;
|
||||
_useTabForIndent = false;
|
||||
}
|
||||
|
||||
public JsonWriter(bool useTabForIndent)
|
||||
{
|
||||
_indent = true;
|
||||
_useTabForIndent = useTabForIndent;
|
||||
_config = config;
|
||||
if (_config == null)
|
||||
{
|
||||
_config = new JsonWriterConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Creator
|
||||
@@ -61,52 +101,52 @@ namespace VAR.Json
|
||||
return false;
|
||||
}
|
||||
|
||||
private void WriteIndent(StringBuilder sbOutput, int level)
|
||||
private void WriteIndent(TextWriter textWriter, int level)
|
||||
{
|
||||
if (!_indent)
|
||||
if (!_config.Indent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sbOutput.Append('\n');
|
||||
if (_useTabForIndent)
|
||||
textWriter.Write('\n');
|
||||
if (_config.UseTabForIndent)
|
||||
{
|
||||
for (int i = 0; i < level; i++) { sbOutput.Append('\t'); }
|
||||
for (int i = 0; i < level; i++) { textWriter.Write('\t'); }
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = level * _indentChars;
|
||||
for (int i = 0; i < n; i++) { sbOutput.Append(' '); }
|
||||
int n = level * _config.IndentChars;
|
||||
for (int i = 0; i < n; i++) { textWriter.Write(' '); }
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteString(StringBuilder sbOutput, string str)
|
||||
private void WriteString(TextWriter textWriter, string str)
|
||||
{
|
||||
sbOutput.Append('"');
|
||||
textWriter.Write('"');
|
||||
char c;
|
||||
int n = str.Length;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
c = str[i];
|
||||
if (c == '"') { sbOutput.Append("\\\""); }
|
||||
else if (c == '\\') { sbOutput.Append("\\\\"); }
|
||||
else if (c == '/') { sbOutput.Append("\\/"); }
|
||||
else if (c == '\b') { sbOutput.Append("\\b"); }
|
||||
else if (c == '\f') { sbOutput.Append("\\f"); }
|
||||
else if (c == '\n') { sbOutput.Append("\\n"); }
|
||||
else if (c == '\r') { sbOutput.Append("\\r"); }
|
||||
else if (c == '\t') { sbOutput.Append("\\t"); }
|
||||
else if (c < 32 || c >= 127) { sbOutput.AppendFormat("\\u{0:X04}", (int)c); }
|
||||
else { sbOutput.Append(c); }
|
||||
if (c == '"') { textWriter.Write("\\\""); }
|
||||
else if (c == '\\') { textWriter.Write("\\\\"); }
|
||||
else if (c == '/') { textWriter.Write("\\/"); }
|
||||
else if (c == '\b') { textWriter.Write("\\b"); }
|
||||
else if (c == '\f') { textWriter.Write("\\f"); }
|
||||
else if (c == '\n') { textWriter.Write("\\n"); }
|
||||
else if (c == '\r') { textWriter.Write("\\r"); }
|
||||
else if (c == '\t') { textWriter.Write("\\t"); }
|
||||
else if (c < 32 || c >= 127) { textWriter.Write("\\u{0:X04}", (int)c); }
|
||||
else { textWriter.Write(c); }
|
||||
}
|
||||
sbOutput.Append('"');
|
||||
textWriter.Write('"');
|
||||
}
|
||||
|
||||
private void WriteValue(StringBuilder sbOutput, object obj, List<object> parentLevels, bool useReflection)
|
||||
private void WriteValue(TextWriter textWriter, object obj, List<object> parentLevels)
|
||||
{
|
||||
if (obj == null || obj is DBNull)
|
||||
{
|
||||
// NULL
|
||||
sbOutput.Append("null");
|
||||
textWriter.Write("null");
|
||||
}
|
||||
else if (
|
||||
(obj is float) ||
|
||||
@@ -117,50 +157,43 @@ namespace VAR.Json
|
||||
false)
|
||||
{
|
||||
// Numbers
|
||||
sbOutput.Append(obj.ToString());
|
||||
textWriter.Write(obj.ToString());
|
||||
}
|
||||
else if (obj is string)
|
||||
{
|
||||
// Strings
|
||||
WriteString(sbOutput, (string)obj);
|
||||
WriteString(textWriter, (string)obj);
|
||||
}
|
||||
else if (obj is bool)
|
||||
{
|
||||
// Booleans
|
||||
sbOutput.Append(((bool)obj) ? "true" : "false");
|
||||
textWriter.Write(((bool)obj) ? "true" : "false");
|
||||
}
|
||||
else if (obj is DateTime)
|
||||
{
|
||||
// DateTime
|
||||
sbOutput.Append('"');
|
||||
sbOutput.Append(((DateTime)obj).ToString("yyyy-MM-ddTHH:mm:ssZ"));
|
||||
sbOutput.Append('"');
|
||||
textWriter.Write('"');
|
||||
textWriter.Write(((DateTime)obj).ToString("yyyy-MM-ddTHH:mm:ss"));
|
||||
textWriter.Write('"');
|
||||
}
|
||||
else if (obj is IDictionary)
|
||||
{
|
||||
// Objects
|
||||
WriteObject(sbOutput, obj, parentLevels);
|
||||
WriteObject(textWriter, obj, parentLevels);
|
||||
}
|
||||
else if (obj is IEnumerable)
|
||||
{
|
||||
// Array/List
|
||||
WriteList(sbOutput, obj, parentLevels);
|
||||
WriteList(textWriter, obj, parentLevels);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (useReflection)
|
||||
{
|
||||
// Reflected object
|
||||
WriteReflectedObject(sbOutput, obj, parentLevels);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteString(sbOutput, Convert.ToString(obj));
|
||||
}
|
||||
// Reflected object
|
||||
WriteReflectedObject(textWriter, obj, parentLevels);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteList(StringBuilder sbOutput, object obj, List<object> parentLevels)
|
||||
private void WriteList(TextWriter textWriter, object obj, List<object> parentLevels)
|
||||
{
|
||||
IEnumerable list = (IEnumerable)obj;
|
||||
int n = 0;
|
||||
@@ -179,40 +212,40 @@ namespace VAR.Json
|
||||
// Empty
|
||||
if (n == 0)
|
||||
{
|
||||
sbOutput.Append("[ ]");
|
||||
textWriter.Write("[ ]");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write array
|
||||
bool first = true;
|
||||
sbOutput.Append("[ ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write("[ ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
foreach (object childObj in list)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sbOutput.Append(", ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write(", ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
parentLevels.Add(obj);
|
||||
WriteValue(sbOutput, childObj, parentLevels, true);
|
||||
WriteValue(textWriter, childObj, parentLevels);
|
||||
parentLevels.Remove(obj);
|
||||
}
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count);
|
||||
WriteIndent(textWriter, parentLevels.Count);
|
||||
}
|
||||
sbOutput.Append(" ]");
|
||||
textWriter.Write(" ]");
|
||||
}
|
||||
|
||||
private void WriteObject(StringBuilder sbOutput, object obj, List<object> parentLevels)
|
||||
private void WriteObject(TextWriter textWriter, object obj, List<object> parentLevels)
|
||||
{
|
||||
IDictionary map = (IDictionary)obj;
|
||||
int n = map.Count;
|
||||
@@ -220,7 +253,7 @@ namespace VAR.Json
|
||||
// Empty
|
||||
if (map.Count == 0)
|
||||
{
|
||||
sbOutput.Append("{ }");
|
||||
textWriter.Write("{ }");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,37 +270,37 @@ namespace VAR.Json
|
||||
|
||||
// Write object
|
||||
bool first = true;
|
||||
sbOutput.Append("{ ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write("{ ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
foreach (object key in map.Keys)
|
||||
{
|
||||
object value = map[key];
|
||||
if (!first)
|
||||
{
|
||||
sbOutput.Append(", ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write(", ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
WriteString(sbOutput, Convert.ToString(key));
|
||||
sbOutput.Append(": ");
|
||||
WriteString(textWriter, Convert.ToString(key));
|
||||
textWriter.Write(": ");
|
||||
parentLevels.Add(obj);
|
||||
WriteValue(sbOutput, value, parentLevels, true);
|
||||
WriteValue(textWriter, value, parentLevels);
|
||||
parentLevels.Remove(obj);
|
||||
}
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count);
|
||||
WriteIndent(textWriter, parentLevels.Count);
|
||||
}
|
||||
sbOutput.Append(" }");
|
||||
textWriter.Write(" }");
|
||||
}
|
||||
|
||||
private void WriteReflectedObject(StringBuilder sbOutput, object obj, List<object> parentLevels)
|
||||
private void WriteReflectedObject(TextWriter textWriter, object obj, List<object> parentLevels)
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
PropertyInfo[] rawProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
@@ -283,7 +316,7 @@ namespace VAR.Json
|
||||
// Empty
|
||||
if (n == 0)
|
||||
{
|
||||
sbOutput.Append("{ }");
|
||||
textWriter.Write("{ }");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,10 +334,10 @@ namespace VAR.Json
|
||||
|
||||
// Write object
|
||||
bool first = true;
|
||||
sbOutput.Append("{ ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write("{ ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
@@ -317,42 +350,106 @@ namespace VAR.Json
|
||||
}
|
||||
if (!first)
|
||||
{
|
||||
sbOutput.Append(", ");
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
textWriter.Write(", ");
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count + 1);
|
||||
WriteIndent(textWriter, parentLevels.Count + 1);
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
WriteString(sbOutput, property.Name);
|
||||
sbOutput.Append(": ");
|
||||
WriteString(textWriter, property.Name);
|
||||
textWriter.Write(": ");
|
||||
parentLevels.Add(obj);
|
||||
if (value != obj && parentLevels.Contains(value) == false)
|
||||
{
|
||||
WriteValue(sbOutput, value, parentLevels, false);
|
||||
WriteValue(textWriter, value, parentLevels);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteValue(sbOutput, null, parentLevels, false);
|
||||
WriteValue(textWriter, null, parentLevels);
|
||||
}
|
||||
parentLevels.Remove(obj);
|
||||
}
|
||||
if (!isLeaf || n > _indentThresold)
|
||||
if (!isLeaf || n > _config.IndentThresold)
|
||||
{
|
||||
WriteIndent(sbOutput, parentLevels.Count);
|
||||
WriteIndent(textWriter, parentLevels.Count);
|
||||
}
|
||||
sbOutput.Append(" }");
|
||||
textWriter.Write(" }");
|
||||
}
|
||||
|
||||
#endregion Private methods
|
||||
|
||||
#region Public methods
|
||||
|
||||
public TextWriter Write(object obj, TextWriter textWriter)
|
||||
{
|
||||
if (textWriter == null)
|
||||
{
|
||||
textWriter = new StringWriter();
|
||||
}
|
||||
WriteValue(textWriter, obj, new List<object>());
|
||||
return textWriter;
|
||||
}
|
||||
|
||||
public string Write(object obj)
|
||||
{
|
||||
StringBuilder sbOutput = new StringBuilder();
|
||||
WriteValue(sbOutput, obj, new List<object>(), true);
|
||||
return sbOutput.ToString();
|
||||
StringWriter textWriter = new StringWriter();
|
||||
WriteValue(textWriter, obj, new List<object>());
|
||||
return textWriter.ToString();
|
||||
}
|
||||
|
||||
private static Dictionary<JsonWriterConfiguration, JsonWriter> _dictInstances = new Dictionary<JsonWriterConfiguration, JsonWriter>();
|
||||
|
||||
public static string WriteObject(object obj,
|
||||
JsonWriterConfiguration config = null,
|
||||
bool indent = false,
|
||||
bool useTabForIndent = false,
|
||||
int indentChars = 4,
|
||||
int indentThresold = 3)
|
||||
{
|
||||
JsonWriter jsonWriter = null;
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
if (_dictInstances.ContainsKey(config) == false)
|
||||
{
|
||||
jsonWriter = new JsonWriter(config);
|
||||
_dictInstances.Add(config, jsonWriter);
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonWriter = _dictInstances[config];
|
||||
}
|
||||
return jsonWriter.Write(obj);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<JsonWriterConfiguration, JsonWriter> pair in _dictInstances)
|
||||
{
|
||||
if (
|
||||
pair.Key.Indent == indent &&
|
||||
pair.Key.UseTabForIndent == useTabForIndent &&
|
||||
pair.Key.IndentChars == indentChars &&
|
||||
pair.Key.IndentThresold == indentThresold &&
|
||||
true)
|
||||
{
|
||||
jsonWriter = pair.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jsonWriter != null)
|
||||
{
|
||||
return jsonWriter.Write(obj);
|
||||
}
|
||||
|
||||
JsonWriterConfiguration jsonWriterConfiguration = new JsonWriterConfiguration(
|
||||
indent: indent,
|
||||
useTabForIndent: useTabForIndent,
|
||||
indentChars: indentChars,
|
||||
indentThresold: indentThresold);
|
||||
jsonWriter = new JsonWriter(jsonWriterConfiguration);
|
||||
_dictInstances.Add(jsonWriterConfiguration, jsonWriter);
|
||||
|
||||
return jsonWriter.Write(obj);
|
||||
}
|
||||
|
||||
#endregion Public methods
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace VAR.Json
|
||||
{
|
||||
public class ObjectActivator
|
||||
{
|
||||
private static Dictionary<Type, Func<object>> _creators = new Dictionary<Type, Func<object>>();
|
||||
private static readonly Dictionary<Type, Func<object>> _creators = new Dictionary<Type, Func<object>>();
|
||||
|
||||
public static Func<object> GetLambdaNew(Type type)
|
||||
{
|
||||
@@ -17,13 +17,18 @@ namespace VAR.Json
|
||||
|
||||
lock (_creators)
|
||||
{
|
||||
if (_creators.ContainsKey(type))
|
||||
{
|
||||
return _creators[type];
|
||||
}
|
||||
|
||||
NewExpression newExp = Expression.New(type);
|
||||
LambdaExpression lambda = Expression.Lambda(typeof(Func<object>), newExp);
|
||||
Func<object> compiledLambdaNew = (Func<object>)lambda.Compile();
|
||||
|
||||
_creators.Add(type, compiledLambdaNew);
|
||||
return _creators[type];
|
||||
}
|
||||
return _creators[type];
|
||||
}
|
||||
|
||||
public static object CreateInstance(Type type)
|
||||
|
||||
@@ -11,4 +11,4 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("28b3f937-145c-4fd4-a75b-a25ea4cc0428")]
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.0.*")]
|
||||
@@ -21,6 +21,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<LangVersion>6</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release .Net 4.6.1|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@@ -30,6 +31,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<LangVersion>6</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug .Net 3.5|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -40,6 +42,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<LangVersion>6</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release .Net 3.5|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@@ -49,6 +52,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<LangVersion>6</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
||||
Reference in New Issue
Block a user