diff --git a/.gitignore b/.gitignore index 9986126..014cdbc 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ sink-data/ # The spkg packed by the subtreams cli *.spkg replay.log +# Compiled binaries +/substreams-codegen +/cmd/substreams-codegen/substreams-codegen diff --git a/evm-events-calls/convo_test.go b/evm-events-calls/convo_test.go index 9711140..7f369b0 100644 --- a/evm-events-calls/convo_test.go +++ b/evm-events-calls/convo_test.go @@ -382,9 +382,8 @@ func TestInvalidWrappedABIFormat(t *testing.T) { }, }) - // Should show error and ask for ABI again - seq := next().(loop.SeqMsg) - msg := seq[0]().(*pbconvo.SystemOutput) + // Should show error message directly (not wrapped in SeqMsg) + msg := next().(*pbconvo.SystemOutput) assert.Contains(t, msg.GetMessage().Markdown, "abi") } diff --git a/registry.go b/registry.go index 0ca6e26..0c4ceca 100644 --- a/registry.go +++ b/registry.go @@ -43,7 +43,12 @@ func ListConversationHandlers() []*ConversationHandler { handlers = append(handlers, handler) } sort.Slice(handlers, func(i, j int) bool { - return handlers[i].Weight > handlers[j].Weight // heighest weight first + // First sort by weight (highest first) + if handlers[i].Weight != handlers[j].Weight { + return handlers[i].Weight > handlers[j].Weight + } + // For same weight, sort alphabetically by ID for deterministic ordering + return handlers[i].ID < handlers[j].ID }) return handlers diff --git a/registry_test.go b/registry_test.go new file mode 100644 index 0000000..36f5a74 --- /dev/null +++ b/registry_test.go @@ -0,0 +1,99 @@ +package codegen + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestListConversationHandlers_DeterministicOrdering(t *testing.T) { + // Save original registry and restore after test + originalRegistry := Registry + defer func() { Registry = originalRegistry }() + + // Create a new registry with test data + Registry = make(map[string]*ConversationHandler) + + // Register handlers with same weights to test secondary sorting + RegisterConversation("zebra-gen", "Zebra", "Last alphabetically", func() Converser { return nil }, 82, "TestGroup") + RegisterConversation("alpha-gen", "Alpha", "First alphabetically", func() Converser { return nil }, 82, "TestGroup") + RegisterConversation("middle-gen", "Middle", "Middle alphabetically", func() Converser { return nil }, 82, "TestGroup") + RegisterConversation("high-weight", "High Weight", "Highest weight", func() Converser { return nil }, 90, "TestGroup") + RegisterConversation("low-weight", "Low Weight", "Lowest weight", func() Converser { return nil }, 70, "TestGroup") + + // Run the function multiple times to ensure consistent ordering + var firstRun []*ConversationHandler + for run := 0; run < 10; run++ { + handlers := ListConversationHandlers() + + if run == 0 { + firstRun = handlers + } else { + // Verify the order is identical to first run + require.Equal(t, len(firstRun), len(handlers), "run %d: handler count mismatch", run) + for i := range handlers { + assert.Equal(t, firstRun[i].ID, handlers[i].ID, "run %d: position %d has different handler", run, i) + } + } + + // Verify the expected order + require.Len(t, handlers, 5) + assert.Equal(t, "high-weight", handlers[0].ID, "highest weight should be first") + + // The three handlers with weight 82 should be in alphabetical order + assert.Equal(t, "alpha-gen", handlers[1].ID, "weight 82 group should be alphabetically sorted") + assert.Equal(t, "middle-gen", handlers[2].ID, "weight 82 group should be alphabetically sorted") + assert.Equal(t, "zebra-gen", handlers[3].ID, "weight 82 group should be alphabetically sorted") + + assert.Equal(t, "low-weight", handlers[4].ID, "lowest weight should be last") + } +} + +func TestListConversationHandlers_WeightOrdering(t *testing.T) { + // Save original registry and restore after test + originalRegistry := Registry + defer func() { Registry = originalRegistry }() + + // Create a new registry with test data + Registry = make(map[string]*ConversationHandler) + + RegisterConversation("gen-50", "Weight 50", "Low weight", func() Converser { return nil }, 50, "TestGroup") + RegisterConversation("gen-100", "Weight 100", "High weight", func() Converser { return nil }, 100, "TestGroup") + RegisterConversation("gen-75", "Weight 75", "Mid weight", func() Converser { return nil }, 75, "TestGroup") + + handlers := ListConversationHandlers() + + require.Len(t, handlers, 3) + + // Verify weights are in descending order + assert.Equal(t, 100, handlers[0].Weight) + assert.Equal(t, 75, handlers[1].Weight) + assert.Equal(t, 50, handlers[2].Weight) +} + +func TestListConversationHandlers_RealWorldEVMScenario(t *testing.T) { + // Save original registry and restore after test + originalRegistry := Registry + defer func() { Registry = originalRegistry }() + + // Create a new registry with test data mimicking real EVM generators + Registry = make(map[string]*ConversationHandler) + + // Register handlers similar to actual EVM generators + RegisterConversation("evm-hello-world", "EVM Hello World", "Hello World", func() Converser { return nil }, 83, "EVM") + RegisterConversation("evm-events-calls", "EVM Events Calls", "Events Calls", func() Converser { return nil }, 82, "EVM") + RegisterConversation("evm-events-calls-raw", "EVM Events Calls Raw", "Events Calls Raw", func() Converser { return nil }, 82, "EVM") + + // Run multiple times to ensure consistent ordering + for run := 0; run < 5; run++ { + handlers := ListConversationHandlers() + + require.Len(t, handlers, 3) + + // Verify the expected order: highest weight first, then alphabetical within same weight + assert.Equal(t, "evm-hello-world", handlers[0].ID, "run %d: highest weight (83) should be first", run) + assert.Equal(t, "evm-events-calls", handlers[1].ID, "run %d: weight 82, alphabetically first", run) + assert.Equal(t, "evm-events-calls-raw", handlers[2].ID, "run %d: weight 82, alphabetically second", run) + } +}