| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- //
- // manager_test.cxx
- // graphics
- //
- // Created by Sam Jaffe on 6/6/19.
- // Copyright © 2019 Sam Jaffe. All rights reserved.
- //
- #include "game/graphics/manager.hpp"
- #include <testing/xcode_gtest_helper.h>
- #include "../src/helper.hpp"
- #include "game/graphics/exception.h"
- #include "game/graphics/material.hpp"
- #include "game/graphics/shader.hpp"
- #include "game/graphics/shader_program.hpp"
- #include "game/graphics/texture.hpp"
- #ifdef __APPLE__
- namespace env::osx {
- extern void bundle(std::string const &);
- }
- #endif
- using testing::_;
- using testing::AllOf;
- using testing::AnyNumber;
- using testing::Eq;
- using testing::Ge;
- using testing::Le;
- using testing::Ne;
- using testing::SizeIs;
- struct mock_manager_impl : graphics::manager {
- using shader = graphics::shader;
- using shader_program = graphics::shader_program;
- using texture = graphics::texture;
- MOCK_CONST_METHOD2(compile_shader,
- shader(graphics::shaders::type, std::string const &));
- MOCK_CONST_METHOD2(compile_program,
- shader_program(identity<shader>, identity<shader>));
- shader compile(graphics::shaders::type t, std::string const & s) const {
- return compile_shader(t, s);
- }
- shader_program compile(identity<shader> f, identity<shader> v) const {
- return compile_program(f, v);
- }
- MOCK_CONST_METHOD3(compile, texture(graphics::textures::format, math::vec2i,
- void const *));
- };
- template <typename T> identity<T> cast(unsigned int id) {
- return *reinterpret_cast<identity<T> *>(&id);
- }
- auto cast_p(unsigned int id) { return cast<graphics::shader_program>(id); }
- auto cast_s(unsigned int id) { return cast<graphics::shader>(id); }
- class ManagerTest : public testing::Test {
- public:
- void SetUp() override;
- mock_manager_impl mock;
- private:
- struct {
- graphics::texture operator()(math::vec2i const & sz) { return {++i, sz}; }
- unsigned int i{0};
- } next_tex;
- struct {
- graphics::shader operator()(graphics::shaders::type tp,
- std::string const & path) {
- return {++i, tp, path};
- }
- unsigned int i{0};
- } next_shader;
- struct {
- graphics::shader_program operator()(identity<graphics::shader> f,
- identity<graphics::shader> v) {
- return {++i, f, v};
- }
- unsigned int i{0};
- } next_program;
- };
- void ManagerTest::SetUp() {
- #ifdef __APPLE__
- env::osx::bundle("leumasjaffe.graphics-test");
- #endif
- using testing::Invoke;
- using testing::WithArg;
- // Start with a new set of IDs
- ON_CALL(mock, compile(_, _, _))
- .WillByDefault(WithArg<1>(Invoke(std::ref(next_tex))));
- ON_CALL(mock, compile_shader(_, _))
- .WillByDefault(Invoke(std::ref(next_shader)));
- ON_CALL(mock, compile_program(_, _))
- .WillByDefault(Invoke(std::ref(next_program)));
- }
- TEST_F(ManagerTest, DoesNotGreedilyCompile) {
- EXPECT_CALL(mock, compile(_, _, _)).Times(0);
- EXPECT_CALL(mock, compile_shader(_, _)).Times(0);
- EXPECT_CALL(mock, compile_program(_, _)).Times(0);
- }
- using TextureTest = ManagerTest;
- TEST_F(TextureTest, ThrowsOnNonExistantFile) {
- EXPECT_THROW(mock.get("resources/missing.png"), std::runtime_error);
- }
- TEST_F(TextureTest, NoExceptIfFileExists) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(1);
- EXPECT_NO_THROW(mock.get("resources/black.bmp"));
- }
- TEST_F(TextureTest, CreatedTextureCanBeRefetched) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(1);
- auto id_1 = mock.get("resources/black.bmp");
- auto id_2 = mock.get("resources/black.bmp");
- EXPECT_THAT(id_1, Eq(id_2));
- }
- TEST_F(TextureTest, CanGetTextureFromId) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(1);
- auto texture_id = mock.get("resources/black.bmp");
- auto texture = mock.get(texture_id);
- EXPECT_THAT(texture, Eq(texture_id));
- }
- TEST_F(TextureTest, SizeOfTexturePassedIntoCompile) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(0);
- EXPECT_CALL(mock, compile(_, math::vec2i(2, 2), _)).Times(1);
- mock.get("resources/black2.bmp");
- }
- TEST_F(TextureTest, CanReadRGBFormat) {
- using graphics::textures::format;
- EXPECT_CALL(mock, compile(format::RGB, math::vec2i(1, 1), _)).Times(1);
- mock.get("resources/black_rgb.png");
- }
- TEST_F(TextureTest, CanReadRGBAFormat) {
- using graphics::textures::format;
- EXPECT_CALL(mock, compile(format::RGBA, math::vec2i(1, 1), _)).Times(1);
- mock.get("resources/black_rgba.png");
- }
- using MaterialTest = ManagerTest;
- TEST_F(MaterialTest, ThrowsExceptionIfNoTexOrUniform) {
- EXPECT_CALL(mock, compile(_, _, _)).Times(AnyNumber());
- EXPECT_THROW(mock.get(cast_p(1), "", ""),
- graphics::unmapped_enum<graphics::materials::uniform>);
- }
- TEST_F(MaterialTest, GeneratesUniformTexturesIfNoTexFile) {
- using graphics::materials::uniform;
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(3);
- EXPECT_NO_THROW(mock.get(cast_p(1), "", "u_normalMap"));
- }
- TEST_F(MaterialTest, CreatedMaterialCanBeRefetched) {
- // Three times and no more
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(3);
- auto id_1 = mock.get(cast_p(1), "", "u_normalMap");
- auto id_2 = mock.get(cast_p(1), "", "u_normalMap");
- EXPECT_THAT(id_1, Eq(id_2));
- }
- TEST_F(MaterialTest, CanGetMaterialFromId) {
- auto material_id = mock.get(cast_p(1), "", "u_normalMap");
- auto material = mock.get(material_id);
- // Ensure that the material is the 'same one' i.e.
- // mock.get(mock.get(id)) == mock.get(id)
- EXPECT_THAT(material, Eq(material_id));
- }
- TEST_F(MaterialTest, UniformMaterialIsOneByOne) {
- auto material = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
- // Uniforms are always sized 1x1
- EXPECT_THAT(material.size, Eq(math::vec2i(1, 1)));
- }
- TEST_F(MaterialTest, SizeCapturesTextureSize) {
- auto material =
- mock.get(mock.get(cast_p(1), "resources/black2.bmp", "u_normalMap"));
- EXPECT_THAT(material.size, Eq(math::vec2i(2, 2)));
- }
- TEST_F(MaterialTest, UniformMaterialHasDataBindingToNormalTex) {
- using graphics::materials::uniform;
- auto material = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
- EXPECT_THAT(material.uniforms, SizeIs(1));
- // Because we never initialize any textures, we are within the first three
- // texture ID units.
- EXPECT_THAT(material.uniforms[0].texture.id, AllOf(Ge(1), Le(3)));
- // Test the mapping from "u_normalMap" to uniform::NORMAL
- EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
- }
- TEST_F(MaterialTest, DifferentProgramMakesDifferentMaterial) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(3);
- auto id_1 = mock.get(cast_p(1), "", "u_normalMap");
- auto id_2 = mock.get(cast_p(2), "", "u_normalMap");
- EXPECT_THAT(id_1, Ne(id_2));
- }
- TEST_F(MaterialTest, DifferentProgramDoesntChangeUniformId) {
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(3);
- auto mat_1 = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
- auto mat_2 = mock.get(mock.get(cast_p(2), "", "u_normalMap"));
- EXPECT_THAT(mat_1.uniforms[0].texture, Eq(mat_2.uniforms[0].texture));
- }
- TEST_F(MaterialTest, TexFileSkipsUniformLoad) {
- using graphics::materials::uniform;
- EXPECT_CALL(mock, compile(_, math::vec2i(1, 1), _)).Times(1);
- auto material =
- mock.get(mock.get(cast_p(1), "resources/black.bmp", "u_normalMap"));
- EXPECT_THAT(material.uniforms, SizeIs(1));
- // Because we never initialize any textures, we are within the first three
- // texture ID units.
- EXPECT_THAT(material.uniforms[0].texture.id, Eq(1));
- // Test the mapping from "u_normalMap" to uniform::NORMAL
- EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
- }
- TEST_F(MaterialTest, MissingFileNoExcept) {
- EXPECT_NO_THROW(
- mock.get(mock.get(cast_p(1), "resources/missing.png", "u_normalMap")));
- }
- TEST_F(MaterialTest, MissingFileFallsBackOnUniform) {
- using graphics::materials::uniform;
- auto material =
- mock.get(mock.get(cast_p(1), "resources/missing.png", "u_normalMap"));
- EXPECT_THAT(material.uniforms, SizeIs(1));
- // Because we never initialize any textures, we are within the first three
- // texture ID units.
- EXPECT_THAT(material.uniforms[0].texture.id, AllOf(Ge(1), Le(3)));
- // Test the mapping from "u_normalMap" to uniform::NORMAL
- EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
- }
- using ShaderTest = ManagerTest;
- TEST_F(ShaderTest, CanCreateShaders) {
- using graphics::shaders::type;
- EXPECT_CALL(mock, compile_shader(_, _)).Times(1);
- EXPECT_NO_THROW(mock.get(type::FRAGMENT, "A"));
- }
- TEST_F(ShaderTest, CreatedShaderCanBeRefetched) {
- using graphics::shaders::type;
- EXPECT_CALL(mock, compile_shader(_, _)).Times(1);
- auto id_1 = mock.get(type::FRAGMENT, "A");
- auto id_2 = mock.get(type::FRAGMENT, "A");
- EXPECT_THAT(id_1, Eq(id_2));
- }
- TEST_F(ShaderTest, DifferentTypeMakesDifferentShader) {
- using graphics::shaders::type;
- EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
- auto id_1 = mock.get(type::FRAGMENT, "A");
- auto id_2 = mock.get(type::VERTEX, "A");
- EXPECT_THAT(id_1, Ne(id_2));
- }
- using ShaderProgramTest = ManagerTest;
- TEST_F(ShaderProgramTest, CreatingProgramCreatesTwoShaders) {
- EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
- EXPECT_CALL(mock, compile_program(cast_s(1), cast_s(2))).Times(1);
- EXPECT_NO_THROW(mock.get("A", "B"));
- }
- TEST_F(ShaderProgramTest, CreatedProgramCanBeRefetched) {
- EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
- EXPECT_CALL(mock, compile_program(cast_s(1), cast_s(2))).Times(1);
- auto id_1 = mock.get("A", "B");
- auto id_2 = mock.get("A", "B");
- EXPECT_THAT(id_1, Eq(id_2));
- }
|