on master help sign in
Move the importer-only fixtures to a jibb-fixtures desk
d43c99bClaude
README.md+5−5
@@ -10,7 +10,7 @@ Milestone 1 of the doc's eight, the parser and the `%jibb` mark, is done; milest
10- `jibb/`: the `%jibb` desk, for the shared host (milestone 4).
10- `jibb/`: the `%jibb` desk, for the shared host (milestone 4).
11- `my-app/`: an example app desk built from the doc's worked examples.
11- `my-app/`: an example app desk built from the doc's worked examples.
12- `vendor/`: pinned copies of the base-dev and landscape files the desks need.
12- `vendor/`: pinned copies of the base-dev and landscape files the desks need.
13−- `tests/`: golden cases in `golden/<case>/`, test suites in `lib/` and their fixtures, for `tools/test-arms` and the ship's `-test` thread, and `my-app-copies.txt`, the list of fixtures that copy `my-app/mar/label.hoon`. `lib/jibb.hoon`, which runs the golden cases on the ship, is generated.
13+- `tests/`: golden cases in `golden/<case>/`, test suites in `lib/` and their fixtures, for `tools/test-arms` and the ship's `-test` thread, and in `clay-fixtures/`, the threads `tools/clay-fixtures` runs and, in `clay-fixtures/desk/`, the Hoon files the `jibb-fixtures` desk adds to `my-app`. `lib/jibb.hoon`, which runs the golden cases on the ship, is generated.
14- `tools/`: dev tooling: `golden`, `test-arms`, `hoon` and `doc-blocks`, with their self-test in `testdata/`, `ship`, and `check`, which runs every check.
14- `tools/`: dev tooling: `golden`, `test-arms`, `hoon` and `doc-blocks`, with their self-test in `testdata/`, `ship`, and `check`, which runs every check.
15- `docs/`: the doc's tabs as Markdown in `spec/`, the status, the open questions, the development guide, the compiler's map, and briefs for milestones in `prompts/`.
15- `docs/`: the doc's tabs as Markdown in `spec/`, the status, the open questions, the development guide, the compiler's map, and briefs for milestones in `prompts/`.
16
16
@@ -19,13 +19,13 @@ Milestone 1 of the doc's eight, the parser and the `%jibb` mark, is done; milest
19The flake (`flake.nix`, pinned by `flake.lock`) builds the desks and runs every check, with vere 4.6, Python 3, click and the brass pill pinned:
19The flake (`flake.nix`, pinned by `flake.lock`) builds the desks and runs every check, with vere 4.6, Python 3, click and the brass pill pinned:
20
20
21```
21```
22−nix build # result/my-app, result/jibb, result/jibb-dev: the desks
22+nix build # result/my-app, result/jibb, result/jibb-dev, result/jibb-fixtures: the desks
23nix flake check # every check: the eval group and, on Linux, the ship group on a fresh fake ~zod
23nix flake check # every check: the eval group and, on Linux, the ship group on a fresh fake ~zod
24nix develop # a shell with urbit, python3 and click, for running the tools by hand
24nix develop # a shell with urbit, python3 and click, for running the tools by hand
25nix build .#fakezod # a freshly booted fake ~zod pier (Linux)
25nix build .#fakezod # a freshly booted fake ~zod pier (Linux)
26```
26```
27
27
28−Jibb has no native binary: what it ships is desks, Hoon and Jibb source that a ship builds. So `nix build` writes the three desks exactly as `tools/ship sync` would commit them (it runs `tools/ship assemble`), and compiles `jibb.hoon` and `jibb-import.hoon` under `urbit eval` to check that they build.
28+Jibb has no native binary: what it ships is desks, Hoon and Jibb source that a ship builds. So `nix build` writes the four desks exactly as `tools/ship sync` would commit them (it runs `tools/ship assemble`), and compiles `jibb.hoon` and `jibb-import.hoon` under `urbit eval` to check that they build.
29
29
30`nix flake check` builds that too, then runs `tools/check --group eval` and, on Linux, `tools/check --group ship` against a copy of a fake ~zod it boots from the pill. Everything runs in the Nix sandbox without network, so a check can't pass because of something on your machine. Each group is one build; a failure prints the failing checks' output, and a passing build keeps every check's log in its output. On four CPUs it takes about 10 minutes, the two groups building side by side: under 3 minutes for the eval group (it took 18 before `tools/test-arms` replaced a script per suite) and 10 for the ship group. To run a single check, use `nix develop -c tools/check <name>` (see [docs/development.md](docs/development.md#before-pushing)).
30`nix flake check` builds that too, then runs `tools/check --group eval` and, on Linux, `tools/check --group ship` against a copy of a fake ~zod it boots from the pill. Everything runs in the Nix sandbox without network, so a check can't pass because of something on your machine. Each group is one build; a failure prints the failing checks' output, and a passing build keeps every check's log in its output. On four CPUs it takes about 10 minutes, the two groups building side by side: under 3 minutes for the eval group (it took 18 before `tools/test-arms` replaced a script per suite) and 10 for the ship group. To run a single check, use `nix develop -c tools/check <name>` (see [docs/development.md](docs/development.md#before-pushing)).
31
31
@@ -90,7 +90,7 @@ Many suites share one eval, so the library is built once per eval, not once per
90
90
91A golden-report suite has a `report` arm and a `/*` file bound to the face `expected`; when one of its arms fails, the runner prints a diff between that file and the report. Before any eval, the runner checks the golden files of the suites it runs, the `%txt` files bound to a face containing `expected`: each must end in exactly one newline, which an arm can't see in the file's wain, and hold no line that starts `BAD ` or ends `: BAD`. `--update` won't write a report that breaks either rule.
91A golden-report suite has a `report` arm and a `/*` file bound to the face `expected`; when one of its arms fails, the runner prints a diff between that file and the report. Before any eval, the runner checks the golden files of the suites it runs, the `%txt` files bound to a face containing `expected`: each must end in exactly one newline, which an arm can't see in the file's wain, and hold no line that starts `BAD ` or ends `: BAD`. `--update` won't write a report that breaks either rule.
92
92
93−The `jibb-dev` desk holds `my-app`'s sources under `/my-app`, without its desk files, so the suites below that check `my-app` files read them there, and a golden case that uses one links to it: `tests/golden/doc-overview-02-theme/source.jibb` is a symlink to `my-app/ui/theme.jibb`. The fixtures that copy `my-app/mar/label.hoon` leave out its first line, a comment; `tests/my-app-copies.txt` lists them, and `tools/test-arms` checks every pair when it runs with no suite or shard named, and with `--copies`, which `tools/check` runs as `my-app-copies`.
93+The `jibb-dev` desk holds `my-app`'s sources under `/my-app`, without its desk files, so the suites below that check `my-app` files read them there, and a golden case that uses one links to it: `tests/golden/doc-overview-02-theme/source.jibb` is a symlink to `my-app/ui/theme.jibb`.
94
94
95`tools/test-arms --list` lists every suite, and [The test suites](docs/development.md#the-test-suites) in the development guide says what each one checks. Each suite it lists runs under eval and on the fake ship, with the same fixtures. The `jibb-import` suite compares the partial Hoon importer's fixture projections against their golden file. The suites `jibb-bridge`, `jibb-import-overlap`, `jibb-import-structural`, `jibb-union-source`, `jibb-union-alias-overlap`, `jibb-full-overlap-basic`, `jibb-full-overlap-graph`, `jibb-generic-recursion`, `jibb-generic-construction`, `jibb-generic-pattern`, `jibb-deferred`, `jibb-deferred-prepared`, `jibb-deferred-resolver`, `jibb-deferred-context`, `jibb-empty`, `jibb-cell-branch`, `jibb-tlon-bridge`, `jibb-mark-bridge`, `jibb-poke-bridge` and `jibb-api-paths` check importer/checker, prelude and partial API path analysis boundaries.
95`tools/test-arms --list` lists every suite, and [The test suites](docs/development.md#the-test-suites) in the development guide says what each one checks. Each suite it lists runs under eval and on the fake ship, with the same fixtures. The `jibb-import` suite compares the partial Hoon importer's fixture projections against their golden file. The suites `jibb-bridge`, `jibb-import-overlap`, `jibb-import-structural`, `jibb-union-source`, `jibb-union-alias-overlap`, `jibb-full-overlap-basic`, `jibb-full-overlap-graph`, `jibb-generic-recursion`, `jibb-generic-construction`, `jibb-generic-pattern`, `jibb-deferred`, `jibb-deferred-prepared`, `jibb-deferred-resolver`, `jibb-deferred-context`, `jibb-empty`, `jibb-cell-branch`, `jibb-tlon-bridge`, `jibb-mark-bridge`, `jibb-poke-bridge` and `jibb-api-paths` check importer/checker, prelude and partial API path analysis boundaries.
96
96
@@ -141,7 +141,7 @@ A sync with nothing to commit takes about 2 s. A commit adds 3 to 10 s, and 300
141
141
142`tools/ship check-commit` proves that `|commit` stores `.jibb` files. It syncs `my-app`, reads every `/ui` file back with `%cx`, byte for byte, and converts `%jibb` to `%mime` and `%txt` and back. It commits half-written files, then deletes them. It merges a file that two desks changed on different lines, and checks that changes to the same line conflict. It can be rerun, and it leaves the two scratch desks it merges with (`%jibb-check-ours` and `%jibb-check-theirs`) holding only what `|new-desk` gives, unmounted.
142`tools/ship check-commit` proves that `|commit` stores `.jibb` files. It syncs `my-app`, reads every `/ui` file back with `%cx`, byte for byte, and converts `%jibb` to `%mime` and `%txt` and back. It commits half-written files, then deletes them. It merges a file that two desks changed on different lines, and checks that changes to the same line conflict. It can be rerun, and it leaves the two scratch desks it merges with (`%jibb-check-ours` and `%jibb-check-theirs`) holding only what `|new-desk` gives, unmounted.
143
143
144−`tools/clay-fixtures` syncs `my-app`, builds its example `/sur` files and marks through Clay, and checks selected types read from the compiled graphs and passed to the partial checker. It compares the results with golden files under `tests/clay-fixtures/`.
144+`tools/clay-fixtures` syncs `my-app` and `jibb-fixtures`, builds their example `/sur` files and marks through Clay, and checks selected types read from the compiled graphs and passed to the partial checker. It compares the results with golden files under `tests/clay-fixtures/`.
145
145
146For anything else:
146For anything else:
147
147
docs/development.md+3−4
@@ -73,13 +73,12 @@ git clone https://github.com/urbit/tools /root/src/tools
73| `tools/check` | Runs every check in this table, or a group (`--group eval` or `ship`), or some by name: see [Before pushing](#before-pushing) |
73| `tools/check` | Runs every check in this table, or a group (`--group eval` or `ship`), or some by name: see [Before pushing](#before-pushing) |
74| `tools/golden` | Runs the golden cases under `urbit eval`: every case, or those matching `--case`; `--update` rewrites the expected outputs; `--show` prints them |
74| `tools/golden` | Runs the golden cases under `urbit eval`: every case, or those matching `--case`; `--update` rewrites the expected outputs; `--show` prints them |
75| `tools/test-arms` | Runs the `test-` arms of the `tests/lib` suites under `urbit eval`, each with the subject Ford would give it on the `jibb-dev` desk: every suite, or those named or matched by a glob, as `tools/test-arms jibb-store 'jibb-program-*'`; `--shard I/N` runs the I-th of N balanced shards; `--list` prints the suites and their arms; `--report` and `--update` print or rewrite a golden-report suite's report; `--copies` checks only the `my-app` copies. See [The test suites](#the-test-suites) |
75| `tools/test-arms` | Runs the `test-` arms of the `tests/lib` suites under `urbit eval`, each with the subject Ford would give it on the `jibb-dev` desk: every suite, or those named or matched by a glob, as `tools/test-arms jibb-store 'jibb-program-*'`; `--shard I/N` runs the I-th of N balanced shards; `--list` prints the suites and their arms; `--report` and `--update` print or rewrite a golden-report suite's report; `--copies` checks only the `my-app` copies. See [The test suites](#the-test-suites) |
76−| `tools/clay-fixtures` | Syncs `my-app`, builds its example `/sur` files and marks through Clay, checks selected mold and mark projections and the partial checker, and records Ford and mark subject shapes on the fake ship |
76+| `tools/clay-fixtures` | Syncs `my-app` and `jibb-fixtures`, builds their example `/sur` files and marks through Clay, checks selected mold and mark projections and the partial checker, and records Ford and mark subject shapes on the fake ship |
77| `tools/hoon` | Evaluates Hoon with the library in scope, as `tools/hoon '(golden /a/b/jibb (crip "++ main view"))'`; `--cord name=file` binds a file's text, `-f` reads the expression from a file; `--no-debug` leaves out `!:`, which gives errors their positions but makes the checker 2.2 to 2.6 times slower than on a ship, for timings |
77| `tools/hoon` | Evaluates Hoon with the library in scope, as `tools/hoon '(golden /a/b/jibb (crip "++ main view"))'`; `--cord name=file` binds a file's text, `-f` reads the expression from a file; `--no-debug` leaves out `!:`, which gives errors their positions but makes the checker 2.2 to 2.6 times slower than on a ship, for timings |
78| `tools/doc-blocks` | Checks the doc's `jibb` blocks against the `doc-*` golden cases: `tools/doc-blocks docs/spec` |
78| `tools/doc-blocks` | Checks the doc's `jibb` blocks against the `doc-*` golden cases: `tools/doc-blocks docs/spec` |
79| `tools/ship` | Runs the fake ship: `start`, `stop`, `status`, `log`, `sync <desk>`, `assemble --out <dir>` (no ship needed), `test`, `gen-tests`, `check-commit`, `scry`, `hoon`, `run`, `poke`, `commit`, `mount`, `unmount` |
79| `tools/ship` | Runs the fake ship: `start`, `stop`, `status`, `log`, `sync <desk>`, `assemble --out <dir>` (no ship needed), `test`, `gen-tests`, `check-commit`, `scry`, `hoon`, `run`, `poke`, `commit`, `mount`, `unmount` |
80| `tools/testdata/selftest` | Tests `tools/golden` and `tools/hoon` against a stub library, `tools/test-arms` against the stub library with suites it writes, and `tools/doc-blocks` against Markdown it writes |
80| `tools/testdata/selftest` | Tests `tools/golden` and `tools/hoon` against a stub library, `tools/test-arms` against the stub library with suites it writes, and `tools/doc-blocks` against Markdown it writes |
81| `tools/testdata/ship-selftest` | Tests `tools/ship`'s test generator and runner against a stub library on the ship |
81| `tools/testdata/ship-selftest` | Tests `tools/ship`'s test generator and runner against a stub library on the ship |
82−| `tools/testdata/clay-fixtures-selftest` | Tests temporary Clay fixture cleanup and signal handling without a ship |
83
82
84`tools/golden` starts `urbit eval` once and builds the library, which takes about 27 s, then runs every case under `mule`, so a crash fails only its own case.
83`tools/golden` starts `urbit eval` once and builds the library, which takes about 27 s, then runs every case under `mule`, so a crash fails only its own case.
85
84
@@ -89,7 +88,7 @@ Each file in `tests/lib` is a suite: a core of `test-` arms, with the libraries
89
88
90A golden-report suite has a `report` arm and a golden file bound to the face `expected`; its test arm compares the report with that file, and `tools/test-arms --list` marks it `, report`. `tools/test-arms --report <suite>` prints the report, and `tools/test-arms --update <suite>` writes it to the file; with no suite named, `--update` writes every golden-report suite's. When such a suite's arm fails, `tools/test-arms` prints a unified diff between the file and the report. `jibb-buttons` and `jibb-deferred-prepared` have golden files too, but compare them inside helpers over several cases and have no `report` arm. Every golden file, a `/*` `%txt` file bound to a face containing `expected`, must end in exactly one newline (a suite compares `wain`s, which can't show a missing one) and hold no line that starts `BAD ` or ends `: BAD`; `tools/test-arms` checks that before any eval, and `--update` won't write a report that breaks it.
89A golden-report suite has a `report` arm and a golden file bound to the face `expected`; its test arm compares the report with that file, and `tools/test-arms --list` marks it `, report`. `tools/test-arms --report <suite>` prints the report, and `tools/test-arms --update <suite>` writes it to the file; with no suite named, `--update` writes every golden-report suite's. When such a suite's arm fails, `tools/test-arms` prints a unified diff between the file and the report. `jibb-buttons` and `jibb-deferred-prepared` have golden files too, but compare them inside helpers over several cases and have no `report` arm. Every golden file, a `/*` `%txt` file bound to a face containing `expected`, must end in exactly one newline (a suite compares `wain`s, which can't show a missing one) and hold no line that starts `BAD ` or ends `: BAD`; `tools/test-arms` checks that before any eval, and `--update` won't write a report that breaks it.
91
90
92−The `jibb-dev` desk holds `my-app`'s `ui/`, `sur/` and `mar/` under `/my-app` (review question 31), so the suites that check `my-app` files bind them there, as `/* sur %txt /my-app/sur/todo/hoon`, and keep no copies. A mark's `/-` line is Ford's, which `ride` can't parse, so the suites that ride a mark drop it with their `+mark-text` arm. Where the table below calls a `my-app` file byte-identical or unchanged, the suite reads that file itself. The fixtures that copy `my-app/mar/label.hoon` leave out its first line, a comment; `tests/my-app-copies.txt` lists them, one per line, as `COPY SOURCE without LINE`. `tools/test-arms` checks every pair when run with no suite or shard named, and `tools/test-arms --copies`, the `my-app-copies` check, checks only them.
91+The `jibb-dev` desk holds `my-app`'s `ui/`, `sur/` and `mar/` under `/my-app` (review question 31), so the suites that check `my-app` files bind them there, as `/* sur %txt /my-app/sur/todo/hoon`, and keep no copies. A mark's `/-` line is Ford's, which `ride` can't parse, so the suites that ride a mark drop it with their `+mark-text` arm. Where the table below calls a `my-app` file byte-identical or unchanged, the suite reads that file itself. Files that only the importer's tests need are kept off `my-app` (review question 34): the Clay fixtures' `/sur` with a Ford import, their mark and the real Tlon notes `/sur` are in `tests/clay-fixtures/desk/`, which the `jibb-fixtures` desk adds to `my-app` and the `jibb-dev` desk leaves out, and the golden cases and `tests/type-poke/mark.txt` that use the mark link to `tests/clay-fixtures/desk/mar/label.hoon`.
93
92
94| Suite | What it checks | Golden files |
93| Suite | What it checks | Golden files |
95| --- | --- | --- |
94| --- | --- | --- |
@@ -162,7 +161,7 @@ tools/check --group eval # only the checks that need no ship, as CI runs the
162nix flake check # the same checks in the Nix sandbox, on a fresh fake ~zod
161nix flake check # the same checks in the Nix sandbox, on a fresh fake ~zod
163```
162```
164
163
165−`tools/check` runs every check the repo has. Their one list is `CHECKS` in the script, so a new check goes there, as well as in the table above; `tools/check --list` prints it with each check's command. A new suite in `tests/lib` needs no new check: `arms-1` to `arms-4` run every suite's arms, in shards of about equal time, and a slow suite's cost belongs in `COSTS` in `tools/test-arms`, which balances them. The eval group, the 9 checks that need only `urbit` and Python, runs several at a time (`-j`, by default one per CPU), the slowest first. The ship group, `ship-selftest`, `ship-test`, `check-commit` and `clay-fixtures`, then runs one check at a time on the ship `tools/ship` talks to; `tools/check` starts it if it isn't running and stops it again afterwards. Name checks, or globs, to run only those: `tools/check golden 'arms-*'`. To run one suite under eval, use `tools/test-arms <suite>`, as `tools/test-arms jibb-todo-full`. A failing check's output follows its FAIL line; `-v` prints every check's output, and `--logs DIR` keeps it all.
164+`tools/check` runs every check the repo has. Their one list is `CHECKS` in the script, so a new check goes there, as well as in the table above; `tools/check --list` prints it with each check's command. A new suite in `tests/lib` needs no new check: `arms-1` to `arms-4` run every suite's arms, in shards of about equal time, and a slow suite's cost belongs in `COSTS` in `tools/test-arms`, which balances them. The eval group, the 7 checks that need only `urbit` and Python, runs several at a time (`-j`, by default one per CPU), the slowest first. The ship group, `ship-selftest`, `ship-test`, `check-commit` and `clay-fixtures`, then runs one check at a time on the ship `tools/ship` talks to; `tools/check` starts it if it isn't running and stops it again afterwards. Name checks, or globs, to run only those: `tools/check golden 'arms-*'`. To run one suite under eval, use `tools/test-arms <suite>`, as `tools/test-arms jibb-todo-full`. A failing check's output follows its FAIL line; `-v` prints every check's output, and `--logs DIR` keeps it all.
166
165
167CI, [.github/workflows/check.yml](../.github/workflows/check.yml), builds the desks and runs the eval group through the flake on every push to `master` and every pull request. It doesn't run the ship group, so run that before pushing.
166CI, [.github/workflows/check.yml](../.github/workflows/check.yml), builds the desks and runs the eval group through the flake on every push to `master` and every pull request. It doesn't run the ship group, so run that before pushing.
168
167
docs/status.md+1−3
@@ -121,7 +121,7 @@ Besides the plan's list:
121
121
122- 689 golden cases: 460 that parse and 229 that fail, each failure at a stated line and column. One failing case has an unclear expectation (corpus question 3). The newer type-output cases exercise only the partial inference fragment. Each case's `about.txt` quotes the doc's words it tests.
122- 689 golden cases: 460 that parse and 229 that fail, each failure at a stated line and column. One failing case has an unclear expectation (corpus question 3). The newer type-output cases exercise only the partial inference fragment. Each case's `about.txt` quotes the doc's words it tests.
123- The 689-case corpus passed under `urbit eval` in 107.0 s while other checks were running. The fake ship passed all 746 tests, including the source-overlap, structural-overlap, generic-union source and alias-overlap, full-module overlap, deferred-context, generic-recursion, generic-construction, generic-pattern, deferred-inference, empty-mold and cell-branch fixtures, importer, importer/checker and mark/checker bridges, module scope, unification, hole, qath, ask, default-wrapper importer, projection, arithmetic, generic-alias, positional-face, API-evidence, request, closed-gate, todo API, constructor, sub, nested-union, gate-free and direct-gate guards and the unchanged todo report. Desk sync took 111.2 s and the ship's `-test` run took 316.7 s. The importer golden compares 221 projections; `tools/clay-fixtures` builds the example Hoon fixtures through Clay, checks a recursive Ford import's origin, and passes Clay-built types through the Clay-built importer and partial checker.
123- The 689-case corpus passed under `urbit eval` in 107.0 s while other checks were running. The fake ship passed all 746 tests, including the source-overlap, structural-overlap, generic-union source and alias-overlap, full-module overlap, deferred-context, generic-recursion, generic-construction, generic-pattern, deferred-inference, empty-mold and cell-branch fixtures, importer, importer/checker and mark/checker bridges, module scope, unification, hole, qath, ask, default-wrapper importer, projection, arithmetic, generic-alias, positional-face, API-evidence, request, closed-gate, todo API, constructor, sub, nested-union, gate-free and direct-gate guards and the unchanged todo report. Desk sync took 111.2 s and the ship's `-test` run took 316.7 s. The importer golden compares 221 projections; `tools/clay-fixtures` builds the example Hoon fixtures through Clay, checks a recursive Ford import's origin, and passes Clay-built types through the Clay-built importer and partial checker.
124−- `tools/testdata/selftest` (23 checks), `tools/testdata/ship-selftest` and `tools/testdata/clay-fixtures-selftest` test the tools themselves; the last checks temporary Clay fixture cleanup and signal handling without a ship.
124+- `tools/testdata/selftest` (23 checks) and `tools/testdata/ship-selftest` test the tools themselves.
125- Two independent audits before 7c739b7, one of which compared the library with a reference parser written in Python from the doc over about 19,000 generated programs. Before ab797a9, a second Python parser, written from the decisions, agreed with the library on 8,000 generated programs and 900 hand-written probes.
125- Two independent audits before 7c739b7, one of which compared the library with a reference parser written in Python from the doc over about 19,000 generated programs. Before ab797a9, a second Python parser, written from the decisions, agreed with the library on 8,000 generated programs and 900 hand-written probes.
126- Speed: starting `urbit eval` and building the library takes about 27 s with the dev tools' `!:`, and 24 s without it (`tools/hoon --no-debug`). After that, a 2,000-line module of 400 definitions parses in about a second. Loops over definitions, arms, lines and items grow no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (library section 3).
126- Speed: starting `urbit eval` and building the library takes about 27 s with the dev tools' `!:`, and 24 s without it (`tools/hoon --no-debug`). After that, a 2,000-line module of 400 definitions parses in about a second. Loops over definitions, arms, lines and items grow no stack; nesting costs a few stack frames a level, and 100,000 nested brackets still parse (library section 3).
127
127
@@ -253,7 +253,6 @@ On a machine set up as [development.md](development.md) says:
253tools/golden # 660 cases under urbit eval
253tools/golden # 660 cases under urbit eval
254tools/test-arms # the my-app copies, then every tests/lib suite under urbit eval
254tools/test-arms # the my-app copies, then every tests/lib suite under urbit eval
255tools/test-arms --list # the suites and their arms; ", report" marks a golden report
255tools/test-arms --list # the suites and their arms; ", report" marks a golden report
256−tools/test-arms --copies # the copies of my-app/mar/label.hoon in tests/my-app-copies.txt match it
257tools/test-arms --report jibb-import # print a golden-report suite's report
256tools/test-arms --report jibb-import # print a golden-report suite's report
258tools/test-arms --update jibb-import # write it to the suite's expected file
257tools/test-arms --update jibb-import # write it to the suite's expected file
259tools/test-arms jibb-import # the Hoon importer fixture projection
258tools/test-arms jibb-import # the Hoon importer fixture projection
@@ -300,7 +299,6 @@ tools/doc-blocks docs/spec # the doc's examples are golden cases
300tools/ship start
299tools/ship start
301tools/ship test # the same 660 cases, and every tests/lib suite, as -test arms on the ship
300tools/ship test # the same 660 cases, and every tests/lib suite, as -test arms on the ship
302tools/testdata/ship-selftest
301tools/testdata/ship-selftest
303−tools/testdata/clay-fixtures-selftest # scratch fixture cleanup without a ship
304tools/ship check-commit # |commit stores .jibb files
302tools/ship check-commit # |commit stores .jibb files
305tools/clay-fixtures # example /sur files and marks build through Clay
303tools/clay-fixtures # example /sur files and marks build through Clay
306```
304```
flake.nix+3−2
@@ -90,7 +90,8 @@
90 '';
90 '';
91
91
92 # The desks, as tools/ship assembles them for the ship:
92 # The desks, as tools/ship assembles them for the ship:
93− # $out/my-app, $out/jibb and $out/jibb-dev, the test desk. The
93+ # $out/my-app, $out/jibb, $out/jibb-dev, the test desk, and
94+ # $out/jibb-fixtures, for the Clay fixtures. The
94 # check phase compiles the two libraries under urbit eval.
95 # check phase compiles the two libraries under urbit eval.
95 desks = pkgs.stdenvNoCC.mkDerivation {
96 desks = pkgs.stdenvNoCC.mkDerivation {
96 # No version in the name, so a commit that changes no desk
97 # No version in the name, so a commit that changes no desk
@@ -123,7 +124,7 @@
123 # The files are the desks' as they are: nothing to patch.
124 # The files are the desks' as they are: nothing to patch.
124 dontFixup = true;
125 dontFixup = true;
125 meta = {
126 meta = {
126− description = "The Jibb desks: my-app, jibb and jibb-dev";
127+ description = "The Jibb desks: my-app, jibb, jibb-dev and jibb-fixtures";
127 platforms = systems;
128 platforms = systems;
128 };
129 };
129 };
130 };
tests/clay-fixtures/expected.txt → tests/clay-fixtures/build-expected.txtrenamed

The content is the same.

my-app/mar/label.hoon → tests/clay-fixtures/desk/mar/label.hoonrenamed−1
@@ -1,4 +1,3 @@
1−:: Fixture for the Hoon mark importer; not supplied by the design doc.
2|_ a=@t
1|_ a=@t
3++ grab |% ++ noun @t --
2++ grab |% ++ noun @t --
4++ grow |% ++ noun a --
3++ grow |% ++ noun a --
my-app/sur/import-fixture.hoon → tests/clay-fixtures/desk/sur/import-fixture.hoonrenamed

The content is the same.

tests/clay-fixtures/desk/sur/mop-tlon-probe.hoonnew file+1
@@ -0,0 +1 @@
1+../../../golden/types-import-tlon-notes/sur/notes.txt
tests/clay-fixtures/ford-import.txt+2−2
@@ -1,8 +1,8 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/import-fixture/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
5+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6=/ cor=type -.src
6=/ cor=type -.src
7=/ typ=type (~(play ut cor) (ream '*sample'))
7=/ typ=type (~(play ut cor) (ream '*sample'))
8=/ read-gate=vase (slap reader (ream 'read-mold-in'))
8=/ read-gate=vase (slap reader (ream 'read-mold-in'))
tests/clay-fixtures/ford-nested-union-bridge.txt+4−4
@@ -1,10 +1,10 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/import-fixture/hoon)
5−=/ blog=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/blog/hoon)
5+=/ blog=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/blog/hoon)
6−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
6+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
7−=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb/hoon)
7+=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb/hoon)
8=/ read-gate=vase (slap reader (ream 'read-named'))
8=/ read-gate=vase (slap reader (ream 'read-named'))
9=/ result=vase (slym read-gate [%import-fixture %nested -.src])
9=/ result=vase (slym read-gate [%import-fixture %nested -.src])
10=/ sample-result=vase (slym read-gate [%import-fixture %sample -.src])
10=/ sample-result=vase (slym read-gate [%import-fixture %sample -.src])
tests/clay-fixtures/ford-nested-union.txt+2−2
@@ -1,8 +1,8 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/import-fixture/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
5+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6=/ read-gate=vase (slap reader (ream 'read-named'))
6=/ read-gate=vase (slap reader (ream 'read-named'))
7=/ got=vase (slym read-gate [%import-fixture %nested -.src])
7=/ got=vase (slym read-gate [%import-fixture %nested -.src])
8=/ show-gate=vase (slap reader (ream 'show-result'))
8=/ show-gate=vase (slap reader (ream 'show-result'))
tests/clay-fixtures/ford-recursive.txt+2−2
@@ -1,8 +1,8 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/import-fixture/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
5+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6=/ read-gate=vase (slap reader (ream 'read-named'))
6=/ read-gate=vase (slap reader (ream 'read-named'))
7=/ got=vase (slym read-gate [%import-fixture %recursive -.src])
7=/ got=vase (slym read-gate [%import-fixture %recursive -.src])
8=/ show-gate=vase (slap reader (ream 'show-result'))
8=/ show-gate=vase (slap reader (ream 'show-result'))
tests/clay-fixtures/ford.txt+1−1
@@ -1,7 +1,7 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/import-fixture/hoon)
5=/ cor=type -.src
5=/ cor=type -.src
6?. ?=([%core *] cor) (pure:m !>('not a core'))
6?. ?=([%core *] cor) (pure:m !>('not a core'))
7=/ subject=type q.q.cor
7=/ subject=type q.q.cor
tests/clay-fixtures/mark-bridge.txt+3−3
@@ -1,9 +1,9 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ mark=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/mar/label/hoon)
4+=/ mark=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/mar/label/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
5+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6−=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb/hoon)
6+=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb/hoon)
7=/ read-gate=vase (slap reader (ream 'read-mark'))
7=/ read-gate=vase (slap reader (ream 'read-mark'))
8=/ label-result=vase (slym read-gate [%label -.mark])
8=/ label-result=vase (slym read-gate [%label -.mark])
9=/ check-gate=vase (slap jibb (ream 'golden-types-with-marks'))
9=/ check-gate=vase (slap jibb (ream 'golden-types-with-marks'))
tests/clay-fixtures/tlon-mop.txt+2−2
@@ -1,8 +1,8 @@
1=/ m (strand ,vase)
1=/ m (strand ,vase)
2;< =bowl:spider bind:m get-bowl
2;< =bowl:spider bind:m get-bowl
3=/ now=@da now.bowl
3=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/mop-tlon-probe/hoon)
4+=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/sur/mop-tlon-probe/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
5+=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6=/ read-gate=vase (slap reader (ream 'read-named'))
6=/ read-gate=vase (slap reader (ream 'read-named'))
7=/ result=vase (slym read-gate [%notes %log -.src])
7=/ result=vase (slym read-gate [%notes %log -.src])
8=/ recursive=vase (slym read-gate [%notes %import-node -.src])
8=/ recursive=vase (slym read-gate [%notes %import-node -.src])
tests/golden/module-import-api-derived-clash/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-import-error/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-mark-prelude-value/mar/same.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-mark-value/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-nested-path/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-paths-mark-value/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-paths-mark-value/mar/other.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-paths-scope-conflict/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-poke-clash/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-request-reason/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-api-scope-conflict/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/module-import-root-import-shadow/mar/label.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/types-import-mark/mar/label.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/types-module-mixed/mar/label.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/golden/types-request-normal/mar/full.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../../../clay-fixtures/desk/mar/label.hoon
tests/my-app-copies.txtdeleted−25
@@ -1,25 +0,0 @@
1−# Files under tests/ that copy my-app/mar/label.hoon without its first
2−# line, a comment. Tests read my-app's other sources where the jibb-dev
3−# desk holds them, under /my-app, and golden cases link to them.
4−# tools/test-arms checks every pair before it runs anything (--copies
5−# runs only that).
6−#
7−# COPY SOURCE [without LINE]: the copy equals the source, or the source
8−# with the first occurrence of LINE and its newline removed.
9−
10−tests/golden/module-import-api-derived-clash/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
11−tests/golden/module-import-api-import-error/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
12−tests/golden/module-import-api-mark-prelude-value/mar/same.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
13−tests/golden/module-import-api-mark-value/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
14−tests/golden/module-import-api-nested-path/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
15−tests/golden/module-import-api-paths-mark-value/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
16−tests/golden/module-import-api-paths-mark-value/mar/other.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
17−tests/golden/module-import-api-paths-scope-conflict/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
18−tests/golden/module-import-api-poke-clash/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
19−tests/golden/module-import-api-request-reason/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
20−tests/golden/module-import-api-scope-conflict/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
21−tests/golden/module-import-root-import-shadow/mar/label.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
22−tests/golden/types-import-mark/mar/label.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
23−tests/golden/types-module-mixed/mar/label.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
24−tests/golden/types-request-normal/mar/full.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
25−tests/type-poke/mark.txt my-app/mar/label.hoon without :: Fixture for the Hoon mark importer; not supplied by the design doc.
tests/type-poke/mark.txtmode 100644 → 120000+1−5
@@ -1,5 +0,0 @@
1−|_ a=@t
2−++ grab |% ++ noun @t --
3−++ grow |% ++ noun a --
4−++ grad %noun
5−--
@@ -0,0 +1 @@
1+../clay-fixtures/desk/mar/label.hoon
tools/check−2
@@ -79,9 +79,7 @@ CHECKS = [
79 ['tools/test-arms', '--shard', '%d/%d' % (i, ARM_SHARDS)])
79 ['tools/test-arms', '--shard', '%d/%d' % (i, ARM_SHARDS)])
80 for i in range(1, ARM_SHARDS + 1)
80 for i in range(1, ARM_SHARDS + 1)
81] + [
81] + [
82− Check('my-app-copies', 'eval', ['tools/test-arms', '--copies']),
83 Check('doc-blocks', 'eval', ['tools/doc-blocks', 'docs/spec']),
82 Check('doc-blocks', 'eval', ['tools/doc-blocks', 'docs/spec']),
84− tool('testdata/clay-fixtures-selftest'),
85 # The ship group. ship-selftest leaves its fixture files on the
83 # The ship group. ship-selftest leaves its fixture files on the
86 # jibb-dev desk, and ship-test, which syncs the desk to the repo
84 # jibb-dev desk, and ship-test, which syncs the desk to the repo
87 # first, puts the real ones back, so it must come after.
85 # first, puts the real ones back, so it must come after.
tools/clay-fixtures+75−221
@@ -1,9 +1,16 @@
1#!/usr/bin/env python3
1#!/usr/bin/env python3
2−"""Build and inspect example /sur and mark fixtures through Clay."""
2+"""Build and inspect example /sur and mark fixtures through Clay.
3+
4+Each fixture is a thread in tests/clay-fixtures, NAME.txt, which
5+tools/ship runs on the ship; what it prints must equal NAME-expected.txt.
6+The threads build my-app's own /sur and marks on the my-app desk. The
7+files only they need, a /sur with a Ford import, a mark and the real
8+Tlon notes /sur (a link to a golden case's fixture), are in
9+tests/clay-fixtures/desk, which the jibb-fixtures desk adds to my-app.
10+Both desks are synced first.
11+"""
3
12
4from pathlib import Path
13from pathlib import Path
5−import shutil
6−import signal
7import subprocess
14import subprocess
8import sys
15import sys
9import tempfile
16import tempfile
@@ -11,228 +18,75 @@ import tempfile
11root = Path(__file__).resolve().parent.parent
18root = Path(__file__).resolve().parent.parent
12ship = root / 'tools' / 'ship'
19ship = root / 'tools' / 'ship'
13fixtures = root / 'tests' / 'clay-fixtures'
20fixtures = root / 'tests' / 'clay-fixtures'
14−try:
15− subprocess.run([str(ship), 'sync', 'my-app'], check=True)
16− result = subprocess.run([str(ship), 'run', str(fixtures / 'build.txt')],
17− stdout=subprocess.PIPE, check=True)
18−except subprocess.CalledProcessError as error:
19− sys.exit(error.returncode)
20−expected = (fixtures / 'expected.txt').read_bytes()
21−if result.stdout != expected:
22− print('Clay fixture builds differ from tests/clay-fixtures/expected.txt',
23− file=sys.stderr)
24− print('expected:', expected.decode().rstrip(), file=sys.stderr)
25− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
26− sys.exit(1)
27−print('Clay fixture builds: 7 passed')
28−
29−# Inject the reader rather than copying it into the fixture: Clay supplies
30−# each compiled /sur type graph, and the current reader examines its molds.
31−reader = (root / 'jibb-dev/lib/jibb-import.hoon').read_text()
32−template = (fixtures / 'import.txt').read_text()
33−if template.count('@@READER@@') != 1:
34− sys.exit('Clay import fixture needs exactly one reader placeholder')
35−binding = '=/ reader\n' + ''.join(' ' + line for line in reader.splitlines(keepends=True))
36−with tempfile.TemporaryDirectory(prefix='jibb-clay-import-') as tmp:
37− program = Path(tmp) / 'import.hoon'
38− program.write_text(template.replace('@@READER@@', binding))
39− try:
40− result = subprocess.run([str(ship), 'run', str(program)],
41− stdout=subprocess.PIPE, check=True)
42− except subprocess.CalledProcessError as error:
43− sys.exit(error.returncode)
44−expected = (fixtures / 'import-expected.txt').read_bytes()
45−if result.stdout != expected:
46− print('Clay imports differ from tests/clay-fixtures/import-expected.txt', file=sys.stderr)
47− print('expected:', expected.decode().rstrip(), file=sys.stderr)
48− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
49− sys.exit(1)
50−print('Clay importer golden: 4 projections passed')
51−
52−# This second report uses Clay-built library cores as well as a Clay-built
53−# /sur, then passes the selected reader result into the partial checker.
54−try:
55− result = subprocess.run([str(ship), 'run', str(fixtures / 'bridge.txt')],
56− stdout=subprocess.PIPE, check=True)
57−except subprocess.CalledProcessError as error:
58− sys.exit(error.returncode)
59−expected = (fixtures / 'bridge-expected.txt').read_bytes()
60−if result.stdout != expected:
61− print('Clay bridge differs from tests/clay-fixtures/bridge-expected.txt', file=sys.stderr)
62− print('expected:', expected.decode().rstrip(), file=sys.stderr)
63− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
64− sys.exit(1)
65−print('Clay importer/checker bridge golden passed')
66−
67−try:
68− result = subprocess.run([str(ship), 'run', str(fixtures / 'record-bridge.txt')],
69− stdout=subprocess.PIPE, check=True)
70−except subprocess.CalledProcessError as error:
71− sys.exit(error.returncode)
72−expected = (fixtures / 'record-bridge-expected.txt').read_bytes()
73−if result.stdout != expected:
74− print('Clay record bridge differs from tests/clay-fixtures/record-bridge-expected.txt', file=sys.stderr)
75− print('expected:', expected.decode().rstrip(), file=sys.stderr)
76− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
77− sys.exit(1)
78−print('Clay record importer/checker bridge golden passed')
79−
80−# A /sur with a Ford import has a different parent subject. This golden
81−# records the actual shape for provenance work without claiming support.
82−try:
83− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford.txt')],
84− stdout=subprocess.PIPE, check=True)
85−except subprocess.CalledProcessError as error:
86− sys.exit(error.returncode)
87−expected = (fixtures / 'ford-expected.txt').read_bytes()
88−if result.stdout != expected:
89− print('Clay Ford subject differs from tests/clay-fixtures/ford-expected.txt', file=sys.stderr)
90− print('expected:', expected.decode().rstrip(), file=sys.stderr)
91− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
92− sys.exit(1)
93−print('Clay Ford subject golden passed')
94−
95−try:
96− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford-import.txt')],
97− stdout=subprocess.PIPE, check=True)
98−except subprocess.CalledProcessError as error:
99− sys.exit(error.returncode)
100−expected = (fixtures / 'ford-import-expected.txt').read_bytes()
101−if result.stdout != expected:
102− print('Clay Ford import differs from tests/clay-fixtures/ford-import-expected.txt', file=sys.stderr)
103− print('expected:', expected.decode().rstrip(), file=sys.stderr)
104− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
105− sys.exit(1)
106−print('Clay Ford importer golden passed')
107−
108−try:
109− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford-recursive.txt')],
110− stdout=subprocess.PIPE, check=True)
111−except subprocess.CalledProcessError as error:
112− sys.exit(error.returncode)
113−expected = (fixtures / 'ford-recursive-expected.txt').read_bytes()
114−if result.stdout != expected:
115− print('Clay recursive Ford import differs from tests/clay-fixtures/ford-recursive-expected.txt', file=sys.stderr)
116− print('expected:', expected.decode().rstrip(), file=sys.stderr)
117− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
118− sys.exit(1)
119−print('Clay recursive Ford importer golden passed')
120−
121−try:
122− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford-nested-union.txt')],
123− stdout=subprocess.PIPE, check=True)
124−except subprocess.CalledProcessError as error:
125− sys.exit(error.returncode)
126−expected = (fixtures / 'ford-nested-union-expected.txt').read_bytes()
127−if result.stdout != expected:
128− print('Clay nested union import differs from tests/clay-fixtures/ford-nested-union-expected.txt', file=sys.stderr)
129− print('expected:', expected.decode().rstrip(), file=sys.stderr)
130− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
131− sys.exit(1)
132−print('Clay nested Ford union importer golden passed')
133
21
134−try:
22+# (thread, what a mismatch says, what a pass says), in the order they run
23+FIXTURES = [
24+ ('build', 'Clay fixture builds differ', 'Clay fixture builds: 7 passed'),
25+ ('import', 'Clay imports differ',
26+ 'Clay importer golden: 4 projections passed'),
27+ # Clay-built library cores as well as a Clay-built /sur; the selected
28+ # reader result goes to the partial checker.
29+ ('bridge', 'Clay bridge differs',
30+ 'Clay importer/checker bridge golden passed'),
31+ ('record-bridge', 'Clay record bridge differs',
32+ 'Clay record importer/checker bridge golden passed'),
33+ # A /sur with a Ford import has a different parent subject. This
34+ # records the actual shape for provenance work without claiming
35+ # support.
36+ ('ford', 'Clay Ford subject differs', 'Clay Ford subject golden passed'),
37+ ('ford-import', 'Clay Ford import differs',
38+ 'Clay Ford importer golden passed'),
39+ ('ford-recursive', 'Clay recursive Ford import differs',
40+ 'Clay recursive Ford importer golden passed'),
41+ ('ford-nested-union', 'Clay nested union import differs',
42+ 'Clay nested Ford union importer golden passed'),
43+ ('ford-nested-union-bridge', 'Clay nested union bridge differs',
44+ 'Clay nested Ford union importer/checker bridge golden passed'),
45+ ('tlon-mop', 'Clay Tlon mop import differs',
46+ 'Clay Tlon named-mold mop importer golden passed'),
47+ ('mark-shape', 'Clay mark subject differs',
48+ 'Clay mark subject golden passed'),
49+ ('mark-import', 'Clay mark import differs',
50+ 'Clay mark importer golden passed'),
51+ ('mark-update-import', 'Clay union mark import differs',
52+ 'Clay union mark importer golden passed'),
53+ ('mark-bridge', 'Clay mark bridge differs',
54+ 'Clay mark importer/checker bridge golden passed'),
55+]
56+
57+
58+def output(name, tmp):
59+ """What the fixture's thread prints."""
60+ thread = fixtures / (name + '.txt')
61+ if name == 'import':
62+ # Inject the reader rather than copying it into the fixture: Clay
63+ # supplies each compiled /sur type graph, and the current reader
64+ # examines its molds.
65+ reader = (root / 'jibb-dev/lib/jibb-import.hoon').read_text()
66+ template = thread.read_text()
67+ if template.count('@@READER@@') != 1:
68+ sys.exit('Clay import fixture needs exactly one reader placeholder')
69+ binding = '=/ reader\n' + ''.join(
70+ ' ' + line for line in reader.splitlines(keepends=True))
71+ thread = Path(tmp) / 'import.hoon'
72+ thread.write_text(template.replace('@@READER@@', binding))
135− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford-nested-union-bridge.txt')],
73+ return subprocess.run([str(ship), 'run', str(thread)],
136− stdout=subprocess.PIPE, check=True)
74+ stdout=subprocess.PIPE, check=True).stdout
137−except subprocess.CalledProcessError as error:
138− sys.exit(error.returncode)
139−expected = (fixtures / 'ford-nested-union-bridge-expected.txt').read_bytes()
140−if result.stdout != expected:
141− print('Clay nested union bridge differs from tests/clay-fixtures/ford-nested-union-bridge-expected.txt', file=sys.stderr)
142− print('expected:', expected.decode().rstrip(), file=sys.stderr)
143− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
144− sys.exit(1)
145−print('Clay nested Ford union importer/checker bridge golden passed')
146
75
147−# Build the real Tlon source in a temporary desk assembly. It lives in the
148−# golden corpus rather than an app desk; the normal desk is restored even if
149−# the temporary sync, thread, or comparison fails.
150−def stop_for_signal(signum, frame):
151− raise InterruptedError('interrupted during temporary Clay fixture')
152
76
153−previous = signal.signal(signal.SIGTERM, stop_for_signal)
154−previous_int = signal.getsignal(signal.SIGINT)
155try:
77try:
78+ for desk in ('my-app', 'jibb-fixtures'):
79+ subprocess.run([str(ship), 'sync', desk], check=True)
156− with tempfile.TemporaryDirectory(prefix='jibb-clay-tlon-') as tmp:
80+ with tempfile.TemporaryDirectory(prefix='jibb-clay-') as tmp:
157− scratch = Path(tmp)
81+ for name, differs, passed in FIXTURES:
158− (scratch / 'tools').mkdir()
82+ got = output(name, tmp)
159− shutil.copy2(ship, scratch / 'tools/ship')
83+ want = 'tests/clay-fixtures/%s-expected.txt' % name
160− shutil.copy2(root / 'tools/golden_case.py', scratch / 'tools/golden_case.py')
161− for folder in ('vendor', 'jibb-dev', 'tests'):
162− (scratch / folder).symlink_to(root / folder, target_is_directory=True)
163− shutil.copytree(root / 'my-app', scratch / 'my-app')
164− shutil.copy2(root / 'tests/golden/types-import-tlon-notes/sur/notes.txt',
165− scratch / 'my-app/sur/mop-tlon-probe.hoon')
166− try:
167− subprocess.run([sys.executable, str(scratch / 'tools/ship'),
168− 'sync', 'my-app'], check=True)
169− result = subprocess.run([str(ship), 'run', str(fixtures / 'tlon-mop.txt')],
170− stdout=subprocess.PIPE, check=True)
171− expected = (fixtures / 'tlon-mop-expected.txt').read_bytes()
84+ expected = (root / want).read_bytes()
172− if result.stdout != expected:
85+ if got != expected:
173− print('Clay Tlon mop import differs from tests/clay-fixtures/tlon-mop-expected.txt',
174− file=sys.stderr)
86+ print('%s from %s' % (differs, want), file=sys.stderr)
175 print('expected:', expected.decode().rstrip(), file=sys.stderr)
87 print('expected:', expected.decode().rstrip(), file=sys.stderr)
176− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
88+ print('actual: ', got.decode().rstrip(), file=sys.stderr)
177− raise SystemExit(1)
178− finally:
179− # A second termination request must not interrupt desk restoration.
180− signal.signal(signal.SIGTERM, signal.SIG_IGN)
181− signal.signal(signal.SIGINT, signal.SIG_IGN)
182− subprocess.run([str(ship), 'sync', 'my-app'], check=True)
183−finally:
184− signal.signal(signal.SIGTERM, previous)
185− signal.signal(signal.SIGINT, previous_int)
186−print('Clay Tlon named-mold mop importer golden passed')
187−
188−try:
189− result = subprocess.run([str(ship), 'run', str(fixtures / 'mark-shape.txt')],
190− stdout=subprocess.PIPE, check=True)
191−except subprocess.CalledProcessError as error:
192− sys.exit(error.returncode)
193−expected = (fixtures / 'mark-shape-expected.txt').read_bytes()
194−if result.stdout != expected:
195− print('Clay mark subject differs from tests/clay-fixtures/mark-shape-expected.txt', file=sys.stderr)
196− print('expected:', expected.decode().rstrip(), file=sys.stderr)
197− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
198− sys.exit(1)
89+ sys.exit(1)
199−print('Clay mark subject golden passed')
90+ print(passed)
200−
201−try:
202− result = subprocess.run([str(ship), 'run', str(fixtures / 'mark-import.txt')],
203− stdout=subprocess.PIPE, check=True)
204−except subprocess.CalledProcessError as error:
205− sys.exit(error.returncode)
206−expected = (fixtures / 'mark-import-expected.txt').read_bytes()
207−if result.stdout != expected:
208− print('Clay mark import differs from tests/clay-fixtures/mark-import-expected.txt', file=sys.stderr)
209− print('expected:', expected.decode().rstrip(), file=sys.stderr)
210− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
211− sys.exit(1)
212−print('Clay mark importer golden passed')
213−
214−try:
215− result = subprocess.run([str(ship), 'run', str(fixtures / 'mark-update-import.txt')],
216− stdout=subprocess.PIPE, check=True)
217−except subprocess.CalledProcessError as error:
218− sys.exit(error.returncode)
219−expected = (fixtures / 'mark-update-import-expected.txt').read_bytes()
220−if result.stdout != expected:
221− print('Clay union mark import differs from tests/clay-fixtures/mark-update-import-expected.txt', file=sys.stderr)
222− print('expected:', expected.decode().rstrip(), file=sys.stderr)
223− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
224− sys.exit(1)
225−print('Clay union mark importer golden passed')
226−
227−try:
228− result = subprocess.run([str(ship), 'run', str(fixtures / 'mark-bridge.txt')],
229− stdout=subprocess.PIPE, check=True)
230except subprocess.CalledProcessError as error:
91except subprocess.CalledProcessError as error:
231 sys.exit(error.returncode)
92 sys.exit(error.returncode)
232−expected = (fixtures / 'mark-bridge-expected.txt').read_bytes()
233−if result.stdout != expected:
234− print('Clay mark bridge differs from tests/clay-fixtures/mark-bridge-expected.txt', file=sys.stderr)
235− print('expected:', expected.decode().rstrip(), file=sys.stderr)
236− print('actual: ', result.stdout.decode().rstrip(), file=sys.stderr)
237− sys.exit(1)
238−print('Clay mark importer/checker bridge golden passed')
tools/ship+12−3
@@ -61,13 +61,19 @@ TESTS_LIB = os.path.join(ROOT, 'tests', 'lib', 'jibb.hoon')
61# order. Every desk gets every package under vendor/. A folder is
61# order. Every desk gets every package under vendor/. A folder is
62# (repo folder, desk folder, folders and files left out). The test
62# (repo folder, desk folder, folders and files left out). The test
63# desk holds my-app's sources under /my-app, so tests read them there
63# desk holds my-app's sources under /my-app, so tests read them there
64−# instead of keeping copies.
64+# instead of keeping copies. jibb-fixtures is my-app plus the Hoon
65+# /sur and mark files only the importer's Clay fixtures build, kept in
66+# tests/clay-fixtures/desk so the example app doesn't carry them.
65DESKS = {
67DESKS = {
66 'my-app': [('jibb-dev', '', ['tests']), ('my-app', '', [])],
68 'my-app': [('jibb-dev', '', ['tests']), ('my-app', '', [])],
67 'jibb': [('jibb', '', [])],
69 'jibb': [('jibb', '', [])],
68− 'jibb-dev': [('jibb-dev', '', []), ('tests', 'tests', []),
70+ 'jibb-dev': [('jibb-dev', '', []),
71+ ('tests', 'tests', [os.path.join('clay-fixtures', 'desk')]),
69 ('my-app', 'my-app',
72 ('my-app', 'my-app',
70 ['desk.bill', 'desk.docket-0', 'sys.kelvin'])],
73 ['desk.bill', 'desk.docket-0', 'sys.kelvin'])],
74+ 'jibb-fixtures': [('jibb-dev', '', ['tests']),
75+ ('my-app', '', ['desk.docket-0']),
76+ (os.path.join('tests', 'clay-fixtures', 'desk'), '', [])],
71}
77}
72# The test desk has no sys.kelvin of its own; Clay refuses a commit
78# The test desk has no sys.kelvin of its own; Clay refuses a commit
73# without one, so it gets the %jibb desk's.
79# without one, so it gets the %jibb desk's.
@@ -902,7 +908,7 @@ def assemble(desk, lib=None, golden=None):
902 golden = golden or GOLDEN
908 golden = golden or GOLDEN
903 if os.path.isdir(os.path.join(ROOT, 'tests')):
909 if os.path.isdir(os.path.join(ROOT, 'tests')):
904 a.add_tree(os.path.join(ROOT, 'tests'), 'tests',
910 a.add_tree(os.path.join(ROOT, 'tests'), 'tests',
905− skip=['golden'], drop=lambda rel:
911+ skip=['golden'] + skip, drop=lambda rel:
906 rel == os.path.join('lib', 'jibb.hoon') or
912 rel == os.path.join('lib', 'jibb.hoon') or
907 (isolated and rel.startswith('lib' + os.sep) and
913 (isolated and rel.startswith('lib' + os.sep) and
908 rel.endswith('.hoon')))
914 rel.endswith('.hoon')))
@@ -2321,6 +2327,9 @@ EPILOG = """\
2321desks:
2327desks:
2322 my-app vendor/* + jibb-dev (without any tests/) + my-app
2328 my-app vendor/* + jibb-dev (without any tests/) + my-app
2323 jibb vendor/* + jibb
2329 jibb vendor/* + jibb
2330+ jibb-fixtures
2331+ vendor/* + jibb-dev (without any tests/) + my-app (without
2332+ desk.docket-0) + tests/clay-fixtures/desk, for tools/clay-fixtures
2324 jibb-dev vendor/* + jibb-dev + tests + my-app (under /my-app, without
2333 jibb-dev vendor/* + jibb-dev + tests + my-app (under /my-app, without
2325 its desk files), the test desk: tests/golden from --golden,
2334 its desk files), the test desk: tests/golden from --golden,
2326 less the case files that link to my-app, tests/lib/jibb.hoon
2335 less the case files that link to my-app, tests/lib/jibb.hoon
tools/test-arms+1−65
@@ -7,7 +7,6 @@
7 tools/test-arms --list the suites, their arms and reports
7 tools/test-arms --list the suites, their arms and reports
8 tools/test-arms --report jibb-poke-bridge
8 tools/test-arms --report jibb-poke-bridge
9 tools/test-arms --update jibb-poke-bridge
9 tools/test-arms --update jibb-poke-bridge
10− tools/test-arms --copies only the my-app copy check
11
10
12The ship runs the same arms with -test /=jibb-dev=/tests (tools/ship
11The ship runs the same arms with -test /=jibb-dev=/tests (tools/ship
13test). Here each suite gets the subject Ford would give it on the
12test). Here each suite gets the subject Ford would give it on the
@@ -29,9 +28,7 @@ left out: tools/golden runs those cases under eval.
29Golden files, the /* %txt files bound to a face with "expected" in its
28Golden files, the /* %txt files bound to a face with "expected" in its
30name, must end in exactly one newline (a wain can't show it) and hold no
29name, must end in exactly one newline (a wain can't show it) and hold no
31line that starts "BAD " or ends ": BAD" (a check's own failure marker).
30line that starts "BAD " or ends ": BAD" (a check's own failure marker).
32−That is checked before any eval, as are, when no suite or shard is named,
31+That is checked before any eval.
33−the copies of my-app/mar/label.hoon that tests/my-app-copies.txt lists,
34−which must match it (--copies checks only them).
35
32
36Exit status: 0 when every arm passes, 1 when one fails, 2 on a usage
33Exit status: 0 when every arm passes, 1 when one fails, 2 on a usage
37error.
34error.
@@ -56,7 +53,6 @@ from noun import atom_to_bytes, to_list # noqa: E402
56
53
57ROOT = os.path.dirname(TOOLS)
54ROOT = os.path.dirname(TOOLS)
58LIB_DIR = os.path.join(ROOT, 'tests', 'lib')
55LIB_DIR = os.path.join(ROOT, 'tests', 'lib')
59−COPIES = os.path.join(ROOT, 'tests', 'my-app-copies.txt')
60GENERATED = 'jibb' # tests/lib/jibb.hoon, from tools/ship gen-tests
56GENERATED = 'jibb' # tests/lib/jibb.hoon, from tools/ship gen-tests
61LIBRARY = 'jibb' # /+ jibb: the library under test, --lib
57LIBRARY = 'jibb' # /+ jibb: the library under test, --lib
62
58
@@ -177,51 +173,6 @@ def lib_source(desk, name):
177 raise Unusable('no /lib/%s.hoon on the jibb-dev desk' % name)
173 raise Unusable('no /lib/%s.hoon on the jibb-dev desk' % name)
178
174
179
175
180−# ---------------------------------------------------------------- copies
181−
182−
183−def check_copies():
184− """The tests/ files that copy my-app sources must match them."""
185− problems, pairs = [], 0
186− with open(COPIES, encoding='utf-8') as f:
187− lines = f.read().split('\n')
188− for n, line in enumerate(lines, 1):
189− if not line.strip() or line.startswith('#'):
190− continue
191− words = line.split(None, 2)
192− without = None
193− if len(words) == 3:
194− if not words[2].startswith('without '):
195− words = []
196− else:
197− without = words[2][len('without '):].encode() + b'\n'
198− if len(words) < 2:
199− problems.append('tests/my-app-copies.txt:%d: COPY SOURCE '
200− '[without LINE], not %s' % (n, line))
201− continue
202− copy, source = words[0], words[1]
203− try:
204− with open(os.path.join(ROOT, copy), 'rb') as f:
205− got = f.read()
206− with open(os.path.join(ROOT, source), 'rb') as f:
207− want = f.read()
208− except OSError as e:
209− problems.append('tests/my-app-copies.txt:%d: %s' % (n, e))
210− continue
211− if without is not None:
212− if without not in want:
213− problems.append('tests/my-app-copies.txt:%d: %s has no line %s'
214− % (n, source, without.decode().rstrip()))
215− continue
216− want = want.replace(without, b'', 1)
217− pairs += 1
218− if got != want:
219− problems.append('%s differs from %s%s' % (
220− copy, source, '' if without is None else
221− ' without %s' % without.decode().rstrip()))
222− return pairs, problems
223−
224−
225def golden_problems(text):
176def golden_problems(text):
226 """What is wrong with a golden file's or report's bytes, or None."""
177 """What is wrong with a golden file's or report's bytes, or None."""
227 if not text.endswith(b'\n') or text.endswith(b'\n\n'):
178 if not text.endswith(b'\n') or text.endswith(b'\n\n'):
@@ -458,23 +409,8 @@ def main(argv):
458 mode.add_argument('--update', action='store_true',
409 mode.add_argument('--update', action='store_true',
459 help="write suites' report arms to their expected "
410 help="write suites' report arms to their expected "
460 "files")
411 "files")
461− mode.add_argument('--copies', action='store_true',
462− help='only check tests/my-app-copies.txt')
463 opts = ap.parse_args(argv)
412 opts = ap.parse_args(argv)
464
413
465− if opts.copies or not (opts.suites or opts.shard or opts.list
466− or opts.report or opts.update
467− or os.path.realpath(opts.dir) != LIB_DIR):
468− pairs, problems = check_copies()
469− for p in problems:
470− print('FAILED my-app copy: %s' % p)
471− if opts.copies:
472− if not problems:
473− print('%d my-app copies match their sources' % pairs)
474− return 1 if problems else 0
475− if problems:
476− return 1
477−
478 global DESK
414 global DESK
479 try:
415 try:
480 if not os.path.isfile(opts.lib):
416 if not os.path.isfile(opts.lib):
tools/testdata/clay-fixtures-selftestdeleted−111
@@ -1,111 +0,0 @@
1−#!/usr/bin/env python3
2−"""Exercise Clay fixture scratch-desk cleanup without contacting a ship."""
3−
4−import json
5−import os
6−from pathlib import Path
7−import shutil
8−import subprocess
9−import sys
10−import tempfile
11−
12−
13−ROOT = Path(__file__).resolve().parents[2]
14−
15−# Both the normal and copied scratch `ship` are this fake. It emits the
16−# checked-in reports, records each operation, and injects one chosen failure.
17−FAKE_SHIP = r'''#!/usr/bin/env python3
18−import json, os, pathlib, signal, sys
19−here = pathlib.Path(__file__).resolve()
20−args = sys.argv[1:]
21−scratch = 'jibb-clay-tlon-' in str(here)
22−kind = ('scratch-sync' if scratch else 'normal-sync') if args[0] == 'sync' else pathlib.Path(args[1]).name
23−with open(os.environ['JIBB_CLAY_TEST_LOG'], 'a') as out:
24− out.write(json.dumps({'kind': kind, 'ship': str(here),
25− 'probe': (here.parents[1] / 'my-app/sur/mop-tlon-probe.hoon').exists()}) + '\n')
26−scenario = os.environ['JIBB_CLAY_TEST_SCENARIO']
27−if scratch and args[0] == 'sync':
28− assert (here.parents[1] / 'my-app/sur/mop-tlon-probe.hoon').read_bytes() == pathlib.Path(os.environ['JIBB_CLAY_TEST_NOTES']).read_bytes()
29− if scenario == 'sync-failure':
30− sys.exit(7)
31−if kind == 'tlon-mop.txt':
32− if scenario == 'thread-failure':
33− sys.exit(9)
34− if scenario in ('interrupt', 'interrupt-int'):
35− os.kill(os.getppid(), signal.SIGTERM if scenario == 'interrupt' else signal.SIGINT)
36− if scenario == 'mismatch':
37− sys.stdout.write('wrong report\n')
38− sys.exit(0)
39−if kind == 'normal-sync':
40− with open(os.environ['JIBB_CLAY_TEST_LOG']) as log:
41− n = sum(json.loads(line)['kind'] == 'normal-sync' for line in log)
42− if n == 2 and scenario == 'restore-failure':
43− sys.exit(11)
44− if n == 2 and scenario in ('restore-interrupt', 'restore-interrupt-int'):
45− os.kill(os.getppid(), signal.SIGTERM if scenario == 'restore-interrupt' else signal.SIGINT)
46−if args[0] == 'run':
47− name = pathlib.Path(args[1]).name
48− if name == 'import.hoon':
49− name = 'import.txt'
50− expected = 'expected.txt' if name == 'build.txt' else name.replace('.txt', '-expected.txt')
51− sys.stdout.buffer.write((pathlib.Path(os.environ['JIBB_CLAY_TEST_FIXTURES']) / expected).read_bytes())
52−'''
53−
54−
55−def exercise(scenario):
56− with tempfile.TemporaryDirectory(prefix='jibb-clay-selftest-') as tmp:
57− root = Path(tmp)
58− (root / 'tools').mkdir()
59− (root / 'my-app/sur').mkdir(parents=True)
60− (root / 'my-app/sur/keep.hoon').write_text('original\n')
61− shutil.copy2(ROOT / 'tools/clay-fixtures', root / 'tools/clay-fixtures')
62− shutil.copy2(ROOT / 'tools/golden_case.py', root / 'tools/golden_case.py')
63− fake = root / 'tools/ship'
64− # This Python, not /usr/bin/env's: a Nix build has no /usr/bin/env.
65− fake.write_text(FAKE_SHIP.replace('/usr/bin/env python3',
66− sys.executable, 1))
67− fake.chmod(0o755)
68− for name in ('vendor', 'jibb-dev', 'tests'):
69− (root / name).symlink_to(ROOT / name, target_is_directory=True)
70− log = root / 'calls.jsonl'
71− env = dict(os.environ, JIBB_CLAY_TEST_LOG=str(log),
72− JIBB_CLAY_TEST_SCENARIO=scenario,
73− JIBB_CLAY_TEST_FIXTURES=str(ROOT / 'tests/clay-fixtures'),
74− JIBB_CLAY_TEST_NOTES=str(ROOT / 'tests/golden/types-import-tlon-notes/sur/notes.txt'))
75− result = subprocess.run([sys.executable, str(root / 'tools/clay-fixtures')],
76− env=env, capture_output=True, text=True, timeout=30)
77− events = [json.loads(line) for line in log.read_text().splitlines()]
78− kinds = [e['kind'] for e in events]
79− assert kinds.count('scratch-sync') == 1, (scenario, kinds, result.stderr)
80− assert kinds.count('normal-sync') == 2, (scenario, kinds, result.stderr)
81− scratch = kinds.index('scratch-sync')
82− restore = [i for i, kind in enumerate(kinds) if kind == 'normal-sync'][1]
83− assert scratch < restore, (scenario, kinds)
84− assert events[scratch]['probe'] and not events[restore]['probe'], scenario
85− assert not Path(events[scratch]['ship']).exists(), scenario
86− assert (root / 'my-app/sur/keep.hoon').read_text() == 'original\n', scenario
87− assert not (root / 'my-app/sur/mop-tlon-probe.hoon').exists(), scenario
88− if scenario in ('success', 'restore-interrupt', 'restore-interrupt-int'):
89− assert result.returncode == 0, (scenario, result.stderr)
90− assert 'Clay Tlon named-mold mop importer golden passed' in result.stdout
91− assert 'mark-bridge.txt' in kinds
92− else:
93− assert result.returncode != 0, scenario
94− assert 'mark-bridge.txt' not in kinds
95− if scenario == 'sync-failure':
96− assert 'tlon-mop.txt' not in kinds
97− else:
98− assert scratch < kinds.index('tlon-mop.txt') < restore
99− print('ok ', scenario)
100−
101−
102−def main():
103− for scenario in ('success', 'sync-failure', 'thread-failure', 'mismatch',
104− 'interrupt', 'interrupt-int', 'restore-failure',
105− 'restore-interrupt', 'restore-interrupt-int'):
106− exercise(scenario)
107− print('PASS: 9 scratch-desk cleanup checks')
108−
109−
110−if __name__ == '__main__':
111− main()
tools/testdata/ship-selftest+10
@@ -469,6 +469,16 @@ def generator_checks(tmp):
469 linked not in normal.files and
469 linked not in normal.files and
470 '/my-app/ui/theme/jibb' in
470 '/my-app/ui/theme/jibb' in
471 normal.files['tests/lib/jibb.hoon'][0].decode())
471 normal.files['tests/lib/jibb.hoon'][0].decode())
472+ fixtures = ship.assemble('jibb-fixtures')
473+ check('jibb-fixtures is my-app plus tests/clay-fixtures/desk, '
474+ 'which only it holds',
475+ {'sur/import-fixture.hoon', 'sur/mop-tlon-probe.hoon',
476+ 'mar/label.hoon', 'sur/blog.hoon', 'lib/jibb-import.hoon'}
477+ <= set(fixtures.files) and
478+ 'desk.docket-0' not in fixtures.files and
479+ 'mar/label.hoon' not in ship.assemble('my-app').files and
480+ not any(p.startswith('tests/clay-fixtures/desk/')
481+ for p in normal.files))
472 for label, kwargs in (('custom library', {'lib': STUB}),
482 for label, kwargs in (('custom library', {'lib': STUB}),
473 ('custom goldens', {'golden': CASES}),
483 ('custom goldens', {'golden': CASES}),
474 ('both overrides', {'lib': STUB, 'golden': CASES})):
484 ('both overrides', {'lib': STUB, 'golden': CASES})):