diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6f28d4183..9c2cf3000 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -223,6 +223,19 @@ else() target_sources(unit PUBLIC ${Assimp_SOURCE_DIR}/contrib/gtest/src/gtest-all.cc) endif() +# RapidJSON +IF(ASSIMP_HUNTER_ENABLED) + hunter_add_package(RapidJSON) + find_package(RapidJSON CONFIG REQUIRED) +ELSE() + INCLUDE_DIRECTORIES("../contrib/rapidjson/include") + ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1) + option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON ) + if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR) + ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS ) + endif() +ENDIF() + IF (ASSIMP_BUILD_DRACO) ADD_DEFINITIONS( -DASSIMP_ENABLE_DRACO ) ENDIF() diff --git a/test/models/glTF2/SchemaFailures/CesiumLogoFlat.png b/test/models/glTF2/SchemaFailures/CesiumLogoFlat.png new file mode 100644 index 000000000..45d502ed2 Binary files /dev/null and b/test/models/glTF2/SchemaFailures/CesiumLogoFlat.png differ diff --git a/test/models/glTF2/SchemaFailures/sceneWrongType.gltf b/test/models/glTF2/SchemaFailures/sceneWrongType.gltf new file mode 100644 index 000000000..9a97c2b95 --- /dev/null +++ b/test/models/glTF2/SchemaFailures/sceneWrongType.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": "hello", + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 33648, + "wrapT": 33071 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ] +} diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index e29d09145..ed4c23547 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include @@ -772,3 +773,60 @@ TEST_F(utglTF2ImportExport, wrongTypes) { } } +namespace { + /// This class provides a fake schema to the GLTF importer. + /// It just checks that the file has a top-level "scene" property which is an integer. + class FakeSchemaProvider : public rapidjson::IRemoteSchemaDocumentProvider + { + public: + FakeSchemaProvider(const char* schemaName) : + m_schemaName(schemaName) + { + rapidjson::Document schemaDoc; + schemaDoc.Parse(R"==({"properties":{"scene" : { "type" : "integer" }}, "required": [ "scene" ]})=="); + EXPECT_FALSE(schemaDoc.HasParseError()); + m_schema = std::make_unique(schemaDoc, m_schemaName.c_str(), static_cast(m_schemaName.size()), this); + } + + const rapidjson::SchemaDocument* GetRemoteDocument(const char* uri, rapidjson::SizeType) override { + if (m_schemaName == uri) { + return m_schema.get(); + } + return nullptr; + } + + private: + std::string m_schemaName; + std::unique_ptr m_schema; + }; +} + +TEST_F(utglTF2ImportExport, schemaCheckPass) { + FakeSchemaProvider schemaProvider("glTF.schema.json"); + Assimp::Importer importer; + importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/gltf2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + EXPECT_NE(scene, nullptr); + EXPECT_STREQ(importer.GetErrorString(), ""); +} + +TEST_F(utglTF2ImportExport, schemaCheckFail) { + FakeSchemaProvider schemaProvider("glTF.schema.json"); + Assimp::Importer importer; + importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/gltf2/SchemaFailures/sceneWrongType.gltf", aiProcess_ValidateDataStructure); + EXPECT_EQ(scene, nullptr); + const std::string errorString = importer.GetErrorString(); + EXPECT_NE(errorString.find("The JSON document did not satisfy the glTF2 schema"), std::string::npos); +} + +TEST_F(utglTF2ImportExport, noSchemaFound) { + // More than one importer might make use the provider, but not all schemas might be present. + // Check that the glTF importer handles the case when an non-null provider returns null when asked for schemas. + FakeSchemaProvider schemaProvider("missingSchema.json"); + Assimp::Importer importer; + importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/gltf2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + EXPECT_NE(scene, nullptr); + EXPECT_STREQ(importer.GetErrorString(), ""); +}