From 8479c7c9b22495319a4989561f8073d2f143d8c2 Mon Sep 17 00:00:00 2001 From: yutopp Date: Fri, 11 Jan 2019 16:32:07 +0900 Subject: [PATCH 01/19] Add a test for glTF components. Fix json schema to export them correctly by using JsonSchema --- Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs | 271 +++++++++++++++++- .../KHR_draco_mesh_compression.cs | 1 - .../ExtensionsAndExtras/glTFExtensions.cs | 4 +- Assets/VRM/UniGLTF/Scripts/Format/glTF.cs | 24 +- Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs | 23 +- Assets/VRM/UniGLTF/Scripts/Format/glTFNode.cs | 10 +- Assets/VRM/UniGLTF/Scripts/Format/glTFSkin.cs | 4 +- .../VRM/UniGLTF/Scripts/Format/glTFTexture.cs | 4 +- .../VRM/UniGLTF/Scripts/IO/ImporterContext.cs | 6 +- .../Format/glTF_VRM_SecondaryAnimation.cs | 3 + 10 files changed, 308 insertions(+), 42 deletions(-) diff --git a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs index d6c8b009a..8fea2ae6d 100644 --- a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs +++ b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs @@ -156,39 +156,145 @@ namespace UniGLTF { new glTFPrimitives { - attributes=new glTFAttributes + attributes = new glTFAttributes { - POSITION=0, + POSITION = 0, } } - } + }, }; 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); Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(mesh, c); + Assert.AreEqual(json, json2); } [Test] public void PrimitiveTest() { - var prims = new List { - new glTFPrimitives + var prim = new glTFPrimitives + { + attributes = new glTFAttributes { - attributes = new glTFAttributes + POSITION = 0, + }, + extras = new glTFPrimitives_extras + { + targetNames = new List { - POSITION = 0, + "aaa", } } }; var f = new JsonFormatter(); - f.Serialize(prims); + f.Serialize(prim); var json = new Utf8String(f.GetStoreBytes()).ToString(); + Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json); Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(prim, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void AttributesTest() + { + var attrs = new glTFAttributes + { + POSITION = 0, + }; + + var f = new JsonFormatter(); + f.Serialize(attrs); + + var json = new Utf8String(f.GetStoreBytes()).ToString(); + Assert.AreEqual(@"{""POSITION"":0}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(attrs, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void TextureInfoTest() + { + var texi = new glTFMaterialBaseColorTextureInfo() + { + index = 1, + }; + + var f = new JsonFormatter(); + f.Serialize(texi); + + var json = new Utf8String(f.GetStoreBytes()).ToString(); + Assert.AreEqual(@"{""index"":1,""texCoord"":0}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(texi, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void TextureInfoTestError() + { + var texi = new glTFMaterialBaseColorTextureInfo(); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(texi, c) + ); + Assert.AreEqual("[index.String] minimum: ! -1>=0", ex.Message); + } + + [Test] + public void MaterialTest() + { + var texi = 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); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(texi, c); + Assert.AreEqual(json, json2); } [Test] @@ -267,5 +373,154 @@ namespace UniGLTF Assert.AreEqual(expected, actual); } + + public void MaterialTestError() + { + var texi = new glTFMaterial() + { + name = "b", + emissiveFactor = new float[] { 1.5f, 0.5f, 0.5f }, + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(texi, c) + ); + Assert.AreEqual("[emissiveFactor.String] maximum: ! 1.5<=1", ex.Message); + } + + [Test] + public void NodeTest() + { + var texi = 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); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(texi, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void NodeTestError() + { + var texi = new glTFNode() + { + name = "a", + camera = -2, + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(texi, c) + ); + Assert.AreEqual("[camera.String] minimum: ! -2>=0", ex.Message); + } + + [Test] + public void SkinTest() + { + var texi = 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); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(texi, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void SkinTestEmptyName() + { + var texi = new glTFSkin() + { + name = "", + joints = new int[] {1}, + }; + + var f = new JsonFormatter(); + f.Serialize(texi); + + var json = new Utf8String(f.GetStoreBytes()).ToString(); + // "name" = "", not excluded + Assert.AreEqual(@"{""joints"":[1],""name"":""""}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(texi, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void SkinTestErrorNull() + { + var texi = new glTFSkin() + { + name = "b", + joints = null, + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(texi, c) + ); + Assert.AreEqual("[joints.String] null", ex.Message); + } + + [Test] + public void SkinTestError() + { + var texi = new glTFSkin() + { + name = "b", + joints = new int[] {}, + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(texi, c) + ); + Assert.AreEqual("[joints.String] minItems", ex.Message); + } } } diff --git a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs index 4f846a782..b304bc0a3 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs @@ -20,7 +20,6 @@ namespace UniGLTF [Serializable] public partial class glTFPrimitives_extensions : ExtensionsBase { - [JsonSchema(Required = true)] public glTF_KHR_draco_mesh_compression KHR_draco_mesh_compression; [JsonSerializeMembers] diff --git a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFExtensions.cs b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFExtensions.cs index fefe47fea..20b649bcc 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFExtensions.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFExtensions.cs @@ -35,12 +35,12 @@ namespace UniGLTF } [ItemJsonSchema(ValueType = ValueNodeType.Object)] - [JsonSchema(MinProperties = 1)] + //[JsonSchema(MinProperties = 1)] public partial class ExtensionsBase : PartialExtensionBase { } - [JsonSchema(MinProperties = 1)] + //[JsonSchema(MinProperties = 1)] public partial class ExtraBase : PartialExtensionBase { } diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs index c4391d3c6..79fbaad53 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs @@ -30,7 +30,7 @@ namespace UniGLTF [JsonSchema(Required = true)] public glTFAssets asset = new glTFAssets(); - #region Buffer + #region Buffer [JsonSchema(MinItems = 1)] public List buffers = new List(); public int AddBuffer(IBytesBuffer bytesBuffer) @@ -197,10 +197,10 @@ namespace UniGLTF } #endregion - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List textures = new List(); - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List samplers = new List(); public glTFTextureSampler GetSampler(int index) { @@ -257,7 +257,7 @@ namespace UniGLTF } } - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List materials = new List(); public string GetUniqueMaterialName(int index) { @@ -288,7 +288,7 @@ namespace UniGLTF return MaterialHasVertexColor(materialIndex); } - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List meshes = new List(); public bool MaterialHasVertexColor(int materialIndex) @@ -302,16 +302,16 @@ namespace UniGLTF return hasVertexColor; } - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List nodes = new List(); - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List skins = new List(); [JsonSchema(Dependencies = new string[] { "scenes" }, Minimum = 0)] public int scene; - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List scenes = new List(); public int[] rootnodes { @@ -321,16 +321,16 @@ namespace UniGLTF } } - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List animations = new List(); - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List cameras = new List(); - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List extensionsUsed = new List(); - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] public List extensionsRequired = new List(); public glTF_extensions extensions = new glTF_extensions(); diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs index a7f70d3dd..526837b9f 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs @@ -7,25 +7,25 @@ namespace UniGLTF [Serializable] public class glTFAttributes : JsonSerializableBase { - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int POSITION = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int NORMAL = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int TANGENT = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int TEXCOORD_0 = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int COLOR_0 = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int JOINTS_0 = -1; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int WEIGHTS_0 = -1; public override int GetHashCode() @@ -66,8 +66,13 @@ namespace UniGLTF [Serializable] public class gltfMorphTarget : JsonSerializableBase { + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int POSITION = -1; + + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int NORMAL = -1; + + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int TANGENT = -1; protected override void SerializeMembers(GLTFJsonFormatter f) @@ -87,7 +92,7 @@ namespace UniGLTF [JsonSchema(EnumValues = new object[] { 0, 1, 2, 3, 4, 5, 6 })] public int mode; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int indices = -1; [JsonSchema(Required = true, SkipSchemaComparison = true)] @@ -104,7 +109,7 @@ namespace UniGLTF [JsonSchema(Minimum = 0)] public int material; - [JsonSchema(MinItems = 1)] + [JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)] [ItemJsonSchema(SkipSchemaComparison = true)] public List targets = new List(); diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFNode.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFNode.cs index a9dd07b6b..edef688f7 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFNode.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFNode.cs @@ -7,7 +7,8 @@ namespace UniGLTF [Serializable] public class glTFNode : JsonSerializableBase { - public string name = ""; + // TODO: need an empty string? + public string name; [JsonSchema(MinItems = 1)] [ItemJsonSchema(Minimum = 0)] @@ -26,20 +27,21 @@ namespace UniGLTF [JsonSchema(MinItems = 3, MaxItems = 3)] public float[] scale; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int mesh = -1; - [JsonSchema(Dependencies = new string[] { "mesh" }, Minimum = 0)] + [JsonSchema(Dependencies = new string[] { "mesh" }, Minimum = 0, ExplicitIgnorableValue = -1)] public int skin = -1; [JsonSchema(Dependencies = new string[] { "mesh" }, MinItems = 1)] public float[] weights; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int camera = -1; // empty schemas public glTFNode_extensions extensions; + public glTFNode_extra extras = new glTFNode_extra(); protected override void SerializeMembers(GLTFJsonFormatter f) diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFSkin.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFSkin.cs index fefad7259..aebffb10a 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFSkin.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFSkin.cs @@ -6,14 +6,14 @@ namespace UniGLTF [Serializable] public class glTFSkin : JsonSerializableBase { - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int inverseBindMatrices = -1; [JsonSchema(Required = true, MinItems = 1)] [ItemJsonSchema(Minimum = 0)] public int[] joints; - [JsonSchema(Minimum = 0)] + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] public int skeleton = -1; // empty schemas diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs index 199846b9e..6f53a7379 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs @@ -49,8 +49,8 @@ namespace UniGLTF public string name; public string uri; - [JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0)] - public int bufferView; + [JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0, ExplicitIgnorableValue = -1)] + public int bufferView = -1; [JsonSchema(EnumValues = new object[] { "image/jpeg", "image/png" }, EnumSerializationType =EnumSerializationType.AsString)] public string mimeType; diff --git a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs index 1ccc1510d..cf7d4a7d3 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs @@ -232,7 +232,7 @@ namespace UniGLTF } /// - /// + /// /// /// public void ParseGlb(Byte[] bytes) @@ -503,12 +503,14 @@ namespace UniGLTF .ContinueWithCoroutine(Scheduler.MainThread, LoadMaterials) .OnExecute(Scheduler.ThreadPool, parent => { + /* if (GLTF.meshes .SelectMany(x => x.primitives) .Any(x => x.extensions.KHR_draco_mesh_compression != null)) { throw new UniGLTFNotSupportedException("draco is not supported"); } + */ // meshes var meshImporter = new MeshImporter(); @@ -958,7 +960,7 @@ namespace UniGLTF /// Destroy resources that created ImporterContext for runtime load. /// public void DestroyRootAndResources() - { + { if (!Application.isPlaying) { Debug.LogWarningFormat("Dispose called in editor mode. This function is for runtime"); diff --git a/Assets/VRM/UniVRM/Scripts/Format/glTF_VRM_SecondaryAnimation.cs b/Assets/VRM/UniVRM/Scripts/Format/glTF_VRM_SecondaryAnimation.cs index c60107309..a293715d0 100644 --- a/Assets/VRM/UniVRM/Scripts/Format/glTF_VRM_SecondaryAnimation.cs +++ b/Assets/VRM/UniVRM/Scripts/Format/glTF_VRM_SecondaryAnimation.cs @@ -90,7 +90,10 @@ namespace VRM [JsonSchema(Title = "vrm.secondaryanimation", Description = "The setting of automatic animation of string-like objects such as tails and hairs.")] public class glTF_VRM_SecondaryAnimation : JsonSerializableBase { + [JsonSchema(ExplicitIgnorableItemLength = 0)] public List boneGroups = new List(); + + [JsonSchema(ExplicitIgnorableItemLength = 0)] public List colliderGroups = new List(); protected override void SerializeMembers(GLTFJsonFormatter f) From da2f7b8490299a9b3a67a5ceb78f72fafb67bb05 Mon Sep 17 00:00:00 2001 From: yutopp Date: Tue, 15 Jan 2019 17:56:44 +0900 Subject: [PATCH 02/19] Add experimental expoter option. Enable error checks for glTF --- Assets/VRM/UniGLTF/Scripts/Format/glTF.cs | 3 ++- Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs index 79fbaad53..2e0e4648a 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs @@ -503,7 +503,8 @@ namespace UniGLTF string json; if (UseUniJSONSerializer) { - json = JsonSchema.FromType(GetType()).Serialize(this); + var c = new JsonSchemaValidationContext(this); + json = JsonSchema.FromType(GetType()).Serialize(this, c); } else { diff --git a/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs b/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs index df919da7b..953ec0f78 100644 --- a/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs +++ b/Assets/VRM/UniVRM/Scripts/Format/VRMExportSettings.cs @@ -24,6 +24,8 @@ namespace VRM public bool PoseFreeze = true; + public bool UseExperimentalExporter = true; + public IEnumerable CanExport() { if (Source == null) @@ -250,7 +252,7 @@ namespace VRM } void Export(string path, List destroy) - { + { var target = Source; if (IsPrefab(target)) { @@ -277,7 +279,7 @@ namespace VRM vrm.extensions.VRM.meta.title = Title; vrm.extensions.VRM.meta.author = Author; - var bytes = vrm.ToGlbBytes(); + var bytes = vrm.ToGlbBytes(UseExperimentalExporter); File.WriteAllBytes(path, bytes); Debug.LogFormat("Export elapsed {0}", sw.Elapsed); } From 3516e488f123328dff45579a4b8e47d39beb9063 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 01:39:18 +0900 Subject: [PATCH 03/19] Support dependencies of JsonSchema. Fix tests to compare values which using ToJson and using JsonSchema. Restrict valudator --- Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs | 153 +++++----- .../Tests/Json/SerializeWithSchemaTests.cs | 48 +++- .../Editor/Tests/Json/ValidatorTests.cs | 31 +- .../Scripts/FormatterExtensionsSerializer.cs | 9 +- Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs | 5 +- .../JsonObjectValidator.cs | 264 +++++++++++------- 6 files changed, 336 insertions(+), 174 deletions(-) diff --git a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs index 8fea2ae6d..0b97c7620 100644 --- a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs +++ b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs @@ -150,7 +150,7 @@ namespace UniGLTF [Test] public void MeshTest() { - var mesh = new glTFMesh("mesh") + var model = new glTFMesh("mesh") { primitives = new List { @@ -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().Serialize(mesh, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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().Serialize(prim, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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().Serialize(attrs, c); + var json2 = JsonSchema.FromType().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().Serialize(texi, c); + var json2 = JsonSchema.FromType().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( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().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().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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().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( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().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().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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().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( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().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().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().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( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().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( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[joints.String] minItems", ex.Message); } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs index e5aacd5cb..d4bbcf99e 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs @@ -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(); + { + 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(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{}"; + + Assert.AreEqual(expected, actual); + } } } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs index 3a071c619..b08eba4c9 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs @@ -354,7 +354,7 @@ namespace UniJSON var s = JsonSchema.FromType(); - 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(); - Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List {} })); + Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List { } })); Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List { 0.5f } })); Assert.NotNull(s.Validator.Validate(c, new HasListObject { xs = new List { 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(); + + 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()); + } + } } } diff --git a/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs b/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs index 1273ee582..94abead16 100644 --- a/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs +++ b/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs @@ -162,7 +162,14 @@ namespace UniJSON { // reflection var schema = JsonSchema.FromType(); - 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); + }; } diff --git a/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs b/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs index 1957c4119..6ad4414c4 100644 --- a/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs +++ b/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs @@ -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); diff --git a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs index 631ae8563..703e60d18 100644 --- a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs +++ b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs @@ -297,28 +297,66 @@ namespace UniJSON } } + static class GenericFieldView + { + public static FieldInfo[] GetFields() + { + var t = typeof(T); + return t.GetFields(BindingFlags.Instance | BindingFlags.Public); + } + + public static void CreateFieldProcessors( + string methodName, + Dictionary 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)Expression.Lambda(call).Compile(); + + processors.Add(fi.Name, lambda()); + } + } + } + + internal class ValidationResult + { + public bool IsIgnorable; + public JsonSchemaValidationException Ex; + } + public static class GenericValidator { class ObjectValidator { delegate JsonSchemaValidationException FieldValidator( - JsonSchema s, JsonSchemaValidationContext c, T o, bool isRequired); + JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable); - Dictionary m_validators = new Dictionary(); + Dictionary m_validators; static FieldValidator CreteFieldValidator(Func 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(); + GenericFieldView.CreateFieldProcessors( + "CreteFieldValidator", validators); - var t = typeof(T); - foreach(var fi in t.GetFields( - BindingFlags.Instance|BindingFlags.Public)) + m_validators = validators; + } + + public JsonSchemaValidationException ValidateProperty( + HashSet required, + KeyValuePair 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)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 required, + Dictionary properties, + JsonSchemaValidationContext c, T o, + Dictionary 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 required, - Dictionary properties, - JsonSchemaValidationContext c, T o) + static void prepareValidator() { if (s_validator == null) { s_validator = new ObjectValidator(); } + } + + public static JsonSchemaValidationException Validate(HashSet required, + Dictionary properties, + JsonSchemaValidationContext c, T o) + { + prepareValidator(); return s_validator.Validate(required, properties, c, o); } + + internal static void ValidationResults(HashSet required, + Dictionary properties, + JsonSchemaValidationContext c, T o, + Dictionary results) + { + prepareValidator(); + s_validator.ValidationResults(required, properties, c, o, results); + } } public JsonSchemaValidationException Validate(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 vRes, string[] deps); - List m_fieldSerializers = new List(); + Dictionary m_serializers; - static FieldSerializer CreateSerializer(FieldInfo fi) + static FieldSerializer CreteFieldSerializer(Func getter, string name) { - var src = Expression.Parameter(typeof(T), "src"); - var getter = Expression.Field(src, fi); - var compiled = (Func)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)Expression.Lambda(call).Compile(); - m_fieldSerializers.Add(compiled()); + var serializers = new Dictionary(); + GenericFieldView.CreateFieldProcessors( + "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(); + GenericValidator.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); } } From 029faf2875fe8a4c91676c1253306d427b1e82e1 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 15:14:58 +0900 Subject: [PATCH 04/19] Fix typo --- .../Scripts/JsonSchemaValidator/JsonObjectValidator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs index 703e60d18..2c6de6c23 100644 --- a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs +++ b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs @@ -346,7 +346,7 @@ namespace UniJSON Dictionary m_validators; - static FieldValidator CreteFieldValidator(Func getter, string name) + static FieldValidator CreateFieldValidator(Func getter, string name) { return (JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable) => { @@ -367,7 +367,7 @@ namespace UniJSON { var validators = new Dictionary(); GenericFieldView.CreateFieldProcessors( - "CreteFieldValidator", validators); + "CreateFieldValidator", validators); m_validators = validators; } @@ -496,7 +496,7 @@ namespace UniJSON Dictionary m_serializers; - static FieldSerializer CreteFieldSerializer(Func getter, string name) + static FieldSerializer CreateFieldSerializer(Func getter, string name) { return (s, c, f, o, vRes, deps) => { @@ -528,7 +528,7 @@ namespace UniJSON { var serializers = new Dictionary(); GenericFieldView.CreateFieldProcessors( - "CreteFieldSerializer", serializers); + "CreateFieldSerializer", serializers); m_serializers = serializers; } From af1251e0365b38b505d7a3fb298d4f4556d966b6 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 16:26:00 +0900 Subject: [PATCH 05/19] Add tests --- Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs | 41 +++++++++++++++++- .../Tests/Json/SerializeWithSchemaTests.cs | 42 +++++++++++++++++++ .../Editor/Tests/Json/ValidatorTests.cs | 24 +++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs index 0b97c7620..f55fa3231 100644 --- a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs +++ b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs @@ -464,7 +464,7 @@ namespace UniGLTF joints = new int[] {1}, }; - var json = model.ToJson(); + var json = model.ToJson(); Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json); Debug.Log(json); @@ -535,5 +535,44 @@ namespace UniGLTF ); Assert.AreEqual("[joints.String] minItems", ex.Message); } + + [Test] + public void AssetsTest() + { + var model = new glTFAssets() + { + version = "0.49", + }; + + //var json = model.ToJson(); + //Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json); + //Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""version"":""0.49""}", json2); + } + + [Test] + public void AssetsTestError() + { + var model = new glTFAssets(); + + //var json = model.ToJson(); + //Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json); + //Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(model, c) + ); + Assert.AreEqual("[version.String] null", ex.Message); + } } } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs index d4bbcf99e..1f0667f9b 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs @@ -123,5 +123,47 @@ namespace UniJSON Assert.AreEqual(expected, actual); } + + public class HasStringTest + { + public string X; + } + + [Test] + public void TestHasString() + { + var obj = new HasStringTest() + { + X = "a", + }; + + var s = JsonSchema.FromType(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{""X"":""a""}"; + + Assert.AreEqual(expected, actual); + } + + [Test] + public void TestHasStringWithNull() + { + var obj = new HasStringTest(); + + var s = JsonSchema.FromType(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{}"; + + Assert.AreEqual(expected, actual); + } } } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs index b08eba4c9..d57f44008 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs @@ -413,5 +413,29 @@ namespace UniJSON Assert.True(c.IsEmpty()); } } + + class HasRequiredStringObject + { + [JsonSchema(Required = true)] + public string s; + } + + [Test] + public void HasRequiredStringObjectValidator() + { + { + var c = new JsonSchemaValidationContext("test") + { + EnableDiagnosisForNotRequiredFields = true, + }; + + var s = JsonSchema.FromType(); + + Assert.NotNull(s.Validator.Validate(c, new HasRequiredStringObject())); + Assert.Null(s.Validator.Validate(c, new HasRequiredStringObject { s = "" })); + + Assert.True(c.IsEmpty()); + } + } } } From 66d8adc191e3048a6e48c53aaa283140faa98697 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 17:40:19 +0900 Subject: [PATCH 06/19] Fix validation configs for JsonSchema when converting to glb bytes --- Assets/VRM/UniGLTF/Scripts/Format/glTF.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs index 2e0e4648a..7df4bd651 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTF.cs @@ -503,7 +503,10 @@ namespace UniGLTF string json; if (UseUniJSONSerializer) { - var c = new JsonSchemaValidationContext(this); + var c = new JsonSchemaValidationContext(this) + { + EnableDiagnosisForNotRequiredFields = true, + }; json = JsonSchema.FromType(GetType()).Serialize(this, c); } else From b2e37c60a1b5e0d02fe669ac196d9d2fccf1b4b5 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 17:40:26 +0900 Subject: [PATCH 07/19] Add tests --- .../Tests/Json/SerializeWithSchemaTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs index 1f0667f9b..1d022739e 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs @@ -165,5 +165,36 @@ namespace UniJSON Assert.AreEqual(expected, actual); } + + public class NestedRequiredTestParent + { + [JsonSchema(Required = true)] + public NestedRequiredTestChild C; + } + + public class NestedRequiredTestChild + { + public string X; + } + + [Test] + public void TestNestedRequired() + { + var obj = new NestedRequiredTestParent() + { + C = new NestedRequiredTestChild(), + }; + + var s = JsonSchema.FromType(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{""C"":{}}"; + + Assert.AreEqual(expected, actual); + } } } From b99a2c39ea7a2cd402b34d717f7724612e50fed4 Mon Sep 17 00:00:00 2001 From: yutopp Date: Wed, 16 Jan 2019 18:39:30 +0900 Subject: [PATCH 08/19] Rename variable names. Add exporting pass which using JsonSchema --- .../Editor/Tests/VRMImportExportTests.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs index fd910333e..3222dc800 100644 --- a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs +++ b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using System.IO; +using UniGLTF; using UniJSON; using UnityEngine; @@ -41,15 +42,15 @@ namespace VRM.Samples using (new ActionDisposer(() => { GameObject.DestroyImmediate(context.Root); })) { - var importJson = JsonParser.Parse(context.Json); - importJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION); - importJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION); - importJson.SetValue("/scene", 0); - importJson.SetValue("/materials/*/doubleSided", false); + var importedJson = JsonParser.Parse(context.Json); + importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION); + importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION); + importedJson.SetValue("/scene", 0); + importedJson.SetValue("/materials/*/doubleSided", false); //importJson.SetValue("/materials/*/pbrMetallicRoughness/roughnessFactor", 0); //importJson.SetValue("/materials/*/pbrMetallicRoughness/baseColorFactor", new float[] { 1, 1, 1, 1 }); - importJson.SetValue("/accessors/*/normalized", false); - importJson.RemoveValue(Utf8String.From("/nodes/*/extras")); + importedJson.SetValue("/accessors/*/normalized", false); + importedJson.RemoveValue(Utf8String.From("/nodes/*/extras")); /* importJson.SetValue("/bufferViews/12/byteStride", 4); importJson.SetValue("/bufferViews/13/byteStride", 4); @@ -78,11 +79,14 @@ namespace VRM.Samples importJson.SetValue("/bufferViews/252/byteStride", 64); importJson.SetValue("/bufferViews/253/byteStride", 64); */ - importJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); + importedJson.RemoveValue(Utf8String.From("/bufferViews/*/byteStride")); var vrm = VRMExporter.Export(context.Root); + var exportJson = JsonParser.Parse(vrm.ToJson()); + var newExportedJson = JsonParser.Parse(JsonSchema.FromType().Serialize(vrm)); + /* foreach (var kv in importJson.Diff(exportJson)) { From 120dc429015035647a34aed59613e6c121d91d6d Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 15:00:16 +0900 Subject: [PATCH 09/19] Fix a default value of glTFTexture.bufferView (Use 0 intead to save compatibility). --- Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs index 6f53a7379..199846b9e 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFTexture.cs @@ -49,8 +49,8 @@ namespace UniGLTF public string name; public string uri; - [JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0, ExplicitIgnorableValue = -1)] - public int bufferView = -1; + [JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0)] + public int bufferView; [JsonSchema(EnumValues = new object[] { "image/jpeg", "image/png" }, EnumSerializationType =EnumSerializationType.AsString)] public string mimeType; From a5ab17049cae245b52b45ff1aeb93591147922ae Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 18:57:09 +0900 Subject: [PATCH 10/19] Add tests for JsonUtility to change deserializer in future --- .../UniGLTF/Editor/JsonDeserializeTests.cs | 36 +++++++++++++++++++ .../Editor/JsonDeserializeTests.cs.meta | 3 ++ 2 files changed, 39 insertions(+) create mode 100644 Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs create mode 100644 Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs.meta diff --git a/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs new file mode 100644 index 000000000..fcccff774 --- /dev/null +++ b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using UnityEngine; + +namespace UniGLTF +{ + public class JsonDeserializeTests + { + static T deserialize(string json) + { + return JsonUtility.FromJson(json); + } + + [Test] + public void PrimitivesExtensionsTest() + { + { + var r = deserialize(""); + Assert.AreEqual(null, r); + } + + { + var r = deserialize("{}"); + Assert.NotNull(r); + // This is a curious behaviour of JsonUtility. + // TODO: We should replace a library which treats JSON from JsonUtility + //Assert.Null(r.KHR_draco_mesh_compression); + } + + { + var r = deserialize("{\"KHR_draco_mesh_compression\":{}}"); + Assert.NotNull(r); + Assert.NotNull(r.KHR_draco_mesh_compression); + } + } + } +} diff --git a/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs.meta b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs.meta new file mode 100644 index 000000000..84f6aba85 --- /dev/null +++ b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6dab77b78a3d45bf8c20e7dcc8046881 +timeCreated: 1547715653 \ No newline at end of file From d2709ea4fda2366eea55d98bc23582c9a2ee32b0 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 19:06:46 +0900 Subject: [PATCH 11/19] Change a logic to check draco to a way written in the specification --- Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs index cf7d4a7d3..7c9d2da87 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs @@ -503,14 +503,12 @@ namespace UniGLTF .ContinueWithCoroutine(Scheduler.MainThread, LoadMaterials) .OnExecute(Scheduler.ThreadPool, parent => { - /* - if (GLTF.meshes - .SelectMany(x => x.primitives) - .Any(x => x.extensions.KHR_draco_mesh_compression != null)) + // UniGLTF does not support draco + // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md#conformance + if (GLTF.extensionsRequired.Contains("KHR_draco_mesh_compression")) { throw new UniGLTFNotSupportedException("draco is not supported"); } - */ // meshes var meshImporter = new MeshImporter(); From 60544f0f1ae150cee9a4d08c51cc0aec2583a212 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 19:27:44 +0900 Subject: [PATCH 12/19] Add tests for serializer of VRM BlendShapes --- .../Editor/Tests/UniVRMSerializeTests.cs | 104 ++++++++++++++++++ .../Editor/Tests/UniVRMSerializeTests.cs.meta | 3 + 2 files changed, 107 insertions(+) create mode 100644 Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs create mode 100644 Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs.meta diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs new file mode 100644 index 000000000..eda7e0163 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -0,0 +1,104 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; +using UnityEngine; + +namespace VRM +{ + public class UniVRMSerializeTests + { + [Test] + public void MaterialValueBindTest() + { + var model = new glTF_VRM_MaterialValueBind(); + + var json = model.ToJson(); + Assert.AreEqual(@"{}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void BlendShapeBindTest() + { + var model = new glTF_VRM_BlendShapeBind() + { + mesh = 1, + weight = 2, + index = 3, + }; + + var json = model.ToJson(); + Assert.AreEqual(@"{""mesh"":1,""index"":3,""weight"":2}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void BlendShapeBindTestError() + { + var model = new glTF_VRM_BlendShapeBind(); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(model, c) + ); + Assert.AreEqual("[mesh.String] minimum: ! -1>=0", ex.Message); + } + + [Test] + public void BlendShapeGroupTest() + { + var model = new glTF_VRM_BlendShapeGroup() + { + presetName = "neutral", + }; + + var json = model.ToJson(); + Assert.AreEqual(@"{""presetName"":""neutral"",""isBinary"":false,""binds"":[],""materialValues"":[]}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""presetName"":""neutral"",""binds"":[],""materialValues"":[],""isBinary"":false}", json2); + } + + [Test] + public void BlendShapeGroupTestError() + { + var model = new glTF_VRM_BlendShapeGroup() + { + presetName = "aaaaaaaaaaaa_not_exists_", + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var ex = Assert.Throws( + () => JsonSchema.FromType().Serialize(model, c) + ); + Assert.AreEqual("[presetName.String] aaaaaaaaaaaa_not_exists_ is not valid enum", ex.Message); + } + } +} diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs.meta b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs.meta new file mode 100644 index 000000000..60e8389fb --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 06e8ebf6af2b4e19a0c72ad986e88444 +timeCreated: 1547719804 \ No newline at end of file From 90a12b33ce5f07d8130f239e953e267433c604e5 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 19:45:17 +0900 Subject: [PATCH 13/19] Add tests for serializer of VRM FirstPerson --- .../Editor/Tests/UniVRMSerializeTests.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index eda7e0163..c399a16fd 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -100,5 +100,56 @@ namespace VRM ); Assert.AreEqual("[presetName.String] aaaaaaaaaaaa_not_exists_ is not valid enum", ex.Message); } + + [Test] + public void DegreeMapTest() + { + var model = new glTF_VRM_DegreeMap(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""xRange"":90,""yRange"":10}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void MeshAnnotationTest() + { + var model = new glTF_VRM_MeshAnnotation(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""mesh"":0}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(json, json2); + } + + [Test] + public void FirstPersonTest() + { + var model = new glTF_VRM_Firstperson(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", json2); + } } } From ab6b22af68db9a55ba7d02a825d13cf9e39103f2 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 19:50:01 +0900 Subject: [PATCH 14/19] Formatting --- Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index c399a16fd..ab024085d 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -141,7 +141,9 @@ namespace VRM var model = new glTF_VRM_Firstperson(); var json = model.ToJson(); - Assert.AreEqual(@"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", json); + Assert.AreEqual( + @"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", + json); Debug.Log(json); var c = new JsonSchemaValidationContext("") @@ -149,7 +151,9 @@ namespace VRM EnableDiagnosisForNotRequiredFields = true, }; var json2 = JsonSchema.FromType().Serialize(model, c); - Assert.AreEqual(@"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", json2); - } + Assert.AreEqual( + @"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", + json2); + } } } From 0bbf103beb3316869b71a550d1279ba0ddb64e26 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 20:04:52 +0900 Subject: [PATCH 15/19] Add tests for serializer of VRM Humanoid --- .../Editor/Tests/UniVRMSerializeTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index ab024085d..eac293fb7 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -155,5 +155,46 @@ namespace VRM @"{""firstPersonBone"":-1,""firstPersonBoneOffset"":{""x"":0,""y"":0,""z"":0},""meshAnnotations"":[],""lookAtTypeName"":""Bone"",""lookAtHorizontalInner"":{""xRange"":90,""yRange"":10},""lookAtHorizontalOuter"":{""xRange"":90,""yRange"":10},""lookAtVerticalDown"":{""xRange"":90,""yRange"":10},""lookAtVerticalUp"":{""xRange"":90,""yRange"":10}}", json2); } + + [Test] + public void HumanoidBoneTest() + { + var model = new glTF_VRM_HumanoidBone() + { + bone = "hips", // NOTE: This field must not be null? + }; + + var json = model.ToJson(); + Assert.AreEqual(@"{""bone"":""hips"",""node"":-1,""useDefaultValues"":true}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual( + @"{""bone"":""hips"",""node"":-1,""useDefaultValues"":true,""min"":{""x"":0,""y"":0,""z"":0},""max"":{""x"":0,""y"":0,""z"":0},""center"":{""x"":0,""y"":0,""z"":0},""axisLength"":0}", + json2); + } + + [Test] + public void HumanoidTest() + { + var model = new glTF_VRM_Humanoid(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""humanBones"":[],""armStretch"":0.05,""legStretch"":0.05,""upperArmTwist"":0.5,""lowerArmTwist"":0.5,""upperLegTwist"":0.5,""lowerLegTwist"":0.5,""feetSpacing"":0,""hasTranslationDoF"":false}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } } } From fa72052f039ce1e4b1b2338ad65e7c81678f53a8 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 20:09:57 +0900 Subject: [PATCH 16/19] Add tests for serializer of VRM Material --- .../Editor/Tests/UniVRMSerializeTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index eac293fb7..fdda5367f 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -196,5 +196,23 @@ namespace VRM // NOTE: New serializer outputs values which will not be used... Assert.AreEqual(json,json2); } + + [Test] + public void MaterialTest() + { + var model = new glTF_VRM_Material(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""renderQueue"":-1,""floatProperties"":{},""vectorProperties"":{},""textureProperties"":{},""keywordMap"":{},""tagMap"":{}}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } } } From cef2f3f92ad4ddcffdccb0e2fcb4e760b213ea82 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 20:19:06 +0900 Subject: [PATCH 17/19] Add tests for serializer of VRM Meta --- .../Editor/Tests/UniVRMSerializeTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index fdda5367f..7db2774df 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -214,5 +214,23 @@ namespace VRM // NOTE: New serializer outputs values which will not be used... Assert.AreEqual(json,json2); } + + [Test] + public void MetaTest() + { + var model = new glTF_VRM_Meta(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""texture"":-1}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } } } From c0e2455e0e8616064cafa471cc5de0917ed35291 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 20:34:17 +0900 Subject: [PATCH 18/19] Add tests for serializer of VRM SecondaryAnimation --- .../Editor/Tests/UniVRMSerializeTests.cs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs index 7db2774df..1213fbba1 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRMSerializeTests.cs @@ -232,5 +232,81 @@ namespace VRM // NOTE: New serializer outputs values which will not be used... Assert.AreEqual(json,json2); } + + [Test] + public void SecondaryAnimationColliderTest() + { + var model = new glTF_VRM_SecondaryAnimationCollider() + { + offset = new Vector3(1, 2, 3), + radius = 42, + }; + + var json = model.ToJson(); + Assert.AreEqual(@"{""offset"":{""x"":1,""y"":2,""z"":3},""radius"":42}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } + + [Test] + public void SecondaryAnimationColliderGroupTest() + { + var model = new glTF_VRM_SecondaryAnimationColliderGroup(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""node"":0,""colliders"":[]}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } + + [Test] + public void SecondaryAnimationGroupTest() + { + var model = new glTF_VRM_SecondaryAnimationGroup(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""stiffiness"":0,""gravityPower"":0,""gravityDir"":{""x"":0,""y"":0,""z"":0},""dragForce"":0,""center"":0,""hitRadius"":0,""bones"":[],""colliderGroups"":[]}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } + + [Test] + public void SecondaryAnimationTest() + { + var model = new glTF_VRM_SecondaryAnimation(); + + var json = model.ToJson(); + Assert.AreEqual(@"{""boneGroups"":[],""colliderGroups"":[]}", json); + Debug.Log(json); + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json2 = JsonSchema.FromType().Serialize(model, c); + // NOTE: New serializer outputs values which will not be used... + Assert.AreEqual(json,json2); + } } } From 38a0a7a715ca282ed4650c02ea8d4248d80ca4ef Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 17 Jan 2019 20:58:58 +0900 Subject: [PATCH 19/19] Remove draco related fields to ignore extensions field. Extensions are already checked by 'ExtentionsUsed' field, it is safe to remove --- Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs | 2 +- Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs | 4 ++-- .../KHR_draco_mesh_compression.cs | 15 --------------- Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs | 6 +----- 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs index fcccff774..e056df6f6 100644 --- a/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs +++ b/Assets/VRM/UniGLTF/Editor/JsonDeserializeTests.cs @@ -29,7 +29,7 @@ namespace UniGLTF { var r = deserialize("{\"KHR_draco_mesh_compression\":{}}"); Assert.NotNull(r); - Assert.NotNull(r.KHR_draco_mesh_compression); + //Assert.NotNull(r.KHR_draco_mesh_compression); } } } diff --git a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs index f55fa3231..5df2d0a1d 100644 --- a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs +++ b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs @@ -173,7 +173,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var json2 = JsonSchema.FromType().Serialize(model, c); - Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extensions"":{}}]}", json2); + Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0}]}", json2); } [Test] @@ -203,7 +203,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var json2 = JsonSchema.FromType().Serialize(model, c); - Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json2); + Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]}}", json2); } [Test] diff --git a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs index b304bc0a3..1e4b9ae48 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/KHR_draco_mesh_compression.cs @@ -4,24 +4,9 @@ using UniJSON; namespace UniGLTF { - [Serializable] - public class glTF_KHR_draco_mesh_compression : JsonSerializableBase - { - [JsonSchema(Required = true, Minimum = 0)] - public int bufferView = -1; - public glTFAttributes attributes; - - protected override void SerializeMembers(GLTFJsonFormatter f) - { - //throw new NotImplementedException(); - } - } - [Serializable] public partial class glTFPrimitives_extensions : ExtensionsBase { - public glTF_KHR_draco_mesh_compression KHR_draco_mesh_compression; - [JsonSerializeMembers] void SerializeMembers_draco(GLTFJsonFormatter f) { diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs index 526837b9f..315041653 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs @@ -116,7 +116,7 @@ namespace UniGLTF public glTFPrimitives_extras extras = new glTFPrimitives_extras(); [JsonSchema(SkipSchemaComparison = true)] - public glTFPrimitives_extensions extensions = new glTFPrimitives_extensions(); + public glTFPrimitives_extensions extensions = null; protected override void SerializeMembers(GLTFJsonFormatter f) { @@ -128,10 +128,6 @@ namespace UniGLTF { f.Key("targets"); f.GLTFValue(targets); } - if (extensions.KHR_draco_mesh_compression != null) - { - f.Key("extensions"); f.GLTFValue(extensions); - } if (extras.targetNames.Count > 0) { f.Key("extras"); f.GLTFValue(extras);