Blender  V3.3
idprop_serialize_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. */
3 
4 #include "testing/testing.h"
5 
6 #include "DNA_ID.h"
7 
8 #include "BKE_idprop.hh"
9 
11 
12 using namespace blender::io::serialize;
13 
14 static void check_container_value(ArrayValue *value)
15 {
16  ASSERT_NE(value, nullptr);
17  ASSERT_EQ(value->type(), eValueType::Array);
18  const ArrayValue::Items elements = value->elements();
19  EXPECT_FALSE(elements.is_empty());
20  EXPECT_EQ(elements.size(), 1);
21 
22  const ArrayValue::Item &item = value->elements()[0];
23  ASSERT_EQ(item->type(), eValueType::Dictionary);
24 }
25 
27  const std::string expected_key,
28  const std::string expected_value)
29 {
30  EXPECT_TRUE(lookup.contains(expected_key));
31  const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
32  ASSERT_EQ(element->type(), eValueType::String);
33  EXPECT_EQ(element->as_string_value()->value(), expected_value);
34 }
35 
37  const std::string expected_key,
38  const int32_t expected_value)
39 {
40  EXPECT_TRUE(lookup.contains(expected_key));
41  const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
42  ASSERT_EQ(element->type(), eValueType::Int);
43  EXPECT_EQ(element->as_int_value()->value(), expected_value);
44 }
45 
47  const std::string expected_key,
48  const float expected_value)
49 {
50  EXPECT_TRUE(lookup.contains(expected_key));
51  const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
52  ASSERT_EQ(element->type(), eValueType::Double);
53  EXPECT_EQ(element->as_double_value()->value(), expected_value);
54 }
55 
57  const std::string expected_key,
58  const double expected_value)
59 {
60  EXPECT_TRUE(lookup.contains(expected_key));
61  const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
62  ASSERT_EQ(element->type(), eValueType::Double);
63  EXPECT_EQ(element->as_double_value()->value(), expected_value);
64 }
65 
66 static void test_string_to_value(const StringRefNull prop_name, const StringRefNull prop_content)
67 {
68  std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
69 
70  std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
71  check_container_value(value.get());
72  const ArrayValue::Item &item = value->elements()[0];
73  const DictionaryValue *object = item->as_dictionary_value();
74  const DictionaryValue::Lookup lookup = object->create_lookup();
75 
76  EXPECT_EQ(lookup.size(), 3);
77  check_object_attribute(lookup, "name", prop_name);
78  check_object_attribute(lookup, "type", "IDP_STRING");
79  check_object_attribute(lookup, "value", prop_content);
80 }
81 
82 TEST(idprop, convert_idp_string_to_value)
83 {
84  test_string_to_value("mykey", "mycontent");
85 }
86 
87 static void test_int_to_value(const StringRefNull prop_name, int32_t prop_content)
88 {
89  std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
90 
91  std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
92  check_container_value(value.get());
93  const ArrayValue::Item &item = value->elements()[0];
94  const DictionaryValue *object = item->as_dictionary_value();
95  const DictionaryValue::Lookup lookup = object->create_lookup();
96 
97  EXPECT_EQ(lookup.size(), 3);
98  check_object_attribute(lookup, "name", prop_name);
99  check_object_attribute(lookup, "type", "IDP_INT");
100  check_object_attribute(lookup, "value", prop_content);
101 }
102 
103 TEST(idprop, convert_idp_int_to_value)
104 {
105  test_int_to_value("mykey", 0);
106 }
107 
108 static void test_float_to_value(const StringRefNull prop_name, float prop_content)
109 {
110  std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
111 
112  std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
113  check_container_value(value.get());
114  const ArrayValue::Item &item = value->elements()[0];
115  const DictionaryValue *object = item->as_dictionary_value();
116  const DictionaryValue::Lookup lookup = object->create_lookup();
117 
118  EXPECT_EQ(lookup.size(), 3);
119  check_object_attribute(lookup, "name", prop_name);
120  check_object_attribute(lookup, "type", "IDP_FLOAT");
121  check_object_attribute(lookup, "value", prop_content);
122 }
123 
124 TEST(idprop, convert_idp_float_to_value)
125 {
126  test_float_to_value("mykey", 0.2f);
127 }
128 
129 static void test_double_to_value(const StringRefNull prop_name, double prop_content)
130 {
131  std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
132 
133  std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
134  check_container_value(value.get());
135  const ArrayValue::Item &item = value->elements()[0];
136  const DictionaryValue *object = item->as_dictionary_value();
137  const DictionaryValue::Lookup lookup = object->create_lookup();
138 
139  EXPECT_EQ(lookup.size(), 3);
140  check_object_attribute(lookup, "name", prop_name);
141  check_object_attribute(lookup, "type", "IDP_DOUBLE");
142  check_object_attribute(lookup, "value", prop_content);
143 }
144 
145 TEST(idprop, convert_idp_double_to_value)
146 {
147  test_double_to_value("mykey", 0.2);
148 }
149 
150 template<typename PrimitiveType, typename ValueType>
151 static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveType> prop_content)
152 {
153  std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
154  std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
155 
156  check_container_value(value.get());
157  const ArrayValue::Item &item = value->elements()[0];
158  const DictionaryValue *object = item->as_dictionary_value();
159  const DictionaryValue::Lookup lookup = object->create_lookup();
160 
161  EXPECT_EQ(lookup.size(), 4);
162  check_object_attribute(lookup, "name", prop_name);
163  check_object_attribute(lookup, "type", "IDP_ARRAY");
164 
165  const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
166  const ArrayValue *subvalues = element->as_array_value();
167  ASSERT_NE(subvalues, nullptr);
168  const ArrayValue::Items &subitems = subvalues->elements();
169  ASSERT_EQ(subitems.size(), prop_content.size());
170 
171  for (size_t i = 0; i < prop_content.size(); i++) {
172  EXPECT_EQ(static_cast<ValueType *>(subitems[i].get())->value(), prop_content[i]);
173  }
174 }
175 
176 TEST(idprop, convert_idp_int_array_to_value)
177 {
178  test_array_to_value<int32_t, IntValue>("my_integer_array",
179  {-16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16});
180 }
181 
182 TEST(idprop, convert_idp_float_array_to_value)
183 {
184  test_array_to_value<float, DoubleValue>(
185  "my_float_array", {-16.8f, -8.4f, -4.2f, -2.1f, -1.0f, 0.0f, 1.0f, 2.1f, 4.2f, 8.4f, 16.8f});
186 }
187 
188 TEST(idprop, convert_idp_double_array_to_value)
189 {
190  test_array_to_value<double, DoubleValue>(
191  "my_double_array", {-16.8, -8.4, -4.2, -2.1, -1.0, 0.0, 1.0, 2.1, 4.2, 8.4, 16.8});
192 }
193 
194 static std::unique_ptr<Value> parse_json(StringRef input)
195 {
196  std::stringstream is(input);
197  JsonFormatter json;
198  std::unique_ptr<Value> value = json.deserialize(is);
199  return value;
200 }
201 
202 static std::string to_json(const Value &value)
203 {
204  std::stringstream out;
205  JsonFormatter json;
206  json.serialize(out, value);
207  return out.str();
208 }
209 
210 static void test_idprop(const IDProperty *id_property,
211  StringRef expected_name,
212  StringRef expected_value)
213 {
214  ASSERT_NE(id_property, nullptr);
215  EXPECT_EQ(id_property->type, IDP_STRING);
216  EXPECT_EQ(id_property->name, expected_name);
217  EXPECT_EQ(IDP_String(id_property), expected_value);
218 }
219 
220 static void test_idprop(const IDProperty *id_property,
221  StringRef expected_name,
222  int32_t expected_value)
223 {
224  ASSERT_NE(id_property, nullptr);
225  EXPECT_EQ(id_property->type, IDP_INT);
226  EXPECT_EQ(id_property->name, expected_name);
227  EXPECT_EQ(IDP_Int(id_property), expected_value);
228 }
229 
230 static void test_idprop(const IDProperty *id_property,
231  StringRef expected_name,
232  float expected_value)
233 {
234  ASSERT_NE(id_property, nullptr);
235  EXPECT_EQ(id_property->type, IDP_FLOAT);
236  EXPECT_EQ(id_property->name, expected_name);
237  EXPECT_EQ(IDP_Float(id_property), expected_value);
238 }
239 
240 static void test_idprop(const IDProperty *id_property,
241  StringRef expected_name,
242  double expected_value)
243 {
244  ASSERT_NE(id_property, nullptr);
245  EXPECT_EQ(id_property->type, IDP_DOUBLE);
246  EXPECT_EQ(id_property->name, expected_name);
247  EXPECT_EQ(IDP_Double(id_property), expected_value);
248 }
249 
250 static void test_idprop(const IDProperty *id_property,
251  StringRef expected_name,
252  const Vector<int32_t> &values)
253 {
254  ASSERT_NE(id_property, nullptr);
255  EXPECT_EQ(id_property->type, IDP_ARRAY);
256  EXPECT_EQ(id_property->subtype, IDP_INT);
257  EXPECT_EQ(id_property->len, values.size());
258  EXPECT_EQ(id_property->name, expected_name);
259  int32_t *idprop_values = static_cast<int32_t *>(IDP_Array(id_property));
260  for (int i = 0; i < values.size(); i++) {
261  EXPECT_EQ(idprop_values[i], values[i]);
262  }
263 }
264 
265 static void test_idprop(const IDProperty *id_property,
266  StringRef expected_name,
267  const Vector<float> &values)
268 {
269  ASSERT_NE(id_property, nullptr);
270  EXPECT_EQ(id_property->type, IDP_ARRAY);
271  EXPECT_EQ(id_property->subtype, IDP_FLOAT);
272  EXPECT_EQ(id_property->len, values.size());
273  EXPECT_EQ(id_property->name, expected_name);
274  float *idprop_values = static_cast<float *>(IDP_Array(id_property));
275  for (int i = 0; i < values.size(); i++) {
276  EXPECT_EQ(idprop_values[i], values[i]);
277  }
278 }
279 
280 static void test_idprop(const IDProperty *id_property,
281  StringRef expected_name,
282  const Vector<double> &values)
283 {
284  ASSERT_NE(id_property, nullptr);
285  EXPECT_EQ(id_property->type, IDP_ARRAY);
286  EXPECT_EQ(id_property->subtype, IDP_DOUBLE);
287  EXPECT_EQ(id_property->len, values.size());
288  EXPECT_EQ(id_property->name, expected_name);
289  double *idprop_values = static_cast<double *>(IDP_Array(id_property));
290  for (int i = 0; i < values.size(); i++) {
291  EXPECT_EQ(idprop_values[i], values[i]);
292  }
293 }
294 
295 template<typename Type>
297  StringRef expected_name,
298  Type expected_value)
299 {
300  std::unique_ptr<Value> value = parse_json(input);
301  IDProperty *id_property = convert_from_serialize_value(*value);
302  test_idprop(id_property, expected_name, expected_value);
303  IDP_FreeProperty(id_property);
304 }
305 
306 TEST(idprop, convert_idp_string_from_value)
307 {
309  R"([{"name":"MyStringName","type":"IDP_STRING","value":"MyString"}])",
310  "MyStringName",
311  "MyString");
312 }
313 
314 TEST(idprop, convert_idp_int_from_value)
315 {
317  R"([{"name":"MyIntegerName","type":"IDP_INT","value":42}])", "MyIntegerName", 42);
318 }
319 
320 TEST(idprop, convert_idp_float_from_value)
321 {
323  R"([{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24}])", "MyFloatName", 42.24f);
324 }
325 
326 TEST(idprop, convert_idp_double_from_value)
327 {
329  R"([{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])", "MyDoubleName", 42.24);
330 }
331 
332 TEST(idprop, convert_idp_array_int_from_value)
333 {
335  R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_INT","value":[42, 24, 35]}])",
336  "MyArrayName",
337  Vector<int32_t>{42, 24, 35});
338 }
339 
340 TEST(idprop, convert_idp_array_float_from_value)
341 {
343  R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[42.0, 24.4, 35.2]}])",
344  "MyArrayName",
345  Vector<float>{42.0f, 24.4f, 35.2f});
346 }
347 
348 TEST(idprop, convert_idp_array_double_from_value)
349 {
351  R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_DOUBLE","value":[42.43,24.5,35.8]}])",
352  "MyArrayName",
353  Vector<double>{42.43, 24.5, 35.8});
354 }
355 
356 TEST(idprop, convert_idp_multiple_from_value)
357 {
358  static const std::string input_json =
359  R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
360  std::unique_ptr<Value> value = parse_json(input_json);
361 
362  IDProperty *id_property = convert_from_serialize_value(*value);
363  IDProperty *id_property_1 = id_property;
364  ASSERT_NE(id_property_1, nullptr);
365  IDProperty *id_property_2 = id_property_1->next;
366  ASSERT_NE(id_property_2, nullptr);
367  IDProperty *id_property_3 = id_property_2->next;
368  ASSERT_NE(id_property_3, nullptr);
369  IDProperty *id_property_4 = id_property_3->next;
370  ASSERT_NE(id_property_4, nullptr);
371 
372  EXPECT_EQ(id_property_1->prev, nullptr);
373  EXPECT_EQ(id_property_2->prev, id_property_1);
374  EXPECT_EQ(id_property_3->prev, id_property_2);
375  EXPECT_EQ(id_property_4->prev, id_property_3);
376  EXPECT_EQ(id_property_4->next, nullptr);
377 
378  test_idprop(id_property_1, "MyIntegerName", 42);
379  test_idprop(id_property_2, "MyStringName", "MyString");
380  test_idprop(id_property_3, "MyFloatName", 42.24f);
381  test_idprop(id_property_4, "MyDoubleName", 42.24);
382 
383  IDP_FreeProperty(id_property_1);
384  IDP_FreeProperty(id_property_2);
385  IDP_FreeProperty(id_property_3);
386  IDP_FreeProperty(id_property_4);
387 }
388 
389 TEST(idprop, convert_idp_multiple_roundtrip)
390 {
391  static const std::string input_json =
392  R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.2400016784668},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
393  std::unique_ptr<Value> value = parse_json(input_json);
394 
395  IDProperty *id_property = convert_from_serialize_value(*value);
396  IDProperty *id_property_1 = id_property;
397  ASSERT_NE(id_property_1, nullptr);
398  IDProperty *id_property_2 = id_property_1->next;
399  ASSERT_NE(id_property_2, nullptr);
400  IDProperty *id_property_3 = id_property_2->next;
401  ASSERT_NE(id_property_3, nullptr);
402  IDProperty *id_property_4 = id_property_3->next;
403  ASSERT_NE(id_property_4, nullptr);
404 
405  std::unique_ptr<Value> value_from_id_properties = convert_to_serialize_values(id_property);
406  std::string output_json = to_json(*value_from_id_properties);
407  EXPECT_EQ(input_json, output_json);
408 
409  IDP_FreeProperty(id_property_1);
410  IDP_FreeProperty(id_property_2);
411  IDP_FreeProperty(id_property_3);
412  IDP_FreeProperty(id_property_4);
413 }
414 
415 TEST(idprop, convert_idp_group_from_value)
416 {
417  static const std::string input_json =
418  R"([{"name":"AssetMetaData.properties","type":"IDP_GROUP","value":[{"name":"dimensions","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[2.0,2.0,2.0]}]}])";
419  std::unique_ptr<Value> value = parse_json(input_json);
420 
421  IDProperty *id_property = convert_from_serialize_value(*value);
422  ASSERT_NE(id_property, nullptr);
423  EXPECT_EQ(id_property->type, IDP_GROUP);
424  EXPECT_EQ(BLI_listbase_count(&id_property->data.group), 1);
425 
426  test_idprop(static_cast<IDProperty *>(id_property->data.group.first),
427  "dimensions",
428  Vector<float>{2.0f, 2.0f, 2.0f});
429 
430  IDP_FreeProperty(id_property);
431 }
432 
433 } // namespace blender::bke::idprop::tests
#define IDP_Float(prop)
Definition: BKE_idprop.h:269
#define IDP_Int(prop)
Definition: BKE_idprop.h:244
#define IDP_String(prop)
Definition: BKE_idprop.h:271
#define IDP_Double(prop)
Definition: BKE_idprop.h:270
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
#define IDP_Array(prop)
Definition: BKE_idprop.h:245
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
ID and Library types, which are fundamental for sdna.
@ IDP_DOUBLE
Definition: DNA_ID.h:143
@ IDP_FLOAT
Definition: DNA_ID.h:138
@ IDP_STRING
Definition: DNA_ID.h:136
@ IDP_INT
Definition: DNA_ID.h:137
@ IDP_GROUP
Definition: DNA_ID.h:141
@ IDP_ARRAY
Definition: DNA_ID.h:140
ATTR_WARN_UNUSED_RESULT const void * element
int64_t size() const
Definition: BLI_vector.hh:694
const Container & elements() const
std::unique_ptr< Value > deserialize(std::istream &is) override
Definition: serialize.cc:212
void serialize(std::ostream &os, const Value &value) override
Definition: serialize.cc:200
const DictionaryValue * as_dictionary_value() const
Definition: serialize.cc:49
ccl_global KernelShaderEvalInput * input
GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id)
static std::unique_ptr< Value > parse_json(StringRef input)
static void test_float_to_value(const StringRefNull prop_name, float prop_content)
static void test_string_to_value(const StringRefNull prop_name, const StringRefNull prop_content)
static void test_convert_idprop_from_value(StringRef input, StringRef expected_name, Type expected_value)
static void test_idprop(const IDProperty *id_property, StringRef expected_name, StringRef expected_value)
static void test_array_to_value(const StringRefNull prop_name, Vector< PrimitiveType > prop_content)
static void check_container_value(ArrayValue *value)
static void test_int_to_value(const StringRefNull prop_name, int32_t prop_content)
TEST(idprop, convert_idp_string_to_value)
static void check_object_attribute(const DictionaryValue::Lookup &lookup, const std::string expected_key, const std::string expected_value)
static void test_double_to_value(const StringRefNull prop_name, double prop_content)
static std::string to_json(const Value &value)
std::unique_ptr< io::serialize::ArrayValue > convert_to_serialize_values(const IDProperty *properties)
Convert the given properties to Value objects for serialization.
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRefNull prop_name, int32_t value)
Allocate a new IDProperty of type IDP_INT, set its name and value.
IDProperty * convert_from_serialize_value(const blender::io::serialize::Value &value)
Convert the given value to an IDProperty.
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
signed int int32_t
Definition: stdint.h:77
ListBase group
Definition: DNA_ID.h:101
int len
Definition: DNA_ID.h:121
struct IDProperty * next
Definition: DNA_ID.h:107
char name[64]
Definition: DNA_ID.h:111
IDPropertyData data
Definition: DNA_ID.h:117
struct IDProperty * prev
Definition: DNA_ID.h:107
char subtype
Definition: DNA_ID.h:108
char type
Definition: DNA_ID.h:108
void * first
Definition: DNA_listBase.h:31