1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4#include <chrono>
5#define CATCH_CONFIG_MAIN
6#include "catch2/catch.hpp"
7
8#include <slint.h>
9#include <slint_image.h>
10
11SCENARIO("SharedString API")
12{
13 slint::SharedString str;
14
15 REQUIRE(str.empty());
16 REQUIRE(str == "");
17 REQUIRE(std::string_view(str.data()) == ""); // this test null termination of data()
18
19 SECTION("Construct from string_view")
20 {
21 std::string foo("Foo");
22 std::string_view foo_view(foo);
23 str = foo_view;
24 REQUIRE(str == "Foo");
25 REQUIRE(std::string_view(str.data()) == "Foo");
26 }
27
28 SECTION("Construct from char*")
29 {
30 str = "Bar";
31 REQUIRE(str == "Bar");
32 }
33
34 SECTION("concatenate")
35 {
36 str = "Hello";
37 str += " ";
38 str += slint::SharedString("🦊") + slint::SharedString("!");
39 REQUIRE(str == "Hello 🦊!");
40 REQUIRE(std::string_view(str.data()) == "Hello 🦊!");
41 }
42
43 SECTION("begin/end")
44 {
45 str = "Hello";
46 REQUIRE(str.begin() + std::string_view(str).size() == str.end());
47 }
48}
49
50TEST_CASE("Basic SharedVector API", "[vector]")
51{
52 slint::SharedVector<int> vec;
53 REQUIRE(vec.empty());
54
55 SECTION("Initializer list")
56 {
57 slint::SharedVector<int> vec({ 1, 4, 10 });
58 REQUIRE(vec.size() == 3);
59 REQUIRE(vec[0] == 1);
60 REQUIRE(vec[1] == 4);
61 REQUIRE(vec[2] == 10);
62 }
63}
64
65TEST_CASE("Property Tracker")
66{
67 using namespace slint::private_api;
68 PropertyTracker tracker1;
69 PropertyTracker tracker2;
70 Property<int> prop(42);
71
72 auto r = tracker1.evaluate([&]() { return tracker2.evaluate([&]() { return prop.get(); }); });
73 REQUIRE(r == 42);
74
75 prop.set(1);
76 REQUIRE(tracker2.is_dirty());
77 REQUIRE(tracker1.is_dirty());
78
79 r = tracker1.evaluate(
80 [&]() { return tracker2.evaluate_as_dependency_root([&]() { return prop.get(); }); });
81 REQUIRE(r == 1);
82 prop.set(100);
83 REQUIRE(tracker2.is_dirty());
84 REQUIRE(!tracker1.is_dirty());
85}
86
87TEST_CASE("Model row changes")
88{
89 using namespace slint::private_api;
90
91 auto model = std::make_shared<slint::VectorModel<int>>();
92
93 PropertyTracker tracker;
94
95 REQUIRE(tracker.evaluate([&]() {
96 model->track_row_count_changes();
97 return model->row_count();
98 }) == 0);
99 REQUIRE(!tracker.is_dirty());
100 model->push_back(1);
101 model->push_back(2);
102 REQUIRE(tracker.is_dirty());
103 REQUIRE(tracker.evaluate([&]() {
104 model->track_row_count_changes();
105 return model->row_count();
106 }) == 2);
107 REQUIRE(!tracker.is_dirty());
108 model->erase(0);
109 REQUIRE(tracker.is_dirty());
110 REQUIRE(tracker.evaluate([&]() {
111 model->track_row_count_changes();
112 return model->row_count();
113 }) == 1);
114}
115
116TEST_CASE("Track model row data changes")
117{
118 using namespace slint::private_api;
119
120 auto model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 0, 1, 2, 3, 4 });
121
122 PropertyTracker tracker;
123
124 REQUIRE(tracker.evaluate([&]() {
125 model->track_row_data_changes(1);
126 return model->row_data(1);
127 }) == 1);
128 REQUIRE(!tracker.is_dirty());
129
130 model->set_row_data(2, 42);
131 REQUIRE(!tracker.is_dirty());
132 model->set_row_data(1, 100);
133 REQUIRE(tracker.is_dirty());
134
135 REQUIRE(tracker.evaluate([&]() {
136 model->track_row_data_changes(1);
137 return model->row_data(1);
138 }) == 100);
139 REQUIRE(!tracker.is_dirty());
140
141 // Any changes to rows (even if after tracked rows) for now also marks watched rows as dirty, to
142 // keep the logic simple.
143 model->push_back(200);
144 REQUIRE(tracker.is_dirty());
145
146 REQUIRE(tracker.evaluate([&]() {
147 model->track_row_data_changes(1);
148 return model->row_data(1);
149 }) == 100);
150 REQUIRE(!tracker.is_dirty());
151
152 model->insert(0, 255);
153 REQUIRE(tracker.is_dirty());
154}
155
156TEST_CASE("Image")
157{
158 using namespace slint;
159
160 Image img;
161 {
162 auto size = img.size();
163 REQUIRE(size.width == 0.);
164 REQUIRE(size.height == 0.);
165 }
166 {
167 REQUIRE(!img.path().has_value());
168 }
169
170#ifndef SLINT_FEATURE_FREESTANDING
171 img = Image::load_from_path(SOURCE_DIR "/../../../logo/slint-logo-square-light-128x128.png");
172 {
173 auto size = img.size();
174 REQUIRE(size.width == 128.);
175 REQUIRE(size.height == 128.);
176 }
177 {
178 auto actual_path = img.path();
179 REQUIRE(actual_path.has_value());
180 REQUIRE(*actual_path == SOURCE_DIR "/../../../logo/slint-logo-square-light-128x128.png");
181 }
182#endif
183
184 img = Image(SharedPixelBuffer<Rgba8Pixel> {});
185 {
186 auto size = img.size();
187 REQUIRE(size.width == 0);
188 REQUIRE(size.height == 0);
189 REQUIRE(!img.path().has_value());
190 }
191 auto red = Rgb8Pixel { 0xff, 0, 0 };
192 auto blu = Rgb8Pixel { 0, 0, 0xff };
193 Rgb8Pixel some_data[] = { red, red, blu, red, blu, blu };
194 img = Image(SharedPixelBuffer<Rgb8Pixel>(3, 2, some_data));
195 {
196 auto size = img.size();
197 REQUIRE(size.width == 3);
198 REQUIRE(size.height == 2);
199 REQUIRE(!img.path().has_value());
200 }
201}
202
203TEST_CASE("SharedVector")
204{
205 using namespace slint;
206
207 SharedVector<SharedString> vec;
208 vec.clear();
209 vec.push_back("Hello");
210 vec.push_back("World");
211 vec.push_back("of");
212 vec.push_back("Vectors");
213
214 auto copy = vec;
215
216 REQUIRE(vec.size() == 4);
217 auto orig_cap = vec.capacity();
218 REQUIRE(orig_cap >= vec.size());
219
220 vec.clear();
221 REQUIRE(vec.size() == 0);
222 REQUIRE(vec.capacity() == 0); // vec was shared, so start with new empty vector.
223 vec.push_back("Welcome back");
224 REQUIRE(vec.size() == 1);
225 REQUIRE(vec.capacity() >= vec.size());
226
227 REQUIRE(copy.size() == 4);
228 REQUIRE(copy.capacity() == orig_cap);
229
230 SharedVector<SharedString> vec2 { "Hello", "World", "of", "Vectors" };
231 REQUIRE(copy == vec2);
232 REQUIRE(copy != vec);
233
234 copy.clear(); // copy is not shared (anymore), retain capacity.
235 REQUIRE(copy.capacity() == orig_cap);
236
237 SharedVector<SharedString> vec3(2, "Welcome back");
238 REQUIRE(vec3.size() == 2);
239 REQUIRE(vec3[1] == "Welcome back");
240 REQUIRE(vec3 != vec);
241
242 vec.push_back("Welcome back");
243 REQUIRE(vec3 == vec);
244
245 SharedVector<int> vec4(5);
246 REQUIRE(vec4.size() == 5);
247 REQUIRE(vec4[3] == 0);
248
249 std::vector<SharedString> std_v(vec2.begin(), vec2.end());
250 SharedVector<SharedString> vec6(std_v.begin(), std_v.end());
251 REQUIRE(vec6 == vec2);
252}
253

source code of slint/api/cpp/tests/datastructures.cpp