Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 6 additions & 5 deletions internal/campaign/edge_case_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package campaign
import (
"context"
"fmt"
"math"
"path/filepath"
"sort"
"strings"
Expand Down Expand Up @@ -585,7 +586,11 @@ func (d *EdgeCaseDetector) parseNumber(arg interface{}) (float64, bool) {
case float32:
return float64(v), true
case float64:
return v, true
if math.IsNaN(v) || math.IsInf(v, 0) {
return 0, false
} else {
return v, true
}
default:
return 0, false
}
Expand Down Expand Up @@ -808,10 +813,6 @@ func (a *EdgeCaseAnalysis) GetPreworkTasks() []string {
// If an empty IntelligenceReport is passed, missing dependencies or metrics could lead
// to incorrect Action decisions.

// TODO: Missing Edge Case - Type Coercion: parseNumber handling NaN and +Inf.
// Check if Mangle returns NaN/Inf for floats; complexity logic might permanently
// trigger ActionRefactorFirst or create panics on math operations.

// TODO: Missing Edge Case - User Request Extremes: Unknown file extensions.
// For `.xyz` or unrecognized file extensions, suggestSplits appends hardcoded
// golang/typescript-style suffixes (`_types`, `_helpers`) which could be invalid syntax.
Expand Down
15 changes: 7 additions & 8 deletions internal/campaign/edge_case_detector_gaps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"
"testing"
"time"

)

// ============================================================================
Expand All @@ -18,7 +17,7 @@ import (
// TestEdgeCaseDetectorGap_AnalyzeFiles_CanceledContext (Vector 1: Empty/Nil Contexts)
func TestEdgeCaseDetectorGap_AnalyzeFiles_CanceledContext(t *testing.T) {
detector := NewEdgeCaseDetector(nil, nil)

ctx, cancel := context.WithCancel(context.Background())
cancel() // Cancel immediately

Expand All @@ -37,7 +36,7 @@ func TestEdgeCaseDetectorGap_AnalyzeFiles_CanceledContext(t *testing.T) {
// TestEdgeCaseDetectorGap_AnalyzeFiles_EmptyIntelligence (Vector 1: Empty Intel)
func TestEdgeCaseDetectorGap_AnalyzeFiles_EmptyIntelligence(t *testing.T) {
detector := NewEdgeCaseDetector(nil, nil)

// Initialized but empty intelligence report
intel := &IntelligenceReport{
FileTopology: make(map[string]FileInfo),
Expand Down Expand Up @@ -79,13 +78,13 @@ func TestEdgeCaseDetectorGap_TypeCoercion(t *testing.T) {

// Test NaN
nanVal, ok := detector.parseNumber(math.NaN())
if !ok || !math.IsNaN(nanVal) {
if ok || nanVal != 0 {
t.Errorf("parseNumber failed to handle NaN")
}

// Test Inf
infVal, ok := detector.parseNumber(math.Inf(1))
if !ok || !math.IsInf(infVal, 1) {
if ok || infVal != 0 {
t.Errorf("parseNumber failed to handle Inf")
}

Expand Down Expand Up @@ -124,7 +123,7 @@ func TestEdgeCaseDetectorGap_ImpactScoreBounds(t *testing.T) {
decision := FileDecision{
Dependents: []string{}, // length 0
}

// Simulate queryDependencies impact calculation
decision.ImpactScore = len(decision.Dependents)
if decision.ImpactScore < 0 {
Expand All @@ -142,7 +141,7 @@ func TestEdgeCaseDetectorGap_FormatForContext_Limits(t *testing.T) {
}

output := analysis.FormatForContext()

// Should truncate and show "and X more"
if !strings.Contains(output, "and 4990 more") {
t.Errorf("Expected truncation message 'and 4990 more', output was: %s", output)
Expand Down Expand Up @@ -173,7 +172,7 @@ func TestEdgeCaseDetectorGap_GodFile(t *testing.T) {
// TestEdgeCaseDetectorGap_Concurrency (Vector 4: Concurrency Safety)
func TestEdgeCaseDetectorGap_Concurrency(t *testing.T) {
detector := NewEdgeCaseDetector(nil, nil)

// Run 10 goroutines calling AnalyzeFiles with the same detector to check for race conditions
done := make(chan bool)
for i := 0; i < 10; i++ {
Expand Down
36 changes: 31 additions & 5 deletions internal/campaign/edge_case_detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package campaign

import (
"context"
"math"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -307,11 +308,6 @@ func TestEdgeCaseAnalysis_FileCategories(t *testing.T) {
// Test with `IntelligenceReport{FileTopology: map[string]FileInfo{}, GitChurnHotspots: []GitChurn{}}`.
// Expected behavior: Should default to ActionCreate gracefully.

// TODO: Missing Edge Case - Type Coercion: parseNumber handling NaN and +Inf.
// Test passing a float64 representing math.NaN() or math.Inf(1) to parseNumber.
// Expected behavior: If Mangle returns an anomalous float, complexity should not become infinite
// or cause ActionRefactorFirst permanently.

// TODO: Missing Edge Case - User Request Extremes: Unknown file extensions.
// Test `detectLanguage` with an esoteric extension like `.zig` or `.mojo` or `.xyz`.
// Expected behavior: Should return "unknown" and suggestions must still be logically sound without crashing.
Expand All @@ -329,3 +325,33 @@ func TestEdgeCaseAnalysis_FileCategories(t *testing.T) {
// TODO: Missing Edge Case - Extreme Values: Max file size boundaries.
// Test determineAction with `LineCount = math.MaxInt32`.
// Expected behavior: Should cleanly suggest ActionModularize without overflow in heuristics (e.g., complexity calc).

func TestEdgeCaseDetector_ParseNumber(t *testing.T) {
detector := NewEdgeCaseDetector(nil, nil)

tests := []struct {
name string
input interface{}
expected float64
ok bool
}{
{"Valid int", 42, 42.0, true},
{"Valid float64", 3.14, 3.14, true},
{"NaN", math.NaN(), 0, false},
{"Positive Infinity", math.Inf(1), 0, false},
{"Negative Infinity", math.Inf(-1), 0, false},
{"Invalid type", "not a number", 0, false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, ok := detector.parseNumber(tt.input)
if ok != tt.ok {
t.Errorf("parseNumber() ok = %v, want %v", ok, tt.ok)
}
if ok && result != tt.expected {
t.Errorf("parseNumber() result = %v, want %v", result, tt.expected)
}
})
}
}