Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion pkg/adt/interval_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,16 @@ func TestIntervalTreeDelete(t *testing.T) {
require.Truef(t, reflect.DeepEqual(expectedAfterDelete11, visitsAfterDelete11), "level order after deleting '11' expected %v, got %v", expectedAfterDelete11, visitsAfterDelete11)
}

func TestIntervalTreeFind(t *testing.T) {
ivt := NewIntervalTree()
ivl1 := NewInt64Interval(3, 6)
assert.Nilf(t, ivt.Find(ivl1), "find expected nil on empty tree")
ivt.Insert(ivl1, 123)
assert.Equalf(t, ivl1, ivt.Find(ivl1).Ivl, "find expected to return exact-matched interval")
ivl2 := NewInt64Interval(3, 7)
assert.Nilf(t, ivt.Find(ivl2), "find expected nil on single-matched endpoint")
}
Comment on lines +272 to +300

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was looking for something more extensive. Quick prompt to ML gave me the following results:

func TestIntervalTreeFind(t *testing.T) {
	t.Run("Basic Find Operations", func(t *testing.T) {
		ivt := NewIntervalTree()
		ivl1 := NewInt64Interval(3, 6)
		val1 := 123

		// 1. Find on empty tree
		assert.Nil(t, ivt.Find(ivl1), "Find on empty tree should return nil")

		// 2. Insert and find exact match
		ivt.Insert(ivl1, val1)
		foundNode := ivt.Find(ivl1)
		assert.NotNil(t, foundNode, "Find should return the inserted interval")
		if foundNode != nil {
			assert.Equal(t, ivl1, foundNode.Ivl, "Found interval should match the inserted interval")
			assert.Equal(t, val1, foundNode.Val, "Found value should match the inserted value")
		}

		// 3. Find non-existent interval (overlapping start, different end)
		ivl2 := NewInt64Interval(3, 7)
		assert.Nil(t, ivt.Find(ivl2), "Find should return nil for an interval not exactly matching (different end)")

		// 4. Find non-existent interval (overlapping end, different start)
		ivl3 := NewInt64Interval(2, 6)
		assert.Nil(t, ivt.Find(ivl3), "Find should return nil for an interval not exactly matching (different start)")

		// 5. Find non-existent interval (completely different)
		ivl4 := NewInt64Interval(10, 20)
		assert.Nil(t, ivt.Find(ivl4), "Find should return nil for a completely different interval")

		// 6. Insert another interval and find both
		ivl5 := NewInt64Interval(10, 15)
		val5 := 456
		ivt.Insert(ivl5, val5)

		foundNode1 := ivt.Find(ivl1)
		assert.NotNil(t, foundNode1)
		if foundNode1 != nil {
			assert.Equal(t, ivl1, foundNode1.Ivl)
			assert.Equal(t, val1, foundNode1.Val)
		}

		foundNode5 := ivt.Find(ivl5)
		assert.NotNil(t, foundNode5)
		if foundNode5 != nil {
			assert.Equal(t, ivl5, foundNode5.Ivl)
			assert.Equal(t, val5, foundNode5.Val)
		}
	})

	t.Run("Find After Deletion", func(t *testing.T) {
		ivt := NewIntervalTree()
		ivlA := NewInt64Interval(1, 5)
		valA := "A"
		ivlB := NewInt64Interval(6, 10)
		valB := "B"

		ivt.Insert(ivlA, valA)
		ivt.Insert(ivlB, valB)

		assert.NotNil(t, ivt.Find(ivlA), "Should find ivlA before deletion")
		assert.NotNil(t, ivt.Find(ivlB), "Should find ivlB before deletion")

		deleted := ivt.Delete(ivlA)
		assert.True(t, deleted, "Delete should return true for an existing interval")
		assert.Nil(t, ivt.Find(ivlA), "Should not find ivlA after deletion")
		assert.NotNil(t, ivt.Find(ivlB), "Should still find ivlB after deleting ivlA")

		deleted = ivt.Delete(NewInt64Interval(100, 200)) // Non-existent
		assert.False(t, deleted, "Delete should return false for a non-existing interval")
	})

	t.Run("Find with StringComparable", func(t *testing.T) {
		ivt := NewIntervalTree()
		sivl1 := NewStringInterval("apple", "banana")
		sval1 := "fruit1"

		assert.Nil(t, ivt.Find(sivl1), "Find on empty string tree should return nil")

		ivt.Insert(sivl1, sval1)
		foundNode := ivt.Find(sivl1)
		assert.NotNil(t, foundNode, "Find should return the inserted string interval")
		if foundNode != nil {
			assert.Equal(t, sivl1, foundNode.Ivl)
			assert.Equal(t, sval1, foundNode.Val)
		}

		sivl2 := NewStringInterval("apple", "cherry") // Different end
		assert.Nil(t, ivt.Find(sivl2), "Find should return nil for a non-exact string interval")
	})

    t.Run("Find with overlapping but not identical intervals", func(t *testing.T) {
        ivt := NewIntervalTree()
        ivlBase := NewInt64Interval(5, 10)
        valBase := "base"
        ivt.Insert(ivlBase, valBase)

        // Test cases that overlap but are not identical
        testCases := []struct {
            name     string
            interval Interval
        }{
            {"Subset", NewInt64Interval(6, 9)},
            {"Superset", NewInt64Interval(4, 11)},
            {"OverlapLeft", NewInt64Interval(3, 7)},
            {"OverlapRight", NewInt64Interval(8, 12)},
            {"TouchesBegin", NewInt64Interval(3, 5)}, // Does not overlap [5,10)
            {"TouchesEnd", NewInt64Interval(10, 12)}, // Does not overlap [5,10)
        }

        for _, tc := range testCases {
            t.Run(tc.name, func(t *testing.T) {
                assert.Nil(t, ivt.Find(tc.interval), "Find(%v) should be nil as it's not an exact match for %v", tc.interval, ivlBase)
            })
        }
         // Ensure the base interval is still findable
        foundNode := ivt.Find(ivlBase)
        assert.NotNil(t, foundNode)
        if foundNode != nil {
            assert.Equal(t, ivlBase, foundNode.Ivl)
        }
    })
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I've expanded TestIntervalTreeFind with a couple workflows along the above code sample. Also checking Find is nil after Delete in TestIntervalTreeRandom.

Let me know if there's more specific cases I should include. Trying to keep the test style +coverage consistent with the rest of interval_tree_test.go.


func TestIntervalTreeIntersects(t *testing.T) {
ivt := NewIntervalTree()
ivt.Insert(NewStringInterval("1", "3"), 123)
Expand Down Expand Up @@ -341,7 +351,11 @@ func TestIntervalTreeRandom(t *testing.T) {
require.NotEmptyf(t, ivt.Stab(NewInt64Point(v)), "expected %v stab non-zero for [%+v)", v, xy)
require.Truef(t, ivt.Intersects(NewInt64Point(v)), "did not get %d as expected for [%+v)", v, xy)
}
assert.Truef(t, ivt.Delete(NewInt64Interval(ab.x, ab.y)), "did not delete %v as expected", ab)
ivl := NewInt64Interval(ab.x, ab.y)
iv := ivt.Find(ivl)
assert.NotNilf(t, iv, "expected find non-nil on %v", ab)
assert.Equalf(t, ivl, iv.Ivl, "find did not get matched interval %v", ab)
assert.Truef(t, ivt.Delete(ivl), "did not delete %v as expected", ab)
delete(ivs, ab)
}

Expand Down