#include "fesa/model/source_target_resolver.h" #include #include #include #include #include #include namespace { fesa::SourceTargetIndexEntry Entry(const fesa::SourceEntityKind entity_kind, std::string instance_name, std::string target_name, const std::int64_t source_label, std::string source_label_text, const fesa::EntityIndex entity_index, const std::size_t declaration_order) { fesa::SourceEntityId source_id{instance_name, source_label, std::move(source_label_text)}; return {entity_kind, std::move(instance_name), std::move(target_name), std::move(source_id), entity_index, declaration_order}; } std::vector Indices( const std::vector& targets) { std::vector indices; indices.reserve(targets.size()); for (const auto& target : targets) { indices.push_back(target.entity_index); } return indices; } void ExpectFailure(const fesa::SourceTargetIndex& index, fesa::SourceTargetQuery query, const std::string& code) { const auto result = fesa::SourceTargetResolver{index}.Resolve(query); ASSERT_FALSE(result.HasValue()); EXPECT_EQ(result.GetStatus().Category(), fesa::FailureCategory::kInput); ASSERT_FALSE(result.GetStatus().Diagnostics().empty()); EXPECT_EQ(result.GetStatus().Diagnostics()[0U].code, code); EXPECT_EQ(result.GetStatus().Diagnostics()[0U].entity_identity, query.target_name_or_label); } } // namespace TEST(SourceTargetResolver, SeparatesNamespacesAndInstancesAndExpandsInDeclarationOrder) { using fesa::SourceEntityKind; fesa::SourceTargetIndex index{{ Entry(SourceEntityKind::kNode, "Beam-1", "Ends", 20, "0020", 1U, 30U), Entry(SourceEntityKind::kElement, "Beam-1", "Ends", 700, "0700", 4U, 10U), Entry(SourceEntityKind::kNode, "Beam-1", "Ends", 10, "0010", 0U, 20U), Entry(SourceEntityKind::kNode, "Beam-2", "Ends", 10, "0010", 2U, 40U), Entry(SourceEntityKind::kNode, "Beam-1", "", 10, "0010", 0U, 0U), }}; const fesa::SourceTargetResolver resolver{index}; auto nodes = resolver.Resolve({SourceEntityKind::kNode, "bEaM-1", "eNdS"}); ASSERT_TRUE(nodes.HasValue()); EXPECT_EQ(Indices(nodes.Value()), (std::vector{0U, 1U})); EXPECT_EQ(nodes.Value()[0U].source_id.instance_name, "Beam-1"); EXPECT_EQ(nodes.Value()[0U].source_id.source_label_text, "0010"); auto elements = resolver.Resolve({SourceEntityKind::kElement, "BEAM-1", "ends"}); ASSERT_TRUE(elements.HasValue()); EXPECT_EQ(Indices(elements.Value()), (std::vector{4U})); auto second_instance = resolver.Resolve({SourceEntityKind::kNode, "beam-2", "ENDS"}); ASSERT_TRUE(second_instance.HasValue()); EXPECT_EQ(Indices(second_instance.Value()), (std::vector{2U})); auto direct = resolver.Resolve({SourceEntityKind::kNode, "Beam-1", "10"}); ASSERT_TRUE(direct.HasValue()); EXPECT_EQ(Indices(direct.Value()), (std::vector{0U})); } TEST(SourceTargetResolver, RejectsMissingAmbiguousAndNonpositiveTargets) { using fesa::SourceEntityKind; const fesa::SourceTargetIndex index{{ Entry(SourceEntityKind::kNode, "Beam-1", "", 10, "10", 0U, 0U), Entry(SourceEntityKind::kNode, "Beam-2", "", 10, "10", 1U, 1U), Entry(SourceEntityKind::kNode, "Beam-1", "10", 20, "20", 2U, 2U), Entry(SourceEntityKind::kNode, "Beam-1", "Shared", 10, "10", 0U, 3U), Entry(SourceEntityKind::kNode, "Beam-2", "Shared", 10, "10", 1U, 4U), }}; ExpectFailure(index, {SourceEntityKind::kNode, "", "Missing"}, "unresolved-source-target"); ExpectFailure(index, {SourceEntityKind::kNode, "", "0"}, "invalid-source-target"); ExpectFailure(index, {SourceEntityKind::kNode, "", "-7"}, "invalid-source-target"); ExpectFailure(index, {SourceEntityKind::kNode, "", "10"}, "ambiguous-source-target"); ExpectFailure(index, {SourceEntityKind::kNode, "", "Shared"}, "ambiguous-source-target"); ExpectFailure(index, {SourceEntityKind::kNode, "Beam-1", "10"}, "ambiguous-source-target"); } TEST(SourceTargetResolver, ReportsDuplicateMembershipsInDeterministicDeclarationOrder) { using fesa::SourceEntityKind; const fesa::SourceTargetIndex index{{ Entry(SourceEntityKind::kNode, "Beam-1", "Duplicate", 10, "10", 0U, 1U), Entry(SourceEntityKind::kNode, "Beam-1", "Duplicate", 10, "10", 0U, 9U), Entry(SourceEntityKind::kNode, "Beam-1", "Duplicate", 20, "20", 1U, 2U), Entry(SourceEntityKind::kNode, "Beam-1", "Duplicate", 20, "20", 1U, 7U), }}; const auto result = fesa::SourceTargetResolver{index}.Resolve( {SourceEntityKind::kNode, "Beam-1", "duplicate"}); ASSERT_FALSE(result.HasValue()); EXPECT_EQ(result.GetStatus().Category(), fesa::FailureCategory::kInput); ASSERT_EQ(result.GetStatus().Diagnostics().size(), 2U); EXPECT_EQ(result.GetStatus().Diagnostics()[0U].code, "duplicate-source-target"); EXPECT_EQ(result.GetStatus().Diagnostics()[0U].message, "Duplicate resolved source target 20."); EXPECT_EQ(result.GetStatus().Diagnostics()[1U].code, "duplicate-source-target"); EXPECT_EQ(result.GetStatus().Diagnostics()[1U].message, "Duplicate resolved source target 10."); }