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