package financial import ( "math" "testing" ) func TestNPVCalculator_CalculateNPV(t *testing.T) { calc := NewNPVCalculator() tests := []struct { name string capex float64 cashFlow float64 discountRate float64 years int wantPositive bool }{ { name: "Positive NPV", capex: 50000.0, cashFlow: 8000.0, discountRate: 0.08, years: 10, wantPositive: true, }, { name: "Negative NPV", capex: 100000.0, cashFlow: 5000.0, discountRate: 0.08, years: 10, wantPositive: false, }, { name: "Zero NPV", capex: 50000.0, cashFlow: 5525.0, // Approximately breakeven at 8% discountRate: 0.08, years: 10, wantPositive: false, // Will be very close to zero }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { npv := calc.CalculateNPV(tt.capex, tt.cashFlow, tt.discountRate, tt.years) if tt.wantPositive && npv <= 0 { t.Errorf("CalculateNPV() = %v, expected positive", npv) } if !tt.wantPositive && npv > 100 { // Allow small positive due to rounding t.Errorf("CalculateNPV() = %v, expected negative or near zero", npv) } }) } } func TestIRRCalculator_CalculateIRR(t *testing.T) { calc := NewIRRCalculator() tests := []struct { name string capex float64 cashFlow float64 years int expected float64 tolerance float64 }{ { name: "Reasonable IRR", capex: 50000.0, cashFlow: 8000.0, years: 10, expected: 9.6, // Approximately 9.6% tolerance: 1.0, }, { name: "High IRR", capex: 50000.0, cashFlow: 15000.0, years: 10, expected: 27.0, // Approximately 27% tolerance: 3.0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { irr := calc.CalculateIRR(tt.capex, tt.cashFlow, tt.years) if math.Abs(irr-tt.expected) > tt.tolerance { t.Errorf("CalculateIRR() = %v, expected ~%v (tolerance: %v)", irr, tt.expected, tt.tolerance) } }) } } func TestPaybackCalculator_CalculatePaybackPeriod(t *testing.T) { calc := NewPaybackCalculator() tests := []struct { name string capex float64 cashFlow float64 expected float64 }{ { name: "Quick payback", capex: 50000.0, cashFlow: 25000.0, expected: 2.0, // 2 years }, { name: "Long payback", capex: 100000.0, cashFlow: 20000.0, expected: 5.0, // 5 years }, { name: "Fractional payback", capex: 30000.0, cashFlow: 15000.0, expected: 2.0, // 2 years }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { payback := calc.CalculatePaybackPeriod(tt.capex, tt.cashFlow) if math.Abs(payback-tt.expected) > 0.01 { t.Errorf("CalculatePaybackPeriod() = %v, expected %v", payback, tt.expected) } }) } } func TestCapexEstimator_EstimateCapex(t *testing.T) { config := DefaultConfig() calc := NewCapexEstimator(config) tests := []struct { name string resourceType string distanceKm float64 annualVolume float64 expectedMin float64 expectedMax float64 }{ { name: "Heat short distance", resourceType: "heat", distanceKm: 5.0, annualVolume: 1000.0, expectedMin: 270000.0, // (5km * 50000 + 20000) * scaleFactor expectedMax: 280000.0, }, { name: "Heat long distance", resourceType: "heat", distanceKm: 50.0, annualVolume: 1000.0, expectedMin: 2520000.0, // (50km * 50000 + 20000) * scaleFactor expectedMax: 2530000.0, }, { name: "Biowaste", resourceType: "biowaste", distanceKm: 10.0, annualVolume: 1000.0, expectedMin: 70000.0, // (10km * 5000 + 20000) * scaleFactor expectedMax: 80000.0, }, { name: "Service", resourceType: "service", distanceKm: 10.0, annualVolume: 1000.0, expectedMin: 20000.0, // (10km * 0 + 20000) * scaleFactor expectedMax: 25000.0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { capex := calc.EstimateCapex(tt.resourceType, tt.distanceKm, tt.annualVolume) if capex < tt.expectedMin || capex > tt.expectedMax { t.Errorf("EstimateCapex() = %v, expected between %v and %v", capex, tt.expectedMin, tt.expectedMax) } }) } } func TestTransportCostCalculator_CalculateTransportCost(t *testing.T) { config := DefaultConfig() calc := NewTransportCostCalculator(config) tests := []struct { name string resourceType string distanceKm float64 expectedMin float64 expectedMax float64 }{ { name: "Heat transport", resourceType: "heat", distanceKm: 10.0, expectedMin: 0.005, // 10km * 0.0005/€km expectedMax: 0.006, }, { name: "Water transport", resourceType: "water", distanceKm: 10.0, expectedMin: 0.01, // 10km * 0.001/€km expectedMax: 0.011, }, { name: "Service transport", resourceType: "service", distanceKm: 10.0, expectedMin: 0.0, expectedMax: 0.1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cost := calc.CalculateTransportCost(tt.resourceType, tt.distanceKm) if cost < tt.expectedMin || cost > tt.expectedMax { t.Errorf("CalculateTransportCost() = %v, expected between %v and %v", cost, tt.expectedMin, tt.expectedMax) } }) } }