#include "gtest/gtest.h" #include "RifRftSegment.h" #include "RiaRftDefines.h" #include #include #include namespace { //-------------------------------------------------------------------------------------------------- /// Build a topology with two tubing branches and their device segments. /// /// Tubing branch 1 (deep) : segment numbers 1-2, branch id 1 /// Tubing branch 2 (shallow) : segment numbers 3-4, branch id 2 /// Device segments for branch 2 : segment numbers 5-6, branch ids 11-12, outflow to segments 3-4 /// Device segments for branch 1 : segment numbers 7-8, branch ids 13-14, outflow to segments 1-2 /// /// The device segments for branch 2 are stored immediately before the device segments for branch 1. //-------------------------------------------------------------------------------------------------- RifRftSegment buildTwoBranchSegment() { // RifRftSegmentData( segnxt, brno, brnst, brnen, segNo ) std::vector topology; topology.emplace_back( 0, 1, 1, 2, 1 ); topology.emplace_back( 1, 1, 1, 2, 2 ); topology.emplace_back( 0, 2, 3, 4, 3 ); topology.emplace_back( 3, 2, 3, 4, 4 ); topology.emplace_back( 3, 11, 5, 5, 5 ); topology.emplace_back( 4, 12, 6, 6, 6 ); topology.emplace_back( 1, 13, 7, 7, 7 ); topology.emplace_back( 2, 14, 8, 8, 8 ); RifRftSegment segment; segment.setSegmentData( topology ); return segment; } //-------------------------------------------------------------------------------------------------- /// Classify the two tubing branches, as done before device branches are identified. //-------------------------------------------------------------------------------------------------- void classifyTubingBranches( RifRftSegment& segment ) { segment.setBranchType( 1, RiaDefines::RftBranchType::RFT_TUBING ); segment.setOneBasedBranchIndex( 1, 1 ); segment.setBranchType( 2, RiaDefines::RftBranchType::RFT_TUBING ); segment.setOneBasedBranchIndex( 2, 2 ); } //-------------------------------------------------------------------------------------------------- /// Measured depths (SEGLENST) indexed by topology position. Branch 1 (deep) is at greater measured /// depth than branch 2 (shallow), and the depths increase monotonically across the boundary between /// the branch-2 and branch-1 device segments. //-------------------------------------------------------------------------------------------------- std::vector seglenstValues() { return { 3700.0, 3800.0, 2700.0, 2800.0, 2700.0, 2800.0, 3700.0, 3800.0 }; } } // namespace //-------------------------------------------------------------------------------------------------- /// Verify that a device branch only claims the device segments that actually connect to its tubing /// branch, and does not absorb device segments belonging to another tubing branch. /// /// Reproduces a topology where a lower-numbered tubing branch (index 1) is located at greater /// measured depth than a higher-numbered tubing branch (index 2). A measured-depth-only terminator /// would incorrectly absorb the branch-1 device segments into branch index 2. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, DeviceBranchDoesNotAbsorbSegmentsFromOtherBranch ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); auto seglenst = seglenstValues(); // Build the device branch for tubing branch index 2, starting at the first device segment that // feeds branch 2 (segment number 5). segment.createDeviceBranch( 5, 2, seglenst ); // The device segments feeding branch 2 must be assigned to branch index 2. EXPECT_EQ( RiaDefines::RftBranchType::RFT_DEVICE, segment.branchType( 11 ) ); EXPECT_EQ( RiaDefines::RftBranchType::RFT_DEVICE, segment.branchType( 12 ) ); EXPECT_EQ( 2, segment.oneBasedBranchIndexForBranchId( 11 ) ); EXPECT_EQ( 2, segment.oneBasedBranchIndexForBranchId( 12 ) ); // The device segments feeding branch 1 must NOT be absorbed into branch index 2. EXPECT_EQ( RiaDefines::RftBranchType::RFT_UNKNOWN, segment.branchType( 13 ) ); EXPECT_EQ( RiaDefines::RftBranchType::RFT_UNKNOWN, segment.branchType( 14 ) ); EXPECT_EQ( -1, segment.oneBasedBranchIndexForBranchId( 13 ) ); EXPECT_EQ( -1, segment.oneBasedBranchIndexForBranchId( 14 ) ); // Building the device branch for tubing branch index 1 assigns the remaining device segments. segment.createDeviceBranch( 7, 1, seglenst ); EXPECT_EQ( RiaDefines::RftBranchType::RFT_DEVICE, segment.branchType( 13 ) ); EXPECT_EQ( RiaDefines::RftBranchType::RFT_DEVICE, segment.branchType( 14 ) ); EXPECT_EQ( 1, segment.oneBasedBranchIndexForBranchId( 13 ) ); EXPECT_EQ( 1, segment.oneBasedBranchIndexForBranchId( 14 ) ); } //-------------------------------------------------------------------------------------------------- /// branchIds() returns the unique branch numbers in sorted order. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, BranchIdsAreUniqueAndSorted ) { RifRftSegment segment = buildTwoBranchSegment(); std::vector expected = { 1, 2, 11, 12, 13, 14 }; EXPECT_EQ( expected, segment.branchIds() ); } //-------------------------------------------------------------------------------------------------- /// Segment lookup by segment number and by index, including lookups that do not match. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, SegmentLookup ) { RifRftSegment segment = buildTwoBranchSegment(); // Lookup by segment number const auto* seg3 = segment.segmentData( 3 ); ASSERT_NE( nullptr, seg3 ); EXPECT_EQ( 3, seg3->segNo() ); EXPECT_EQ( 2, seg3->segBrno() ); EXPECT_EQ( nullptr, segment.segmentData( 99 ) ); // Segment number to index EXPECT_EQ( 2, segment.segmentIndexFromSegmentNumber( 3 ) ); EXPECT_EQ( -1, segment.segmentIndexFromSegmentNumber( 99 ) ); // Lookup by index const auto* firstSeg = segment.segmentDataByIndex( 0 ); ASSERT_NE( nullptr, firstSeg ); EXPECT_EQ( 1, firstSeg->segNo() ); EXPECT_EQ( 1, firstSeg->segBrno() ); } //-------------------------------------------------------------------------------------------------- /// Unknown branches default to RFT_UNKNOWN type and branch index -1. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, UnknownBranchDefaults ) { RifRftSegment segment = buildTwoBranchSegment(); EXPECT_EQ( RiaDefines::RftBranchType::RFT_UNKNOWN, segment.branchType( 11 ) ); EXPECT_EQ( -1, segment.oneBasedBranchIndexForBranchId( 11 ) ); EXPECT_EQ( -1, segment.oneBasedBranchIndexForBranchId( 999 ) ); } //-------------------------------------------------------------------------------------------------- /// tubingBranchIds() returns only the branches classified as tubing. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, TubingBranchIdsFiltersByType ) { RifRftSegment segment = buildTwoBranchSegment(); // No branch is classified yet EXPECT_TRUE( segment.tubingBranchIds().empty() ); classifyTubingBranches( segment ); std::vector expected = { 1, 2 }; EXPECT_EQ( expected, segment.tubingBranchIds() ); } //-------------------------------------------------------------------------------------------------- /// segmentIndicesForBranchNumber() returns the indices for one branch, or all when branchNumber<=0. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, SegmentIndicesForBranchNumber ) { RifRftSegment segment = buildTwoBranchSegment(); std::vector expectedBranch2 = { 2, 3 }; EXPECT_EQ( expectedBranch2, segment.segmentIndicesForBranchNumber( 2 ) ); // branchNumber <= 0 returns all segment indices EXPECT_EQ( 8u, segment.segmentIndicesForBranchNumber( 0 ).size() ); EXPECT_EQ( 8u, segment.segmentIndicesForBranchNumber( -1 ).size() ); } //-------------------------------------------------------------------------------------------------- /// segmentIndicesForBranchIndex() filters on both the one-based branch index and the branch type. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, SegmentIndicesForBranchIndexFiltersByIndexAndType ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); std::vector expectedBranch2 = { 2, 3 }; EXPECT_EQ( expectedBranch2, segment.segmentIndicesForBranchIndex( 2, RiaDefines::RftBranchType::RFT_TUBING ) ); std::vector expectedBranch1 = { 0, 1 }; EXPECT_EQ( expectedBranch1, segment.segmentIndicesForBranchIndex( 1, RiaDefines::RftBranchType::RFT_TUBING ) ); // Matching index but wrong branch type yields nothing EXPECT_TRUE( segment.segmentIndicesForBranchIndex( 2, RiaDefines::RftBranchType::RFT_DEVICE ).empty() ); // branchIndex <= 0 returns all segment indices EXPECT_EQ( 8u, segment.segmentIndicesForBranchIndex( 0, RiaDefines::RftBranchType::RFT_TUBING ).size() ); } //-------------------------------------------------------------------------------------------------- /// segmentNumbersForBranchIndex() returns segment numbers for a given branch index and type. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, SegmentNumbersForBranchIndex ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); std::vector expected = { 3, 4 }; EXPECT_EQ( expected, segment.segmentNumbersForBranchIndex( 2, RiaDefines::RftBranchType::RFT_TUBING ) ); } //-------------------------------------------------------------------------------------------------- /// branchIdsAndOneBasedBranchIndices() filters by branch type, and returns all for RFT_UNKNOWN. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, BranchIdsAndOneBasedBranchIndicesFiltersByType ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); auto tubingMap = segment.branchIdsAndOneBasedBranchIndices( RiaDefines::RftBranchType::RFT_TUBING ); std::map expectedTubing = { { 1, 1 }, { 2, 2 } }; EXPECT_EQ( expectedTubing, tubingMap ); // No device branches are assigned yet EXPECT_TRUE( segment.branchIdsAndOneBasedBranchIndices( RiaDefines::RftBranchType::RFT_DEVICE ).empty() ); // RFT_UNKNOWN returns all branches that have a one-based index assigned auto allMap = segment.branchIdsAndOneBasedBranchIndices( RiaDefines::RftBranchType::RFT_UNKNOWN ); EXPECT_EQ( expectedTubing, allMap ); } //-------------------------------------------------------------------------------------------------- /// After both device branches are built, they are reported with their tubing branch index. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, DeviceBranchesReportedAfterBuild ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); auto seglenst = seglenstValues(); segment.createDeviceBranch( 5, 2, seglenst ); segment.createDeviceBranch( 7, 1, seglenst ); auto deviceMap = segment.branchIdsAndOneBasedBranchIndices( RiaDefines::RftBranchType::RFT_DEVICE ); std::map expectedDevice = { { 11, 2 }, { 12, 2 }, { 13, 1 }, { 14, 1 } }; EXPECT_EQ( expectedDevice, deviceMap ); std::set expectedIndices = { 1, 2 }; EXPECT_EQ( expectedIndices, segment.uniqueOneBasedBranchIndices( RiaDefines::RftBranchType::RFT_TUBING ) ); } //-------------------------------------------------------------------------------------------------- /// createDeviceBranch() stops claiming segments when it reaches an already typed branch. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, DeviceBranchStopsAtAlreadyTypedSegment ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); // Pre-classify the first branch-2 device segment as a device segment of a different branch segment.setBranchType( 11, RiaDefines::RftBranchType::RFT_DEVICE ); segment.setOneBasedBranchIndex( 11, 1 ); auto seglenst = seglenstValues(); segment.createDeviceBranch( 5, 2, seglenst ); // The already typed branch keeps its index and nothing further is claimed EXPECT_EQ( 1, segment.oneBasedBranchIndexForBranchId( 11 ) ); EXPECT_EQ( -1, segment.oneBasedBranchIndexForBranchId( 12 ) ); } //-------------------------------------------------------------------------------------------------- /// nonContinuousDeviceSegmentIndices() returns nothing when there are fewer than two device segments. //-------------------------------------------------------------------------------------------------- TEST( RifRftSegmentTest, NonContinuousDeviceSegmentIndicesEmptyForFewSegments ) { RifRftSegment segment = buildTwoBranchSegment(); classifyTubingBranches( segment ); // Branch index 2 has no device segments before they are built EXPECT_TRUE( segment.nonContinuousDeviceSegmentIndices( 2 ).empty() ); }