xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/common/inspectable_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h"
16 
17 #include <gmock/gmock.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/testing/inspect.h"
20 #include "pw_unit_test/framework.h"
21 
22 #ifndef NINSPECT
23 
24 namespace bt {
25 
26 namespace {
27 
28 using namespace inspect::testing;
29 
30 template <typename T>
31 class TestProperty {
32  public:
33   using ValueCallback = fit::function<void(const T& value)>;
34   TestProperty() = default;
TestProperty(T value,ValueCallback cb)35   TestProperty(T value, ValueCallback cb)
36       : value_(value), value_cb_(std::move(cb)) {}
37 
Set(const T & value)38   void Set(const T& value) {
39     value_ = value;
40     if (value_cb_) {
41       value_cb_(value_);
42     }
43   }
44 
45  private:
46   T value_;
47   fit::function<void(const T& value)> value_cb_;
48 };
49 
50 struct TestValue {
TestValuebt::__anon1dbb00630111::TestValue51   explicit TestValue(int val) : value(val) {}
set_valuebt::__anon1dbb00630111::TestValue52   void set_value(int val) { value = val; }
53   int value;
54 };
55 
56 struct StringValue {
ToStringbt::__anon1dbb00630111::StringValue57   std::string ToString() const { return value; }
58   std::string value;
59 };
60 
61 }  // namespace
62 
63 using TestInspectable = Inspectable<int, TestProperty<int>, int>;
64 
TEST(InspectableTest,SetPropertyChangesProperty)65 TEST(InspectableTest, SetPropertyChangesProperty) {
66   std::optional<int> prop_value_0;
67   auto prop_cb_0 = [&](auto value) { prop_value_0 = value; };
68 
69   TestInspectable inspectable(0, TestProperty<int>(1, prop_cb_0));
70   EXPECT_EQ(0, *inspectable);
71   ASSERT_TRUE(prop_value_0.has_value());
72   EXPECT_EQ(0, prop_value_0.value());
73 
74   std::optional<int> prop_value_1;
75   auto prop_cb_1 = [&](auto value) { prop_value_1 = value; };
76   inspectable.SetProperty(TestProperty<int>(1, prop_cb_1));
77   ASSERT_TRUE(prop_value_1.has_value());
78   // New property should be updated with current value.
79   EXPECT_EQ(0, prop_value_1.value());
80 
81   inspectable.Set(2);
82   // Old property should not be updated.
83   ASSERT_TRUE(prop_value_0.has_value());
84   EXPECT_EQ(0, prop_value_0.value());
85   // New property should be updated.
86   ASSERT_TRUE(prop_value_1.has_value());
87   EXPECT_EQ(2, prop_value_1.value());
88 }
89 
TEST(InspectableTest,ConstructionWithValueOnly)90 TEST(InspectableTest, ConstructionWithValueOnly) {
91   TestInspectable inspectable(2);
92   EXPECT_EQ(2, *inspectable);
93 
94   // Updating property should be a no-op, but value should still be updated.
95   inspectable.Set(1);
96   EXPECT_EQ(1, *inspectable);
97 }
98 
TEST(InspectableTest,PropertyValueUpdatedOnConstruction)99 TEST(InspectableTest, PropertyValueUpdatedOnConstruction) {
100   std::optional<int> prop_value;
101   auto prop_cb = [&](auto value) { prop_value = value; };
102 
103   TestInspectable inspectable(0, TestProperty<int>(1, std::move(prop_cb)));
104   EXPECT_EQ(0, *inspectable);
105   ASSERT_TRUE(prop_value.has_value());
106   // Property value should not still be 1.
107   EXPECT_EQ(0, prop_value.value());
108 }
109 
TEST(InspectableTest,Set)110 TEST(InspectableTest, Set) {
111   std::optional<int> prop_value;
112   auto prop_cb = [&](auto value) { prop_value = value; };
113 
114   TestInspectable inspectable(0, TestProperty<int>(0, std::move(prop_cb)));
115   inspectable.Set(1);
116   EXPECT_EQ(1, *inspectable);
117   ASSERT_TRUE(prop_value.has_value());
118   EXPECT_EQ(1, prop_value.value());
119 }
120 
TEST(InspectableTest,UpdateValueThroughMutable)121 TEST(InspectableTest, UpdateValueThroughMutable) {
122   std::optional<int> prop_value;
123   auto prop_cb = [&](auto value) { prop_value = value; };
124 
125   Inspectable<TestValue, TestProperty<int>, int> inspectable(
126       TestValue(0),
127       TestProperty<int>(0, std::move(prop_cb)),
128       [](const TestValue& v) { return v.value; });
129   inspectable.Mutable()->set_value(1);
130   EXPECT_EQ(1, inspectable->value);
131   ASSERT_TRUE(prop_value.has_value());
132   EXPECT_EQ(1, prop_value.value());
133 }
134 
TEST(InspectableTest,MakeToStringInspectConvertFunction)135 TEST(InspectableTest, MakeToStringInspectConvertFunction) {
136   const auto kPropertyName = "test_property";
137   inspect::Inspector inspector;
138   auto& root = inspector.GetRoot();
139 
140   StringInspectable inspectable(StringValue{""},
141                                 root.CreateString(kPropertyName, ""),
142                                 MakeToStringInspectConvertFunction());
143 
144   const std::string kExpectedValue = "fuchsia";
145   inspectable.Mutable()->value = kExpectedValue;
146   EXPECT_EQ(kExpectedValue, inspectable->value);
147 
148   auto hierarchy = inspect::ReadFromVmo(inspector.DuplicateVmo());
149   ASSERT_TRUE(hierarchy.is_ok());
150   EXPECT_THAT(hierarchy.take_value(),
151               AllOf(NodeMatches(PropertyList(
152                   ElementsAre(StringIs(kPropertyName, kExpectedValue))))));
153 }
154 
TEST(InspectableTest,MakeContainerOfToStringConvertFunction)155 TEST(InspectableTest, MakeContainerOfToStringConvertFunction) {
156   const auto kPropertyName = "test_property";
157   inspect::Inspector inspector;
158   auto& root = inspector.GetRoot();
159 
160   std::array values = {
161       StringValue{"fuchsia"}, StringValue{"purple"}, StringValue{"magenta"}};
162   StringInspectable inspectable(
163       std::move(values),
164       root.CreateString(kPropertyName, ""),
165       MakeContainerOfToStringConvertFunction(
166           {.prologue = "��", .delimiter = "��", .epilogue = "��"}));
167 
168   auto hierarchy = inspect::ReadFromVmo(inspector.DuplicateVmo());
169   ASSERT_TRUE(hierarchy.is_ok());
170   EXPECT_THAT(hierarchy.take_value(),
171               AllOf(NodeMatches(PropertyList(ElementsAre(
172                   StringIs(kPropertyName, "��fuchsia��purple��magenta��"))))));
173 }
174 
TEST(InspectableTest,InspectRealStringProperty)175 TEST(InspectableTest, InspectRealStringProperty) {
176   const auto kPropertyName = "test_property";
177 
178   inspect::Inspector inspector;
179   auto& root = inspector.GetRoot();
180   StringInspectable inspectable(std::string("A"));
181   inspectable.AttachInspect(root, kPropertyName);
182 
183   auto hierarchy = inspect::ReadFromVmo(inspector.DuplicateVmo());
184   ASSERT_TRUE(hierarchy.is_ok());
185   EXPECT_THAT(hierarchy.take_value(),
186               AllOf(NodeMatches(
187                   PropertyList(ElementsAre(StringIs(kPropertyName, "A"))))));
188 
189   inspectable.Set("B");
190 
191   hierarchy = inspect::ReadFromVmo(inspector.DuplicateVmo());
192   ASSERT_TRUE(hierarchy.is_ok());
193   EXPECT_THAT(hierarchy.take_value(),
194               AllOf(NodeMatches(
195                   PropertyList(ElementsAre(StringIs(kPropertyName, "B"))))));
196 }
197 
198 }  // namespace bt
199 
200 #endif  // NINSPECT
201