From 40a1edef7f76efe01fee6b7d839cd52c0665ecc2 Mon Sep 17 00:00:00 2001 From: JosiahWI Date: Sat, 22 Oct 2022 16:36:29 -0500 Subject: [PATCH] Test invalid JSON Also converted all .cpp and .h line endings to CRLF in this commit. --- source/Irrlicht/CGLTFMeshFileLoader.cpp | 135 ++++++++++-------- source/Irrlicht/CGLTFMeshFileLoader.h | 33 +++++ source/Irrlicht/tests/inMemoryFile.cpp | 108 +++++++------- source/Irrlicht/tests/inMemoryFile.h | 64 ++++----- .../tests/testCGLTFMeshFileLoader.cpp | 128 +++++++++++------ 5 files changed, 276 insertions(+), 192 deletions(-) create mode 100644 source/Irrlicht/CGLTFMeshFileLoader.h diff --git a/source/Irrlicht/CGLTFMeshFileLoader.cpp b/source/Irrlicht/CGLTFMeshFileLoader.cpp index 22378e97d..81f4fd8a1 100644 --- a/source/Irrlicht/CGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/CGLTFMeshFileLoader.cpp @@ -1,59 +1,76 @@ -#include "CGLTFMeshFileLoader.h" -#include "CMeshBuffer.h" -#include "coreutil.h" -#include "IAnimatedMesh.h" -#include "IReadFile.h" -#include "irrTypes.h" -#include "path.h" -#include "S3DVertex.h" -#include "SAnimatedMesh.h" -#include "SColor.h" -#include "SMesh.h" - -#include - -namespace irr -{ - -namespace scene -{ - -CGLTFMeshFileLoader::CGLTFMeshFileLoader() -{ -} - -bool CGLTFMeshFileLoader::isALoadableFileExtension( - const io::path& filename) const -{ - return core::hasFileExtension(filename, "gltf"); -} - -IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file) -{ - if (file->getSize() == 0) { - return nullptr; - } - - // sorry Bjarne - SMeshBuffer* meshbuf { new SMeshBuffer {} }; - - const video::S3DVertex* vertices { new video::S3DVertex[3] { - {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 0.0f}}, - {{0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {1.0f, 0.0f}}, - {{-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 1.0f}} } }; - const u16* indices { new u16[3] {0, 1, 2} }; - meshbuf->append(vertices, 3, indices, 3); - - SMesh* mesh { new SMesh {} }; - mesh->addMeshBuffer(meshbuf); - - SAnimatedMesh* animatedMesh { new SAnimatedMesh {} }; - animatedMesh->addMesh(mesh); - - return animatedMesh; -} - -} // namespace irr - -} // namespace scene - +#include "CGLTFMeshFileLoader.h" +#include "CMeshBuffer.h" +#include "coreutil.h" +#include "IAnimatedMesh.h" +#include "IReadFile.h" +#include "irrTypes.h" +#include "path.h" +#include "S3DVertex.h" +#include "SAnimatedMesh.h" +#include "SColor.h" +#include "SMesh.h" + +#define TINYGLTF_IMPLEMENTATION +#include + +#include +#include + +namespace irr +{ + +namespace scene +{ + +CGLTFMeshFileLoader::CGLTFMeshFileLoader() +{ +} + +bool CGLTFMeshFileLoader::isALoadableFileExtension( + const io::path& filename) const +{ + return core::hasFileExtension(filename, "gltf"); +} + +IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (file->getSize() == 0 || !tryParseGLTF(file)) { + return nullptr; + } + + // sorry Bjarne + SMeshBuffer* meshbuf { new SMeshBuffer {} }; + + const video::S3DVertex* vertices { new video::S3DVertex[3] { + {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 0.0f}}, + {{0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {1.0f, 0.0f}}, + {{-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 1.0f}} } }; + const u16* indices { new u16[3] {0, 1, 2} }; + meshbuf->append(vertices, 3, indices, 3); + + SMesh* mesh { new SMesh {} }; + mesh->addMeshBuffer(meshbuf); + + SAnimatedMesh* animatedMesh { new SAnimatedMesh {} }; + animatedMesh->addMesh(mesh); + + return animatedMesh; +} + +bool CGLTFMeshFileLoader::tryParseGLTF(io::IReadFile* file) const +{ + tinygltf::Model model {}; + tinygltf::TinyGLTF loader {}; + std::string err {}; + std::string warn {}; + + auto buf = std::make_unique(file->getSize()); + file->read(buf.get(), file->getSize()); + return loader.LoadASCIIFromString( + &model, &err, &warn, buf.get(), file->getSize(), "", 1); +} + +} // namespace irr + +} // namespace scene + diff --git a/source/Irrlicht/CGLTFMeshFileLoader.h b/source/Irrlicht/CGLTFMeshFileLoader.h new file mode 100644 index 000000000..76f464df3 --- /dev/null +++ b/source/Irrlicht/CGLTFMeshFileLoader.h @@ -0,0 +1,33 @@ +#ifndef __C_GLTF_MESH_FILE_LOADER_INCLUDED__ +#define __C_GLTF_MESH_FILE_LOADER_INCLUDED__ + +#include "IAnimatedMesh.h" +#include "IMeshLoader.h" +#include "IReadFile.h" +#include "path.h" + +namespace irr +{ + +namespace scene +{ + +class CGLTFMeshFileLoader : public IMeshLoader +{ +public: + CGLTFMeshFileLoader(); + + bool isALoadableFileExtension(const io::path& filename) const override; + + IAnimatedMesh* createMesh(io::IReadFile* file) override; + +private: + bool tryParseGLTF(io::IReadFile* file) const; +}; + +} // namespace scene + +} // namespace irr + +#endif // __C_GLTF_MESH_FILE_LOADER_INCLUDED__ + diff --git a/source/Irrlicht/tests/inMemoryFile.cpp b/source/Irrlicht/tests/inMemoryFile.cpp index b48c74343..61402e1dd 100644 --- a/source/Irrlicht/tests/inMemoryFile.cpp +++ b/source/Irrlicht/tests/inMemoryFile.cpp @@ -1,54 +1,54 @@ -#include "inMemoryFile.h" - -#include - -#include - -namespace irr -{ - -namespace io -{ - -InMemoryFile::InMemoryFile(const io::path& filename, const std::string& s) - : m_filename { filename } - , m_sstream { s } -{ -} - -std::size_t InMemoryFile::read(void* buffer, std::size_t sizeToRead) -{ - m_sstream.read(reinterpret_cast(buffer), sizeToRead); - return m_sstream.gcount(); -} - -bool InMemoryFile::seek(long finalPos, bool relativeMovement) -{ - if (relativeMovement) { - m_sstream.seekg(finalPos, std::ios::beg); - } else { - m_sstream.seekg(finalPos); - } - - return m_sstream.fail(); -} - -long InMemoryFile::getSize() const -{ - return m_sstream.str().size(); -} - -long InMemoryFile::getPos() const -{ - return m_sstream.tellg(); -} - -const io::path& InMemoryFile::getFileName() const -{ - return m_filename; -} - -} // namespace irr - -} // namespace io - +#include "inMemoryFile.h" + +#include + +#include + +namespace irr +{ + +namespace io +{ + +InMemoryFile::InMemoryFile(const io::path& filename, const std::string& s) + : m_filename { filename } + , m_sstream { s } +{ +} + +std::size_t InMemoryFile::read(void* buffer, std::size_t sizeToRead) +{ + m_sstream.read(reinterpret_cast(buffer), sizeToRead); + return m_sstream.gcount(); +} + +bool InMemoryFile::seek(long finalPos, bool relativeMovement) +{ + if (relativeMovement) { + m_sstream.seekg(finalPos, std::ios::beg); + } else { + m_sstream.seekg(finalPos); + } + + return m_sstream.fail(); +} + +long InMemoryFile::getSize() const +{ + return m_sstream.str().size(); +} + +long InMemoryFile::getPos() const +{ + return m_sstream.tellg(); +} + +const io::path& InMemoryFile::getFileName() const +{ + return m_filename; +} + +} // namespace irr + +} // namespace io + diff --git a/source/Irrlicht/tests/inMemoryFile.h b/source/Irrlicht/tests/inMemoryFile.h index 8cbd195c7..be33ad4a9 100644 --- a/source/Irrlicht/tests/inMemoryFile.h +++ b/source/Irrlicht/tests/inMemoryFile.h @@ -1,32 +1,32 @@ -#include - -#include -#include -#include - -namespace irr -{ - -namespace io -{ - -class InMemoryFile: public IReadFile -{ -public: - InMemoryFile(const io::path& filename, const std::string& s); - - std::size_t read(void* buffer, std::size_t sizeToRead) override; - bool seek(long finalPos, bool relativeMovement=false) override; - long getSize() const override; - long getPos() const override; - const io::path& getFileName() const override; - -private: - io::path m_filename; - mutable std::stringstream m_sstream; -}; - -} // namespace io - -} // namespace irr - +#include + +#include +#include +#include + +namespace irr +{ + +namespace io +{ + +class InMemoryFile: public IReadFile +{ +public: + InMemoryFile(const io::path& filename, const std::string& s); + + std::size_t read(void* buffer, std::size_t sizeToRead) override; + bool seek(long finalPos, bool relativeMovement=false) override; + long getSize() const override; + long getPos() const override; + const io::path& getFileName() const override; + +private: + io::path m_filename; + mutable std::stringstream m_sstream; +}; + +} // namespace io + +} // namespace irr + diff --git a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp index 73f618daa..c717ac5a2 100644 --- a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp @@ -1,47 +1,81 @@ -#include "inMemoryFile.h" - -#define CATCH_CONFIG_MAIN -#include -#include - -TEST_CASE("load empty gltf file") { - irr::IrrlichtDevice* device { irr::createDevice(irr::video::EDT_NULL) }; - irr::scene::ISceneManager* smgr { device->getSceneManager() }; - irr::io::InMemoryFile filebuf {"test.gltf", ""}; - auto* mesh { smgr->getMesh(&filebuf) }; - - CHECK(mesh == nullptr); - - device->drop(); -} - -TEST_CASE("minimal triangle has correct vertices") { - irr::IrrlichtDevice* device { irr::createDevice(irr::video::EDT_NULL) }; - irr::scene::ISceneManager* smgr { device->getSceneManager() }; - auto* mesh { smgr->getMesh( - "source/Irrlicht/tests/assets/minimal_triangle.gltf", "") }; - - REQUIRE(mesh != nullptr); - REQUIRE(mesh->getMeshBufferCount() == 1); - auto* meshbuf { mesh->getMeshBuffer(0) }; - REQUIRE(meshbuf->getVertexCount() == 3); - irr::video::S3DVertex* vertices { - reinterpret_cast( - meshbuf->getVertices()) }; - CHECK(vertices[0].Pos == irr::core::vector3df {0.0f, 0.0f, 0.0f}); - CHECK(vertices[1].Pos == irr::core::vector3df {0.0f, 1.0f, 0.0f}); - CHECK(vertices[2].Pos == irr::core::vector3df {-1.0f, 0.0f, 0.0f}); - - device->drop(); -} - -TEST_CASE("mesh loader returns nullptr when given null file pointer") { - irr::IrrlichtDevice* device { irr::createDevice(irr::video::EDT_NULL) }; - irr::scene::ISceneManager* smgr { device->getSceneManager() }; - auto* mesh { smgr->getMesh(nullptr) }; - - CHECK(mesh == nullptr); - - device->drop(); -} - +#include "inMemoryFile.h" + +#define CATCH_CONFIG_MAIN +#include +#include + +class ScopedMesh +{ +public: + ScopedMesh(irr::io::IReadFile* file) + : m_device { irr::createDevice(irr::video::EDT_NULL) } + , m_mesh { nullptr } + { + auto* smgr = m_device->getSceneManager(); + m_mesh = smgr->getMesh(file); + } + + ScopedMesh(const irr::io::path& filepath) + : m_device { irr::createDevice(irr::video::EDT_NULL) } + , m_mesh { nullptr } + { + auto* smgr = m_device->getSceneManager(); + m_mesh = smgr->getMesh(filepath, ""); + } + + ~ScopedMesh() + { + m_device->drop(); + m_mesh = nullptr; + } + + const irr::scene::IAnimatedMesh* getMesh() const + { + return m_mesh; + } + +private: + irr::IrrlichtDevice* m_device; + irr::scene::IAnimatedMesh* m_mesh; +}; + +TEST_CASE("load empty gltf file") { + irr::io::InMemoryFile filebuf {"test.gltf", ""}; + ScopedMesh sm { &filebuf }; + CHECK(sm.getMesh() == nullptr); +} + +TEST_CASE("minimal triangle has correct vertices") { + ScopedMesh sm { "source/Irrlicht/tests/assets/minimal_triangle.gltf" }; + + auto* mesh = sm.getMesh(); + REQUIRE(mesh != nullptr); + REQUIRE(mesh->getMeshBufferCount() == 1); + auto* meshbuf = mesh->getMeshBuffer(0); + REQUIRE(meshbuf->getVertexCount() == 3); + auto* vertices = reinterpret_cast( + meshbuf->getVertices()); + CHECK(vertices[0].Pos == irr::core::vector3df {0.0f, 0.0f, 0.0f}); + CHECK(vertices[1].Pos == irr::core::vector3df {0.0f, 1.0f, 0.0f}); + CHECK(vertices[2].Pos == irr::core::vector3df {-1.0f, 0.0f, 0.0f}); +} + +TEST_CASE("mesh loader returns nullptr when given null file pointer") { + ScopedMesh sm { nullptr }; + CHECK(sm.getMesh() == nullptr); +} + +TEST_CASE("invalid JSON returns nullptr") { + SECTION("missing closing brace") { + irr::io::InMemoryFile filebuf {"test.gltf", "{"}; + ScopedMesh sm { &filebuf }; + CHECK(sm.getMesh() == nullptr); + } + + SECTION("missing colon") { + irr::io::InMemoryFile filebuf {"test.gltf", "{\"a\" \"b\"}"}; + ScopedMesh sm { &filebuf }; + CHECK(sm.getMesh() == nullptr); + } +} +