diff --git a/.clang-tidy b/.clang-tidy index 41a81da3a..d1b048ecd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,8 +1,91 @@ --- Checks: - "-*" - - "misc-include-cleaner" - - "bugprone-implicit-widening-of-multiplication-result" + # - "misc-include-cleaner" + # - "bugprone-argument-comment" + # - "bugprone-assert-side-effect" + # - "bugprone-assignment-in-if-condition" + # - "bugprone-bad-signal-to-kill-thread" + # - "bugprone-bool-pointer-implicit-conversion" + # - "bugprone-branch-clone" + # - "bugprone-casting-through-void" + # - "bugprone-chained-comparison" + # - "bugprone-compare-pointer-to-member-virtual-function" + # - "bugprone-copy-constructor-init" + # - "bugprone-crtp-constructor-accessibility" + # - "bugprone-dangling-handle" + # - "bugprone-dynamic-static-initializers" + # - "-bugprone-easily-swappable-parameters" + # - "bugprone-empty-catch" + # - "-bugprone-exception-escape" # For now + # - "bugprone-fold-init-type" + # - "bugprone-forward-declaration-namespace" + # - "bugprone-forwarding-reference-overload" + # - "bugprone-implicit-widening-of-multiplication-result" + # - "bugprone-inaccurate-erase" + # - "bugprone-inc-dec-in-conditions" + # - "bugprone-incorrect-enable-if" + # - "bugprone-incorrect-roundings" + # - "bugprone-infinite-loop" + # - "bugprone-unhandled-self-assignment" + - "bugprone-unchecked-optional-access" + + # - "bugprone-integer-division" + # - "bugprone-lambda-function-name" + # - "bugprone-macro-parentheses" + # - "bugprone-macro-repeated-side-effects" + # - "bugprone-misplaced-operator-in-strlen-in-alloc" + # - "bugprone-misplaced-pointer-arithmetic-in-alloc" + # - "bugprone-misplaced-widening-cast" + # - "bugprone-move-forwarding-reference" + # - "bugprone-multi-level-implicit-pointer-conversion" + # - "bugprone-multiple-new-in-one-expression" + # - "bugprone-multiple-statement-macro" + # - "bugprone-no-escape" + # - "bugprone-non-zero-enum-to-bool-conversion" + # - "bugprone-not-null-terminated-result" + # - "bugprone-optional-value-conversion" + # - "bugprone-parent-virtual-call" + # - "bugprone-pointer-arithmetic-on-polymorphic-object" + # - "bugprone-posix-return" + # - "bugprone-redundant-branch-condition" + # - "bugprone-reserved-identifier" + # - "bugprone-return-const-ref-from-parameter" + # - "bugprone-shared-ptr-array-mismatch" + # - "bugprone-signal-handler" + # - "bugprone-signed-char-misuse" + # - "bugprone-sizeof-container" + # - "bugprone-sizeof-expression" + # - "bugprone-spuriously-wake-up-functions" + # - "bugprone-standalone-empty" + # - "bugprone-string-constructor" + # - "bugprone-string-integer-assignment" + # - "bugprone-string-literal-with-embedded-nul" + # - "bugprone-stringview-nullptr" + # - "bugprone-suspicious-enum-usage" + # - "bugprone-suspicious-include" + # - "bugprone-suspicious-memory-comparison" + # - "bugprone-suspicious-memset-usage" + # - "bugprone-suspicious-missing-comma" + # - "bugprone-suspicious-realloc-usage" + # - "bugprone-suspicious-semicolon" + # - "bugprone-suspicious-string-compare" + # - "bugprone-suspicious-stringview-data-usage" + # - "bugprone-swapped-arguments" + # - "bugprone-switch-missing-default-case" + # - "bugprone-terminating-continue" + # - "bugprone-throw-keyword-missing" + # - "bugprone-too-small-loop-variable" + # - "bugprone-undefined-memory-manipulation" + # - "bugprone-undelegated-constructor" + # - "bugprone-unhandled-exception-at-new" + # - "bugprone-unique-ptr-array-mismatch" + # - "bugprone-unsafe-functions" + # - "bugprone-unused-local-non-trivial-variable" + # - "bugprone-unused-raii" + # - "bugprone-unused-return-value" + # - "bugprone-use-after-move" + # - "bugprone-virtual-near-miss" WarningsAsErrors: "*" FormatStyle: none diff --git a/Cesium3DTiles/test/TestMetadataQuery.cpp b/Cesium3DTiles/test/TestMetadataQuery.cpp index f216ff373..e9bac6ae7 100644 --- a/Cesium3DTiles/test/TestMetadataQuery.cpp +++ b/Cesium3DTiles/test/TestMetadataQuery.cpp @@ -53,6 +53,9 @@ TEST_CASE("MetadataQuery") { withSemantic, "SOME_SEMANTIC"); REQUIRE(foundProperty2); + if (!foundProperty2) { + return; + } CHECK(foundProperty2->classIdentifier == "someClass"); CHECK(&foundProperty2->classDefinition == &classDefinition); CHECK(foundProperty2->propertyIdentifier == "somePropertyWithSemantic"); diff --git a/Cesium3DTilesContent/src/B3dmToGltfConverter.cpp b/Cesium3DTilesContent/src/B3dmToGltfConverter.cpp index 63fb76dd9..46ccbc434 100644 --- a/Cesium3DTilesContent/src/B3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/src/B3dmToGltfConverter.cpp @@ -164,20 +164,22 @@ rapidjson::Document parseFeatureTableJsonData( return document; } - const auto rtcIt = document.FindMember("RTC_CENTER"); - if (rtcIt != document.MemberEnd() && rtcIt->value.IsArray() && - rtcIt->value.Size() == 3 && rtcIt->value[0].IsNumber() && - rtcIt->value[1].IsNumber() && rtcIt->value[2].IsNumber()) { - // Add the RTC_CENTER value to the glTF as a CESIUM_RTC extension. - rapidjson::Value& rtcValue = rtcIt->value; - auto& cesiumRTC = - result.model->addExtension(); - result.model->addExtensionRequired( - CesiumGltf::ExtensionCesiumRTC::ExtensionName); - cesiumRTC.center = { - rtcValue[0].GetDouble(), - rtcValue[1].GetDouble(), - rtcValue[2].GetDouble()}; + if (result.model) { + const auto rtcIt = document.FindMember("RTC_CENTER"); + if (rtcIt != document.MemberEnd() && rtcIt->value.IsArray() && + rtcIt->value.Size() == 3 && rtcIt->value[0].IsNumber() && + rtcIt->value[1].IsNumber() && rtcIt->value[2].IsNumber()) { + // Add the RTC_CENTER value to the glTF as a CESIUM_RTC extension. + rapidjson::Value& rtcValue = rtcIt->value; + auto& cesiumRTC = + result.model->addExtension(); + result.model->addExtensionRequired( + CesiumGltf::ExtensionCesiumRTC::ExtensionName); + cesiumRTC.center = { + rtcValue[0].GetDouble(), + rtcValue[1].GetDouble(), + rtcValue[2].GetDouble()}; + } } return document; diff --git a/Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp index fea071580..88c8a9eb7 100644 --- a/Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesContent/src/BatchTableToGltfStructuralMetadata.cpp @@ -67,7 +67,7 @@ struct MaskedType { bool isFloat64; bool isBool; - MaskedType() : MaskedType(true){}; + MaskedType() : MaskedType(true) {}; MaskedType(bool defaultValue) : isInt8(defaultValue), @@ -123,12 +123,12 @@ struct MaskedArrayType { uint32_t minArrayCount; uint32_t maxArrayCount; - MaskedArrayType() : MaskedArrayType(true){}; + MaskedArrayType() : MaskedArrayType(true) {}; MaskedArrayType(bool defaultValue) : elementType(defaultValue), minArrayCount(std::numeric_limits::max()), - maxArrayCount(std::numeric_limits::min()){}; + maxArrayCount(std::numeric_limits::min()) {}; MaskedArrayType( MaskedType inElementType, @@ -197,10 +197,10 @@ struct CompatibleTypes { bool _canUseNullStringSentinel = true; public: - CompatibleTypes() : _type(){}; - CompatibleTypes(const MaskedType& maskedType) : _type(maskedType){}; + CompatibleTypes() : _type() {}; + CompatibleTypes(const MaskedType& maskedType) : _type(maskedType) {}; CompatibleTypes(const MaskedArrayType& maskedArrayType) - : _type(maskedArrayType){}; + : _type(maskedArrayType) {}; /** * Whether this is exclusively compatible with array types. This indicates an @@ -732,7 +732,8 @@ void updateExtensionWithJsonStringProperty( // Because serialized string json will add double quotations in the // buffer which is not needed by us, we will manually add the string to // the buffer - const auto& rapidjsonStr = it->IsNull() ? *noDataValue : it->GetString(); + const auto& rapidjsonStr = + it->IsNull() && noDataValue ? *noDataValue : it->GetString(); rapidjsonStrBuffer.Reserve(it->GetStringLength()); for (rapidjson::SizeType j = 0; j < it->GetStringLength(); ++j) { rapidjsonStrBuffer.PutUnsafe(rapidjsonStr[j]); @@ -814,7 +815,7 @@ void updateExtensionWithJsonScalarProperty( } for (int64_t i = 0; i < propertyTable.count; ++i, ++p, ++it) { - if (it->IsNull()) { + if (it->IsNull() && noDataValue) { *p = *noDataValue; } else { *p = static_cast(it->template Get()); diff --git a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp index 609f53d68..7f38c6b2f 100644 --- a/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/src/I3dmToGltfConverter.cpp @@ -364,7 +364,7 @@ CesiumAsync::Future convertI3dmContent( pBinaryData + *parsedContent.position), numInstances); decodedInstances.positions.assign(rawPositions.begin(), rawPositions.end()); - } else { + } else if (parsedContent.positionQuantized) { gsl::span rawQuantizedPositions( reinterpret_cast( pBinaryData + *parsedContent.positionQuantized), diff --git a/Cesium3DTilesContent/src/PntsToGltfConverter.cpp b/Cesium3DTilesContent/src/PntsToGltfConverter.cpp index 1bd8c68dd..38ac30ea2 100644 --- a/Cesium3DTilesContent/src/PntsToGltfConverter.cpp +++ b/Cesium3DTilesContent/src/PntsToGltfConverter.cpp @@ -1148,8 +1148,10 @@ void parsePositionsFromFeatureTableBinary( featureTableBinaryData.data() + parsedContent.position.byteOffset), pointsLength); + // NOLINTBEGIN(bugprone-unchecked-optional-access) const glm::vec3 quantizedVolumeScale(*parsedContent.quantizedVolumeScale); const glm::vec3 quantizedVolumeOffset(*parsedContent.quantizedVolumeOffset); + // NOLINTEND(bugprone-unchecked-optional-access) const glm::vec3 quantizedPositionScalar = quantizedVolumeScale / 65535.0f; @@ -1186,6 +1188,7 @@ void parsePositionsFromFeatureTableBinary( void parseColorsFromFeatureTableBinary( const gsl::span& featureTableBinaryData, PntsContent& parsedContent) { + CESIUM_ASSERT(parsedContent.color); PntsSemantic& color = *parsedContent.color; std::vector& colorData = color.data; if (colorData.size() > 0) { @@ -1248,6 +1251,7 @@ void parseColorsFromFeatureTableBinary( void parseNormalsFromFeatureTableBinary( const gsl::span& featureTableBinaryData, PntsContent& parsedContent) { + CESIUM_ASSERT(parsedContent.normal); PntsSemantic& normal = *parsedContent.normal; std::vector& normalData = normal.data; if (normalData.size() > 0) { @@ -1287,6 +1291,7 @@ void parseNormalsFromFeatureTableBinary( void parseBatchIdsFromFeatureTableBinary( const gsl::span& featureTableBinaryData, PntsContent& parsedContent) { + CESIUM_ASSERT(parsedContent.batchId); PntsSemantic& batchId = *parsedContent.batchId; std::vector& batchIdData = batchId.data; if (batchIdData.size() > 0) { @@ -1410,6 +1415,7 @@ void addPositionsToGltf(PntsContent& parsedContent, Model& gltf) { } void addColorsToGltf(PntsContent& parsedContent, Model& gltf) { + CESIUM_ASSERT(parsedContent.color); PntsSemantic& color = *parsedContent.color; const int64_t count = static_cast(parsedContent.pointsLength); @@ -1445,6 +1451,7 @@ void addColorsToGltf(PntsContent& parsedContent, Model& gltf) { } void addNormalsToGltf(PntsContent& parsedContent, Model& gltf) { + CESIUM_ASSERT(parsedContent.normal); PntsSemantic& normal = *parsedContent.normal; const int64_t count = static_cast(parsedContent.pointsLength); diff --git a/Cesium3DTilesContent/test/TestB3dmToGltfConverter.cpp b/Cesium3DTilesContent/test/TestB3dmToGltfConverter.cpp index 79f59a093..7de9e9eb5 100644 --- a/Cesium3DTilesContent/test/TestB3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/test/TestB3dmToGltfConverter.cpp @@ -24,6 +24,9 @@ TEST_CASE("B3dmToGltfConverter") { GltfConverterResult result = ConvertTileToGltf::fromB3dm(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; REQUIRE(gltf.getExtension() != nullptr); @@ -38,6 +41,9 @@ TEST_CASE("B3dmToGltfConverter") { GltfConverterResult result = ConvertTileToGltf::fromB3dm(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(!gltf.meshes.empty()); diff --git a/Cesium3DTilesContent/test/TestI3dmToGltfConverter.cpp b/Cesium3DTilesContent/test/TestI3dmToGltfConverter.cpp index 96b6e0947..520aea45b 100644 --- a/Cesium3DTilesContent/test/TestI3dmToGltfConverter.cpp +++ b/Cesium3DTilesContent/test/TestI3dmToGltfConverter.cpp @@ -22,6 +22,9 @@ TEST_CASE("I3dmToGltfConverter") { GltfConverterResult result = ConvertTileToGltf::fromI3dm(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } CHECK(result.model->isExtensionUsed( ExtensionExtMeshGpuInstancing::ExtensionName)); CHECK(result.model->isExtensionRequired( @@ -48,6 +51,9 @@ TEST_CASE("I3dmToGltfConverter") { GltfConverterResult result = ConvertTileToGltf::fromI3dm(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } CHECK(result.model->isExtensionUsed( ExtensionExtMeshGpuInstancing::ExtensionName)); CHECK(result.model->isExtensionRequired( diff --git a/Cesium3DTilesContent/test/TestImplicitTilingUtilities.cpp b/Cesium3DTilesContent/test/TestImplicitTilingUtilities.cpp index 90ccbff1b..feb56aecd 100644 --- a/Cesium3DTilesContent/test/TestImplicitTilingUtilities.cpp +++ b/Cesium3DTilesContent/test/TestImplicitTilingUtilities.cpp @@ -492,6 +492,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { std::optional maybeBox = TileBoundingVolumes::getOrientedBoundingBox(l1x0y0); REQUIRE(maybeBox); + + if (!maybeBox) { + return; + } + CHECK(maybeBox->getCenter() == glm::dvec3(-4.0, -3.0, 3.0)); CHECK(maybeBox->getLengths() == glm::dvec3(10.0, 10.0, 20.0)); @@ -502,6 +507,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { std::optional maybeRegion = TileBoundingVolumes::getBoundingRegion(l1x1y0, Ellipsoid::WGS84); REQUIRE(maybeRegion); + + if (!maybeRegion) { + return; + } + CHECK(maybeRegion->getRectangle().getWest() == 2.0); CHECK(maybeRegion->getRectangle().getSouth() == 2.0); CHECK(maybeRegion->getRectangle().getEast() == 3.0); @@ -518,6 +528,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { l1x0y1, Ellipsoid::WGS84); REQUIRE(maybeS2); + + if (!maybeS2) { + return; + } + CHECK(maybeS2->getCellID().getFace() == 1); CHECK( maybeS2->getCellID().getID() == @@ -554,6 +569,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { std::optional maybeBox = TileBoundingVolumes::getOrientedBoundingBox(l1x0y0); REQUIRE(maybeBox); + + if (!maybeBox) { + return; + } + CHECK(maybeBox->getCenter() == glm::dvec3(-4.0, -3.0, -2.0)); CHECK(maybeBox->getLengths() == glm::dvec3(10.0, 10.0, 10.0)); @@ -564,6 +584,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { std::optional maybeRegion = TileBoundingVolumes::getBoundingRegion(l1x1y0, Ellipsoid::WGS84); REQUIRE(maybeRegion); + + if (!maybeRegion) { + return; + } + CHECK(maybeRegion->getRectangle().getWest() == 2.0); CHECK(maybeRegion->getRectangle().getSouth() == 2.0); CHECK(maybeRegion->getRectangle().getEast() == 3.0); @@ -580,6 +605,11 @@ TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") { l1x0y1, Ellipsoid::WGS84); REQUIRE(maybeS2); + + if (!maybeS2) { + return; + } + CHECK(maybeS2->getCellID().getFace() == 1); CHECK( maybeS2->getCellID().getID() == diff --git a/Cesium3DTilesContent/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesContent/test/TestPntsToGltfConverter.cpp index bbe8319ee..e227f5eab 100644 --- a/Cesium3DTilesContent/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesContent/test/TestPntsToGltfConverter.cpp @@ -153,6 +153,9 @@ TEST_CASE("Converts simple point cloud to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.asset.version == "2.0"); @@ -264,6 +267,9 @@ TEST_CASE("Converts point cloud with RGBA to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -329,6 +335,9 @@ TEST_CASE("Converts point cloud with RGB to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -394,6 +403,9 @@ TEST_CASE("Converts point cloud with RGB565 to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -457,6 +469,9 @@ TEST_CASE("Converts point cloud with CONSTANT_RGBA") { const int32_t pointsLength = 8; REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -482,6 +497,9 @@ TEST_CASE("Converts point cloud with CONSTANT_RGBA") { REQUIRE(gltf.materials.size() == 1); Material& material = gltf.materials[0]; REQUIRE(material.pbrMetallicRoughness); + if (!material.pbrMetallicRoughness) { + return; + } MaterialPBRMetallicRoughness& pbrMetallicRoughness = *material.pbrMetallicRoughness; const auto& baseColorFactor = pbrMetallicRoughness.baseColorFactor; @@ -508,6 +526,9 @@ TEST_CASE("Converts point cloud with quantized positions to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(!gltf.hasExtension()); @@ -584,6 +605,9 @@ TEST_CASE("Converts point cloud with normals to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -650,6 +674,9 @@ TEST_CASE("Converts point cloud with oct-encoded normals to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -726,6 +753,9 @@ TEST_CASE("Converts point cloud with batch IDs to glTF with " GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in @@ -806,6 +836,9 @@ TEST_CASE("Converts point cloud with per-point properties to glTF with " GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in @@ -865,6 +898,9 @@ TEST_CASE("Converts point cloud with Draco compression to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -1015,6 +1051,10 @@ TEST_CASE("Converts point cloud with partial Draco compression to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } + Model& gltf = *result.model; CHECK(gltf.hasExtension()); @@ -1157,6 +1197,9 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in diff --git a/Cesium3DTilesContent/test/TestSkirtMeshMetadata.cpp b/Cesium3DTilesContent/test/TestSkirtMeshMetadata.cpp index f47f8a641..3b7115fcc 100644 --- a/Cesium3DTilesContent/test/TestSkirtMeshMetadata.cpp +++ b/Cesium3DTilesContent/test/TestSkirtMeshMetadata.cpp @@ -87,39 +87,45 @@ TEST_CASE("Test converting gltf extras to skirt mesh metadata") { SECTION("Gltf Extras has correct format") { JsonValue::Object extras = {{"skirtMeshMetadata", gltfSkirtMeshMetadata}}; - SkirtMeshMetadata skirtMeshMetadata = - *SkirtMeshMetadata::parseFromGltfExtras(extras); + std::optional skirtMeshMetadata = + SkirtMeshMetadata::parseFromGltfExtras(extras); - REQUIRE(skirtMeshMetadata.noSkirtIndicesBegin == 0); - REQUIRE(skirtMeshMetadata.noSkirtIndicesCount == 12); - REQUIRE(skirtMeshMetadata.noSkirtVerticesBegin == 24); - REQUIRE(skirtMeshMetadata.noSkirtVerticesCount == 48); + REQUIRE(skirtMeshMetadata); + + if (!skirtMeshMetadata) { + return; + } + + REQUIRE(skirtMeshMetadata->noSkirtIndicesBegin == 0); + REQUIRE(skirtMeshMetadata->noSkirtIndicesCount == 12); + REQUIRE(skirtMeshMetadata->noSkirtVerticesBegin == 24); + REQUIRE(skirtMeshMetadata->noSkirtVerticesCount == 48); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.meshCenter.x, + skirtMeshMetadata->meshCenter.x, 1.0, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.meshCenter.y, + skirtMeshMetadata->meshCenter.y, 2.0, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.meshCenter.z, + skirtMeshMetadata->meshCenter.z, 3.0, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.skirtWestHeight, + skirtMeshMetadata->skirtWestHeight, 12.4, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.skirtSouthHeight, + skirtMeshMetadata->skirtSouthHeight, 10.0, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.skirtEastHeight, + skirtMeshMetadata->skirtEastHeight, 2.4, Math::Epsilon7)); REQUIRE(Math::equalsEpsilon( - skirtMeshMetadata.skirtNorthHeight, + skirtMeshMetadata->skirtNorthHeight, 1.4, Math::Epsilon7)); } diff --git a/Cesium3DTilesContent/test/TestSubtreeAvailability.cpp b/Cesium3DTilesContent/test/TestSubtreeAvailability.cpp index 457c31e97..52db3b58d 100644 --- a/Cesium3DTilesContent/test/TestSubtreeAvailability.cpp +++ b/Cesium3DTilesContent/test/TestSubtreeAvailability.cpp @@ -590,7 +590,10 @@ TEST_CASE("Test parsing subtree format") { asyncSystem.dispatchMainThreadTasks(); auto parsedSubtree = subtreeFuture.wait(); - REQUIRE(parsedSubtree != std::nullopt); + REQUIRE(parsedSubtree); + if (!parsedSubtree) { + return; + } for (const auto& tileID : availableTileIDs) { uint64_t mortonID = libmorton::morton2D_64_encode(tileID.x, tileID.y); @@ -623,7 +626,10 @@ TEST_CASE("Test parsing subtree format") { std::move(subtreeBuffers), std::move(subtreeJson)); - REQUIRE(parsedSubtree != std::nullopt); + REQUIRE(parsedSubtree); + if (!parsedSubtree) { + return; + } for (const auto& tileID : availableTileIDs) { uint64_t mortonID = libmorton::morton2D_64_encode(tileID.x, tileID.y); @@ -729,6 +735,9 @@ TEST_CASE("SubtreeAvailability modifications") { ImplicitTileSubdivisionScheme::Quadtree, 5); REQUIRE(maybeAvailability); + if (!maybeAvailability) { + return; + } SubtreeAvailability& availability = *maybeAvailability; diff --git a/Cesium3DTilesContent/test/TestTileBoundingVolumes.cpp b/Cesium3DTilesContent/test/TestTileBoundingVolumes.cpp index e02dc23aa..72c1e819d 100644 --- a/Cesium3DTilesContent/test/TestTileBoundingVolumes.cpp +++ b/Cesium3DTilesContent/test/TestTileBoundingVolumes.cpp @@ -34,6 +34,9 @@ TEST_CASE("TileBoundingVolumes") { std::optional box = TileBoundingVolumes::getOrientedBoundingBox(bv); REQUIRE(box); + if (!box) { + return; + } CHECK(box->getCenter().x == Catch::Approx(0.0)); CHECK(box->getCenter().y == Catch::Approx(0.0)); @@ -56,6 +59,9 @@ TEST_CASE("TileBoundingVolumes") { std::optional sphere = TileBoundingVolumes::getBoundingSphere(bv); REQUIRE(sphere); + if (!sphere) { + return; + } CHECK(sphere->getCenter().x == Catch::Approx(0.0)); CHECK(sphere->getCenter().y == Catch::Approx(0.0)); @@ -82,6 +88,9 @@ TEST_CASE("TileBoundingVolumes") { std::optional region = TileBoundingVolumes::getBoundingRegion(bv, Ellipsoid::WGS84); REQUIRE(region); + if (!region) { + return; + } CHECK( region->getRectangle().getWest() == Catch::Approx(-1.3197004795898053)); @@ -110,6 +119,9 @@ TEST_CASE("TileBoundingVolumes") { std::optional s2 = TileBoundingVolumes::getS2CellBoundingVolume(bv, Ellipsoid::WGS84); REQUIRE(s2); + if (!s2) { + return; + } CHECK(s2->getCellID().getID() == S2CellID::fromToken("89c6c7").getID()); CHECK(s2->getMinimumHeight() == Catch::Approx(0.0)); diff --git a/Cesium3DTilesContent/test/TestTileTransform.cpp b/Cesium3DTilesContent/test/TestTileTransform.cpp index ed98cd2f4..5ccea2efa 100644 --- a/Cesium3DTilesContent/test/TestTileTransform.cpp +++ b/Cesium3DTilesContent/test/TestTileTransform.cpp @@ -32,6 +32,9 @@ TEST_CASE("TileTransform::getTransform") { std::optional maybeTransform = Cesium3DTilesContent::TileTransform::getTransform(tile); REQUIRE(maybeTransform); + if (!maybeTransform) { + return; + } const glm::dmat4& transform = *maybeTransform; CHECK(Math::equalsEpsilon( transform[0], @@ -97,6 +100,9 @@ TEST_CASE("TileTransform::getTransform") { std::optional maybeTransform = Cesium3DTilesContent::TileTransform::getTransform(tile); REQUIRE(maybeTransform); + if (!maybeTransform) { + return; + } const glm::dmat4& transform = *maybeTransform; CHECK(Math::equalsEpsilon( transform[0], diff --git a/Cesium3DTilesContent/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesContent/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index afbcf982b..5ee7aa92e 100644 --- a/Cesium3DTilesContent/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesContent/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -205,6 +205,9 @@ static void createTestForNonArrayJson( const std::optional schema = pMetadata->schema; REQUIRE(schema); + if (!schema) { + return; + } const std::unordered_map& classes = schema->classes; REQUIRE(classes.size() == 1); diff --git a/Cesium3DTilesReader/test/TestTilesetReader.cpp b/Cesium3DTilesReader/test/TestTilesetReader.cpp index 8ddea9a21..6c5691c11 100644 --- a/Cesium3DTilesReader/test/TestTilesetReader.cpp +++ b/Cesium3DTilesReader/test/TestTilesetReader.cpp @@ -26,8 +26,24 @@ TEST_CASE("Reads tileset JSON") { auto result = reader.readFromJson(data); REQUIRE(result.value); + if (!result.value) { + return; + } + const Cesium3DTiles::Tileset& tileset = *result.value; + REQUIRE(tileset.root.content); + + if (!tileset.root.content) { + return; + } + + REQUIRE(tileset.root.content->boundingVolume); + + if (!tileset.root.content->boundingVolume) { + return; + } + REQUIRE(tileset.asset.version == "1.0"); REQUIRE(tileset.geometricError == 494.50961650991815); REQUIRE(tileset.extensionsUsed.size() == 0); @@ -40,7 +56,6 @@ TEST_CASE("Reads tileset JSON") { CHECK(tileset.properties.at("Latitude").maximum == 0.899060112939701); CHECK(tileset.properties.at("Height").minimum == 1.0); CHECK(tileset.properties.at("Height").maximum == 241.6); - CHECK(tileset.root.content->uri == "0/0/0.b3dm"); CHECK(tileset.root.geometricError == 268.37878244706053); CHECK(tileset.root.refine == Cesium3DTiles::Tile::Refine::ADD); @@ -90,6 +105,18 @@ TEST_CASE("Reads tileset JSON") { const Cesium3DTiles::Tile& child = tileset.root.children[0]; + REQUIRE(child.content); + + if (!child.content) { + return; + } + + REQUIRE(child.content->boundingVolume); + + if (!child.content->boundingVolume) { + return; + } + REQUIRE_THAT( child.boundingVolume.region, Catch::Matchers::Approx(expectedChildRegion)); @@ -140,6 +167,9 @@ TEST_CASE("Reads extras") { REQUIRE(result.errors.empty()); REQUIRE(result.warnings.empty()); REQUIRE(result.value); + if (!result.value) { + return; + } Cesium3DTiles::Tileset& tileset = *result.value; @@ -218,6 +248,9 @@ TEST_CASE("Reads 3DTILES_content_gltf") { REQUIRE(result.errors.empty()); REQUIRE(result.warnings.empty()); REQUIRE(result.value); + if (!result.value) { + return; + } Cesium3DTiles::Tileset& tileset = *result.value; CHECK(tileset.asset.version == "1.0"); @@ -267,6 +300,9 @@ TEST_CASE("Reads custom extension") { gsl::span(reinterpret_cast(s.c_str()), s.size())); REQUIRE(withCustomExt.errors.empty()); REQUIRE(withCustomExt.value); + if (!withCustomExt.value) { + return; + } REQUIRE(withCustomExt.value->extensions.size() == 2); @@ -292,6 +328,10 @@ TEST_CASE("Reads custom extension") { auto withoutCustomExt = reader.readFromJson( gsl::span(reinterpret_cast(s.c_str()), s.size())); + REQUIRE(withoutCustomExt.value); + if (!withoutCustomExt.value) { + return; + } auto& zeroExtensions = withoutCustomExt.value->extensions; REQUIRE(zeroExtensions.empty()); @@ -309,7 +349,9 @@ TEST_CASE("Reads tileset JSON with unknown properties") { CHECK(result.errors.empty()); CHECK(result.warnings.empty()); REQUIRE(result.value); - + if (!result.value) { + return; + } const CesiumUtility::JsonValue::Object& unknownProperties = result.value->asset.unknownProperties; @@ -375,6 +417,9 @@ TEST_CASE("Reads tileset JSON with unknown properties and ignores them when " CHECK(result.errors.empty()); CHECK(result.warnings.empty()); REQUIRE(result.value); + if (!result.value) { + return; + } const CesiumUtility::JsonValue::Object& unknownProperties = result.value->asset.unknownProperties; diff --git a/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp b/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp index 1d236a34d..34482c96c 100644 --- a/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp +++ b/Cesium3DTilesSelection/test/TestTilesetContentManager.cpp @@ -901,7 +901,10 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { { CHECK(modelReadResult.errors.empty()); CHECK(modelReadResult.warnings.empty()); - CHECK(modelReadResult.model); + REQUIRE(modelReadResult.model); + if (!modelReadResult.model) { + return; + } const auto& buffers = modelReadResult.model->buffers; CHECK(buffers.size() == 1); @@ -973,7 +976,10 @@ TEST_CASE("Test the tileset content manager's post processing for gltf") { readFile(testDataPath / "gltf" / "embedded_box" / "Box.glb"); auto modelReadResult = gltfReader.readGltf(gltfBoxFile); CHECK(modelReadResult.errors.empty()); - CHECK(modelReadResult.model); + REQUIRE(modelReadResult.model); + if (!modelReadResult.model) { + return; + } // retrieve expected accessor index and remove normal attribute CesiumGltf::Mesh& prevMesh = modelReadResult.model->meshes.front(); diff --git a/Cesium3DTilesSelection/test/TestTilesetJsonLoader.cpp b/Cesium3DTilesSelection/test/TestTilesetJsonLoader.cpp index 1ba2d97b9..404919bd0 100644 --- a/Cesium3DTilesSelection/test/TestTilesetJsonLoader.cpp +++ b/Cesium3DTilesSelection/test/TestTilesetJsonLoader.cpp @@ -453,6 +453,9 @@ TEST_CASE("Test creating tileset json loader") { const TilesetMetadata& metadata = pExternal->metadata; const std::optional& schema = metadata.schema; REQUIRE(schema); + if (!schema) { + return; + } CHECK(schema->id == "foo"); } } diff --git a/Cesium3DTilesSelection/test/TestTilesetSelectionAlgorithm.cpp b/Cesium3DTilesSelection/test/TestTilesetSelectionAlgorithm.cpp index 27d79ba4a..f58cad740 100644 --- a/Cesium3DTilesSelection/test/TestTilesetSelectionAlgorithm.cpp +++ b/Cesium3DTilesSelection/test/TestTilesetSelectionAlgorithm.cpp @@ -1169,6 +1169,9 @@ TEST_CASE("Makes metadata available once root tile is loaded") { const TilesetMetadata& metadata = pExternal->metadata; const std::optional& schema = metadata.schema; REQUIRE(schema); + if (!schema) { + return; + } CHECK(schema->id == "foo"); } @@ -1282,12 +1285,19 @@ TEST_CASE("Allows access to material variants") { REQUIRE(pMetadata->schema); REQUIRE(pMetadata->metadata); + if (!pMetadata->schema || !pMetadata->metadata) { + return; + } + std::optional found1 = Cesium3DTiles::MetadataQuery::findFirstPropertyWithSemantic( *pMetadata->schema, *pMetadata->metadata, "MATERIAL_VARIANTS"); REQUIRE(found1); + if (!found1) { + return; + } CHECK(found1->classIdentifier == "MaterialVariants"); CHECK(found1->classDefinition.properties.size() == 1); CHECK(found1->propertyIdentifier == "material_variants"); diff --git a/Cesium3DTilesWriter/test/TestTilesetWriter.cpp b/Cesium3DTilesWriter/test/TestTilesetWriter.cpp index a834971d6..46c2218d0 100644 --- a/Cesium3DTilesWriter/test/TestTilesetWriter.cpp +++ b/Cesium3DTilesWriter/test/TestTilesetWriter.cpp @@ -20,6 +20,9 @@ void check(const std::string& input, const std::string& expectedOutput) { REQUIRE(readResult.errors.empty()); REQUIRE(readResult.warnings.empty()); REQUIRE(readResult.value); + if (!readResult.value) { + return; + } Cesium3DTiles::Tileset& tileset = *readResult.value; diff --git a/CesiumAsync/src/ResponseCacheControl.h b/CesiumAsync/src/ResponseCacheControl.h index 8d30ebbcf..d2de61208 100644 --- a/CesiumAsync/src/ResponseCacheControl.h +++ b/CesiumAsync/src/ResponseCacheControl.h @@ -88,7 +88,10 @@ class ResponseCacheControl { /** * @brief Value of Max-Age directive that appears in the Cache-Control header. */ - int maxAgeValue() const noexcept { return *_maxAge; } + int maxAgeValue() const noexcept { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + return *_maxAge; + } /** * @brief Existence of S-Maxage directive that appears in the Cache-Control @@ -100,7 +103,10 @@ class ResponseCacheControl { * @brief Value of S-Maxage directive that appears in the Cache-Control * header. */ - int sharedMaxAgeValue() const noexcept { return *_sharedMaxAge; } + int sharedMaxAgeValue() const noexcept { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + return *_sharedMaxAge; + } /** * @brief Existence of Stale-While-Revalidate directive that appears in the @@ -115,6 +121,7 @@ class ResponseCacheControl { * Cache-Control header. */ int staleWhileRevalidateValue() const noexcept { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) return *_staleWhileRevalidate; } diff --git a/CesiumAsync/test/TestCacheAssetAccessor.cpp b/CesiumAsync/test/TestCacheAssetAccessor.cpp index bdf395062..0034cc620 100644 --- a/CesiumAsync/test/TestCacheAssetAccessor.cpp +++ b/CesiumAsync/test/TestCacheAssetAccessor.cpp @@ -556,7 +556,11 @@ TEST_CASE("Test calculation of expiry time for the cached response") { ->get(asyncSystem, "test.com", std::vector{}) .wait(); REQUIRE(mockCacheDatabase->storeResponseCall == true); - REQUIRE( + REQUIRE(mockCacheDatabase->storeRequestParam); + if (!mockCacheDatabase->storeRequestParam) { + return; + } + CHECK( mockCacheDatabase->storeRequestParam->expiryTime - std::time(nullptr) == 400); } @@ -593,8 +597,12 @@ TEST_CASE("Test calculation of expiry time for the cached response") { cacheAssetAccessor ->get(asyncSystem, "test.com", std::vector{}) .wait(); - REQUIRE(mockCacheDatabase->storeResponseCall == true); - REQUIRE(mockCacheDatabase->storeRequestParam->expiryTime == 2139722880); + CHECK(mockCacheDatabase->storeResponseCall == true); + REQUIRE(mockCacheDatabase->storeRequestParam); + if (!mockCacheDatabase->storeRequestParam) { + return; + } + CHECK(mockCacheDatabase->storeRequestParam->expiryTime == 2139722880); } } diff --git a/CesiumAsync/test/TestDiskCache.cpp b/CesiumAsync/test/TestDiskCache.cpp index 3dc193c5f..4e0509d58 100644 --- a/CesiumAsync/test/TestDiskCache.cpp +++ b/CesiumAsync/test/TestDiskCache.cpp @@ -58,6 +58,12 @@ TEST_CASE("Test disk cache with Sqlite") { request->response()->data())); std::optional cacheItem = diskCache.getEntry("TestKey"); + REQUIRE(cacheItem); + + if (!cacheItem) { + return; + } + REQUIRE(cacheItem->expiryTime == currentTime); const CacheRequest& cacheRequest = cacheItem->cacheRequest; @@ -139,7 +145,11 @@ TEST_CASE("Test disk cache with Sqlite") { for (int i = 17; i < 20; ++i) { std::optional cacheItem = diskCache.getEntry("TestKey" + std::to_string(i)); - REQUIRE(cacheItem != std::nullopt); + REQUIRE(cacheItem); + + if (!cacheItem) { + return; + } // make sure the item is still in there REQUIRE(cacheItem->expiryTime == currentTime + interval + i); @@ -169,6 +179,9 @@ TEST_CASE("Test disk cache with Sqlite") { std::optional cacheControl = ResponseCacheControl::parseFromResponseHeaders(cacheResponse.headers); REQUIRE(cacheControl); + if (!cacheControl) { + return; + } REQUIRE(cacheControl->mustRevalidate() == true); REQUIRE(cacheControl->noCache() == false); REQUIRE(cacheControl->noStore() == true); diff --git a/CesiumAsync/test/TestResponseCacheControl.cpp b/CesiumAsync/test/TestResponseCacheControl.cpp index 7a8b1e6b0..bc77c4d1a 100644 --- a/CesiumAsync/test/TestResponseCacheControl.cpp +++ b/CesiumAsync/test/TestResponseCacheControl.cpp @@ -28,18 +28,23 @@ TEST_CASE("Test parsing cache-control header") { std::optional cacheControl = ResponseCacheControl::parseFromResponseHeaders(responseHeader); - REQUIRE(cacheControl != std::nullopt); - REQUIRE(cacheControl->mustRevalidate()); - REQUIRE(cacheControl->noCache()); - REQUIRE(cacheControl->noStore()); - REQUIRE(cacheControl->noTransform()); - REQUIRE(cacheControl->accessControlPublic()); - REQUIRE(cacheControl->accessControlPrivate()); - REQUIRE(cacheControl->proxyRevalidate()); - REQUIRE(cacheControl->maxAgeExists() == true); - REQUIRE(cacheControl->maxAgeValue() == 1000); - REQUIRE(cacheControl->sharedMaxAgeExists() == true); - REQUIRE(cacheControl->sharedMaxAgeValue() == 10); + REQUIRE(cacheControl); + + if (!cacheControl) { + return; + } + + CHECK(cacheControl->mustRevalidate()); + CHECK(cacheControl->noCache()); + CHECK(cacheControl->noStore()); + CHECK(cacheControl->noTransform()); + CHECK(cacheControl->accessControlPublic()); + CHECK(cacheControl->accessControlPrivate()); + CHECK(cacheControl->proxyRevalidate()); + CHECK(cacheControl->maxAgeExists() == true); + CHECK(cacheControl->maxAgeValue() == 1000); + CHECK(cacheControl->sharedMaxAgeExists() == true); + CHECK(cacheControl->sharedMaxAgeValue() == 10); } SECTION("Header has cache-control header with only some directive") { @@ -51,17 +56,22 @@ TEST_CASE("Test parsing cache-control header") { std::optional cacheControl = ResponseCacheControl::parseFromResponseHeaders(responseHeader); - REQUIRE(cacheControl != std::nullopt); - REQUIRE(cacheControl->mustRevalidate()); - REQUIRE(cacheControl->noCache()); - REQUIRE(cacheControl->noStore()); - REQUIRE(cacheControl->noTransform() == false); - REQUIRE(cacheControl->accessControlPublic()); - REQUIRE(cacheControl->accessControlPrivate()); - REQUIRE(cacheControl->proxyRevalidate() == false); - REQUIRE(cacheControl->maxAgeExists() == true); - REQUIRE(cacheControl->maxAgeValue() == 1000); - REQUIRE(cacheControl->sharedMaxAgeExists() == true); - REQUIRE(cacheControl->sharedMaxAgeValue() == 10); + REQUIRE(cacheControl); + + if (!cacheControl) { + return; + } + + CHECK(cacheControl->mustRevalidate()); + CHECK(cacheControl->noCache()); + CHECK(cacheControl->noStore()); + CHECK(cacheControl->noTransform() == false); + CHECK(cacheControl->accessControlPublic()); + CHECK(cacheControl->accessControlPrivate()); + CHECK(cacheControl->proxyRevalidate() == false); + CHECK(cacheControl->maxAgeExists() == true); + CHECK(cacheControl->maxAgeValue() == 1000); + CHECK(cacheControl->sharedMaxAgeExists() == true); + CHECK(cacheControl->sharedMaxAgeValue() == 10); } } diff --git a/CesiumGeometry/include/CesiumGeometry/Availability.h b/CesiumGeometry/include/CesiumGeometry/Availability.h index 420d61948..ad7969114 100644 --- a/CesiumGeometry/include/CesiumGeometry/Availability.h +++ b/CesiumGeometry/include/CesiumGeometry/Availability.h @@ -96,13 +96,17 @@ class CESIUMGEOMETRY_API AvailabilityAccessor { * @brief Unsafe is isBufferView is false. */ const gsl::span& getBufferAccessor() const { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) return *bufferAccessor; } /** * @brief Unsafe if isBufferView is false. */ - const std::byte& operator[](size_t i) const { return (*bufferAccessor)[i]; } + const std::byte& operator[](size_t i) const { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + return (*bufferAccessor)[i]; + } /** * @brief Unsafe if isBufferView is false; diff --git a/CesiumGeometry/test/TestIntersectionTests.cpp b/CesiumGeometry/test/TestIntersectionTests.cpp index f3bea6ca0..fd4cf53f6 100644 --- a/CesiumGeometry/test/TestIntersectionTests.cpp +++ b/CesiumGeometry/test/TestIntersectionTests.cpp @@ -281,6 +281,14 @@ TEST_CASE("IntersectionTests::rayOBB") { testCase.xHalf, testCase.yHalf, glm::cross(testCase.xHalf, testCase.yHalf)))); + REQUIRE(intersectionPoint); + if (!intersectionPoint) { + return; + } + REQUIRE(testCase.expectedIntersectionPoint); + if (!testCase.expectedIntersectionPoint) { + return; + } CHECK(glm::all(glm::lessThan( glm::abs(*intersectionPoint - *testCase.expectedIntersectionPoint), glm::dvec3(CesiumUtility::Math::Epsilon6)))); diff --git a/CesiumGeospatial/test/TestEarthGravitationalModel1996Grid.cpp b/CesiumGeospatial/test/TestEarthGravitationalModel1996Grid.cpp index a92a1cd48..be47b6bb5 100644 --- a/CesiumGeospatial/test/TestEarthGravitationalModel1996Grid.cpp +++ b/CesiumGeospatial/test/TestEarthGravitationalModel1996Grid.cpp @@ -222,6 +222,10 @@ TEST_CASE("EarthGravitationalModel1996Grid::sampleHeight") { SECTION("Correct values at bounds") { REQUIRE(grid); + if (!grid) { + return; + } + for (const Egm96TestCase& testCase : boundsCases) { const double obtainedValue = grid->sampleHeight(testCase.cartographicPosition); @@ -236,6 +240,10 @@ TEST_CASE("EarthGravitationalModel1996Grid::sampleHeight") { SECTION("Calculates correct height values") { REQUIRE(grid); + if (!grid) { + return; + } + for (const Egm96TestCase& testCase : testCases) { const double obtainedValue = grid->sampleHeight(testCase.cartographicPosition); diff --git a/CesiumGeospatial/test/TestGlobeRectangle.cpp b/CesiumGeospatial/test/TestGlobeRectangle.cpp index c6c11a9f4..414a4397f 100644 --- a/CesiumGeospatial/test/TestGlobeRectangle.cpp +++ b/CesiumGeospatial/test/TestGlobeRectangle.cpp @@ -77,6 +77,9 @@ TEST_CASE("GlobeRectangle::equals") { CHECK(split.first.getSouth() == crossing1.getSouth()); CHECK(split.first.getNorth() == crossing1.getNorth()); REQUIRE(split.second); + if (!split.second) { + return; + } CHECK(split.second->getWest() == -Math::OnePi); CHECK(split.second->getEast() == crossing1.getEast()); CHECK(split.second->getSouth() == crossing1.getSouth()); @@ -91,6 +94,9 @@ TEST_CASE("GlobeRectangle::equals") { CHECK(split.first.getSouth() == crossing2.getSouth()); CHECK(split.first.getNorth() == crossing2.getNorth()); REQUIRE(split.second); + if (!split.second) { + return; + } CHECK(split.second->getWest() == crossing2.getWest()); CHECK(split.second->getEast() == Math::OnePi); CHECK(split.second->getSouth() == crossing2.getSouth()); @@ -105,6 +111,9 @@ TEST_CASE("GlobeRectangle::equals") { CHECK(split.first.getSouth() == crossing3.getSouth()); CHECK(split.first.getNorth() == crossing3.getNorth()); REQUIRE(split.second); + if (!split.second) { + return; + } CHECK(split.second->getWest() == -Math::OnePi); CHECK(split.second->getEast() == crossing3.getEast()); CHECK(split.second->getSouth() == crossing3.getSouth()); diff --git a/CesiumGeospatial/test/TestSimplePlanarEllipsoidCurve.cpp b/CesiumGeospatial/test/TestSimplePlanarEllipsoidCurve.cpp index 710500fa3..f8c7cf723 100644 --- a/CesiumGeospatial/test/TestSimplePlanarEllipsoidCurve.cpp +++ b/CesiumGeospatial/test/TestSimplePlanarEllipsoidCurve.cpp @@ -48,7 +48,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { philadelphiaEcef, tokyoEcef); - CHECK(curve); + REQUIRE(curve); + + if (!curve) { + return; + } + CHECK(Math::equalsEpsilon( curve->getPosition(0.0), philadelphiaEcef, @@ -66,7 +71,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { philadelphiaEcef, tokyoEcef); - CHECK(curve); + REQUIRE(curve); + + if (!curve) { + return; + } + // needs three points to form a plane - get midpoint to make third point glm::dvec3 midpoint = curve->getPosition(0.5); glm::dvec3 planeNormal = glm::normalize( @@ -89,7 +99,11 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { philadelphiaEcef, philadelphiaAntipodeEcef); - CHECK(curve); + REQUIRE(curve); + + if (!curve) { + return; + } int steps = 100; for (int i = 0; i <= steps; i++) { @@ -111,7 +125,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { philadelphiaEcef, tokyoEcef); - CHECK(forwardCurve); + REQUIRE(forwardCurve); + + if (!forwardCurve) { + return; + } + glm::dvec3 forwardResult = forwardCurve->getPosition(0.5); std::optional reverseCurve = @@ -120,7 +139,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { tokyoEcef, philadelphiaEcef); - CHECK(reverseCurve); + REQUIRE(reverseCurve); + + if (!reverseCurve) { + return; + } + glm::dvec3 reverseResult = reverseCurve->getPosition(0.5); CHECK(Math::equalsEpsilon(forwardResult, reverseResult, Math::Epsilon6)); @@ -133,7 +157,11 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { philadelphiaEcef, philadelphiaEcef); - CHECK(curve); + REQUIRE(curve); + + if (!curve) { + return; + } // check a whole bunch of points along the curve to make sure it stays the // same @@ -154,7 +182,11 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { Cartographic(25.0, 100.0, startHeight), Cartographic(25.0, 100.0, endHeight)); - CHECK(flightPath); + REQUIRE(flightPath); + + if (!flightPath) { + return; + } std::optional position25Percent = Ellipsoid::WGS84.cartesianToCartographic(flightPath->getPosition(0.25)); @@ -163,17 +195,28 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { std::optional position75Percent = Ellipsoid::WGS84.cartesianToCartographic(flightPath->getPosition(0.75)); - CHECK(position25Percent); + REQUIRE(position25Percent); + + if (!position25Percent) { + return; + } + CHECK(Math::equalsEpsilon( position25Percent->height, (endHeight - startHeight) * 0.25 + startHeight, Math::Epsilon6)); - CHECK(position50Percent); + REQUIRE(position50Percent); + if (!position50Percent) { + return; + } CHECK(Math::equalsEpsilon( position50Percent->height, (endHeight - startHeight) * 0.5 + startHeight, Math::Epsilon6)); - CHECK(position75Percent); + REQUIRE(position75Percent); + if (!position75Percent) { + return; + } CHECK(Math::equalsEpsilon( position75Percent->height, (endHeight - startHeight) * 0.75 + startHeight, @@ -190,7 +233,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::getPosition") { timesSquareEcef, newYorkCityEcef); - CHECK(curve); + REQUIRE(curve); + + if (!curve) { + return; + } + const double expectedDistance = glm::distance(timesSquareEcef, newYorkCityEcef); const glm::dvec3 midpoint = curve->getPosition(0.5); @@ -233,8 +281,12 @@ TEST_CASE("SimplePlanarEllipsoidCurve::fromLongitudeLatitudeHeight") { philadelphiaEcef, tokyoEcef); - CHECK(llhCurve); - CHECK(ecefCurve); + REQUIRE(llhCurve); + REQUIRE(ecefCurve); + + if (!llhCurve || !ecefCurve) { + return; + } int steps = 100; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index ee2d37420..9811517f2 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -675,7 +675,8 @@ class PropertyTablePropertyView } ElementType value = getRaw(index); - if (this->noData() && value == *(this->noData())) { + std::optional maybeNoData = this->noData(); + if (maybeNoData && value == *maybeNoData) { return propertyValueViewToCopy(this->defaultValue()); } else if constexpr (IsMetadataScalar::value) { return transformValue( diff --git a/CesiumGltf/test/TestAccessorUtility.cpp b/CesiumGltf/test/TestAccessorUtility.cpp index 9fd7d1055..b715985dc 100644 --- a/CesiumGltf/test/TestAccessorUtility.cpp +++ b/CesiumGltf/test/TestAccessorUtility.cpp @@ -1060,6 +1060,9 @@ TEST_CASE("Test TexCoordFromAccessor") { TexCoordFromAccessor{static_cast(i)}, texCoordAccessor); REQUIRE(maybeTexCoord); + if (!maybeTexCoord) { + return; + } auto expected = glm::dvec2(texCoords0[i][0], texCoords0[i][1]); REQUIRE(*maybeTexCoord == expected); @@ -1073,6 +1076,9 @@ TEST_CASE("Test TexCoordFromAccessor") { TexCoordFromAccessor{static_cast(i)}, texCoordAccessor); REQUIRE(maybeTexCoord); + if (!maybeTexCoord) { + return; + } auto expected = glm::dvec2(texCoords1[i][0], texCoords1[i][1]); expected /= 255; diff --git a/CesiumGltf/test/TestFeatureIdTextureView.cpp b/CesiumGltf/test/TestFeatureIdTextureView.cpp index cfc116775..1aa08f0ac 100644 --- a/CesiumGltf/test/TestFeatureIdTextureView.cpp +++ b/CesiumGltf/test/TestFeatureIdTextureView.cpp @@ -308,7 +308,10 @@ TEST_CASE("Test FeatureIdTextureView with applyKhrTextureTransformExtension = " REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); auto textureTransform = view.getTextureTransform(); - REQUIRE(textureTransform != std::nullopt); + REQUIRE(textureTransform); + if (!textureTransform) { + return; + } REQUIRE(textureTransform->offset() == glm::dvec2(1.0, 2.0)); REQUIRE(textureTransform->rotation() == CesiumUtility::Math::PiOverTwo); REQUIRE(textureTransform->scale() == glm::dvec2(2.0, 0.5)); @@ -359,7 +362,10 @@ TEST_CASE("Test FeatureIdTextureView with applyKhrTextureTransformExtension = " REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); auto textureTransform = view.getTextureTransform(); - REQUIRE(textureTransform != std::nullopt); + REQUIRE(textureTransform); + if (!textureTransform) { + return; + } REQUIRE(textureTransform->offset() == glm::dvec2(1.0, 2.0)); REQUIRE(textureTransform->rotation() == CesiumUtility::Math::PiOverTwo); REQUIRE(textureTransform->scale() == glm::dvec2(2.0, 0.5)); diff --git a/CesiumGltf/test/TestModel.cpp b/CesiumGltf/test/TestModel.cpp index 524f3db4a..a6f9f8c1d 100644 --- a/CesiumGltf/test/TestModel.cpp +++ b/CesiumGltf/test/TestModel.cpp @@ -792,6 +792,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->name == "test"); } @@ -808,6 +811,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->name == "test"); } @@ -829,6 +835,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->name == "test"); } @@ -843,6 +852,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->name == "test"); } @@ -864,6 +876,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->classes.size() == 2); auto it1 = pExtension->schema->classes.find("foo"); @@ -891,6 +906,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } CHECK(pExtension->schema->classes.size() == 2); auto it1 = pExtension->schema->classes.find("foo"); @@ -919,6 +937,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } REQUIRE(pExtension->propertyTables.size() == 2); CHECK(pExtension->propertyTables[0].classProperty == "foo"); @@ -943,6 +964,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } REQUIRE(pExtension->propertyAttributes.size() == 2); CHECK(pExtension->propertyAttributes[0].classProperty == "foo"); @@ -966,6 +990,9 @@ TEST_CASE("Model::merge") { m1.getExtension(); REQUIRE(pExtension); REQUIRE(pExtension->schema); + if (!pExtension->schema) { + return; + } REQUIRE(pExtension->propertyTextures.size() == 2); CHECK(pExtension->propertyTextures[0].classProperty == "foo"); @@ -1206,15 +1233,25 @@ TEST_CASE("Model::merge") { m1.meshes[0].primitives[0].getExtension(); REQUIRE(pMeshFeatures1); REQUIRE(pMeshFeatures1->featureIds.size() == 1); - REQUIRE(pMeshFeatures1->featureIds[0].texture); - CHECK(pMeshFeatures1->featureIds[0].texture->index == 0); + std::optional featureIdTexture = + pMeshFeatures1->featureIds[0].texture; + REQUIRE(featureIdTexture); + if (!featureIdTexture) { + return; + } + CHECK(featureIdTexture->index == 0); ExtensionExtMeshFeatures* pMeshFeatures2 = m1.meshes[1].primitives[0].getExtension(); REQUIRE(pMeshFeatures2); REQUIRE(pMeshFeatures2->featureIds.size() == 1); - REQUIRE(pMeshFeatures2->featureIds[0].texture); - CHECK(pMeshFeatures2->featureIds[0].texture->index == 1); + std::optional maybeFeatureIdTexture = + pMeshFeatures2->featureIds[0].texture; + REQUIRE(maybeFeatureIdTexture); + if (!maybeFeatureIdTexture) { + return; + } + CHECK(maybeFeatureIdTexture->index == 1); } } } diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index e1f113a1c..d2f23d174 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -117,8 +117,7 @@ static void checkNumeric( for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); if constexpr (IsMetadataFloating::value) { - REQUIRE( - property.get(i) == Catch::Approx(*expected[static_cast(i)])); + REQUIRE(property.get(i) == *expected[static_cast(i)]); } else { REQUIRE(property.get(i) == expected[static_cast(i)]); } @@ -222,6 +221,9 @@ static void checkVariableLengthArray( auto maybeValues = property.get(i); REQUIRE(maybeValues); + if (!maybeValues) { + return; + } for (int64_t j = 0; j < values.size(); ++j) { REQUIRE((*maybeValues)[j] == values[j]); } @@ -1305,7 +1307,7 @@ TEST_CASE("Check matN PropertyTablePropertyView (normalized)") { } TEST_CASE("Check boolean PropertyTablePropertyView") { - std::bitset bits = 0b11110101; + std::bitset bits = 0b11110101; unsigned long val = bits.to_ulong(); std::vector data(sizeof(val)); std::memcpy(data.data(), &val, sizeof(val)); diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index b1a54c35b..25de7ba3a 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -321,6 +321,9 @@ void checkTextureArrayValues( auto maybeValue = view.get(uv[0], uv[1]); REQUIRE(maybeValue); + if (!maybeValue) { + return; + } REQUIRE(maybeValue->size() == value.size()); for (int64_t j = 0; j < value.size(); j++) { REQUIRE(value[j] == expectedValue[static_cast(j)]); @@ -1836,7 +1839,7 @@ TEST_CASE("Test PropertyTextureProperty constructs with " REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); auto textureTransform = view.getTextureTransform(); - REQUIRE(textureTransform != std::nullopt); + REQUIRE(textureTransform); REQUIRE(textureTransform->offset() == glm::dvec2(0.5, -0.5)); REQUIRE(textureTransform->rotation() == CesiumUtility::Math::PiOverTwo); REQUIRE(textureTransform->scale() == glm::dvec2(0.5, 0.5)); @@ -1909,7 +1912,10 @@ TEST_CASE("Test normalized PropertyTextureProperty constructs with " REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); auto textureTransform = view.getTextureTransform(); - REQUIRE(textureTransform != std::nullopt); + REQUIRE(textureTransform); + if (!textureTransform) { + return; + } REQUIRE(textureTransform->offset() == glm::dvec2(0.5, -0.5)); REQUIRE(textureTransform->rotation() == CesiumUtility::Math::PiOverTwo); REQUIRE(textureTransform->scale() == glm::dvec2(0.5, 0.5)); diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 2e64bcdc7..81a9b3f67 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -63,7 +63,10 @@ void verifyTextureTransformConstruction( const PropertyTexturePropertyView& propertyView, const ExtensionKhrTextureTransform& extension) { auto textureTransform = propertyView.getTextureTransform(); - REQUIRE(textureTransform != std::nullopt); + REQUIRE(textureTransform); + if (!textureTransform) { + return; + } REQUIRE( textureTransform->offset() == glm::dvec2{extension.offset[0], extension.offset[1]}); @@ -1091,6 +1094,9 @@ TEST_CASE("Test array PropertyTextureProperty") { auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); REQUIRE(maybeValue); + if (!maybeValue) { + return; + } for (int64_t j = 0; j < maybeValue->size(); j++) { REQUIRE((*maybeValue)[j] == value[j]); } diff --git a/CesiumGltfContent/test/TestGltfUtilities.cpp b/CesiumGltfContent/test/TestGltfUtilities.cpp index 86cdc50fc..33fee72b0 100644 --- a/CesiumGltfContent/test/TestGltfUtilities.cpp +++ b/CesiumGltfContent/test/TestGltfUtilities.cpp @@ -1,3 +1,5 @@ +#include "CesiumGltf/MaterialPBRMetallicRoughness.h" + #include #include #include @@ -34,6 +36,9 @@ TEST_CASE("GltfUtilities::getNodeTransform") { std::optional maybeMatrix = GltfUtilities::getNodeTransform(node); REQUIRE(maybeMatrix); + if (!maybeMatrix) { + return; + } glm::dmat4x4 m = *maybeMatrix; CHECK(m[0] == glm::dvec4(1.0, 2.0, 3.0, 4.0)); @@ -55,6 +60,9 @@ TEST_CASE("GltfUtilities::getNodeTransform") { std::optional maybeMatrix = GltfUtilities::getNodeTransform(node); REQUIRE(maybeMatrix); + if (!maybeMatrix) { + return; + } glm::dmat4x4 m = *maybeMatrix; CHECK(m[0] == glm::dvec4(1.0, 2.0, 3.0, 4.0)); @@ -92,6 +100,9 @@ TEST_CASE("GltfUtilities::getNodeTransform") { std::optional maybeMatrix = GltfUtilities::getNodeTransform(node); REQUIRE(maybeMatrix); + if (!maybeMatrix) { + return; + } glm::dmat4x4 m = *maybeMatrix; @@ -241,9 +252,19 @@ TEST_CASE("GltfUtilities::removeUnusedTextures") { CHECK(m.textures.size() == 1); REQUIRE(m.materials.size() == 1); - REQUIRE(m.materials[0].pbrMetallicRoughness); - REQUIRE(m.materials[0].pbrMetallicRoughness->baseColorTexture); - CHECK(m.materials[0].pbrMetallicRoughness->baseColorTexture->index == 0); + + std::optional pbrMetallicRoughness; + + REQUIRE(pbrMetallicRoughness); + if (!pbrMetallicRoughness) { + return; + } + REQUIRE(pbrMetallicRoughness->baseColorTexture); + if (!pbrMetallicRoughness->baseColorTexture) { + return; + } + + CHECK(pbrMetallicRoughness->baseColorTexture->index == 0); } } diff --git a/CesiumGltfContent/test/TestIntersectRayGltf.cpp b/CesiumGltfContent/test/TestIntersectRayGltf.cpp index 385cce7fd..21479ffaa 100644 --- a/CesiumGltfContent/test/TestIntersectRayGltf.cpp +++ b/CesiumGltfContent/test/TestIntersectRayGltf.cpp @@ -83,18 +83,23 @@ void checkIntersection( void checkBadUnitCube(const std::string& testModelName, bool shouldHitAnyway) { GltfReader reader; - Model testModel = - *reader - .readGltf(readFile( - std::filesystem::path(CesiumGltfContent_TEST_DATA_DIR) / - testModelName)) - .model; + std::optional testModel = + reader + .readGltf(readFile( + std::filesystem::path(CesiumGltfContent_TEST_DATA_DIR) / + testModelName)) + .model; + + REQUIRE(testModel); + if (!testModel) { + return; + } // Do an intersection with top side of the cube GltfUtilities::IntersectResult hitResult = GltfUtilities::intersectRayGltfModel( Ray(glm::dvec3(0.0, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, glm::dmat4x4(1.0)); @@ -112,17 +117,22 @@ void checkBadUnitCube(const std::string& testModelName, bool shouldHitAnyway) { void checkValidUnitCube(const std::string& testModelName) { GltfReader reader; - Model testModel = - *reader - .readGltf(readFile( - std::filesystem::path(CesiumGltfContent_TEST_DATA_DIR) / - testModelName)) - .model; + std::optional testModel = + reader + .readGltf(readFile( + std::filesystem::path(CesiumGltfContent_TEST_DATA_DIR) / + testModelName)) + .model; + + REQUIRE(testModel); + if (!testModel) { + return; + } // intersects the top side of the cube checkIntersection( Ray(glm::dvec3(0.0, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, glm::dmat4x4(1.0), true, @@ -131,7 +141,7 @@ void checkValidUnitCube(const std::string& testModelName) { // misses the top side of the cube to the right checkIntersection( Ray(glm::dvec3(0.6, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, glm::dmat4x4(1.0), false, @@ -140,7 +150,7 @@ void checkValidUnitCube(const std::string& testModelName) { // misses the top side of the cube because it's behind it (avoid backfaces) checkIntersection( Ray(glm::dvec3(0.0, 0.0, 0.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, glm::dmat4x4(1.0), false, @@ -149,7 +159,7 @@ void checkValidUnitCube(const std::string& testModelName) { // hits backface triangles checkIntersection( Ray(glm::dvec3(0.0, 0.0, 0.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, false, glm::dmat4x4(1.0), true, @@ -158,7 +168,7 @@ void checkValidUnitCube(const std::string& testModelName) { // tests against backfaces, and picks first hit (top) checkIntersection( Ray(glm::dvec3(0.0, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, false, glm::dmat4x4(1.0), true, @@ -167,7 +177,7 @@ void checkValidUnitCube(const std::string& testModelName) { // tests against backfaces, and picks first hit (bottom) checkIntersection( Ray(glm::dvec3(0.0, 0.0, -2.0), glm::dvec3(0.0, 0.0, 1.0)), - testModel, + *testModel, false, glm::dmat4x4(1.0), true, @@ -178,7 +188,7 @@ void checkValidUnitCube(const std::string& testModelName) { translationMatrix[3] = glm::dvec4(0.6, 0.0, 0.0, 1.0); checkIntersection( Ray(glm::dvec3(0.0, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, translationMatrix, false, @@ -187,7 +197,7 @@ void checkValidUnitCube(const std::string& testModelName) { // just hits the top side of a cube translated to the right checkIntersection( Ray(glm::dvec3(0.6, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, translationMatrix, true, @@ -201,7 +211,7 @@ void checkValidUnitCube(const std::string& testModelName) { glm::dvec4(0.0, 0.0, 0.0, 1.0)); checkIntersection( Ray(glm::dvec3(0.0, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, scaleMatrix, true, @@ -210,7 +220,7 @@ void checkValidUnitCube(const std::string& testModelName) { // just misses a scaled cube to the right checkIntersection( Ray(glm::dvec3(1.1, 0.0, 2.0), glm::dvec3(0.0, 0.0, -1.0)), - testModel, + *testModel, true, scaleMatrix, false, diff --git a/CesiumGltfReader/src/GltfReader.cpp b/CesiumGltfReader/src/GltfReader.cpp index df7d333ab..31dd7b849 100644 --- a/CesiumGltfReader/src/GltfReader.cpp +++ b/CesiumGltfReader/src/GltfReader.cpp @@ -265,6 +265,9 @@ void postprocess( const GltfReader& reader, GltfReaderResult& readGltf, const GltfReaderOptions& options) { + if (!readGltf.model) { + return; + } Model& model = *readGltf.model; auto extFeatureMetadataIter = std::find( @@ -512,6 +515,13 @@ void CesiumGltfReader::GltfReader::postprocessGltf( } auto pResult = std::make_unique(std::move(result)); + std::optional maybeModel = pResult->model; + + if (!maybeModel) { + return asyncSystem.createResolvedFuture(std::move(*pResult.release())); + } + + Model& model = *maybeModel; struct ExternalBufferLoadResult { bool success = false; @@ -525,7 +535,7 @@ void CesiumGltfReader::GltfReader::postprocessGltf( constexpr std::string_view dataPrefix = "data:"; constexpr size_t dataPrefixLength = dataPrefix.size(); - for (Buffer& buffer : pResult->model->buffers) { + for (Buffer& buffer : model.buffers) { if (buffer.uri && buffer.uri->substr(0, dataPrefixLength) != dataPrefix) { resolvedBuffers.push_back( pAssetAccessor @@ -551,7 +561,7 @@ void CesiumGltfReader::GltfReader::postprocessGltf( } if (options.resolveExternalImages) { - for (Image& image : pResult->model->images) { + for (Image& image : model.images) { if (image.uri && image.uri->substr(0, dataPrefixLength) != dataPrefix) { resolvedBuffers.push_back( pAssetAccessor diff --git a/CesiumGltfReader/src/applyKhrTextureTransform.cpp b/CesiumGltfReader/src/applyKhrTextureTransform.cpp index d79f2898d..d441d07c2 100644 --- a/CesiumGltfReader/src/applyKhrTextureTransform.cpp +++ b/CesiumGltfReader/src/applyKhrTextureTransform.cpp @@ -121,14 +121,16 @@ void applyKhrTextureTransform(Model& model) { for (MeshPrimitive& primitive : mesh.primitives) { Material* material = Model::getSafe(&model.materials, primitive.material); if (material) { - processTextureInfo( - model, - primitive, - material->pbrMetallicRoughness->baseColorTexture); - processTextureInfo( - model, - primitive, - material->pbrMetallicRoughness->metallicRoughnessTexture); + if (material->pbrMetallicRoughness) { + processTextureInfo( + model, + primitive, + material->pbrMetallicRoughness->baseColorTexture); + processTextureInfo( + model, + primitive, + material->pbrMetallicRoughness->metallicRoughnessTexture); + } processTextureInfo(model, primitive, material->normalTexture); processTextureInfo(model, primitive, material->occlusionTexture); processTextureInfo(model, primitive, material->emissiveTexture); diff --git a/CesiumGltfReader/src/decodeDraco.cpp b/CesiumGltfReader/src/decodeDraco.cpp index 67dde5433..8bb995391 100644 --- a/CesiumGltfReader/src/decodeDraco.cpp +++ b/CesiumGltfReader/src/decodeDraco.cpp @@ -43,6 +43,7 @@ std::unique_ptr decodeBufferViewToDracoMesh( CesiumGltf::MeshPrimitive& /* primitive */, const CesiumGltf::ExtensionKhrDracoMeshCompression& draco) { CESIUM_TRACE("CesiumGltfReader::decodeBufferViewToDracoMesh"); + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) CesiumGltf::Model& model = *readGltf.model; CesiumGltf::BufferView* pBufferView = @@ -113,6 +114,9 @@ void copyDecodedIndices( const CesiumGltf::MeshPrimitive& primitive, draco::Mesh* pMesh) { CESIUM_TRACE("CesiumGltfReader::copyDecodedIndices"); + if (!readGltf.model) { + return; + } CesiumGltf::Model& model = *readGltf.model; if (primitive.indices < 0) { @@ -220,6 +224,7 @@ void copyDecodedAttribute( const draco::Mesh* pMesh, const draco::PointAttribute* pAttribute) { CESIUM_TRACE("CesiumGltfReader::copyDecodedAttribute"); + CESIUM_ASSERT(readGltf.model); CesiumGltf::Model& model = *readGltf.model; if (pAccessor->count != pMesh->num_points()) { @@ -288,6 +293,9 @@ void decodePrimitive( CesiumGltf::MeshPrimitive& primitive, CesiumGltf::ExtensionKhrDracoMeshCompression& draco) { CESIUM_TRACE("CesiumGltfReader::decodePrimitive"); + if (!readGltf.model) { + return; + } CesiumGltf::Model& model = *readGltf.model; std::unique_ptr pMesh = diff --git a/CesiumGltfReader/test/TestExtensionModelExtStructuralMetadata.cpp b/CesiumGltfReader/test/TestExtensionModelExtStructuralMetadata.cpp index c679577e2..8a1eb37e5 100644 --- a/CesiumGltfReader/test/TestExtensionModelExtStructuralMetadata.cpp +++ b/CesiumGltfReader/test/TestExtensionModelExtStructuralMetadata.cpp @@ -73,12 +73,18 @@ TEST_CASE( REQUIRE(readerResult.errors.empty()); REQUIRE(readerResult.model); + if (!readerResult.model) { + return; + } ExtensionModelExtStructuralMetadata* pMetadata = readerResult.model->getExtension(); REQUIRE(pMetadata); REQUIRE(pMetadata->schema); + if (!pMetadata->schema) { + return; + } REQUIRE(pMetadata->schema->classes.size() == 1); auto treesIt = pMetadata->schema->classes.find("tree"); @@ -88,7 +94,16 @@ TEST_CASE( auto birdCountIt = treesIt->second.properties.find("birdCount"); REQUIRE(birdCountIt != treesIt->second.properties.end()); - REQUIRE(!birdCountIt->second.max); - REQUIRE(birdCountIt->second.min); - REQUIRE(birdCountIt->second.min->getSafeNumberOrDefault(-1) == 1); + + std::optional min = birdCountIt->second.min; + std::optional max = birdCountIt->second.max; + + CHECK(!max); + + REQUIRE(min); + if (!min) { + return; + } + + REQUIRE(min->getSafeNumberOrDefault(-1) == 1); } diff --git a/CesiumGltfReader/test/TestGltfReader.cpp b/CesiumGltfReader/test/TestGltfReader.cpp index 767ca553b..f6809c536 100644 --- a/CesiumGltfReader/test/TestGltfReader.cpp +++ b/CesiumGltfReader/test/TestGltfReader.cpp @@ -98,6 +98,9 @@ TEST_CASE("CesiumGltfReader::GltfReader") { gsl::span(reinterpret_cast(s.c_str()), s.size())); CHECK(result.errors.empty()); REQUIRE(result.model); + if (!result.model) { + return; + } Model& model = *result.model; REQUIRE(model.accessors.size() == 1); @@ -198,6 +201,10 @@ TEST_CASE("Can decompress meshes using EXT_meshopt_compression") { GltfReaderResult result = reader.readGltf(readFile( CesiumGltfReader_TEST_DATA_DIR + std::string("/DucksMeshopt/Duck.glb"))); + REQUIRE(result.model); + if (!result.model) { + return; + } const Model& model = *result.model; // These extensions should be removed during the load process. @@ -221,6 +228,9 @@ TEST_CASE("Can decompress meshes using EXT_meshopt_compression") { GltfReader reader; GltfReaderResult result = reader.readGltf(data); REQUIRE(result.model); + if (!result.model) { + return; + } REQUIRE(result.warnings.empty()); const Model& model = *result.model; VertexAttributeRange compressedVar = getVertexAttributeRange(model); @@ -249,6 +259,9 @@ TEST_CASE("Read TriangleWithoutIndices") { GltfReader reader; GltfReaderResult result = reader.readGltf(data); REQUIRE(result.model); + if (!result.model) { + return; + } const Model& model = *result.model; REQUIRE(model.meshes.size() == 1); @@ -296,6 +309,9 @@ TEST_CASE("Nested extras deserializes properly") { REQUIRE(result.errors.empty()); REQUIRE(result.model); + if (!result.model) { + return; + } Model& model = *result.model; auto cit = model.extras.find("C"); @@ -349,6 +365,9 @@ TEST_CASE("Can deserialize KHR_draco_mesh_compression") { REQUIRE(result.errors.empty()); REQUIRE(result.model); + if (!result.model) { + return; + } Model& model = *result.model; REQUIRE(model.meshes.size() == 1); @@ -377,6 +396,9 @@ TEST_CASE("Can deserialize KHR_draco_mesh_compression") { REQUIRE(result2.errors.empty()); REQUIRE(result2.model); + if (!result2.model) { + return; + } Model& model2 = *result2.model; REQUIRE(model2.meshes.size() == 1); @@ -412,6 +434,9 @@ TEST_CASE("Can deserialize KHR_draco_mesh_compression") { REQUIRE(result3.errors.empty()); REQUIRE(result3.model); + if (!result3.model) { + return; + } Model& model3 = *result3.model; REQUIRE(model3.meshes.size() == 1); @@ -449,6 +474,9 @@ TEST_CASE("Extensions deserialize to JsonVaue iff " REQUIRE(withCustomExtModel.errors.empty()); REQUIRE(withCustomExtModel.model); + if (!withCustomExtModel.model) { + return; + } REQUIRE(withCustomExtModel.model->extensions.size() == 2); @@ -478,6 +506,10 @@ TEST_CASE("Extensions deserialize to JsonVaue iff " gsl::span(reinterpret_cast(s.c_str()), s.size()), options); + REQUIRE(withoutCustomExt.model); + if (!withoutCustomExt.model) { + return; + } auto& zeroExtensions = withoutCustomExt.model->extensions; REQUIRE(zeroExtensions.empty()); } @@ -554,6 +586,9 @@ TEST_CASE("Test KTX2") { CesiumGltfReader::GltfReader reader; GltfReaderResult result = reader.readGltf(data); REQUIRE(result.model); + if (!result.model) { + return; + } const Model& model = *result.model; REQUIRE(model.meshes.size() == 1); @@ -576,6 +611,9 @@ TEST_CASE("Can apply RTC CENTER if model uses Cesium RTC extension") { gsl::span(reinterpret_cast(s.c_str()), s.size()), options); REQUIRE(result.model); + if (!result.model) { + return; + } Model& model = *result.model; const ExtensionCesiumRTC* cesiumRTC = model.getExtension(); @@ -594,6 +632,9 @@ TEST_CASE("Can correctly interpret mipmaps in KTX2 files") { ImageReaderResult imageResult = GltfReader::readImage(data, Ktx2TranscodeTargets{}); REQUIRE(imageResult.image); + if (!imageResult.image) { + return; + } const ImageCesium& image = *imageResult.image; REQUIRE(image.mipPositions.size() == 1); @@ -614,6 +655,9 @@ TEST_CASE("Can correctly interpret mipmaps in KTX2 files") { ImageReaderResult imageResult = GltfReader::readImage(data, Ktx2TranscodeTargets{}); REQUIRE(imageResult.image); + if (!imageResult.image) { + return; + } const ImageCesium& image = *imageResult.image; REQUIRE(image.mipPositions.size() == 0); @@ -628,6 +672,9 @@ TEST_CASE("Can correctly interpret mipmaps in KTX2 files") { ImageReaderResult imageResult = GltfReader::readImage(data, Ktx2TranscodeTargets{}); REQUIRE(imageResult.image); + if (!imageResult.image) { + return; + } const ImageCesium& image = *imageResult.image; REQUIRE(image.mipPositions.size() == 9); @@ -664,6 +711,9 @@ TEST_CASE("Can read unknown properties from a glTF") { gsl::span(reinterpret_cast(s.c_str()), s.size()), options); REQUIRE(result.model); + if (!result.model) { + return; + } auto unknownIt1 = result.model->unknownProperties.find("someUnknownProperty"); REQUIRE(unknownIt1 != result.model->unknownProperties.end()); @@ -694,6 +744,9 @@ TEST_CASE("Ignores unknown properties if requested") { gsl::span(reinterpret_cast(s.c_str()), s.size()), options); REQUIRE(result.model); + if (!result.model) { + return; + } CHECK(result.model->unknownProperties.empty()); CHECK(result.model->asset.unknownProperties.empty()); } @@ -795,6 +848,9 @@ TEST_CASE("GltfReader::loadGltf") { reader.loadGltf(asyncSystem, uri, {}, pMockAssetAccessor); GltfReaderResult result = waitForFuture(asyncSystem, std::move(future)); REQUIRE(result.model); + if (!result.model) { + return; + } CHECK(result.errors.empty()); // There will be warnings, because this model has accessors that don't match // the Draco-decoded size. It seems to be ambiguous whether this is @@ -822,6 +878,9 @@ TEST_CASE("GltfReader::loadGltf") { reader.loadGltf(asyncSystem, uri, {}, pMockAssetAccessor, options); GltfReaderResult result = waitForFuture(asyncSystem, std::move(future)); REQUIRE(result.model); + if (!result.model) { + return; + } CHECK(result.errors.empty()); // There will be warnings, because this model has accessors that don't match // the Draco-decoded size. It seems to be ambiguous whether this is diff --git a/CesiumGltfWriter/test/TestGltfWriter.cpp b/CesiumGltfWriter/test/TestGltfWriter.cpp index 91fded038..af13b73ec 100644 --- a/CesiumGltfWriter/test/TestGltfWriter.cpp +++ b/CesiumGltfWriter/test/TestGltfWriter.cpp @@ -25,6 +25,9 @@ void check(const std::string& input, const std::string& expectedOutput) { REQUIRE(readResult.errors.empty()); REQUIRE(readResult.warnings.empty()); REQUIRE(readResult.model); + if (!readResult.model) { + return; + } CesiumGltf::Model& model = *readResult.model; @@ -553,6 +556,9 @@ TEST_CASE("Writes glb") { REQUIRE(readResult.errors.empty()); REQUIRE(readResult.warnings.empty()); REQUIRE(readResult.model); + if (!readResult.model) { + return; + } CesiumGltf::Model& readModel = *readResult.model; const std::vector readModelBuffer = diff --git a/CesiumIonClient/test/TestConnection.cpp b/CesiumIonClient/test/TestConnection.cpp index f5f3c57d2..d111fcb87 100644 --- a/CesiumIonClient/test/TestConnection.cpp +++ b/CesiumIonClient/test/TestConnection.cpp @@ -62,6 +62,10 @@ TEST_CASE("CesiumIonClient::Connection") { REQUIRE(defaults.value); + if (!defaults.value) { + return; + } + CHECK(defaults.value->defaultAssets.imagery == 2); CHECK(defaults.value->defaultAssets.terrain == 1); CHECK(defaults.value->defaultAssets.buildings == 624); @@ -107,7 +111,10 @@ TEST_CASE("CesiumIonClient::Connection on single-user mode") { Future> futureMe = connection.me(); Response me = waitForFuture(asyncSystem, std::move(futureMe)); - CHECK(me.value); + REQUIRE(me.value); + if (!me.value) { + return; + } CHECK(me.value->id == 0); CHECK(me.value->username == "ion-user"); } diff --git a/CesiumQuantizedMeshTerrain/test/TestLayer.cpp b/CesiumQuantizedMeshTerrain/test/TestLayer.cpp index f020edc8d..a130e1294 100644 --- a/CesiumQuantizedMeshTerrain/test/TestLayer.cpp +++ b/CesiumQuantizedMeshTerrain/test/TestLayer.cpp @@ -25,11 +25,17 @@ TEST_CASE("LayerJsonUtilities") { layer.projection = "EPSG:4326"; maybeProjection = layer.getProjection(Ellipsoid::WGS84); REQUIRE(maybeProjection); + if (!maybeProjection) { + return; + } CHECK(std::get_if(&*maybeProjection) != nullptr); layer.projection = "EPSG:3857"; maybeProjection = layer.getProjection(Ellipsoid::WGS84); REQUIRE(maybeProjection); + if (!maybeProjection) { + return; + } CHECK(std::get_if(&*maybeProjection) != nullptr); layer.projection = "foo"; @@ -44,6 +50,9 @@ TEST_CASE("LayerJsonUtilities") { layer.projection = "EPSG:4326"; maybeTilingScheme = layer.getTilingScheme(Ellipsoid::WGS84); REQUIRE(maybeTilingScheme); + if (!maybeTilingScheme) { + return; + } CHECK(maybeTilingScheme->getRootTilesX() == 2); CHECK(maybeTilingScheme->getRootTilesY() == 1); CHECK( @@ -58,6 +67,9 @@ TEST_CASE("LayerJsonUtilities") { layer.projection = "EPSG:3857"; maybeTilingScheme = layer.getTilingScheme(Ellipsoid::WGS84); REQUIRE(maybeTilingScheme); + if (!maybeTilingScheme) { + return; + } CHECK(maybeTilingScheme->getRootTilesX() == 1); CHECK(maybeTilingScheme->getRootTilesY() == 1); CHECK(Math::equalsEpsilon( @@ -85,6 +97,9 @@ TEST_CASE("LayerJsonUtilities") { layer.projection = "EPSG:4326"; maybeBoundingRegion = layer.getRootBoundingRegion(Ellipsoid::WGS84); REQUIRE(maybeBoundingRegion); + if (!maybeBoundingRegion) { + return; + } CHECK( maybeBoundingRegion->getRectangle().getWest() == GeographicProjection::MAXIMUM_GLOBE_RECTANGLE.getWest()); @@ -103,6 +118,9 @@ TEST_CASE("LayerJsonUtilities") { layer.projection = "EPSG:3857"; maybeBoundingRegion = layer.getRootBoundingRegion(Ellipsoid::WGS84); REQUIRE(maybeBoundingRegion); + if (!maybeBoundingRegion) { + return; + } CHECK( maybeBoundingRegion->getRectangle().getWest() == WebMercatorProjection::MAXIMUM_GLOBE_RECTANGLE.getWest()); diff --git a/CesiumQuantizedMeshTerrain/test/TestLayerWriter.cpp b/CesiumQuantizedMeshTerrain/test/TestLayerWriter.cpp index 13ffce70d..eb8f10c11 100644 --- a/CesiumQuantizedMeshTerrain/test/TestLayerWriter.cpp +++ b/CesiumQuantizedMeshTerrain/test/TestLayerWriter.cpp @@ -59,6 +59,9 @@ TEST_CASE("LayerWriter") { CHECK(readResult.errors.empty()); CHECK(readResult.warnings.empty()); REQUIRE(readResult.value); + if (!readResult.value) { + return; + } Layer& readLayer = *readResult.value; diff --git a/CesiumQuantizedMeshTerrain/test/TestQuantizedMeshContent.cpp b/CesiumQuantizedMeshTerrain/test/TestQuantizedMeshContent.cpp index 22ab0c604..27342c967 100644 --- a/CesiumQuantizedMeshTerrain/test/TestQuantizedMeshContent.cpp +++ b/CesiumQuantizedMeshTerrain/test/TestQuantizedMeshContent.cpp @@ -809,8 +809,10 @@ TEST_CASE("Test converting quantized mesh to gltf with skirt") { QuantizedMeshLoadResult loadResult = QuantizedMeshLoader::load(tileID, boundingVolume, "url", data, false); REQUIRE(!loadResult.errors.hasErrors()); - REQUIRE(loadResult.model != std::nullopt); - + REQUIRE(loadResult.model); + if (!loadResult.model) { + return; + } checkGltfSanity(*loadResult.model); // make sure the gltf is the grid @@ -883,7 +885,10 @@ TEST_CASE("Test converting quantized mesh to gltf with skirt") { auto loadResult = QuantizedMeshLoader::load(tileID, boundingVolume, "url", data, false); REQUIRE(!loadResult.errors.hasErrors()); - REQUIRE(loadResult.model != std::nullopt); + REQUIRE(loadResult.model); + if (!loadResult.model) { + return; + } checkGltfSanity(*loadResult.model); @@ -957,7 +962,10 @@ TEST_CASE("Test converting quantized mesh to gltf with skirt") { auto loadResult = QuantizedMeshLoader::load(tileID, boundingVolume, "url", data, false); REQUIRE(!loadResult.errors.hasErrors()); - REQUIRE(loadResult.model != std::nullopt); + REQUIRE(loadResult.model); + if (!loadResult.model) { + return; + } checkGltfSanity(*loadResult.model); @@ -1049,7 +1057,10 @@ TEST_CASE("Test converting quantized mesh to gltf with skirt") { auto loadResult = QuantizedMeshLoader::load(tileID, boundingVolume, "url", data, false); REQUIRE(!loadResult.errors.hasErrors()); - REQUIRE(loadResult.model != std::nullopt); + REQUIRE(loadResult.model); + if (!loadResult.model) { + return; + } checkGltfSanity(*loadResult.model); diff --git a/CesiumRasterOverlays/src/BingMapsRasterOverlay.cpp b/CesiumRasterOverlays/src/BingMapsRasterOverlay.cpp index 5fc1fef7d..38268a271 100644 --- a/CesiumRasterOverlays/src/BingMapsRasterOverlay.cpp +++ b/CesiumRasterOverlays/src/BingMapsRasterOverlay.cpp @@ -182,7 +182,12 @@ class BingMapsTileProvider final : public QuadtreeRasterOverlayTileProvider { options.rectangle = this->getTilingScheme().tileToRectangle(tileID); std::vector& tileCredits = options.credits = this->getOwner().getCredits(); - tileCredits.push_back(*this->getCredit()); + + std::optional credit = this->getCredit(); + + if (credit) { + tileCredits.push_back(*credit); + } const CesiumGeospatial::GlobeRectangle tileRectangle = CesiumGeospatial::unprojectRectangleSimple( diff --git a/CesiumRasterOverlays/src/QuadtreeRasterOverlayTileProvider.cpp b/CesiumRasterOverlays/src/QuadtreeRasterOverlayTileProvider.cpp index db8a4a6f1..e49e04cbc 100644 --- a/CesiumRasterOverlays/src/QuadtreeRasterOverlayTileProvider.cpp +++ b/CesiumRasterOverlays/src/QuadtreeRasterOverlayTileProvider.cpp @@ -541,8 +541,9 @@ void QuadtreeRasterOverlayTileProvider::unloadCachedTiles() { // If this is the last use of this data, it will be freed when the shared // pointer goes out of scope, so reduce the cachedBytes accordingly. if (pImage.use_count() == 1) { - if (pImage->image) { - this->_cachedBytes -= int64_t(pImage->image->pixelData.size()); + std::optional maybeImageCesium = pImage->image; + if (maybeImageCesium) { + this->_cachedBytes -= int64_t(maybeImageCesium->pixelData.size()); CESIUM_ASSERT(this->_cachedBytes >= 0); } } diff --git a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp index a97db2571..94f940742 100644 --- a/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp +++ b/CesiumRasterOverlays/src/RasterOverlayUtilities.cpp @@ -943,8 +943,8 @@ bool upsamplePrimitiveForRasterOverlays( int64_t indicesCount = indicesView.size(); std::optional parentSkirtMeshMetadata = SkirtMeshMetadata::parseFromGltfExtras(primitive.extras); - const bool hasSkirt = (parentSkirtMeshMetadata != std::nullopt) && - (positionAttributeIndex != -1); + const bool hasSkirt = + parentSkirtMeshMetadata && (positionAttributeIndex != -1); if (hasSkirt) { indicesBegin = parentSkirtMeshMetadata->noSkirtIndicesBegin; indicesCount = parentSkirtMeshMetadata->noSkirtIndicesCount; diff --git a/CesiumRasterOverlays/test/TestAddRasterOverlayToGltf.cpp b/CesiumRasterOverlays/test/TestAddRasterOverlayToGltf.cpp index 9a8096cd1..5d2c5e3c9 100644 --- a/CesiumRasterOverlays/test/TestAddRasterOverlayToGltf.cpp +++ b/CesiumRasterOverlays/test/TestAddRasterOverlayToGltf.cpp @@ -66,6 +66,9 @@ TEST_CASE("Add raster overlay to glTF") { GltfReader reader; GltfReaderResult result = reader.readGltf(bytes); REQUIRE(result.model); + if (!result.model) { + return; + } Model& gltf = *result.model; @@ -287,6 +290,9 @@ TEST_CASE("Add raster overlay to glTF") { // Read it back and verify everything still looks good. GltfReaderResult resultBack = reader.readGltf(writeResult.gltfBytes); REQUIRE(resultBack.model); + if (!resultBack.model) { + return; + } const Model& gltfBack = *resultBack.model; diff --git a/CesiumRasterOverlays/test/TestQuadtreeRasterOverlayTileProvider.cpp b/CesiumRasterOverlays/test/TestQuadtreeRasterOverlayTileProvider.cpp index d3b2fc2ce..3d2e23a5f 100644 --- a/CesiumRasterOverlays/test/TestQuadtreeRasterOverlayTileProvider.cpp +++ b/CesiumRasterOverlays/test/TestQuadtreeRasterOverlayTileProvider.cpp @@ -217,6 +217,9 @@ TEST_CASE("QuadtreeRasterOverlayTileProvider getTile") { std::optional centerTileID = pTestProvider->getTilingScheme().positionToTile(center, expectedLevel); REQUIRE(centerTileID); + if (!centerTileID) { + return; + } Rectangle centerRectangle = pTestProvider->getTilingScheme().tileToRectangle(*centerTileID); @@ -237,6 +240,9 @@ TEST_CASE("QuadtreeRasterOverlayTileProvider getTile") { tileRectangle.getLowerRight(), expectedLevel); REQUIRE(southeastID); + if (!southeastID) { + return; + } pTestProvider->errorTiles.emplace_back(*southeastID); diff --git a/CesiumRasterOverlays/test/TestUpsampleGltfForRasterOverlay.cpp b/CesiumRasterOverlays/test/TestUpsampleGltfForRasterOverlay.cpp index 164b201b6..106b8da4d 100644 --- a/CesiumRasterOverlays/test/TestUpsampleGltfForRasterOverlay.cpp +++ b/CesiumRasterOverlays/test/TestUpsampleGltfForRasterOverlay.cpp @@ -207,14 +207,19 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { CesiumGeometry::QuadtreeTileID(1, 1, 1)}; SECTION("Upsample bottom left child") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, lowerLeft, false); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -224,10 +229,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0]; @@ -287,14 +292,19 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { uvWriter[i].y = 1.0f - uvWriter[i].y; } - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, lowerLeft, true); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -304,10 +314,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0]; @@ -361,14 +371,19 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Upsample upper left child") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, upperLeft, false); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -378,10 +393,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0]; @@ -435,14 +450,17 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Upsample upper right child") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, upperRight, false); + if (!upsampledModel) { + return; + } - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -452,10 +470,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0]; @@ -509,14 +527,17 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Upsample bottom right child") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, lowerRight, false); + if (!upsampledModel) { + return; + } - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -526,10 +547,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0]; @@ -598,14 +619,18 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { primitive.extras = SkirtMeshMetadata::createGltfExtras(skirtMeshMetadata); SECTION("Check bottom left skirt") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, lowerLeft, false); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -615,10 +640,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); // check west edge @@ -703,14 +728,18 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Check upper left skirt") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, upperLeft, false); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -720,10 +749,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); // check west edge @@ -832,14 +861,17 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Check upper right skirt") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, upperRight, false); + if (!upsampledModel) { + return; + } - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -849,10 +881,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); // check west edge @@ -937,14 +969,19 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { } SECTION("Check bottom right skirt") { - Model upsampledModel = - *RasterOverlayUtilities::upsampleGltfForRasterOverlays( + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( model, lowerRight, false); - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel); + if (!upsampledModel) { + return; + } + + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -954,10 +991,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_SHORT indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); // check west edge @@ -1215,13 +1252,19 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_BYTE indices") { CesiumGeometry::UpsampledQuadtreeNode lowerLeft{ CesiumGeometry::QuadtreeTileID(1, 0, 0)}; - Model upsampledModel = *RasterOverlayUtilities::upsampleGltfForRasterOverlays( - model, - lowerLeft, - false); + std::optional upsampledModel = + RasterOverlayUtilities::upsampleGltfForRasterOverlays( + model, + lowerLeft, + false); + + REQUIRE(upsampledModel); + if (!upsampledModel) { + return; + } - REQUIRE(upsampledModel.meshes.size() == 1); - const Mesh& upsampledMesh = upsampledModel.meshes.back(); + REQUIRE(upsampledModel->meshes.size() == 1); + const Mesh& upsampledMesh = upsampledModel->meshes.back(); REQUIRE(upsampledMesh.primitives.size() == 1); const MeshPrimitive& upsampledPrimitive = upsampledMesh.primitives.back(); @@ -1231,10 +1274,10 @@ TEST_CASE("upsampleGltfForRasterOverlay with UNSIGNED_BYTE indices") { upsampledPrimitive.attributes.find("POSITION") != upsampledPrimitive.attributes.end()); AccessorView upsampledPosition( - upsampledModel, + *upsampledModel, upsampledPrimitive.attributes.at("POSITION")); AccessorView upsampledIndices( - upsampledModel, + *upsampledModel, upsampledPrimitive.indices); glm::vec3 p0 = upsampledPosition[0];