test: prove platform filename selection
This commit is contained in:
@@ -260,11 +260,12 @@ until `ww init` gives it a stable module/package identity.
|
|||||||
|
|
||||||
### 3.1 One directory, one package
|
### 3.1 One directory, one package
|
||||||
|
|
||||||
A package directory contains its immediate regular source files only. The build
|
A package directory contains its immediate regular source files and source-name
|
||||||
does not follow source symlinks. Nested directories are separate packages. Every
|
symlinks that resolve to regular files. A source-name symlink to a directory is
|
||||||
selected production source MUST begin with the same canonical `package name;`
|
ignored. Nested directories are separate packages. Every selected production
|
||||||
clause. The declared name MUST be a valid WW identifier. It need not repeat the
|
source MUST begin with the same canonical `package name;` clause. The declared
|
||||||
directory leaf because identity and source qualifier are separate concepts.
|
name MUST be a valid WW identifier. It need not repeat the directory leaf
|
||||||
|
because identity and source qualifier are separate concepts.
|
||||||
|
|
||||||
The following current forms are errors after the migration:
|
The following current forms are errors after the migration:
|
||||||
|
|
||||||
@@ -279,41 +280,47 @@ still the smallest package and needs no extra metadata.
|
|||||||
|
|
||||||
### 3.2 File membership and target selection
|
### 3.2 File membership and target selection
|
||||||
|
|
||||||
Production candidates are immediate regular files ending `.ww`, excluding
|
The current toolchain has one honest target, `linux/amd64`. Production
|
||||||
`*_test.ww` and generated outputs. Names are byte-sorted after UTF-8 validity and
|
candidates are immediate visible names ending `.ww`, excluding selected
|
||||||
normalization checks. A source symlink, duplicate normalized name, case-fold
|
`*_test.ww` files. Directory entries beginning `.` or `_` are ignored. Candidate
|
||||||
collision, or non-regular candidate is a loud error on every host.
|
names are byte-sorted before any selected source is opened, parsed, or checked.
|
||||||
|
|
||||||
Target variants use this only convention:
|
WW applies Go 1.26.5's filename suffix algorithm to the portion of the basename
|
||||||
|
before its first dot. A final `_test` token is removed for this decision. If the
|
||||||
|
last two remaining underscore-delimited tokens are a known OS followed by a
|
||||||
|
known architecture, both must match `linux/amd64`. Otherwise a final known OS
|
||||||
|
or architecture must match. A known mismatch excludes the file; an unknown or
|
||||||
|
misplaced token leaves it ordinary. The pinned known sets are:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
stem[+os][+arch][+environment].ww
|
OS: aix android darwin dragonfly freebsd hurd illumos ios js linux nacl
|
||||||
|
netbsd openbsd plan9 solaris wasip1 windows zos
|
||||||
|
ARCH: 386 amd64 amd64p32 arm armbe arm64 arm64be loong64 mips mipsle
|
||||||
|
mips64 mips64le mips64p32 mips64p32le ppc ppc64 ppc64le riscv
|
||||||
|
riscv64 s390 s390x sparc sparc64 wasm
|
||||||
```
|
```
|
||||||
|
|
||||||
Recognized tags come from the selected target descriptor, not from the host.
|
The suffix requires a nonempty prefix and an underscore. Thus `linux.ww` and
|
||||||
Files are grouped by `stem`. The matching member with the greatest number of
|
`plan9_test.ww` are ordinary files, `x_plan9_test.ww` is excluded,
|
||||||
tags wins; the untagged member is the fallback. Two equally specific matches are
|
`x_linux_amd64.ww` is selected, and `x_windows_amd64.ww` is excluded. The first
|
||||||
an error. Examples are `poll.ww`, `poll+linux.ww`, and
|
dot ends inspection: `x.extra_windows.ww` is ordinary. Pair recognition takes
|
||||||
`poll+linux+amd64+gnu.ww`. This is replacement selection, not additive feature
|
precedence over the final single token; `x_windows_amd64.ww` does not match just
|
||||||
selection; additive code uses a distinct stem. Unknown tags are errors. There
|
because `amd64` does. Conversely `x_amd64_linux.ww` has no OS/architecture pair
|
||||||
are no boolean selectors, glob expressions, or manifest-defined tag meanings.
|
and matches its final single `linux` token, exactly as Go does.
|
||||||
|
|
||||||
Test variants put the same tags before the reserved suffix, for example
|
Selection is additive, not replacement-based: every matching file belongs to
|
||||||
`poll+linux_test.ww`; their grammar is `stem[+tags]_test.ww` and the identical
|
the package. The production variant then excludes `*_test.ww`; internal and
|
||||||
most-specific rule applies within the test set. A production stem ending
|
external test classification uses only the already platform-selected test
|
||||||
`_test` is reserved and rejected, preventing a tagged test from being mistaken
|
files. An excluded file creates no source occurrence, import, dependency edge,
|
||||||
for production source.
|
package/action/variant identity, compiler input, export, archive member, link
|
||||||
|
input, artifact, status, or persistence dependency. Adding or editing one is a
|
||||||
|
producer no-op. Adding, removing, or editing a selected file changes the owning
|
||||||
|
unit normally.
|
||||||
|
|
||||||
The selected file-name list is itself an action-key input. Therefore adding or
|
WW implements no source-level build expressions, user tags, target descriptor,
|
||||||
removing a more-specific file invalidates the package even when the old files'
|
`UseAllFiles` escape, `+tag` replacement scheme, or manifest-defined selector.
|
||||||
bytes do not change.
|
Those would introduce a second build language or a manifest model and are
|
||||||
|
outside the local, manifest-free product.
|
||||||
CPU features and optimization mode always enter the compile key but do not add
|
|
||||||
another WW source-selection language. WW-level specialization uses compiler
|
|
||||||
intrinsics/runtime dispatch or a distinct package; CPU/float-ABI/PIC-sensitive C
|
|
||||||
or assembly uses the finite native `when` constraints in section 8.4. This keeps
|
|
||||||
ordinary source membership conventional while still making exceptional native
|
|
||||||
selection exact and inspectable.
|
|
||||||
|
|
||||||
### 3.3 Imports, names, and resolution
|
### 3.3 Imports, names, and resolution
|
||||||
|
|
||||||
@@ -5132,7 +5139,7 @@ first regenerated byte-identical semantic export.
|
|||||||
|
|
||||||
The owner source voucher remains `<action>.unit.ww`; a linked product root also
|
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
|
owns `<root>.init.unit.ww` for its dispatcher unit, `.init.s`, `.init.o`, and
|
||||||
two-member archive. Current persistent formats are build 17 and test 16. Warm
|
two-member archive. Current persistent formats are build 18 and test 17. Warm
|
||||||
consumers select a dependency's staged `.wwi.new` or `.a.new` when that exact
|
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
|
action changed in the same request. All action artifacts, init artifacts, tool
|
||||||
identity copies, stamp, library/executable publications, and test statuses are
|
identity copies, stamp, library/executable publications, and test statuses are
|
||||||
@@ -5192,6 +5199,151 @@ persistent-workdir, rejection-state, byte-identity, and bootstrap observers own
|
|||||||
their unchanged broader boundaries. Grouped imports, quoted imports, and dot
|
their unchanged broader boundaries. Grouped imports, quoted imports, and dot
|
||||||
imports remain deliberately unimplemented.
|
imports remain deliberately unimplemented.
|
||||||
|
|
||||||
|
### 11.21 Implemented Go platform filename eligibility
|
||||||
|
|
||||||
|
Directory packages now apply Go 1.26.5's OS/architecture filename rule before
|
||||||
|
a source can enter WW's production or test graph. This closes a loader-wide
|
||||||
|
divergence rather than adding a syntax feature: WW remains a local,
|
||||||
|
manifest-free toolchain with unquoted dotted imports and one supported target,
|
||||||
|
`linux/amd64`.
|
||||||
|
|
||||||
|
#### Pinned Go evidence and pre-fix divergence
|
||||||
|
|
||||||
|
The reference is official Go 1.26.5 at commit
|
||||||
|
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||||
|
|
||||||
|
- `Context.matchFile` first rejects leading-dot/underscore names and unrelated
|
||||||
|
extensions, calls `goodOSArchFile`, and only then joins and opens the source
|
||||||
|
([`go/build/build.go`, lines 1438–1509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509)).
|
||||||
|
- `goodOSArchFile` cuts at the first dot, requires an underscore-prefixed
|
||||||
|
suffix, removes a final `test` token, gives a known OS/architecture pair
|
||||||
|
precedence over a final known single token, and treats every other suffix as
|
||||||
|
ordinary
|
||||||
|
([`go/build/build.go`, lines 1980–2027](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1980-L2027)).
|
||||||
|
Its match operation is against the selected `GOOS`/`GOARCH`, with only the
|
||||||
|
documented Android/Linux, illumos/Solaris, and iOS/Darwin aliases
|
||||||
|
([`go/build/build.go`, lines 1933–1977](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1933-L1977)).
|
||||||
|
- The exact past, present, and future filename-recognition sets are
|
||||||
|
`syslist.KnownOS` and `syslist.KnownArch`; they are intentionally broader than
|
||||||
|
currently supported targets and explicitly must not lose old names
|
||||||
|
([`internal/syslist/syslist.go`, lines 14–36 and 56–83](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/syslist/syslist.go#L14-L83)).
|
||||||
|
- `go/build` requires sorted directory presentation, its ordinary reader uses
|
||||||
|
byte-sorted names, and package classification consumes that order
|
||||||
|
([`go/build/build.go`, lines 108–111 and 193–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L207),
|
||||||
|
[lines 859–914](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L914),
|
||||||
|
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125)).
|
||||||
|
- The official `TestMatchFile` table accepts `android.go`, `plan9.go`, and
|
||||||
|
`plan9_test.go` as whole-name ordinary files, accepts matching architecture
|
||||||
|
and Android/Linux aliases, and rejects a mismatching `foo_darwin.go`
|
||||||
|
([`go/build/build_test.go`, lines 381–425](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L381-L425)).
|
||||||
|
Command testdata independently proves that a selected Linux suffix contributes
|
||||||
|
its file and import on `linux/amd64` and both disappear on Darwin
|
||||||
|
([`cmd/go/testdata/script/list_constraints.txt`, lines 1–29 and 57–60](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_constraints.txt#L1-L60)).
|
||||||
|
An explicit package whose files are all excluded is rejected
|
||||||
|
([`build_no_go.txt`, lines 1–17 and 31–41](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_no_go.txt#L1-L41)).
|
||||||
|
|
||||||
|
Before this slice, both drivers accepted every visible `.ww` entry apart from
|
||||||
|
the production/test partition, and `internal/wwpackage` discovered every such
|
||||||
|
entry recursively. They opened and parsed candidates in raw filesystem order.
|
||||||
|
On Linux/amd64, a malformed `bad_windows.ww` therefore rejected the request;
|
||||||
|
an otherwise valid `platform_windows_arm64.ww` could add imports, actions,
|
||||||
|
direct `.wwi` inputs, archives, linker inputs, initialization, and runtime
|
||||||
|
behavior; wrong-target internal and external tests ran; a directory containing
|
||||||
|
only `only_windows.ww` was selected recursively; and editing an ineligible file
|
||||||
|
recompiled its owner. Cstage and WWstage agreed with each other but were both
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
#### Final source and graph ownership
|
||||||
|
|
||||||
|
The basename predicate is exact and allocation-free. It examines the stem
|
||||||
|
before the first dot, removes final `_test` for suffix analysis, then recognizes
|
||||||
|
only the pinned Go `KnownOS`/`KnownArch` sets. A recognized pair must be
|
||||||
|
`linux_amd64`; a recognized final single must be `linux` or `amd64`. Unknown or
|
||||||
|
misplaced tokens remain ordinary. There is no alias-, declared-name-, path-leaf-,
|
||||||
|
physical-directory-, artifact-, or request-order input to this decision.
|
||||||
|
|
||||||
|
Both drivers first collect every visible `.ww` basename in checked dynamically
|
||||||
|
grown storage, byte-sort the names, then apply target and production/test
|
||||||
|
eligibility before source stat/open/parse and package validation. This removes
|
||||||
|
the former filesystem-order diagnostic race and adds no fixed file bound. The
|
||||||
|
shared coordinator already sorts directory entries; its source predicate now
|
||||||
|
removes a mismatching basename before it is appended to discovery or grouped
|
||||||
|
into a package/test product. A recursive pattern skips a directory with no
|
||||||
|
eligible sources. An explicit directory with no eligible production source
|
||||||
|
retains WW's stable `directory contains no WW package sources` rejection.
|
||||||
|
|
||||||
|
Eligibility owns whether a source occurrence exists. For a selected file, the
|
||||||
|
parser and checker retain its exact file-local imports, aliases, blank
|
||||||
|
occurrences, positions, and declarations, and the package graph deduplicates
|
||||||
|
their resolved canonical targets exactly as before. For an excluded file there
|
||||||
|
is no occurrence to resolve: missing, self, cycle, final-`internal`, vendor, and
|
||||||
|
imported-`main` validation do not run, and the file contributes no canonical
|
||||||
|
dependency or action. This is source/file ownership before package-graph
|
||||||
|
ownership, never another identity dimension.
|
||||||
|
|
||||||
|
#### Build, test, artifacts, and execution
|
||||||
|
|
||||||
|
Production sees all matching non-test sources. The internal-test variant sees
|
||||||
|
that production category followed by matching same-package `*_test.ww` files;
|
||||||
|
the external variant sees only matching external `*_test.ww` files. The suffix
|
||||||
|
rule therefore removes wrong-target test-only imports and initialization before
|
||||||
|
variant construction, support generation, or generated-main generation.
|
||||||
|
`plan9_test.ww` remains ordinary because the suffix has no nonempty prefix;
|
||||||
|
`x_plan9_test.ww` is excluded; first-dot and pair-precedence cases behave like
|
||||||
|
the pinned Go table.
|
||||||
|
|
||||||
|
No checker, interface writer, assembler, archiver, or linker protocol changed.
|
||||||
|
The drivers simply stop excluded bytes before those owners. Each selected
|
||||||
|
package unit still contains its category-ordered source files and exact import
|
||||||
|
occurrences. The compiler still receives one byte-sorted direct `.wwi` input per
|
||||||
|
canonical edge; `.wwi` still contains only semantic exports; archives still
|
||||||
|
contain only their canonical package action (plus the command root dispatcher
|
||||||
|
member where applicable); and the linker still receives the root plus reachable
|
||||||
|
archive-only closure. An import found only in an excluded file therefore
|
||||||
|
creates no `.wwi`, object, archive, init task, dispatcher edge, linker argument,
|
||||||
|
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
|
||||||
|
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
|
||||||
|
product policy may still relink an explicitly requested executable from its
|
||||||
|
unchanged archives. A selected private implementation edit rebuilds its owner;
|
||||||
|
if its `.wwi` is byte-identical, reverse compilation stops and only affected
|
||||||
|
products relink.
|
||||||
|
|
||||||
|
Wrong-target malformed sources and wrong-target structural import sites are
|
||||||
|
ignored without producers. Selected structural failures are reported in
|
||||||
|
byte-sorted filename order before producers. Any later selected-source compiler
|
||||||
|
failure remains inside the existing request transaction: staged dependency
|
||||||
|
changes are discarded, all prior actions/tool records/stamps/publications stay
|
||||||
|
byte-identical, no `.new` generation survives, and no mixed package or test
|
||||||
|
result is published.
|
||||||
|
|
||||||
|
`cmd/ww/main.c` and `selfhost/cmd/ww/main.ww` mechanically mirror direct
|
||||||
|
enumeration, sorting, target filtering, and checked allocation. The shared
|
||||||
|
`internal/wwpackage/package.ww` predicate owns recursive build/test discovery.
|
||||||
|
The compiler/checker/writer consume only selected units and require no special
|
||||||
|
case; `w6a` and `w6l` remain unchanged. The focused native
|
||||||
|
`platform_filename_source_selection` observer generates independent cold and
|
||||||
|
persistent Cstage/WWstage work roots and proves exact suffix edge cases,
|
||||||
|
sorted diagnostics, direct and recursive build/test selection, production/test
|
||||||
|
isolation, repeated-edge canonicalization, exact compiler/assembler/linker
|
||||||
|
argv, archive-only closure, artifact/assembly/binary equality, reversed-root
|
||||||
|
independence, runtime results, ignored-edit reuse, `.wwi`-stable reverse
|
||||||
|
propagation, and late-failure rollback. Existing dynamic-allocation,
|
||||||
|
no-follow, byte-identity, bootstrap, internal, vendor, and imported-command
|
||||||
|
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.
|
||||||
|
|
||||||
## 12. Candidate architectures and hard-gate decision
|
## 12. Candidate architectures and hard-gate decision
|
||||||
|
|
||||||
Five candidates were developed as coherent systems, not as feature bins.
|
Five candidates were developed as coherent systems, not as feature bins.
|
||||||
|
|||||||
14
docs/spec.md
14
docs/spec.md
@@ -255,6 +255,20 @@ ImportPath = ident { "." ident } .
|
|||||||
`.ww` files sharing one declared package name compiles as one package. The
|
`.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
|
declared name need not equal the directory name or the final component of its
|
||||||
canonical import identity.
|
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
|
||||||
|
architecture token must match `linux` or `amd64`; a final known OS followed
|
||||||
|
by a known architecture takes precedence and both must match. The known-name
|
||||||
|
sets are Go 1.26.5's `syslist.KnownOS` and `syslist.KnownArch`. Unknown or
|
||||||
|
misplaced suffixes are ordinary, and a platform word without a nonempty
|
||||||
|
underscore prefix is ordinary (`linux.ww` and `plan9_test.ww` are selected;
|
||||||
|
`x_windows.ww` and `x_plan9_test.ww` are not). Leading-dot/underscore entries
|
||||||
|
are ignored. Eligible names are byte-sorted before source validation.
|
||||||
|
Production excludes selected `*_test.ww`; test variants classify only those
|
||||||
|
selected test files. An excluded file contributes no declarations, imports,
|
||||||
|
package edge, action, export, artifact, initialization, test, or persistent
|
||||||
|
invalidation.
|
||||||
- `import acme.codec;` loads the canonical package `acme.codec`. If that
|
- `import acme.codec;` loads the canonical package `acme.codec`. If that
|
||||||
package declares `package wire;`, the importing file sees its exported names
|
package declares `package wire;`, the importing file sees its exported names
|
||||||
as `wire.Name`; `codec.Name` is not an additional binding. An explicit alias
|
as `wire.Name`; `codec.Name` is not an additional binding. An explicit alias
|
||||||
|
|||||||
@@ -224,6 +224,19 @@ run always executes from the temp root. Without `-c`, it removes the
|
|||||||
temporary binary and scratch with its workspace. The language runtime
|
temporary binary and scratch with its workspace. The language runtime
|
||||||
owns individual `@test` functions.
|
owns individual `@test` functions.
|
||||||
|
|
||||||
|
Before package grouping, both directory drivers and the shared recursive
|
||||||
|
coordinator apply Go 1.26.5's filename OS/architecture rule for WW's fixed
|
||||||
|
`linux/amd64` target. The basename stem ends at its first dot; a final `_test`
|
||||||
|
token is removed for matching; a recognized OS/architecture pair takes
|
||||||
|
precedence over a recognized final single token; and unknown or misplaced
|
||||||
|
tokens remain ordinary. Wrong-target production, same-package test, and
|
||||||
|
external-test files therefore create no imports, variants, generated-main
|
||||||
|
inputs, runtime tests, artifacts, or persistent invalidation. Names are
|
||||||
|
byte-sorted before selected-source validation, so diagnostics do not depend on
|
||||||
|
directory entry order. A recursive pattern omits a directory with no eligible
|
||||||
|
source, while an explicit wrong-target-only build rejects it as having no WW
|
||||||
|
package source. There is no source-level build-expression or user-tag mode.
|
||||||
|
|
||||||
Separate compilation is the only driver build path; no compatibility mode
|
Separate compilation is the only driver build path; no compatibility mode
|
||||||
switch remains.
|
switch remains.
|
||||||
|
|
||||||
@@ -255,6 +268,19 @@ exact-argv, command, and persistent-workdir observers, the package suite proves
|
|||||||
archive-only link argv and exact warm/rejection-state behavior without
|
archive-only link argv and exact warm/rejection-state behavior without
|
||||||
duplicating those broader mechanisms in this observer.
|
duplicating those broader mechanisms in this observer.
|
||||||
|
|
||||||
|
The same package owner contains the focused
|
||||||
|
`platform_filename_source_selection` observer. It independently generates the
|
||||||
|
suffix matrix, production/internal/external sources, wrong-target import and
|
||||||
|
malformed sentinels, wrong-target-only directories, and reverse-created
|
||||||
|
diagnostic files. Across cold and persistent Cstage/WWstage roots it compares
|
||||||
|
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.
|
||||||
|
|
||||||
`test/sep/sepinit_test.ww` is the single focused package-initialization owner.
|
`test/sep/sepinit_test.ww` is the single focused package-initialization owner.
|
||||||
It generates all source trees temporarily and runs independent cold/persistent
|
It generates all source trees temporarily and runs independent cold/persistent
|
||||||
Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
||||||
|
|||||||
@@ -5118,6 +5118,637 @@ fn hexbytes(value: str) str = {
|
|||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@test fn platform_filename_source_selection() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let source: str = strings.concat(root, "/source");
|
||||||
|
let app: str = strings.concat(source, "/app");
|
||||||
|
let good: str = strings.concat(source, "/dep/good");
|
||||||
|
let pkg: str = strings.concat(source, "/pkg");
|
||||||
|
let testgood: str = strings.concat(source, "/test/good");
|
||||||
|
let wrongonly: str = strings.concat(source, "/wrongonly");
|
||||||
|
let notests: str = strings.concat(source, "/notests");
|
||||||
|
let internal: str = strings.concat(source, "/foreign/internal/secret");
|
||||||
|
let command: str = strings.concat(source, "/command");
|
||||||
|
let vendored: str = strings.concat(app, "/vendor/vendored");
|
||||||
|
let order: str = strings.concat(root, "/order");
|
||||||
|
let tools: str = strings.concat(root, "/tools");
|
||||||
|
mkdirall(app); mkdirall(good); mkdirall(pkg); mkdirall(testgood);
|
||||||
|
mkdirall(wrongonly); mkdirall(notests); mkdirall(internal);
|
||||||
|
mkdirall(command); mkdirall(vendored); mkdirall(order); mkdirall(tools);
|
||||||
|
|
||||||
|
let good5: str = strings.concat("package good;\n",
|
||||||
|
"export fn value() i32 = { return 5; };\n");
|
||||||
|
let good6: str = strings.concat("package good;\n",
|
||||||
|
"export fn value() i32 = { return 6; };\n");
|
||||||
|
let good7: str = strings.concat("package good;\n",
|
||||||
|
"export fn value() i32 = { return 7; };\n");
|
||||||
|
let appmain: str = strings.concat(
|
||||||
|
"package main;\nimport dep.good;\n",
|
||||||
|
"fn main() i32 = { return good.value() + wholelinux() + ",
|
||||||
|
"afterdot() + arch() + reversed() + future() + osname() + pair(); };\n");
|
||||||
|
let wholelinux: str =
|
||||||
|
"package main;\nfn wholelinux() i32 = { return 1; };\n";
|
||||||
|
let afterdot: str =
|
||||||
|
"package main;\nfn afterdot() i32 = { return 1; };\n";
|
||||||
|
let arch: str =
|
||||||
|
"package main;\nfn arch() i32 = { return 1; };\n";
|
||||||
|
let reversed: str =
|
||||||
|
"package main;\nfn reversed() i32 = { return 1; };\n";
|
||||||
|
let future: str =
|
||||||
|
"package main;\nfn future() i32 = { return 1; };\n";
|
||||||
|
let osname: str = strings.concat(
|
||||||
|
"package main;\nimport _ dep.good;\n",
|
||||||
|
"fn osname() i32 = { return 1; };\n");
|
||||||
|
let pair: str =
|
||||||
|
"package main;\nfn pair() i32 = { return 1; };\n";
|
||||||
|
let ignoredparse: str =
|
||||||
|
"this wrong-target source is deliberately malformed\n";
|
||||||
|
let ignoredparseedit: str =
|
||||||
|
"a different malformed wrong-target edit {\n";
|
||||||
|
let ignoreddep: str = strings.concat(
|
||||||
|
"package main;\nimport dep.wrong;\n",
|
||||||
|
"fn wrong_dep() i32 = { return wrong.value(); };\n");
|
||||||
|
let ignoredinternal: str = strings.concat(
|
||||||
|
"package main;\nimport foreign.internal.secret;\n",
|
||||||
|
"fn wrong_internal() i32 = { return secret.value(); };\n");
|
||||||
|
let ignoredmain: str = strings.concat(
|
||||||
|
"package main;\nimport command;\n",
|
||||||
|
"fn wrong_main() i32 = { return 0; };\n");
|
||||||
|
let ignoredvendor: str = strings.concat(
|
||||||
|
"package main;\nimport vendored;\n",
|
||||||
|
"fn wrong_vendor() i32 = { return vendored.value(); };\n");
|
||||||
|
writefile(strings.concat(good, "/good.ww"), good5);
|
||||||
|
writefile(strings.concat(app, "/main.ww"), appmain);
|
||||||
|
writefile(strings.concat(app, "/linux.ww"), wholelinux);
|
||||||
|
writefile(strings.concat(app, "/platform.extra_windows.ww"), afterdot);
|
||||||
|
writefile(strings.concat(app, "/platform_amd64.ww"), arch);
|
||||||
|
writefile(strings.concat(app, "/platform_amd64_linux.ww"), reversed);
|
||||||
|
writefile(strings.concat(app, "/platform_future.ww"), future);
|
||||||
|
writefile(strings.concat(app, "/platform_linux.ww"), osname);
|
||||||
|
writefile(strings.concat(app, "/platform_linux_amd64.ww"), pair);
|
||||||
|
writefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
|
||||||
|
writefile(strings.concat(app, "/baddep_arm64.ww"), ignoreddep);
|
||||||
|
writefile(strings.concat(app, "/badinternal_windows_amd64.ww"),
|
||||||
|
ignoredinternal);
|
||||||
|
writefile(strings.concat(app, "/badmain_linux_arm64.ww"), ignoredmain);
|
||||||
|
writefile(strings.concat(app, "/badvendor_windows.ww"), ignoredvendor);
|
||||||
|
writefile(strings.concat(internal, "/secret.ww"), strings.concat(
|
||||||
|
"package secret;\n",
|
||||||
|
"export fn value() i32 = { return 19; };\n"));
|
||||||
|
writefile(strings.concat(command, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 0; };\n");
|
||||||
|
writefile(strings.concat(vendored, "/vendored.ww"), strings.concat(
|
||||||
|
"package vendored;\n",
|
||||||
|
"export fn value() i32 = { return 23; };\n"));
|
||||||
|
|
||||||
|
let pkgbase: str = strings.concat("package pkg;\n",
|
||||||
|
"export fn value() i32 = { return 7; };\n");
|
||||||
|
let samepair: str = strings.concat(
|
||||||
|
"package pkg;\nimport test.good;\n",
|
||||||
|
"@test fn selected_internal_pair() void = { ",
|
||||||
|
"assert(value() + good.value() == 18); };\n");
|
||||||
|
let samewhole: str = strings.concat(
|
||||||
|
"package pkg;\n",
|
||||||
|
"@test fn selected_whole_plan9_name() void = { assert(value() == 7); };\n");
|
||||||
|
let samereversed: str = strings.concat(
|
||||||
|
"package pkg;\n",
|
||||||
|
"@test fn selected_reversed_suffix() void = { assert(value() == 7); };\n");
|
||||||
|
let externalpair: str = strings.concat(
|
||||||
|
"package pkg_test;\nimport pkg;\nimport test.good;\n",
|
||||||
|
"@test fn selected_external_pair() void = { ",
|
||||||
|
"assert(pkg.value() + good.value() == 18); };\n");
|
||||||
|
let externaldot: str = strings.concat(
|
||||||
|
"package pkg_test;\nimport pkg;\n",
|
||||||
|
"@test fn selected_external_after_dot() void = { ",
|
||||||
|
"assert(pkg.value() == 7); };\n");
|
||||||
|
let wrongtest: str = strings.concat(
|
||||||
|
"package pkg;\nimport test.wrong;\n",
|
||||||
|
"@test fn wrong_target_test() void = { abort(\"wrong test ran\"); };\n");
|
||||||
|
let wrongtestedit: str =
|
||||||
|
"this edited wrong-target test remains deliberately malformed\n";
|
||||||
|
writefile(strings.concat(pkg, "/base.ww"), pkgbase);
|
||||||
|
writefile(strings.concat(pkg, "/internal_linux_amd64_test.ww"), samepair);
|
||||||
|
writefile(strings.concat(pkg, "/plan9_test.ww"), samewhole);
|
||||||
|
writefile(strings.concat(pkg, "/reverse_amd64_linux_test.ww"),
|
||||||
|
samereversed);
|
||||||
|
writefile(strings.concat(pkg, "/external_linux_amd64_test.ww"),
|
||||||
|
externalpair);
|
||||||
|
writefile(strings.concat(pkg, "/external.extra_windows_test.ww"),
|
||||||
|
externaldot);
|
||||||
|
writefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
|
||||||
|
wrongtest);
|
||||||
|
writefile(strings.concat(pkg, "/external_linux_arm64_test.ww"),
|
||||||
|
wrongtest);
|
||||||
|
writefile(strings.concat(pkg, "/x_plan9_test.ww"), wrongtest);
|
||||||
|
writefile(strings.concat(testgood, "/good.ww"), strings.concat(
|
||||||
|
"package good;\n",
|
||||||
|
"export fn value() i32 = { return 11; };\n"));
|
||||||
|
writefile(strings.concat(wrongonly, "/only_windows.ww"), ignoredparse);
|
||||||
|
writefile(strings.concat(notests, "/base.ww"),
|
||||||
|
"package notests;\nexport fn value() i32 = { return 1; };\n");
|
||||||
|
writefile(strings.concat(notests, "/only_windows_test.ww"), ignoredparse);
|
||||||
|
// Creation order is deliberately the inverse of byte order.
|
||||||
|
writefile(strings.concat(order, "/z_linux.ww"),
|
||||||
|
"package order;\n@test fn z() void = { };\n");
|
||||||
|
writefile(strings.concat(order, "/a_linux.ww"),
|
||||||
|
"package order;\n@test fn a() void = { };\n");
|
||||||
|
|
||||||
|
let compilerwrapper: str = strings.concat(tools, "/w6c.sh");
|
||||||
|
let assemblerwrapper: str = strings.concat(tools, "/w6a.sh");
|
||||||
|
let linkerwrapper: str = strings.concat(tools, "/w6l.sh");
|
||||||
|
writeexecutable(compilerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_COMPILER_TRACE\"\n",
|
||||||
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
|
"\"$WW_PLATFORM_COMPILER_TRACE\"; done\n",
|
||||||
|
"printf '\\n' >> \"$WW_PLATFORM_COMPILER_TRACE\"\n",
|
||||||
|
"exec \"$WW_PLATFORM_REAL_COMPILER\" \"$@\"\n"));
|
||||||
|
writeexecutable(assemblerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_ASSEMBLER_TRACE\"\n",
|
||||||
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
|
"\"$WW_PLATFORM_ASSEMBLER_TRACE\"; done\n",
|
||||||
|
"printf '\\n' >> \"$WW_PLATFORM_ASSEMBLER_TRACE\"\n",
|
||||||
|
"exec \"$WW_PLATFORM_REAL_ASSEMBLER\" \"$@\"\n"));
|
||||||
|
writeexecutable(linkerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PLATFORM_LINKER_TRACE\"\n",
|
||||||
|
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||||
|
"\"$WW_PLATFORM_LINKER_TRACE\"; done\n",
|
||||||
|
"printf '\\n' >> \"$WW_PLATFORM_LINKER_TRACE\"\n",
|
||||||
|
"exec \"$WW_PLATFORM_REAL_LINKER\" \"$@\"\n"));
|
||||||
|
|
||||||
|
let stages: []str = ["ww", "ww_ww"];
|
||||||
|
let compilers: []str = ["w6c", "w6c_ww"];
|
||||||
|
let assemblers: []str = ["w6a", "w6a_ww"];
|
||||||
|
let linkers: []str = ["w6l", "w6l_ww"];
|
||||||
|
let labels: []str = ["c", "ww"];
|
||||||
|
let artifactnames: []str = ["app.unit.ww", "app.wwi", "app.s",
|
||||||
|
"app.o", "app.a", "app.init.unit.ww", "app.init.s", "app.init.o",
|
||||||
|
"dep.good.unit.ww", "dep.good.wwi", "dep.good.s", "dep.good.o",
|
||||||
|
"dep.good.a"];
|
||||||
|
let artifactrefs: []str = ["", "", "", "", "", "", "", "", "",
|
||||||
|
"", "", "", ""];
|
||||||
|
let testartifactnames: []str = ["pkg.unit.ww", "pkg.wwi", "pkg.a",
|
||||||
|
"pkg-internal-test.unit.ww", "pkg-internal-test.wwi",
|
||||||
|
"pkg-internal-test.a", "pkg_test-external-test.unit.ww",
|
||||||
|
"pkg_test-external-test.wwi", "pkg_test-external-test.a",
|
||||||
|
"pkg-internal-test-main.a", "pkg_test-external-test-main.a"];
|
||||||
|
let testartifactrefs: []str = ["", "", "", "", "", "", "", "",
|
||||||
|
"", "", ""];
|
||||||
|
let binref: str = "";
|
||||||
|
let compilerref: str = "";
|
||||||
|
let assemblerref: str = "";
|
||||||
|
let linkerref: str = "";
|
||||||
|
let prodarchiveref: str = "";
|
||||||
|
let prodwwiref: str = "";
|
||||||
|
let testoutref: str = "";
|
||||||
|
let testerrref: str = "";
|
||||||
|
let faildiagref: str = "";
|
||||||
|
let recursiveoutref: str = "";
|
||||||
|
let recursiveerrref: str = "";
|
||||||
|
let baseenv: []str = os.getenvs();
|
||||||
|
let si: i32 = 0;
|
||||||
|
for (si < stages.len) {
|
||||||
|
rewritefile(strings.concat(good, "/good.ww"), good5);
|
||||||
|
rewritefile(strings.concat(app, "/platform_future.ww"), future);
|
||||||
|
rewritefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
|
||||||
|
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
|
||||||
|
wrongtest);
|
||||||
|
let work: str = strings.concat(root, "/", labels[si], "-work");
|
||||||
|
let reversework: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-reverse-work");
|
||||||
|
let outdir: str = strings.concat(root, "/", labels[si], "-out");
|
||||||
|
let reverseout: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-reverse-out");
|
||||||
|
let compilertrace: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-compiler");
|
||||||
|
let assemblertrace: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-assembler");
|
||||||
|
let linkertrace: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-linker");
|
||||||
|
assert(os.mkdir(work, 448i32) == 0);
|
||||||
|
assert(os.mkdir(reversework, 448i32) == 0);
|
||||||
|
assert(os.mkdir(outdir, 448i32) == 0);
|
||||||
|
assert(os.mkdir(reverseout, 448i32) == 0);
|
||||||
|
writefile(compilertrace, ""); writefile(assemblertrace, "");
|
||||||
|
writefile(linkertrace, "");
|
||||||
|
let env: []str = alloc([], (baseenv.len + 9): u64)!;
|
||||||
|
let ei: i32 = 0;
|
||||||
|
for (ei < baseenv.len) {
|
||||||
|
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei], "WW_W6A=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_COMPILER_TRACE=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_ASSEMBLER_TRACE=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_LINKER_TRACE=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_REAL_COMPILER=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_REAL_ASSEMBLER=")
|
||||||
|
&& !strings.hasprefix(baseenv[ei],
|
||||||
|
"WW_PLATFORM_REAL_LINKER=")) {
|
||||||
|
append(env, baseenv[ei]);
|
||||||
|
};
|
||||||
|
ei += 1;
|
||||||
|
};
|
||||||
|
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||||
|
append(env, strings.concat("WW_W6A=", assemblerwrapper));
|
||||||
|
append(env, strings.concat("WW_W6L=", linkerwrapper));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_COMPILER_TRACE=", compilertrace));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_ASSEMBLER_TRACE=", assemblertrace));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_LINKER_TRACE=", linkertrace));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_REAL_COMPILER=",
|
||||||
|
driver(compilers[si])));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_REAL_ASSEMBLER=",
|
||||||
|
driver(assemblers[si])));
|
||||||
|
append(env, strings.concat("WW_PLATFORM_REAL_LINKER=",
|
||||||
|
driver(linkers[si])));
|
||||||
|
|
||||||
|
let forward: []str = [driver(stages[si]), "build", "-w", work,
|
||||||
|
"-I", source, "-o", strings.concat(outdir, "/"), app, good];
|
||||||
|
let reverse: []str = [driver(stages[si]), "build", "-w", reversework,
|
||||||
|
"-I", source, "-o", strings.concat(reverseout, "/"), good, app];
|
||||||
|
let out: commandout;
|
||||||
|
runcommandenv(root, strings.concat("platform-cold-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
|
let ctrace: str = readfile(compilertrace);
|
||||||
|
let atrace: str = readfile(assemblertrace);
|
||||||
|
let ltrace: str = readfile(linkertrace);
|
||||||
|
assert(occurrences(ctrace, "\n") == 2);
|
||||||
|
assert(occurrences(atrace, "\n") == 3);
|
||||||
|
assert(occurrences(ltrace, "\n") == 1);
|
||||||
|
let appline: str = linecontaining(ctrace, "/app.unit.new");
|
||||||
|
assert(occurrences(appline, "<--import><dep.good>") == 1);
|
||||||
|
assert(occurrences(appline, "/dep.good.wwi.new>") == 1);
|
||||||
|
assert(!has(ctrace, "dep.wrong"));
|
||||||
|
assert(!has(ctrace, "foreign.internal.secret"));
|
||||||
|
assert(!has(ctrace, "vendored"));
|
||||||
|
assert(!has(ctrace, "command.wwi"));
|
||||||
|
assert(occurrences(ltrace, strings.concat(work, "/app.a.new")) == 1);
|
||||||
|
assert(occurrences(ltrace, strings.concat(work,
|
||||||
|
"/dep.good.a.new")) == 1);
|
||||||
|
assert(!has(ltrace, ".wwi"));
|
||||||
|
assert(!has(ltrace, "dep.wrong"));
|
||||||
|
let unitprefix: str = strings.concat(
|
||||||
|
"//ww:module-reset app\n", wholelinux, "\n",
|
||||||
|
"//ww:module-reset app\n", appmain, "\n",
|
||||||
|
"//ww:module-reset app\n", afterdot, "\n",
|
||||||
|
"//ww:module-reset app\n", arch, "\n",
|
||||||
|
"//ww:module-reset app\n", reversed, "\n",
|
||||||
|
"//ww:module-reset app\n", future, "\n",
|
||||||
|
"//ww:module-reset app\n", osname, "\n",
|
||||||
|
"//ww:module-reset app\n", pair, "\n");
|
||||||
|
let appunit: str = readfile(strings.concat(work, "/app.unit.ww"));
|
||||||
|
assert(strings.hasprefix(appunit, unitprefix));
|
||||||
|
assert(has(appunit, "//ww:direct-export dep.good "));
|
||||||
|
assert(!has(appunit, "wrong_dep"));
|
||||||
|
assert(!has(appunit, "wrong_internal"));
|
||||||
|
assert(!has(appunit, "wrong_main"));
|
||||||
|
assert(!has(appunit, "wrong_vendor"));
|
||||||
|
assert(!os.exists(strings.concat(work, "/dep.wrong.unit.ww")));
|
||||||
|
let bin: str = strings.concat(outdir, "/app");
|
||||||
|
let runav: []str = [bin];
|
||||||
|
runcommand(root, strings.concat("platform-run-", labels[si]), runav,
|
||||||
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 12);
|
||||||
|
let ai: i32 = 0;
|
||||||
|
for (ai < artifactnames.len) {
|
||||||
|
let bytes: str = readfile(strings.concat(work, "/",
|
||||||
|
artifactnames[ai]));
|
||||||
|
if (si == 0) { artifactrefs[ai] = strings.dup(bytes); }
|
||||||
|
else { assert(same(artifactrefs[ai], bytes)); };
|
||||||
|
ai += 1;
|
||||||
|
};
|
||||||
|
let normalizedcompiler: str = normalizedtrace(ctrace,
|
||||||
|
strings.concat(work, "/"), outdir);
|
||||||
|
let normalizedassembler: str = normalizedtrace(atrace,
|
||||||
|
strings.concat(work, "/"), outdir);
|
||||||
|
let normalizedlinker: str = normalizedtrace(ltrace,
|
||||||
|
strings.concat(work, "/"), outdir);
|
||||||
|
if (si == 0) {
|
||||||
|
compilerref = strings.dup(normalizedcompiler);
|
||||||
|
assemblerref = strings.dup(normalizedassembler);
|
||||||
|
linkerref = strings.dup(normalizedlinker);
|
||||||
|
binref = strings.dup(readfile(bin));
|
||||||
|
} else {
|
||||||
|
assert(same(compilerref, normalizedcompiler));
|
||||||
|
assert(same(assemblerref, normalizedassembler));
|
||||||
|
assert(same(linkerref, normalizedlinker));
|
||||||
|
assert(same(binref, readfile(bin)));
|
||||||
|
};
|
||||||
|
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-reverse-", labels[si]),
|
||||||
|
reverse, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(same(readfile(bin), readfile(strings.concat(reverseout, "/app"))));
|
||||||
|
assert(same(normalizedcompiler, normalizedtrace(readfile(compilertrace),
|
||||||
|
strings.concat(reversework, "/"), reverseout)));
|
||||||
|
assert(same(normalizedassembler, normalizedtrace(readfile(assemblertrace),
|
||||||
|
strings.concat(reversework, "/"), reverseout)));
|
||||||
|
assert(same(normalizedlinker, normalizedtrace(readfile(linkertrace),
|
||||||
|
strings.concat(reversework, "/"), reverseout)));
|
||||||
|
ai = 0;
|
||||||
|
for (ai < artifactnames.len) {
|
||||||
|
assert(same(readfile(strings.concat(work, "/", artifactnames[ai])),
|
||||||
|
readfile(strings.concat(reversework, "/", artifactnames[ai]))));
|
||||||
|
ai += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let stableunit: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/app.unit.ww")));
|
||||||
|
let stablewwi: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/app.wwi")));
|
||||||
|
let stablearchive: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/app.a")));
|
||||||
|
let stabledepwwi: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/dep.good.wwi")));
|
||||||
|
let stablebin: str = strings.dup(readfile(bin));
|
||||||
|
let stablestamp: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/.wwtool.stamp")));
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-warm-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(occurrences(readfile(linkertrace), "\n") == 1);
|
||||||
|
|
||||||
|
rewritefile(strings.concat(app, "/badparse_windows.ww"),
|
||||||
|
ignoredparseedit);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-ignored-edit-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(occurrences(readfile(linkertrace), "\n") == 1);
|
||||||
|
assert(same(stableunit, readfile(strings.concat(work, "/app.unit.ww"))));
|
||||||
|
assert(same(stablewwi, readfile(strings.concat(work, "/app.wwi"))));
|
||||||
|
assert(same(stablearchive, readfile(strings.concat(work, "/app.a"))));
|
||||||
|
assert(same(stabledepwwi, readfile(strings.concat(work,
|
||||||
|
"/dep.good.wwi"))));
|
||||||
|
assert(same(stablebin, readfile(bin)));
|
||||||
|
assert(same(stablestamp, readfile(strings.concat(work,
|
||||||
|
"/.wwtool.stamp"))));
|
||||||
|
|
||||||
|
rewritefile(strings.concat(good, "/good.ww"), good6);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-private-edit-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(occurrences(readfile(compilertrace), "\n") == 1);
|
||||||
|
assert(has(readfile(compilertrace), "/dep.good.unit.new"));
|
||||||
|
assert(!has(readfile(compilertrace), "/app.unit.new"));
|
||||||
|
assert(occurrences(readfile(assemblertrace), "\n") == 1);
|
||||||
|
assert(occurrences(readfile(linkertrace), "\n") == 1);
|
||||||
|
assert(same(stabledepwwi, readfile(strings.concat(work,
|
||||||
|
"/dep.good.wwi"))));
|
||||||
|
assert(same(stableunit, readfile(strings.concat(work, "/app.unit.ww"))));
|
||||||
|
assert(same(stablewwi, readfile(strings.concat(work, "/app.wwi"))));
|
||||||
|
assert(same(stablearchive, readfile(strings.concat(work, "/app.a"))));
|
||||||
|
assert(!same(stablebin, readfile(bin)));
|
||||||
|
let runchanged: []str = [bin];
|
||||||
|
runcommand(root, strings.concat("platform-run-edited-", labels[si]),
|
||||||
|
runchanged, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 13);
|
||||||
|
let committeddepunit: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/dep.good.unit.ww")));
|
||||||
|
let committeddepa: str = strings.dup(readfile(strings.concat(work,
|
||||||
|
"/dep.good.a")));
|
||||||
|
let committedbin: str = strings.dup(readfile(bin));
|
||||||
|
rewritefile(strings.concat(good, "/good.ww"), good7);
|
||||||
|
rewritefile(strings.concat(app, "/platform_future.ww"),
|
||||||
|
"package main;\nfn future() i32 = { return missing_name; };\n");
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-late-failure-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stderr, "undefined: missing_name"));
|
||||||
|
let normalizedfailure: str = normalizedtrace(out.stderr,
|
||||||
|
strings.concat(work, "/"), bin);
|
||||||
|
if (si == 0) { faildiagref = strings.dup(normalizedfailure); }
|
||||||
|
else { assert(same(faildiagref, normalizedfailure)); };
|
||||||
|
assert(occurrences(readfile(compilertrace), "\n") == 2);
|
||||||
|
assert(occurrences(readfile(assemblertrace), "\n") == 1);
|
||||||
|
assert(readfile(linkertrace).len == 0);
|
||||||
|
assert(same(committeddepunit, readfile(strings.concat(work,
|
||||||
|
"/dep.good.unit.ww"))));
|
||||||
|
assert(same(committeddepa, readfile(strings.concat(work,
|
||||||
|
"/dep.good.a"))));
|
||||||
|
assert(same(committedbin, readfile(bin)));
|
||||||
|
assert(same(stablestamp, readfile(strings.concat(work,
|
||||||
|
"/.wwtool.stamp"))));
|
||||||
|
assert(!os.exists(strings.concat(work, "/dep.good.unit.new")));
|
||||||
|
assert(!os.exists(strings.concat(work, "/dep.good.wwi.new")));
|
||||||
|
assert(!os.exists(strings.concat(work, "/dep.good.a.new")));
|
||||||
|
assert(!os.exists(strings.concat(work, "/app.unit.new")));
|
||||||
|
assert(!os.exists(strings.concat(work, "/app.wwi.new")));
|
||||||
|
assert(!os.exists(strings.concat(work, "/app.a.new")));
|
||||||
|
rewritefile(strings.concat(good, "/good.ww"), good6);
|
||||||
|
rewritefile(strings.concat(app, "/platform_future.ww"), future);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-restored-", labels[si]),
|
||||||
|
forward, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(occurrences(readfile(linkertrace), "\n") == 1);
|
||||||
|
assert(same(committedbin, readfile(bin)));
|
||||||
|
|
||||||
|
rewritefile(strings.concat(good, "/good.ww"), good5);
|
||||||
|
rewritefile(strings.concat(app, "/badparse_windows.ww"), ignoredparse);
|
||||||
|
let prodwork: str = strings.concat(root, "/", labels[si], "-prod-work");
|
||||||
|
let prodout: str = strings.concat(root, "/", labels[si], "-pkg.a");
|
||||||
|
assert(os.mkdir(prodwork, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let prodav: []str = [driver(stages[si]), "build", "-w", prodwork,
|
||||||
|
"-I", source, "-o", prodout, pkg];
|
||||||
|
runcommandenv(root, strings.concat("platform-production-", labels[si]),
|
||||||
|
prodav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(occurrences(readfile(compilertrace), "\n") == 1);
|
||||||
|
assert(!has(readfile(compilertrace), "test.good"));
|
||||||
|
assert(!has(readfile(strings.concat(prodwork, "/pkg.unit.ww")),
|
||||||
|
"selected_internal"));
|
||||||
|
if (si == 0) {
|
||||||
|
prodarchiveref = strings.dup(readfile(prodout));
|
||||||
|
prodwwiref = strings.dup(readfile(strings.concat(prodout, ".wwi")));
|
||||||
|
} else {
|
||||||
|
assert(same(prodarchiveref, readfile(prodout)));
|
||||||
|
assert(same(prodwwiref, readfile(strings.concat(prodout, ".wwi"))));
|
||||||
|
};
|
||||||
|
|
||||||
|
let testwork: str = strings.concat(root, "/", labels[si], "-test-work");
|
||||||
|
assert(os.mkdir(testwork, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let testav: []str = [driver(stages[si]), "test", "-w", testwork,
|
||||||
|
"-I", source, pkg];
|
||||||
|
runcommandenv(root, strings.concat("platform-test-", labels[si]), testav,
|
||||||
|
env, (180i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "selected_internal_pair ... ok\n"));
|
||||||
|
assert(has(out.stdout, "selected_whole_plan9_name ... ok\n"));
|
||||||
|
assert(has(out.stdout, "selected_reversed_suffix ... ok\n"));
|
||||||
|
assert(has(out.stdout, "selected_external_pair ... ok\n"));
|
||||||
|
assert(has(out.stdout, "selected_external_after_dot ... ok\n"));
|
||||||
|
assert(!has(out.stdout, "wrong_target_test"));
|
||||||
|
assert(!has(out.stderr, "wrong-target"));
|
||||||
|
let testctrace: str = readfile(compilertrace);
|
||||||
|
let testltrace: str = readfile(linkertrace);
|
||||||
|
assert(!has(testctrace, "test.wrong"));
|
||||||
|
let sameline: str = linecontaining(testctrace,
|
||||||
|
"/pkg-internal-test.unit.new");
|
||||||
|
let externalline: str = linecontaining(testctrace,
|
||||||
|
"/pkg_test-external-test.unit.new");
|
||||||
|
assert(occurrences(sameline, "<--import><test.good>") == 1);
|
||||||
|
assert(occurrences(externalline, "<--import><pkg>") == 1);
|
||||||
|
assert(occurrences(externalline, "<--import><test.good>") == 1);
|
||||||
|
assert(!has(testltrace, ".wwi"));
|
||||||
|
let sameunit: str = readfile(strings.concat(testwork,
|
||||||
|
"/pkg-internal-test.unit.ww"));
|
||||||
|
let externalunit: str = readfile(strings.concat(testwork,
|
||||||
|
"/pkg_test-external-test.unit.ww"));
|
||||||
|
assert(has(sameunit, "selected_internal_pair"));
|
||||||
|
assert(has(sameunit, "selected_whole_plan9_name"));
|
||||||
|
assert(has(sameunit, "selected_reversed_suffix"));
|
||||||
|
assert(!has(sameunit, "wrong_target_test"));
|
||||||
|
assert(has(externalunit, "selected_external_pair"));
|
||||||
|
assert(has(externalunit, "selected_external_after_dot"));
|
||||||
|
assert(!has(externalunit, "wrong_target_test"));
|
||||||
|
ai = 0;
|
||||||
|
for (ai < testartifactnames.len) {
|
||||||
|
let bytes: str = readfile(strings.concat(testwork, "/",
|
||||||
|
testartifactnames[ai]));
|
||||||
|
if (si == 0) { testartifactrefs[ai] = strings.dup(bytes); }
|
||||||
|
else { assert(same(testartifactrefs[ai], bytes)); };
|
||||||
|
ai += 1;
|
||||||
|
};
|
||||||
|
if (si == 0) {
|
||||||
|
testoutref = strings.dup(out.stdout);
|
||||||
|
testerrref = strings.dup(out.stderr);
|
||||||
|
} else {
|
||||||
|
assert(same(testoutref, out.stdout));
|
||||||
|
assert(same(testerrref, out.stderr));
|
||||||
|
};
|
||||||
|
let stabletestunit: str = strings.dup(sameunit);
|
||||||
|
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
|
||||||
|
wrongtestedit);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
runcommandenv(root, strings.concat("platform-test-warm-", labels[si]),
|
||||||
|
testav, env, (180i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(same(testoutref, out.stdout));
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(occurrences(readfile(linkertrace), "\n") == 2);
|
||||||
|
assert(same(stabletestunit, readfile(strings.concat(testwork,
|
||||||
|
"/pkg-internal-test.unit.ww"))));
|
||||||
|
rewritefile(strings.concat(pkg, "/internal_windows_amd64_test.ww"),
|
||||||
|
wrongtest);
|
||||||
|
|
||||||
|
let onlywork: str = strings.concat(root, "/", labels[si], "-only-work");
|
||||||
|
let onlyout: str = strings.concat(root, "/", labels[si], "-only-bin");
|
||||||
|
assert(os.mkdir(onlywork, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let onlyav: []str = [driver(stages[si]), "build", "-w", onlywork,
|
||||||
|
"-o", onlyout, wrongonly];
|
||||||
|
runcommandenv(root, strings.concat("platform-only-", labels[si]), onlyav,
|
||||||
|
env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(same(out.stderr, strings.concat("ww: ", wrongonly,
|
||||||
|
": directory contains no WW package sources\n")));
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(readfile(linkertrace).len == 0);
|
||||||
|
assert(!os.exists(onlyout));
|
||||||
|
assert(!os.exists(strings.concat(onlywork, "/.wwtool.stamp")));
|
||||||
|
|
||||||
|
let orderwork: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-order-work");
|
||||||
|
assert(os.mkdir(orderwork, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let orderav: []str = [driver(stages[si]), "build", "-w", orderwork,
|
||||||
|
"-o", strings.concat(root, "/", labels[si], "-order.a"), order];
|
||||||
|
runcommandenv(root, strings.concat("platform-order-", labels[si]),
|
||||||
|
orderav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(same(out.stderr, strings.concat("ww: ", order,
|
||||||
|
"/a_linux.ww: @test declaration outside *_test.ww\n")));
|
||||||
|
assert(readfile(compilertrace).len == 0);
|
||||||
|
assert(readfile(assemblertrace).len == 0);
|
||||||
|
assert(readfile(linkertrace).len == 0);
|
||||||
|
assert(!os.exists(strings.concat(orderwork, "/.wwtool.stamp")));
|
||||||
|
|
||||||
|
let recursivework: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-recursive-work");
|
||||||
|
let recursiveout: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-recursive-out");
|
||||||
|
assert(os.mkdir(recursivework, 448i32) == 0);
|
||||||
|
assert(os.mkdir(recursiveout, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let recursiveav: []str = [driver(stages[si]), "build", "-w",
|
||||||
|
recursivework, "-I", source, "-o", strings.concat(recursiveout,
|
||||||
|
"/"), strings.concat(source, "/...")];
|
||||||
|
runcommandenv(root, strings.concat("platform-recursive-build-",
|
||||||
|
labels[si]), recursiveav, env,
|
||||||
|
(180i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||||
|
assert(!has(readfile(compilertrace), "wrongonly"));
|
||||||
|
assert(!has(readfile(compilertrace), "dep.wrong"));
|
||||||
|
let recbin: str = strings.concat(recursiveout, "/app");
|
||||||
|
let recrun: []str = [recbin];
|
||||||
|
runcommand(root, strings.concat("platform-recursive-run-", labels[si]),
|
||||||
|
recrun, (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 12);
|
||||||
|
assert(same(binref, readfile(recbin)));
|
||||||
|
|
||||||
|
let recursivetestwork: str = strings.concat(root, "/", labels[si],
|
||||||
|
"-recursive-test-work");
|
||||||
|
assert(os.mkdir(recursivetestwork, 448i32) == 0);
|
||||||
|
rewritefile(compilertrace, ""); rewritefile(assemblertrace, "");
|
||||||
|
rewritefile(linkertrace, "");
|
||||||
|
let recursivetestav: []str = [driver(stages[si]), "test", "-w",
|
||||||
|
recursivetestwork, "-I", source, strings.concat(source, "/...")];
|
||||||
|
runcommandenv(root, strings.concat("platform-recursive-test-",
|
||||||
|
labels[si]), recursivetestav, env,
|
||||||
|
(240i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "selected_internal_pair ... ok\n"));
|
||||||
|
assert(has(out.stdout, "selected_external_pair ... ok\n"));
|
||||||
|
assert(has(out.stdout, strings.concat("? ", notests,
|
||||||
|
" [no tests]\n")));
|
||||||
|
assert(!has(out.stdout, "wrong_target_test"));
|
||||||
|
assert(!has(out.stderr, "only_windows"));
|
||||||
|
assert(!has(readfile(compilertrace), "dep.wrong"));
|
||||||
|
if (si == 0) {
|
||||||
|
recursiveoutref = strings.dup(out.stdout);
|
||||||
|
recursiveerrref = strings.dup(out.stderr);
|
||||||
|
} else {
|
||||||
|
assert(same(recursiveoutref, out.stdout));
|
||||||
|
assert(same(recursiveerrref, out.stderr));
|
||||||
|
};
|
||||||
|
si += 1;
|
||||||
|
};
|
||||||
|
clean(root);
|
||||||
|
};
|
||||||
|
|
||||||
// Invalid @test attribute shapes reject at build with stable text on
|
// Invalid @test attribute shapes reject at build with stable text on
|
||||||
// BOTH frontends (the -T synth checker owns them; the fixture corpus
|
// BOTH frontends (the -T synth checker owns them; the fixture corpus
|
||||||
// cannot reach -T, so these rows live here). Fragments only — the
|
// cannot reach -T, so these rows live here). Fragments only — the
|
||||||
|
|||||||
Reference in New Issue
Block a user