diff --git a/pkg/models/geo.go b/pkg/models/geo.go index b8c8ffe19..5f27db85a 100644 --- a/pkg/models/geo.go +++ b/pkg/models/geo.go @@ -112,9 +112,13 @@ func (pcg precomputedCellGeometry) CalculateCovering() (s2.CellUnion, error) { // * geo.ErrRadiusMustBeLargerThan0 func UnionVolumes4D(volumes ...*Volume4D) (*Volume4D, error) { result := &Volume4D{} + var unboundedStartTime, unboundedEndTime bool for _, volume := range volumes { - if volume.EndTime != nil { + if volume.EndTime == nil { + unboundedEndTime = true + result.EndTime = nil + } else if !unboundedEndTime { if result.EndTime != nil { if volume.EndTime.After(*result.EndTime) { *result.EndTime = *volume.EndTime @@ -124,7 +128,10 @@ func UnionVolumes4D(volumes ...*Volume4D) (*Volume4D, error) { } } - if volume.StartTime != nil { + if volume.StartTime == nil { + unboundedStartTime = true + result.StartTime = nil + } else if !unboundedStartTime { if result.StartTime != nil { if volume.StartTime.Before(*result.StartTime) { *result.StartTime = *volume.StartTime diff --git a/pkg/models/geo_test.go b/pkg/models/geo_test.go index 148d25108..747448a7a 100644 --- a/pkg/models/geo_test.go +++ b/pkg/models/geo_test.go @@ -2,8 +2,10 @@ package models import ( "testing" + "time" "github.com/golang/geo/s2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -53,3 +55,71 @@ func TestPolygonCovering(t *testing.T) { require.NoError(t, err) require.Equal(t, want, got) } + +func TestUnionVolumes4D_Time(t *testing.T) { + now := time.Now() + start := now.Add(time.Hour) + end := start.Add(time.Hour) + + nextStart := end.Add(time.Hour) + nextEnd := nextStart.Add(time.Hour) + + tests := []struct { + name string + volumes []*Volume4D + wantStartTime *time.Time + wantEndTime *time.Time + }{ + { + name: "unbounded", + volumes: []*Volume4D{{}}, + wantStartTime: nil, + wantEndTime: nil, + }, + { + name: "single bounded", + volumes: []*Volume4D{{StartTime: &start, EndTime: &end}}, + wantStartTime: &start, + wantEndTime: &end, + }, + { + name: "single unbounded start", + volumes: []*Volume4D{{EndTime: &end}}, + wantStartTime: nil, + wantEndTime: &end, + }, + { + name: "single unbounded end", + volumes: []*Volume4D{{StartTime: &start}}, + wantStartTime: &start, + wantEndTime: nil, + }, + { + name: "multiple bounded", + volumes: []*Volume4D{{StartTime: &start, EndTime: &end}, {StartTime: &nextStart, EndTime: &nextEnd}}, + wantStartTime: &start, + wantEndTime: &nextEnd, + }, + { + name: "multiple unbounded", + volumes: []*Volume4D{{StartTime: &start, EndTime: &end}, {}}, + wantStartTime: nil, + wantEndTime: nil, + }, + { + name: "multiple unbounded combination", + volumes: []*Volume4D{{StartTime: &start}, {EndTime: &nextEnd}}, + wantStartTime: nil, + wantEndTime: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + union, err := UnionVolumes4D(tt.volumes...) + require.NoError(t, err) + assert.Equal(t, tt.wantStartTime, union.StartTime) + assert.Equal(t, tt.wantEndTime, union.EndTime) + }) + } +}