package ucxl import ( "reflect" "testing" "time" ) func TestNewTemporalNavigator(t *testing.T) { tests := []struct { name string maxVersion int expectedMax int expectedCurrent int }{ { name: "positive max version", maxVersion: 10, expectedMax: 10, expectedCurrent: 10, }, { name: "zero max version", maxVersion: 0, expectedMax: 0, expectedCurrent: 0, }, { name: "negative max version defaults to 0", maxVersion: -5, expectedMax: 0, expectedCurrent: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { nav := NewTemporalNavigator(tt.maxVersion) if nav.GetMaxVersion() != tt.expectedMax { t.Errorf("GetMaxVersion() = %d, want %d", nav.GetMaxVersion(), tt.expectedMax) } if nav.GetCurrentVersion() != tt.expectedCurrent { t.Errorf("GetCurrentVersion() = %d, want %d", nav.GetCurrentVersion(), tt.expectedCurrent) } if nav.GetHistory() == nil { t.Error("History should be initialized") } if len(nav.GetHistory()) != 0 { t.Error("History should be empty initially") } }) } } func TestNavigateLatest(t *testing.T) { nav := NewTemporalNavigator(10) // Navigate to version 5 first nav.currentVersion = 5 segment := TemporalSegment{Type: TemporalLatest} result, err := nav.Navigate(segment) if err != nil { t.Fatalf("Navigate() error = %v, want nil", err) } if !result.Success { t.Error("Navigation should be successful") } if result.TargetVersion != 10 { t.Errorf("TargetVersion = %d, want 10", result.TargetVersion) } if result.PreviousVersion != 5 { t.Errorf("PreviousVersion = %d, want 5", result.PreviousVersion) } if nav.GetCurrentVersion() != 10 { t.Errorf("Current version = %d, want 10", nav.GetCurrentVersion()) } } func TestNavigateAny(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 segment := TemporalSegment{Type: TemporalAny} result, err := nav.Navigate(segment) if err != nil { t.Fatalf("Navigate() error = %v, want nil", err) } if !result.Success { t.Error("Navigation should be successful") } if result.TargetVersion != 5 { t.Errorf("TargetVersion = %d, want 5 (should stay at current)", result.TargetVersion) } if nav.GetCurrentVersion() != 5 { t.Errorf("Current version = %d, want 5", nav.GetCurrentVersion()) } } func TestNavigateSpecific(t *testing.T) { nav := NewTemporalNavigator(10) tests := []struct { name string version int shouldError bool expectedPos int }{ { name: "valid version", version: 7, shouldError: false, expectedPos: 7, }, { name: "version 0", version: 0, shouldError: false, expectedPos: 0, }, { name: "max version", version: 10, shouldError: false, expectedPos: 10, }, { name: "negative version", version: -1, shouldError: true, expectedPos: 10, // Should stay at original position }, { name: "version beyond max", version: 15, shouldError: true, expectedPos: 10, // Should stay at original position }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { nav.Reset() // Reset to max version segment := TemporalSegment{ Type: TemporalSpecific, Count: tt.version, } result, err := nav.Navigate(segment) if tt.shouldError { if err == nil { t.Error("Expected error but got none") } if result.Success { t.Error("Result should indicate failure") } } else { if err != nil { t.Errorf("Unexpected error: %v", err) } if !result.Success { t.Error("Result should indicate success") } } if nav.GetCurrentVersion() != tt.expectedPos { t.Errorf("Current version = %d, want %d", nav.GetCurrentVersion(), tt.expectedPos) } }) } } func TestNavigateBackward(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 tests := []struct { name string count int shouldError bool expectedPos int }{ { name: "valid backward navigation", count: 2, shouldError: false, expectedPos: 3, }, { name: "backward to version 0", count: 5, shouldError: false, expectedPos: 0, }, { name: "backward beyond version 0", count: 10, shouldError: true, expectedPos: 5, // Should stay at original position }, { name: "negative count", count: -1, shouldError: true, expectedPos: 5, // Should stay at original position }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { nav.currentVersion = 5 // Reset position segment := TemporalSegment{ Type: TemporalRelative, Direction: DirectionBackward, Count: tt.count, } result, err := nav.Navigate(segment) if tt.shouldError { if err == nil { t.Error("Expected error but got none") } if result.Success { t.Error("Result should indicate failure") } } else { if err != nil { t.Errorf("Unexpected error: %v", err) } if !result.Success { t.Error("Result should indicate success") } } if nav.GetCurrentVersion() != tt.expectedPos { t.Errorf("Current version = %d, want %d", nav.GetCurrentVersion(), tt.expectedPos) } }) } } func TestNavigateForward(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 tests := []struct { name string count int shouldError bool expectedPos int }{ { name: "valid forward navigation", count: 3, shouldError: false, expectedPos: 8, }, { name: "forward to max version", count: 5, shouldError: false, expectedPos: 10, }, { name: "forward beyond max version", count: 10, shouldError: true, expectedPos: 5, // Should stay at original position }, { name: "negative count", count: -1, shouldError: true, expectedPos: 5, // Should stay at original position }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { nav.currentVersion = 5 // Reset position segment := TemporalSegment{ Type: TemporalRelative, Direction: DirectionForward, Count: tt.count, } result, err := nav.Navigate(segment) if tt.shouldError { if err == nil { t.Error("Expected error but got none") } if result.Success { t.Error("Result should indicate failure") } } else { if err != nil { t.Errorf("Unexpected error: %v", err) } if !result.Success { t.Error("Result should indicate success") } } if nav.GetCurrentVersion() != tt.expectedPos { t.Errorf("Current version = %d, want %d", nav.GetCurrentVersion(), tt.expectedPos) } }) } } func TestNavigationHistory(t *testing.T) { nav := NewTemporalNavigator(10) // Perform several navigations segments := []TemporalSegment{ {Type: TemporalSpecific, Count: 5}, {Type: TemporalRelative, Direction: DirectionBackward, Count: 2}, {Type: TemporalLatest}, } for _, segment := range segments { nav.Navigate(segment) } history := nav.GetHistory() if len(history) != 3 { t.Errorf("History length = %d, want 3", len(history)) } // Check that all steps are recorded for i, step := range history { if step.Operation == "" { t.Errorf("Step %d should have operation recorded", i) } if step.Timestamp.IsZero() { t.Errorf("Step %d should have timestamp", i) } if !step.Success { t.Errorf("Step %d should be successful", i) } } // Test clear history nav.ClearHistory() if len(nav.GetHistory()) != 0 { t.Error("History should be empty after ClearHistory()") } } func TestSetMaxVersion(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 // Test increasing max version err := nav.SetMaxVersion(15) if err != nil { t.Errorf("SetMaxVersion(15) error = %v, want nil", err) } if nav.GetMaxVersion() != 15 { t.Errorf("Max version = %d, want 15", nav.GetMaxVersion()) } if nav.GetCurrentVersion() != 5 { t.Errorf("Current version should remain at 5, got %d", nav.GetCurrentVersion()) } // Test decreasing max version below current err = nav.SetMaxVersion(3) if err != nil { t.Errorf("SetMaxVersion(3) error = %v, want nil", err) } if nav.GetMaxVersion() != 3 { t.Errorf("Max version = %d, want 3", nav.GetMaxVersion()) } if nav.GetCurrentVersion() != 3 { t.Errorf("Current version should be adjusted to 3, got %d", nav.GetCurrentVersion()) } // Test negative max version err = nav.SetMaxVersion(-1) if err == nil { t.Error("SetMaxVersion(-1) should return error") } } func TestVersionInfo(t *testing.T) { nav := NewTemporalNavigator(10) info := VersionInfo{ Version: 5, Created: time.Now(), Author: "test-author", Description: "test version", Tags: []string{"stable", "release"}, } // Set version info nav.SetVersionInfo(5, info) // Retrieve version info retrievedInfo, exists := nav.GetVersionInfo(5) if !exists { t.Error("Version info should exist") } if retrievedInfo.Author != info.Author { t.Errorf("Author = %s, want %s", retrievedInfo.Author, info.Author) } // Test non-existent version _, exists = nav.GetVersionInfo(99) if exists { t.Error("Version info should not exist for version 99") } // Test GetAllVersions allVersions := nav.GetAllVersions() if len(allVersions) != 1 { t.Errorf("All versions count = %d, want 1", len(allVersions)) } } func TestCanNavigate(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 tests := []struct { name string direction string count int expected bool }{ {"can go backward 3", "backward", 3, true}, {"can go backward 5", "backward", 5, true}, {"cannot go backward 6", "backward", 6, false}, {"can go forward 3", "forward", 3, true}, {"can go forward 5", "forward", 5, true}, {"cannot go forward 6", "forward", 6, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var result bool if tt.direction == "backward" { result = nav.CanNavigateBackward(tt.count) } else { result = nav.CanNavigateForward(tt.count) } if result != tt.expected { t.Errorf("Can navigate %s %d = %v, want %v", tt.direction, tt.count, result, tt.expected) } }) } } func TestValidateTemporalSegment(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 tests := []struct { name string segment TemporalSegment shouldError bool }{ { name: "latest is valid", segment: TemporalSegment{Type: TemporalLatest}, shouldError: false, }, { name: "any is valid", segment: TemporalSegment{Type: TemporalAny}, shouldError: false, }, { name: "valid specific version", segment: TemporalSegment{Type: TemporalSpecific, Count: 7}, shouldError: false, }, { name: "specific version out of range", segment: TemporalSegment{Type: TemporalSpecific, Count: 15}, shouldError: true, }, { name: "valid backward navigation", segment: TemporalSegment{Type: TemporalRelative, Direction: DirectionBackward, Count: 3}, shouldError: false, }, { name: "backward navigation out of range", segment: TemporalSegment{Type: TemporalRelative, Direction: DirectionBackward, Count: 10}, shouldError: true, }, { name: "valid forward navigation", segment: TemporalSegment{Type: TemporalRelative, Direction: DirectionForward, Count: 3}, shouldError: false, }, { name: "forward navigation out of range", segment: TemporalSegment{Type: TemporalRelative, Direction: DirectionForward, Count: 10}, shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := nav.ValidateTemporalSegment(tt.segment) if tt.shouldError { if err == nil { t.Error("Expected error but got none") } } else { if err != nil { t.Errorf("Unexpected error: %v", err) } } }) } } func TestNavigatorClone(t *testing.T) { nav := NewTemporalNavigator(10) nav.currentVersion = 5 // Add some version info and history nav.SetVersionInfo(5, VersionInfo{Author: "test"}) nav.Navigate(TemporalSegment{Type: TemporalLatest}) cloned := nav.Clone() // Test that basic properties are cloned if cloned.GetCurrentVersion() != nav.GetCurrentVersion() { t.Error("Current version should be cloned") } if cloned.GetMaxVersion() != nav.GetMaxVersion() { t.Error("Max version should be cloned") } // Test that history is cloned originalHistory := nav.GetHistory() clonedHistory := cloned.GetHistory() if !reflect.DeepEqual(originalHistory, clonedHistory) { t.Error("History should be cloned") } // Test that version info is cloned originalVersions := nav.GetAllVersions() clonedVersions := cloned.GetAllVersions() if !reflect.DeepEqual(originalVersions, clonedVersions) { t.Error("Version info should be cloned") } // Test independence - modifying clone shouldn't affect original cloned.currentVersion = 0 if nav.GetCurrentVersion() == cloned.GetCurrentVersion() { t.Error("Clone should be independent") } } func TestGetLastNavigation(t *testing.T) { nav := NewTemporalNavigator(10) // Initially should return nil last := nav.GetLastNavigation() if last != nil { t.Error("GetLastNavigation() should return nil when no navigation has occurred") } // After navigation should return the step segment := TemporalSegment{Type: TemporalSpecific, Count: 5} nav.Navigate(segment) last = nav.GetLastNavigation() if last == nil { t.Error("GetLastNavigation() should return the last navigation step") } if last.Operation != segment.String() { t.Errorf("Operation = %s, want %s", last.Operation, segment.String()) } } // Benchmark tests func BenchmarkNavigate(b *testing.B) { nav := NewTemporalNavigator(100) segment := TemporalSegment{Type: TemporalSpecific, Count: 50} b.ResetTimer() for i := 0; i < b.N; i++ { nav.Navigate(segment) } } func BenchmarkValidateTemporalSegment(b *testing.B) { nav := NewTemporalNavigator(100) nav.currentVersion = 50 segment := TemporalSegment{Type: TemporalRelative, Direction: DirectionBackward, Count: 10} b.ResetTimer() for i := 0; i < b.N; i++ { nav.ValidateTemporalSegment(segment) } }