object_test.cxx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. //
  2. // object_test.cxx
  3. // reflection-test
  4. //
  5. // Created by Sam Jaffe on 7/4/22.
  6. // Copyright © 2022 Sam Jaffe. All rights reserved.
  7. //
  8. #include "reflection/object.h"
  9. #include "xcode_gtest_helper.h"
  10. using reflection::Object;
  11. using reflection::Reflection;
  12. using testing::Eq;
  13. using testing::NotNull;
  14. namespace {
  15. struct Example {
  16. int a;
  17. int get_c() const { return a + 4; }
  18. void set_c(int c) { a = c - 4; }
  19. };
  20. struct Compound {
  21. Example ex;
  22. };
  23. }
  24. namespace reflection {
  25. INSTANTIATE_REFLECTION(Example);
  26. INSTANTIATE_REFLECTION(Compound);
  27. }
  28. REFLECTION(Example)
  29. .bind("a", &Example::a)
  30. .bind("c", &Example::get_c, &Example::set_c);
  31. REFLECTION(Compound).bind("ex", &Compound::ex);
  32. TEST(ObjectTest, CanFetchData) {
  33. Example ex{.a = 1};
  34. Object a = Object(ex).get("a");
  35. EXPECT_NO_THROW((void)int(a)) << a.type().name();
  36. EXPECT_THAT(int(a), 1);
  37. }
  38. TEST(ObjectTest, CanSetDataOnNonConst) {
  39. Example ex{.a = 1};
  40. {
  41. Object a = Object(ex).get("a");
  42. EXPECT_NO_THROW((void)static_cast<int &>(a)) << a.type().name();
  43. static_cast<int &>(a) = 2;
  44. }
  45. EXPECT_THAT(ex.a, 2);
  46. }
  47. TEST(ObjectTest, ThrowsWhenTryingToEditConst) {
  48. Example const ex{.a = 1};
  49. Object a = Object(ex).get("a");
  50. EXPECT_THROW((void)static_cast<int &>(a), std::bad_cast);
  51. }
  52. TEST(ObjectTest, ThrowsWhenTryingToEditMoved) {
  53. Object a = Object(Example{.a = 1}).get("a");
  54. EXPECT_THROW((void)static_cast<int &>(a), std::bad_cast);
  55. }
  56. TEST(ObjectTest, CanCoerceNumericTypes) {
  57. Example const ex{.a = 1};
  58. Object a = Object(ex).get("a");
  59. EXPECT_THAT(double(a), 1.0);
  60. }
  61. TEST(ObjectTest, ThrowsWhenPerformingIllegalTypeCoersion) {
  62. Example const ex{.a = 1};
  63. Object a = Object(ex).get("a");
  64. EXPECT_THROW((void)std::string(a), std::bad_cast);
  65. }
  66. TEST(ObjectTest, CanFetchWithGetter) {
  67. Example ex{.a = 1};
  68. Object c = Object(ex).get("c");
  69. EXPECT_NO_THROW((void)int(c)) << c.type().name();
  70. EXPECT_THAT(int(c), Eq(5));
  71. static_cast<int &>(c) = 4;
  72. }
  73. TEST(ObjectTest, CanModifyWithSetter) {
  74. Example ex{.a = 1};
  75. {
  76. Object c = Object(ex).get("c");
  77. EXPECT_NO_THROW((void)static_cast<int &>(c)) << c.type().name();
  78. static_cast<int &>(c) = 4;
  79. // Notice that the setter is scoped on the Object expiring
  80. EXPECT_THAT(ex.a, Eq(1));
  81. }
  82. EXPECT_THAT(ex.a, Eq(0));
  83. }
  84. TEST(ObjectTest, ThrowsWhenUsingSetterOnConst) {
  85. Example const ex{.a = 1};
  86. Object c = Object(ex).get("c");
  87. EXPECT_THROW((void)static_cast<int &>(c), std::bad_cast);
  88. }
  89. TEST(ObjectTest, CanDive) {
  90. Compound cm{.ex = {.a = 2}};
  91. Object a = Object(cm).get(std::vector{"ex", "a"});
  92. EXPECT_NO_THROW((void)int(a));
  93. EXPECT_THAT(int(a), Eq(2));
  94. }
  95. TEST(ObjectTest, AttachesNameInfo) {
  96. Compound cm{.ex = {.a = 2}};
  97. Object a = Object(cm).get(std::vector{"ex", "a"});
  98. EXPECT_THAT(a.path(), Eq("this.ex.a"));
  99. EXPECT_THAT(a.name(), Eq("a"));
  100. }
  101. TEST(ObjectTest, CanReflectVariableName) {
  102. Compound cm{.ex = {.a = 2}};
  103. Object a = reflect(cm).get(std::vector{"ex", "a"});
  104. EXPECT_THAT(a.path(), Eq("cm.ex.a"));
  105. EXPECT_THAT(a.name(), Eq("a"));
  106. }