test: load test workspaces into the compiler instead of copying them - #561
Merged
Conversation
Add `init2`, which hands every `.flix` file of a test workspace directory to the compiler by URI and content, instead of copying the directory into the active workspace. The files are compiled where they live in `testWorkspaces`, so nothing changes on disk and no file-system watcher is involved — the delete/copy/settle dance of `init` is skipped entirely. This is backed by two test-only commands, `flix.addUri` and `flix.remUri`, alongside the existing `flix.checkCount` and `flix.allJobsFinished`. `handleAddUri` now forwards an optional `src`, which the compiler uses instead of reading the file from disk, as `updateUri` already did for unsaved changes. Since no watcher will ever report these files as gone, a suite has to clean up after itself: `teardown2` blanks the content the compiler holds for them. `codeActions` is the first suite converted; the rest still use `init`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Convert the remaining suites to `init2`/`teardown2`, so that only `files.test.ts` — which is about file-system manipulation — still copies a workspace into place. A full run drops from ~2 minutes to ~21 seconds. Most suites only needed their URIs pointed at `testWorkspaces` and a teardown added. Two did not: - `completions` creates its file and types into it, so `src/Temp.flix` stays a real file in the active workspace; saving into the fixture directory would modify a tracked file. It is deleted again in the teardown. - `diagnostics` no longer copies `latent/X.flix` into `src/`. It loads each latent fixture where it lies with `loadFile`, and blanks it again after the test. Clearing content is now done with `blankFile` rather than an editor edit, which reaches the compiler as the same `api/addUri` job carrying `src`. Fix an ordering bug in `init2` found by this: on the first suite the compiler is not connected yet, so the initial workspace scan is enqueued once the socket opens — after the removals `init2` had already sent, silently re-adding the previous suite's files. It now waits for the check that scan triggers, but only when the extension was not already active and the scan found files, which is exactly when that check is guaranteed. Remove `copyFile` and `replaceDocumentContent`, which no test uses anymore. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Now that a test workspace is loaded by URI and content rather than copied into place, it no longer has to look like a Flix project: `codeActions` is simply `Main.flix` and `Date.flix`. Drop the `src` directory and the `flix.toml` of every directory loaded by `init2` — nothing reads the manifest, as the compiler is handed the files directly and `ensureFlixExists` resolves `flix.jar` without it. `files` keeps its layout, since `init` still copies it into the active workspace, where the extension discovers it by glob. `init2` correspondingly loads the `.flix` files *directly in* the directory. Subdirectories are now what marks a fixture as dormant, so `diagnostics/latent` keeps working as before, and `findFixtureFiles` loses its recursion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Parked in 094c374 to work around a compiler crash on associated effect types (flix/flix#8326), for a `test.skip`ped implementation test which 878f74e has since removed. Nothing references it, and neither the extension's glob nor `init2` ever loaded it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… ones Four of the six error fixtures can be part of the same program, so `init2` now loads them like every other suite and the tests are plain assertions on the resulting diagnostics. The other two cannot: a duplicate formal parameter (`WeederError.flix`) or a cycle among type aliases (`ResolutionError.flix`) stops the compiler from reporting the errors of the other files. Loading all six together leaves only the weeder error, and holding back just the weeder error leaves the type, redundancy and safety errors unreported. Those two therefore stay in `latent` and are loaded for the duration of their own test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ResolutionError.flix` used a cycle among type aliases, which suppresses the errors of every other file, so it had to be loaded on its own. An undefined name — the most common resolution error, per TestResolver.scala — does not suppress anything, so it now joins the files `init2` loads, and `latent` holds only the weeder fixture. Weeder errors block regardless of which one is used: a non-linear pattern (TestWeeder.scala) suppresses the other files exactly as the duplicate formal parameter does, so that fixture stays as it was. Rewrite `RedundancyError.flix`, which called the long-gone `Files.readLines` and so reported an undefined name and two type errors on top of the shadowing it is meant to test. It now reports exactly the two shadowing errors. Delete `latent/UnusedFunction.flix`: it no longer parses, and an unused definition is not reported at all in LSP mode — no fixture can test it — which is why no test ever referenced it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A weeder error suppresses the errors of every other file, so `WeederError.flix` could never be part of the program the other tests assert on. Dropping it costs the coverage of that one error class and buys a uniform suite: every diagnostics fixture is now loaded by `init2` like every other test workspace, and the tests are plain assertions with no loading, no blanking and no `latent` directory. Subdirectories are still skipped by `init2`, so a fixture that must stay out of the program can be put in one and loaded with `loadFile`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A file is created before it is deleted, and the codebase names the pair that way round throughout: `api/addUri` / `api/remUri`, `flix.addUri` / `flix.remUri`, `addFile` / `deleteFile`. The tests stay grouped by artifact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`normalizeLocation` and `normalizeUri` lost their last caller when 878f74e removed the ignored implementation tests. `sleep` and `copyDirContents` are only used inside util, so they no longer need to be exported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`files.test.ts` was the only caller of `init`, and carried 138 lines of util with it: clearing the active workspace, copying a whole directory into it, and `settleAfterChange`, whose 500ms quiescence loop existed to cover the debounced reconciliation a folder-level create or delete can trigger. The suite only ever mutates two artifacts, so it now loads `Main.flix` and `Assert.flix` in place like every other suite, and owns `src/Area.flix` and `lib/circleArea.fpkg` itself: they are recreated from the fixture's `workspace` directory before each test and deleted when the suite ends. The `workspace` directory mirrors the paths they are copied to, and is skipped by `init2` for being a subdirectory. The active workspace is therefore empty before and after the run, and `test/testWorkspaces` no longer holds a `flix.toml` at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…piler Every suite now cleans up after itself, so the active workspace is only dirty when a run was interrupted. `init2` therefore no longer makes the compiler forget the files it finds there — it deletes them, and does so before `ext.activate()`, while no file-system watcher exists to report them. That removes the race the removal had to work around: the workspace scan is enqueued when the compiler connects, which happens after `activate()` returns, so anything sent before that could be undone by it. The special case for the first suite goes with it. `flix.remUri` has no callers left, so drop it from the extension. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`init2`, `teardown2`, `loadFile` and `blankFile` counted `lsp/check` responses to be sure the compiler had reacted. That is only necessary when the extension hears about a change through a file-system watcher, which fires at a time of its own choosing. These four hand the file to the compiler directly, and the notification that does so travels the same ordered connection as the one `flix.allJobsFinished` sends. The server enqueues the job as it handles the first notification, so by the time it handles the second the queue is not empty, and waiting for idle covers the file — including the check the compiler runs once the queue drains. Verified over three consecutive full runs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The provider commands resolve the document from the URI they are given, and `init2` already opens every fixture document, so showing an editor bought nothing in five suites. It did have an effect, though: making a file outside the workspace the active editor is what triggered the extension's warning that the file is not part of the project, once per opened fixture. Only the completion test needs an editor, since typing goes to the active one, so `open` moves to its single call site. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The suite created `src/Temp.flix` in the active workspace, typed into it and saved, because saving was the only way to leave a clean editor behind for the next suite. It does not need a file of its own: the extension sends the compiler the content of the editor, so the typed text reaches it whether or not the document is saved. It now types into an empty fixture loaded by `init2` like any other, and reverts the buffer when the suite ends — which both leaves the fixture untouched on disk and closes the editor without a save prompt. `typeText` no longer saves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`addFile`, `deleteFile`, `tryDeleteFile` and the active-workspace URI helper are only used by the file manipulation suite, now that the completion test types into an unsaved fixture buffer instead of creating a file of its own. They live in that suite, below its tests, ordered from the ones the tests call down to the primitives those are built on. `util.ts` exports `awaitCheck` and `getFileUri` in their place: `awaitCheck` is still shared, since `typeText` needs it for the same reason — an editor reports a change when it sees fit, so the compiler has to be observed reacting to it. The active-workspace helper is renamed `getWorkspaceDocUri`, which says what distinguishes it from `getFixtureDocUri` now that the two sit side by side. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The names were taken by the copy-based setup, which no longer exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Test workspaces are no longer copied into
test/activeWorkspacebefore each suite. Every suite now hands its.flixfiles to the compiler by URI and content, so they are compiled where they live intest/testWorkspaces, and blanks them again when it finishes. Nothing is written to disk, so no file-system watcher is involved and there is nothing to clean up.A full run goes from ~2 minutes to ~18 seconds.
Extension changes
flix.addUri, alongside the existingflix.checkCountandflix.allJobsFinished.handleAddUriforwards an optionalsrc, which the compiler uses instead of reading the file from disk — the same inline-source pathupdateUrialready used for unsaved editor changes. Withoutsrc, behaviour is unchanged.Test changes
init(name)/teardown(name)replace the copy-based setup. The oldinitand its 138 lines of supporting code — clearing the workspace, copying a directory into it, and a 500ms quiescence loop covering debounced reconciliation — are gone.flix.toml, nosrc/.test/testWorkspaces/codeActions/is simplyMain.flixandDate.flix. Files in a subdirectory are not loaded, which is how a fixture opts out of being part of the program.files.test.tsis the only suite that still touches the file system, since it exists to test that the extension notices files appearing and disappearing. It owns those helpers itself now, and creates and deletes the two artifacts it mutates.test/activeWorkspaceis empty before and after a run, and is cleaned before the extension starts if a previous run was interrupted.test/src/util.ts: 518 → 305 lines.