test_common.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #pragma once
  2. #include <igl/read_triangle_mesh.h>
  3. #include <igl/find.h>
  4. #include <igl/readDMAT.h>
  5. #include <Eigen/Core>
  6. #include <gtest/gtest.h>
  7. #include <cctype>
  8. #include <string>
  9. #include <functional>
  10. #include <algorithm>
  11. #include <tuple>
  12. namespace test_common
  13. {
  14. // Input:
  15. // s arbitrary string
  16. // Returns s with all non-alphanumeric characters replaced with underscores '_'
  17. inline std::string safe_test_name(std::string s)
  18. {
  19. std::for_each(s.begin(),s.end(),[](char &c){if(!std::isalnum(c)) c='_';});
  20. return s;
  21. };
  22. inline std::string string_test_name(const ::testing::TestParamInfo<std::string>& info)
  23. {
  24. return test_common::safe_test_name(info.param);
  25. };
  26. inline std::vector<std::string> closed_genus_0_meshes()
  27. {
  28. return
  29. {
  30. "cube.obj",
  31. "decimated-knight.obj",
  32. "boolean_minus_test_cube.obj",
  33. "boolean_minus_test_green.obj",
  34. };
  35. };
  36. inline std::vector<std::string> closed_manifold_meshes()
  37. {
  38. std::vector<std::string> meshes = closed_genus_0_meshes();
  39. meshes.insert(meshes.end(),
  40. {
  41. "TinyTorus.obj",
  42. });
  43. return meshes;
  44. };
  45. inline std::vector<std::string> manifold_meshes()
  46. {
  47. std::vector<std::string> meshes = closed_manifold_meshes();
  48. meshes.insert(meshes.end(),
  49. {
  50. "bunny.off",
  51. "elephant.off",
  52. "hemisphere.obj",
  53. });
  54. return meshes;
  55. };
  56. inline std::vector<std::string> tet_meshes()
  57. {
  58. return
  59. {
  60. "decimated-knight.mesh"
  61. };
  62. };
  63. inline std::vector<std::string> all_meshes()
  64. {
  65. std::vector<std::string> meshes = manifold_meshes();
  66. meshes.insert(meshes.end(),
  67. {
  68. "truck.obj",
  69. });
  70. return meshes;
  71. };
  72. inline std::string data_path(std::string s)
  73. {
  74. return std::string(LIBIGL_DATA_DIR) + "/" + s;
  75. };
  76. // TODO: this seems like a pointless indirection. Should just find and
  77. // replace test_common::load_mesh(X,...) with
  78. // igl::read_triangle_mesh(test_common::data_path(X),...)
  79. template<typename DerivedV, typename DerivedF>
  80. void load_mesh(
  81. const std::string& filename,
  82. Eigen::PlainObjectBase<DerivedV>& V,
  83. Eigen::PlainObjectBase<DerivedF>& F)
  84. {
  85. igl::read_triangle_mesh(data_path(filename), V, F);
  86. }
  87. // TODO: this seems like a pointless indirection. Should just find and
  88. // replace test_common::load_matrix(X,...) with
  89. // igl::readDMAT(test_common::data_path(X),...)
  90. template<typename Derived>
  91. void load_matrix(
  92. const std::string& filename,
  93. Eigen::PlainObjectBase<Derived>& M)
  94. {
  95. igl::readDMAT(data_path(filename), M);
  96. }
  97. template <typename DerivedA, typename DerivedB>
  98. void assert_eq(
  99. const Eigen::MatrixBase<DerivedA> & A,
  100. const Eigen::MatrixBase<DerivedB> & B)
  101. {
  102. // Sizes should match
  103. ASSERT_EQ(A.rows(),B.rows());
  104. ASSERT_EQ(A.cols(),B.cols());
  105. for(int i = 0;i<A.rows();i++)
  106. {
  107. for(int j = 0;j<A.cols();j++)
  108. {
  109. // Create an ijv tuple to trick GoogleTest into printing (i,j) so we
  110. // know where the disagreement is.
  111. std::tuple<int,int,typename DerivedA::Scalar> Aijv {i,j,A(i,j)};
  112. std::tuple<int,int,typename DerivedB::Scalar> Bijv {i,j,B(i,j)};
  113. ASSERT_EQ(Aijv,Bijv);
  114. }
  115. }
  116. }
  117. template <typename DerivedA, typename DerivedB>
  118. void assert_eq(
  119. const Eigen::SparseMatrix<DerivedA> & A,
  120. const Eigen::SparseMatrix<DerivedB> & B)
  121. {
  122. // Sizes should match
  123. ASSERT_EQ(A.rows(),B.rows());
  124. ASSERT_EQ(A.cols(),B.cols());
  125. Eigen::Matrix<long int,Eigen::Dynamic, 1> AI,AJ;
  126. Eigen::Matrix<long int,Eigen::Dynamic, 1> BI,BJ;
  127. Eigen::Matrix<DerivedA,Eigen::Dynamic, 1> AV;
  128. Eigen::Matrix<DerivedB,Eigen::Dynamic, 1> BV;
  129. // Assumes A and B are in same Major Ordering
  130. igl::find(A,AI,AJ,AV);
  131. igl::find(B,BI,BJ,BV);
  132. // This doesn't generalized to assert_near nicely, and it makes it hard to
  133. // tell which entries are different:
  134. assert_eq(AI,BI);
  135. assert_eq(AJ,BJ);
  136. assert_eq(AV,BV);
  137. }
  138. template <typename DerivedA, typename DerivedB, typename EpsType>
  139. void assert_near(
  140. const Eigen::MatrixBase<DerivedA> & A,
  141. const Eigen::MatrixBase<DerivedB> & B,
  142. const EpsType & eps)
  143. {
  144. // Sizes should match
  145. ASSERT_EQ(A.rows(),B.rows());
  146. ASSERT_EQ(A.cols(),B.cols());
  147. for(int i = 0;i<A.rows();i++)
  148. {
  149. for(int j = 0;j<A.cols();j++)
  150. {
  151. // Create an ijv tuple to trick GoogleTest into printing (i,j) so we
  152. // know where the disagreement is.
  153. //
  154. // Equivalent to ASSERT_NEAR(Aijv,Bijv)
  155. {
  156. std::tuple<int,int,typename DerivedA::Scalar> Aijv {i,j,A(i,j)};
  157. std::tuple<int,int,typename DerivedB::Scalar> Bijv {i,j,B(i,j)+eps};
  158. ASSERT_LT(Aijv,Bijv);
  159. }
  160. {
  161. std::tuple<int,int,typename DerivedA::Scalar> Aijv {i,j,A(i,j)+eps};
  162. std::tuple<int,int,typename DerivedB::Scalar> Bijv {i,j,B(i,j)};
  163. ASSERT_GT(Aijv,Bijv);
  164. }
  165. }
  166. }
  167. }
  168. }