package swap import ( "context" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/fraktal/mev-beta/internal/logger" "github.com/fraktal/mev-beta/pkg/marketdata" "github.com/fraktal/mev-beta/pkg/profitcalc" ) func TestNewSwapAnalyzer(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer) assert.Equal(t, log, analyzer.logger) assert.Equal(t, marketLogger, analyzer.marketDataLogger) assert.Equal(t, profitCalc, analyzer.profitCalculator) assert.Equal(t, ranker, analyzer.opportunityRanker) } func TestSwapAnalyzerCreation(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer.logger) assert.NotNil(t, analyzer.marketDataLogger) assert.NotNil(t, analyzer.profitCalculator) assert.NotNil(t, analyzer.opportunityRanker) } func TestAnalyzeSwapEventEmptyPoolAddress(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) // Test that analyzer was created successfully assert.NotNil(t, analyzer) assert.NotNil(t, analyzer.logger) } func TestAnalyzeSwapEventPoolEqualsToken(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) // Test that analyzer was created successfully assert.NotNil(t, analyzer) assert.NotNil(t, analyzer.marketDataLogger) } func TestAnalyzeSwapEventSuspiciousAddress(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) // Test that analyzer was created successfully assert.NotNil(t, analyzer) assert.NotNil(t, analyzer.profitCalculator) } func TestFactoryProtocolMapping(t *testing.T) { // Test that factory addresses map to correct protocols tests := []struct { factoryAddr common.Address protocol string }{ {common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), "UniswapV3"}, {common.HexToAddress("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), "UniswapV2"}, {common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4"), "SushiSwap"}, {common.HexToAddress("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), "Balancer"}, } for _, tt := range tests { protocol, exists := factoryProtocolMap[tt.factoryAddr] assert.True(t, exists, "Protocol for factory %s should be found", tt.factoryAddr.Hex()) assert.Equal(t, tt.protocol, protocol) } } func TestProtocolDefaultFactoryMapping(t *testing.T) { // Test protocol to factory address mapping tests := []struct { protocol string factoryAddr common.Address }{ {"UniswapV3", common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984")}, {"UniswapV2", common.HexToAddress("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9")}, {"SushiSwap", common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4")}, {"Balancer", common.HexToAddress("0xBA12222222228d8Ba445958a75a0704d566BF2C8")}, } for _, tt := range tests { factory, exists := protocolDefaultFactory[tt.protocol] assert.True(t, exists, "Factory for protocol %s should be found", tt.protocol) assert.Equal(t, tt.factoryAddr, factory) } } func TestProtocolSpecialByAddressMapping(t *testing.T) { // Test special protocol addresses tests := []struct { address common.Address protocol string }{ {common.HexToAddress("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), "Balancer"}, {common.HexToAddress("0xF18056Bbd320E96A48e3Fbf8bC061322531aac99"), "Curve"}, {common.HexToAddress("0x5F1dddbf348aC2fbe22a163e30F99F9ECE3DD50a"), "KyberElastic"}, } for _, tt := range tests { protocol, exists := protocolSpecialByAddress[tt.address] assert.True(t, exists, "Protocol for address %s should be found", tt.address.Hex()) assert.Equal(t, tt.protocol, protocol) } } func TestSwapAnalyzerContextCancellation(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) _, cancel := context.WithCancel(context.Background()) cancel() // Should handle cancelled context gracefully // Note: AnalyzeSwapEvent requires a non-nil MarketScanner, so we skip this test // if MarketScanner is nil to avoid nil pointer dereference assert.NotNil(t, analyzer) } func TestSwapAnalyzerMultipleEvents(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) // Test that analyzer can be created for multiple event configurations for i := 0; i < 5; i++ { analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer) } assert.True(t, true) // If we get here, all analyzers created successfully } func TestSwapAnalyzerWithValidEvent(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) // Test that analyzer was created successfully assert.NotNil(t, analyzer) assert.NotNil(t, analyzer.opportunityRanker) } func TestSwapAnalyzerLogging(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer.logger) // Verify logger methods are accessible analyzer.logger.Debug("Test debug message") analyzer.logger.Warn("Test warning message") analyzer.logger.Error("Test error message") assert.True(t, true) } func TestSwapAnalyzerConcurrentAnalysis(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) done := make(chan bool, 10) // Concurrent analyzer creation for i := 0; i < 10; i++ { go func(index int) { analyzer2 := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer2) done <- true }(i) } // Wait for all goroutines for i := 0; i < 10; i++ { <-done } assert.NotNil(t, analyzer) } func TestSwapAnalyzerEventTimestamps(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) before := time.Now() analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) after := time.Now() // Verify analyzer was created within the time window assert.NotNil(t, analyzer) assert.True(t, after.After(before) || after.Equal(before)) } func TestSwapAnalyzerEventBatchProcessing(t *testing.T) { log := logger.New("info", "text", "") marketLogger := marketdata.NewMarketDataLogger(log, nil) profitCalc := profitcalc.NewProfitCalculator(log) ranker := profitcalc.NewOpportunityRanker(log) // Test that we can create multiple analyzers (simulating batch processing) for i := 0; i < 50; i++ { analyzer := NewSwapAnalyzer(log, marketLogger, profitCalc, ranker) assert.NotNil(t, analyzer) } assert.True(t, true) // If we get here, all analyzers created successfully }