mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
205 lines
8.7 KiB
Go
205 lines
8.7 KiB
Go
package service_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/geospatial"
|
|
"bugulma/backend/internal/service"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type TransportationServiceTestSuite struct {
|
|
suite.Suite
|
|
geoCalc geospatial.Calculator
|
|
svc *service.TransportationService
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) SetupTest() {
|
|
suite.geoCalc = geospatial.NewCalculatorWithDefaults()
|
|
suite.svc = service.NewTransportationService(suite.geoCalc)
|
|
}
|
|
|
|
func TestTransportationService(t *testing.T) {
|
|
suite.Run(t, new(TransportationServiceTestSuite))
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestNewTransportationService() {
|
|
assert.NotNil(suite.T(), suite.svc)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Truck() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeTruck, 15.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Verify cost calculation (Berlin to Hamburg, ~290km, truck cost ~€0.12/km)
|
|
assert.Greater(suite.T(), cost.CostEur, 30.0) // Should be around €34.80
|
|
// Haversine distance for Berlin->Hamburg can be ~255km; use a lower bound
|
|
assert.Greater(suite.T(), cost.StraightDistanceKm, 250.0)
|
|
assert.Greater(suite.T(), cost.RoadDistanceKm, cost.StraightDistanceKm) // Road distance > straight distance
|
|
assert.Greater(suite.T(), cost.TimeHours, 4.0) // Should take several hours
|
|
assert.Equal(suite.T(), domain.TransportModeTruck, cost.TransportMode)
|
|
assert.Equal(suite.T(), 1.0, cost.EnvironmentalFactor) // Truck baseline
|
|
assert.Greater(suite.T(), cost.CapacityUtilization, 50.0) // 15/25 = 60% utilization
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Rail() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeRail, 50.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Rail should be cheaper than truck
|
|
assert.Greater(suite.T(), cost.CostEur, 20.0) // Should be around €23.20 (rail €0.08/km)
|
|
assert.Equal(suite.T(), domain.TransportModeRail, cost.TransportMode)
|
|
assert.Equal(suite.T(), 0.7, cost.EnvironmentalFactor) // Rail better for environment
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_Pipeline() {
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModePipe, 500.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Pipeline should be cheapest
|
|
assert.Greater(suite.T(), cost.CostEur, 5.0) // Should be around €5.80 (pipeline €0.02/km)
|
|
assert.Equal(suite.T(), domain.TransportModePipe, cost.TransportMode)
|
|
assert.Equal(suite.T(), 0.5, cost.EnvironmentalFactor) // Pipeline best for environment
|
|
assert.Greater(suite.T(), cost.CapacityUtilization, 0.0) // Some modes (like pipeline) may have very low utilization at small volumes.
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestCalculateTransportCost_VolumeExceedsCapacity() {
|
|
// Try to transport 150 tons with truck (max 25 tons)
|
|
_, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 53.5511, 9.9937, domain.TransportModeTruck, 150.0)
|
|
assert.Error(suite.T(), err)
|
|
assert.Contains(suite.T(), err.Error(), "transport volume exceeds capacity")
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestFindOptimalTransportRoutes() {
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 20.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Len(suite.T(), options, 3) // Should return all 3 transport modes
|
|
|
|
// Verify all transport modes are present
|
|
modeCount := make(map[domain.TransportMode]bool)
|
|
for _, option := range options {
|
|
modeCount[option.TransportMode] = true
|
|
}
|
|
assert.True(suite.T(), modeCount[domain.TransportModeTruck])
|
|
assert.True(suite.T(), modeCount[domain.TransportModeRail])
|
|
assert.True(suite.T(), modeCount[domain.TransportModePipe])
|
|
|
|
// Verify they're sorted by overall score (highest first)
|
|
for i := 0; i < len(options)-1; i++ {
|
|
assert.GreaterOrEqual(suite.T(), options[i].OverallScore, options[i+1].OverallScore)
|
|
}
|
|
|
|
// Pipeline should generally have the highest score due to cost and environment
|
|
// (though this depends on the exact scoring algorithm)
|
|
found := false
|
|
for _, option := range options {
|
|
if option.TransportMode == domain.TransportModePipe {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(suite.T(), found)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestFindOptimalTransportRoutes_LargeVolume() {
|
|
// Test with large volume that excludes some transport modes
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 150.0)
|
|
assert.NoError(suite.T(), err)
|
|
|
|
// Truck should be excluded (25 ton capacity), others should remain
|
|
for _, option := range options {
|
|
assert.NotEqual(suite.T(), domain.TransportModeTruck, option.TransportMode)
|
|
}
|
|
|
|
assert.Len(suite.T(), options, 2) // Rail and Pipeline only
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Truck() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModeTruck)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.12, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 60.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 25.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 1.0, profile.EnvironmentalFactor) // Pipeline best for environment
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Rail() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModeRail)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.08, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 40.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 200.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 0.7, profile.EnvironmentalFactor) // Rail better for environment
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_Pipeline() {
|
|
profile, err := suite.svc.GetTransportProfile(domain.TransportModePipe)
|
|
assert.NoError(suite.T(), err)
|
|
assert.Equal(suite.T(), 0.05, profile.CostPerKm)
|
|
assert.Equal(suite.T(), 100.0, profile.SpeedKmH)
|
|
assert.Equal(suite.T(), 1000.0, profile.MaxCapacity)
|
|
assert.Equal(suite.T(), 0.5, profile.EnvironmentalFactor)
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestGetTransportProfile_InvalidMode() {
|
|
_, err := suite.svc.GetTransportProfile(domain.TransportMode("invalid"))
|
|
assert.Error(suite.T(), err)
|
|
assert.Contains(suite.T(), err.Error(), "invalid transport mode")
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestTransportCost_SameLocation() {
|
|
// Test transport cost for same location (should still have some cost)
|
|
cost, err := suite.svc.CalculateTransportCost(52.5200, 13.4050, 52.5200, 13.4050, domain.TransportModeTruck, 10.0)
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotNil(suite.T(), cost)
|
|
|
|
// Distance should be very small
|
|
assert.Less(suite.T(), cost.StraightDistanceKm, 0.1)
|
|
assert.GreaterOrEqual(suite.T(), cost.CostEur, 0.0) // Should still have some cost
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestTransportOptions_CompleteData() {
|
|
options, err := suite.svc.FindOptimalTransportRoutes(50.1109, 8.6821, 52.5200, 13.4050, 10.0) // Frankfurt to Berlin
|
|
assert.NoError(suite.T(), err)
|
|
assert.NotEmpty(suite.T(), options)
|
|
|
|
// Verify all required fields are populated
|
|
for _, option := range options {
|
|
assert.NotEqual(suite.T(), domain.TransportMode(""), option.TransportMode)
|
|
assert.Greater(suite.T(), option.DistanceKm, 500.0) // Frankfurt to Berlin is ~550km
|
|
assert.Greater(suite.T(), option.CostEur, 10.0) // Should have meaningful cost
|
|
assert.Greater(suite.T(), option.TimeHours, 5.0) // Should take several hours
|
|
assert.GreaterOrEqual(suite.T(), option.EnvironmentalScore, 5.0) // Should have environmental score
|
|
// Some modes (like pipeline) may have very low utilization at small volumes.
|
|
// Ensure there is at least a non-zero utilization percentage.
|
|
assert.Greater(suite.T(), option.CapacityUtilization, 0.0)
|
|
assert.NotEqual(suite.T(), 0.0, option.OverallScore) // Should have overall score
|
|
}
|
|
}
|
|
|
|
func (suite *TransportationServiceTestSuite) TestEnvironmentalFactor_Impact() {
|
|
// Test that environmental factor affects scoring
|
|
options, err := suite.svc.FindOptimalTransportRoutes(52.5200, 13.4050, 53.5511, 9.9937, 10.0)
|
|
assert.NoError(suite.T(), err)
|
|
|
|
// Find pipeline option (should have highest environmental score)
|
|
var pipelineOption *domain.TransportOption
|
|
for _, option := range options {
|
|
if option.TransportMode == domain.TransportModePipe {
|
|
pipelineOption = option
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.NotNil(suite.T(), pipelineOption)
|
|
// Environmental score is computed as 10.0 / factor. For pipeline with 0.5,
|
|
// the expected score is 20.0.
|
|
assert.Equal(suite.T(), 20.0, pipelineOption.EnvironmentalScore)
|
|
}
|