feat: implement synthetic edge fallback in FindRoute

- Add addSyntheticEdgesForNode function that connects nodes to city hubs
- Modify FindRoute to add synthetic edges as fallback when no route found
- Write TestFindRouteWithSyntheticFallback test

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-15 01:33:23 +03:00
parent c92baeca02
commit 26c4be2d3a
3 changed files with 296 additions and 12 deletions

View File

@@ -544,6 +544,58 @@ func TestSortEdges_AlreadySorted(t *testing.T) {
}
}
// TestSelectHubStations tests the SelectHubStations function.
// It verifies that hub stations are selected based on the minOutgoingFlights criterion.
func TestSelectHubStations(t *testing.T) {
// Test with stations from different cities
stations := []StationInfo{
{ID: "s1", Name: "Station 1", CityCode: "c1", CityName: "City A"},
{ID: "s2", Name: "Station 2", CityCode: "c2", CityName: "City B"},
{ID: "s3", Name: "Station 3", CityCode: "c3", CityName: "City C"},
{ID: "s4", Name: "Station 4", CityCode: "c4", CityName: "City D"},
}
// With minOutgoingFlights=2, all 4 stations connect to 4 unique cities, so all should be selected
hubs := SelectHubStations(stations, 2)
if len(hubs) != 4 {
t.Errorf("expected 4 hubs with minOutgoingFlights=2, got %d", len(hubs))
}
// Verify all stations are included
ids := make(map[string]bool)
for _, h := range hubs {
ids[h.ID] = true
}
if !ids["s1"] || !ids["s2"] || !ids["s3"] || !ids["s4"] {
t.Error("expected all 4 stations to be selected as hubs")
}
// With minOutgoingFlights=5, only stations with 5+ unique city connections should be selected
// There are only 4 unique cities, so no stations should be selected
hubs5 := SelectHubStations(stations, 5)
if len(hubs5) != 0 {
t.Errorf("expected 0 hubs with minOutgoingFlights=5, got %d", len(hubs5))
}
// With minOutgoingFlights=1, all stations should be selected (1+ cities)
hubs1 := SelectHubStations(stations, 1)
if len(hubs1) != 4 {
t.Errorf("expected 4 hubs with minOutgoingFlights=1, got %d", len(hubs1))
}
// Edge case: empty stations list
hubsEmpty := SelectHubStations(nil, 1)
if len(hubsEmpty) != 0 {
t.Errorf("expected 0 hubs for empty stations list, got %d", len(hubsEmpty))
}
// Edge case: empty stations list with 0 min outgoing flights
hubsZero := SelectHubStations(nil, 0)
if len(hubsZero) != 0 {
t.Errorf("expected 0 hubs for nil stations with minOutgoingFlights=0, got %d", len(hubsZero))
}
}
// TestSortEdges_ReverseSorted tests that reverse-sorted edges are correctly sorted.
func TestSortEdges_ReverseSorted(t *testing.T) {
edges := []*Edge{
@@ -556,3 +608,44 @@ func TestSortEdges_ReverseSorted(t *testing.T) {
t.Error("expected edges to be sorted from shortest to longest")
}
}
// TestFindRouteWithSyntheticFallback tests that FindRoute can find routes
// via synthetic edges when lazy expansion finds no direct connection.
func TestFindRouteWithSyntheticFallback(t *testing.T) {
// Create a graph using BuildGraphFromStations with stations in the same city
stations := []StationInfo{
{ID: "s1", Name: "Moscow", CityCode: "c1", CityName: "Moscow"},
{ID: "s2", Name: "Tula", CityCode: "c1", CityName: "Moscow"},
}
graph := BuildGraphFromStations(stations)
// Search for route with max 2 transfers between the two stations
// They're connected via the city hub with synthetic edges (s1 -> city_hub -> s2)
opts := SearchOptions{MaxTransfers: 2, MCT: 300}
result := graph.FindRoute("s1", "s2", opts)
// Should find a route via synthetic edges (s1 -> city_hub -> s2)
if result == nil {
t.Error("expected a route to be found via synthetic edges")
}
// 2 synthetic edges: s1->city_hub and city_hub->s2, each IsTransfer=true
if result.TotalTransfers != 2 {
t.Errorf("expected 2 transfers (via city hub), got %d", result.TotalTransfers)
}
if result.TotalDuration <= 0 {
t.Errorf("expected positive duration, got %d", result.TotalDuration)
}
// Verify synthetic edges exist in the graph
edges := graph.Edges()
syntheticCount := 0
for _, e := range edges {
if e.Kind == EdgeKindSynthetic {
syntheticCount++
}
}
// BuildGraphFromStations adds 2 synthetic edges (station<->city hub) per station = 4 total
if syntheticCount < 4 {
t.Errorf("expected at least 4 synthetic edges from BuildGraphFromStations, got %d", syntheticCount)
}
}