From 5d5c03983e00eeda44983238e013eda4bb86d62f Mon Sep 17 00:00:00 2001 From: Udeshya Dhungana <075bct095.udeshya@pcampus.edu.np> Date: Fri, 7 Nov 2025 14:18:27 +0545 Subject: [PATCH 1/3] Add better hints for string type mismatch --- go.mod | 2 +- internal/resp_assertions/bulk_string_assertion.go | 9 +++++++++ .../bulk_string_present_in_array_assertion.go | 11 +++++++++++ .../resp_assertions/simple_string_assertion.go | 9 +++++++++ internal/stages_test.go | 9 ++++++++- .../fixtures/ping-pong/string_type_mismatch | 14 ++++++++++++++ .../string_type_mismatch/codecrafters.yml | 5 +++++ .../string_type_mismatch/spawn_redis_server.sh | 15 +++++++++++++++ 8 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 internal/test_helpers/fixtures/ping-pong/string_type_mismatch create mode 100644 internal/test_helpers/scenarios/ping-pong/string_type_mismatch/codecrafters.yml create mode 100755 internal/test_helpers/scenarios/ping-pong/string_type_mismatch/spawn_redis_server.sh diff --git a/go.mod b/go.mod index 1f961e26..7beebd60 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.24.2 require ( github.com/codecrafters-io/tester-utils v0.4.9 + github.com/dustin/go-humanize v1.0.1 github.com/hdt3213/rdb v1.2.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/pretty v1.2.1 @@ -14,7 +15,6 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/internal/resp_assertions/bulk_string_assertion.go b/internal/resp_assertions/bulk_string_assertion.go index c5d3e21c..4705ef43 100644 --- a/internal/resp_assertions/bulk_string_assertion.go +++ b/internal/resp_assertions/bulk_string_assertion.go @@ -15,6 +15,15 @@ func NewBulkStringAssertion(expectedValue string) RESPAssertion { } func (a BulkStringAssertion) Run(value resp_value.Value) error { + // Frequently occurs in user submissions + if value.Type == resp_value.SIMPLE_STRING && value.String() == a.ExpectedValue { + return fmt.Errorf( + "Expected bulk string \"%s\", got simple string \"%s\" instead", + value.String(), + value.String(), + ) + } + bulkStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.BULK_STRING} if err := bulkStringTypeAssertion.Run(value); err != nil { diff --git a/internal/resp_assertions/bulk_string_present_in_array_assertion.go b/internal/resp_assertions/bulk_string_present_in_array_assertion.go index 05a0103a..cc44f586 100644 --- a/internal/resp_assertions/bulk_string_present_in_array_assertion.go +++ b/internal/resp_assertions/bulk_string_present_in_array_assertion.go @@ -25,5 +25,16 @@ func (a BulkStringPresentInArrayAssertion) Run(value resp_value.Value) error { } } + // Possible frequent-occurence inferring from the existing errors in user submissions + for _, element := range array { + if element.Type == resp_value.SIMPLE_STRING && element.String() == a.ExpectedString { + return fmt.Errorf( + "Expected bulk string '%s' to be present in the array, but simple string '%s' is present instead", + element.String(), + element.String(), + ) + } + } + return fmt.Errorf("Expected bulk string '%s' to be present in the array, but is absent", a.ExpectedString) } diff --git a/internal/resp_assertions/simple_string_assertion.go b/internal/resp_assertions/simple_string_assertion.go index f0febec8..3b5aceb1 100644 --- a/internal/resp_assertions/simple_string_assertion.go +++ b/internal/resp_assertions/simple_string_assertion.go @@ -15,6 +15,15 @@ func NewSimpleStringAssertion(expectedValue string) RESPAssertion { } func (a SimpleStringAssertion) Run(value resp_value.Value) error { + // Frequently occurs in user submissions + if value.Type == resp_value.BULK_STRING && value.String() == a.ExpectedValue { + return fmt.Errorf( + "Expected simple string \"%s\", got bulk string \"%s\" instead", + value.String(), + value.String(), + ) + } + simpleStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.SIMPLE_STRING} if err := simpleStringTypeAssertion.Run(value); err != nil { diff --git a/internal/stages_test.go b/internal/stages_test.go index 55545856..0dbbf8f0 100644 --- a/internal/stages_test.go +++ b/internal/stages_test.go @@ -51,7 +51,7 @@ func TestStages(t *testing.T) { UntilStageSlug: "rg2", CodePath: "./test_helpers/scenarios/ping-pong/slow_response", ExpectedExitCode: 0, - StdoutFixturePath: "./test_helpers/fixtures/ping-pong/slow_response", + StdoutFixturePath: "./test_helpers/fixtures/fping-pong/slow_response", NormalizeOutputFunc: normalizeTesterOutput, }, "ping_pong_without_read_multiple_pongs": { @@ -61,6 +61,13 @@ func TestStages(t *testing.T) { StdoutFixturePath: "./test_helpers/fixtures/ping-pong/without_read_multiple_pongs", NormalizeOutputFunc: normalizeTesterOutput, }, + "ping_pong_string_type_mismatch": { + StageSlugs: []string{"rg2"}, + CodePath: "./test_helpers/scenarios/ping-pong/string_type_mismatch", + ExpectedExitCode: 1, + StdoutFixturePath: "./test_helpers/fixtures/ping-pong/string_type_mismatch", + NormalizeOutputFunc: normalizeTesterOutput, + }, "invalid_resp_error": { StageSlugs: []string{"rg2"}, CodePath: "./test_helpers/scenarios/invalid-resp/", diff --git a/internal/test_helpers/fixtures/ping-pong/string_type_mismatch b/internal/test_helpers/fixtures/ping-pong/string_type_mismatch new file mode 100644 index 00000000..d07f08ac --- /dev/null +++ b/internal/test_helpers/fixtures/ping-pong/string_type_mismatch @@ -0,0 +1,14 @@ +Debug = true + +[tester::#RG2] Running tests for Stage #RG2 (rg2) +[tester::#RG2] $ ./spawn_redis_server.sh +[your_program] hey, binding to 6379 +[tester::#RG2] Connection established, sending ping command... +[tester::#RG2] [client] $ redis-cli PING +[tester::#RG2] [client] Sent bytes: "*1\r\n$4\r\nPING\r\n" +[tester::#RG2] [client] Received bytes: "$4\r\nPONG\r\n" +[tester::#RG2] [client] Received RESP bulk string: "PONG" +[tester::#RG2] Expected simple string "PONG", got bulk string "PONG" instead +[tester::#RG2] Test failed +[tester::#RG2] Terminating program +[tester::#RG2] Program terminated successfully diff --git a/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/codecrafters.yml b/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/codecrafters.yml new file mode 100644 index 00000000..f544b940 --- /dev/null +++ b/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/codecrafters.yml @@ -0,0 +1,5 @@ +# Set this to true if you want debug logs. +# +# These can be VERY verbose, so we suggest turning them off +# unless you really need them. +debug: true \ No newline at end of file diff --git a/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/spawn_redis_server.sh b/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/spawn_redis_server.sh new file mode 100755 index 00000000..a9647891 --- /dev/null +++ b/internal/test_helpers/scenarios/ping-pong/string_type_mismatch/spawn_redis_server.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env -S python3 -u +import socket +import time +print("hey, binding to 6379") +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +sock.bind(('', 6379)) + +sock.listen(1) + +conn, cli_addr = sock.accept() + +# Send bulk string instead of simple string +conn.send(b"$4\r\nPONG\r\n") From 11ed176db208825cab9855b00726f35efcea0aa5 Mon Sep 17 00:00:00 2001 From: Udeshya Dhungana <075bct095.udeshya@pcampus.edu.np> Date: Fri, 7 Nov 2025 14:20:17 +0545 Subject: [PATCH 2/3] Fix error message --- internal/resp_assertions/bulk_string_assertion.go | 2 +- .../resp_assertions/bulk_string_present_in_array_assertion.go | 2 +- internal/resp_assertions/simple_string_assertion.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/resp_assertions/bulk_string_assertion.go b/internal/resp_assertions/bulk_string_assertion.go index 4705ef43..a15a1301 100644 --- a/internal/resp_assertions/bulk_string_assertion.go +++ b/internal/resp_assertions/bulk_string_assertion.go @@ -19,7 +19,7 @@ func (a BulkStringAssertion) Run(value resp_value.Value) error { if value.Type == resp_value.SIMPLE_STRING && value.String() == a.ExpectedValue { return fmt.Errorf( "Expected bulk string \"%s\", got simple string \"%s\" instead", - value.String(), + a.ExpectedValue, value.String(), ) } diff --git a/internal/resp_assertions/bulk_string_present_in_array_assertion.go b/internal/resp_assertions/bulk_string_present_in_array_assertion.go index cc44f586..03017f6e 100644 --- a/internal/resp_assertions/bulk_string_present_in_array_assertion.go +++ b/internal/resp_assertions/bulk_string_present_in_array_assertion.go @@ -30,7 +30,7 @@ func (a BulkStringPresentInArrayAssertion) Run(value resp_value.Value) error { if element.Type == resp_value.SIMPLE_STRING && element.String() == a.ExpectedString { return fmt.Errorf( "Expected bulk string '%s' to be present in the array, but simple string '%s' is present instead", - element.String(), + a.ExpectedString, element.String(), ) } diff --git a/internal/resp_assertions/simple_string_assertion.go b/internal/resp_assertions/simple_string_assertion.go index 3b5aceb1..16b40e97 100644 --- a/internal/resp_assertions/simple_string_assertion.go +++ b/internal/resp_assertions/simple_string_assertion.go @@ -19,7 +19,7 @@ func (a SimpleStringAssertion) Run(value resp_value.Value) error { if value.Type == resp_value.BULK_STRING && value.String() == a.ExpectedValue { return fmt.Errorf( "Expected simple string \"%s\", got bulk string \"%s\" instead", - value.String(), + a.ExpectedValue, value.String(), ) } From 7aa2ff66b70ef4f79c995eca0eb419b6372288dc Mon Sep 17 00:00:00 2001 From: Udeshya Dhungana <075bct095.udeshya@pcampus.edu.np> Date: Fri, 7 Nov 2025 15:06:54 +0545 Subject: [PATCH 3/3] Revert back typo --- internal/stages_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/stages_test.go b/internal/stages_test.go index 0dbbf8f0..cfd72857 100644 --- a/internal/stages_test.go +++ b/internal/stages_test.go @@ -51,7 +51,7 @@ func TestStages(t *testing.T) { UntilStageSlug: "rg2", CodePath: "./test_helpers/scenarios/ping-pong/slow_response", ExpectedExitCode: 0, - StdoutFixturePath: "./test_helpers/fixtures/fping-pong/slow_response", + StdoutFixturePath: "./test_helpers/fixtures/ping-pong/slow_response", NormalizeOutputFunc: normalizeTesterOutput, }, "ping_pong_without_read_multiple_pongs": {