// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. #pragma once #include #include #include "GLTFSDK/IStreamWriter.h" #include "GLTFSDK/Constants.h" #include "GLTFSDK/Serialize.h" #include "GLTFSDK/Deserialize.h" #include #include #include #include "WStringUtils.h" #include "StreamMock.h" #include #include #include #include #include namespace Microsoft::glTF::Toolkit::Test { class TestUtils { public: static std::string GetBasePath(const char * absolutePath) { std::string path(absolutePath); #ifdef __APPLE__ return path.substr(0, path.rfind('/') + 1); #else return path.substr(0, path.rfind('\\') + 1); #endif } static std::string GetAbsolutePath(const char * relativePath) { #ifdef __APPLE__ // Leaving Win32 alone (below), but macOS requires working directory to be set std::string finalPath(relativePath); std::replace(finalPath.begin(), finalPath.end(), '\\', '/'); return finalPath; #else std::string currentPath = __FILE__; std::string sourcePath = currentPath.substr(0, currentPath.rfind('\\')); std::string resourcePath = sourcePath.substr(0, sourcePath.rfind('\\')); return resourcePath + "\\" + relativePath; #endif } static std::wstring GetAbsolutePathW(const char * relativePath) { std::string absolutePath = GetAbsolutePath(relativePath); std::wstringstream wss; wss << absolutePath.c_str(); return wss.str(); } static std::shared_ptr ReadLocalAsset(const std::string& filename) { // Read local file int64_t m_readPosition = 0; std::shared_ptr> m_buffer; std::ifstream ifs; ifs.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); if (ifs.is_open()) { std::streampos start = ifs.tellg(); ifs.seekg(0, std::ios::end); m_buffer = std::make_shared>(static_cast(ifs.tellg() - start)); ifs.seekg(0, std::ios::beg); ifs.read(reinterpret_cast(const_cast(m_buffer->data())), m_buffer->size()); ifs.close(); } else { throw std::runtime_error("Could not open the file for reading"); } // To IStream unsigned long writeBufferLength = 4096L * 1024L; auto tempStream = std::make_shared(); auto tempBuffer = new char[writeBufferLength]; // Read the file for as long as we can fill the buffer completely. // This means there is more content to be read. unsigned long bytesRead; do { auto bytesAvailable = m_buffer->size() - m_readPosition; unsigned long br = std::min(static_cast(bytesAvailable), writeBufferLength); #ifdef _WIN32 memcpy_s(tempBuffer, br, m_buffer->data() + m_readPosition, br); #else memcpy(tempBuffer, m_buffer->data() + m_readPosition, br); #endif m_readPosition += br; bytesRead = br; tempStream->write(tempBuffer, bytesRead); } while (bytesRead == writeBufferLength); delete[] tempBuffer; if (tempStream.get()->bad()) { throw std::runtime_error("Bad std::stringstream after copying the file"); } return tempStream; } typedef std::function GLTFAction; static void LoadAndExecuteGLTFTest(const char * gltfRelativePath, GLTFAction action) { // This asset has all textures auto absolutePath = TestUtils::GetAbsolutePath(gltfRelativePath); auto input = TestUtils::ReadLocalAsset(absolutePath); try { // Deserialize input json auto inputJson = std::string(std::istreambuf_iterator(*input), std::istreambuf_iterator()); auto doc = Deserialize(inputJson); action(doc, absolutePath); } catch (std::exception ex) { std::stringstream ss; ss << "Received exception was unexpected. Got: " << ex.what(); Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail(WStringUtils::ToWString(ss).c_str()); } } }; class TestStreamReader : public IStreamReader { public: TestStreamReader(std::string gltfAbsolutePath) : m_basePath(TestUtils::GetBasePath(gltfAbsolutePath.c_str())) {} virtual ~TestStreamReader() override {} virtual std::shared_ptr GetInputStream(const std::string& filename) const override { auto path = m_basePath; #ifdef __APPLE__ path += "/" + filename; #else path += "\\" + filename; #endif return std::make_shared(path, std::ios::binary); } private: const std::string m_basePath; }; }