mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Initialize git repository - Add comprehensive .gitignore for Go projects - Install golangci-lint v2.6.0 (latest v2) globally - Configure .golangci.yml with appropriate linters and formatters - Fix all formatting issues (gofmt) - Fix all errcheck issues (unchecked errors) - Adjust complexity threshold for validation functions - All checks passing: build, test, vet, lint
169 lines
6.6 KiB
Go
169 lines
6.6 KiB
Go
package models
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/damirmukimov/city_resource_graph/models/cost"
|
|
"github.com/damirmukimov/city_resource_graph/models/customer"
|
|
"github.com/damirmukimov/city_resource_graph/models/impact"
|
|
"github.com/damirmukimov/city_resource_graph/models/params"
|
|
"github.com/damirmukimov/city_resource_graph/models/revenue"
|
|
"github.com/damirmukimov/city_resource_graph/models/validator"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCalculate(t *testing.T) {
|
|
p := createTestParamsForCalc()
|
|
|
|
result, err := Calculate(p)
|
|
require.NoError(t, err, "Calculate should not return an error")
|
|
|
|
assert.Equal(t, 3, len(result.Years), "Should calculate 3 years")
|
|
|
|
// Test Year 1
|
|
year1 := result.Years[0]
|
|
assert.Equal(t, 1, year1.Year, "Year 1 should have year=1")
|
|
assert.Equal(t, 500, year1.Customer.TotalOrgs, "Year 1 should have 500 total orgs")
|
|
assert.Equal(t, 150, year1.Customer.PayingOrgs, "Year 1 should have 150 paying orgs")
|
|
|
|
// Test that types are correct
|
|
assert.IsType(t, revenue.RevenueBreakdown{}, year1.Revenue, "Revenue should be RevenueBreakdown")
|
|
assert.IsType(t, cost.CostBreakdown{}, year1.Costs, "Costs should be CostBreakdown")
|
|
assert.IsType(t, impact.ImpactMetrics{}, year1.Impact, "Impact should be ImpactMetrics")
|
|
assert.IsType(t, customer.CustomerMetrics{}, year1.Customer, "Customer should be CustomerMetrics")
|
|
assert.IsType(t, customer.TierDistribution{}, year1.TierDist, "TierDist should be TierDistribution")
|
|
assert.IsType(t, validator.ValidationResult{}, year1.Validation, "Validation should be ValidationResult")
|
|
|
|
// Test ARPU range (B2B SaaS typical)
|
|
assert.True(t, year1.ARPU > 300, "Year 1 ARPU should be above 300")
|
|
assert.True(t, year1.ARPU < 6000, "Year 1 ARPU should be below 6000")
|
|
|
|
// Test summary
|
|
assert.True(t, result.Summary.TotalRevenue > 0, "Total revenue should be positive")
|
|
assert.True(t, result.Summary.TotalProfit > 0, "Total profit should be positive")
|
|
assert.True(t, result.Summary.TotalCO2Avoided > 0, "Total CO2 avoided should be positive")
|
|
}
|
|
|
|
func TestCalculateYear(t *testing.T) {
|
|
p := createTestParamsForCalc()
|
|
|
|
year1, err := CalculateYear(1, p)
|
|
require.NoError(t, err, "CalculateYear should not return an error")
|
|
|
|
assert.Equal(t, 1, year1.Year, "Should return year 1")
|
|
assert.Equal(t, 500, year1.Customer.TotalOrgs, "Should calculate customer metrics")
|
|
assert.True(t, year1.Revenue.Total > 0, "Should calculate revenue")
|
|
assert.True(t, year1.Costs.Total > 0, "Should calculate costs")
|
|
assert.True(t, year1.Impact.CO2Avoided > 0, "Should calculate impact")
|
|
}
|
|
|
|
func TestCalculateSummary(t *testing.T) {
|
|
// Create test data
|
|
years := []YearResult{
|
|
{
|
|
Revenue: revenue.RevenueBreakdown{Total: 100000.0},
|
|
Costs: cost.CostBreakdown{Total: 80000.0},
|
|
Profit: 20000.0,
|
|
Impact: impact.ImpactMetrics{
|
|
CO2Avoided: 1000.0,
|
|
WaterReused: 50000.0,
|
|
WasteDiverted: 2000.0,
|
|
},
|
|
},
|
|
{
|
|
Revenue: revenue.RevenueBreakdown{Total: 150000.0},
|
|
Costs: cost.CostBreakdown{Total: 100000.0},
|
|
Profit: 50000.0,
|
|
Impact: impact.ImpactMetrics{
|
|
CO2Avoided: 1500.0,
|
|
WaterReused: 75000.0,
|
|
WasteDiverted: 3000.0,
|
|
},
|
|
},
|
|
}
|
|
|
|
// Test the summary calculation directly
|
|
summary := calculateSummary(years)
|
|
|
|
assert.InDelta(t, 250000.0, summary.TotalRevenue, 0.01, "Total revenue should be sum of all years")
|
|
assert.InDelta(t, 180000.0, summary.TotalCosts, 0.01, "Total costs should be sum of all years")
|
|
assert.InDelta(t, 70000.0, summary.TotalProfit, 0.01, "Total profit should be sum of all years")
|
|
assert.InDelta(t, 2500.0, summary.TotalCO2Avoided, 0.01, "Total CO2 avoided should be sum of all years")
|
|
assert.InDelta(t, 125000.0, summary.TotalWaterReused, 0.01, "Total water reused should be sum of all years")
|
|
assert.InDelta(t, 5000.0, summary.TotalWasteDiverted, 0.01, "Total waste diverted should be sum of all years")
|
|
}
|
|
|
|
func createTestParamsForCalc() *params.Params {
|
|
return ¶ms.Params{
|
|
Time: params.TimeParams{Years: []int{1, 2, 3}},
|
|
Adoption: params.AdoptionParams{
|
|
TotalOrgs: params.YearlyInt{"1": 500, "2": 2000, "3": 5000},
|
|
PayingShare: params.YearlyFloat{"1": 0.3, "2": 0.3, "3": 0.3},
|
|
},
|
|
Pricing: params.PricingParams{
|
|
Basic: 35.0,
|
|
Business: 120.0,
|
|
Enterprise: 400.0,
|
|
BlendedUplift: params.BlendedUplift{
|
|
Basic: 0.20,
|
|
Business: 0.25,
|
|
Enterprise: 0.25,
|
|
},
|
|
TierMix: params.YearlyTierMix{
|
|
"1": params.TierMix{Basic: 0.60, Business: 0.30, Enterprise: 0.10},
|
|
"2": params.TierMix{Basic: 0.60, Business: 0.30, Enterprise: 0.10},
|
|
"3": params.TierMix{Basic: 0.54, Business: 0.38, Enterprise: 0.08},
|
|
},
|
|
},
|
|
Transactions: params.TransactionParams{
|
|
AvgIntroFee: 550.0,
|
|
IntrosPerYear: params.YearlyInt{"1": 200, "2": 400, "3": 600},
|
|
IntroConversion: params.YearlyFloat{"1": 0.35, "2": 0.38, "3": 0.40},
|
|
ServiceGMV: params.YearlyFloat{"1": 300000, "2": 800000, "3": 1500000},
|
|
ServiceCommission: 0.15,
|
|
GroupGMV: params.YearlyFloat{"1": 200000, "2": 400000, "3": 800000},
|
|
GroupCommission: 0.04,
|
|
},
|
|
Municipal: params.MunicipalParams{
|
|
Cities: params.YearlyInt{"1": 1, "2": 2, "3": 4},
|
|
AvgLicense: params.YearlyFloat{"1": 60000, "2": 90000, "3": 110000},
|
|
DataLicensing: params.YearlyFloat{"1": 0, "2": 50000, "3": 150000},
|
|
},
|
|
ImplServices: params.ImplementationParams{
|
|
MatchesPerOrg: 0.5,
|
|
PaidShare: 0.25,
|
|
AvgFee: 5000.0,
|
|
},
|
|
Impact: params.ImpactParams{
|
|
HeatMWh: params.YearlyFloat{"1": 500000, "2": 1500000, "3": 3000000},
|
|
GridFactor: 0.3,
|
|
HXEff: 0.9,
|
|
Utilization: 0.7,
|
|
WaterPerOrg: 25000.0,
|
|
WaterReuseRate: params.YearlyFloat{"1": 0.20, "2": 0.25, "3": 0.30},
|
|
WastePerOrg: 100.0,
|
|
WasteDiversionRate: params.YearlyFloat{"1": 0.15, "2": 0.25, "3": 0.35},
|
|
},
|
|
Costs: params.CostParams{
|
|
Engineers: params.YearlyInt{"1": 8, "2": 12, "3": 15},
|
|
EngineerSalary: 100000.0,
|
|
Infrastructure: params.YearlyFloat{"1": 200000, "2": 250000, "3": 400000},
|
|
MarketingSales: params.YearlyFloat{"1": 300000, "2": 600000, "3": 900000},
|
|
Operations: params.YearlyFloat{"1": 100000, "2": 150000, "3": 200000},
|
|
},
|
|
Market: params.MarketParams{
|
|
TAM: 500000000000.0,
|
|
AddressableDigital: 3000000000.0,
|
|
PilotCityEconomicBenefit: 4000000.0,
|
|
ScalabilityPotential: 400000000.0,
|
|
EUIndustrialFacilities: 2100000,
|
|
EnergyWastePotential: 0.45,
|
|
ResourceCostReduction: 0.25,
|
|
ViableExchangeRate: 0.15,
|
|
PlatformCaptureRate: 0.50,
|
|
SOM: params.YearlyFloat{"1": 50000000, "2": 300000000, "3": 1500000000},
|
|
},
|
|
}
|
|
}
|