Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .claude/skills/implement-awk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Run this sequence after every coherent implementation step:
```bash
make fmt
go test ./...
RSHELL_BIN=./rshell AWK_UNDER_TEST=tools/awk-harness/rshell-awk tools/awk-harness/run.sh rewritten
RSHELL_BIN=./rshell AWK_UNDER_TEST=tools/awk-harness/rshell-awk tools/awk-harness/run.sh gawk
RSHELL_BIN=./rshell AWK_UNDER_TEST=tools/awk-harness/rshell-awk tools/awk-harness/run.sh onetrueawk
```
Expand Down Expand Up @@ -104,6 +105,8 @@ make build
- safety rejection behavior
- runtime or resource limit
7. Add or update original rshell tests for the intended behavior.
Prefer `tests/awk_scenarios` for GNU awk behavior that came from upstream
AWK coverage, and include upstream metadata for traceability.
8. Implement the smallest code change that addresses the cluster.
9. Run `make fmt`.
10. Run focused tests.
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/awk-harness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install pinned GNU awk oracle
run: tools/awk-harness/run.sh install-gawk
- name: Run rewritten AWK scenarios against pinned GNU awk
run: tools/awk-harness/run.sh rewritten
- name: Fetch One True Awk tests
env:
AWK_HARNESS_BOOTSTRAP: "1"
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build fmt test test_all test_against_bash compliance
.PHONY: build fmt test test_all test_against_bash test_awk_rewritten compliance

build:
go build -o rshell ./cmd/rshell
Expand All @@ -15,5 +15,8 @@ test_all:
test_against_bash:
RSHELL_BASH_TEST=1 go test -v ./tests/ -run TestShellScenariosAgainstBash -count=1

test_awk_rewritten:
tools/awk-harness/run.sh rewritten

compliance:
RSHELL_COMPLIANCE_TEST=1 go test -v ./tests/ -run TestCompliance -count=1
39 changes: 39 additions & 0 deletions tests/awk_scenarios/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# AWK Scenario Rewrites

This directory contains rshell-owned AWK tests rewritten from upstream behavior
coverage. Do not copy upstream test bodies, helper scripts, comments, fixtures,
or expected output into this directory.

Each scenario is a small GNU awk behavior case with metadata that identifies
which upstream suite or coverage area it belongs to and what behavior it covers.
The tests run through the AWK-specific Go runner in
`tests/awk_scenarios_test.go`.

`enabled.txt` is the only run list. Each non-comment line is a path relative to
this directory:

```text
gawk/basic/begin_end_records.yaml
onetrueawk/basic/pattern_action.yaml
```

`upstream-map.yaml` is an audit ledger for rewrite progress. It does not decide
which tests run.

Run the rewritten scenarios against the pinned GNU awk oracle:

```bash
tools/awk-harness/run.sh install-gawk
tools/awk-harness/run.sh rewritten
```

Run the same scenarios against rshell's `awk` adapter once the builtin exists:

```bash
make build
RSHELL_BIN=./rshell AWK_UNDER_TEST=tools/awk-harness/rshell-awk tools/awk-harness/run.sh rewritten
```

The runner still compares rshell output to the pinned GNU awk oracle when
`GAWK_ORACLE` is set, so expected output in these files and live GNU awk
behavior must stay aligned.
10 changes: 10 additions & 0 deletions tests/awk_scenarios/enabled.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Each non-comment line is a path relative to tests/awk_scenarios.
gawk/basic/begin_end_records.yaml
gawk/basic/field_separator.yaml
gawk/cli/variable_assignment.yaml
gawk/expressions/arithmetic_comparison.yaml
gawk/fields/assign_rebuilds_record.yaml
gawk/functions/split.yaml
gawk/output/print_separators.yaml
gawk/regex/pattern_match.yaml
onetrueawk/basic/pattern_action.yaml
25 changes: 25 additions & 0 deletions tests/awk_scenarios/gawk/basic/begin_end_records.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
description: BEGIN and END blocks wrap per-record actions
upstream:
suite: gawk
id: test/beginfile1.awk
ref: gawk-5.4.0
covers:
- BEGIN actions run before input records are processed
- END actions run after all input records are processed
- NR is incremented for each input record
- $1 and $NF read the first and last fields of the current record
input:
program: |
BEGIN { print "start" }
{ print NR ":" $1 "-" $NF }
END { print "count=" NR }
stdin: |
alpha beta
gamma delta epsilon
expect:
stdout: |
start
1:alpha-beta
2:gamma-epsilon
count=2
exit_code: 0
20 changes: 20 additions & 0 deletions tests/awk_scenarios/gawk/basic/field_separator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: FS controls field splitting and NF for comma-separated records
upstream:
suite: gawk
id: test/fieldwdth.awk
ref: gawk-5.4.0
covers:
- FS controls field splitting for subsequent records
- NF reflects the number of fields in the current record
input:
program: |
BEGIN { FS = "," }
{ print $2 ":" NF }
stdin: |
a,b,c
x,y
expect:
stdout: |
b:3
y:2
exit_code: 0
30 changes: 30 additions & 0 deletions tests/awk_scenarios/gawk/cli/variable_assignment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
description: -v assignments are visible before BEGIN and file arguments set FILENAME and FNR
upstream:
suite: gawk
id: test/argtest.awk
ref: gawk-5.4.0
covers:
- -v assignments are visible before BEGIN runs
- FILENAME is set to the current input file path
- FNR counts records within the current input file
setup:
files:
- path: records.txt
content: |
red
blue
input:
awk_args:
- -v
- label=color
program: |
BEGIN { print label }
{ print FILENAME ":" FNR ":" $0 }
args:
- records.txt
expect:
stdout: |
color
records.txt:1:red
records.txt:2:blue
exit_code: 0
30 changes: 30 additions & 0 deletions tests/awk_scenarios/gawk/expressions/arithmetic_comparison.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
description: Arithmetic and comparison expressions drive conditional actions
upstream:
suite: gawk
id: test/compare.awk
ref: gawk-5.4.0
covers:
- numeric addition updates an accumulator
- modulo participates in equality comparisons
- if and else choose actions from numeric comparisons
input:
program: |
{
total += $1
if ($1 % 2 == 0)
print $1, "even"
else
print $1, "odd"
}
END { print "total", total }
stdin: |
3
4
9
expect:
stdout: |
3 odd
4 even
9 odd
total 16
exit_code: 0
27 changes: 27 additions & 0 deletions tests/awk_scenarios/gawk/fields/assign_rebuilds_record.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
description: Assigning a numbered field rebuilds $0 using OFS
upstream:
suite: gawk
id: test/assignnumfield.awk
ref: gawk-5.4.0
covers:
- assigning to a numbered field changes that field
- rebuilding $0 after a field assignment uses OFS
- NF remains the number of fields when assigning an existing field
input:
program: |
BEGIN { OFS = "|" }
{
$2 = "patched"
print $0
print NF
}
stdin: |
alpha beta gamma
solo pair
expect:
stdout: |
alpha|patched|gamma
3
solo|patched
2
exit_code: 0
23 changes: 23 additions & 0 deletions tests/awk_scenarios/gawk/functions/split.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
description: split populates array elements and returns the element count
upstream:
suite: gawk
id: test/splitargv.awk
ref: gawk-5.4.0
covers:
- split returns the number of elements it created
- split stores array elements using one-based numeric indexes
- split accepts a string field separator argument
input:
program: |
BEGIN {
n = split("north:south:east", parts, ":")
print n
for (i = 1; i <= n; i++) print i "=" parts[i]
}
expect:
stdout: |
3
1=north
2=south
3=east
exit_code: 0
20 changes: 20 additions & 0 deletions tests/awk_scenarios/gawk/output/print_separators.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: print uses OFS between arguments and ORS after each record
upstream:
suite: gawk
id: test/ofs1.awk
ref: gawk-5.4.0
covers:
- print inserts OFS between arguments
- print appends ORS after the output record
- numeric arguments are formatted for print output
input:
program: |
BEGIN {
OFS = "::"
ORS = "<end>\n"
print "left", "right", 7
}
expect:
stdout: |
left::right::7<end>
exit_code: 0
26 changes: 26 additions & 0 deletions tests/awk_scenarios/gawk/regex/pattern_match.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
description: Regular expression patterns and !~ select records
upstream:
suite: gawk
id: test/re_test.awk
ref: gawk-5.4.0
covers:
- regex patterns select matching input records
- anchors constrain regex matches to the whole record
- !~ negates a regex match expression
input:
program: |
/^[[:alpha:]]+[0-9]$/ { print NR ":" $0 }
$0 !~ /[aeiou]/ { print "no-vowel:" $0 }
stdin: |
abc1
sky
lake2
B7
expect:
stdout: |
1:abc1
no-vowel:sky
3:lake2
4:B7
no-vowel:B7
exit_code: 0
25 changes: 25 additions & 0 deletions tests/awk_scenarios/onetrueawk/basic/pattern_action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
description: Pattern-only and action-only rules compose across records
upstream:
suite: onetrueawk
id: testdir/t.3
ref: 3c2e168a8f794ed61c93131b05fb998d79d155df
notes: Also covers the default action behavior represented by testdir/t.0.
covers:
- pattern-only rules print the current record
- action-only rules run for every record
- END actions can observe accumulated values
input:
program: |
/keep/
{ total += $2 }
END { print "total=" total }
stdin: |
keep 4
drop 7
keep 2
expect:
stdout: |
keep 4
keep 2
total=13
exit_code: 0
Loading
Loading