Files
test2/source/blender/blenkernel/intern/idprop_serialize_test.cc
Sergey Sharybin c1bc70b711 Cleanup: Add a copyright notice to files and use SPDX format
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.

This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.

Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.

Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:

    https://reuse.software/faq/
2023-05-31 16:19:06 +02:00

435 lines
15 KiB
C++

/* SPDX-FileCopyrightText: 2021 Blender Foundation.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "testing/testing.h"
#include "DNA_ID.h"
#include "BKE_idprop.hh"
namespace blender::bke::idprop::tests {
using namespace blender::io::serialize;
static void check_container_value(ArrayValue *value)
{
ASSERT_NE(value, nullptr);
ASSERT_EQ(value->type(), eValueType::Array);
const ArrayValue::Items elements = value->elements();
EXPECT_FALSE(elements.is_empty());
EXPECT_EQ(elements.size(), 1);
const ArrayValue::Item &item = value->elements()[0];
ASSERT_EQ(item->type(), eValueType::Dictionary);
}
static void check_object_attribute(const DictionaryValue::Lookup &lookup,
const std::string expected_key,
const std::string expected_value)
{
EXPECT_TRUE(lookup.contains(expected_key));
const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
ASSERT_EQ(element->type(), eValueType::String);
EXPECT_EQ(element->as_string_value()->value(), expected_value);
}
static void check_object_attribute(const DictionaryValue::Lookup &lookup,
const std::string expected_key,
const int32_t expected_value)
{
EXPECT_TRUE(lookup.contains(expected_key));
const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
ASSERT_EQ(element->type(), eValueType::Int);
EXPECT_EQ(element->as_int_value()->value(), expected_value);
}
static void check_object_attribute(const DictionaryValue::Lookup &lookup,
const std::string expected_key,
const float expected_value)
{
EXPECT_TRUE(lookup.contains(expected_key));
const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
ASSERT_EQ(element->type(), eValueType::Double);
EXPECT_EQ(element->as_double_value()->value(), expected_value);
}
static void check_object_attribute(const DictionaryValue::Lookup &lookup,
const std::string expected_key,
const double expected_value)
{
EXPECT_TRUE(lookup.contains(expected_key));
const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
ASSERT_EQ(element->type(), eValueType::Double);
EXPECT_EQ(element->as_double_value()->value(), expected_value);
}
static void test_string_to_value(const StringRefNull prop_name, const StringRefNull prop_content)
{
std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
EXPECT_EQ(lookup.size(), 3);
check_object_attribute(lookup, "name", prop_name);
check_object_attribute(lookup, "type", "IDP_STRING");
check_object_attribute(lookup, "value", prop_content);
}
TEST(idprop, convert_idp_string_to_value)
{
test_string_to_value("mykey", "mycontent");
}
static void test_int_to_value(const StringRefNull prop_name, int32_t prop_content)
{
std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
EXPECT_EQ(lookup.size(), 3);
check_object_attribute(lookup, "name", prop_name);
check_object_attribute(lookup, "type", "IDP_INT");
check_object_attribute(lookup, "value", prop_content);
}
TEST(idprop, convert_idp_int_to_value)
{
test_int_to_value("mykey", 0);
}
static void test_float_to_value(const StringRefNull prop_name, float prop_content)
{
std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
EXPECT_EQ(lookup.size(), 3);
check_object_attribute(lookup, "name", prop_name);
check_object_attribute(lookup, "type", "IDP_FLOAT");
check_object_attribute(lookup, "value", prop_content);
}
TEST(idprop, convert_idp_float_to_value)
{
test_float_to_value("mykey", 0.2f);
}
static void test_double_to_value(const StringRefNull prop_name, double prop_content)
{
std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
EXPECT_EQ(lookup.size(), 3);
check_object_attribute(lookup, "name", prop_name);
check_object_attribute(lookup, "type", "IDP_DOUBLE");
check_object_attribute(lookup, "value", prop_content);
}
TEST(idprop, convert_idp_double_to_value)
{
test_double_to_value("mykey", 0.2);
}
template<typename PrimitiveType, typename ValueType>
static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveType> prop_content)
{
std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
check_container_value(value.get());
const ArrayValue::Item &item = value->elements()[0];
const DictionaryValue *object = item->as_dictionary_value();
const DictionaryValue::Lookup lookup = object->create_lookup();
EXPECT_EQ(lookup.size(), 4);
check_object_attribute(lookup, "name", prop_name);
check_object_attribute(lookup, "type", "IDP_ARRAY");
const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
const ArrayValue *subvalues = element->as_array_value();
ASSERT_NE(subvalues, nullptr);
const ArrayValue::Items &subitems = subvalues->elements();
ASSERT_EQ(subitems.size(), prop_content.size());
for (size_t i = 0; i < prop_content.size(); i++) {
EXPECT_EQ(static_cast<ValueType *>(subitems[i].get())->value(), prop_content[i]);
}
}
TEST(idprop, convert_idp_int_array_to_value)
{
test_array_to_value<int32_t, IntValue>("my_integer_array",
{-16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16});
}
TEST(idprop, convert_idp_float_array_to_value)
{
test_array_to_value<float, DoubleValue>(
"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});
}
TEST(idprop, convert_idp_double_array_to_value)
{
test_array_to_value<double, DoubleValue>(
"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});
}
static std::unique_ptr<Value> parse_json(StringRef input)
{
std::stringstream is(input);
JsonFormatter json;
std::unique_ptr<Value> value = json.deserialize(is);
return value;
}
static std::string to_json(const Value &value)
{
std::stringstream out;
JsonFormatter json;
json.serialize(out, value);
return out.str();
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
StringRef expected_value)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_STRING);
EXPECT_EQ(id_property->name, expected_name);
EXPECT_EQ(IDP_String(id_property), expected_value);
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
int32_t expected_value)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_INT);
EXPECT_EQ(id_property->name, expected_name);
EXPECT_EQ(IDP_Int(id_property), expected_value);
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
float expected_value)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_FLOAT);
EXPECT_EQ(id_property->name, expected_name);
EXPECT_EQ(IDP_Float(id_property), expected_value);
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
double expected_value)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_DOUBLE);
EXPECT_EQ(id_property->name, expected_name);
EXPECT_EQ(IDP_Double(id_property), expected_value);
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<int32_t> &values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);
EXPECT_EQ(id_property->subtype, IDP_INT);
EXPECT_EQ(id_property->len, values.size());
EXPECT_EQ(id_property->name, expected_name);
int32_t *idprop_values = static_cast<int32_t *>(IDP_Array(id_property));
for (int i = 0; i < values.size(); i++) {
EXPECT_EQ(idprop_values[i], values[i]);
}
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<float> &values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);
EXPECT_EQ(id_property->subtype, IDP_FLOAT);
EXPECT_EQ(id_property->len, values.size());
EXPECT_EQ(id_property->name, expected_name);
float *idprop_values = static_cast<float *>(IDP_Array(id_property));
for (int i = 0; i < values.size(); i++) {
EXPECT_EQ(idprop_values[i], values[i]);
}
}
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<double> &values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);
EXPECT_EQ(id_property->subtype, IDP_DOUBLE);
EXPECT_EQ(id_property->len, values.size());
EXPECT_EQ(id_property->name, expected_name);
double *idprop_values = static_cast<double *>(IDP_Array(id_property));
for (int i = 0; i < values.size(); i++) {
EXPECT_EQ(idprop_values[i], values[i]);
}
}
template<typename Type>
static void test_convert_idprop_from_value(StringRef input,
StringRef expected_name,
Type expected_value)
{
std::unique_ptr<Value> value = parse_json(input);
IDProperty *id_property = convert_from_serialize_value(*value);
test_idprop(id_property, expected_name, expected_value);
IDP_FreeProperty(id_property);
}
TEST(idprop, convert_idp_string_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyStringName","type":"IDP_STRING","value":"MyString"}])",
"MyStringName",
"MyString");
}
TEST(idprop, convert_idp_int_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyIntegerName","type":"IDP_INT","value":42}])", "MyIntegerName", 42);
}
TEST(idprop, convert_idp_float_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24}])", "MyFloatName", 42.24f);
}
TEST(idprop, convert_idp_double_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])", "MyDoubleName", 42.24);
}
TEST(idprop, convert_idp_array_int_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_INT","value":[42, 24, 35]}])",
"MyArrayName",
Vector<int32_t>{42, 24, 35});
}
TEST(idprop, convert_idp_array_float_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[42.0, 24.4, 35.2]}])",
"MyArrayName",
Vector<float>{42.0f, 24.4f, 35.2f});
}
TEST(idprop, convert_idp_array_double_from_value)
{
test_convert_idprop_from_value(
R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_DOUBLE","value":[42.43,24.5,35.8]}])",
"MyArrayName",
Vector<double>{42.43, 24.5, 35.8});
}
TEST(idprop, convert_idp_multiple_from_value)
{
static const std::string input_json =
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}])";
std::unique_ptr<Value> value = parse_json(input_json);
IDProperty *id_property = convert_from_serialize_value(*value);
IDProperty *id_property_1 = id_property;
ASSERT_NE(id_property_1, nullptr);
IDProperty *id_property_2 = id_property_1->next;
ASSERT_NE(id_property_2, nullptr);
IDProperty *id_property_3 = id_property_2->next;
ASSERT_NE(id_property_3, nullptr);
IDProperty *id_property_4 = id_property_3->next;
ASSERT_NE(id_property_4, nullptr);
EXPECT_EQ(id_property_1->prev, nullptr);
EXPECT_EQ(id_property_2->prev, id_property_1);
EXPECT_EQ(id_property_3->prev, id_property_2);
EXPECT_EQ(id_property_4->prev, id_property_3);
EXPECT_EQ(id_property_4->next, nullptr);
test_idprop(id_property_1, "MyIntegerName", 42);
test_idprop(id_property_2, "MyStringName", "MyString");
test_idprop(id_property_3, "MyFloatName", 42.24f);
test_idprop(id_property_4, "MyDoubleName", 42.24);
IDP_FreeProperty(id_property_1);
IDP_FreeProperty(id_property_2);
IDP_FreeProperty(id_property_3);
IDP_FreeProperty(id_property_4);
}
TEST(idprop, convert_idp_multiple_roundtrip)
{
static const std::string input_json =
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}])";
std::unique_ptr<Value> value = parse_json(input_json);
IDProperty *id_property = convert_from_serialize_value(*value);
IDProperty *id_property_1 = id_property;
ASSERT_NE(id_property_1, nullptr);
IDProperty *id_property_2 = id_property_1->next;
ASSERT_NE(id_property_2, nullptr);
IDProperty *id_property_3 = id_property_2->next;
ASSERT_NE(id_property_3, nullptr);
IDProperty *id_property_4 = id_property_3->next;
ASSERT_NE(id_property_4, nullptr);
std::unique_ptr<Value> value_from_id_properties = convert_to_serialize_values(id_property);
std::string output_json = to_json(*value_from_id_properties);
EXPECT_EQ(input_json, output_json);
IDP_FreeProperty(id_property_1);
IDP_FreeProperty(id_property_2);
IDP_FreeProperty(id_property_3);
IDP_FreeProperty(id_property_4);
}
TEST(idprop, convert_idp_group_from_value)
{
static const std::string input_json =
R"([{"name":"AssetMetaData.properties","type":"IDP_GROUP","value":[{"name":"dimensions","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[2.0,2.0,2.0]}]}])";
std::unique_ptr<Value> value = parse_json(input_json);
IDProperty *id_property = convert_from_serialize_value(*value);
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_GROUP);
EXPECT_EQ(BLI_listbase_count(&id_property->data.group), 1);
test_idprop(static_cast<IDProperty *>(id_property->data.group.first),
"dimensions",
Vector<float>{2.0f, 2.0f, 2.0f});
IDP_FreeProperty(id_property);
}
} // namespace blender::bke::idprop::tests