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
|
||||
|
||||
A package directory contains its immediate regular source files only. The build
|
||||
does not follow source symlinks. Nested directories are separate packages. Every
|
||||
selected production source MUST begin with the same canonical `package name;`
|
||||
clause. The declared name MUST be a valid WW identifier. It need not repeat the
|
||||
directory leaf because identity and source qualifier are separate concepts.
|
||||
A package directory contains its immediate regular source files and source-name
|
||||
symlinks that resolve to regular files. A source-name symlink to a directory is
|
||||
ignored. Nested directories are separate packages. Every selected production
|
||||
source MUST begin with the same canonical `package name;` clause. The declared
|
||||
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:
|
||||
|
||||
@@ -279,41 +280,47 @@ still the smallest package and needs no extra metadata.
|
||||
|
||||
### 3.2 File membership and target selection
|
||||
|
||||
Production candidates are immediate regular files ending `.ww`, excluding
|
||||
`*_test.ww` and generated outputs. Names are byte-sorted after UTF-8 validity and
|
||||
normalization checks. A source symlink, duplicate normalized name, case-fold
|
||||
collision, or non-regular candidate is a loud error on every host.
|
||||
The current toolchain has one honest target, `linux/amd64`. Production
|
||||
candidates are immediate visible names ending `.ww`, excluding selected
|
||||
`*_test.ww` files. Directory entries beginning `.` or `_` are ignored. Candidate
|
||||
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
|
||||
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.
|
||||
Files are grouped by `stem`. The matching member with the greatest number of
|
||||
tags wins; the untagged member is the fallback. Two equally specific matches are
|
||||
an error. Examples are `poll.ww`, `poll+linux.ww`, and
|
||||
`poll+linux+amd64+gnu.ww`. This is replacement selection, not additive feature
|
||||
selection; additive code uses a distinct stem. Unknown tags are errors. There
|
||||
are no boolean selectors, glob expressions, or manifest-defined tag meanings.
|
||||
The suffix requires a nonempty prefix and an underscore. Thus `linux.ww` and
|
||||
`plan9_test.ww` are ordinary files, `x_plan9_test.ww` is excluded,
|
||||
`x_linux_amd64.ww` is selected, and `x_windows_amd64.ww` is excluded. The first
|
||||
dot ends inspection: `x.extra_windows.ww` is ordinary. Pair recognition takes
|
||||
precedence over the final single token; `x_windows_amd64.ww` does not match just
|
||||
because `amd64` does. Conversely `x_amd64_linux.ww` has no OS/architecture pair
|
||||
and matches its final single `linux` token, exactly as Go does.
|
||||
|
||||
Test variants put the same tags before the reserved suffix, for example
|
||||
`poll+linux_test.ww`; their grammar is `stem[+tags]_test.ww` and the identical
|
||||
most-specific rule applies within the test set. A production stem ending
|
||||
`_test` is reserved and rejected, preventing a tagged test from being mistaken
|
||||
for production source.
|
||||
Selection is additive, not replacement-based: every matching file belongs to
|
||||
the package. The production variant then excludes `*_test.ww`; internal and
|
||||
external test classification uses only the already platform-selected test
|
||||
files. An excluded file creates no source occurrence, import, dependency edge,
|
||||
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
|
||||
removing a more-specific file invalidates the package even when the old files'
|
||||
bytes do not change.
|
||||
|
||||
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.
|
||||
WW implements no source-level build expressions, user tags, target descriptor,
|
||||
`UseAllFiles` escape, `+tag` replacement scheme, or manifest-defined selector.
|
||||
Those would introduce a second build language or a manifest model and are
|
||||
outside the local, manifest-free product.
|
||||
|
||||
### 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
|
||||
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
|
||||
action changed in the same request. All action artifacts, init artifacts, tool
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
package declares `package wire;`, the importing file sees its exported names
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
It generates all source trees temporarily and runs independent cold/persistent
|
||||
Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
|
||||
|
||||
@@ -5118,6 +5118,637 @@ fn hexbytes(value: str) str = {
|
||||
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
|
||||
// BOTH frontends (the -T synth checker owns them; the fixture corpus
|
||||
// cannot reach -T, so these rows live here). Fragments only — the
|
||||
|
||||
Reference in New Issue
Block a user