1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/bind.h"
6 #include "base/strings/string16.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "testing/platform_test.h"
10 #include "ui/views/metadata/metadata_header_macros.h"
11 #include "ui/views/metadata/metadata_impl_macros.h"
12 #include "ui/views/metadata/metadata_types.h"
13 #include "ui/views/view.h"
14
15 namespace VM = views::metadata;
16
17 class MetadataTest : public PlatformTest {
18 public:
19 MetadataTest() = default;
20 ~MetadataTest() override = default;
21
float_property_changed() const22 bool float_property_changed() const { return float_property_changed_; }
OnFloatPropertyChanged()23 void OnFloatPropertyChanged() { float_property_changed_ = true; }
24
25 protected:
26 template <typename T>
GetMemberMetaData(T * obj,const std::string & member_name)27 VM::MemberMetaDataBase* GetMemberMetaData(T* obj,
28 const std::string& member_name) {
29 VM::ClassMetaData* meta_data = obj->GetClassMetaData();
30 if (meta_data == nullptr)
31 return nullptr;
32
33 VM::MemberMetaDataBase* member_data =
34 meta_data->FindMemberData(member_name);
35 return member_data;
36 }
37
38 private:
39 bool float_property_changed_ = false;
40 };
41
42 // Base view in which a simple hierarchy is created for testing metadata
43 // iteration across class types.
44 class MetadataTestBaseView : public views::View {
45 public:
46 MetadataTestBaseView() = default;
47 ~MetadataTestBaseView() override = default;
48
49 METADATA_HEADER(MetadataTestBaseView);
50
SetIntProperty(int new_value)51 void SetIntProperty(int new_value) {
52 if (new_value == int_property_)
53 return;
54 int_property_ = new_value;
55 OnPropertyChanged(&int_property_, views::kPropertyEffectsNone);
56 }
GetIntProperty() const57 int GetIntProperty() const { return int_property_; }
AddIntPropertyChangedCallback(views::PropertyChangedCallback callback)58 views::PropertyChangedSubscription AddIntPropertyChangedCallback(
59 views::PropertyChangedCallback callback) WARN_UNUSED_RESULT {
60 return AddPropertyChangedCallback(&int_property_, std::move(callback));
61 }
62
63 private:
64 int int_property_ = 0;
65 };
66
67 BEGIN_METADATA(MetadataTestBaseView, views::View)
68 ADD_PROPERTY_METADATA(int, IntProperty)
69 END_METADATA
70
71 // Descendent view in the simple hierarchy. The inherited properties are visible
72 // within the metadata.
73 class MetadataTestView : public MetadataTestBaseView {
74 public:
75 MetadataTestView() = default;
76 ~MetadataTestView() override = default;
77
78 METADATA_HEADER(MetadataTestView);
79
SetFloatProperty(float new_value)80 void SetFloatProperty(float new_value) {
81 if (float_property_ == new_value)
82 return;
83 float_property_ = new_value;
84 OnPropertyChanged(&float_property_, views::kPropertyEffectsNone);
85 }
GetFloatProperty() const86 float GetFloatProperty() const { return float_property_; }
AddFloatPropertyChangedCallback(views::PropertyChangedCallback callback)87 views::PropertyChangedSubscription AddFloatPropertyChangedCallback(
88 views::PropertyChangedCallback callback) WARN_UNUSED_RESULT {
89 return AddPropertyChangedCallback(&float_property_, std::move(callback));
90 }
91
92 private:
93 float float_property_ = 0.f;
94 };
95
BEGIN_METADATA(MetadataTestView,MetadataTestBaseView)96 BEGIN_METADATA(MetadataTestView, MetadataTestBaseView)
97 ADD_PROPERTY_METADATA(float, FloatProperty)
98 END_METADATA
99
100 TEST_F(MetadataTest, TestFloatMetadataPropertyAccess) {
101 const float start_value = 12.34f;
102
103 MetadataTestView test_obj;
104 test_obj.SetFloatProperty(start_value);
105
106 VM::MemberMetaDataBase* member_data =
107 GetMemberMetaData(&test_obj, "FloatProperty");
108
109 ASSERT_TRUE(member_data);
110 base::string16 member_value = member_data->GetValueAsString(&test_obj);
111 CHECK_EQ(member_value, base::NumberToString16(start_value));
112 }
113
TEST_F(MetadataTest,TestFloatPropertyChangedCallback)114 TEST_F(MetadataTest, TestFloatPropertyChangedCallback) {
115 const float start_value = 12.34f;
116
117 MetadataTestView test_obj;
118 views::PropertyChangedSubscription callback =
119 test_obj.AddFloatPropertyChangedCallback(base::BindRepeating(
120 &MetadataTest::OnFloatPropertyChanged, base::Unretained(this)));
121
122 VM::MemberMetaDataBase* member_data =
123 GetMemberMetaData(&test_obj, "FloatProperty");
124
125 ASSERT_TRUE(member_data);
126
127 member_data->SetValueAsString(&test_obj, base::NumberToString16(start_value));
128
129 CHECK(float_property_changed());
130
131 base::string16 member_value = member_data->GetValueAsString(&test_obj);
132 CHECK_EQ(member_value, base::NumberToString16(start_value));
133 }
134
TEST_F(MetadataTest,TestMetaDataParentClassTracking)135 TEST_F(MetadataTest, TestMetaDataParentClassTracking) {
136 VM::ClassMetaData* base_class_meta_data = MetadataTestBaseView::MetaData();
137 VM::ClassMetaData* derived_class_meta_data = MetadataTestView::MetaData();
138
139 CHECK_EQ(base_class_meta_data,
140 derived_class_meta_data->parent_class_meta_data());
141 }
142
TEST_F(MetadataTest,TestMetaDataFindParentClassMember)143 TEST_F(MetadataTest, TestMetaDataFindParentClassMember) {
144 VM::ClassMetaData* derived_class_meta_data = MetadataTestView::MetaData();
145
146 VM::MemberMetaDataBase* member_data =
147 derived_class_meta_data->FindMemberData("IntProperty");
148
149 CHECK_NE(member_data, nullptr);
150 }
151
TEST_F(MetadataTest,TestMetaDataMemberIterator)152 TEST_F(MetadataTest, TestMetaDataMemberIterator) {
153 VM::ClassMetaData* derived_class_meta_data = MetadataTestView::MetaData();
154
155 std::string derived_class_member_name = "IntProperty";
156 bool found_derived_class_member = false;
157
158 std::string base_class_member_name = "IntProperty";
159 bool found_base_class_member = false;
160
161 for (VM::MemberMetaDataBase* member_data : *derived_class_meta_data) {
162 if (member_data->member_name() == derived_class_member_name)
163 found_derived_class_member = true;
164
165 if (member_data->member_name() == base_class_member_name)
166 found_base_class_member = true;
167 }
168
169 CHECK(found_derived_class_member);
170 CHECK(found_base_class_member);
171 }
172
TEST_F(MetadataTest,TestTypeCacheContainsTestClass)173 TEST_F(MetadataTest, TestTypeCacheContainsTestClass) {
174 VM::MetaDataCache* cache = VM::MetaDataCache::GetInstance();
175 ASSERT_TRUE(cache != nullptr);
176
177 VM::ClassMetaData* test_class_meta = MetadataTestView::MetaData();
178
179 const auto& cache_meta = cache->GetCachedTypes();
180 CHECK(std::find(cache_meta.begin(), cache_meta.end(), test_class_meta) !=
181 cache_meta.end());
182 }
183
TEST_F(MetadataTest,TestMetaDataFile)184 TEST_F(MetadataTest, TestMetaDataFile) {
185 VM::ClassMetaData* metadata = MetadataTestBaseView::MetaData();
186
187 CHECK_EQ(metadata->file(), "ui/views/metadata/metadata_unittest.cc");
188 }
189