Browse Source

Tests: Moved test files download out of the tests, and added tests for both Net471 and netcoreapp2.2
+refactors, code cleanup & docs.

Vicente Penades 6 years ago
parent
commit
0d6d1e349b
34 changed files with 454 additions and 189 deletions
  1. 7 0
      SharpGLTF.sln
  2. 3 1
      src/SharpGLTF.Core/Debug/DebuggerDisplay.cs
  3. 88 30
      src/SharpGLTF.Core/Memory/FloatingArrays.cs
  4. 14 6
      src/SharpGLTF.Core/Memory/IntegerArrays.cs
  5. 5 5
      src/SharpGLTF.Toolkit/Geometry/MeshBuilderToolkit.cs
  6. 14 0
      src/SharpGLTF.Toolkit/Geometry/PrimitiveBuilder.cs
  7. 8 0
      src/SharpGLTF.Toolkit/Geometry/VertexBuilder.cs
  8. 2 2
      src/SharpGLTF.Toolkit/Materials/ChannelBuilder.cs
  9. 4 4
      src/SharpGLTF.Toolkit/Materials/MaterialBuilder.cs
  10. 1 1
      src/SharpGLTF.Toolkit/Materials/MaterialEnums.cs
  11. 4 0
      src/SharpGLTF.Toolkit/Scenes/CameraBuilder.cs
  12. 7 0
      src/SharpGLTF.Toolkit/Scenes/LightBuilder.cs
  13. 2 0
      src/SharpGLTF.Toolkit/Scenes/SceneBuilder.Schema2.cs
  14. 8 0
      src/SharpGLTF.Toolkit/Scenes/Transformers.cs
  15. 7 0
      tests/0_Readme.txt
  16. 2 0
      tests/1_DownloadTestFiles.cmd
  17. 2 0
      tests/2_RunTests.cmd
  18. 73 0
      tests/SharpGLTF.DownloadTestFiles/DownloadUtils.cs
  19. 67 0
      tests/SharpGLTF.DownloadTestFiles/ExampleFiles.cs
  20. 18 0
      tests/SharpGLTF.DownloadTestFiles/Program.cs
  21. 13 0
      tests/SharpGLTF.DownloadTestFiles/SharpGLTF.DownloadTestFiles.csproj
  22. 3 3
      tests/SharpGLTF.Tests/Geometry/MeshBuilderTests.cs
  23. 1 1
      tests/SharpGLTF.Tests/Geometry/Parametric/SolidMeshUtils.cs
  24. 6 2
      tests/SharpGLTF.Tests/NumericsAssert.cs
  25. 4 4
      tests/SharpGLTF.Tests/Plotting.cs
  26. 6 6
      tests/SharpGLTF.Tests/Scenes/SceneBuilderTests.cs
  27. 15 15
      tests/SharpGLTF.Tests/Schema2/Authoring/ExtensionsCreationTests.cs
  28. 6 6
      tests/SharpGLTF.Tests/Schema2/Authoring/MeshBuilderCreationTests.cs
  29. 1 1
      tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadGeneratedTests.cs
  30. 1 1
      tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSampleTests.cs
  31. 1 1
      tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSpecialModelsTest.cs
  32. 2 3
      tests/SharpGLTF.Tests/SharpGLTF.Tests.csproj
  33. 56 32
      tests/SharpGLTF.Tests/TestFiles.cs
  34. 3 65
      tests/SharpGLTF.Tests/Utils.cs

+ 7 - 0
SharpGLTF.sln

@@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpGLTF.Runtime.MonoGame"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoGameScene", "examples\MonoGameScene\MonoGameScene.csproj", "{894781CA-F508-43AE-8526-6AA6B6EDF613}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLTF.DownloadTestFiles", "tests\SharpGLTF.DownloadTestFiles\SharpGLTF.DownloadTestFiles.csproj", "{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -78,6 +80,10 @@ Global
 		{894781CA-F508-43AE-8526-6AA6B6EDF613}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{894781CA-F508-43AE-8526-6AA6B6EDF613}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{894781CA-F508-43AE-8526-6AA6B6EDF613}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -92,6 +98,7 @@ Global
 		{F64C6CC1-BD12-47B8-B6EA-D5609AC738DF} = {83E7E49D-8A28-45E8-9DBD-1F3AEDEF3E42}
 		{6C7B3CD8-21D0-447E-9034-8F72057F2ED7} = {83E7E49D-8A28-45E8-9DBD-1F3AEDEF3E42}
 		{894781CA-F508-43AE-8526-6AA6B6EDF613} = {83E7E49D-8A28-45E8-9DBD-1F3AEDEF3E42}
+		{7CC20DF6-14B5-4C1C-B4FC-151E97AED4F4} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {1D7BBAD9-834C-4981-AC96-0AA5226FC43F}

+ 3 - 1
src/SharpGLTF.Core/Debug/DebuggerDisplay.cs

@@ -138,7 +138,9 @@ namespace SharpGLTF.Debug
                     break;
             }
 
-            var primName = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(prim.DrawPrimitiveType.ToString().ToLower());
+            var culture = System.Globalization.CultureInfo.CurrentCulture;
+
+            var primName = culture.TextInfo.ToTitleCase(prim.DrawPrimitiveType.ToString().ToLower(culture));
             txt += $" {primName}[{pcount}]";
 
             // gather morph attributes information

+ 88 - 30
src/SharpGLTF.Core/Memory/FloatingArrays.cs

@@ -217,7 +217,7 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Single"/> values
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{single}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Float[{Count}]")]
     public struct ScalarArray : IList<Single>, IReadOnlyList<Single>
@@ -227,17 +227,15 @@ namespace SharpGLTF.Memory
         /// <summary>
         /// Initializes a new instance of the <see cref="ScalarArray"/> struct.
         /// </summary>
-        /// <param name="source">The array to wrap.</param>
-        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
-        /// <param name="itemsCount">The number of <see cref="Single"/> items in <paramref name="source"/>.</param>
+        /// <param name="source">The array range to wrap.</param>
         /// <param name="byteStride">
         /// The byte stride between elements.
         /// If the value is zero, the size of the item is used instead.
         /// </param>
         /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
         /// <param name="normalized">True if values are normalized.</param>
-        public ScalarArray(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public ScalarArray(Byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ScalarArray"/> struct.
@@ -252,6 +250,21 @@ namespace SharpGLTF.Memory
         public ScalarArray(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScalarArray"/> struct.
+        /// </summary>
+        /// <param name="source">The array to wrap.</param>
+        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
+        /// <param name="itemsCount">The number of <see cref="Single"/> items in <paramref name="source"/>.</param>
+        /// <param name="byteStride">
+        /// The byte stride between elements.
+        /// If the value is zero, the size of the item is used instead.
+        /// </param>
+        /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
+        /// <param name="normalized">True if values are normalized.</param>
+        public ScalarArray(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ScalarArray"/> struct.
         /// </summary>
@@ -328,7 +341,7 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Vector2"/> values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{Vector2}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Vector2[{Count}]")]
     public struct Vector2Array : IList<Vector2>, IReadOnlyList<Vector2>
@@ -339,16 +352,14 @@ namespace SharpGLTF.Memory
         /// Initializes a new instance of the <see cref="Vector2Array"/> struct.
         /// </summary>
         /// <param name="source">The array range to wrap.</param>
-        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
-        /// <param name="itemsCount">>The number of <see cref="Vector2"/> items in <paramref name="source"/>.</param>
         /// <param name="byteStride">
         /// The byte stride between elements.
         /// If the value is zero, the size of the item is used instead.
         /// </param>
         /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
         /// <param name="normalized">True if values are normalized.</param>
-        public Vector2Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public Vector2Array(Byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector2Array"/> struct.
@@ -363,6 +374,21 @@ namespace SharpGLTF.Memory
         public Vector2Array(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Vector2Array"/> struct.
+        /// </summary>
+        /// <param name="source">The array range to wrap.</param>
+        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
+        /// <param name="itemsCount">>The number of <see cref="Vector2"/> items in <paramref name="source"/>.</param>
+        /// <param name="byteStride">
+        /// The byte stride between elements.
+        /// If the value is zero, the size of the item is used instead.
+        /// </param>
+        /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
+        /// <param name="normalized">True if values are normalized.</param>
+        public Vector2Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector2Array"/> struct.
         /// </summary>
@@ -447,7 +473,7 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Vector3"/> values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{Vector3}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Vector3[{Count}]")]
     public struct Vector3Array : IList<Vector3>, IReadOnlyList<Vector3>
@@ -457,17 +483,15 @@ namespace SharpGLTF.Memory
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector3Array"/> struct.
         /// </summary>
-        /// <param name="source">The array to wrap.</param>
-        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
-        /// <param name="itemsCount">The number of <see cref="Vector3"/> items in <paramref name="source"/>.</param>
+        /// <param name="source">The array range to wrap.</param>
         /// <param name="byteStride">
         /// The byte stride between elements.
         /// If the value is zero, the size of the item is used instead.
         /// </param>
         /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
         /// <param name="normalized">True if values are normalized.</param>
-        public Vector3Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public Vector3Array(Byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector3Array"/> struct.
@@ -482,6 +506,21 @@ namespace SharpGLTF.Memory
         public Vector3Array(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Vector3Array"/> struct.
+        /// </summary>
+        /// <param name="source">The array to wrap.</param>
+        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
+        /// <param name="itemsCount">The number of <see cref="Vector3"/> items in <paramref name="source"/>.</param>
+        /// <param name="byteStride">
+        /// The byte stride between elements.
+        /// If the value is zero, the size of the item is used instead.
+        /// </param>
+        /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
+        /// <param name="normalized">True if values are normalized.</param>
+        public Vector3Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector3Array"/> struct.
         /// </summary>
@@ -567,7 +606,7 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Vector4"/> values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{Vector4}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Vector4[{Count}]")]
     public struct Vector4Array : IList<Vector4>, IReadOnlyList<Vector4>
@@ -577,17 +616,15 @@ namespace SharpGLTF.Memory
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector4Array"/> struct.
         /// </summary>
-        /// <param name="source">The array to wrap.</param>
-        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
-        /// <param name="itemsCount">The number of <see cref="Vector3"/> items in <paramref name="source"/>.</param>
+        /// <param name="source">The array range to wrap.</param>
         /// <param name="byteStride">
         /// The byte stride between elements.
         /// If the value is zero, the size of the item is used instead.
         /// </param>
         /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
         /// <param name="normalized">True if values are normalized.</param>
-        public Vector4Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public Vector4Array(Byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector4Array"/> struct.
@@ -602,6 +639,21 @@ namespace SharpGLTF.Memory
         public Vector4Array(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Vector4Array"/> struct.
+        /// </summary>
+        /// <param name="source">The array to wrap.</param>
+        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
+        /// <param name="itemsCount">The number of <see cref="Vector3"/> items in <paramref name="source"/>.</param>
+        /// <param name="byteStride">
+        /// The byte stride between elements.
+        /// If the value is zero, the size of the item is used instead.
+        /// </param>
+        /// <param name="encoding">A value of <see cref="ENCODING"/>.</param>
+        /// <param name="normalized">True if values are normalized.</param>
+        public Vector4Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="Vector4Array"/> struct.
         /// </summary>
@@ -688,19 +740,22 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Quaternion"/> values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{Quaternion}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Quaternion[{Count}]")]
     public struct QuaternionArray : IList<Quaternion>, IReadOnlyList<Quaternion>
     {
         #region constructors
 
-        public QuaternionArray(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public QuaternionArray(Byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         public QuaternionArray(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        public QuaternionArray(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         public QuaternionArray(BYTES source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding, Boolean normalized)
         {
             _Accessor = new FloatingAccessor(source, byteOffset, itemsCount, byteStride, 4, encoding, normalized);
@@ -775,19 +830,22 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="Matrix4x4"/> values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{Matrix4x4}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Matrix4x4[{Count}]")]
     public struct Matrix4x4Array : IList<Matrix4x4>, IReadOnlyList<Matrix4x4>
     {
         #region constructors
 
-        public Matrix4x4Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
-            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+        public Matrix4x4Array(byte[] source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
         public Matrix4x4Array(BYTES source, int byteStride = 0, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
             : this(source, 0, int.MaxValue, byteStride, encoding, normalized) { }
 
+        public Matrix4x4Array(Byte[] source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding = ENCODING.FLOAT, Boolean normalized = false)
+            : this(new BYTES(source), byteOffset, itemsCount, byteStride, encoding, normalized) { }
+
         public Matrix4x4Array(BYTES source, int byteOffset, int itemsCount, int byteStride, ENCODING encoding, Boolean normalized)
         {
             _Accessor = new FloatingAccessor(source, byteOffset, itemsCount, byteStride, 16, encoding, normalized);
@@ -880,7 +938,7 @@ namespace SharpGLTF.Memory
     }
 
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="float"/> array values.
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an IList{Single[]}/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Float[][{Count}]")]
     public struct MultiArray : IList<Single[]>, IReadOnlyList<Single[]>

+ 14 - 6
src/SharpGLTF.Core/Memory/IntegerArrays.cs

@@ -10,7 +10,7 @@ using ENCODING = SharpGLTF.Schema2.IndexEncodingType;
 namespace SharpGLTF.Memory
 {
     /// <summary>
-    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an array of <see cref="UInt32"/> values
+    /// Wraps an encoded <see cref="BYTES"/> and exposes it as an <see cref="IList{UInt32}"/>.
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("Integer[{Count}]")]
     public struct IntegerArray : IList<UInt32>, IReadOnlyList<UInt32>
@@ -20,12 +20,10 @@ namespace SharpGLTF.Memory
         /// <summary>
         /// Initializes a new instance of the <see cref="IntegerArray"/> struct.
         /// </summary>
-        /// <param name="source">The array to wrap.</param>
-        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
-        /// <param name="itemsCount">The number of <see cref="UInt32"/> items in <paramref name="source"/>.</param>
+        /// <param name="source">The array range to wrap.</param>
         /// <param name="encoding">Byte encoding.</param>
-        public IntegerArray(Byte[] source, int byteOffset, int itemsCount, ENCODING encoding)
-            : this(new BYTES(source), byteOffset, itemsCount, encoding) { }
+        public IntegerArray(Byte[] source, ENCODING encoding = ENCODING.UNSIGNED_INT)
+            : this(source, 0, int.MaxValue, encoding) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="IntegerArray"/> struct.
@@ -35,6 +33,16 @@ namespace SharpGLTF.Memory
         public IntegerArray(BYTES source, ENCODING encoding = ENCODING.UNSIGNED_INT)
             : this(source, 0, int.MaxValue, encoding) { }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IntegerArray"/> struct.
+        /// </summary>
+        /// <param name="source">The array to wrap.</param>
+        /// <param name="byteOffset">The zero-based index of the first <see cref="Byte"/> in <paramref name="source"/>.</param>
+        /// <param name="itemsCount">The number of <see cref="UInt32"/> items in <paramref name="source"/>.</param>
+        /// <param name="encoding">Byte encoding.</param>
+        public IntegerArray(Byte[] source, int byteOffset, int itemsCount, ENCODING encoding)
+            : this(new BYTES(source), byteOffset, itemsCount, encoding) { }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="IntegerArray"/> struct.
         /// </summary>

+ 5 - 5
src/SharpGLTF.Toolkit/Geometry/MeshBuilderToolkit.cs

@@ -132,11 +132,11 @@ namespace SharpGLTF.Geometry
         /// Given a set of 4 points defining a quadrangle, it determines which
         /// is the optimal diagonal to choose to reprensent the quadrangle as two triangles.
         /// </summary>
-        /// <param name="a"></param>
-        /// <param name="b"></param>
-        /// <param name="c"></param>
-        /// <param name="d"></param>
-        /// <returns></returns>
+        /// <param name="a">The first vertex.</param>
+        /// <param name="b">The second vertex.</param>
+        /// <param name="c">The third vertex.</param>
+        /// <param name="d">The fourth vertex.</param>
+        /// <returns>True if two triangles are (A,B,C),(A,C,D) , false if two triangles are (B,C,D),(B,D,A).</returns>
         public static bool GetQuadrangleDiagonal(Vector3 a, Vector3 b, Vector3 c, Vector3 d)
         {
             var area1 = Vector3.Cross(a - b, c - b).Length() + Vector3.Cross(a - d, c - d).Length();

+ 14 - 0
src/SharpGLTF.Toolkit/Geometry/PrimitiveBuilder.cs

@@ -224,6 +224,8 @@ namespace SharpGLTF.Geometry
         /// <returns>The indices of the vertices.</returns>
         public int AddPoint(IVertexBuilder a)
         {
+            Guard.NotNull(a, nameof(a));
+
             return AddPoint(ConvertVertex(a));
         }
 
@@ -235,6 +237,9 @@ namespace SharpGLTF.Geometry
         /// <returns>The indices of the vertices, or, in case the line is degenerated, (-1,-1).</returns>
         public (int, int) AddLine(IVertexBuilder a, IVertexBuilder b)
         {
+            Guard.NotNull(a, nameof(a));
+            Guard.NotNull(b, nameof(b));
+
             return AddLine(ConvertVertex(a), ConvertVertex(b));
         }
 
@@ -247,6 +252,10 @@ namespace SharpGLTF.Geometry
         /// <returns>The indices of the vertices, or, in case the triangle is degenerated, (-1,-1,-1).</returns>
         public (int, int, int) AddTriangle(IVertexBuilder a, IVertexBuilder b, IVertexBuilder c)
         {
+            Guard.NotNull(a, nameof(a));
+            Guard.NotNull(b, nameof(b));
+            Guard.NotNull(c, nameof(c));
+
             return AddTriangle(ConvertVertex(a), ConvertVertex(b), ConvertVertex(c));
         }
 
@@ -264,6 +273,11 @@ namespace SharpGLTF.Geometry
         /// </remarks>
         public (int, int, int, int) AddQuadrangle(IVertexBuilder a, IVertexBuilder b, IVertexBuilder c, IVertexBuilder d)
         {
+            Guard.NotNull(a, nameof(a));
+            Guard.NotNull(b, nameof(b));
+            Guard.NotNull(c, nameof(c));
+            Guard.NotNull(d, nameof(d));
+
             return AddQuadrangle(ConvertVertex(a), ConvertVertex(b), ConvertVertex(c), ConvertVertex(d));
         }
 

+ 8 - 0
src/SharpGLTF.Toolkit/Geometry/VertexBuilder.cs

@@ -222,6 +222,8 @@ namespace SharpGLTF.Geometry
             return new VertexBuilder<TvG, TvM, TvS>(g);
         }
 
+        #pragma warning disable CA1000 // Do not declare static members on generic types
+
         public static VertexBuilder<TvG, TvM, TvS> Create(Vector3 position)
         {
             var v = default(VertexBuilder<TvG, TvM, TvS>);
@@ -246,6 +248,8 @@ namespace SharpGLTF.Geometry
             return v;
         }
 
+        #pragma warning restore CA1000 // Do not declare static members on generic types
+
         #endregion
 
         #region data
@@ -357,6 +361,8 @@ namespace SharpGLTF.Geometry
             return new VertexBuilder<TvPP, TvMM, TvSS>(p, m, s);
         }
 
+        #pragma warning disable CA1000 // Do not declare static members on generic types
+
         public static MeshBuilder<TMaterial, TvG, TvM, TvS> CreateCompatibleMesh<TMaterial>(string name = null)
         {
             return new MeshBuilder<TMaterial, TvG, TvM, TvS>(name);
@@ -367,6 +373,8 @@ namespace SharpGLTF.Geometry
             return new MeshBuilder<TvG, TvM, TvS>(name);
         }
 
+        #pragma warning restore CA1000 // Do not declare static members on generic types
+
         IVertexGeometry IVertexBuilder.GetGeometry() { return this.Geometry; }
 
         IVertexMaterial IVertexBuilder.GetMaterial() { return this.Material; }

+ 2 - 2
src/SharpGLTF.Toolkit/Materials/ChannelBuilder.cs

@@ -15,7 +15,7 @@ namespace SharpGLTF.Materials
         {
             Guard.NotNull(parent, nameof(parent));
             Guard.NotNullOrEmpty(key, nameof(key));
-            Guard.IsTrue(Enum.GetNames(typeof(KnownChannels)).Contains(key), nameof(key), $"{nameof(key)} must be a name of {nameof(KnownChannels)}.");
+            Guard.IsTrue(Enum.GetNames(typeof(KnownChannel)).Contains(key), nameof(key), $"{nameof(key)} must be a name of {nameof(KnownChannel)}.");
 
             _Parent = parent;
             _Key = key;
@@ -76,7 +76,7 @@ namespace SharpGLTF.Materials
         #region properties
 
         /// <summary>
-        /// Gets the <see cref="ChannelBuilder"/> name. It must be a name of <see cref="KnownChannels"/>.
+        /// Gets the <see cref="ChannelBuilder"/> name. It must be a name of <see cref="KnownChannel"/>.
         /// </summary>
         public String Key => _Key;
 

+ 4 - 4
src/SharpGLTF.Toolkit/Materials/MaterialBuilder.cs

@@ -167,7 +167,7 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public ChannelBuilder GetChannel(KnownChannels channelKey)
+        public ChannelBuilder GetChannel(KnownChannel channelKey)
         {
             return GetChannel(channelKey.ToString());
         }
@@ -181,7 +181,7 @@ namespace SharpGLTF.Materials
             return _Channels.FirstOrDefault(item => string.Equals(channelKey, item.Key, StringComparison.OrdinalIgnoreCase));
         }
 
-        public ChannelBuilder UseChannel(KnownChannels channelKey)
+        public ChannelBuilder UseChannel(KnownChannel channelKey)
         {
             return UseChannel(channelKey.ToString());
         }
@@ -212,7 +212,7 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public MaterialBuilder WithChannelParam(KnownChannels channelKey, Vector4 parameter)
+        public MaterialBuilder WithChannelParam(KnownChannel channelKey, Vector4 parameter)
         {
             this.UseChannel(channelKey).Parameter = parameter;
 
@@ -226,7 +226,7 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public MaterialBuilder WithChannelImage(KnownChannels channelKey, string primaryImagePath)
+        public MaterialBuilder WithChannelImage(KnownChannel channelKey, string primaryImagePath)
         {
             this.UseChannel(channelKey)
                 .UseTexture()

+ 1 - 1
src/SharpGLTF.Toolkit/Materials/MaterialEnums.cs

@@ -14,7 +14,7 @@ namespace SharpGLTF.Materials
         BLEND,
     }
 
-    public enum KnownChannels
+    public enum KnownChannel
     {
         Normal,
         Occlusion,

+ 4 - 0
src/SharpGLTF.Toolkit/Scenes/CameraBuilder.cs

@@ -27,6 +27,8 @@ namespace SharpGLTF.Scenes
 
         #region types
 
+        #pragma warning disable CA1034 // Nested types should not be visible
+
         [System.Diagnostics.DebuggerDisplay("Orthographic ({XMag},{YMag})  {ZNear} < {ZFar}")]
         public sealed class Orthographic : CameraBuilder
         {
@@ -113,6 +115,8 @@ namespace SharpGLTF.Scenes
             #endregion
         }
 
+        #pragma warning restore CA1034 // Nested types should not be visible
+
         #endregion
     }
 }

+ 7 - 0
src/SharpGLTF.Toolkit/Scenes/LightBuilder.cs

@@ -9,6 +9,8 @@ namespace SharpGLTF.Scenes
     {
         protected LightBuilder(Schema2.PunctualLight light)
         {
+            Guard.NotNull(light, nameof(light));
+
             this.Color = light.Color;
             this.Intensity = light.Intensity;
         }
@@ -29,6 +31,8 @@ namespace SharpGLTF.Scenes
 
         #region types
 
+        #pragma warning disable CA1034 // Nested types should not be visible
+
         [System.Diagnostics.DebuggerDisplay("Directional")]
         public sealed class Directional : LightBuilder
         {
@@ -54,6 +58,7 @@ namespace SharpGLTF.Scenes
         }
 
         [System.Diagnostics.DebuggerDisplay("Spot")]
+
         public sealed class Spot : LightBuilder
         {
             internal Spot(Schema2.PunctualLight light)
@@ -84,6 +89,8 @@ namespace SharpGLTF.Scenes
             public Single OuterConeAngle { get; set; }
         }
 
+        #pragma warning restore CA1034 // Nested types should not be visible
+
         #endregion
     }
 }

+ 2 - 0
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.Schema2.cs

@@ -163,6 +163,8 @@ namespace SharpGLTF.Scenes
 
         public static ModelRoot ToSchema2(IEnumerable<SceneBuilder> srcScenes, bool useStridedBuffers = true)
         {
+            Guard.NotNull(srcScenes, nameof(srcScenes));
+
             var context = new Schema2SceneBuilder();
 
             var dstModel = ModelRoot.CreateModel();

+ 8 - 0
src/SharpGLTF.Toolkit/Scenes/Transformers.cs

@@ -27,6 +27,8 @@ namespace SharpGLTF.Scenes
 
         protected ContentTransformer(ContentTransformer other)
         {
+            Guard.NotNull(other, nameof(other));
+
             this._Content = other._Content;
             this._Morphings = other._Morphings?.Clone();
         }
@@ -98,6 +100,8 @@ namespace SharpGLTF.Scenes
         protected FixedTransformer(FixedTransformer other)
             : base(other)
         {
+            Guard.NotNull(other, nameof(other));
+
             this._WorldTransform = other._WorldTransform;
         }
 
@@ -147,6 +151,8 @@ namespace SharpGLTF.Scenes
         protected RigidTransformer(RigidTransformer other)
             : base(other)
         {
+            Guard.NotNull(other, nameof(other));
+
             this._Node = other._Node;
         }
 
@@ -202,6 +208,8 @@ namespace SharpGLTF.Scenes
         protected SkinnedTransformer(SkinnedTransformer other)
             : base(other)
         {
+            Guard.NotNull(other, nameof(other));
+
             this._TargetBindMatrix = other._TargetBindMatrix;
             this._Joints.AddRange(other._Joints);
         }

+ 7 - 0
tests/0_Readme.txt

@@ -0,0 +1,7 @@
+
+
+Before running the tests in Visual Studio, or by Command line, first we need to download the required test files.
+
+To do so, we just need to run "1_DownloadTestFiles.cmd" once.  If we need to update the test files we can run it again.
+
+After the test files have been successfully downloaded, we can either run the tests in Visual Studio, or run "2_RunTests.cmd"

+ 2 - 0
tests/1_DownloadTestFiles.cmd

@@ -0,0 +1,2 @@
+dotnet run --project SharpGLTF.DownloadTestFiles\SharpGLTF.DownloadTestFiles.csproj "%~dp0\TestFiles"
+pause

+ 2 - 0
tests/2_RunTests.cmd

@@ -0,0 +1,2 @@
+dotnet test SharpGLTF.Tests\SharpGLTF.Tests.csproj
+pause

+ 73 - 0
tests/SharpGLTF.DownloadTestFiles/DownloadUtils.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharpGLTF
+{
+    static class DownloadUtils
+    {
+        private static readonly Object _DownloadMutex = new object();
+
+        public static void SyncronizeGitRepository(string remoteUrl, string localDirectoryPath)
+        {
+            if (!System.IO.Path.IsPathRooted(localDirectoryPath)) throw new ArgumentException(nameof(localDirectoryPath));
+
+            lock (_DownloadMutex)
+            {
+                if (LibGit2Sharp.Repository.Discover(localDirectoryPath) == null)
+                {
+                    Console.WriteLine($"Cloning {remoteUrl} can take several minutes; Please wait...");
+
+                    LibGit2Sharp.Repository.Clone(remoteUrl, localDirectoryPath);
+
+                    Console.WriteLine($"... Clone Completed");
+
+                    return;
+                }
+
+                using (var repo = new LibGit2Sharp.Repository(localDirectoryPath))
+                {
+                    var options = new LibGit2Sharp.PullOptions
+                    {
+                        FetchOptions = new LibGit2Sharp.FetchOptions()
+                    };
+
+                    var r = LibGit2Sharp.Commands.Pull(repo, new LibGit2Sharp.Signature("Anonymous", "[email protected]", new DateTimeOffset(DateTime.Now)), options);
+
+                    Console.WriteLine($"{remoteUrl} is {r.Status}");
+                }
+            }
+        }
+
+        public static string DownloadFile(string remoteUri, string localFilePath)
+        {
+            if (!System.IO.Path.IsPathRooted(localFilePath)) throw new ArgumentException(nameof(localFilePath));
+
+            lock (_DownloadMutex)
+            {
+                if (System.IO.File.Exists(localFilePath)) return localFilePath; // we check again because we could have downloaded the file while waiting.
+
+                Console.WriteLine($"Downloading {remoteUri}... Please Wait...");
+
+                var dir = System.IO.Path.GetDirectoryName(localFilePath);
+                System.IO.Directory.CreateDirectory(dir);
+
+                using (var wc = new System.Net.WebClient())
+                {
+                    wc.DownloadFile(remoteUri, localFilePath);
+                }
+
+                if (localFilePath.ToLower().EndsWith(".zip"))
+                {
+                    Console.WriteLine($"Extracting {localFilePath}...");
+
+                    var extractPath = System.IO.Path.Combine(dir, System.IO.Path.GetFileNameWithoutExtension(localFilePath));
+
+                    System.IO.Compression.ZipFile.ExtractToDirectory(localFilePath, extractPath);
+                }
+
+                return localFilePath;
+            }
+        }
+    }
+}

+ 67 - 0
tests/SharpGLTF.DownloadTestFiles/ExampleFiles.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SharpGLTF
+{
+    /// <summary>
+    /// Encapsulates the access to test files.
+    /// </summary>
+    class ExampleFiles
+    {
+        #region lifecycle        
+
+        public ExampleFiles(string workingDirectory)
+        {
+            _WorkingDirectory = workingDirectory;            
+
+            _SchemaDir = System.IO.Path.Combine(_WorkingDirectory, "glTF-Schema");
+            _SampleModelsDir = System.IO.Path.Combine(_WorkingDirectory, "glTF-Sample-Models");
+            _PollyModelsDir = System.IO.Path.Combine(_WorkingDirectory, "glTF-Blender-Exporter");
+            _UniVRMModelsDir = System.IO.Path.Combine(_WorkingDirectory, "UniVRM");
+            _BabylonJsMeshesDir = System.IO.Path.Combine(_WorkingDirectory, "BabylonJS-MeshesLibrary");
+            _BabylonJsPlaygroundDir = System.IO.Path.Combine(_WorkingDirectory, "BabylonJS-PlaygroundScenes");
+        }
+
+        public void DownloadReferenceModels()
+        {
+            Console.WriteLine("Downloading reference files... It might take a while, please, wait...");            
+
+            var dstPath = System.IO.Path.Combine(_WorkingDirectory, "GeneratedReferenceModels", "v_0_6_1.zip");
+            _GeneratedModelsDir = DownloadUtils.DownloadFile("https://github.com/KhronosGroup/glTF-Asset-Generator/releases/download/v0.6.1/GeneratedAssets-0.6.1.zip", dstPath);
+
+            dstPath = System.IO.Path.Combine(_UniVRMModelsDir, "AliciaSolid_vrm-0.40.vrm");
+            DownloadUtils.DownloadFile("https://github.com/vrm-c/UniVRMTest/raw/master/Models/Alicia_vrm-0.40/AliciaSolid_vrm-0.40.vrm", dstPath);
+
+            Console.WriteLine("Checking out test files... It might take a while, please, wait...");            
+
+            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Sample-Models.git", _SampleModelsDir);
+            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Blender-Exporter.git", _PollyModelsDir);            
+            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF.git", _SchemaDir);
+            DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/MeshesLibrary.git", _BabylonJsMeshesDir);
+            // DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/Babylon.js.git", _BabylonJsPlaygroundDir);
+
+            Console.WriteLine("... Download Completed.");
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly string _WorkingDirectory;
+
+        private readonly string _SchemaDir;
+        private readonly string _SampleModelsDir;
+        private readonly string _PollyModelsDir;
+        private readonly string _UniVRMModelsDir;
+        private readonly string _BabylonJsMeshesDir;
+        private readonly string _BabylonJsPlaygroundDir;
+
+        private readonly string[] _BabylonJsInvalidFiles = { };
+
+        private string _GeneratedModelsDir;        
+
+        #endregion        
+    }
+}

+ 18 - 0
tests/SharpGLTF.DownloadTestFiles/Program.cs

@@ -0,0 +1,18 @@
+using System;
+
+namespace SharpGLTF
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            if (args.Length == 0) return;
+
+            System.IO.Directory.CreateDirectory(args[0]);
+
+            var examples = new ExampleFiles(args[0]);
+
+            examples.DownloadReferenceModels();
+        }
+    }
+}

+ 13 - 0
tests/SharpGLTF.DownloadTestFiles/SharpGLTF.DownloadTestFiles.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <RootNamespace>SharpGLTF</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="LibGit2Sharp" Version="0.26.1" />    
+  </ItemGroup>
+
+</Project>

+ 3 - 3
tests/SharpGLTF.Tests/Geometry/MeshBuilderTests.cs

@@ -211,9 +211,9 @@ namespace SharpGLTF.Geometry
 
             // since Materials.MaterialBuilder is not immutable we can change the contents,
             // so now, material1, material2 and material3 no longer represent the same material
-            material1.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannels.BaseColor, Vector4.One * 0.2f);
-            material2.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannels.BaseColor, Vector4.One * 0.4f);
-            material3.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannels.BaseColor, Vector4.One * 0.6f);
+            material1.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannel.BaseColor, Vector4.One * 0.2f);
+            material2.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannel.BaseColor, Vector4.One * 0.4f);
+            material3.WithMetallicRoughnessShader().WithChannelParam(Materials.KnownChannel.BaseColor, Vector4.One * 0.6f);
 
             var mesh2 = model.CreateMeshes(mesh)[0];
             Assert.AreEqual(4, model.LogicalMaterials.Count);

+ 1 - 1
tests/SharpGLTF.Tests/Geometry/Parametric/SolidMeshUtils.cs

@@ -231,7 +231,7 @@ namespace SharpGLTF.Geometry.Parametric
         {
             // we create a new material to use with the terrain mesh
             var material = new Materials.MaterialBuilder("TerrainMaterial")
-                .WithChannelImage(Materials.KnownChannels.BaseColor, terrainColorImagePath);
+                .WithChannelImage(Materials.KnownChannel.BaseColor, terrainColorImagePath);
 
             // we create a MeshBuilder
             var terrainMesh = new MeshBuilder<VertexPosition, VertexTexture1>("terrain");

+ 6 - 2
tests/SharpGLTF.Tests/NumericsAssert.cs

@@ -11,12 +11,16 @@ namespace SharpGLTF
     {
         public static void IsFinite(Single value, string message = null)
         {
-            Assert.IsTrue(float.IsFinite(value), message);
+            // Assert.IsTrue(float.IsFinite(value), message);
+
+            Assert.IsTrue(!float.IsNaN(value) && !float.IsInfinity(value), message);
         }
 
         public static void IsFinite(Double value, string message = null)
         {
-            Assert.IsTrue(double.IsFinite(value), message);
+            // Assert.IsTrue(double.IsFinite(value), message);
+
+            Assert.IsTrue(!Double.IsNaN(value) && !Double.IsInfinity(value), message);
         }
 
         public static void IsFinite(Vector2 vector)

+ 4 - 4
tests/SharpGLTF.Tests/Plotting.cs

@@ -61,7 +61,7 @@ namespace SharpGLTF
             {
                 var points = series
                     .Select((y, x) => (x, y))
-                    .Where(item => float.IsFinite(item.Item2))
+                    .Where(item => item.Item2.IsFinite())
                     .Select(item => new Vector2(item.Item1, item.Item2));
 
                 return Create(points, lt);
@@ -71,7 +71,7 @@ namespace SharpGLTF
             {
                 var points = series
                     .Select((y, x) => (x, (float)y))
-                    .Where(item => float.IsFinite(item.Item2))
+                    .Where(item => item.Item2.IsFinite())
                     .Select(item => new Vector2(item.Item1, item.Item2));
 
                 return Create(points, lt);
@@ -79,7 +79,7 @@ namespace SharpGLTF
 
             public static Point2Series Create(IEnumerable<Vector2> points, LineType lt = LineType.Dot)
             {
-                points = points.Where(item => float.IsFinite(item.X) && float.IsFinite(item.Y));
+                points = points.Where(item => item.X.IsFinite() && item.Y.IsFinite());
 
                 var ps = new Point2Series();
                 ps._Points.AddRange(points.Select(item => new Point2(item)));
@@ -175,7 +175,7 @@ namespace SharpGLTF
 
             public static Point3Series Create(IEnumerable<Vector3> points)
             {
-                points = points.Where(item => float.IsFinite(item.X) && float.IsFinite(item.Y) && float.IsFinite(item.Z) );
+                points = points.Where(item => item.X.IsFinite() && item.Y.IsFinite() && item.Z.IsFinite() );
 
                 var ps = new Point3Series();
                 ps._Points.AddRange(points);

+ 6 - 6
tests/SharpGLTF.Tests/Scenes/SceneBuilderTests.cs

@@ -243,11 +243,11 @@ namespace SharpGLTF.Scenes
             // create two materials
 
             var pink = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 0, 1, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1))
                 .WithDoubleSide(true);
 
             var yellow = new MaterialBuilder("material2")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 1, 0, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1))
                 .WithDoubleSide(true);
 
             // create the mesh            
@@ -330,11 +330,11 @@ namespace SharpGLTF.Scenes
             // create two materials
 
             var pink = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 0, 1, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1))
                 .WithDoubleSide(true);
 
             var yellow = new MaterialBuilder("material2")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 1, 0, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1))
                 .WithDoubleSide(true);
 
             // create the mesh            
@@ -441,10 +441,10 @@ namespace SharpGLTF.Scenes
             // create two materials
 
             var pink = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 0, 1, 1));
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1));
 
             var yellow = new MaterialBuilder("material2")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 1, 0, 1));
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1));
 
             var scene = new SceneBuilder();
 

+ 15 - 15
tests/SharpGLTF.Tests/Schema2/Authoring/ExtensionsCreationTests.cs

@@ -16,7 +16,7 @@ namespace SharpGLTF.Schema2.Authoring
         [OneTimeSetUp]
         public void Setup()
         {
-            TestFiles.DownloadReferenceModels();
+            // TestFiles.DownloadReferenceModels();
         }
 
         #endregion
@@ -49,26 +49,26 @@ namespace SharpGLTF.Schema2.Authoring
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachGltfValidatorLinks();
 
-            var basePath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "glTF-Sample-Models", "2.0", "SpecGlossVsMetalRough", "glTF");
+            var basePath = System.IO.Path.Combine(TestFiles.RootDirectory, "glTF-Sample-Models", "2.0", "SpecGlossVsMetalRough", "glTF");
 
             // first, create a default material
             var material = new Materials.MaterialBuilder("material1 fallback")
                 .WithMetallicRoughnessShader()
-                .WithChannelImage(Materials.KnownChannels.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
-                .WithChannelImage(Materials.KnownChannels.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
-                .WithChannelImage(Materials.KnownChannels.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
-                .WithChannelImage(Materials.KnownChannels.BaseColor, System.IO.Path.Combine(basePath, "WaterBottle_baseColor.png"))
-                .WithChannelImage(Materials.KnownChannels.MetallicRoughness, System.IO.Path.Combine(basePath, "WaterBottle_roughnessMetallic.png"));
+                .WithChannelImage(Materials.KnownChannel.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
+                .WithChannelImage(Materials.KnownChannel.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
+                .WithChannelImage(Materials.KnownChannel.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
+                .WithChannelImage(Materials.KnownChannel.BaseColor, System.IO.Path.Combine(basePath, "WaterBottle_baseColor.png"))
+                .WithChannelImage(Materials.KnownChannel.MetallicRoughness, System.IO.Path.Combine(basePath, "WaterBottle_roughnessMetallic.png"));
 
             // wrap the fallback material with a PBR Specular Glossiness material.
             material = new Materials.MaterialBuilder("material1")
                 .WithFallback(material)
                 .WithSpecularGlossinessShader()
-                .WithChannelImage(Materials.KnownChannels.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
-                .WithChannelImage(Materials.KnownChannels.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
-                .WithChannelImage(Materials.KnownChannels.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
-                .WithChannelImage(Materials.KnownChannels.Diffuse, System.IO.Path.Combine(basePath, "WaterBottle_diffuse.png"))
-                .WithChannelImage(Materials.KnownChannels.SpecularGlossiness, System.IO.Path.Combine(basePath, "WaterBottle_specularGlossiness.png"));
+                .WithChannelImage(Materials.KnownChannel.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
+                .WithChannelImage(Materials.KnownChannel.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
+                .WithChannelImage(Materials.KnownChannel.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
+                .WithChannelImage(Materials.KnownChannel.Diffuse, System.IO.Path.Combine(basePath, "WaterBottle_diffuse.png"))
+                .WithChannelImage(Materials.KnownChannel.SpecularGlossiness, System.IO.Path.Combine(basePath, "WaterBottle_specularGlossiness.png"));
 
             var mesh = new Geometry.MeshBuilder<VPOS, VTEX>("mesh1");
             mesh.UsePrimitive(material).AddQuadrangle
@@ -101,7 +101,7 @@ namespace SharpGLTF.Schema2.Authoring
                 .WithMetallicRoughnessShader()
                 .WithChannelImage
                 (
-                    Materials.KnownChannels.BaseColor,
+                    Materials.KnownChannel.BaseColor,
                     System.IO.Path.Combine(basePath, textureFileName)
                 );                
 
@@ -141,9 +141,9 @@ namespace SharpGLTF.Schema2.Authoring
             var material = new Materials.MaterialBuilder("material1")
                 .WithDoubleSide(true)
                 .WithMetallicRoughnessShader()
-                .WithChannelImage(Materials.KnownChannels.BaseColor, System.IO.Path.Combine(basePath, "shannon.jpg"));
+                .WithChannelImage(Materials.KnownChannel.BaseColor, System.IO.Path.Combine(basePath, "shannon.jpg"));
 
-            material.GetChannel(Materials.KnownChannels.BaseColor).UseTexture().WithTransform(0.40f,0.25f, 0.5f,0.5f);
+            material.GetChannel(Materials.KnownChannel.BaseColor).UseTexture().WithTransform(0.40f,0.25f, 0.5f,0.5f);
 
             var mesh = new Geometry.MeshBuilder<VPOS, VTEX>("mesh1");
 

+ 6 - 6
tests/SharpGLTF.Tests/Schema2/Authoring/MeshBuilderCreationTests.cs

@@ -33,7 +33,7 @@ namespace SharpGLTF.Schema2.Authoring
             var v4 = new VPOSNRM(-10, -10, 0, 0, 0, 1);
 
             // create a material
-            var material1 = new MaterialBuilder("material1").WithChannelParam(KnownChannels.BaseColor, Vector4.One);
+            var material1 = new MaterialBuilder("material1").WithChannelParam(KnownChannel.BaseColor, Vector4.One);
 
             // create model
             var meshBuilder = new MeshBuilder<VPOSNRM>("mesh1");
@@ -61,10 +61,10 @@ namespace SharpGLTF.Schema2.Authoring
 
             // create materials
             var material1 = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 1, 0, 1));
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1));
 
             var material2 = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 0, 1, 1));            
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1));            
 
             // create several meshes
             var meshBuilder1 = new MeshBuilder<VPOSNRM>("mesh1");
@@ -128,7 +128,7 @@ namespace SharpGLTF.Schema2.Authoring
             };
 
             // create a material
-            var material1 = new MaterialBuilder("material1").WithChannelParam(KnownChannels.BaseColor, Vector4.One);
+            var material1 = new MaterialBuilder("material1").WithChannelParam(KnownChannel.BaseColor, Vector4.One);
 
             // create a mesh
             var meshBuilder = new MeshBuilder<VPOSNRM>("mesh1");
@@ -166,11 +166,11 @@ namespace SharpGLTF.Schema2.Authoring
 
             // create two materials
             var pink = new MaterialBuilder("material1")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 0, 1, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1))
                 .WithDoubleSide(true);
 
             var yellow = new MaterialBuilder("material2")
-                .WithChannelParam(KnownChannels.BaseColor, new Vector4(1, 1, 0, 1))
+                .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1))
                 .WithDoubleSide(true);
 
             // create the mesh

+ 1 - 1
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadGeneratedTests.cs

@@ -19,7 +19,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [OneTimeSetUp]
         public void Setup()
         {
-            TestFiles.DownloadReferenceModels();
+            // TestFiles.DownloadReferenceModels();
         }
 
         #endregion        

+ 1 - 1
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSampleTests.cs

@@ -19,7 +19,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [OneTimeSetUp]
         public void Setup()
         {
-            TestFiles.DownloadReferenceModels();
+            // TestFiles.DownloadReferenceModels();
         }
         
         #endregion

+ 1 - 1
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSpecialModelsTest.cs

@@ -19,7 +19,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [OneTimeSetUp]
         public void Setup()
         {
-            TestFiles.DownloadReferenceModels();
+            // TestFiles.DownloadReferenceModels();
         }
 
         #endregion

+ 2 - 3
tests/SharpGLTF.Tests/SharpGLTF.Tests.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <TargetFrameworks>netcoreapp2.2;net471</TargetFrameworks>
 
     <IsPackable>false</IsPackable>
 
@@ -10,8 +10,7 @@
     <LangVersion>7.1</LangVersion>
   </PropertyGroup>
 
-  <ItemGroup>
-    <PackageReference Include="LibGit2Sharp" Version="0.26.1" />
+  <ItemGroup>    
     <PackageReference Include="nunit" Version="3.12.0" />
     <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />

+ 56 - 32
tests/SharpGLTF.Tests/TestFiles.cs

@@ -16,48 +16,42 @@ namespace SharpGLTF
 
         static TestFiles()
         {
-            var workingDir = TestContext.CurrentContext.WorkDirectory;
-
-            _SchemaDir = System.IO.Path.Combine(workingDir, "glTF-Schema");
-            _SampleModelsDir = System.IO.Path.Combine(workingDir, "glTF-Sample-Models");
-            _PollyModelsDir = System.IO.Path.Combine(workingDir, "glTF-Blender-Exporter");
-            _UniVRMModelsDir = System.IO.Path.Combine(workingDir, "UniVRM");
-            _BabylonJsMeshesDir = System.IO.Path.Combine(workingDir, "BabylonJS-MeshesLibrary");
-            _BabylonJsPlaygroundDir = System.IO.Path.Combine(workingDir, "BabylonJS-PlaygroundScenes");
-        }
-
-        public static void DownloadReferenceModels()
-        {
-            if (_DonwloadCompleted) return;
-            _DonwloadCompleted = true;
-            
-            TestContext.Progress.WriteLine("Downloading reference files... It might take a while, please, wait...");            
+            var wdir = TestContext.CurrentContext.WorkDirectory;
 
-            var dstPath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "GeneratedReferenceModels", "v_0_6_1.zip");
-            _GeneratedModelsDir = DownloadUtils.DownloadFile("https://github.com/KhronosGroup/glTF-Asset-Generator/releases/download/v0.6.1/GeneratedAssets-0.6.1.zip", dstPath);
+            _ExamplesFound = false;
 
-            dstPath = System.IO.Path.Combine(_UniVRMModelsDir, "AliciaSolid_vrm-0.40.vrm");
-            DownloadUtils.DownloadFile("https://github.com/vrm-c/UniVRMTest/raw/master/Models/Alicia_vrm-0.40/AliciaSolid_vrm-0.40.vrm", dstPath);
+            while (wdir.Length > 3)
+            {
+                _RootDir = System.IO.Path.Combine(wdir, "TestFiles");
 
+                if (wdir.ToLower().EndsWith("tests") && System.IO.Directory.Exists(_RootDir))
+                {
+                    _ExamplesFound = true;
+                    break;
+                }
 
-            
+                wdir = System.IO.Path.GetDirectoryName(wdir);
+            }
 
-            TestContext.Progress.WriteLine("Checking out test files... It might take a while, please, wait...");            
+            _Check();
 
-            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Sample-Models.git", _SampleModelsDir);
-            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Blender-Exporter.git", _PollyModelsDir);            
-            DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF.git", _SchemaDir);
-            DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/MeshesLibrary.git", _BabylonJsMeshesDir);
-            // DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/Babylon.js.git", _BabylonJsPlaygroundDir);
+            _SchemaDir = System.IO.Path.Combine(_RootDir, "glTF-Schema");
+            _SampleModelsDir = System.IO.Path.Combine(_RootDir, "glTF-Sample-Models");
+            _PollyModelsDir = System.IO.Path.Combine(_RootDir, "glTF-Blender-Exporter");
+            _UniVRMModelsDir = System.IO.Path.Combine(_RootDir, "UniVRM");
+            _BabylonJsMeshesDir = System.IO.Path.Combine(_RootDir, "BabylonJS-MeshesLibrary");
+            _BabylonJsPlaygroundDir = System.IO.Path.Combine(_RootDir, "BabylonJS-PlaygroundScenes");
 
-            TestContext.Progress.WriteLine("... Download Completed.");
-        }
+            _GeneratedModelsDir = System.IO.Path.Combine(_RootDir, "GeneratedReferenceModels", "v_0_6_1");
+        }       
 
         #endregion
 
         #region data
 
-        private static Boolean _DonwloadCompleted = false;
+        private static Boolean _ExamplesFound = false;
+
+        private static readonly string _RootDir;
 
         private static readonly string _SchemaDir;
         private static readonly string _SampleModelsDir;
@@ -65,22 +59,38 @@ namespace SharpGLTF
         private static readonly string _UniVRMModelsDir;
         private static readonly string _BabylonJsMeshesDir;
         private static readonly string _BabylonJsPlaygroundDir;
+        private static readonly string _GeneratedModelsDir;
 
         private static readonly string[] _BabylonJsInvalidFiles = { };
 
-        private static string _GeneratedModelsDir;        
+        
+
+        #endregion
+
+        #region properties
+
+        public static string RootDirectory { get { _Check(); return _RootDir; } }
 
         #endregion
 
         #region API
 
+        private static void _Check()
+        {
+            Assert.IsTrue(_ExamplesFound, "TestFiles directory not found; please, run '1_DownloadTestFiles.cmd' before running the tests.");            
+        }
+
         public static IReadOnlyList<string> GetSchemaExtensionsModelsPaths()
         {
+            _Check();
+
             return GetModelPathsInDirectory(_SchemaDir, "extensions", "2.0");         
         }
 
         public static IEnumerable<(string, bool)> GetReferenceModelPaths(bool useNegative = false)
         {
+            _Check();
+
             var dirPath = _GeneratedModelsDir;
             if (dirPath.EndsWith(".zip")) dirPath = dirPath.Substring(0, dirPath.Length - 4);
 
@@ -118,6 +128,8 @@ namespace SharpGLTF
 
         public static IReadOnlyList<string> GetSampleModelsPaths()
         {
+            _Check();
+
             var files = GetModelPathsInDirectory(_SampleModelsDir, "2.0");
 
             return files
@@ -128,17 +140,22 @@ namespace SharpGLTF
 
         public static IReadOnlyList<string> GetBabylonJSValidModelsPaths()
         {
+            _Check();
+
             var files = GetModelPathsInDirectory(_BabylonJsMeshesDir);
 
             return files
                 .OrderBy(item => item)
                 .Where(item => !item.Contains("\\AssetGenerator\\0.6\\"))
+                .Where(item => !item.Contains("\\Sheen\\"))
                 .Where(item => !_BabylonJsInvalidFiles.Any(ff => item.EndsWith(ff)))                
                 .ToList();
         }
 
         public static IReadOnlyList<string> GetBabylonJSInvalidModelsPaths()
         {
+            _Check();
+
             var files = GetModelPathsInDirectory(_BabylonJsMeshesDir);
 
             return files
@@ -150,21 +167,28 @@ namespace SharpGLTF
 
         public static string GetPollyFileModelPath()
         {
+            _Check();
+
             return System.IO.Path.Combine(_PollyModelsDir, "polly", "project_polly.glb");
         }
 
         public static string GetUniVRMModelPath()
         {
+            _Check();
+
             return System.IO.Path.Combine(_UniVRMModelsDir, "AliciaSolid_vrm-0.40.vrm");
         }
 
         private static IReadOnlyList<string> GetModelPathsInDirectory(params string[] paths)
         {
+            _Check();
+
             var dirPath = System.IO.Path.Combine(paths);
 
             if (dirPath.EndsWith(".zip")) dirPath = dirPath.Substring(0, dirPath.Length-4);
 
-            if (!System.IO.Path.IsPathFullyQualified(dirPath)) throw new ArgumentException(nameof(dirPath));
+            // if (!System.IO.Path.IsPathFullyQualified(dirPath)) throw new ArgumentException(nameof(dirPath));
+            if (!System.IO.Path.IsPathRooted(dirPath)) throw new ArgumentException(nameof(dirPath));
 
             var gltf = System.IO.Directory.GetFiles(dirPath, "*.gltf", System.IO.SearchOption.AllDirectories);
             var glbb = System.IO.Directory.GetFiles(dirPath, "*.glb", System.IO.SearchOption.AllDirectories);

+ 3 - 65
tests/SharpGLTF.Tests/Utils.cs

@@ -172,75 +172,13 @@ namespace SharpGLTF
         }
     }
 
-    static class DownloadUtils
+    static class VectorsUtils
     {
-        private static readonly Object _DownloadMutex = new object();
-
-        public static void SyncronizeGitRepository(string remoteUrl, string localDirectoryPath)
-        {
-            if (!System.IO.Path.IsPathRooted(localDirectoryPath)) throw new ArgumentException(nameof(localDirectoryPath));
-
-            lock (_DownloadMutex)
-            {
-                if (LibGit2Sharp.Repository.Discover(localDirectoryPath) == null)
-                {
-                    TestContext.Progress.WriteLine($"Cloning {remoteUrl} can take several minutes; Please wait...");
-
-                    LibGit2Sharp.Repository.Clone(remoteUrl, localDirectoryPath);
-
-                    TestContext.Progress.WriteLine($"... Clone Completed");
-
-                    return;
-                }
-
-                using (var repo = new LibGit2Sharp.Repository(localDirectoryPath))
-                {
-                    var options = new LibGit2Sharp.PullOptions
-                    {
-                        FetchOptions = new LibGit2Sharp.FetchOptions()
-                    };
-
-                    var r = LibGit2Sharp.Commands.Pull(repo, new LibGit2Sharp.Signature("Anonymous", "[email protected]", new DateTimeOffset(DateTime.Now)), options);
-
-                    TestContext.Progress.WriteLine($"{remoteUrl} is {r.Status}");
-                }
-            }
-        }
-
-        public static string DownloadFile(string remoteUri, string localFilePath)
+        public static bool IsFinite(this float value)
         {
-            if (!System.IO.Path.IsPathRooted(localFilePath)) throw new ArgumentException(nameof(localFilePath));
-
-            lock (_DownloadMutex)
-            {
-                if (System.IO.File.Exists(localFilePath)) return localFilePath; // we check again because we could have downloaded the file while waiting.
-
-                TestContext.Progress.WriteLine($"Downloading {remoteUri}... Please Wait...");
-
-                var dir = System.IO.Path.GetDirectoryName(localFilePath);
-                System.IO.Directory.CreateDirectory(dir);
-
-                using (var wc = new System.Net.WebClient())
-                {
-                    wc.DownloadFile(remoteUri, localFilePath);
-                }
-
-                if (localFilePath.ToLower().EndsWith(".zip"))
-                {
-                    TestContext.Progress.WriteLine($"Extracting {localFilePath}...");
-
-                    var extractPath = System.IO.Path.Combine(dir, System.IO.Path.GetFileNameWithoutExtension(localFilePath));
-
-                    System.IO.Compression.ZipFile.ExtractToDirectory(localFilePath, extractPath);
-                }
-
-                return localFilePath;
-            }
+            return !float.IsNaN(value) && !float.IsInfinity(value);
         }
-    }    
 
-    static class VectorsUtils
-    {
         public static Single NextSingle(this Random rnd)
         {
             return (Single)rnd.NextDouble();