mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-08 20:08:53 -05:00
Support dependencies of JsonSchema. Fix tests to compare values which using ToJson and using JsonSchema. Restrict valudator
This commit is contained in:
@@ -150,7 +150,7 @@ namespace UniGLTF
|
||||
[Test]
|
||||
public void MeshTest()
|
||||
{
|
||||
var mesh = new glTFMesh("mesh")
|
||||
var model = new glTFMesh("mesh")
|
||||
{
|
||||
primitives = new List<glTFPrimitives>
|
||||
{
|
||||
@@ -164,25 +164,22 @@ namespace UniGLTF
|
||||
},
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(mesh);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extensions"":{}}]}", json);
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""indices"":-1,""attributes"":{""POSITION"":0},""material"":0}]}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFMesh>().Serialize(mesh, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFMesh>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extensions"":{}}]}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrimitiveTest()
|
||||
{
|
||||
var prim = new glTFPrimitives
|
||||
var model = new glTFPrimitives
|
||||
{
|
||||
attributes = new glTFAttributes
|
||||
{
|
||||
@@ -197,33 +194,27 @@ namespace UniGLTF
|
||||
}
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(prim);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json);
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""mode"":0,""indices"":-1,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]}}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFPrimitives>().Serialize(prim, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFPrimitives>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AttributesTest()
|
||||
{
|
||||
var attrs = new glTFAttributes
|
||||
var model = new glTFAttributes
|
||||
{
|
||||
POSITION = 0,
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(attrs);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""POSITION"":0}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
@@ -231,22 +222,19 @@ namespace UniGLTF
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFAttributes>().Serialize(attrs, c);
|
||||
var json2 = JsonSchema.FromType<glTFAttributes>().Serialize(model, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextureInfoTest()
|
||||
{
|
||||
var texi = new glTFMaterialBaseColorTextureInfo()
|
||||
var model = new glTFMaterialBaseColorTextureInfo()
|
||||
{
|
||||
index = 1,
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(texi);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""index"":1,""texCoord"":0}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
@@ -254,21 +242,21 @@ namespace UniGLTF
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFMaterialBaseColorTextureInfo>().Serialize(texi, c);
|
||||
var json2 = JsonSchema.FromType<glTFMaterialBaseColorTextureInfo>().Serialize(model, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TextureInfoTestError()
|
||||
{
|
||||
var texi = new glTFMaterialBaseColorTextureInfo();
|
||||
var model = new glTFMaterialBaseColorTextureInfo();
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var ex = Assert.Throws<JsonSchemaValidationException>(
|
||||
() => JsonSchema.FromType<glTFMaterialBaseColorTextureInfo>().Serialize(texi, c)
|
||||
() => JsonSchema.FromType<glTFMaterialBaseColorTextureInfo>().Serialize(model, c)
|
||||
);
|
||||
Assert.AreEqual("[index.String] minimum: ! -1>=0", ex.Message);
|
||||
}
|
||||
@@ -276,25 +264,40 @@ namespace UniGLTF
|
||||
[Test]
|
||||
public void MaterialTest()
|
||||
{
|
||||
var texi = new glTFMaterial()
|
||||
var model = new glTFMaterial()
|
||||
{
|
||||
name = "a",
|
||||
emissiveFactor = new float[] { 0.5f, 0.5f, 0.5f },
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(texi);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""alphaCutoff"":0.5,""doubleSided"":false}", json);
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""doubleSided"":false}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFMaterial>().Serialize(texi, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFMaterial>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""doubleSided"":false}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaterialAlphaTest()
|
||||
{
|
||||
var model = new glTFMaterial()
|
||||
{
|
||||
name = "a",
|
||||
emissiveFactor = new float[] { 0.5f, 0.5f, 0.5f },
|
||||
alphaMode = "MASK",
|
||||
};
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json = JsonSchema.FromType<glTFMaterial>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""alphaMode"":""MASK"",""alphaCutoff"":0.5,""doubleSided"":false}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -376,7 +379,7 @@ namespace UniGLTF
|
||||
|
||||
public void MaterialTestError()
|
||||
{
|
||||
var texi = new glTFMaterial()
|
||||
var model = new glTFMaterial()
|
||||
{
|
||||
name = "b",
|
||||
emissiveFactor = new float[] { 1.5f, 0.5f, 0.5f },
|
||||
@@ -387,7 +390,7 @@ namespace UniGLTF
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var ex = Assert.Throws<JsonSchemaValidationException>(
|
||||
() => JsonSchema.FromType<glTFMaterial>().Serialize(texi, c)
|
||||
() => JsonSchema.FromType<glTFMaterial>().Serialize(model, c)
|
||||
);
|
||||
Assert.AreEqual("[emissiveFactor.String] maximum: ! 1.5<=1", ex.Message);
|
||||
}
|
||||
@@ -395,32 +398,48 @@ namespace UniGLTF
|
||||
[Test]
|
||||
public void NodeTest()
|
||||
{
|
||||
var texi = new glTFNode()
|
||||
var model = new glTFNode()
|
||||
{
|
||||
name = "a",
|
||||
skin = 0,
|
||||
camera = -1,
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(texi);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Assert.AreEqual(@"{""name"":""a"",""skin"":0,""extras"":{}}", json);
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""name"":""a"",""skin"":0}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFNode>().Serialize(texi, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFNode>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""name"":""a"",""extras"":{}}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NodeMeshTest()
|
||||
{
|
||||
var model = new glTFNode()
|
||||
{
|
||||
name = "a",
|
||||
mesh = 2,
|
||||
skin = 0,
|
||||
camera = -1,
|
||||
};
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json = JsonSchema.FromType<glTFNode>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""name"":""a"",""mesh"":2,""skin"":0,""extras"":{}}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NodeTestError()
|
||||
{
|
||||
var texi = new glTFNode()
|
||||
var model = new glTFNode()
|
||||
{
|
||||
name = "a",
|
||||
camera = -2,
|
||||
@@ -431,7 +450,7 @@ namespace UniGLTF
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var ex = Assert.Throws<JsonSchemaValidationException>(
|
||||
() => JsonSchema.FromType<glTFNode>().Serialize(texi, c)
|
||||
() => JsonSchema.FromType<glTFNode>().Serialize(model, c)
|
||||
);
|
||||
Assert.AreEqual("[camera.String] minimum: ! -2>=0", ex.Message);
|
||||
}
|
||||
@@ -439,56 +458,50 @@ namespace UniGLTF
|
||||
[Test]
|
||||
public void SkinTest()
|
||||
{
|
||||
var texi = new glTFSkin()
|
||||
var model = new glTFSkin()
|
||||
{
|
||||
name = "b",
|
||||
joints = new int[] {1},
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(texi);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Assert.AreEqual(@"{""joints"":[1],""name"":""b""}", json);
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFSkin>().Serialize(texi, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFSkin>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""joints"":[1],""name"":""b""}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SkinTestEmptyName()
|
||||
{
|
||||
var texi = new glTFSkin()
|
||||
var model = new glTFSkin()
|
||||
{
|
||||
name = "",
|
||||
joints = new int[] {1},
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(texi);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
var json = model.ToJson();
|
||||
// "name" = "", not excluded
|
||||
Assert.AreEqual(@"{""joints"":[1],""name"":""""}", json);
|
||||
Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTFSkin>().Serialize(texi, c);
|
||||
Assert.AreEqual(json, json2);
|
||||
var json2 = JsonSchema.FromType<glTFSkin>().Serialize(model, c);
|
||||
Assert.AreEqual(@"{""joints"":[1],""name"":""""}", json2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SkinTestErrorNull()
|
||||
{
|
||||
var texi = new glTFSkin()
|
||||
var model = new glTFSkin()
|
||||
{
|
||||
name = "b",
|
||||
joints = null,
|
||||
@@ -499,7 +512,7 @@ namespace UniGLTF
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var ex = Assert.Throws<JsonSchemaValidationException>(
|
||||
() => JsonSchema.FromType<glTFSkin>().Serialize(texi, c)
|
||||
() => JsonSchema.FromType<glTFSkin>().Serialize(model, c)
|
||||
);
|
||||
Assert.AreEqual("[joints.String] null", ex.Message);
|
||||
}
|
||||
@@ -507,7 +520,7 @@ namespace UniGLTF
|
||||
[Test]
|
||||
public void SkinTestError()
|
||||
{
|
||||
var texi = new glTFSkin()
|
||||
var model = new glTFSkin()
|
||||
{
|
||||
name = "b",
|
||||
joints = new int[] {},
|
||||
@@ -518,7 +531,7 @@ namespace UniGLTF
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
var ex = Assert.Throws<JsonSchemaValidationException>(
|
||||
() => JsonSchema.FromType<glTFSkin>().Serialize(texi, c)
|
||||
() => JsonSchema.FromType<glTFSkin>().Serialize(model, c)
|
||||
);
|
||||
Assert.AreEqual("[joints.String] minItems", ex.Message);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace UniJSON
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int X;
|
||||
|
||||
[JsonSchema(Minimum = 10)] // Not required, thus ignored when the value violates the constraints
|
||||
[JsonSchema(Minimum = 10, ExplicitIgnorableValue = 0)] // Not required, thus ignored when the value violates the constraints
|
||||
public int Y;
|
||||
}
|
||||
|
||||
@@ -77,5 +77,51 @@ namespace UniJSON
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
public class HasDepsTest
|
||||
{
|
||||
[JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)]
|
||||
public int X;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] {"X"})]
|
||||
public int Y;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHasDeps()
|
||||
{
|
||||
var obj = new HasDepsTest();
|
||||
|
||||
var s = JsonSchema.FromType<HasDepsTest>();
|
||||
{
|
||||
var c = new JsonSchemaValidationContext(obj);
|
||||
Assert.Null(s.Validator.Validate(c, s));
|
||||
}
|
||||
var actual = s.Serialize(obj);
|
||||
|
||||
var expected = @"{""X"":0,""Y"":0}";
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHasDepsHasViolation()
|
||||
{
|
||||
var obj = new HasDepsTest()
|
||||
{
|
||||
X = -1,
|
||||
};
|
||||
|
||||
var s = JsonSchema.FromType<HasDepsTest>();
|
||||
{
|
||||
var c = new JsonSchemaValidationContext(obj);
|
||||
Assert.Null(s.Validator.Validate(c, s));
|
||||
}
|
||||
var actual = s.Serialize(obj);
|
||||
|
||||
var expected = @"{}";
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ namespace UniJSON
|
||||
|
||||
var s = JsonSchema.FromType<HasArrayOBject>();
|
||||
|
||||
Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] {} }));
|
||||
Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { } }));
|
||||
Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { 0.5f } }));
|
||||
Assert.NotNull(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { 1.5f } }));
|
||||
|
||||
@@ -379,12 +379,39 @@ namespace UniJSON
|
||||
|
||||
var s = JsonSchema.FromType<HasListObject>();
|
||||
|
||||
Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List<float> {} }));
|
||||
Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List<float> { } }));
|
||||
Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List<float> { 0.5f } }));
|
||||
Assert.NotNull(s.Validator.Validate(c, new HasListObject { xs = new List<float> { 1.5f } }));
|
||||
|
||||
Assert.True(c.IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
class HasRequiredListObject
|
||||
{
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
[ItemJsonSchema(Minimum = 0)]
|
||||
public int[] xs;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasRequiredListObjecttValidator()
|
||||
{
|
||||
{
|
||||
var c = new JsonSchemaValidationContext("test")
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
|
||||
var s = JsonSchema.FromType<HasRequiredListObject>();
|
||||
|
||||
Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject()));
|
||||
Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] {} }));
|
||||
Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] { -1 } }));
|
||||
Assert.Null(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] { 0 } }));
|
||||
|
||||
Assert.True(c.IsEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,14 @@ namespace UniJSON
|
||||
{
|
||||
// reflection
|
||||
var schema = JsonSchema.FromType<T>();
|
||||
return (IFormatter f, T value) => schema.Serialize(f, value);
|
||||
return (IFormatter f, T value) =>
|
||||
{
|
||||
var c = new JsonSchemaValidationContext(value)
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true
|
||||
};
|
||||
schema.Serialize(f, value, c);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -392,7 +392,10 @@ namespace UniJSON
|
||||
{
|
||||
if (c == null)
|
||||
{
|
||||
c = new JsonSchemaValidationContext(o);
|
||||
c = new JsonSchemaValidationContext(o)
|
||||
{
|
||||
EnableDiagnosisForNotRequiredFields = true,
|
||||
};
|
||||
}
|
||||
|
||||
var ex = Validator.Validate(c, o);
|
||||
|
||||
@@ -297,28 +297,66 @@ namespace UniJSON
|
||||
}
|
||||
}
|
||||
|
||||
static class GenericFieldView<T>
|
||||
{
|
||||
public static FieldInfo[] GetFields()
|
||||
{
|
||||
var t = typeof(T);
|
||||
return t.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
public static void CreateFieldProcessors<G, D>(
|
||||
string methodName,
|
||||
Dictionary<string, D> processors
|
||||
)
|
||||
{
|
||||
var mi = typeof(G).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
var t = typeof(T);
|
||||
foreach (var fi in GetFields())
|
||||
{
|
||||
var value = Expression.Parameter(t, "value");
|
||||
var fieldValue = Expression.Field(value, fi);
|
||||
var compileld = Expression.Lambda(fieldValue, value).Compile();
|
||||
|
||||
var getter = Expression.Constant(compileld);
|
||||
var name = Expression.Constant(fi.Name);
|
||||
|
||||
var g = mi.MakeGenericMethod(fi.FieldType);
|
||||
var call = Expression.Call(g, getter, name);
|
||||
var lambda = (Func<D>)Expression.Lambda(call).Compile();
|
||||
|
||||
processors.Add(fi.Name, lambda());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ValidationResult
|
||||
{
|
||||
public bool IsIgnorable;
|
||||
public JsonSchemaValidationException Ex;
|
||||
}
|
||||
|
||||
public static class GenericValidator<T>
|
||||
{
|
||||
class ObjectValidator
|
||||
{
|
||||
delegate JsonSchemaValidationException FieldValidator(
|
||||
JsonSchema s, JsonSchemaValidationContext c, T o, bool isRequired);
|
||||
JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable);
|
||||
|
||||
Dictionary<string, FieldValidator> m_validators = new Dictionary<string, FieldValidator>();
|
||||
Dictionary<string, FieldValidator> m_validators;
|
||||
|
||||
static FieldValidator CreteFieldValidator<U>(Func<T, U> getter, string name)
|
||||
{
|
||||
return (s, c, o, isRequired) =>
|
||||
return (JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable) =>
|
||||
{
|
||||
var v = s.Validator;
|
||||
using (c.Push(name))
|
||||
{
|
||||
var field = getter(o);
|
||||
var ex = v.Validate(c, field);
|
||||
if (ex != null && !isRequired && s.IsExplicitlyIgnorableValue(field))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
isIgnorable = ex != null && s.IsExplicitlyIgnorableValue(field);
|
||||
|
||||
return ex;
|
||||
}
|
||||
@@ -327,25 +365,46 @@ namespace UniJSON
|
||||
|
||||
public ObjectValidator()
|
||||
{
|
||||
var mi = typeof(ObjectValidator).GetMethod("CreteFieldValidator",
|
||||
BindingFlags.Static|BindingFlags.NonPublic);
|
||||
var validators = new Dictionary<string, FieldValidator>();
|
||||
GenericFieldView<T>.CreateFieldProcessors<ObjectValidator, FieldValidator>(
|
||||
"CreteFieldValidator", validators);
|
||||
|
||||
var t = typeof(T);
|
||||
foreach(var fi in t.GetFields(
|
||||
BindingFlags.Instance|BindingFlags.Public))
|
||||
m_validators = validators;
|
||||
}
|
||||
|
||||
public JsonSchemaValidationException ValidateProperty(
|
||||
HashSet<string> required,
|
||||
KeyValuePair<string, JsonSchema> property,
|
||||
JsonSchemaValidationContext c,
|
||||
T o,
|
||||
out bool isIgnorable
|
||||
)
|
||||
{
|
||||
var fieldName = property.Key;
|
||||
var schema = property.Value;
|
||||
|
||||
isIgnorable = false;
|
||||
|
||||
FieldValidator fv;
|
||||
if (m_validators.TryGetValue(fieldName, out fv))
|
||||
{
|
||||
var value = Expression.Parameter(typeof(T), "value");
|
||||
var fieldValue = Expression.Field(value, fi);
|
||||
var compileld = Expression.Lambda(fieldValue, value).Compile();
|
||||
var isRequired = required != null && required.Contains(fieldName);
|
||||
|
||||
var getter = Expression.Constant(compileld);
|
||||
var name = Expression.Constant(fi.Name);
|
||||
var g = mi.MakeGenericMethod(fi.FieldType);
|
||||
var call = Expression.Call(g, getter, name);
|
||||
var lambda = (Func<FieldValidator>)Expression.Lambda(call).Compile();
|
||||
bool isMemberIgnorable;
|
||||
var ex = fv(schema, c, o, out isMemberIgnorable);
|
||||
if (ex != null)
|
||||
{
|
||||
isIgnorable = !isRequired && isMemberIgnorable;
|
||||
|
||||
m_validators.Add(fi.Name, lambda());
|
||||
if (isRequired // required fields must be checked
|
||||
|| c.EnableDiagnosisForNotRequiredFields)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JsonSchemaValidationException Validate(
|
||||
@@ -355,41 +414,62 @@ namespace UniJSON
|
||||
{
|
||||
foreach (var kv in properties)
|
||||
{
|
||||
var fieldName = kv.Key;
|
||||
var schema = kv.Value;
|
||||
|
||||
FieldValidator fv;
|
||||
if (m_validators.TryGetValue(fieldName, out fv))
|
||||
bool isIgnorable;
|
||||
var ex = ValidateProperty(required, kv, c, o, out isIgnorable);
|
||||
if (ex != null && !isIgnorable)
|
||||
{
|
||||
var isRequired = required != null && required.Contains(fieldName);
|
||||
var ex = fv(schema, c, o, isRequired);
|
||||
if (ex != null)
|
||||
{
|
||||
if (isRequired // required fields must be checked
|
||||
|| c.EnableDiagnosisForNotRequiredFields)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ValidationResults
|
||||
(HashSet<string> required,
|
||||
Dictionary<string, JsonSchema> properties,
|
||||
JsonSchemaValidationContext c, T o,
|
||||
Dictionary<string, ValidationResult> results)
|
||||
{
|
||||
foreach (var kv in properties)
|
||||
{
|
||||
bool isIgnorable;
|
||||
var ex = ValidateProperty(required, kv, c, o, out isIgnorable);
|
||||
|
||||
results.Add(kv.Key, new ValidationResult {
|
||||
IsIgnorable = isIgnorable,
|
||||
Ex = ex,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ObjectValidator s_validator;
|
||||
|
||||
public static JsonSchemaValidationException Validate(HashSet<string> required,
|
||||
Dictionary<string, JsonSchema> properties,
|
||||
JsonSchemaValidationContext c, T o)
|
||||
static void prepareValidator()
|
||||
{
|
||||
if (s_validator == null)
|
||||
{
|
||||
s_validator = new ObjectValidator();
|
||||
}
|
||||
}
|
||||
|
||||
public static JsonSchemaValidationException Validate(HashSet<string> required,
|
||||
Dictionary<string, JsonSchema> properties,
|
||||
JsonSchemaValidationContext c, T o)
|
||||
{
|
||||
prepareValidator();
|
||||
return s_validator.Validate(required, properties, c, o);
|
||||
}
|
||||
|
||||
internal static void ValidationResults(HashSet<string> required,
|
||||
Dictionary<string, JsonSchema> properties,
|
||||
JsonSchemaValidationContext c, T o,
|
||||
Dictionary<string, ValidationResult> results)
|
||||
{
|
||||
prepareValidator();
|
||||
s_validator.ValidationResults(required, properties, c, o, results);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonSchemaValidationException Validate<T>(JsonSchemaValidationContext c, T o)
|
||||
@@ -411,103 +491,89 @@ namespace UniJSON
|
||||
{
|
||||
class Serializer
|
||||
{
|
||||
delegate void FieldSerializer(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T src);
|
||||
delegate void FieldSerializer(JsonSchema s, JsonSchemaValidationContext c, IFormatter f, T o,
|
||||
Dictionary<string, ValidationResult> vRes, string[] deps);
|
||||
|
||||
List<FieldSerializer> m_fieldSerializers = new List<FieldSerializer>();
|
||||
Dictionary<string, FieldSerializer> m_serializers;
|
||||
|
||||
static FieldSerializer CreateSerializer<U>(FieldInfo fi)
|
||||
static FieldSerializer CreteFieldSerializer<U>(Func<T, U> getter, string name)
|
||||
{
|
||||
var src = Expression.Parameter(typeof(T), "src");
|
||||
var getter = Expression.Field(src, fi);
|
||||
var compiled = (Func<T, U>)Expression.Lambda(getter, src).Compile();
|
||||
var name = fi.Name;
|
||||
return (v, f, c, s) =>
|
||||
return (s, c, f, o, vRes, deps) =>
|
||||
{
|
||||
//c.Push(name);
|
||||
var v = s.Validator;
|
||||
var field = getter(o);
|
||||
|
||||
var validator = v.Properties[name].Validator;
|
||||
|
||||
var value = compiled(s);
|
||||
|
||||
// validate
|
||||
if (validator.Validate(c, value) != null)
|
||||
if (vRes[name].Ex != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// depencencies
|
||||
string[] dependencies;
|
||||
if (validator.Dependencies.TryGetValue(name, out dependencies))
|
||||
if (deps != null)
|
||||
{
|
||||
// check dependencies
|
||||
bool hasDependencies = true;
|
||||
foreach (var x in dependencies)
|
||||
foreach(var dep in deps)
|
||||
{
|
||||
if (!map.ContainsKey(x))
|
||||
if (vRes[dep].Ex != null)
|
||||
{
|
||||
hasDependencies = false;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!hasDependencies)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
f.Key(name);
|
||||
validator.Serialize(f, c, value);
|
||||
//f.Serialize(value);
|
||||
|
||||
//c.Pop();
|
||||
v.Serialize(f, c, field);
|
||||
};
|
||||
}
|
||||
|
||||
public void AddField(FieldInfo fi)
|
||||
public Serializer()
|
||||
{
|
||||
var mi = typeof(Serializer).GetMethod("CreateSerializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(fi.FieldType);
|
||||
var f = Expression.Constant(fi);
|
||||
var call = Expression.Call(g, f);
|
||||
var compiled = (Func<FieldSerializer>)Expression.Lambda(call).Compile();
|
||||
m_fieldSerializers.Add(compiled());
|
||||
var serializers = new Dictionary<string, FieldSerializer>();
|
||||
GenericFieldView<T>.CreateFieldProcessors<Serializer, FieldSerializer>(
|
||||
"CreteFieldSerializer", serializers);
|
||||
|
||||
m_serializers = serializers;
|
||||
}
|
||||
|
||||
public void Serialize(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T value)
|
||||
public void Serialize(JsonObjectValidator objectValidator,
|
||||
IFormatter f, JsonSchemaValidationContext c, T o)
|
||||
{
|
||||
f.BeginMap(m_fieldSerializers.Count);
|
||||
foreach (var s in m_fieldSerializers)
|
||||
// Validates fields
|
||||
var validationResults = new Dictionary<string, ValidationResult>();
|
||||
GenericValidator<T>.ValidationResults(
|
||||
objectValidator.Required, objectValidator.Properties,
|
||||
c, o, validationResults);
|
||||
|
||||
// Serialize fields
|
||||
f.BeginMap(objectValidator.Properties.Count());
|
||||
foreach (var property in objectValidator.Properties)
|
||||
{
|
||||
s(v, f, c, value);
|
||||
var fieldName = property.Key;
|
||||
var schema = property.Value;
|
||||
|
||||
string[] deps = null;
|
||||
objectValidator.Dependencies.TryGetValue(fieldName, out deps);
|
||||
|
||||
FieldSerializer fs;
|
||||
if (m_serializers.TryGetValue(fieldName, out fs))
|
||||
{
|
||||
fs(schema, c, f, o, validationResults, deps);
|
||||
}
|
||||
}
|
||||
f.EndMap();
|
||||
}
|
||||
}
|
||||
|
||||
static FieldInfo[] s_fields;
|
||||
static Serializer s_serializer;
|
||||
|
||||
public static void Serialize(JsonObjectValidator validator,
|
||||
public static void Serialize(JsonObjectValidator objectValidator,
|
||||
IFormatter f, JsonSchemaValidationContext c, T value)
|
||||
{
|
||||
if (s_serializer == null)
|
||||
{
|
||||
var t = typeof(T);
|
||||
if (t == typeof(object))
|
||||
{
|
||||
throw new ArgumentException("object cannot serialize");
|
||||
}
|
||||
var serializer = new Serializer();
|
||||
var fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||
foreach (var fi in fields)
|
||||
{
|
||||
serializer.AddField(fi);
|
||||
}
|
||||
s_serializer = serializer;
|
||||
s_serializer = new Serializer();
|
||||
}
|
||||
s_serializer.Serialize(validator, f, c, value);
|
||||
|
||||
s_serializer.Serialize(objectValidator, f, c, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user