test: prove canonical directory test products
This commit is contained in:
@@ -2829,7 +2829,8 @@ and every component of the canonical import path. A selected command directory
|
||||
declares `package main` while retaining its complete canonical import identity.
|
||||
A source import of a command package from a
|
||||
different directory is rejected; the one same-directory exception is an
|
||||
external `main_test` variant's canonical import of its production action. Two
|
||||
external `main_test` variant's canonical import of its effective augmented
|
||||
test action. Two
|
||||
ordinary logical identities for one physical directory are rejected rather
|
||||
than compiled twice; section 11.16 records the deliberate exception for
|
||||
distinct expanded vendor routes that converge through symlinks.
|
||||
@@ -2948,54 +2949,57 @@ supported manifest-free forms include `ww build DIR...`, `ww build DIR/...`,
|
||||
`ww test DIR...`, and `ww test DIR/...`, with overlapping direct and recursive
|
||||
roots. Test retains its existing `-run`, `-filter`, `-list`, `-timeout-ms`,
|
||||
`-j`, `-c`, and `-w` forms. `ww test -c -o test.bin DIR` names the result when
|
||||
the selected directory has one test variant; the coordinator rejects one output
|
||||
name for a multi-variant or recursive test request. Explicit `ww test FILE`
|
||||
retains its compatibility path.
|
||||
the request selects one canonical directory, including a directory with both
|
||||
same-package and external-package test sources. The coordinator rejects one
|
||||
output name only when it would fan out over multiple directory products.
|
||||
Explicit `ww test FILE` retains its compatibility path.
|
||||
|
||||
The test coordinator still discovers requested directories, enumerates the
|
||||
test package names, selects variants, executes independent binaries, and emits
|
||||
captured results in byte-sorted package order. It no longer concatenates a
|
||||
The test coordinator still discovers requested directories, classifies the
|
||||
selected test package names, executes one binary per test-bearing canonical
|
||||
directory, and emits captured results in byte-sorted directory order. It no
|
||||
longer concatenates a
|
||||
generated production/test root, resolves imports, or starts one package graph
|
||||
per binary or directory. Instead it sends one ordered build request containing
|
||||
every selected directory/variant root to the Cstage or WWstage command. Its
|
||||
semantic selections are only the directory and selected variant/package
|
||||
identities; it also carries output destinations, coordinator-private completion
|
||||
paths, import search roots, and the optional command-scoped work-directory
|
||||
policy. The command owns source selection, package loading, compiler inputs,
|
||||
archive construction, generated-main construction, and linking for every
|
||||
package variant:
|
||||
per declared test package. Instead it sends one ordered build request containing
|
||||
one product descriptor per selected directory, with optional production,
|
||||
same-package, and external-package selectors, to the Cstage or WWstage command.
|
||||
It also carries output destinations, coordinator-private completion paths,
|
||||
import search roots, and the optional command-scoped work-directory policy.
|
||||
The command owns source selection, package loading, substitution, compiler
|
||||
inputs, archive construction, the single generated main, and linking:
|
||||
|
||||
- The ordinary production action selects the directory's byte-sorted non-test
|
||||
files. A no-test requested product uses this action directly, and every
|
||||
ordinary, internal-test, or external-test import of that package reuses it.
|
||||
files. A no-test request uses this action directly. Ordinary builds and
|
||||
dependencies outside a tested closure continue to use it.
|
||||
- The internal production-plus-test variant selects the byte-sorted production
|
||||
files followed by byte-sorted matching `package p` test files. It is distinct
|
||||
from production so its private production declarations and test declarations
|
||||
remain isolated to that test product.
|
||||
from production, exports declarations contributed by internal test files, and
|
||||
replaces the ordinary action throughout the applicable tested closure.
|
||||
- When production sources establish `p`, the external variant selects only
|
||||
matching `package p_test` files, where `p` is the production declaration
|
||||
rather than an import-path leaf. A test-only directory may establish its own
|
||||
one consistent test package name, matching pinned `go/build` classification.
|
||||
A real source import of the production package uses its canonical import
|
||||
path and is a direct edge to the same ordinary production action used by
|
||||
ordinary products and transitive imports; there is no external-production
|
||||
role or artifact.
|
||||
`p`, `p_test`, or valid `p`/`p_test` pair, matching pinned `go/build`
|
||||
classification. The external action's import of the package under test binds
|
||||
to the augmented internal action when it exists. Importers affected by that
|
||||
replacement are copied and rewired transitively; an ordinary and augmented
|
||||
instance of one canonical package never coexist in the linked test closure.
|
||||
- Generated main is a separate package action whose owner-only generated unit
|
||||
declares `package main` and imports exactly the selected variant and test
|
||||
support. It consumes those direct `.wwi` files, emits its own `.wwi/.o/.a`,
|
||||
and alone receives compiler `-T --entry`. Its target edge also receives the
|
||||
compiler-private `--test-target-package <canonical-path>` binding. That
|
||||
private canonical-path qualifier prevents a tested command declared `main`
|
||||
from colliding with generated main; it is not user alias syntax.
|
||||
declares `package main` and imports every applicable internal/external target
|
||||
plus test support. It consumes those direct `.wwi` files, emits its own
|
||||
`.wwi/.o/.a`, and alone receives compiler `-T --entry`. Repeated byte-sorted
|
||||
`--test-target-package <canonical-path>` arguments identify the target set.
|
||||
Those compiler-private canonical qualifiers prevent declared-name collisions;
|
||||
they are not user alias syntax.
|
||||
|
||||
The authoritative directory-action identity is the triple **(canonical
|
||||
filesystem directory, canonical ordinary import path, semantic variant)**.
|
||||
The semantic variants are production, internal production-plus-test, and
|
||||
external `_test`; generated main and the reserved test-support alias are
|
||||
explicit non-directory action classes. The declared package name is stored
|
||||
separately and is not part of canonical directory/path interning. Requested-root
|
||||
state, discovery role, product ordinal, output path, persistent artifact key,
|
||||
and discovery order never enter the triple.
|
||||
The coordinator groups one test product by canonical directory, but physical
|
||||
location is not a compiler/package identity. The authoritative action key uses
|
||||
the finalized canonical dotted import identity, semantic variant, role, and,
|
||||
for a copy made by recompile-for-test, the owning canonical directory product's
|
||||
stable test identity. The semantic variants are production,
|
||||
production-plus-same-package-test, external `_test`, directory generated main,
|
||||
and recompiled-for-test. The declared package name, local import binding,
|
||||
request spelling, path leaf, source filename, artifact basename, product
|
||||
ordinal, output path, and discovery order are presentation or source-location
|
||||
state and never substitute for that key.
|
||||
|
||||
A literal directory root may enter the interner before its full import spelling
|
||||
is known. It is provisionally interned by canonical directory and variant, and
|
||||
@@ -3059,19 +3063,19 @@ introduces a package registry.
|
||||
|
||||
Artifact publication follows the semantic action instead of product order:
|
||||
production uses the full finalized ordinary identity, internal appends
|
||||
`-internal-test`, external appends `_test-external-test`, and their generated
|
||||
mains append `-main`. Generated package identities are likewise derived from
|
||||
the full variant identity, for example `__wwtestmain.a.foo.internal.main` and
|
||||
`__wwtestmain.b.foo_test.external.main`. Equivalent products therefore reuse an
|
||||
already-interned directory action and generated-main action and publish through
|
||||
the same persistent-workdir slots regardless of discovery or product order.
|
||||
`-internal-test`, external appends `_test-external-test`, and the one
|
||||
directory-owned generated main appends `-test-main`. Its package identity is
|
||||
`__wwtestmain.<canonical-directory-product-base>.main`, independent of either
|
||||
declared test name. Equivalent roots therefore converge on one directory
|
||||
product and reuse already interned actions and persistent-workdir slots
|
||||
regardless of discovery or request order.
|
||||
The narrow raw single-file compatibility path alone retains `__root`.
|
||||
|
||||
A deterministic dependency-first traversal of the complete command union
|
||||
invokes the compiler, assembler, and in-driver deterministic archiver once per
|
||||
interned action. This is compile-time interning, not linker-argument
|
||||
deduplication. Each product is then linked separately from its generated-main
|
||||
or executable root archive and the complete reachable archive closure. The
|
||||
deduplication. Each canonical directory product is linked once from its single
|
||||
generated-main root archive and the complete reachable archive closure. The
|
||||
shared plan remains package-test-specific; it is not a generalized scheduler,
|
||||
action schema, cache, or protocol.
|
||||
|
||||
@@ -3095,15 +3099,19 @@ a rejected union build. After one successful union build, the completed test
|
||||
products share the coordinator's existing `-j` process bound; captured output
|
||||
is still emitted only in byte-sorted directory/package order.
|
||||
|
||||
Every source-imported dependency is a production variant, so dependency
|
||||
`*_test.ww` files never enter the graph. Imports that occur only in selected
|
||||
test files add edges only to that internal or external variant. Each compiler
|
||||
unit contains only its action's owned source set, while its invocation receives
|
||||
only the byte-sorted direct dependency `.wwi` artifacts as separate inputs.
|
||||
Ordinary production loading never selects dependency `*_test.ww` files.
|
||||
Imports that occur only in selected test files add edges only to the applicable
|
||||
internal or external action. Recompile-for-test may create a product-scoped copy
|
||||
of an ordinary transitive importer, but that copy retains the importer's
|
||||
production source unit and changes only canonical dependency targets. Each
|
||||
compiler unit contains only its action's owned source set, while its invocation
|
||||
receives only the byte-sorted direct dependency `.wwi` artifacts as separate
|
||||
inputs.
|
||||
Variant compiles receive `--test-package`, which validates and retains private
|
||||
`@test` declarations as compiler-only export metadata without synthesizing an
|
||||
entry point. The distinct generated-main action consumes that metadata from its
|
||||
direct variant export and synthesizes the dispatcher with `-T`.
|
||||
entry point. The distinct directory generated-main action consumes that
|
||||
metadata from every direct target export and synthesizes one dispatcher with
|
||||
`-T`.
|
||||
|
||||
The generated-main action, rather than the tested variant, owns the implicit
|
||||
direct test-runtime support edge. The command-scoped plan compiles the common
|
||||
@@ -3125,22 +3133,23 @@ coexist only because the former is explicitly rebound to the compiler-only
|
||||
qualifier `__wwtest`. This is the sole role-based directory alias and cannot be
|
||||
created by a source import. The separate expanded-vendor-route exception in
|
||||
section 11.16 is canonical source-tree identity, not a role alias. All ordinary
|
||||
production actions, including an external test's colocated production
|
||||
dependency, use canonical directory identity and the global bidirectional
|
||||
import-path checks above. There is no role-based tolerance for duplicate
|
||||
ordinary import identities and no late product-closure ambiguity to resolve.
|
||||
and test actions use canonical action identity and the global bidirectional
|
||||
import-path checks above. External self-import substitution changes the target
|
||||
action, never the source spelling or file-local binding. There is no role-based
|
||||
tolerance for duplicate ordinary import identities and no late product-closure
|
||||
ambiguity to resolve.
|
||||
|
||||
The selected internal/external variants and a production action reached by
|
||||
their imports or test-runtime closure are the sanctioned graph nodes that may
|
||||
share a physical directory. This also lets a toolchain package's own tests
|
||||
coexist with the production action required by the test runtime. An internal
|
||||
variant already defines those production symbols, so the colocated production
|
||||
archive is omitted from that product's final link while the production action's
|
||||
dependency archives remain in the closure. The external product includes the
|
||||
production archive. Variant-only archives are never linked into another
|
||||
product. All ordinary logical and physical package-identity collision checks
|
||||
remain unchanged; only distinct expanded vendor routes receive the section
|
||||
11.16 symlink-convergence exception.
|
||||
Production, internal, and external actions may select source from one physical
|
||||
directory, but the final directory test closure is strict: wherever the
|
||||
augmented internal action substitutes for production, every affected direct and
|
||||
transitive edge is rewired before tools. A closure containing both ordinary
|
||||
`p` and its augmented `ptest` is rejected rather than hidden by initialization
|
||||
or linker filtering. The external action therefore sees internal-test exports
|
||||
through `ptest`, and the one linked process owns exactly one package state.
|
||||
Variant-only archives never leak into an unrelated directory product. All
|
||||
ordinary logical and physical package-identity collision checks remain
|
||||
unchanged; only distinct expanded vendor routes receive the section 11.16
|
||||
symlink-convergence exception.
|
||||
|
||||
Both stage linkers receive the generated-main archive first, followed by the
|
||||
complete reverse-topological reachable package-archive closure, runtime, and
|
||||
@@ -3155,10 +3164,13 @@ one stable escape of the canonical discovery directory names the persistent
|
||||
command work directory. It contains neither a declared package leaf nor a
|
||||
product ordinal, so equivalent path spellings and reordered products select the
|
||||
same request state.
|
||||
Every `*_test.ww` package variant is built even when a file only
|
||||
declares helpers and contains no `@test`, so its package clause and imports are
|
||||
still checked by the shared loader. Every built variant is run, and a successful
|
||||
compiler-owned dispatcher with empty output is reported as `[no tests]`.
|
||||
Every selected `*_test.ww` package variant is built even when its files only
|
||||
declare helpers and contain no `@test`, so its package clause and imports are
|
||||
still checked; that is a real zero-test package and runs one empty combined
|
||||
harness. A directory with no selected test files instead follows the no-real-run
|
||||
path: validate/compile ordinary production as needed, publish status only, and
|
||||
create no support action, generated main, link, binary, result, or process. The
|
||||
coordinator alone emits its `[no tests]` report.
|
||||
|
||||
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
|
||||
per-action committed units. When that global identity is stale, the command
|
||||
@@ -3175,12 +3187,9 @@ stops as soon as a regenerated importer export is byte-identical. Stable
|
||||
semantic artifact keys make that behavior independent of which ordinary or
|
||||
test product first discovered the action.
|
||||
|
||||
This ownership split follows the pinned Go 1.26.5 implementation cited in
|
||||
section 11.12: its loader reuses canonical cached package objects, its work
|
||||
builder interns actions by mode and package, and its test loader reuses ordinary
|
||||
production while constructing only the required internal, external, and
|
||||
generated-main variants. WW borrows that command-global ownership boundary
|
||||
without adding Go's build cache, import configuration format, or module system.
|
||||
The completed topology and its pinned Go 1.26.5 evidence are specified in
|
||||
section 11.22. WW borrows that command-global action boundary without adding
|
||||
Go's build cache, import-configuration format, or module system.
|
||||
|
||||
### 11.8 Implemented exact package-tool invocation slice
|
||||
|
||||
@@ -3389,7 +3398,8 @@ imports use their explicit compiler-owned bindings. Executable linking
|
||||
independently walks the full reachable package
|
||||
closure and passes archives, never interfaces. The same path handles an
|
||||
ordinary package, the production-plus-internal-test variant, the external test
|
||||
package and its reused production package, compiler-generated test main, and
|
||||
package and its effective production-or-augmented self dependency,
|
||||
compiler-generated directory test main, and
|
||||
the reserved test-support package. Persistent workdirs compare a newly emitted
|
||||
export with its committed predecessor before allowing a direct importer to
|
||||
reuse owner-identical artifacts, retaining correctness without a new cache
|
||||
@@ -3411,8 +3421,9 @@ its non-`main` canonical identity in the unit, export, archive, compiler argv,
|
||||
and linker argv; the bootstrap self-rebuild independently proves the same rule
|
||||
for the real `w6a` and `w6l` command directories. A focused command-test row
|
||||
proves distinct production, internal, external, and generated-main actions,
|
||||
colocated external-production reuse, parser-only command markers, stage-equal
|
||||
unit/export/archive bytes, both test binaries' runtime behavior, and pre-tool
|
||||
colocated external-to-augmented substitution, parser-only command markers,
|
||||
stage-equal unit/export/archive bytes, the one combined test binary's runtime
|
||||
behavior, and pre-tool
|
||||
rejection when another directory tries to import the command.
|
||||
|
||||
The exact-argv regression uses the real diamond
|
||||
@@ -3424,9 +3435,9 @@ and byte-identical units, exports, archives, executables, and tool argument
|
||||
vectors across two clean
|
||||
Cstage builds and two clean WWstage builds. The existing directory-package
|
||||
variant regression checks separate production, internal, external, and
|
||||
generated-main actions, exact generated-main direct variant/support exports,
|
||||
canonical production reuse across ordinary and test products, and archive-only
|
||||
link closures. It also reverses equivalent product descriptors and compares
|
||||
directory-generated-main actions, exact generated-main direct target/support
|
||||
exports, canonical recompile-for-test substitution, and one archive-only link
|
||||
closure. It also reverses equivalent product descriptors and compares
|
||||
exact compiler and linker trace bytes, then changes a shared direct export in
|
||||
persistent workdirs to prove propagation through direct importers stops at the
|
||||
first byte-identical regenerated export. Both stages compile and run those
|
||||
@@ -3662,8 +3673,9 @@ direct sorted/deduplicated `.wwi` compiler inputs, long mangled assembler
|
||||
symbols, complete archive-only link closures, runtime results, and independent
|
||||
Cstage/WWstage artifact bytes. Two deep outside-root directories declaring
|
||||
the same leaf coexist under distinct reversible identities. A long command
|
||||
package and its production, internal, external, and two generated-main actions
|
||||
remain distinct. Logical and literal roots, dependency-first and root-first
|
||||
package's internal, external, and one directory generated-main actions remain
|
||||
distinct while retaining its canonical package identity. Logical and literal
|
||||
roots, dependency-first and root-first
|
||||
discovery, equivalent and symlink spellings, reordered products, and warm
|
||||
requests reuse the same production action and persistent slot. The persistent
|
||||
diamond observer also changes a shared dependency export, proves rebuilding of
|
||||
@@ -3757,7 +3769,7 @@ lazily zero-extended `contextstate: []u8`.
|
||||
Products, load frames, and topological frames use typed dynamically allocated
|
||||
slices. `internal/wwpackage` continues to construct one union command for all
|
||||
selected directory-test groups, but now checks the complete
|
||||
`12 + 6*products + 2*includes` builder argument count before allocating or
|
||||
`12 + 9*products + 2*includes` builder argument count before allocating or
|
||||
starting the driver.
|
||||
|
||||
All graph and product growth starts at capacity 8 and doubles until it covers
|
||||
@@ -3819,30 +3831,26 @@ byte-identical export. Closing the chain at `p299 -> p000` produces the complete
|
||||
stage-identical 300-node cycle diagnostic with empty compiler, assembler, and
|
||||
linker traces.
|
||||
|
||||
`dynamic_package_universe_crosses_former_boundary` first selects 309 package-test
|
||||
products through 257 directory spellings in one direct request per stage.
|
||||
Fifty-two real directories each produce ordinary production, internal
|
||||
production-plus-test, external `_test`, and two generated-main actions; the
|
||||
shared support closure brings that command-global universe to 270 actions. Two
|
||||
hundred five explicit symlink spellings of `p000` add distinct valid products
|
||||
and resolution contexts while reusing its one canonical internal action. The
|
||||
observer reverses product and variant order between stages, proves one compile
|
||||
per action, checks all 309 binaries exist, runs boundary products, validates
|
||||
variant-owned units, and compares every action artifact plus representative
|
||||
binaries byte-for-byte.
|
||||
`dynamic_package_universe_crosses_former_boundary` selects 257 canonical
|
||||
directory products in one direct request per stage. Fifty-two directories have
|
||||
combined same/external tests and each produces `ptest`, `pxtest`, and one
|
||||
directory `pmain`; 205 production-only directories take the no-test path. The
|
||||
shared support closure brings the command-global universe to exactly 370
|
||||
compile actions and 422 assembler invocations, with 52 generated dispatchers,
|
||||
links, binaries, and results. The 205 no-test products have only ordinary
|
||||
production actions and statuses: no support-owned target, main, link, binary,
|
||||
or result. The observer reverses all directory descriptors between stages,
|
||||
proves one compile per action, runs a boundary combined binary, validates
|
||||
variant-owned units and external self substitution, and compares representative
|
||||
action artifacts, normalized traces, and binaries byte-for-byte.
|
||||
|
||||
The same observer then exercises the public `ww test <tree>/...` coordinator
|
||||
path. The generated tree has 257 real directories: the 52 test-bearing
|
||||
directories above plus 205 production-only directories. The coordinator forms
|
||||
and passes 309 products and 258 contexts (including support) in one driver
|
||||
request. Reusing the direct request's persistent semantic-action store preserves all 270
|
||||
existing actions and adds exactly 410 production/generated-main actions, for 680
|
||||
distinct actions. Both stages run every product, produce byte-identical ordered
|
||||
coordinator output and all 680 action artifacts, and perform no compilation on a
|
||||
second equivalent public request. It checks all 104 test-bearing result labels
|
||||
and all 205 no-test result labels, while a builder-boundary observer records
|
||||
exactly one invocation containing all 309 descriptors for each cold and warm
|
||||
public request. Existing focused observers continue to prove
|
||||
The same observer exercises the public `ww test <tree>/...` coordinator path
|
||||
against that persistent action store. The coordinator passes exactly 257
|
||||
directory descriptors in one driver request, prints 52 combined `ok` reports
|
||||
and 205 no-test `?` reports, and performs no new compilation. An unchanged warm
|
||||
request again invokes no compiler or assembler; the 52 real products follow the
|
||||
existing explicit-output relink convention while no-test products still create
|
||||
no linker work. Existing focused observers continue to prove
|
||||
dependency-first/root-first canonical reuse, root-only/combined artifact
|
||||
identity, exact reordered-product trace bytes, and request-shape-independent
|
||||
persistent action reuse.
|
||||
@@ -4351,8 +4359,9 @@ selected test-only directory remains an unusable build root and fails. Build
|
||||
creates one production product per remaining directory. Test retains test-only
|
||||
directories and, after selection, constructs the already specified isolated
|
||||
production/no-test, internal production-plus-test, external `_test`, support,
|
||||
and generated-main actions. Pattern expansion does not create those variants
|
||||
and cannot make one variant visible to another.
|
||||
recompiled-for-test, and one directory-generated-main action. Pattern expansion
|
||||
does not create those actions; graph-owned substitution alone makes the
|
||||
augmented package visible through applicable external and transitive edges.
|
||||
|
||||
Vendor selection remains distinct from vendor import resolution. Selecting a
|
||||
directory below `vendor`, literally or through an explicitly vendor-rooted
|
||||
@@ -4592,14 +4601,14 @@ directory may establish one consistent package name from its test files, as in
|
||||
pinned `go/build`. External action identity remains the canonical production
|
||||
identity plus the existing external variant suffix where that production
|
||||
exists. Imports found only in internal or external test files belong only to
|
||||
that variant. Support and generated-main actions retain their isolated
|
||||
that action. Support and the directory generated-main retain isolated action
|
||||
identities and archive closures. A generated dispatcher privately binds its
|
||||
tested target through
|
||||
`--test-target-package <canonical-path>` so a command variant declared `main`
|
||||
tested targets through repeated, byte-sorted
|
||||
`--test-target-package <canonical-path>` arguments so a command variant declared `main`
|
||||
does not collide with the dispatcher's own synthesized `main`; this is
|
||||
compiler-generated wiring distinct from ordinary source aliases. Zero-test
|
||||
dispatchers mark their compiler-owned target/support metadata imports consumed.
|
||||
That private binding is installed or marked consumed only in the generated
|
||||
compiler-generated wiring distinct from ordinary source aliases. A real
|
||||
zero-test directory product marks all compiler-owned target/support metadata
|
||||
imports consumed. Those private bindings are installed or marked consumed only in the generated
|
||||
dispatcher's source section; an import from an earlier test-file section
|
||||
neither supplies nor satisfies it.
|
||||
|
||||
@@ -5117,14 +5126,15 @@ the reachable archive closure and runtime/native inputs; no `.wwi`, alias,
|
||||
blank spelling, or dispatcher sidecar appears.
|
||||
|
||||
Production, production-plus-internal-test, external `_test`, test support, and
|
||||
generated main retain separate action identities. An internal product replaces
|
||||
the colocated production task with its combined variant and includes test-only
|
||||
blank edges/init declarations exactly once. An external product initializes
|
||||
ordinary production and its production dependencies before the external task.
|
||||
Support is an ordinary dependency task; generated main owns only the final
|
||||
dispatcher call and cannot duplicate a tested task. Test-file-only imports,
|
||||
runtime lets, and init functions never enter production. A blank import cannot
|
||||
bypass imported-`main` rejection, including through vendor expansion.
|
||||
directory generated main retain separate action identities. One canonical
|
||||
directory product replaces colocated production with `ptest` wherever internal
|
||||
tests augment it, rewires `pxtest` self-import and affected transitive importers
|
||||
to that action, and includes test-only blank edges/init declarations exactly
|
||||
once. Support is an ordinary dependency task; the one generated main owns only
|
||||
the final dispatcher call and cannot duplicate a tested task. Test-file-only
|
||||
imports, runtime lets, and init functions never enter production. A blank
|
||||
import cannot bypass imported-`main` rejection, including through vendor
|
||||
expansion.
|
||||
|
||||
`.wwi` contains neither blank-only spelling, init declarations/bodies, hidden
|
||||
variable helpers, slice backing symbols, package tasks, nor dispatcher facts.
|
||||
@@ -5139,7 +5149,7 @@ first regenerated byte-identical semantic export.
|
||||
|
||||
The owner source voucher remains `<action>.unit.ww`; a linked product root also
|
||||
owns `<root>.init.unit.ww` for its dispatcher unit, `.init.s`, `.init.o`, and
|
||||
two-member archive. Current persistent formats are build 18 and test 17. Warm
|
||||
two-member archive. Current persistent formats are build 18 and test 19. Warm
|
||||
consumers select a dependency's staged `.wwi.new` or `.a.new` when that exact
|
||||
action changed in the same request. All action artifacts, init artifacts, tool
|
||||
identity copies, stamp, library/executable publications, and test statuses are
|
||||
@@ -5184,9 +5194,10 @@ diamonds, independent lexical ties, aggregate and allocation initialization,
|
||||
multiple-cycle diagnostics, special-init rejection, test-variant isolation,
|
||||
canonical task/dispatcher/archive bytes, init-only invalidation, and warm
|
||||
invalid-init rollback across independent Cstage and WWstage roots. Direct and
|
||||
recursive test legs compare variant dispatcher/archive bytes and observable
|
||||
production-dependency order; exact task counts include support and generated
|
||||
main. Rejection rows compare complete normalized diagnostics and prove cold
|
||||
recursive test legs compare the one directory dispatcher/archive and observable
|
||||
dependency, `ptest`, `pxtest`, then `pmain` order; every production and
|
||||
dependency task runs exactly once. Exact task counts include support and the
|
||||
single generated main. Rejection rows compare complete normalized diagnostics and prove cold
|
||||
scratch absence. The observer also uses a repository-built `setrlimit` launcher
|
||||
to find one shared bounded-memory ceiling at which both drivers fail before a
|
||||
producer, and proves no-follow atomic rejection of dangling driver staging and
|
||||
@@ -5305,7 +5316,7 @@ binary effect, or test execution.
|
||||
|
||||
#### Persistence, rejection, and stage responsibility
|
||||
|
||||
Persistent formats are build 18 and test 17 so a pre-slice workdir performs one
|
||||
Persistent formats are build 18 and test 19 so a pre-slice workdir performs one
|
||||
complete reachable-action refresh under the new membership contract. Thereafter
|
||||
an excluded-file add, removal, or content edit changes no unit voucher, `.wwi`,
|
||||
assembly, object, archive, dispatcher, test status, or reverse action. Existing
|
||||
@@ -5340,9 +5351,242 @@ observers retain their broader ownership.
|
||||
Source-level `//go:build`/`+build` equivalents, arbitrary tags, cross-target
|
||||
selection, grouped/quoted/dot imports, modules, manifests, registries, and a
|
||||
programmable build language remain deliberately unsupported. Go's `UseAllFiles`
|
||||
escape is also not exposed. The separate remaining Go test-product topology
|
||||
divergence—one generated main for combined internal and external variants—is
|
||||
not hidden or changed by this slice.
|
||||
escape is also not exposed. Section 11.22 closes the formerly separate
|
||||
directory test-product topology divergence without changing these filename
|
||||
eligibility boundaries.
|
||||
|
||||
### 11.22 Implemented one canonical directory package-test product
|
||||
|
||||
`ww test` now owns one practical test product per canonical selected directory,
|
||||
not one product per declared test package. Production, augmented internal test,
|
||||
external test, support, recompiled dependency, and generated-main actions stay
|
||||
separate compilation units; only their execution/publication ownership is
|
||||
unified. This is the applicable Go 1.26.5 topology for WW's local, dotted,
|
||||
manifest-free package model.
|
||||
|
||||
#### Pinned Go evidence and pre-fix divergence
|
||||
|
||||
The reference is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `TestPackagesFor` defines one `pmain` test binary running `ptest` and optional
|
||||
`pxtest`, with `ptest` equal to production plus same-package test files
|
||||
([`cmd/go/internal/load/test.go`, lines 85–101 and 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L101)).
|
||||
- External self-import is recognized before the external package is formed and
|
||||
is rebound to `ptest`, not ordinary `p`
|
||||
([lines 144–161 and 228–266](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L144-L161)).
|
||||
- One `pmain` receives both applicable targets, one sorted import set, and then
|
||||
`recompileForTest` copy-on-write rewires every affected transitive importer
|
||||
from ordinary production to the augmented package
|
||||
([lines 272–293, 342–376, and 421–490](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L272-L293)).
|
||||
- The generated source scans both target classes into one function set and one
|
||||
`testing.MainStart`/`Run`
|
||||
([lines 595–638 and 790–860](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L595-L638)).
|
||||
- A directory with no selected test files takes the early ordinary-production
|
||||
compile path and creates no test support, generated main, link, executable,
|
||||
or subprocess; its print action reports `[no test files]`
|
||||
([`cmd/go/internal/test/test.go`, lines 1133–1170 and 1524–1557](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1170)).
|
||||
- A real test package creates one generated source, one link action, and one
|
||||
output-copy/install or run action, including `-c`/`-o`
|
||||
([lines 1200–1364](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1200-L1364)).
|
||||
- Go's action cache distinguishes cloned package objects even when their import
|
||||
paths match, compiler inputs come from the selected action's direct
|
||||
dependencies, and the link closure selects one archive per import path
|
||||
([`cmd/go/internal/work/action.go`, lines 202–206, 437–447, and 628–658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
|
||||
[`exec.go`, lines 410–438 and 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L410-L438)).
|
||||
- `go/build` classifies same-package and `_test` external files independently
|
||||
and accepts directories containing only either class
|
||||
([`go/build/build.go`, lines 948–953, 1005–1036, and 1076–1082](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L953)).
|
||||
|
||||
Official command testdata closes the observable cases. `test_empty.txt` lines
|
||||
3–24 and 30–53 accepts production-only, internal-only, external-only, combined,
|
||||
test-only internal, test-only external, and mixed test-only directories
|
||||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_empty.txt#L3-L24)).
|
||||
`vendor_test_issue11864.txt` lines 8–9 and 64–80 proves an external test can use
|
||||
an export declared only in an internal test source
|
||||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/vendor_test_issue11864.txt#L64-L80)).
|
||||
`list_test_imports.txt` lines 3–21 proves transitive rebuilding when a helper
|
||||
imports the package under test
|
||||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_imports.txt#L3-L21)).
|
||||
`toolexec.txt` lines 27–50 observes distinct `ptest`, `pxtest`, and `pmain`
|
||||
compiles but one main and linker call
|
||||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/toolexec.txt#L27-L50)).
|
||||
`test_no_tests.txt` lines 1–14 uses a panicking production initializer to prove
|
||||
that no-test reporting does not execute a test process
|
||||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_no_tests.txt#L1-L14)).
|
||||
|
||||
Before this slice WW constructed one generated main, link, binary, result, and
|
||||
report for each declared same/external test package. A combined directory ran
|
||||
two processes, initialized production state twice, hid internal-test exports
|
||||
from the external package, and made `-c -o` fail as a multi-product request.
|
||||
Even a directory with no selected tests manufactured support, a main, a link,
|
||||
and a temporary executable merely to print `[no tests]`. Test-only external
|
||||
directories were mislabeled, a valid mixed test-only directory was rejected,
|
||||
and a transitive importer was compiled against ordinary production.
|
||||
|
||||
#### Final product and action topology
|
||||
|
||||
For canonical directory product `P`, the action graph is:
|
||||
|
||||
- `p`: ordinary production sources only;
|
||||
- `ptest`: production plus same-package selected `*_test.ww` sources;
|
||||
- `pxtest`: external-package selected `*_test.ww` sources only;
|
||||
- product-scoped recompiled actions: unchanged source units whose direct target
|
||||
set was rewritten by the `p -> ptest` substitution;
|
||||
- support: one command-global production support action (or the reserved
|
||||
`__wwtest` compiler binding when user `test` occupies that spelling);
|
||||
- `pmain`: one directory-owned generated-main action importing every applicable
|
||||
target and support.
|
||||
|
||||
The source shapes produce these reachable roots:
|
||||
|
||||
| Directory shape | Test closure and externally visible product |
|
||||
| --- | --- |
|
||||
| production, no selected tests | ordinary `p`; no support/main/link/run/output/result |
|
||||
| production + internal | `ptest` + `pmain`; one binary/result |
|
||||
| production + external | unaugmented `p` + `pxtest` + `pmain`; one binary/result |
|
||||
| production + both | `ptest` + `pxtest -> ptest` + `pmain`; one binary/result |
|
||||
| test-only same package | `ptest` + `pmain`; one binary/result |
|
||||
| test-only external package | `pxtest` + `pmain`; one binary/result |
|
||||
| test-only same + external | `ptest` + `pxtest -> ptest` + `pmain`; one binary/result |
|
||||
|
||||
A selected helper-only `*_test.ww` file is still a real test source: it is
|
||||
loaded and may yield an empty harness. The no-real-run branch is specifically
|
||||
the absence of selected test files after platform filtering. Ordinary
|
||||
`ww build` excludes test filenames before reading even their package clauses,
|
||||
so malformed test-only content and test-only imports cannot affect production.
|
||||
|
||||
The coordinator in `internal/wwpackage/package.ww` classifies all selected
|
||||
files into one directory group. Classification is production-name-relative,
|
||||
so a legitimate production package literally named `foo_test` has external
|
||||
name `foo_test_test`; without production, a valid `p`/`p_test` pair is retained
|
||||
as same/external rather than blindly stripping every suffix. The private driver
|
||||
descriptor is an ordered directory record:
|
||||
|
||||
```
|
||||
--ww-package-test KIND FAMILY PRODUCTION INTERNAL EXTERNAL DIR OUTPUT STATUS
|
||||
```
|
||||
|
||||
Missing action selectors are `-`. One descriptor owns at most one output and
|
||||
one status. Canonically duplicate products and pairwise output/status/staging
|
||||
collisions reject before producer execution. Declared names and output stems do
|
||||
not identify products or actions.
|
||||
|
||||
The Cstage and WWstage drivers first load and validate the ordinary production
|
||||
root. They form `ptest` and `pxtest` as separate source actions, bind external
|
||||
self-import to `ptest`, seed `p -> ptest`, and copy/rewrite the affected
|
||||
dependency closure. Both deduplicated dependency edges and every original
|
||||
file-local import binding target are rewritten through action identity. The
|
||||
strict closure validator rejects any leaked ordinary/augmented duplicate; no
|
||||
initialization or archive-order fallback can hide an incomplete substitution.
|
||||
|
||||
`pmain` stores a checked, byte-sorted unique target action set. Its generated
|
||||
unit imports each target once plus support. The compiler argv repeats
|
||||
`--test-target-package` in that same order, followed by the exact byte-sorted
|
||||
direct `--import PATH WWI` set. Thus a combined shape has the essential form:
|
||||
|
||||
```
|
||||
w6c --test-package ... -I PTEST.wwi -o PTEST.s PTEST.unit.ww
|
||||
w6c --test-package ... --import P PTEST.wwi ... -I PXTEST.wwi ...
|
||||
w6c -T --entry --test-support-module test \
|
||||
--test-target-package P --test-target-package P_test \
|
||||
--import P PTEST.wwi --import P_test PXTEST.wwi --import test TEST.wwi \
|
||||
-I PMAIN.wwi -o PMAIN.s PMAIN.unit.ww
|
||||
```
|
||||
|
||||
Actual arguments also contain action-owned init and dispatcher symbols. The
|
||||
assembler receives one source object per compiled action and exactly one
|
||||
`pmain.init.s -> pmain.init.o` dispatcher. Test target archives contain only
|
||||
their deterministic `pkg.o` member; the main archive contains `pkg.o` then
|
||||
`init.o`. Link argv is root plus reachable archives only:
|
||||
|
||||
```
|
||||
w6l -o OUTPUT.new PMAIN.a [PXTEST.a] [PTEST-or-P.a] ... TEST.a libwwrt.a
|
||||
```
|
||||
|
||||
No `.wwi`, source filename, standalone semantic object, or linker-order choice
|
||||
participates. Both native linkers already resolve archive members by symbols;
|
||||
they required no topology-specific change.
|
||||
|
||||
#### Import, export, initialization, and execution ownership
|
||||
|
||||
Default, explicit-alias, and blank imports remain file-local source
|
||||
occurrences. The package graph still uses one canonical edge per target and
|
||||
preserves every occurrence for usage and legality diagnostics. Substitution
|
||||
changes only the chosen canonical action. Consequently an external source
|
||||
continues to spell `import P`, but its direct compiler export input is
|
||||
`ptest.wwi`; an exported helper in an internal test source is ordinary augmented
|
||||
package export data and needs no special reader format. Per-owner `@test`
|
||||
metadata in `.wwi` remains sufficient. The writer/reader format did not change.
|
||||
|
||||
`cmd/w6c/main.c`, `cmd/wcc/ww.h`, and `cmd/wcc/check.c`, with their self-hosted
|
||||
twins, changed singular generated-target state into a target set. Every target
|
||||
import is marked used, and every imported `@test` declaration receives its
|
||||
canonical target qualifier. The coordinator controls target order; the checker
|
||||
does not resolve directories. `wwdump` passes an empty target set on its
|
||||
non-test path.
|
||||
|
||||
One dependency-first dispatcher is generated from the substituted closure.
|
||||
Each reachable canonical action contributes one initialization task; `pmain`
|
||||
is the sole entry package that calls the dispatcher. A combined directory
|
||||
therefore initializes dependencies, augmented production, external tests,
|
||||
support, and main exactly once in one process. Filtering and listing operate on
|
||||
the single deterministic enumeration containing both target sets; output has
|
||||
one accounting block and one directory report. `ww test -c -o OUTPUT DIR`
|
||||
publishes the one directory binary even when both target classes exist.
|
||||
|
||||
#### Artifacts, persistence, invalidation, and rejection
|
||||
|
||||
Semantic action artifacts remain separate: `.unit.ww`, `.wwi`, `.s`, `.o`, and
|
||||
`.a` for each production/test/recompiled/main/support action, plus main init
|
||||
unit/assembly/object. The directory product alone owns the binary, status, and
|
||||
result. Test persistent-work format is `19`; semantic package storage is format
|
||||
`3` and includes the product-scoped `for_test` identity for recompiled actions.
|
||||
There is still no cache, CAS, manifest, registry, database, or result cache.
|
||||
|
||||
Warm reuse compares owner-unit bytes and exact direct export bytes. An internal
|
||||
helper body edit with stable `.wwi` rebuilds only `ptest` and relinks; external
|
||||
and reverse compilation stop. An external body-only edit rebuilds only
|
||||
`pxtest`. Adding or changing an exported internal helper changes `ptest.wwi`,
|
||||
then rebuilds exactly affected recompiled importers, `pxtest`, and `pmain`.
|
||||
Adding or removing a target class changes only the owning directory product and
|
||||
newly reachable actions. Request/root order and equivalent directory spelling
|
||||
do not change action bytes, target order, output, or reuse.
|
||||
|
||||
Loader-owned source classification, import legality, canonical-product,
|
||||
duplicate-closure, cycle, command-kind, and publication-path errors reject
|
||||
before compiler, assembler, linker, support, or main work. Production failure
|
||||
is diagnosed once even though an augmented action would contain the same
|
||||
sources. Later compiler, assembler, generated-main, archive, link, staging, or
|
||||
commit failure remains one request-wide transaction: no sibling product runs,
|
||||
no status/result/binary or mixed generation is published, prior committed
|
||||
bytes remain unchanged, and every staged `.new` is discarded. Both drivers use
|
||||
checked dynamic allocation and transactional clone construction; allocation
|
||||
failure cannot publish a partial action or leave cleanup to traverse
|
||||
uninitialized storage.
|
||||
|
||||
The native proof is primarily
|
||||
`directory_package_graph_variants`,
|
||||
`multi_directory_shared_package_plan`,
|
||||
`empty_and_invalid_package_classes`,
|
||||
`dynamic_package_universe_crosses_former_boundary`,
|
||||
`platform_filename_source_selection`,
|
||||
`vendor_directory_import_resolution`, and
|
||||
`test_variant_initialization`, with late transaction ownership in
|
||||
`sibling_test_variant_failures_are_isolated`. Together they compare
|
||||
cold/persistent Cstage and WWstage units, exports, assembly, objects, exact
|
||||
archive members, mains, binaries, diagnostics, runtime order, literal and
|
||||
normalized compiler/assembler/linker argv, both root orders in each stage,
|
||||
precise body/export and target-removal/re-addition invalidation, combined-graph
|
||||
allocation failure, repeated late internal/external/main/link rollback, and a
|
||||
complete work-directory sweep for staged residue.
|
||||
|
||||
Deliberately unchanged or unsupported behavior includes the raw single-file
|
||||
compatibility path, WW's `[no tests]` presentation text, Go modules and build
|
||||
cache, network resolution, manifests, coverage/vet/fuzz/benchmark generation,
|
||||
source-level build expressions, quoted/grouped/dot imports, and targets other
|
||||
than the separately specified fixed `linux/amd64` filename selection. None is
|
||||
used to define canonical package or directory-product identity.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
|
||||
42
docs/spec.md
42
docs/spec.md
@@ -251,10 +251,12 @@ ImportName = ident .
|
||||
ImportPath = ident { "." ident } .
|
||||
```
|
||||
|
||||
- Every source file begins with a package clause. A directory of eligible
|
||||
`.ww` files sharing one declared package name compiles as one package. The
|
||||
declared name need not equal the directory name or the final component of its
|
||||
canonical import identity.
|
||||
- Every source file begins with a package clause. Within one semantic source
|
||||
action, eligible `.ww` files share one declared package name. Ordinary
|
||||
production and same-package test sources use `p`; external test sources may
|
||||
use the related `p_test`, and the actions remain separate even though one
|
||||
canonical directory owns their test product. The declared name need not equal
|
||||
the directory name or the final component of its canonical import identity.
|
||||
- Directory source eligibility uses Go 1.26.5 filename suffix semantics for
|
||||
WW's fixed `linux/amd64` target. In the basename stem before the first dot, a
|
||||
final `_test` token is ignored for platform matching. A final known OS or
|
||||
@@ -286,10 +288,12 @@ ImportPath = ident { "." ident } .
|
||||
initialization. Repeated blank occurrences and blank plus default/explicit
|
||||
named occurrences of one path are valid; every named occurrence remains
|
||||
independently subject to duplicate-binding and unused checks.
|
||||
The package dependency graph is the sorted, deduplicated union of the real
|
||||
imports in all eligible files. Occurrences retain their owning file and
|
||||
position, but equal canonical targets create one graph edge/package action.
|
||||
Self-import is rejected.
|
||||
Each semantic action's package dependency graph is the sorted, deduplicated
|
||||
union of real imports in that action's eligible source set. Occurrences retain
|
||||
their owning file and position, but equal canonical targets create one graph
|
||||
edge. Test-only occurrences never enter ordinary production. Self-import is
|
||||
rejected, except that toolchain-owned external-test self wiring is rebound to
|
||||
the effective augmented package action after ordinary per-site validation.
|
||||
- An executable package is one declared `package main` and containing a
|
||||
`fn main`; path and directory spelling do not classify commands. An ordinary
|
||||
import of a package declared `main` is rejected, except for the toolchain's
|
||||
@@ -606,13 +610,21 @@ the program. Two placements, following the Go `foo` / `foo_test` model:
|
||||
```
|
||||
|
||||
Production, production-plus-white-box-test, external black-box-test, test
|
||||
support, and generated test main are distinct package actions. Before a test
|
||||
function runs, the generated test product initializes its exact reachable
|
||||
variant graph dependency-first and once per canonical action. A white-box
|
||||
variant replaces the colocated production task rather than initializing both;
|
||||
an external variant depends on ordinary production. Imports, runtime lets, and
|
||||
init declarations found only in `*_test.ww` never enter an ordinary production
|
||||
build.
|
||||
support, recompiled-for-test dependencies, and generated test main are distinct
|
||||
package actions. One canonical selected directory owns one test product and one
|
||||
generated main, which imports every applicable same-package and external target
|
||||
and produces one binary/result. The external action's import of the package
|
||||
under test binds to the augmented white-box action when it exists; affected
|
||||
transitive importers are copied and rewired so ordinary and augmented package
|
||||
state do not coexist in the linked closure.
|
||||
|
||||
Before a test function runs, the one generated product initializes its exact
|
||||
effective graph dependency-first and once per canonical action. Imports,
|
||||
runtime lets, and init declarations found only in `*_test.ww` never enter an
|
||||
ordinary production build. Test-only same-package, external-package, and valid
|
||||
mixed directories are accepted from their selected test files. A directory
|
||||
with no selected test file validates ordinary production but creates no test
|
||||
support, generated main, link, binary, result, or process.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -193,8 +193,9 @@ and nonempty-version-constant assertions.
|
||||
|
||||
`ww test` delegates directory package requests to the native package
|
||||
coordinator. The coordinator owns request-pattern expansion, package grouping,
|
||||
same-package and external-package variant selection, filtering, result
|
||||
aggregation, and its internal temporary workspace. Test sources are exclusively
|
||||
same-package and external-package action selection, one canonical
|
||||
directory-owned product, filtering, result aggregation, and its internal
|
||||
temporary workspace. Test sources are exclusively
|
||||
`*_test.ww` (Go's `_test.go` contract): a line-leading `@test` declaration in
|
||||
any other source is rejected loudly — by both driver stages at directory
|
||||
enumeration and by the coordinator at source classification. A local spelling
|
||||
@@ -204,8 +205,11 @@ directory prefix before the first wildcard. Recursive children beginning `.`
|
||||
or `_` and exact `testdata` subtrees are pruned; child directory symlinks are
|
||||
not followed. A wildcard cannot consume a non-terminal exact `vendor` element,
|
||||
while an explicitly vendor-rooted pattern remains legal. Every selected
|
||||
test-bearing directory becomes one package run, and selected source-bearing
|
||||
directories without tests report the usual `?` line. The coordinator first
|
||||
test-bearing directory becomes exactly one package run, binary, and result even
|
||||
when both internal and external actions exist. Selected source-bearing
|
||||
directories without selected test files report the usual `?` line after
|
||||
ordinary production validation, with no support, generated main, link, binary,
|
||||
result, or process. The coordinator first
|
||||
launches one driver plan for the complete command-global package/action union.
|
||||
After that shared build completes, `-j N` schedules up to N successful selected
|
||||
test binaries concurrently under `os.exec` start/poll supervision (no threads);
|
||||
@@ -213,10 +217,11 @@ emission stays strictly in group order, so the byte stream is identical at
|
||||
every `-j` level, and `-j 1` — the default — matches the former sequential
|
||||
run loop exactly. Measured on the 31-package `lib/...` walk:
|
||||
7.0s sequential, 2.4s at `-j 4`. With `-c`, it publishes each exact
|
||||
`<package>.test` binary in the package directory; the first output owns the one
|
||||
`<package>.test` directory binary; the first output owns the one
|
||||
shared cold sepwork containing the command-global action universe. Those become
|
||||
caller-owned artifacts. `-c -o <name>`
|
||||
names that artifact instead of the fixed stem, for exactly one package:
|
||||
names that artifact instead of the fixed stem for exactly one directory,
|
||||
including a combined internal/external directory:
|
||||
the coordinator rejects a multi-package fan-out ("cannot use -o with
|
||||
multiple packages", Go's `go test -o` rule), and `-o` without `-c` is
|
||||
rejected at the driver ("needs -c for a package target") because a plain
|
||||
@@ -256,8 +261,10 @@ archive/action ownership, one canonical direct edge for repeated occurrences,
|
||||
stage-equal diagnostics and binaries, and clean rejection state.
|
||||
The declared-name observer proves imports are file-scoped while dependency
|
||||
edges are the package-wide sorted union; command and
|
||||
production/internal/external/generated-main variants retain canonical action
|
||||
ownership; vendor expansion changes identity but not the effective qualifier;
|
||||
production/internal/external/directory-main actions retain canonical action
|
||||
ownership while one canonical directory owns their product; external
|
||||
self-imports bind the augmented internal action; vendor expansion changes
|
||||
identity but not the effective qualifier;
|
||||
compiler argv contains only direct `.wwi` inputs; and its named rejected
|
||||
actions leave neither committed nor staged action artifacts or a published
|
||||
binary. It also forces a request transaction to reject after dependency work
|
||||
@@ -277,9 +284,15 @@ normalized compiler/assembler/linker argv, units, `.wwi`, assembly, objects,
|
||||
archives, generated-main archives, binaries, runtime/test output, direct and
|
||||
recursive behavior, reversed roots, ignored-edit reuse, selected private-change
|
||||
propagation, and request rollback after a dependency has staged and the root
|
||||
compiler fails. The existing bounded-memory package-initialization observer
|
||||
continues to own allocation-failure parity for the shared dynamically grown
|
||||
action universe.
|
||||
compiler fails. Wrong-target test files cannot add a target to the directory
|
||||
main or create one for an otherwise no-test directory. The bounded-memory
|
||||
package-initialization observer now pressures the combined directory topology
|
||||
itself: production, augmented internal test, external self-import, a transitive
|
||||
recompile-for-test clone, support, and the two-target generated main. Each stage
|
||||
searches its own bounded address-space ceiling, while the accepted failure must
|
||||
have the same `ww: out of memory` diagnostic, invoke no compiler, assembler, or
|
||||
linker, and leave an empty caller work directory with no output, status, or
|
||||
staging path.
|
||||
|
||||
`test/sep/sepinit_test.ww` is the single focused package-initialization owner.
|
||||
It generates all source trees temporarily and runs independent cold/persistent
|
||||
@@ -287,15 +300,18 @@ Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
||||
diamond, and independent ready-task order; runtime call/allocation and aggregate
|
||||
package lets; multiple init declarations and invalid forms; direct/qualified
|
||||
init invisibility; initialization cycles and diagnostic order; command,
|
||||
internal-test, external-test, support, and generated-main ownership; canonical
|
||||
internal-test, external-test, support, and one directory-generated-main
|
||||
ownership; canonical
|
||||
task and dispatcher symbols; deterministic one- and two-member archives;
|
||||
`.wwi` exclusion; byte-identical artifacts/binaries; init-only invalidation;
|
||||
warm invalid-init rollback; direct/recursive variant equivalence; exact
|
||||
production, support, and generated-main task ordering; complete normalized
|
||||
production, support, ptest-before-pxtest-before-main task ordering, exactly-once
|
||||
package/dependency initialization in one dispatcher; complete normalized
|
||||
rejection diagnostics; dangling staging/rollback no-follow rejection; and
|
||||
checked compiler-output failure/non-regular-destination rollback; and
|
||||
bounded-memory allocation-failure parity under one shared ceiling supplied by
|
||||
the repository-built `sep-limitexec` helper.
|
||||
bounded-memory Cstage/WWstage allocation-failure parity across the complete
|
||||
combined package-test graph, under independently discovered ceilings supplied
|
||||
by the repository-built `sep-limitexec` helper.
|
||||
|
||||
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful
|
||||
directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned
|
||||
@@ -330,9 +346,11 @@ create false reuse or a mixed generation; a successful executable link still
|
||||
reruns when required. One workdir serves one invocation at a time and may hold
|
||||
the complete command-global action universe for all selected roots and isolated
|
||||
variants; semantic identity, rather than request shape, controls reuse. Both
|
||||
driver stages implement the identical contract. This is build staleness in the
|
||||
driver stages implement the identical contract. Test-mode persistent workdirs
|
||||
use format 19. This is build staleness in the
|
||||
Make/mk/Go sense, not a result cache:
|
||||
tests always run, and the byte-identity and bootstrap gates keep building on
|
||||
real directory test products always run, while no-selected-test directories do
|
||||
not create a process. The byte-identity and bootstrap gates keep building on
|
||||
fresh scratch. `make clean` reclaims every workdir under `out/`.
|
||||
|
||||
On a package or tree target, `ww build/test -w DIR` forwards that exact caller
|
||||
|
||||
@@ -3,7 +3,7 @@ package pass_test;
|
||||
import test;
|
||||
|
||||
@test fn alpha_pass() void = {
|
||||
assert(test.current() == "pass_test.alpha_pass");
|
||||
assert(test.current() == "pass.alpha_pass");
|
||||
};
|
||||
|
||||
@test fn beta_skip() void = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -736,7 +736,11 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
|
||||
let td: str = testenv.fresh();
|
||||
let tree: str = strings.concat(td, "/tree");
|
||||
assert(os.mkdir(tree, 493) == 0);
|
||||
let body: str = "package main;\n";
|
||||
let target: str = strings.concat(tree, "/target");
|
||||
let bridge: str = strings.concat(tree, "/bridge");
|
||||
assert(os.mkdir(target, 493) == 0);
|
||||
assert(os.mkdir(bridge, 493) == 0);
|
||||
let body: str = "package target;\n";
|
||||
let i: i32 = 0;
|
||||
for (i < 600) {
|
||||
let name: str = allocpkgname(i);
|
||||
@@ -747,63 +751,98 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
|
||||
body = strings.concat(body, "import _ ", name, ";\n");
|
||||
i += 1;
|
||||
};
|
||||
body = strings.concat(body, "fn main() i32 = { return 0; };\n");
|
||||
let src: str = strings.concat(td, "/main.ww");
|
||||
testenv.writefile(src, body);
|
||||
let wrapper: str = strings.concat(td, "/w6c-trace.sh");
|
||||
body = strings.concat(body,
|
||||
"export fn value() i32 = { return 41; };\n");
|
||||
testenv.writefile(strings.concat(target, "/target.ww"), body);
|
||||
testenv.writefile(strings.concat(target, "/same_test.ww"), strings.concat(
|
||||
"package target;\n",
|
||||
"export fn internal_helper() i32 = { return value(); };\n",
|
||||
"@test fn internal_runs() void = { assert(value() == 41); };\n"));
|
||||
testenv.writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
|
||||
"package bridge;\nimport target;\n",
|
||||
"export fn helper() i32 = { return target.internal_helper(); };\n"));
|
||||
testenv.writefile(strings.concat(target, "/external_test.ww"),
|
||||
strings.concat("package target_test;\nimport bridge;\nimport target;\n",
|
||||
"@test fn external_runs() void = {\n",
|
||||
" assert(target.internal_helper() == 41);\n",
|
||||
" assert(bridge.helper() == 41);\n};\n"));
|
||||
let wrapper: str = strings.concat(td, "/tool-trace.sh");
|
||||
testenv.writeexecutable(wrapper, strings.concat("#!/bin/sh\n",
|
||||
"printf x >> \"$WW_SEPINIT_W6C_TRACE\"\nexit 99\n"));
|
||||
"printf x >> \"$WW_SEPINIT_TOOL_TRACE\"\nexit 99\n"));
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let launcher: str = testenv.driver("sep-limitexec");
|
||||
let accepted: [2]str;
|
||||
let stagei: i32 = 0;
|
||||
// Address-space layouts differ, so each implementation searches its own
|
||||
// bounded ceiling. The accepted point must fail while constructing the
|
||||
// combined p/ptest/pxtest/pmain and transitive-clone graph, before any tool.
|
||||
for (stagei < stages.len) {
|
||||
let found: bool = false;
|
||||
let last: str = "";
|
||||
let limit: i64 = 2621440i64;
|
||||
let li: i32 = 0;
|
||||
// Both implementations must reject under the same address-space ceiling.
|
||||
// Search a bounded same-limit ladder because loader mappings differ across
|
||||
// supported hosts; the 600-action graph makes the driver-allocation window
|
||||
// broad, while the compiler trace pins failure before the first tool.
|
||||
for (limit <= 16777216i64 && !found) {
|
||||
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC);
|
||||
let good: [2]bool;
|
||||
let diags: [2]str;
|
||||
i = 0;
|
||||
for (i < stages.len) {
|
||||
for (limit <= 33554432i64 && !found) {
|
||||
let tag: str = allocpkgname(li);
|
||||
let trace: str = strings.concat(td, "/alloc-", stages[i], "-",
|
||||
let trace: str = strings.concat(td, "/alloc-", stages[stagei], "-",
|
||||
tag, ".trace");
|
||||
let work: str = strings.concat(td, "/alloc-work-", stages[stagei],
|
||||
"-", tag);
|
||||
let output: str = strings.concat(td, "/alloc-output-",
|
||||
stages[stagei], "-", tag);
|
||||
let status: str = strings.concat(td, "/alloc-status-",
|
||||
stages[stagei], "-", tag);
|
||||
testenv.writefile(trace, "");
|
||||
let env: []str = compilertraceenv(wrapper,
|
||||
testenv.driver(compilers[i]), trace);
|
||||
let output: str = strings.concat(td, "/alloc-", stages[i], "-",
|
||||
tag);
|
||||
let av: []str = [launcher, limitstr, testenv.driver(stages[i]),
|
||||
"build", "-I", tree, "-o", output, src];
|
||||
let out: testenv.commandout;
|
||||
runenv(td, strings.concat("allocation-", stages[i], "-", tag),
|
||||
av, env, &out);
|
||||
last = strings.dup(out.stderr);
|
||||
good[i] = exitcode(&out) == 1 && testenv.same(out.stderr,
|
||||
"ww: out of memory\n")
|
||||
&& testenv.readfile(trace).len == 0;
|
||||
diags[i] = strings.dup(out.stderr);
|
||||
if (testenv.exists(output) || testenv.exists(strings.concat(output,
|
||||
".sepwork"))) {
|
||||
fail("allocation", "failed pressure leg published state");
|
||||
assert(os.mkdir(work, 493) == 0);
|
||||
let base: []str = os.getenvs();
|
||||
let env: []str = alloc([], (base.len + 4): u64)!;
|
||||
i = 0;
|
||||
for (i < base.len) {
|
||||
if (!strings.hasprefix(base[i], "WW_W6C=")
|
||||
&& !strings.hasprefix(base[i], "WW_W6A=")
|
||||
&& !strings.hasprefix(base[i], "WW_W6L=")
|
||||
&& !strings.hasprefix(base[i],
|
||||
"WW_SEPINIT_TOOL_TRACE=")) {
|
||||
append(env, base[i]);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (good[0] && good[1]) {
|
||||
if (!testenv.same(diags[0], diags[1])) {
|
||||
fail("allocation", "C/WW allocation diagnostic mismatch");
|
||||
append(env, strings.concat("WW_W6C=", wrapper));
|
||||
append(env, strings.concat("WW_W6A=", wrapper));
|
||||
append(env, strings.concat("WW_W6L=", wrapper));
|
||||
append(env, strings.concat("WW_SEPINIT_TOOL_TRACE=", trace));
|
||||
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC);
|
||||
let av: []str = [launcher, limitstr, testenv.driver(stages[stagei]),
|
||||
"test", "-c", "-w", work, "-I", tree,
|
||||
"--ww-package-test", "test", "target", "target", "target",
|
||||
"target_test", target, output, status, target];
|
||||
let out: testenv.commandout;
|
||||
runenv(td, strings.concat("allocation-", stages[stagei], "-", tag),
|
||||
av, env, &out);
|
||||
last = strings.dup(out.stderr);
|
||||
if (testenv.listdir(work).len != 0
|
||||
|| nofollowexists(output)
|
||||
|| nofollowexists(strings.concat(output, ".new"))
|
||||
|| nofollowexists(strings.concat(output, ".sepwork"))
|
||||
|| nofollowexists(status)
|
||||
|| nofollowexists(strings.concat(status, ".new"))) {
|
||||
fail("allocation", "failed pressure leg published state");
|
||||
};
|
||||
if (exitcode(&out) == 1 && out.stdout.len == 0
|
||||
&& testenv.same(out.stderr, "ww: out of memory\n")
|
||||
&& testenv.readfile(trace).len == 0) {
|
||||
accepted[stagei] = strings.dup(out.stderr);
|
||||
found = true;
|
||||
};
|
||||
testenv.clean(work);
|
||||
limit += 131072i64;
|
||||
li += 1;
|
||||
};
|
||||
if (!found) { fail("allocation", last); };
|
||||
stagei += 1;
|
||||
};
|
||||
if (!testenv.same(accepted[0], accepted[1])) {
|
||||
fail("allocation", "C/WW allocation diagnostic mismatch");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@@ -932,16 +971,12 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
|
||||
let tags: []str = ["c", "ww"];
|
||||
let reference: str = "";
|
||||
let variantnames: []str = [
|
||||
"widget-internal-test-main.init.unit.ww",
|
||||
"widget-internal-test-main.init.s",
|
||||
"widget-internal-test-main.init.o",
|
||||
"widget-internal-test-main.a",
|
||||
"widget_test-external-test-main.init.unit.ww",
|
||||
"widget_test-external-test-main.init.s",
|
||||
"widget_test-external-test-main.init.o",
|
||||
"widget_test-external-test-main.a",
|
||||
"widget-test-main.init.unit.ww",
|
||||
"widget-test-main.init.s",
|
||||
"widget-test-main.init.o",
|
||||
"widget-test-main.a",
|
||||
];
|
||||
let variantrefs: []str = ["", "", "", "", "", "", "", ""];
|
||||
let variantrefs: []str = ["", "", "", ""];
|
||||
let i: i32 = 0;
|
||||
for (i < 2) {
|
||||
let work: str = strings.concat(td, "/test-work-", tags[i]);
|
||||
@@ -967,61 +1002,45 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
|
||||
let rr: i32 = testenv.pos(out.stdout, "<R>");
|
||||
let ii: i32 = testenv.pos(out.stdout, "<I>");
|
||||
let tt: i32 = testenv.pos(out.stdout, "<T>");
|
||||
let tail: str = "";
|
||||
if (tt >= 0) { tail = strings.sub(out.stdout, tt + 3, out.stdout.len); };
|
||||
let de: i32 = testenv.pos(tail, "<D>");
|
||||
let pe: i32 = testenv.pos(tail, "<P>");
|
||||
let w: i32 = testenv.pos(tail, "<W>");
|
||||
let e: i32 = testenv.pos(tail, "<E>");
|
||||
let x: i32 = testenv.pos(tail, "<X>");
|
||||
if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < tt
|
||||
&& de >= 0 && de < pe && pe < w && w < e && e < x)) {
|
||||
let w: i32 = testenv.pos(out.stdout, "<W>");
|
||||
let e: i32 = testenv.pos(out.stdout, "<E>");
|
||||
let x: i32 = testenv.pos(out.stdout, "<X>");
|
||||
if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < w
|
||||
&& w < e && e < tt && tt < x)) {
|
||||
fail("variants", strings.concat("test init order: ", out.stdout));
|
||||
};
|
||||
if (testenv.occurrences(out.stdout, "<Q>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<D>") != 2
|
||||
|| testenv.occurrences(out.stdout, "<D>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<R>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<W>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<I>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<E>") != 1
|
||||
|| testenv.occurrences(out.stdout, "<P>") != 2) {
|
||||
|| testenv.occurrences(out.stdout, "<P>") != 1) {
|
||||
fail("variants", "variant initialization count");
|
||||
};
|
||||
let internal: str = testenv.readfile(strings.concat(work,
|
||||
"/widget-internal-test-main.init.unit.ww"));
|
||||
if (testenv.occurrences(internal,
|
||||
let dispatcher: str = testenv.readfile(strings.concat(work,
|
||||
"/widget-test-main.init.unit.ww"));
|
||||
if (testenv.occurrences(dispatcher,
|
||||
"__ww..pkg.p.testside.v0.r0.init") != 1
|
||||
|| testenv.occurrences(internal,
|
||||
|| testenv.occurrences(dispatcher,
|
||||
"__ww..pkg.p.prodside.v0.r0.init") != 1
|
||||
|| testenv.occurrences(internal,
|
||||
|| testenv.occurrences(dispatcher,
|
||||
"__ww..pkg.p.widget.v1.r0.init") != 1
|
||||
|| testenv.occurrences(internal,
|
||||
"__ww..pkg.p.test.v0.r0.init") != 1
|
||||
|| testenv.occurrences(internal,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init") != 1
|
||||
|| testenv.pos(internal, "__ww..pkg.p.test.v0.r0.init")
|
||||
>= testenv.pos(internal,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init")
|
||||
|| testenv.has(internal, "__ww..pkg.p.widget.v0.r0.init")) {
|
||||
fail("variants", "internal variant dispatcher ownership");
|
||||
};
|
||||
let external: str = testenv.readfile(strings.concat(work,
|
||||
"/widget_test-external-test-main.init.unit.ww"));
|
||||
if (testenv.occurrences(external,
|
||||
"__ww..pkg.p.widget.v0.r0.init") != 1
|
||||
|| testenv.occurrences(external,
|
||||
"__ww..pkg.p.prodside.v0.r0.init") != 1
|
||||
|| testenv.occurrences(external,
|
||||
|| testenv.occurrences(dispatcher,
|
||||
"__ww..pkg.p.widget_test.v2.r0.init") != 1
|
||||
|| testenv.occurrences(external,
|
||||
|| testenv.occurrences(dispatcher,
|
||||
"__ww..pkg.p.test.v0.r0.init") != 1
|
||||
|| testenv.occurrences(external,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init") != 1
|
||||
|| testenv.pos(external, "__ww..pkg.p.test.v0.r0.init")
|
||||
>= testenv.pos(external,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init")
|
||||
|| testenv.has(external, "testside")) {
|
||||
fail("variants", "external variant dispatcher ownership");
|
||||
|| testenv.occurrences(dispatcher,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init") != 1
|
||||
|| testenv.pos(dispatcher, "__ww..pkg.p.widget.v1.r0.init")
|
||||
>= testenv.pos(dispatcher,
|
||||
"__ww..pkg.p.widget_test.v2.r0.init")
|
||||
|| testenv.pos(dispatcher,
|
||||
"__ww..pkg.p.widget_test.v2.r0.init")
|
||||
>= testenv.pos(dispatcher,
|
||||
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init")
|
||||
|| testenv.has(dispatcher, "__ww..pkg.p.widget.v0.r0.init")) {
|
||||
fail("variants", "directory test dispatcher ownership");
|
||||
};
|
||||
let directstdout: str = strings.dup(out.stdout);
|
||||
let recursivework: str = strings.concat(td, "/test-recursive-work-",
|
||||
@@ -1100,7 +1119,7 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
|
||||
av, env, tmo(), &out);
|
||||
if (exitcode(&out) == 0
|
||||
|| !testenv.has(out.stderr,
|
||||
"ww: dependency cycle in initialization closure")
|
||||
"ww: dependency cycle: p -> q -> r -> p")
|
||||
|| testenv.readfile(trace).len != 0
|
||||
|| testenv.listdir(work).len != 0) {
|
||||
fail("test-cycle", out.stderr);
|
||||
|
||||
Reference in New Issue
Block a user