object_test.cxx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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, ThrowsWhenPerformingTypeCoersion) {
  57. Example const ex{.a = 1};
  58. Object a = Object(ex).get("a");
  59. EXPECT_THROW((void)double(a), std::bad_cast);
  60. }
  61. TEST(ObjectTest, CanFetchWithGetter) {
  62. Example ex{.a = 1};
  63. Object c = Object(ex).get("c");
  64. EXPECT_NO_THROW((void)int(c)) << c.type().name();
  65. EXPECT_THAT(int(c), Eq(5));
  66. static_cast<int &>(c) = 4;
  67. }
  68. TEST(ObjectTest, CanModifyWithSetter) {
  69. Example ex{.a = 1};
  70. {
  71. Object c = Object(ex).get("c");
  72. EXPECT_NO_THROW((void)static_cast<int &>(c)) << c.type().name();
  73. static_cast<int &>(c) = 4;
  74. // Notice that the setter is scoped on the Object expiring
  75. EXPECT_THAT(ex.a, Eq(1));
  76. }
  77. EXPECT_THAT(ex.a, Eq(0));
  78. }
  79. TEST(ObjectTest, ThrowsWhenUsingSetterOnConst) {
  80. Example const ex{.a = 1};
  81. Object c = Object(ex).get("c");
  82. EXPECT_THROW((void)static_cast<int &>(c), std::bad_cast);
  83. }
  84. TEST(ObjectTest, CanDive) {
  85. Compound cm{.ex = {.a = 2}};
  86. Object a = Object(cm).get(std::vector{"ex", "a"});
  87. EXPECT_NO_THROW((void)int(a));
  88. EXPECT_THAT(int(a), Eq(2));
  89. }
  90. TEST(ObjectTest, AttachesNameInfo) {
  91. Compound cm{.ex = {.a = 2}};
  92. Object a = Object(cm).get(std::vector{"ex", "a"});
  93. EXPECT_THAT(a.path(), Eq("this.ex.a"));
  94. EXPECT_THAT(a.name(), Eq("a"));
  95. }
  96. TEST(ObjectTest, CanReflectVariableName) {
  97. Compound cm{.ex = {.a = 2}};
  98. Object a = reflect(cm).get(std::vector{"ex", "a"});
  99. EXPECT_THAT(a.path(), Eq("cm.ex.a"));
  100. EXPECT_THAT(a.name(), Eq("a"));
  101. }