Skip to content

Commit ebc9989

Browse files
authored
Move CLAUDE.md to top level (#29)
1 parent 12a98f7 commit ebc9989

File tree

3 files changed

+165
-21
lines changed

3 files changed

+165
-21
lines changed

CLAUDE.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Claude Development Guide
2+
3+
## Next Steps
4+
5+
To find the next test to work on, run:
6+
7+
```bash
8+
go run ./cmd/next-test
9+
```
10+
11+
This tool finds all tests with `todo: true` in their metadata and returns the one with the shortest `query.sql` file.
12+
13+
## Workflow
14+
15+
1. Run `go run ./cmd/next-test` to find the next test to implement
16+
2. Check the test's `query.sql` to understand what ClickHouse SQL needs parsing
17+
3. Check the test's `explain.txt` to understand the expected EXPLAIN output
18+
4. Implement the necessary AST types in `ast/`
19+
5. Add parser logic in `parser/parser.go`
20+
6. Update the `Explain()` function if needed to match ClickHouse's output format
21+
7. Enable the test by removing `todo: true` from its `metadata.json` (set it to `{}`)
22+
8. Run `go test ./parser/... -timeout 5s` to verify
23+
9. Check if other todo tests now pass (see below)
24+
25+
## Running Tests
26+
27+
Always run parser tests with a 5 second timeout:
28+
29+
```bash
30+
go test ./parser/... -timeout 5s
31+
```
32+
33+
The tests are very fast. If a test is timing out, it indicates a bug (likely an infinite loop in the parser).
34+
35+
## Checking for Newly Passing Todo Tests
36+
37+
After implementing parser changes, run:
38+
39+
```bash
40+
go test ./parser/... -check-skipped -v 2>&1 | grep "PASSES NOW"
41+
```
42+
43+
Tests that output `PASSES NOW` can have their `todo` flag removed from `metadata.json`. This helps identify when parser improvements fix multiple tests at once.
44+
45+
## Test Structure
46+
47+
Each test in `parser/testdata/` contains:
48+
49+
- `metadata.json` - `{}` for enabled tests, `{"todo": true}` for pending tests
50+
- `query.sql` - ClickHouse SQL to parse
51+
- `explain.txt` - Expected EXPLAIN AST output (matches ClickHouse's format)
52+
53+
### Metadata Options
54+
55+
- `todo: true` - Test is pending implementation
56+
- `skip: true` - Skip test entirely (e.g., causes infinite loop)
57+
- `explain: false` - Skip test (e.g., ClickHouse couldn't parse it)
58+
- `parse_error: true` - Query is intentionally invalid SQL
59+
60+
## Important Rules
61+
62+
**NEVER modify `explain.txt` files** - These are golden files containing the expected output from ClickHouse. If tests fail due to output mismatches, fix the Go code to match the expected output, not the other way around.

cmd/next-test/main.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"sort"
9+
)
10+
11+
type testMetadata struct {
12+
Todo bool `json:"todo,omitempty"`
13+
Explain *bool `json:"explain,omitempty"`
14+
Skip bool `json:"skip,omitempty"`
15+
ParseError bool `json:"parse_error,omitempty"`
16+
}
17+
18+
type todoTest struct {
19+
name string
20+
querySize int
21+
}
22+
23+
func main() {
24+
testdataDir := "parser/testdata"
25+
entries, err := os.ReadDir(testdataDir)
26+
if err != nil {
27+
fmt.Fprintf(os.Stderr, "Error reading testdata: %v\n", err)
28+
os.Exit(1)
29+
}
30+
31+
var todoTests []todoTest
32+
33+
for _, entry := range entries {
34+
if !entry.IsDir() {
35+
continue
36+
}
37+
38+
testDir := filepath.Join(testdataDir, entry.Name())
39+
metadataPath := filepath.Join(testDir, "metadata.json")
40+
41+
// Read metadata
42+
metadataBytes, err := os.ReadFile(metadataPath)
43+
if err != nil {
44+
continue
45+
}
46+
47+
var metadata testMetadata
48+
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
49+
continue
50+
}
51+
52+
// Only include tests marked as todo
53+
if !metadata.Todo {
54+
continue
55+
}
56+
57+
// Skip tests with skip or explain=false or parse_error
58+
if metadata.Skip || (metadata.Explain != nil && !*metadata.Explain) || metadata.ParseError {
59+
continue
60+
}
61+
62+
// Read query to get its size
63+
queryPath := filepath.Join(testDir, "query.sql")
64+
queryBytes, err := os.ReadFile(queryPath)
65+
if err != nil {
66+
continue
67+
}
68+
69+
todoTests = append(todoTests, todoTest{
70+
name: entry.Name(),
71+
querySize: len(queryBytes),
72+
})
73+
}
74+
75+
if len(todoTests) == 0 {
76+
fmt.Println("No todo tests found!")
77+
return
78+
}
79+
80+
// Sort by query size (shortest first)
81+
sort.Slice(todoTests, func(i, j int) bool {
82+
return todoTests[i].querySize < todoTests[j].querySize
83+
})
84+
85+
// Print the shortest one
86+
next := todoTests[0]
87+
testDir := filepath.Join(testdataDir, next.name)
88+
89+
fmt.Printf("Next test: %s\n\n", next.name)
90+
91+
// Print query.sql contents
92+
queryPath := filepath.Join(testDir, "query.sql")
93+
queryBytes, _ := os.ReadFile(queryPath)
94+
fmt.Printf("Query (%d bytes):\n%s\n", next.querySize, string(queryBytes))
95+
96+
// Print explain.txt contents if it exists
97+
explainPath := filepath.Join(testDir, "explain.txt")
98+
if explainBytes, err := os.ReadFile(explainPath); err == nil {
99+
fmt.Printf("\nExpected EXPLAIN output:\n%s\n", string(explainBytes))
100+
}
101+
102+
fmt.Printf("\nRemaining todo tests: %d\n", len(todoTests))
103+
}

parser/CLAUDE.md

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)