From b14471030e5e9f8a2878e6f35db6c8892e3d25b9 Mon Sep 17 00:00:00 2001 From: Paul Kuruvilla Date: Wed, 20 Aug 2025 20:58:07 -0700 Subject: [PATCH 1/3] Add Go test case formatting guide to CLAUDE.md for better code organization --- CLAUDE.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..7e58e76a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,73 @@ +# Go Test Case Formatting Guide + +## Package Declaration and Imports +- Package declaration on line 1 +- Empty line after package declaration +- Import statements grouped with empty line between stdlib and external packages +- Empty line after imports + +## Type Definitions +- Type definitions immediately after imports with no empty line +- Struct fields are not separated by empty lines +- Empty line after each type definition + +## Method Grouping +- Methods on the same receiver are grouped together without empty lines between them +- Empty line between methods with different receivers or between different logical groups + +## Function Bodies +- No empty lines at the start or end of function bodies +- Empty lines used sparingly within functions to separate logical blocks +- Variable declarations at the beginning of functions are not separated by empty lines + +## Control Flow +- No empty lines before or after if statements, for loops, or switch statements +- Empty lines can be used to separate distinct logical operations within loops + +## Comments +- Single-line comments directly above the code they describe (no empty line) +- Multi-line comments for structs and methods follow Go conventions + +## Specific Patterns + +### Simple Test Cases (e.g., WaitTestCase, ZaddTestCase) +```go +type TestCase struct { + Field1 type1 + Field2 type2 +} + +func (t TestCase) Run(...) error { + // Implementation without empty lines unless separating logical blocks + return nil +} +``` + +### Complex Test Cases with Multiple Methods +```go +type ComplexTestCase struct { + Fields +} + +func (t *ComplexTestCase) Method1() error { + // Implementation +} + +func (t *ComplexTestCase) Method2() error { + // Implementation +} +``` + +### Multi-Step Operations +- When performing multiple related operations (like in TransactionTestCase.RunAll), no empty lines between sequential method calls +- Empty line before return statement only if it improves readability + +### Error Handling +- Error checks immediately follow the operation that might fail (no empty line) +- Multiple error checks in sequence don't have empty lines between them + +## Key Principles +1. Minimize empty lines within functions +2. Use empty lines to separate type definitions and method groups +3. Keep related code visually grouped together +4. Follow standard Go formatting conventions (gofmt) \ No newline at end of file From 30fefa84ca610088b5a104eda403dc22dce8c4cc Mon Sep 17 00:00:00 2001 From: Paul Kuruvilla Date: Wed, 20 Aug 2025 21:03:34 -0700 Subject: [PATCH 2/3] Update Go formatting guide with new structure and clarity on empty lines. --- CLAUDE.md | 66 +++++++++++++++---------------------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 7e58e76a..195d7ec5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,73 +1,43 @@ -# Go Test Case Formatting Guide +# Go File Formatting Guide ## Package Declaration and Imports + - Package declaration on line 1 - Empty line after package declaration - Import statements grouped with empty line between stdlib and external packages - Empty line after imports ## Type Definitions -- Type definitions immediately after imports with no empty line -- Struct fields are not separated by empty lines -- Empty line after each type definition -## Method Grouping -- Methods on the same receiver are grouped together without empty lines between them -- Empty line between methods with different receivers or between different logical groups +- Type definitions immediately after imports +- Struct fields are not separated by empty lines, unless there's a comment that applies to a single field +- Empty lines around each type definition ## Function Bodies + - No empty lines at the start or end of function bodies - Empty lines used sparingly within functions to separate logical blocks -- Variable declarations at the beginning of functions are not separated by empty lines +- Variable declarations at the beginning of functions are not separated by empty lines unless there's a logical grouping ## Control Flow -- No empty lines before or after if statements, for loops, or switch statements -- Empty lines can be used to separate distinct logical operations within loops - -## Comments -- Single-line comments directly above the code they describe (no empty line) -- Multi-line comments for structs and methods follow Go conventions - -## Specific Patterns -### Simple Test Cases (e.g., WaitTestCase, ZaddTestCase) -```go -type TestCase struct { - Field1 type1 - Field2 type2 -} +- A `return` statement should always have a blank line before it, unless it's the only statement in the function / indented block -func (t TestCase) Run(...) error { - // Implementation without empty lines unless separating logical blocks - return nil -} -``` +## Indented blocks -### Complex Test Cases with Multiple Methods -```go -type ComplexTestCase struct { - Fields -} +- Any statement that triggers an indented block (like a `if` statement, `for` loop or even a struct initialization that spans multiple lines) should have empty lines around it -func (t *ComplexTestCase) Method1() error { - // Implementation -} - -func (t *ComplexTestCase) Method2() error { - // Implementation -} -``` +## Comments -### Multi-Step Operations -- When performing multiple related operations (like in TransactionTestCase.RunAll), no empty lines between sequential method calls -- Empty line before return statement only if it improves readability +- Single-line comments directly above the code they describe (no empty line) +- Multi-line comments for structs and methods follow Go conventions ### Error Handling + - Error checks immediately follow the operation that might fail (no empty line) -- Multiple error checks in sequence don't have empty lines between them ## Key Principles -1. Minimize empty lines within functions -2. Use empty lines to separate type definitions and method groups -3. Keep related code visually grouped together -4. Follow standard Go formatting conventions (gofmt) \ No newline at end of file + +1. Use empty lines within functions to improve readability, but only when there's indented blocks or logical grouping. +2. Keep related code visually grouped together +3. Follow standard Go formatting conventions (gofmt) From d0c1d682eb75a09d5d7848c9a0a92cc800f43336 Mon Sep 17 00:00:00 2001 From: Paul Kuruvilla Date: Wed, 20 Aug 2025 21:10:19 -0700 Subject: [PATCH 3/3] update --- CLAUDE.md | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 195d7ec5..28ca4fc7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,35 +7,252 @@ - Import statements grouped with empty line between stdlib and external packages - Empty line after imports +### Good Example +```go +package internal + +import ( + "fmt" + "io" + + resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value" + "github.com/codecrafters-io/tester-utils/test_case_harness" +) +``` + +### Bad Example (no empty lines between groups) +```go +package internal +import ( + "fmt" + "github.com/codecrafters-io/redis-tester/internal/resp/value" + "io" +) +``` + ## Type Definitions - Type definitions immediately after imports - Struct fields are not separated by empty lines, unless there's a comment that applies to a single field - Empty lines around each type definition +### Good Example +```go +type StringAssertion struct { + ExpectedValue string +} + +type CommandAssertion struct { + Command string + Args []string +} +``` + +### Bad Example (no empty lines between types) +```go +type StringAssertion struct { + ExpectedValue string +} +type CommandAssertion struct { + Command string + Args []string +} +``` + ## Function Bodies - No empty lines at the start or end of function bodies - Empty lines used sparingly within functions to separate logical blocks - Variable declarations at the beginning of functions are not separated by empty lines unless there's a logical grouping +### Good Example +```go +func testEcho(stageHarness *test_case_harness.TestCaseHarness) error { + b := redis_executable.NewRedisExecutable(stageHarness) + if err := b.Run(); err != nil { + return err + } + + logger := stageHarness.Logger + + client, err := instrumented_resp_connection.NewFromAddr(logger, "localhost:6379", "client") + if err != nil { + return err + } + + randomWord := random.RandomWord() + + commandTestCase := test_cases.SendCommandTestCase{ + Command: "echo", + Args: []string{randomWord}, + Assertion: resp_assertions.NewStringAssertion(randomWord), + } + + if err := commandTestCase.Run(client, logger); err != nil { + logFriendlyError(logger, err) + return err + } + + client.Close() + + return nil +} +``` + +### Bad Example (empty lines at start/end) +```go +func testEcho(stageHarness *test_case_harness.TestCaseHarness) error { + + b := redis_executable.NewRedisExecutable(stageHarness) + // ... rest of function ... + + return nil + +} +``` + ## Control Flow - A `return` statement should always have a blank line before it, unless it's the only statement in the function / indented block +### Good Example +```go +func (a StringAssertion) Run(value resp_value.Value) error { + if value.Type != resp_value.SIMPLE_STRING && value.Type != resp_value.BULK_STRING { + return fmt.Errorf("Expected simple string or bulk string, got %s", value.Type) + } + + if value.String() != a.ExpectedValue { + return fmt.Errorf("Expected %q, got %q", a.ExpectedValue, value.String()) + } + + return nil +} +``` + +### Bad Example (no blank line before final return) +```go +func (a StringAssertion) Run(value resp_value.Value) error { + if value.Type != resp_value.SIMPLE_STRING && value.Type != resp_value.BULK_STRING { + return fmt.Errorf("Expected simple string or bulk string, got %s", value.Type) + } + + if value.String() != a.ExpectedValue { + return fmt.Errorf("Expected %q, got %q", a.ExpectedValue, value.String()) + } + return nil +} +``` + ## Indented blocks - Any statement that triggers an indented block (like a `if` statement, `for` loop or even a struct initialization that spans multiple lines) should have empty lines around it +### Good Example +```go +func doDecodeValue(reader *bytes.Reader) (resp_value.Value, error) { + firstByte, err := reader.ReadByte() + if err == io.EOF { + return resp_value.Value{}, IncompleteInputError{ + Reader: reader, + Message: "Expected start of a new RESP2 value", + } + } + + switch firstByte { + case '+': + return decodeSimpleString(reader) + case '-': + return decodeError(reader) + case ':': + return decodeInteger(reader) + default: + reader.UnreadByte() + + return resp_value.Value{}, InvalidInputError{ + Reader: reader, + Message: fmt.Sprintf("%q is not valid", string(firstByte)), + } + } +} +``` + +### Bad Example (no empty lines around blocks) +```go +func doDecodeValue(reader *bytes.Reader) (resp_value.Value, error) { + firstByte, err := reader.ReadByte() + if err == io.EOF { + return resp_value.Value{}, IncompleteInputError{ + Reader: reader, + Message: "Expected start of a new RESP2 value", + } + } + switch firstByte { + case '+': + return decodeSimpleString(reader) + case '-': + return decodeError(reader) + default: + reader.UnreadByte() + return resp_value.Value{}, InvalidInputError{ + Reader: reader, + Message: fmt.Sprintf("%q is not valid", string(firstByte)), + } + } +} +``` + ## Comments - Single-line comments directly above the code they describe (no empty line) - Multi-line comments for structs and methods follow Go conventions -### Error Handling +### Good Example +```go +// Tests 'ECHO' +func testEcho(stageHarness *test_case_harness.TestCaseHarness) error { + // Implementation here +} + +// We use multiple replicas to assert whether sent commands are replicated +replicas, err := SpawnReplicas(replicaCount, stageHarness, logger, "localhost:6379") +``` + +### Bad Example (empty line between comment and code) +```go +// Tests 'ECHO' + +func testEcho(stageHarness *test_case_harness.TestCaseHarness) error { + // Implementation here +} +``` + +## Error Handling - Error checks immediately follow the operation that might fail (no empty line) +### Good Example +```go +client, err := instrumented_resp_connection.NewFromAddr(logger, "localhost:6379", "client") +if err != nil { + return err +} + +b := redis_executable.NewRedisExecutable(stageHarness) +if err := b.Run(); err != nil { + return err +} +``` + +### Bad Example (empty line between operation and error check) +```go +client, err := instrumented_resp_connection.NewFromAddr(logger, "localhost:6379", "client") + +if err != nil { + return err +} +``` + ## Key Principles 1. Use empty lines within functions to improve readability, but only when there's indented blocks or logical grouping.