Browse Source

Added khronos gltf validator for unit testing. (WIP, a few tests fail)

Vicente Penades 5 years ago
parent
commit
cdb990d2c6

+ 6 - 0
src/SharpGLTF.Core/Memory/InMemoryImage.cs

@@ -41,6 +41,12 @@ namespace SharpGLTF.Memory
 
 
         public InMemoryImage(Byte[] image) { _Image = image == null ? default : new ArraySegment<byte>(image); }
         public InMemoryImage(Byte[] image) { _Image = image == null ? default : new ArraySegment<byte>(image); }
 
 
+        public InMemoryImage(string filePath)
+        {
+            var data = System.IO.File.ReadAllBytes(filePath);
+            _Image = new ArraySegment<byte>(data);
+        }
+
         #endregion
         #endregion
 
 
         #region data
         #region data

+ 2 - 0
src/SharpGLTF.Toolkit/Geometry/MeshBuilder.cs

@@ -97,8 +97,10 @@ namespace SharpGLTF.Geometry
 
 
         #region data
         #region data
 
 
+        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         private readonly Dictionary<(TMaterial Material, int PrimType), PrimitiveBuilder<TMaterial, TvG, TvM, TvS>> _Primitives = new Dictionary<(TMaterial, int), PrimitiveBuilder<TMaterial, TvG, TvM, TvS>>();
         private readonly Dictionary<(TMaterial Material, int PrimType), PrimitiveBuilder<TMaterial, TvG, TvM, TvS>> _Primitives = new Dictionary<(TMaterial, int), PrimitiveBuilder<TMaterial, TvG, TvM, TvS>>();
 
 
+        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         private VertexPreprocessor<TvG, TvM, TvS> _VertexPreprocessor;
         private VertexPreprocessor<TvG, TvM, TvS> _VertexPreprocessor;
 
 
         #endregion
         #endregion

+ 6 - 1
tests/SharpGLTF.Tests/SharpGLTF.Tests.csproj

@@ -8,7 +8,7 @@
     <RootNamespace>SharpGLTF</RootNamespace>
     <RootNamespace>SharpGLTF</RootNamespace>
 
 
     <LangVersion>latest</LangVersion>
     <LangVersion>latest</LangVersion>
-  </PropertyGroup>
+  </PropertyGroup>  
 
 
   <ItemGroup>
   <ItemGroup>
     <None Remove="Assets\SpecialCases\mouse.glb" />
     <None Remove="Assets\SpecialCases\mouse.glb" />
@@ -20,6 +20,11 @@
     </Content>
     </Content>
   </ItemGroup>
   </ItemGroup>
 
 
+  <ItemGroup>
+    <None Include="..\..\tools\linux64\gltf_validator" Link="gltf_validator" />
+    <None Include="..\..\tools\win64\gltf_validator.exe" Link="gltf_validator.exe" />
+  </ItemGroup>
+
   <ItemGroup>    
   <ItemGroup>    
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />    
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />    
     <PackageReference Include="nunit" Version="3.12.0" />
     <PackageReference Include="nunit" Version="3.12.0" />

+ 36 - 22
tests/SharpGLTF.Tests/Utils.cs

@@ -113,28 +113,7 @@ namespace SharpGLTF
             context.AttachLink("🌍 VirtualGIS Cesium Sandbox", "https://www.virtualgis.io/gltfviewer/");
             context.AttachLink("🌍 VirtualGIS Cesium Sandbox", "https://www.virtualgis.io/gltfviewer/");
         }
         }
 
 
-        public static void AttachToCurrentTest(this Schema2.ModelRoot model, string fileName)
-        {
-            // find the output path for the current test
-            fileName = TestContext.CurrentContext.GetAttachmentPath(fileName, true);
-
-            if (fileName.ToLower().EndsWith(".glb"))
-            {
-                model.SaveGLB(fileName);
-            }
-            else if (fileName.ToLower().EndsWith(".gltf"))
-            {
-                model.Save(fileName, new Schema2.WriteSettings { JsonIndented=true } );
-            }
-            else if (fileName.ToLower().EndsWith(".obj"))
-            {
-                fileName = fileName.Replace(" ", "_");
-                Schema2.Schema2Toolkit.SaveAsWavefront(model, fileName);
-            }
-
-            // Attach the saved file to the current test
-            TestContext.AddTestAttachment(fileName);
-        }
+        
 
 
         public static void AttachToCurrentTest(this Scenes.SceneBuilder scene, string fileName)
         public static void AttachToCurrentTest(this Scenes.SceneBuilder scene, string fileName)
         {
         {
@@ -170,6 +149,41 @@ namespace SharpGLTF
 
 
             gl2model.AttachToCurrentTest(fileName);
             gl2model.AttachToCurrentTest(fileName);
         }
         }
+
+        public static void AttachToCurrentTest(this Schema2.ModelRoot model, string fileName)
+        {
+            // find the output path for the current test
+            fileName = TestContext.CurrentContext.GetAttachmentPath(fileName, true);
+
+            if (fileName.ToLower().EndsWith(".glb"))
+            {
+                model.SaveGLB(fileName);
+            }
+            else if (fileName.ToLower().EndsWith(".gltf"))
+            {
+                model.Save(fileName, new Schema2.WriteSettings { JsonIndented = true });
+            }
+            else if (fileName.ToLower().EndsWith(".obj"))
+            {
+                fileName = fileName.Replace(" ", "_");
+                Schema2.Schema2Toolkit.SaveAsWavefront(model, fileName);
+            }
+
+            // Attach the saved file to the current test
+            TestContext.AddTestAttachment(fileName);
+
+            if (fileName.ToLower().EndsWith(".obj")) return;
+
+            var report = gltf_validator.ValidateFile(fileName);
+            if (report == null) return;
+
+            if (report.HasErrors || report.HasWarnings)
+            {
+                TestContext.WriteLine(report.ToString());
+            }
+
+            Assert.IsFalse(report.HasErrors);
+        }
     }
     }
 
 
     static class VectorsUtils
     static class VectorsUtils

+ 123 - 0
tests/SharpGLTF.Tests/gltf_validator.cs

@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace SharpGLTF
+{
+    /// <summary>
+    /// Wraps Khronos GLTF Validator command line tool.
+    /// </summary>
+    /// <see href="https://github.com/KhronosGroup/glTF-Validator"/>
+    /// <remarks>
+    /// LINUX execution path has not been tested!
+    /// </remarks>
+    static class gltf_validator
+    {
+        static gltf_validator()
+        {
+            if (RuntimeInformation.OSArchitecture != Architecture.X64) return;
+
+            ValidatorExePath = System.IO.Path.GetDirectoryName(typeof(gltf_validator).Assembly.Location);
+
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                ValidatorExePath = System.IO.Path.Combine(ValidatorExePath, "gltf_validator.exe");
+            }
+
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+            {
+                ValidatorExePath = System.IO.Path.Combine(ValidatorExePath, "gltf_validator");
+            }
+        }
+
+        public static string ValidatorExePath { get; set; }
+
+        public static ValidationReport ValidateFile(string gltfFilePath)
+        {
+            if (string.IsNullOrWhiteSpace(ValidatorExePath)) return null;
+
+            if (!System.IO.File.Exists(ValidatorExePath)) throw new System.IO.FileNotFoundException(ValidatorExePath);
+
+            if (!System.IO.Path.IsPathRooted(gltfFilePath)) gltfFilePath = System.IO.Path.GetFullPath(gltfFilePath);
+
+            var psi = new System.Diagnostics.ProcessStartInfo(ValidatorExePath);
+            psi.Arguments = $"-p -r -a \"{gltfFilePath}\"";
+            psi.UseShellExecute = false;            
+            psi.RedirectStandardError = true;
+
+            var p = System.Diagnostics.Process.Start(psi);
+
+            if (!p.WaitForExit(1000 * 10))
+            {
+                try { p.Kill(); } catch { }
+            }
+
+            var rawReport = p.StandardError.ReadToEnd();
+
+            if (string.IsNullOrWhiteSpace(rawReport)) return null;
+
+            return new ValidationReport(gltfFilePath, rawReport);
+        }
+
+        public sealed class ValidationReport
+        {
+            internal ValidationReport(string srcPath, string rawReport)
+            {
+                var lines = rawReport.Split('\n');
+
+                var status = 0;
+
+                var www = new List<string>();
+                var eee = new List<string>();
+
+                foreach (var l in lines)
+                {
+                    if (l == "\tWarnings:") { status = 1; continue; }
+                    if (l == "\tErrors:") { status = 2; continue; }
+
+                    if (status == 1) www.Add(l.Trim());
+                    if (status == 2) eee.Add(l.Trim());
+                }
+
+                FilePath = srcPath;
+                RawReport = rawReport;
+                Warnings = www;
+                Errors = eee;
+            }
+
+            public string RawReport { get; private set; }
+
+            public readonly IReadOnlyList<String> Warnings;
+            public readonly IReadOnlyList<String> Errors;
+
+            public string FilePath { get; private set; }
+
+            public bool HasWarnings => Warnings.Count > 0;
+            public bool HasErrors => Errors.Count > 0;
+
+            public string ToString()
+            {
+                return RawReport;
+
+                var sb = new StringBuilder();
+
+                sb.AppendLine(FilePath);
+
+                if (HasWarnings)
+                {
+                    sb.AppendLine("\tWarnings:");
+                    foreach (var w in Warnings) sb.AppendLine($"\t\t{w}");
+                }
+
+                if (HasErrors)
+                {
+                    sb.AppendLine("\tErrors:");
+                    foreach (var e in Errors) sb.AppendLine($"\t\t{e}");
+                }
+
+                return sb.ToString();
+            }
+        }
+    }
+}

BIN
tools/linux64/gltf_validator


BIN
tools/win64/gltf_validator.exe