#include "reference_tolerance_policy.h" #include #include #include #include #include #include #include namespace { using fesa::test::ReferenceToleranceBranch; using fesa::test::ReferenceToleranceFamily; using fesa::test::ReferenceTolerancePolicy; using fesa::test::ReferenceToleranceRow; ReferenceToleranceFamily MakeFamily(std::string identity, std::vector components, bool blocking, std::vector rows) { return {std::move(identity), std::move(components), blocking, std::move(rows)}; } TEST(ReferenceTolerancePolicy, AppliesRelativeAndNearZeroThresholdsAtTheirInclusiveBoundaries) { const auto evaluation = ReferenceTolerancePolicy::Evaluate({MakeFamily( "displacement-translation", {"UX", "UY", "UZ"}, true, {{105.0, 100.0}, {105.001, 100.0}, {2.0, 1.0}, {2.001, 1.0}})}); ASSERT_TRUE(evaluation.valid); ASSERT_EQ(evaluation.families.size(), 1U); const auto& family = evaluation.families.front(); EXPECT_EQ(family.row_count, 4U); EXPECT_DOUBLE_EQ(family.reference_scale, 100.0); EXPECT_DOUBLE_EQ(family.near_zero_band, 1.0); EXPECT_EQ(family.near_zero_count, 2U); EXPECT_FALSE(family.passed); ASSERT_EQ(family.rows.size(), 4U); EXPECT_EQ(family.rows[0U].branch, ReferenceToleranceBranch::kRelative); EXPECT_TRUE(family.rows[0U].relative_error_applicable); EXPECT_DOUBLE_EQ(family.rows[0U].relative_error, 0.05); EXPECT_DOUBLE_EQ(family.rows[0U].threshold, 5.0); EXPECT_TRUE(family.rows[0U].passed); EXPECT_FALSE(family.rows[1U].passed); EXPECT_EQ(family.rows[2U].branch, ReferenceToleranceBranch::kNearZero); EXPECT_FALSE(family.rows[2U].relative_error_applicable); EXPECT_DOUBLE_EQ(family.rows[2U].threshold, 1.0); EXPECT_TRUE(family.rows[2U].passed); EXPECT_FALSE(family.rows[3U].passed); } TEST(ReferenceTolerancePolicy, RejectsFamiliesWhoseScaleRelativeRmsExceedsOnePercent) { const auto evaluation = ReferenceTolerancePolicy::Evaluate({MakeFamily( "reaction-force", {"RF1", "RF2", "RF3"}, true, {{101.1, 100.0}, {101.1, 100.0}, {101.1, 100.0}, {101.1, 100.0}})}); ASSERT_TRUE(evaluation.valid); const auto& family = evaluation.families.front(); EXPECT_EQ(family.row_count, 4U); EXPECT_TRUE(std::all_of(family.rows.begin(), family.rows.end(), [](const auto& row) { return row.passed; })); EXPECT_NEAR(family.relative_rms, 0.011, 1.0e-15); EXPECT_FALSE(family.rms_passed); EXPECT_FALSE(family.passed); EXPECT_FALSE(evaluation.passed); } TEST(ReferenceTolerancePolicy, FailsClosedForZeroScaleNonzeroErrorWithoutNonfiniteMetrics) { const auto evaluation = ReferenceTolerancePolicy::Evaluate( {MakeFamily("section-force", {"N"}, true, {{0.0, 0.0}, {1.0, 0.0}})}); ASSERT_TRUE(evaluation.valid); const auto& family = evaluation.families.front(); EXPECT_EQ(family.row_count, 2U); EXPECT_DOUBLE_EQ(family.reference_scale, 0.0); EXPECT_DOUBLE_EQ(family.near_zero_band, 0.0); EXPECT_EQ(family.near_zero_count, 2U); EXPECT_EQ(family.diagnostic_code, "zero-reference-scale-nonzero-error"); EXPECT_EQ(family.rows[0U].branch, ReferenceToleranceBranch::kZeroScaleExact); EXPECT_TRUE(family.rows[0U].passed); EXPECT_FALSE(family.rows[1U].passed); EXPECT_FALSE(family.rows[1U].relative_error_applicable); EXPECT_TRUE(std::isfinite(family.relative_rms)); EXPECT_DOUBLE_EQ(family.relative_rms, 0.0); EXPECT_FALSE(family.rms_passed); EXPECT_FALSE(family.passed); } TEST(ReferenceTolerancePolicy, KeepsWarningOnlyFamilyExceedanceOutOfBlockingVerdict) { const auto evaluation = ReferenceTolerancePolicy::Evaluate( {MakeFamily("translation", {"U1", "U2", "U3"}, true, {{0.0, 0.0}}), MakeFamily("rotation", {"UR1", "UR2", "UR3"}, false, {{1.0, 0.0}})}); ASSERT_TRUE(evaluation.valid); ASSERT_EQ(evaluation.families.size(), 2U); EXPECT_TRUE(evaluation.families[0U].passed); EXPECT_FALSE(evaluation.families[1U].passed); EXPECT_TRUE(evaluation.passed); } TEST(ReferenceTolerancePolicy, RejectsNonfiniteInputsBeforeToleranceEvaluation) { const auto evaluation = ReferenceTolerancePolicy::Evaluate( {MakeFamily("displacement-translation", {"UX", "UY", "UZ"}, true, {{std::numeric_limits::quiet_NaN(), 0.0}})}); EXPECT_FALSE(evaluation.valid); EXPECT_EQ(evaluation.diagnostic_code, "nonfinite-comparison-value"); EXPECT_TRUE(evaluation.families.empty()); } }