on master help sign in
Move the importer-only fixtures to a jibb-fixtures desk

my-app, the example app, carried two files that only the importer's Clay fixtures build: sur/import-fixture.hoon, a /sur with a Ford import, and mar/label.hoon, a mark. The Tlon mop fixture went further: tools/clay-fixtures copied my-app into a scratch tree, added the Tlon notes /sur, synced that over the my-app desk and synced the real one back, which needed tools/testdata/clay-fixtures-selftest to check the restore under failures and signals. This is review question 34 (A113). - tests/clay-fixtures/desk holds the two files and sur/mop-tlon-probe.hoon, a link to the golden case's Tlon notes /sur. The new jibb-fixtures desk is my-app (without its docket) plus that folder; the jibb-dev desk leaves the folder out, so -test never builds them. - The Clay threads that build those files read jibb-fixtures. The tool syncs both desks first and runs each thread from one table; the scratch sync, its restore and their self-test are gone. tests/clay-fixtures/expected.txt is now build-expected.txt, like the other threads' files. - label.hoon loses its comment line, so the 15 golden mark fixtures and tests/type-poke/mark.txt, which copied it without that line, are now links to it. With no copies left, tests/my-app-copies.txt, the --copies option and the my-app-copies check are gone. The ship self-test checks what jibb-fixtures holds and that my-app and jibb-dev don't. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U4FzmSdubYxmZGDp2VJRAQ

commitd43c99be103d2989844541df7c2dc4ef6670f68a authorClaude <noreply@anthropic.com> dateTue 3 Nov 2026, 02:09 (9 hours ago) parent8125287
38 files changed+143−538
README.md+5−5 docs/development.md+3−4 docs/status.md+1−3 flake.nix+3−2 tests/clay-fixtures/expected.txt → tests/clay-fixtures/build-expected.txt my-app/mar/label.hoon → tests/clay-fixtures/desk/mar/label.hoon−1 my-app/sur/import-fixture.hoon → tests/clay-fixtures/desk/sur/import-fixture.hoon tests/clay-fixtures/desk/sur/mop-tlon-probe.hoon+1 tests/clay-fixtures/ford-import.txt+2−2 tests/clay-fixtures/ford-nested-union-bridge.txt+4−4 tests/clay-fixtures/ford-nested-union.txt+2−2 tests/clay-fixtures/ford-recursive.txt+2−2 tests/clay-fixtures/ford.txt+1−1 tests/clay-fixtures/mark-bridge.txt+3−3 tests/clay-fixtures/tlon-mop.txt+2−2 tests/golden/module-import-api-derived-clash/mar/full.txt+1−5 tests/golden/module-import-api-import-error/mar/full.txt+1−5 tests/golden/module-import-api-mark-prelude-value/mar/same.txt+1−5 tests/golden/module-import-api-mark-value/mar/full.txt+1−5 tests/golden/module-import-api-nested-path/mar/full.txt+1−5 tests/golden/module-import-api-paths-mark-value/mar/full.txt+1−5 tests/golden/module-import-api-paths-mark-value/mar/other.txt+1−5 tests/golden/module-import-api-paths-scope-conflict/mar/full.txt+1−5 tests/golden/module-import-api-poke-clash/mar/full.txt+1−5 tests/golden/module-import-api-request-reason/mar/full.txt+1−5 tests/golden/module-import-api-scope-conflict/mar/full.txt+1−5 tests/golden/module-import-root-import-shadow/mar/label.txt+1−5 tests/golden/types-import-mark/mar/label.txt+1−5 tests/golden/types-module-mixed/mar/label.txt+1−5 tests/golden/types-request-normal/mar/full.txt+1−5 tests/my-app-copies.txt−25 tests/type-poke/mark.txt+1−5 tools/check−2 tools/clay-fixtures+75−221 tools/ship+12−3 tools/test-arms+1−65 tools/testdata/clay-fixtures-selftest−111 tools/testdata/ship-selftest+10
README.md+5−5
@@ -10,7 +10,7 @@ Milestone 1 of the doc's eight, the parser and the `%jibb` mark, is done; milest
1010- `jibb/`: the `%jibb` desk, for the shared host (milestone 4).
1111- `my-app/`: an example app desk built from the doc's worked examples.
1212- `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.
1414- `tools/`: dev tooling: `golden`, `test-arms`, `hoon` and `doc-blocks`, with their self-test in `testdata/`, `ship`, and `check`, which runs every check.
1515- `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/`.
1616
@@ -19,13 +19,13 @@ Milestone 1 of the doc's eight, the parser and the `%jibb` mark, is done; milest
1919The 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:
2020
2121```
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
2323nix flake check # every check: the eval group and, on Linux, the ship group on a fresh fake ~zod
2424nix develop # a shell with urbit, python3 and click, for running the tools by hand
2525nix build .#fakezod # a freshly booted fake ~zod pier (Linux)
2626```
2727
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.
2929
3030`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)).
3131
@@ -90,7 +90,7 @@ Many suites share one eval, so the library is built once per eval, not once per
9090
9191A 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.
9292
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`.
9494
9595`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.
9696
@@ -141,7 +141,7 @@ A sync with nothing to commit takes about 2 s. A commit adds 3 to 10 s, and 300
141141
142142`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.
143143
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/`.
145145
146146For anything else:
147147
docs/development.md+3−4
@@ -73,13 +73,12 @@ git clone https://github.com/urbit/tools /root/src/tools
7373| `tools/check` | Runs every check in this table, or a group (`--group eval` or `ship`), or some by name: see [Before pushing](#before-pushing) |
7474| `tools/golden` | Runs the golden cases under `urbit eval`: every case, or those matching `--case`; `--update` rewrites the expected outputs; `--show` prints them |
7575| `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 |
7777| `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 |
7878| `tools/doc-blocks` | Checks the doc's `jibb` blocks against the `doc-*` golden cases: `tools/doc-blocks docs/spec` |
7979| `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` |
8080| `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 |
8181| `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 |
8382
8483`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.
8584
@@ -89,7 +88,7 @@ Each file in `tests/lib` is a suite: a core of `test-` arms, with the libraries
8988
9089A 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.
9190
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`.
9392
9493| Suite | What it checks | Golden files |
9594| --- | --- | --- |
@@ -162,7 +161,7 @@ tools/check --group eval # only the checks that need no ship, as CI runs the
162161nix flake check # the same checks in the Nix sandbox, on a fresh fake ~zod
163162```
164163
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.
166165
167166CI, [.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.
168167
docs/status.md+1−3
@@ -121,7 +121,7 @@ Besides the plan's list:
121121
122122- 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.
123123- 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.
125125- 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.
126126- 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).
127127
@@ -253,7 +253,6 @@ On a machine set up as [development.md](development.md) says:
253253tools/golden # 660 cases under urbit eval
254254tools/test-arms # the my-app copies, then every tests/lib suite under urbit eval
255255tools/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
257256tools/test-arms --report jibb-import # print a golden-report suite's report
258257tools/test-arms --update jibb-import # write it to the suite's expected file
259258tools/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
300299tools/ship start
301300tools/ship test # the same 660 cases, and every tests/lib suite, as -test arms on the ship
302301tools/testdata/ship-selftest
303−tools/testdata/clay-fixtures-selftest # scratch fixture cleanup without a ship
304302tools/ship check-commit # |commit stores .jibb files
305303tools/clay-fixtures # example /sur files and marks build through Clay
306304```
flake.nix+3−2
@@ -90,7 +90,8 @@
9090 '';
9191
9292 # 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
9495 # check phase compiles the two libraries under urbit eval.
9596 desks = pkgs.stdenvNoCC.mkDerivation {
9697 # No version in the name, so a commit that changes no desk
@@ -123,7 +124,7 @@
123124 # The files are the desks' as they are: nothing to patch.
124125 dontFixup = true;
125126 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";
127128 platforms = systems;
128129 };
129130 };
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.
21|_ a=@t
32++ grab |% ++ noun @t --
43++ 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 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(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)
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)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
66=/ cor=type -.src
77=/ typ=type (~(play ut cor) (ream '*sample'))
88=/ read-gate=vase (slap reader (ream 'read-mold-in'))
tests/clay-fixtures/ford-nested-union-bridge.txt+4−4
@@ -1,10 +1,10 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/import-fixture/hoon)
5−=/ blog=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/sur/blog/hoon)
6−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
7−=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb/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)]/jibb-fixtures/[(scot %da now)]/sur/blog/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)]/jibb-fixtures/[(scot %da now)]/lib/jibb/hoon)
88=/ read-gate=vase (slap reader (ream 'read-named'))
99=/ result=vase (slym read-gate [%import-fixture %nested -.src])
1010=/ sample-result=vase (slym read-gate [%import-fixture %sample -.src])
tests/clay-fixtures/ford-nested-union.txt+2−2
@@ -1,8 +1,8 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(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)
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)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
66=/ read-gate=vase (slap reader (ream 'read-named'))
77=/ got=vase (slym read-gate [%import-fixture %nested -.src])
88=/ show-gate=vase (slap reader (ream 'show-result'))
tests/clay-fixtures/ford-recursive.txt+2−2
@@ -1,8 +1,8 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(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)
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)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
66=/ read-gate=vase (slap reader (ream 'read-named'))
77=/ got=vase (slym read-gate [%import-fixture %recursive -.src])
88=/ show-gate=vase (slap reader (ream 'show-result'))
tests/clay-fixtures/ford.txt+1−1
@@ -1,7 +1,7 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ 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)
55=/ cor=type -.src
66?. ?=([%core *] cor) (pure:m !>('not a core'))
77=/ subject=type q.q.cor
tests/clay-fixtures/mark-bridge.txt+3−3
@@ -1,9 +1,9 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ mark=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/mar/label/hoon)
5−=/ reader=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb-import/hoon)
6−=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(scot %da now)]/lib/jibb/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)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
6+=/ jibb=vase .^(vase %ca /[(scot %p our.bowl)]/jibb-fixtures/[(scot %da now)]/lib/jibb/hoon)
77=/ read-gate=vase (slap reader (ream 'read-mark'))
88=/ label-result=vase (slym read-gate [%label -.mark])
99=/ check-gate=vase (slap jibb (ream 'golden-types-with-marks'))
tests/clay-fixtures/tlon-mop.txt+2−2
@@ -1,8 +1,8 @@
11=/ m (strand ,vase)
22;< =bowl:spider bind:m get-bowl
33=/ now=@da now.bowl
4−=/ src=vase .^(vase %ca /[(scot %p our.bowl)]/my-app/[(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)
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)]/jibb-fixtures/[(scot %da now)]/lib/jibb-import/hoon)
66=/ read-gate=vase (slap reader (ream 'read-named'))
77=/ result=vase (slym read-gate [%notes %log -.src])
88=/ 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 = [
7979 ['tools/test-arms', '--shard', '%d/%d' % (i, ARM_SHARDS)])
8080 for i in range(1, ARM_SHARDS + 1)
8181] + [
82− Check('my-app-copies', 'eval', ['tools/test-arms', '--copies']),
8382 Check('doc-blocks', 'eval', ['tools/doc-blocks', 'docs/spec']),
84− tool('testdata/clay-fixtures-selftest'),
8583 # The ship group. ship-selftest leaves its fixture files on the
8684 # jibb-dev desk, and ship-test, which syncs the desk to the repo
8785 # first, puts the real ones back, so it must come after.
tools/clay-fixtures+75−221
@@ -1,9 +1,16 @@
11#!/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+"""
312
413from pathlib import Path
5−import shutil
6−import signal
714import subprocess
815import sys
916import tempfile
@@ -11,228 +18,75 @@ import tempfile
1118root = Path(__file__).resolve().parent.parent
1219ship = root / 'tools' / 'ship'
1320fixtures = 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')
13321
134−try:
135− result = subprocess.run([str(ship), 'run', str(fixtures / 'ford-nested-union-bridge.txt')],
136− stdout=subprocess.PIPE, check=True)
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')
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))
73+ return subprocess.run([str(ship), 'run', str(thread)],
74+ stdout=subprocess.PIPE, check=True).stdout
14675
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')
15276
153−previous = signal.signal(signal.SIGTERM, stop_for_signal)
154−previous_int = signal.getsignal(signal.SIGINT)
15577try:
156− with tempfile.TemporaryDirectory(prefix='jibb-clay-tlon-') as tmp:
157− scratch = Path(tmp)
158− (scratch / 'tools').mkdir()
159− shutil.copy2(ship, scratch / 'tools/ship')
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()
172− if result.stdout != expected:
173− print('Clay Tlon mop import differs from tests/clay-fixtures/tlon-mop-expected.txt',
174− file=sys.stderr)
78+ for desk in ('my-app', 'jibb-fixtures'):
79+ subprocess.run([str(ship), 'sync', desk], check=True)
80+ with tempfile.TemporaryDirectory(prefix='jibb-clay-') as tmp:
81+ for name, differs, passed in FIXTURES:
82+ got = output(name, tmp)
83+ want = 'tests/clay-fixtures/%s-expected.txt' % name
84+ expected = (root / want).read_bytes()
85+ if got != expected:
86+ print('%s from %s' % (differs, want), file=sys.stderr)
17587 print('expected:', expected.decode().rstrip(), file=sys.stderr)
176− print('actual: ', result.stdout.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)
199−print('Clay mark subject golden 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)
88+ print('actual: ', got.decode().rstrip(), file=sys.stderr)
89+ sys.exit(1)
90+ print(passed)
23091except subprocess.CalledProcessError as error:
23192 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')
6161# order. Every desk gets every package under vendor/. A folder is
6262# (repo folder, desk folder, folders and files left out). The test
6363# 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.
6567DESKS = {
6668 'my-app': [('jibb-dev', '', ['tests']), ('my-app', '', [])],
6769 'jibb': [('jibb', '', [])],
68− 'jibb-dev': [('jibb-dev', '', []), ('tests', 'tests', []),
70+ 'jibb-dev': [('jibb-dev', '', []),
71+ ('tests', 'tests', [os.path.join('clay-fixtures', 'desk')]),
6972 ('my-app', 'my-app',
7073 ['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'), '', [])],
7177}
7278# The test desk has no sys.kelvin of its own; Clay refuses a commit
7379# without one, so it gets the %jibb desk's.
@@ -902,7 +908,7 @@ def assemble(desk, lib=None, golden=None):
902908 golden = golden or GOLDEN
903909 if os.path.isdir(os.path.join(ROOT, 'tests')):
904910 a.add_tree(os.path.join(ROOT, 'tests'), 'tests',
905− skip=['golden'], drop=lambda rel:
911+ skip=['golden'] + skip, drop=lambda rel:
906912 rel == os.path.join('lib', 'jibb.hoon') or
907913 (isolated and rel.startswith('lib' + os.sep) and
908914 rel.endswith('.hoon')))
@@ -2321,6 +2327,9 @@ EPILOG = """\
23212327desks:
23222328 my-app vendor/* + jibb-dev (without any tests/) + my-app
23232329 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
23242333 jibb-dev vendor/* + jibb-dev + tests + my-app (under /my-app, without
23252334 its desk files), the test desk: tests/golden from --golden,
23262335 less the case files that link to my-app, tests/lib/jibb.hoon
tools/test-arms+1−65
@@ -7,7 +7,6 @@
77 tools/test-arms --list the suites, their arms and reports
88 tools/test-arms --report jibb-poke-bridge
99 tools/test-arms --update jibb-poke-bridge
10− tools/test-arms --copies only the my-app copy check
1110
1211The ship runs the same arms with -test /=jibb-dev=/tests (tools/ship
1312test). 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.
2928Golden files, the /* %txt files bound to a face with "expected" in its
3029name, must end in exactly one newline (a wain can't show it) and hold no
3130line 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,
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).
31+That is checked before any eval.
3532
3633Exit status: 0 when every arm passes, 1 when one fails, 2 on a usage
3734error.
@@ -56,7 +53,6 @@ from noun import atom_to_bytes, to_list # noqa: E402
5653
5754ROOT = os.path.dirname(TOOLS)
5855LIB_DIR = os.path.join(ROOT, 'tests', 'lib')
59−COPIES = os.path.join(ROOT, 'tests', 'my-app-copies.txt')
6056GENERATED = 'jibb' # tests/lib/jibb.hoon, from tools/ship gen-tests
6157LIBRARY = 'jibb' # /+ jibb: the library under test, --lib
6258
@@ -177,51 +173,6 @@ def lib_source(desk, name):
177173 raise Unusable('no /lib/%s.hoon on the jibb-dev desk' % name)
178174
179175
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−
225176def golden_problems(text):
226177 """What is wrong with a golden file's or report's bytes, or None."""
227178 if not text.endswith(b'\n') or text.endswith(b'\n\n'):
@@ -458,23 +409,8 @@ def main(argv):
458409 mode.add_argument('--update', action='store_true',
459410 help="write suites' report arms to their expected "
460411 "files")
461− mode.add_argument('--copies', action='store_true',
462− help='only check tests/my-app-copies.txt')
463412 opts = ap.parse_args(argv)
464413
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−
478414 global DESK
479415 try:
480416 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):
469469 linked not in normal.files and
470470 '/my-app/ui/theme/jibb' in
471471 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))
472482 for label, kwargs in (('custom library', {'lib': STUB}),
473483 ('custom goldens', {'golden': CASES}),
474484 ('both overrides', {'lib': STUB, 'golden': CASES})):