Blender V4.3
asset_catalog_path_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "BLI_set.hh"
8#include "BLI_vector.hh"
9
10#include <set>
11#include <sstream>
12
13#include "testing/testing.h"
14
16
17TEST(AssetCatalogPathTest, construction)
18{
19 AssetCatalogPath default_constructed;
20 /* Use `.str()` to use `std:string`'s comparison operators here, not our own (which are tested
21 * later). */
22 EXPECT_EQ(default_constructed.str(), "");
23
24 /* C++ considers this construction special, it doesn't call the default constructor but does
25 * recursive, member-wise value initialization. See https://stackoverflow.com/a/4982720. */
26 AssetCatalogPath value_initialized = AssetCatalogPath();
27 EXPECT_EQ(value_initialized.str(), "");
28
29 AssetCatalogPath from_char_literal("the/path");
30
31 const std::string str_const = "the/path";
32 AssetCatalogPath from_string_constant(str_const);
33
34 std::string str_variable = "the/path";
35 AssetCatalogPath from_string_variable(str_variable);
36
37 std::string long_string = "this is a long/string/with/a/path in the middle";
38 StringRef long_string_ref(long_string);
39 StringRef middle_bit = long_string_ref.substr(10, 23);
40 AssetCatalogPath from_string_ref(middle_bit);
41 EXPECT_EQ(from_string_ref, "long/string/with/a/path");
42}
43
44TEST(AssetCatalogPathTest, length)
45{
46 const AssetCatalogPath one("1");
47 EXPECT_EQ(1, one.length());
48
49 const AssetCatalogPath empty("");
50 EXPECT_EQ(0, empty.length());
51
52 const AssetCatalogPath utf8("some/родитель");
53 EXPECT_EQ(21, utf8.length()) << "13 characters should be 21 bytes.";
54}
55
56TEST(AssetCatalogPathTest, name)
57{
59 EXPECT_EQ(StringRefNull("word"), AssetCatalogPath("word").name());
60 EXPECT_EQ(StringRefNull("Пермь"), AssetCatalogPath("дорога/в/Пермь").name());
61 EXPECT_EQ(StringRefNull("windows\\paths"),
62 AssetCatalogPath("these/are/not/windows\\paths").name());
63}
64
65TEST(AssetCatalogPathTest, comparison_operators)
66{
67 const AssetCatalogPath empty("");
68 const AssetCatalogPath the_path("the/path");
69 const AssetCatalogPath the_path_child("the/path/child");
70 const AssetCatalogPath unrelated_path("unrelated/path");
71 const AssetCatalogPath other_instance_same_path("the/path");
72
73 EXPECT_LT(empty, the_path);
74 EXPECT_LT(the_path, the_path_child);
75 EXPECT_LT(the_path, unrelated_path);
76
77 EXPECT_EQ(empty, empty) << "Identical empty instances should compare equal.";
78 EXPECT_EQ(empty, "") << "Comparison to empty string should be possible.";
79 EXPECT_EQ(the_path, the_path) << "Identical non-empty instances should compare equal.";
80 EXPECT_EQ(the_path, "the/path") << "Comparison to string should be possible.";
81 EXPECT_EQ(the_path, other_instance_same_path)
82 << "Different instances with equal path should compare equal.";
83
84 EXPECT_NE(the_path, the_path_child);
85 EXPECT_NE(the_path, unrelated_path);
86 EXPECT_NE(the_path, empty);
87
88 EXPECT_FALSE(empty);
89 EXPECT_TRUE(the_path);
90}
91
92TEST(AssetCatalogPathTest, move_semantics)
93{
94 AssetCatalogPath source_path("source/path");
95 EXPECT_TRUE(source_path);
96
97 AssetCatalogPath dest_path = std::move(source_path);
98 EXPECT_FALSE(source_path); /* NOLINT: bugprone-use-after-move */
99 EXPECT_TRUE(dest_path);
100}
101
102TEST(AssetCatalogPathTest, concatenation)
103{
104 AssetCatalogPath some_parent("some/родитель");
105 AssetCatalogPath child = some_parent / "ребенок";
106
107 EXPECT_EQ(some_parent, "some/родитель")
108 << "Appending a child path should not modify the parent.";
109 EXPECT_EQ(child, "some/родитель/ребенок");
110
111 AssetCatalogPath appended_compound_path = some_parent / "ребенок/внук";
112 EXPECT_EQ(appended_compound_path, "some/родитель/ребенок/внук");
113
114 AssetCatalogPath empty("");
115 AssetCatalogPath child_of_the_void = empty / "child";
116 EXPECT_EQ(child_of_the_void, "child")
117 << "Appending to an empty path should not create an initial slash.";
118
119 AssetCatalogPath parent_of_the_void = some_parent / empty;
120 EXPECT_EQ(parent_of_the_void, "some/родитель")
121 << "Prepending to an empty path should not create a trailing slash.";
122
123 std::string subpath = "child";
124 AssetCatalogPath concatenated_with_string = some_parent / subpath;
125 EXPECT_EQ(concatenated_with_string, "some/родитель/child");
126}
127
128TEST(AssetCatalogPathTest, hashable)
129{
130 AssetCatalogPath path("heyyyyy");
131
132 std::set<AssetCatalogPath> path_std_set;
133 path_std_set.insert(path);
134
135 blender::Set<AssetCatalogPath> path_blender_set;
136 path_blender_set.add(path);
137}
138
139TEST(AssetCatalogPathTest, stream_operator)
140{
141 AssetCatalogPath path("путь/в/Пермь");
142 std::stringstream sstream;
143 sstream << path;
144 EXPECT_EQ("путь/в/Пермь", sstream.str());
145}
146
147TEST(AssetCatalogPathTest, is_contained_in)
148{
149 const AssetCatalogPath catpath("simple/path/child");
150 EXPECT_FALSE(catpath.is_contained_in("unrelated"));
151 EXPECT_FALSE(catpath.is_contained_in("sim"));
152 EXPECT_FALSE(catpath.is_contained_in("simple/pathx"));
153 EXPECT_FALSE(catpath.is_contained_in("simple/path/c"));
154 EXPECT_FALSE(catpath.is_contained_in("simple/path/child/grandchild"));
155 EXPECT_FALSE(catpath.is_contained_in("simple/path/"))
156 << "Non-normalized paths are not expected to work.";
157
158 EXPECT_TRUE(catpath.is_contained_in(""));
159 EXPECT_TRUE(catpath.is_contained_in("simple"));
160 EXPECT_TRUE(catpath.is_contained_in("simple/path"));
161
162 /* Test with some UTF8 non-ASCII characters. */
163 AssetCatalogPath some_parent("some/родитель");
164 AssetCatalogPath child = some_parent / "ребенок";
165
166 EXPECT_TRUE(child.is_contained_in(some_parent));
167 EXPECT_TRUE(child.is_contained_in("some"));
168
169 AssetCatalogPath appended_compound_path = some_parent / "ребенок/внук";
170 EXPECT_TRUE(appended_compound_path.is_contained_in(some_parent));
171 EXPECT_TRUE(appended_compound_path.is_contained_in(child));
172
173 /* Test "going up" directory-style. */
174 AssetCatalogPath child_with_dotdot = some_parent / "../../other/hierarchy/part";
175 EXPECT_TRUE(child_with_dotdot.is_contained_in(some_parent))
176 << "dotdot path components should have no meaning";
177}
178
179TEST(AssetCatalogPathTest, cleanup)
180{
181 {
182 AssetCatalogPath ugly_path("/ some / родитель / ");
183 AssetCatalogPath clean_path = ugly_path.cleanup();
184 EXPECT_EQ(AssetCatalogPath("/ some / родитель / "), ugly_path)
185 << "cleanup should not modify the path instance itself";
186 EXPECT_EQ(AssetCatalogPath("some/родитель"), clean_path);
187 }
188 {
189 AssetCatalogPath double_slashed("some//родитель");
190 EXPECT_EQ(AssetCatalogPath("some/родитель"), double_slashed.cleanup());
191 }
192 {
193 AssetCatalogPath with_colons("some/key:subkey=value/path");
194 EXPECT_EQ(AssetCatalogPath("some/key-subkey=value/path"), with_colons.cleanup());
195 }
196 {
197 const AssetCatalogPath with_backslashes("windows\\for\\life");
198 EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_backslashes.cleanup());
199 }
200 {
201 const AssetCatalogPath with_mixed("windows\\for/life");
202 EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_mixed.cleanup());
203 }
204 {
205 const AssetCatalogPath with_punctuation("is!/this?/¿valid?");
206 EXPECT_EQ(AssetCatalogPath("is!/this?/¿valid?"), with_punctuation.cleanup());
207 }
208}
209
210TEST(AssetCatalogPathTest, iterate_components)
211{
212 AssetCatalogPath path("путь/в/Пермь");
214
215 path.iterate_components([&seen_components](StringRef component_name, bool is_last_component) {
216 std::pair<std::string, bool> parameter_pair = std::make_pair<std::string, bool>(
217 component_name, bool(is_last_component));
218 seen_components.append(parameter_pair);
219 });
220
221 ASSERT_EQ(3, seen_components.size());
222
223 EXPECT_EQ("путь", seen_components[0].first);
224 EXPECT_EQ("в", seen_components[1].first);
225 EXPECT_EQ("Пермь", seen_components[2].first);
226
227 EXPECT_FALSE(seen_components[0].second);
228 EXPECT_FALSE(seen_components[1].second);
229 EXPECT_TRUE(seen_components[2].second);
230}
231
232TEST(AssetCatalogPathTest, rebase)
233{
234 AssetCatalogPath path("some/path/to/some/catalog");
235 EXPECT_EQ(path.rebase("some/path", "new/base"), "new/base/to/some/catalog");
236 EXPECT_EQ(path.rebase("", "new/base"), "new/base/some/path/to/some/catalog");
237
238 EXPECT_EQ(path.rebase("some/path/to/some/catalog", "some/path/to/some/catalog"),
239 "some/path/to/some/catalog")
240 << "Rebasing to itself should not change the path.";
241
242 EXPECT_EQ(path.rebase("path/to", "new/base"), "")
243 << "Non-matching base path should return empty string to indicate 'NO'.";
244
245 /* Empty strings should be handled without crashing or other nasty side-effects. */
246 AssetCatalogPath empty("");
247 EXPECT_EQ(empty.rebase("path/to", "new/base"), "");
248 EXPECT_EQ(empty.rebase("", "new/base"), "new/base");
249 EXPECT_EQ(empty.rebase("", ""), "");
250}
251
252TEST(AssetCatalogPathTest, parent)
253{
254 const AssetCatalogPath ascii_path("path/with/missing/parents");
255 EXPECT_EQ(ascii_path.parent(), "path/with/missing");
256
257 const AssetCatalogPath path("путь/в/Пермь/долог/и/далек");
258 EXPECT_EQ(path.parent(), "путь/в/Пермь/долог/и");
259 EXPECT_EQ(path.parent().parent(), "путь/в/Пермь/долог");
260 EXPECT_EQ(path.parent().parent().parent(), "путь/в/Пермь");
261
262 const AssetCatalogPath one_level("one");
263 EXPECT_EQ(one_level.parent(), "");
264
265 const AssetCatalogPath empty("");
266 EXPECT_EQ(empty.parent(), "");
267}
268
269} // namespace blender::asset_system::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr StringRef substr(int64_t start, int64_t size) const
int64_t size() const
void append(const T &value)
AssetCatalogPath rebase(const AssetCatalogPath &from_path, const AssetCatalogPath &to_path) const
bool is_contained_in(const AssetCatalogPath &other_path) const
void iterate_components(ComponentIteratorFn callback) const
TEST(AssetCatalogPathTest, construction)