Add callback tests

This commit is contained in:
Janine Liu 2023-05-22 17:26:11 -04:00
parent efb95c5659
commit 3dd83ab8d0
2 changed files with 253 additions and 86 deletions

View File

@ -81,7 +81,7 @@ public:
/**
* @brief Gets a MetadataPropertyView through a callback that accepts a
* property name and a std::optional<MetadataPropertyView<T>> to view the data
* property name and a MetadataPropertyView<T> to view the data
* of a property stored in the ExtensionExtStructuralMetadataPropertyTable.
*
* This method will validate the EXT_structural_metadata format to ensure
@ -90,13 +90,13 @@ public:
* uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar
* types, a glm matN composed of one of the scalar types, bool,
* std::string_view, or MetadataArrayView<T> with T as one of the
* aforementioned types. If the property is invalid, std::nullopt will be
* passed to the callback. Otherwise, a valid property view will be passed to
* the callback.
* aforementioned types. If the property is invalid, an empty
* MetadataPropertyView with an error status code will be passed to the
* callback. Otherwise, a valid property view will be passed to the callback.
*
* @param propertyName The name of the property to retrieve data from
* @tparam callback A callback function that accepts property name and
* std::optional<MetadataPropertyView<T>>
* MetadataPropertyView<T>
*/
template <typename Callback>
void
@ -121,6 +121,12 @@ public:
type,
componentType,
std::forward<Callback>(callback));
} else if (type == PropertyType::Scalar) {
getScalarPropertyViewImpl(
propertyName,
*pClassProperty,
componentType,
std::forward<Callback>(callback));
} else if (isPropertyTypeVecN(type)) {
getVecNPropertyViewImpl(
propertyName,
@ -135,20 +141,26 @@ public:
type,
componentType,
std::forward<Callback>(callback));
} else {
getPrimitivePropertyViewImpl(
} else if (type == PropertyType::String) {
callback(
propertyName,
*pClassProperty,
type,
componentType,
std::forward<Callback>(callback));
getPropertyViewImpl<std::string_view>(propertyName, *pClassProperty));
} else if (type == PropertyType::Boolean) {
callback(
propertyName,
getPropertyViewImpl<bool>(propertyName, *pClassProperty));
} else {
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
}
}
/**
* @brief Iterates over each property in the
* ExtensionExtStructuralMetadataPropertyTable with a callback that accepts a
* property name and a std::optional<MetadataPropertyView<T>> to view the data
* property name and a MetadataPropertyView<T> to view the data
* stored in the ExtensionExtStructuralMetadataPropertyTableProperty.
*
* This method will validate the EXT_structural_metadata format to ensure
@ -157,13 +169,14 @@ public:
* uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar
* types, a glm matN composed of one of the scalar types, bool,
* std::string_view, or MetadataArrayView<T> with T as one of the
* aforementioned types. If the property is invalid, std::nullopt will be
* passed to the callback. Otherwise, a valid property view will be passed to
* aforementioned types. If the property is invalid, an empty
* MetadataPropertyView with an error status code will be passed to the
* callback. Otherwise, a valid property view will be passed to
* the callback.
*
* @param propertyName The name of the property to retrieve data from
* @tparam callback A callback function that accepts property name and
* std::optional<MetadataPropertyView<T>>
* MetadataPropertyView<T>
*/
template <typename Callback> void forEachProperty(Callback&& callback) const {
for (const auto& property : this->_pClass->properties) {
@ -266,6 +279,10 @@ private:
classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}
@ -348,6 +365,10 @@ private:
classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}
@ -383,6 +404,10 @@ private:
std::forward<Callback>(callback));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
break;
}
}
@ -465,6 +490,10 @@ private:
classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}
@ -500,6 +529,10 @@ private:
std::forward<Callback>(callback));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
break;
}
}
@ -545,6 +578,11 @@ private:
getPropertyViewImpl<MetadataArrayView<std::string_view>>(
propertyName,
classProperty));
} else {
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
}
}
@ -625,6 +663,10 @@ private:
classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}
@ -660,6 +702,10 @@ private:
std::forward<Callback>(callback));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
break;
}
}
@ -742,6 +788,10 @@ private:
classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}
@ -777,80 +827,77 @@ private:
std::forward<Callback>(callback));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorTypeMismatch));
break;
}
}
template <typename Callback>
void getPrimitivePropertyViewImpl(
void getScalarPropertyViewImpl(
const std::string& propertyName,
const ExtensionExtStructuralMetadataClassProperty& classProperty,
PropertyType type,
PropertyComponentType componentType,
Callback&& callback) const {
if (type == PropertyType::Scalar) {
switch (componentType) {
case PropertyComponentType::Int8:
callback(
propertyName,
getPropertyViewImpl<int8_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint8:
callback(
propertyName,
getPropertyViewImpl<uint8_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int16:
callback(
propertyName,
getPropertyViewImpl<int16_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint16:
callback(
propertyName,
getPropertyViewImpl<uint16_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int32:
callback(
propertyName,
getPropertyViewImpl<int32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint32:
callback(
propertyName,
getPropertyViewImpl<uint32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int64:
callback(
propertyName,
getPropertyViewImpl<int64_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint64:
callback(
propertyName,
getPropertyViewImpl<uint64_t>(propertyName, classProperty));
break;
case PropertyComponentType::Float32:
callback(
propertyName,
getPropertyViewImpl<float>(propertyName, classProperty));
break;
case PropertyComponentType::Float64:
callback(
propertyName,
getPropertyViewImpl<double>(propertyName, classProperty));
break;
default:
break;
}
} else if (type == PropertyType::String) {
switch (componentType) {
case PropertyComponentType::Int8:
callback(
propertyName,
getPropertyViewImpl<std::string_view>(propertyName, classProperty));
} else if (type == PropertyType::Boolean) {
getPropertyViewImpl<int8_t>(propertyName, classProperty));
return;
case PropertyComponentType::Uint8:
callback(
propertyName,
getPropertyViewImpl<bool>(propertyName, classProperty));
getPropertyViewImpl<uint8_t>(propertyName, classProperty));
return;
case PropertyComponentType::Int16:
callback(
propertyName,
getPropertyViewImpl<int16_t>(propertyName, classProperty));
return;
case PropertyComponentType::Uint16:
callback(
propertyName,
getPropertyViewImpl<uint16_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int32:
callback(
propertyName,
getPropertyViewImpl<int32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint32:
callback(
propertyName,
getPropertyViewImpl<uint32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int64:
callback(
propertyName,
getPropertyViewImpl<int64_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint64:
callback(
propertyName,
getPropertyViewImpl<uint64_t>(propertyName, classProperty));
break;
case PropertyComponentType::Float32:
callback(
propertyName,
getPropertyViewImpl<float>(propertyName, classProperty));
break;
case PropertyComponentType::Float64:
callback(
propertyName,
getPropertyViewImpl<double>(propertyName, classProperty));
break;
default:
callback(
propertyName,
createInvalidPropertyView<uint8_t>(
MetadataPropertyViewStatus::ErrorComponentTypeMismatch));
break;
}
}

View File

@ -250,7 +250,7 @@ TEST_CASE("Test StructuralMetadata vecN property") {
REQUIRE(ivec3Property.size() > 0);
for (int64_t i = 0; i < ivec3Property.size(); ++i) {
REQUIRE(ivec3Property.get(i) == values[i]);
REQUIRE(ivec3Property.get(i) == values[static_cast<size_t>(i)]);
}
}
@ -441,7 +441,7 @@ TEST_CASE("Test StructuralMetadata matN property") {
REQUIRE(u32mat2x2Property.size() > 0);
for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) {
REQUIRE(u32mat2x2Property.get(i) == values[i]);
REQUIRE(u32mat2x2Property.get(i) == values[static_cast<size_t>(i)]);
}
}
@ -2590,11 +2590,51 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") {
}
}
TEST_CASE("Test StructuralMetadata callback for invalid property") {
Model model;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace();
ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"];
ExtensionExtStructuralMetadataClassProperty& testClassProperty =
testClass.properties["InvalidProperty"];
testClassProperty.type =
ExtensionExtStructuralMetadataClassProperty::Type::SCALAR;
testClassProperty.componentType =
ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32;
ExtensionExtStructuralMetadataPropertyTable& propertyTable =
metadata.propertyTables.emplace_back();
propertyTable.classProperty = "TestClass";
propertyTable.count = static_cast<int64_t>(5);
ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty =
propertyTable.properties["InvalidProperty"];
propertyTableProperty.values = static_cast<int32_t>(-1);
MetadataPropertyTableView view(&model, &propertyTable);
const ExtensionExtStructuralMetadataClassProperty* classProperty =
view.getClassProperty("InvalidProperty");
REQUIRE(classProperty);
classProperty = view.getClassProperty("NonexistentProperty");
REQUIRE(!classProperty);
auto testCallback = [](const std::string& /*propertyName*/,
auto propertyValue) mutable {
REQUIRE(propertyValue.status() != MetadataPropertyViewStatus::Valid);
REQUIRE(propertyValue.size() == 0);
};
view.getPropertyView("InvalidProperty", testCallback);
view.getPropertyView("NonexistentProperty", testCallback);
}
TEST_CASE("Test StructuralMetadata callback for scalar property") {
Model model;
std::vector<uint32_t> values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33};
size_t valueBufferIndex = 0;
size_t valueBufferViewIndex = 0;
// Buffers are constructed in scope to ensure that the tests don't use their
@ -2608,7 +2648,6 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") {
valueBuffer.cesium.data.data(),
values.data(),
valueBuffer.cesium.data.size());
valueBufferIndex = model.buffers.size() - 1;
BufferView& valueBufferView = model.bufferViews.emplace_back();
valueBufferView.buffer = static_cast<int32_t>(model.buffers.size() - 1);
@ -2655,12 +2694,12 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") {
[&values](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid);
REQUIRE(propertyValue.size() > 0);
if constexpr (std::is_same_v<
MetadataPropertyView<uint32_t>,
decltype(propertyValue)>) {
REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid);
REQUIRE(propertyValue.size() > 0);
for (int64_t i = 0; i < propertyValue.size(); ++i) {
REQUIRE(
static_cast<uint32_t>(propertyValue.get(i)) ==
@ -2682,7 +2721,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") {
glm::ivec3(-2, 6, 12),
glm::ivec3(-4, 8, -13)};
size_t valueBufferIndex = 0;
size_t valueBufferViewIndex = 0;
// Buffers are constructed in scope to ensure that the tests don't use their
@ -2696,7 +2734,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") {
valueBuffer.cesium.data.data(),
values.data(),
valueBuffer.cesium.data.size());
valueBufferIndex = model.buffers.size() - 1;
BufferView& valueBufferView = model.bufferViews.emplace_back();
valueBufferView.buffer = static_cast<int32_t>(model.buffers.size() - 1);
@ -3038,7 +3075,7 @@ TEST_CASE("Test StructuralMetadata callback for string property") {
REQUIRE(classProperty->count == std::nullopt);
REQUIRE(!classProperty->array);
view.getPropertyView(
view.getPropertyView(
"TestClassProperty",
[&expected](
const std::string& /*propertyName*/,
@ -3060,3 +3097,86 @@ TEST_CASE("Test StructuralMetadata callback for string property") {
}
});
}
TEST_CASE("Test StructuralMetadata callback for scalar array") {
Model model;
std::vector<uint32_t> values =
{12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11};
size_t valueBufferViewIndex = 0;
{
Buffer& valueBuffer = model.buffers.emplace_back();
valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t));
valueBuffer.byteLength =
static_cast<int64_t>(valueBuffer.cesium.data.size());
std::memcpy(
valueBuffer.cesium.data.data(),
values.data(),
valueBuffer.cesium.data.size());
BufferView& valueBufferView = model.bufferViews.emplace_back();
valueBufferView.buffer = static_cast<int32_t>(model.buffers.size() - 1);
valueBufferView.byteOffset = 0;
valueBufferView.byteLength = valueBuffer.byteLength;
valueBufferViewIndex = model.bufferViews.size() - 1;
}
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace();
ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"];
ExtensionExtStructuralMetadataClassProperty& testClassProperty =
testClass.properties["TestClassProperty"];
testClassProperty.type =
ExtensionExtStructuralMetadataClassProperty::Type::SCALAR;
testClassProperty.componentType =
ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32;
testClassProperty.array = true;
testClassProperty.count = 3;
ExtensionExtStructuralMetadataPropertyTable& propertyTable =
metadata.propertyTables.emplace_back();
propertyTable.classProperty = "TestClass";
propertyTable.count = static_cast<int64_t>(
values.size() / static_cast<size_t>(testClassProperty.count.value()));
ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty =
propertyTable.properties["TestClassProperty"];
propertyTableProperty.values =
static_cast<int32_t>(model.bufferViews.size() - 1);
MetadataPropertyTableView view(&model, &propertyTable);
const ExtensionExtStructuralMetadataClassProperty* classProperty =
view.getClassProperty("TestClassProperty");
REQUIRE(
classProperty->type ==
ExtensionExtStructuralMetadataClassProperty::Type::SCALAR);
REQUIRE(
classProperty->componentType ==
ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32);
REQUIRE(classProperty->array);
REQUIRE(classProperty->count == 3);
view.getPropertyView(
"TestClassProperty",
[&values](const std::string& /*propertyName*/, auto propertyValue) {
REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid);
REQUIRE(propertyValue.size() > 0);
if constexpr (std::is_same_v<
MetadataPropertyView<MetadataArrayView<uint32_t>>,
decltype(propertyValue)>) {
for (int64_t i = 0; i < propertyValue.size(); ++i) {
MetadataArrayView<uint32_t> member = propertyValue.get(i);
for (int64_t j = 0; j < member.size(); ++j) {
REQUIRE(member[j] == values[static_cast<size_t>(i * 3 + j)]);
}
}
} else {
FAIL("getPropertyView returned MetadataPropertyView of incorrect "
"type for TestClassProperty.");
}
});
}