Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
347 lines
8.2 KiB
Go
347 lines
8.2 KiB
Go
package calculation_validation
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
)
|
|
|
|
func TestValidateThresholdCheck(t *testing.T) {
|
|
validator := NewProfitValidator(1.0)
|
|
|
|
tests := []struct {
|
|
name string
|
|
check *ThresholdCheck
|
|
wantValid bool
|
|
}{
|
|
{
|
|
name: "valid executable - profit above threshold",
|
|
check: &ThresholdCheck{
|
|
NetProfit: big.NewFloat(834.210302),
|
|
MinThreshold: big.NewFloat(0.0001),
|
|
Passed: true,
|
|
},
|
|
wantValid: true,
|
|
},
|
|
{
|
|
name: "valid rejection - profit below threshold",
|
|
check: &ThresholdCheck{
|
|
NetProfit: big.NewFloat(0.00001),
|
|
MinThreshold: big.NewFloat(0.0001),
|
|
Passed: false,
|
|
},
|
|
wantValid: true,
|
|
},
|
|
{
|
|
name: "invalid - should pass but marked failed",
|
|
check: &ThresholdCheck{
|
|
NetProfit: big.NewFloat(1.0),
|
|
MinThreshold: big.NewFloat(0.0001),
|
|
Passed: false, // Wrong!
|
|
},
|
|
wantValid: false,
|
|
},
|
|
{
|
|
name: "edge case - profit equals threshold",
|
|
check: &ThresholdCheck{
|
|
NetProfit: big.NewFloat(0.0001),
|
|
MinThreshold: big.NewFloat(0.0001),
|
|
Passed: true,
|
|
},
|
|
wantValid: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
valid := validator.validateThresholdCheck(tt.check)
|
|
if valid != tt.wantValid {
|
|
t.Errorf("validateThresholdCheck() = %v, want %v", valid, tt.wantValid)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateThresholdComparison(t *testing.T) {
|
|
validator := NewProfitValidator(1.0)
|
|
minThresholdWei := big.NewInt(100000000000000) // 0.0001 ETH
|
|
|
|
tests := []struct {
|
|
name string
|
|
netProfit *big.Float
|
|
shouldExecute bool
|
|
wantValid bool
|
|
wantExecutable bool
|
|
}{
|
|
{
|
|
name: "bug fix scenario - 834 ETH",
|
|
netProfit: big.NewFloat(834.210302),
|
|
shouldExecute: true,
|
|
wantValid: true,
|
|
wantExecutable: true,
|
|
},
|
|
{
|
|
name: "below threshold",
|
|
netProfit: big.NewFloat(0.00001),
|
|
shouldExecute: false,
|
|
wantValid: true,
|
|
wantExecutable: false,
|
|
},
|
|
{
|
|
name: "exactly at threshold",
|
|
netProfit: big.NewFloat(0.0001),
|
|
shouldExecute: true,
|
|
wantValid: true,
|
|
wantExecutable: true,
|
|
},
|
|
{
|
|
name: "large profit",
|
|
netProfit: big.NewFloat(1249.324868),
|
|
shouldExecute: true,
|
|
wantValid: true,
|
|
wantExecutable: true,
|
|
},
|
|
{
|
|
name: "buggy comparison - should reject but marked executable",
|
|
netProfit: big.NewFloat(0.00001),
|
|
shouldExecute: true, // Wrong!
|
|
wantValid: false,
|
|
wantExecutable: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := validator.ValidateThresholdComparison(tt.netProfit, minThresholdWei, tt.shouldExecute)
|
|
|
|
if result.IsValid != tt.wantValid {
|
|
t.Errorf("ValidateThresholdComparison() valid = %v, want %v", result.IsValid, tt.wantValid)
|
|
if len(result.Errors) > 0 {
|
|
t.Logf("Errors: %v", result.Errors)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateV3Calculation(t *testing.T) {
|
|
validator := NewProfitValidator(1.0)
|
|
|
|
tests := []struct {
|
|
name string
|
|
calc SwapCalculation
|
|
wantValid bool
|
|
wantWarns bool
|
|
}{
|
|
{
|
|
name: "valid calculation with 0.3% fee",
|
|
calc: SwapCalculation{
|
|
AmountIn: big.NewInt(1000000),
|
|
AmountOut: big.NewInt(995000),
|
|
Fee: 3000,
|
|
FinalOut: big.NewInt(992015), // ~0.3% less
|
|
},
|
|
wantValid: true,
|
|
wantWarns: false,
|
|
},
|
|
{
|
|
name: "zero output",
|
|
calc: SwapCalculation{
|
|
AmountIn: big.NewInt(1000000),
|
|
AmountOut: big.NewInt(0),
|
|
Fee: 3000,
|
|
FinalOut: big.NewInt(0),
|
|
},
|
|
wantValid: true,
|
|
wantWarns: true,
|
|
},
|
|
{
|
|
name: "invalid - finalOut > amountOut",
|
|
calc: SwapCalculation{
|
|
AmountIn: big.NewInt(1000000),
|
|
AmountOut: big.NewInt(1000000),
|
|
Fee: 3000,
|
|
FinalOut: big.NewInt(1100000), // Impossible!
|
|
},
|
|
wantValid: false,
|
|
wantWarns: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := validator.ValidateV3Calculation(tt.calc)
|
|
|
|
if result.IsValid != tt.wantValid {
|
|
t.Errorf("ValidateV3Calculation() valid = %v, want %v", result.IsValid, tt.wantValid)
|
|
if len(result.Errors) > 0 {
|
|
t.Logf("Errors: %v", result.Errors)
|
|
}
|
|
}
|
|
|
|
hasWarnings := len(result.Warnings) > 0
|
|
if hasWarnings != tt.wantWarns {
|
|
t.Errorf("ValidateV3Calculation() warnings = %v, want %v", hasWarnings, tt.wantWarns)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCompareETHtoWei(t *testing.T) {
|
|
validator := NewProfitValidator(1.0)
|
|
|
|
tests := []struct {
|
|
name string
|
|
ethValue *big.Float
|
|
weiValue *big.Int
|
|
wantValid bool
|
|
}{
|
|
{
|
|
name: "correct conversion - 1 ETH",
|
|
ethValue: big.NewFloat(1.0),
|
|
weiValue: big.NewInt(1e18),
|
|
wantValid: true,
|
|
},
|
|
{
|
|
name: "correct conversion - 0.0001 ETH",
|
|
ethValue: big.NewFloat(0.0001),
|
|
weiValue: big.NewInt(1e14),
|
|
wantValid: true,
|
|
},
|
|
{
|
|
name: "incorrect conversion - off by factor of 1000",
|
|
ethValue: big.NewFloat(1.0),
|
|
weiValue: big.NewInt(1e15), // Wrong!
|
|
wantValid: false,
|
|
},
|
|
{
|
|
name: "bug scenario - using Int(nil) without scaling",
|
|
ethValue: big.NewFloat(834.210302),
|
|
weiValue: big.NewInt(834), // Buggy conversion!
|
|
wantValid: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := validator.CompareETHtoWei(tt.ethValue, tt.weiValue)
|
|
|
|
if result.IsValid != tt.wantValid {
|
|
t.Errorf("CompareETHtoWei() valid = %v, want %v", result.IsValid, tt.wantValid)
|
|
if len(result.Errors) > 0 {
|
|
t.Logf("Errors: %v", result.Errors)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCalculateStatistics(t *testing.T) {
|
|
profits := []*big.Float{
|
|
big.NewFloat(0.311819),
|
|
big.NewFloat(1249.324868),
|
|
big.NewFloat(2.166576),
|
|
big.NewFloat(1363.860509),
|
|
big.NewFloat(83.981698),
|
|
}
|
|
|
|
total, average, max, min := CalculateStatistics(profits)
|
|
|
|
// Verify total
|
|
expectedTotal := 2699.645470 // Sum of all values
|
|
totalFloat, _ := total.Float64()
|
|
if diff := totalFloat - expectedTotal; diff > 0.0001 || diff < -0.0001 {
|
|
t.Errorf("Total = %.6f, want %.6f", totalFloat, expectedTotal)
|
|
}
|
|
|
|
// Verify average
|
|
expectedAvg := expectedTotal / 5.0
|
|
avgFloat, _ := average.Float64()
|
|
if diff := avgFloat - expectedAvg; diff > 0.0001 || diff < -0.0001 {
|
|
t.Errorf("Average = %.6f, want %.6f", avgFloat, expectedAvg)
|
|
}
|
|
|
|
// Verify max
|
|
maxFloat, _ := max.Float64()
|
|
if maxFloat != 1363.860509 {
|
|
t.Errorf("Max = %.6f, want 1363.860509", maxFloat)
|
|
}
|
|
|
|
// Verify min
|
|
minFloat, _ := min.Float64()
|
|
if minFloat != 0.311819 {
|
|
t.Errorf("Min = %.6f, want 0.311819", minFloat)
|
|
}
|
|
}
|
|
|
|
func TestValidateOpportunity(t *testing.T) {
|
|
validator := NewProfitValidator(1.0)
|
|
|
|
tests := []struct {
|
|
name string
|
|
opp *OpportunityTestData
|
|
wantValid bool
|
|
wantErrs int
|
|
wantWarns int
|
|
}{
|
|
{
|
|
name: "valid executable opportunity",
|
|
opp: &OpportunityTestData{
|
|
ID: "test_1",
|
|
NetProfitETH: big.NewFloat(1.0),
|
|
IsExecutable: true,
|
|
RejectReason: "",
|
|
ThresholdCheck: &ThresholdCheck{
|
|
NetProfit: big.NewFloat(1.0),
|
|
MinThreshold: big.NewFloat(0.0001),
|
|
Passed: true,
|
|
},
|
|
},
|
|
wantValid: true,
|
|
wantErrs: 0,
|
|
wantWarns: 0,
|
|
},
|
|
{
|
|
name: "invalid - executable but zero profit",
|
|
opp: &OpportunityTestData{
|
|
ID: "test_2",
|
|
NetProfitETH: big.NewFloat(0.0),
|
|
IsExecutable: true,
|
|
RejectReason: "",
|
|
},
|
|
wantValid: false,
|
|
wantErrs: 1,
|
|
wantWarns: 0,
|
|
},
|
|
{
|
|
name: "warning - executable but has reject reason",
|
|
opp: &OpportunityTestData{
|
|
ID: "test_3",
|
|
NetProfitETH: big.NewFloat(1.0),
|
|
IsExecutable: true,
|
|
RejectReason: "some reason",
|
|
},
|
|
wantValid: true,
|
|
wantErrs: 0,
|
|
wantWarns: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := validator.ValidateOpportunity(tt.opp)
|
|
|
|
if result.IsValid != tt.wantValid {
|
|
t.Errorf("ValidateOpportunity() valid = %v, want %v", result.IsValid, tt.wantValid)
|
|
}
|
|
|
|
if len(result.Errors) != tt.wantErrs {
|
|
t.Errorf("ValidateOpportunity() errors = %d, want %d: %v", len(result.Errors), tt.wantErrs, result.Errors)
|
|
}
|
|
|
|
if len(result.Warnings) != tt.wantWarns {
|
|
t.Errorf("ValidateOpportunity() warnings = %d, want %d: %v", len(result.Warnings), tt.wantWarns, result.Warnings)
|
|
}
|
|
})
|
|
}
|
|
}
|