package pricing import ( "testing" "github.com/stretchr/testify/assert" ) func TestMMS43Prices(t *testing.T) { testCases := []struct { name string params PricingParams expectedPrices map[string]Price expectedError bool }{ { name: "First trip - should be free for passenger", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 0, // First trip Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 10000, // 10km in meters DriverDistance: 15000, // 15km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 0.0, Currency: "EUR"}, // Free for first trip "driver": {Amount: 4.5, Currency: "EUR"}, // 15km * 0.30€/km }, expectedError: false, }, { name: "Second trip - should be free for passenger", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 1, // Second trip Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 20000, // 20km in meters DriverDistance: 25000, // 25km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 0.0, Currency: "EUR"}, // Free for second trip "driver": {Amount: 7.5, Currency: "EUR"}, // 25km * 0.30€/km }, expectedError: false, }, { name: "Third trip - passenger should pay", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 2, // Third trip Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 10000, // 10km in meters DriverDistance: 10000, // 10km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 1.5, Currency: "EUR"}, // 10km * 0.15€/km "driver": {Amount: 3.0, Currency: "EUR"}, // 10km * 0.30€/km }, expectedError: false, }, { name: "Multiple trips - passenger pays normal rate", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 5, // Multiple trips Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 30000, // 30km in meters DriverDistance: 35000, // 35km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 4.5, Currency: "EUR"}, // 30km * 0.15€/km "driver": {Amount: 10.5, Currency: "EUR"}, // 35km * 0.30€/km }, expectedError: false, }, { name: "Zero distance - should return zero amounts", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 3, Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 0, DriverDistance: 0, }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 0.0, Currency: "EUR"}, "driver": {Amount: 0.0, Currency: "EUR"}, }, expectedError: false, }, { name: "Large distances - check calculation accuracy", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 10, Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 100000, // 100km in meters DriverDistance: 120000, // 120km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 15.0, Currency: "EUR"}, // 100km * 0.15€/km "driver": {Amount: 36.0, Currency: "EUR"}, // 120km * 0.30€/km }, expectedError: false, }, { name: "Edge case - exactly 2 trips history (3rd trip)", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 2, // Exactly at the limit Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 4000, // 4km in meters DriverDistance: 5000, // 5km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 0.6, Currency: "EUR"}, // 4km * 0.15€/km (first paid trip) "driver": {Amount: 1.5, Currency: "EUR"}, // 5km * 0.30€/km }, expectedError: false, }, { name: "Small distances with fractions", params: PricingParams{ Beneficiary: BeneficiaryParams{ History: 3, Priority: false, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 2000, // 2km in meters DriverDistance: 3000, // 3km in meters }, }, expectedPrices: map[string]Price{ "passenger": {Amount: 0.3, Currency: "EUR"}, // 2km * 0.15€/km "driver": {Amount: 0.9, Currency: "EUR"}, // 3km * 0.30€/km }, expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { pricingService, err := NewMMS43PricingService() assert.NoError(t, err) prices, err := pricingService.Prices(tc.params) if tc.expectedError { assert.Error(t, err) } else { assert.NoError(t, err) // Use InDelta for floating-point comparisons to handle precision issues assert.InDelta(t, tc.expectedPrices["passenger"].Amount, prices["passenger"].Amount, 0.001) assert.Equal(t, tc.expectedPrices["passenger"].Currency, prices["passenger"].Currency) assert.InDelta(t, tc.expectedPrices["driver"].Amount, prices["driver"].Amount, 0.001) assert.Equal(t, tc.expectedPrices["driver"].Currency, prices["driver"].Currency) } }) } } func TestMMS43PricingEdgeCases(t *testing.T) { pricingService, err := NewMMS43PricingService() assert.NoError(t, err) t.Run("Negative history should still work", func(t *testing.T) { params := PricingParams{ Beneficiary: BeneficiaryParams{ History: -1, // Edge case: negative history }, SharedMobility: SharedMobilityParams{ PassengerDistance: 10000, DriverDistance: 10000, }, } prices, err := pricingService.Prices(params) assert.NoError(t, err) // Should still be free (2 - (-1) = 3 > 0) assert.InDelta(t, 0.0, prices["passenger"].Amount, 0.001) assert.InDelta(t, 3.0, prices["driver"].Amount, 0.001) }) t.Run("Very high history", func(t *testing.T) { params := PricingParams{ Beneficiary: BeneficiaryParams{ History: 100, }, SharedMobility: SharedMobilityParams{ PassengerDistance: 10000, DriverDistance: 10000, }, } prices, err := pricingService.Prices(params) assert.NoError(t, err) // Should charge normal rate assert.InDelta(t, 1.5, prices["passenger"].Amount, 0.001) assert.InDelta(t, 3.0, prices["driver"].Amount, 0.001) }) }