manager_test.cxx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // manager_test.cxx
  3. // graphics
  4. //
  5. // Created by Sam Jaffe on 6/6/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include <gmock/gmock.h>
  9. #include "../src/helper.hpp"
  10. #include "game/graphics/manager.hpp"
  11. #include "game/graphics/material.hpp"
  12. #include "game/graphics/shader.hpp"
  13. #include "game/graphics/shader_program.hpp"
  14. #include "game/graphics/texture.hpp"
  15. using testing::AllOf;
  16. using testing::AnyNumber;
  17. using testing::Eq;
  18. using testing::Ge;
  19. using testing::Le;
  20. using testing::Ne;
  21. using testing::SizeIs;
  22. using testing::_;
  23. struct mock_manager_impl : graphics::manager {
  24. using shader = graphics::shader;
  25. using shader_program = graphics::shader_program;
  26. using texture = graphics::texture;
  27. MOCK_CONST_METHOD2(compile_shader,
  28. shader(graphics::shaders::type, std::string const &));
  29. MOCK_CONST_METHOD2(compile_program,
  30. shader_program(identity<shader>, identity<shader>));
  31. shader compile(graphics::shaders::type t, std::string const & s) const {
  32. return compile_shader(t, s);
  33. }
  34. shader_program compile(identity<shader> f, identity<shader> v) const {
  35. return compile_program(f, v);
  36. }
  37. MOCK_CONST_METHOD3(compile, texture(graphics::textures::format, math::vec2i,
  38. void const *));
  39. };
  40. template <typename T> identity<T> cast(unsigned int id) {
  41. return *reinterpret_cast<identity<T> *>(&id);
  42. }
  43. auto cast_p(unsigned int id) { return cast<graphics::shader_program>(id); }
  44. auto cast_s(unsigned int id) { return cast<graphics::shader>(id); }
  45. class ManagerTest : public testing::Test {
  46. public:
  47. void SetUp() override;
  48. mock_manager_impl mock;
  49. private:
  50. struct {
  51. graphics::texture operator()(math::vec2i const & sz) { return {++i, sz}; }
  52. unsigned int i{0};
  53. } next_tex;
  54. struct {
  55. graphics::shader operator()(graphics::shaders::type tp,
  56. std::string const & path) {
  57. return {++i, tp, path};
  58. }
  59. unsigned int i{0};
  60. } next_shader;
  61. struct {
  62. graphics::shader_program operator()(identity<graphics::shader> f,
  63. identity<graphics::shader> v) {
  64. return {++i, f, v};
  65. }
  66. unsigned int i{0};
  67. } next_program;
  68. };
  69. void ManagerTest::SetUp() {
  70. using testing::Invoke;
  71. using testing::WithArg;
  72. // Start with a new set of IDs
  73. ON_CALL(mock, compile(_, _, _))
  74. .WillByDefault(WithArg<1>(Invoke(std::ref(next_tex))));
  75. ON_CALL(mock, compile_shader(_, _))
  76. .WillByDefault(Invoke(std::ref(next_shader)));
  77. ON_CALL(mock, compile_program(_, _))
  78. .WillByDefault(Invoke(std::ref(next_program)));
  79. }
  80. TEST_F(ManagerTest, DoesNotGreedilyCompile) {
  81. EXPECT_CALL(mock, compile(_, _, _)).Times(0);
  82. EXPECT_CALL(mock, compile_shader(_, _)).Times(0);
  83. EXPECT_CALL(mock, compile_program(_, _)).Times(0);
  84. }
  85. using MaterialTest = ManagerTest;
  86. // TEST_F(MaterialTest, ThrowsExceptionIfNoTexOrUniform) {
  87. // EXPECT_CALL(mock, compile(_, _, _)).Times(AnyNumber());
  88. // // TODO (sjaffe): Throw a specific exception here, since throw; kills us
  89. // EXPECT_ANY_THROW(mock.get(cast_p(1), "", ""));
  90. //}
  91. TEST_F(MaterialTest, GeneratesUniformTexturesIfNoTexFile) {
  92. using graphics::materials::uniform;
  93. EXPECT_CALL(mock, compile(_, make_vector(1, 1), _)).Times(3);
  94. EXPECT_NO_THROW(mock.get(cast_p(1), "", "u_normalMap"));
  95. }
  96. TEST_F(MaterialTest, CreatedMaterialCanBeRefetched) {
  97. // Three times and no more
  98. EXPECT_CALL(mock, compile(_, make_vector(1, 1), _)).Times(3);
  99. auto id_1 = mock.get(cast_p(1), "", "u_normalMap");
  100. auto id_2 = mock.get(cast_p(1), "", "u_normalMap");
  101. EXPECT_THAT(id_1, Eq(id_2));
  102. }
  103. TEST_F(MaterialTest, CanGetMaterialFromId) {
  104. auto material_id = mock.get(cast_p(1), "", "u_normalMap");
  105. auto material = mock.get(material_id);
  106. // Ensure that the material is the 'same one' i.e.
  107. // mock.get(mock.get(id)) == mock.get(id)
  108. EXPECT_THAT(material, Eq(material_id));
  109. }
  110. TEST_F(MaterialTest, UniformMaterialIsOneByOne) {
  111. using graphics::materials::uniform;
  112. auto material = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
  113. // Uniforms are always sized 1x1
  114. EXPECT_THAT(material.size, Eq(make_vector(1, 1)));
  115. }
  116. TEST_F(MaterialTest, UniformMaterialHasDataBindingToNormalTex) {
  117. using graphics::materials::uniform;
  118. auto material = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
  119. EXPECT_THAT(material.uniforms, SizeIs(1));
  120. // Because we never initialize any textures, we are within the first three
  121. // texture ID units.
  122. EXPECT_THAT(material.uniforms[0].texture.id, AllOf(Ge(1), Le(3)));
  123. // Test the mapping from "u_normalMap" to uniform::NORMAL
  124. EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
  125. }
  126. TEST_F(MaterialTest, DifferentProgramMakesDifferentMaterial) {
  127. using graphics::materials::uniform;
  128. EXPECT_CALL(mock, compile(_, make_vector(1, 1), _)).Times(3);
  129. auto id_1 = mock.get(cast_p(1), "", "u_normalMap");
  130. auto id_2 = mock.get(cast_p(2), "", "u_normalMap");
  131. EXPECT_THAT(id_1, Ne(id_2));
  132. }
  133. TEST_F(MaterialTest, DifferentProgramDoesntChangeUniformId) {
  134. using graphics::materials::uniform;
  135. EXPECT_CALL(mock, compile(_, make_vector(1, 1), _)).Times(3);
  136. auto mat_1 = mock.get(mock.get(cast_p(1), "", "u_normalMap"));
  137. auto mat_2 = mock.get(mock.get(cast_p(2), "", "u_normalMap"));
  138. EXPECT_THAT(mat_1.uniforms[0].texture, Eq(mat_2.uniforms[0].texture));
  139. }
  140. TEST_F(MaterialTest, TexFileSkipsUniformLoad) {
  141. using graphics::materials::uniform;
  142. EXPECT_CALL(mock, compile(_, make_vector(1, 1), _)).Times(1);
  143. auto material =
  144. mock.get(mock.get(cast_p(1), "resources/black.bmp", "u_normalMap"));
  145. EXPECT_THAT(material.uniforms, SizeIs(1));
  146. // Because we never initialize any textures, we are within the first three
  147. // texture ID units.
  148. EXPECT_THAT(material.uniforms[0].texture.id, Eq(1));
  149. // Test the mapping from "u_normalMap" to uniform::NORMAL
  150. EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
  151. }
  152. TEST_F(MaterialTest, MissingFileNoExcept) {
  153. EXPECT_NO_THROW(
  154. mock.get(mock.get(cast_p(1), "resources/missing.png", "u_normalMap")));
  155. }
  156. TEST_F(MaterialTest, MissingFileFallsBackOnUniform) {
  157. using graphics::materials::uniform;
  158. auto material =
  159. mock.get(mock.get(cast_p(1), "resources/missing.png", "u_normalMap"));
  160. EXPECT_THAT(material.uniforms, SizeIs(1));
  161. // Because we never initialize any textures, we are within the first three
  162. // texture ID units.
  163. EXPECT_THAT(material.uniforms[0].texture.id, AllOf(Ge(1), Le(3)));
  164. // Test the mapping from "u_normalMap" to uniform::NORMAL
  165. EXPECT_THAT(material.uniforms[0].uniform_id, Eq(uniform::NORMAL));
  166. }
  167. using ShaderTest = ManagerTest;
  168. TEST_F(ShaderTest, CanCreateShaders) {
  169. using graphics::shaders::type;
  170. EXPECT_CALL(mock, compile_shader(_, _)).Times(1);
  171. EXPECT_NO_THROW(mock.get(type::FRAGMENT, "A"));
  172. }
  173. TEST_F(ShaderTest, CreatedShaderCanBeRefetched) {
  174. using graphics::shaders::type;
  175. EXPECT_CALL(mock, compile_shader(_, _)).Times(1);
  176. auto id_1 = mock.get(type::FRAGMENT, "A");
  177. auto id_2 = mock.get(type::FRAGMENT, "A");
  178. EXPECT_THAT(id_1, Eq(id_2));
  179. }
  180. TEST_F(ShaderTest, DifferentTypeMakesDifferentShader) {
  181. using graphics::shaders::type;
  182. EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
  183. auto id_1 = mock.get(type::FRAGMENT, "A");
  184. auto id_2 = mock.get(type::VERTEX, "A");
  185. EXPECT_THAT(id_1, Ne(id_2));
  186. }
  187. using ShaderProgramTest = ManagerTest;
  188. TEST_F(ShaderProgramTest, CreatingProgramCreatesTwoShaders) {
  189. EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
  190. EXPECT_CALL(mock, compile_program(cast_s(1), cast_s(2))).Times(1);
  191. EXPECT_NO_THROW(mock.get("A", "B"));
  192. }
  193. TEST_F(ShaderProgramTest, CreatedProgramCanBeRefetched) {
  194. EXPECT_CALL(mock, compile_shader(_, _)).Times(2);
  195. EXPECT_CALL(mock, compile_program(cast_s(1), cast_s(2))).Times(1);
  196. auto id_1 = mock.get("A", "B");
  197. auto id_2 = mock.get("A", "B");
  198. EXPECT_THAT(id_1, Eq(id_2));
  199. }