diff options
31 files changed, 415 insertions, 84 deletions
| diff --git a/.crepe-root b/.crepe-root new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.crepe-root diff --git a/.gitmodules b/.gitmodules index 2f64601..bd6e7f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,7 @@  	path = lib/libdb  	url = https://github.com/berkeleydb/libdb  	shallow = true +[submodule "lib/whereami/whereami"] +	path = lib/whereami/lib +	url = https://github.com/gpakosz/whereami +	shallow = true diff --git a/contributing.md b/contributing.md index 9c95851..77a2908 100644 --- a/contributing.md +++ b/contributing.md @@ -15,7 +15,11 @@ that you can click on to open them.    `name/feature` (i.e. `loek/dll-so-poc` or `jaro/class2`)  - The master branch is considered stable, and should always contain a    working/compiling version of the project +- Pull requests for new code include either automated tests for the new code or +  an explanation as to why the code can not (reliably) be tested +<!--  - TODO: tagging / versions +-->  # Code style @@ -790,6 +794,7 @@ that you can click on to open them.    }    ```    </td></tr></table></details> +- Do not implement new classes as singletons  ## CMakeLists-specific diff --git a/lib/whereami/CMakeLists.txt b/lib/whereami/CMakeLists.txt new file mode 100644 index 0000000..96d3a23 --- /dev/null +++ b/lib/whereami/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.28) +set(CMAKE_C_STANDARD 11) +project(whereami C) + +include(CMakePackageConfigHelpers) + +add_library(whereami SHARED) + +target_include_directories(whereami PRIVATE SYSTEM lib/src) +target_sources(whereami PRIVATE lib/src/whereami.c) + +install( +	TARGETS whereami +	EXPORT whereamiTargets +	LIBRARY DESTINATION lib +	ARCHIVE DESTINATION lib +	RUNTIME DESTINATION lib +	INCLUDES DESTINATION include +) +install( +	FILES lib/src/whereami.h +	DESTINATION include +) +write_basic_package_version_file( +	"${CMAKE_CURRENT_BINARY_DIR}/whereami-config-version.cmake" +	VERSION 0.0.0 +	COMPATIBILITY AnyNewerVersion +) +install( +	FILES +		"${CMAKE_CURRENT_BINARY_DIR}/whereami-config-version.cmake" +	DESTINATION lib/cmake/whereami +) +install( +	EXPORT whereamiTargets +	FILE whereami-config.cmake +	DESTINATION lib/cmake/whereami +) diff --git a/lib/whereami/lib b/lib/whereami/lib new file mode 160000 +Subproject dcb52a058dc14530ba9ae05e4339bd3ddfae0e0 @@ -32,6 +32,7 @@ This project uses the following libraries  |`SoLoud`|(latest git `master` version)|  |Google Test (`GTest`)|1.15.2|  |Berkeley DB (`libdb`)|5.3.21| +|Where Am I?|(latest git `master` version)  > [!NOTE]  > Most of these libraries are likely available from your package manager if you @@ -49,6 +50,11 @@ $ git submodule update --init --recursive --depth 1  Then, follow these steps for each library you want to install: +> [!IMPORTANT] +> A dollar sign prompt (`$`) indicates commands to be run as a regular user, +> while a hashtag (`#`) is used to denote commands that must be run with +> privileges (e.g. as root or using `sudo`). +  1. Change into the library folder (run **one** of these):     ```     $ cd lib/googletest @@ -56,6 +62,7 @@ Then, follow these steps for each library you want to install:     $ cd lib/soloud/contrib     $ cd lib/sdl_image     $ cd lib/sdl_ttf +   $ cd lib/whereami     ```  2. Use CMake to configure the build, run the build and install (run **all** of     these): diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 445a8b2..c3f29da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ find_package(SDL2 REQUIRED)  find_package(SDL2_image REQUIRED)  find_package(SoLoud REQUIRED)  find_package(GTest REQUIRED) +find_package(whereami REQUIRED)  find_library(BERKELEY_DB db)  add_library(crepe SHARED) @@ -25,6 +26,7 @@ target_link_libraries(crepe  	PUBLIC SDL2  	PUBLIC SDL2_image  	PUBLIC ${BERKELEY_DB} +	PUBLIC whereami  )  add_subdirectory(crepe) diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp deleted file mode 100644 index 9c41ecb..0000000 --- a/src/crepe/Asset.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include <filesystem> - -#include "Asset.h" - -using namespace crepe; -using namespace std; - -// FIXME: restore this -// src(std::filesystem::canonical(src)) -Asset::Asset(const std::string & src) : src(src) { -	this->file = std::ifstream(this->src, std::ios::in | std::ios::binary); -} - -istream & Asset::get_stream() { return this->file; } - -const string & Asset::get_canonical() const { return this->src; } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h deleted file mode 100644 index 9051c5e..0000000 --- a/src/crepe/Asset.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <fstream> -#include <iostream> -#include <string> - -namespace crepe { - -/** - * \brief Asset location helper - * - * This class is used to locate and canonicalize paths to game asset files, and should *always* - * be used when retrieving files from disk. - */ -class Asset { -public: -	/** -	 * \param src  Unique identifier to asset -	 */ -	Asset(const std::string & src); - -public: -	/** -	 * \brief Get an input stream to the contents of this asset -	 * \return Input stream with file contents -	 */ -	std::istream & get_stream(); -	/** -	 * \brief Get the canonical path to this asset -	 * \return Canonical path to this asset -	 */ -	const std::string & get_canonical() const; - -private: -	//! Canonical path to asset -	const std::string src; -	//! File handle (stream) -	std::ifstream file; -}; - -} // namespace crepe diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 3b05742..7e176e7 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,5 +1,4 @@  target_sources(crepe PUBLIC -	Asset.cpp  	Particle.cpp  	ComponentManager.cpp  	Component.cpp @@ -7,7 +6,6 @@ target_sources(crepe PUBLIC  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES -	Asset.h  	ComponentManager.h  	ComponentManager.hpp  	Component.h diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h index 2107453..0956d1e 100644 --- a/src/crepe/ComponentManager.h +++ b/src/crepe/ComponentManager.h @@ -8,6 +8,7 @@  #include "api/Vector2.h"  #include "Component.h" +#include "types.h"  namespace crepe { @@ -112,7 +113,7 @@ public:  	 * \return A vector of all components of the specific type and id  	 */  	template <typename T> -	std::vector<std::reference_wrapper<T>> get_components_by_id(game_object_id_t id) const; +	RefVector<T> get_components_by_id(game_object_id_t id) const;  	/**  	 * \brief Get all components of a specific type  	 *  @@ -122,7 +123,7 @@ public:  	 * \return A vector of all components of the specific type  	 */  	template <typename T> -	std::vector<std::reference_wrapper<T>> get_components_by_type() const; +	RefVector<T> get_components_by_type() const;  private:  	/** diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp index be99cac..4d5eaf4 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/ComponentManager.hpp @@ -81,15 +81,14 @@ void ComponentManager::delete_components() {  }  template <typename T> -std::vector<std::reference_wrapper<T>> -ComponentManager::get_components_by_id(game_object_id_t id) const { +RefVector<T> ComponentManager::get_components_by_id(game_object_id_t id) const {  	using namespace std;  	// Determine the type of T (this is used as the key of the unordered_map<>)  	type_index type = typeid(T);  	// Create an empty vector<> -	vector<reference_wrapper<T>> component_vector; +	RefVector<T> component_vector;  	if (this->components.find(type) == this->components.end()) return component_vector; @@ -114,14 +113,14 @@ ComponentManager::get_components_by_id(game_object_id_t id) const {  }  template <typename T> -std::vector<std::reference_wrapper<T>> ComponentManager::get_components_by_type() const { +RefVector<T> ComponentManager::get_components_by_type() const {  	using namespace std;  	// Determine the type of T (this is used as the key of the unordered_map<>)  	type_index type = typeid(T);  	// Create an empty vector<> -	vector<reference_wrapper<T>> component_vector; +	RefVector<T> component_vector;  	// Find the type (in the unordered_map<>)  	if (this->components.find(type) == this->components.end()) return component_vector; diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp new file mode 100644 index 0000000..e148367 --- /dev/null +++ b/src/crepe/api/Asset.cpp @@ -0,0 +1,54 @@ +#include <filesystem> +#include <stdexcept> +#include <whereami.h> + +#include "api/Config.h" + +#include "Asset.h" + +using namespace crepe; +using namespace std; + +Asset::Asset(const string & src) : src(find_asset(src)) {} +Asset::Asset(const char * src) : src(find_asset(src)) {} + +const string & Asset::get_path() const noexcept { return this->src; } + +string Asset::find_asset(const string & src) const { +	auto & cfg = Config::get_instance(); +	string & root_pattern = cfg.asset.root_pattern; + +	// if root_pattern is empty, find_asset must return all paths as-is +	if (root_pattern.empty()) return src; + +	// absolute paths do not need to be resolved, only canonicalized +	filesystem::path path = src; +	if (path.is_absolute()) return filesystem::canonical(path); + +	// find directory matching root_pattern +	filesystem::path root = this->whereami(); +	while (1) { +		if (filesystem::exists(root / root_pattern)) break; +		if (!root.has_parent_path()) +			throw runtime_error(format("Asset: Cannot find root pattern ({})", root_pattern)); +		root = root.parent_path(); +	} + +	// join path to root (base directory) and canonicalize +	return filesystem::canonical(root / path); +} + +string Asset::whereami() const noexcept { +	string path; +	size_t path_length = wai_getExecutablePath(NULL, 0, NULL); +	path.resize(path_length + 1); // wai writes null byte +	wai_getExecutablePath(path.data(), path_length, NULL); +	path.resize(path_length); +	return path; +} + +bool Asset::operator==(const Asset & other) const noexcept { return this->src == other.src; } + +size_t std::hash<const Asset>::operator()(const Asset & asset) const noexcept { +	return std::hash<string>{}(asset.get_path()); +}; diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h new file mode 100644 index 0000000..bfd0ac7 --- /dev/null +++ b/src/crepe/api/Asset.h @@ -0,0 +1,84 @@ +#pragma once + +#include <string> + +namespace crepe { + +/** + * \brief Asset location helper + * + * This class is used to locate game asset files, and should *always* be used + * instead of reading file paths directly. + */ +class Asset { +public: +	/** +	 * \param src  Unique identifier to asset +	 */ +	Asset(const std::string & src); +	/** +	 * \param src  Unique identifier to asset +	 */ +	Asset(const char * src); + +public: +	/** +	 * \brief Get the path to this asset +	 * \return path to this asset +	 */ +	const std::string & get_path() const noexcept; + +	/** +	 * \brief Comparison operator +	 * \param other Possibly different instance of \c Asset to test equality against +	 * \return True if \c this and \c other are equal +	 */ +	bool operator==(const Asset & other) const noexcept; + +private: +	//! path to asset +	const std::string src; + +private: +	/** +	 * \brief Locate asset path, or throw exception if it cannot be found +	 * +	 * This function resolves asset locations relative to crepe::Config::root_pattern if it is +	 * set and \p src is a relative path. If \p src is an absolute path, it is canonicalized. +	 * This function only returns if the file can be found. +	 * +	 * \param src Arbitrary path to resource file +	 * +	 * \returns \p src if crepe::Config::root_pattern is empty +	 * \returns Canonical path to \p src +	 * +	 * \throws std::runtime_error if root_pattern cannot be found +	 * \throws std::filesystem::filesystem_error if the resolved path does not exist +	 * \throws std::filesystem::filesystem_error if the path cannot be canonicalized +	 */ +	std::string find_asset(const std::string & src) const; +	/** +	 * \returns The path to the current executable +	 */ +	std::string whereami() const noexcept; +}; + +} // namespace crepe + +namespace std { + +//! Hash helper struct +template <> +struct hash<const crepe::Asset> { +	/** +	 * \brief Hash operator for crepe::Asset +	 * +	 * This function hashes a crepe::Asset instance, allowing it to be used as a key in an \c +	 * std::unordered_map. +	 * +	 * \returns Hash value +	 */ +	size_t operator()(const crepe::Asset & asset) const noexcept; +}; + +} // namespace std diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index f9b370f..6557656 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(crepe PUBLIC  	Animator.cpp  	LoopManager.cpp  	LoopTimer.cpp +	Asset.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -45,4 +46,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Animator.h  	LoopManager.h  	LoopTimer.h +	Asset.h  ) diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 3ab877a..13eabd1 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -62,6 +62,20 @@ public:  		 */  		double gravity = 1;  	} physics; + +	//! Asset loading options +	struct { +		/** +		 * \brief Pattern to match for Asset base directory +		 * +		 * All non-absolute paths resolved using \c Asset will be made relative to +		 * the first parent directory relative to the calling executable where +		 * appending this pattern results in a path that exists. If this string is +		 * empty, path resolution is disabled, and Asset will return all paths +		 * as-is. +		 */ +		std::string root_pattern = ".crepe-root"; +	} asset;  };  } // namespace crepe diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp index de0d0ea..6a1e4d8 100644 --- a/src/crepe/api/Texture.cpp +++ b/src/crepe/api/Texture.cpp @@ -26,7 +26,7 @@ Texture::~Texture() {  void Texture::load(unique_ptr<Asset> res) {  	SDLContext & ctx = SDLContext::get_instance(); -	this->texture = std::move(ctx.texture_from_path(res->get_canonical())); +	this->texture = std::move(ctx.texture_from_path(res->get_path()));  }  int Texture::get_width() const { diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 83e91f8..f2daada 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -149,7 +149,7 @@ SDLContext::texture_from_path(const std::string & path) {  	SDL_Surface * tmp = IMG_Load(path.c_str());  	if (tmp == nullptr) { -		tmp = IMG_Load("../asset/texture/ERROR.png"); +		tmp = IMG_Load("asset/texture/ERROR.png");  	}  	std::unique_ptr<SDL_Surface, std::function<void(SDL_Surface *)>> img_surface; diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 7aa89a9..4d3abf5 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -16,7 +16,7 @@ Sound::Sound(const char * src) {  	this->load(make_unique<Asset>(src));  } -void Sound::load(unique_ptr<Asset> res) { this->sample.load(res->get_canonical().c_str()); } +void Sound::load(unique_ptr<Asset> res) { this->sample.load(res->get_path().c_str()); }  void Sound::play() {  	SoundContext & ctx = SoundContext::get_instance(); diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index 32b6478..4c68f32 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -4,7 +4,7 @@  #include <soloud/soloud.h>  #include <soloud/soloud_wav.h> -#include "../Asset.h" +#include "../api/Asset.h"  namespace crepe { diff --git a/src/crepe/types.h b/src/crepe/types.h index 0d459e8..914c76c 100644 --- a/src/crepe/types.h +++ b/src/crepe/types.h @@ -1,9 +1,16 @@  #pragma once  #include <cstdint> +#include <functional> +#include <vector>  namespace crepe { +//! GameObject ID  typedef uint32_t game_object_id_t; -} +//! vector of reference_wrapper +template <typename T> +using RefVector = std::vector<std::reference_wrapper<T>>; + +} // namespace crepe diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt index 4be738a..94ed906 100644 --- a/src/crepe/util/CMakeLists.txt +++ b/src/crepe/util/CMakeLists.txt @@ -9,5 +9,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Log.hpp  	Proxy.h  	Proxy.hpp +	OptionalRef.h +	OptionalRef.hpp  ) diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h new file mode 100644 index 0000000..57f9635 --- /dev/null +++ b/src/crepe/util/OptionalRef.h @@ -0,0 +1,64 @@ +#pragma once + +namespace crepe { + +/** + * \brief Optional reference utility + * + * This class doesn't need to know the full definition of \c T to be used. + * + * \tparam T Value type + */ +template <typename T> +class OptionalRef { +public: +	//! Initialize empty (nonexistant) reference +	OptionalRef() = default; +	//! Initialize reference with value +	OptionalRef(T & ref); +	/** +	 * \brief Assign new reference +	 * +	 * \param ref Reference to assign +	 * +	 * \return Reference to this (required for operator) +	 */ +	OptionalRef<T> & operator=(T & ref); +	/** +	 * \brief Check if this reference is not empty +	 * +	 * \returns `true` if reference is set, or `false` if it is not +	 */ +	explicit operator bool() const noexcept; + +	/** +	 * \brief Assign new reference +	 * +	 * \param ref Reference to assign +	 */ +	void set(T & ref) noexcept; +	/** +	 * \brief Retrieve this reference +	 * +	 * \returns Internal reference if it is set +	 * +	 * \throws std::runtime_error if this function is called while the reference it not set +	 */ +	T & get() const; +	/** +	 * \brief Make this reference empty +	 */ +	void clear() noexcept; + +private: +	/** +	 * \brief Reference to the value of type \c T +	 * +	 * \note This raw pointer is *not* managed, and only used as a reference! +	 */ +	T * ref = nullptr; +}; + +} // namespace crepe + +#include "OptionalRef.hpp" diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp new file mode 100644 index 0000000..71e2a39 --- /dev/null +++ b/src/crepe/util/OptionalRef.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <stdexcept> + +#include "OptionalRef.h" + +namespace crepe { + +template <typename T> +OptionalRef<T>::OptionalRef(T & ref) { +	this->set(ref); +} + +template <typename T> +T & OptionalRef<T>::get() const { +	if (this->ref == nullptr) +		throw std::runtime_error("OptionalRef: attempt to dereference nullptr"); +	return *this->ref; +} + +template <typename T> +void OptionalRef<T>::set(T & ref) noexcept { +	this->ref = &ref; +} + +template <typename T> +void OptionalRef<T>::clear() noexcept { +	this->ref = nullptr; +} + +template <typename T> +OptionalRef<T> & OptionalRef<T>::operator=(T & ref) { +	this->set(ref); +	return *this; +} + +template <typename T> +OptionalRef<T>::operator bool() const noexcept { +	return this->ref != nullptr; +} + +} // namespace crepe diff --git a/src/example/audio_internal.cpp b/src/example/audio_internal.cpp index 661161a..1647f20 100644 --- a/src/example/audio_internal.cpp +++ b/src/example/audio_internal.cpp @@ -25,11 +25,11 @@ int _ = []() {  int main() {  	// Load a background track (Ogg Vorbis) -	auto bgm = Sound("../mwe/audio/bgm.ogg"); +	auto bgm = Sound("mwe/audio/bgm.ogg");  	// Load three short samples (WAV) -	auto sfx1 = Sound("../mwe/audio/sfx1.wav"); -	auto sfx2 = Sound("../mwe/audio/sfx2.wav"); -	auto sfx3 = Sound("../mwe/audio/sfx3.wav"); +	auto sfx1 = Sound("mwe/audio/sfx1.wav"); +	auto sfx2 = Sound("mwe/audio/sfx2.wav"); +	auto sfx3 = Sound("mwe/audio/sfx3.wav");  	// Start the background track  	bgm.play(); diff --git a/src/example/particles.cpp b/src/example/particles.cpp index 3d5f676..d4638a2 100644 --- a/src/example/particles.cpp +++ b/src/example/particles.cpp @@ -18,7 +18,7 @@ int main(int argc, char * argv[]) {  	GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0);  	Color color(0, 0, 0, 0);  	Sprite test_sprite = game_object.add_component<Sprite>( -		make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true}); +		make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{true, true});  	game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{  		.position = {0, 0},  		.max_particles = 100, diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index ecd3f6a..01794f8 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -30,17 +30,16 @@ int main() {  	// Normal adding components  	{  		Color color(0, 0, 0, 0); -		Sprite & sprite -			= obj.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), -										color, FlipSettings{false, false}); +		Sprite & sprite = obj.add_component<Sprite>( +			make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{false, false});  		sprite.sorting_in_layer = 2;  		sprite.order_in_layer = 1; -		obj.add_component<Camera>(Color::get_red()); +		obj.add_component<Camera>(Color::RED);  	}  	{  		Color color(0, 0, 0, 0);  		Sprite & sprite = obj1.add_component<Sprite>( -			make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true}); +			make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{true, true});  		sprite.sorting_in_layer = 2;  		sprite.order_in_layer = 2;  	} @@ -48,7 +47,7 @@ int main() {  	{  		Color color(0, 0, 0, 0);  		Sprite & sprite = obj2.add_component<Sprite>( -			make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true}); +			make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{true, true});  		sprite.sorting_in_layer = 1;  		sprite.order_in_layer = 2;  	} @@ -56,7 +55,7 @@ int main() {  	/*  	{  		Color color(0, 0, 0, 0); -		auto img = mgr.cache<Texture>("../asset/texture/second.png"); +		auto img = mgr.cache<Texture>("asset/texture/second.png");  		obj2.add_component<Sprite>(img, color, FlipSettings{true, true});  	}  	*/ diff --git a/src/test/AssetTest.cpp b/src/test/AssetTest.cpp new file mode 100644 index 0000000..8aa7629 --- /dev/null +++ b/src/test/AssetTest.cpp @@ -0,0 +1,26 @@ +#include <gtest/gtest.h> + +#include <crepe/api/Asset.h> +#include <crepe/api/Config.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class AssetTest : public Test { +public: +	Config & cfg = Config::get_instance(); +	void SetUp() override { this->cfg.asset.root_pattern = ".crepe-root"; } +}; + +TEST_F(AssetTest, Existant) { ASSERT_NO_THROW(Asset{"asset/texture/img.png"}); } + +TEST_F(AssetTest, Nonexistant) { ASSERT_ANY_THROW(Asset{"asset/nonexistant"}); } + +TEST_F(AssetTest, Rootless) { +	cfg.asset.root_pattern.clear(); + +	string arbitrary = "\\/this is / /../passed through as-is"; +	Asset asset{arbitrary}; +	ASSERT_EQ(arbitrary, asset.get_path()); +} diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d56d80f..f189e3d 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,6 +3,9 @@ target_sources(test_main PUBLIC  	PhysicsTest.cpp  	ScriptTest.cpp  	ParticleTest.cpp +	AssetTest.cpp +	OptionalRefTest.cpp +	RenderSystemTest.cpp  	ECSTest.cpp  	SceneManagerTest.cpp  ) diff --git a/src/test/OptionalRefTest.cpp b/src/test/OptionalRefTest.cpp new file mode 100644 index 0000000..2072d56 --- /dev/null +++ b/src/test/OptionalRefTest.cpp @@ -0,0 +1,37 @@ +#include <gtest/gtest.h> + +#include <crepe/util/OptionalRef.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +TEST(OptionalRefTest, Explicit) { +	string value = "foo"; +	OptionalRef<string> ref; +	EXPECT_FALSE(ref); +	ASSERT_THROW(ref.get(), runtime_error); + +	ref.set(value); +	EXPECT_TRUE(ref); +	ASSERT_NO_THROW(ref.get()); + +	ref.clear(); +	EXPECT_FALSE(ref); +	ASSERT_THROW(ref.get(), runtime_error); +} + +TEST(OptionalRefTest, Implicit) { +	string value = "foo"; +	OptionalRef<string> ref = value; +	EXPECT_TRUE(ref); +	ASSERT_NO_THROW(ref.get()); + +	ref.clear(); +	EXPECT_FALSE(ref); +	ASSERT_THROW(ref.get(), runtime_error); + +	ref = value; +	EXPECT_TRUE(ref); +	ASSERT_NO_THROW(ref.get()); +} diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 4e655a9..cfbbc0e 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -29,7 +29,7 @@ public:  			Color color(0, 0, 0, 0);  			Sprite test_sprite = game_object.add_component<Sprite>( -				make_shared<Texture>("../asset/texture/img.png"), color, +				make_shared<Texture>("asset/texture/img.png"), color,  				FlipSettings{true, true});  			game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ |