Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,12 @@ jobs:
# TUs — the single biggest CI cost) via the run_tests_aot dependency and
# sweeps all of tests/. Nightly + manual dispatch only; per-PR lanes get
# the test_aot_subset compile+link gate from the Build step instead.
# Then the big C++ tests (tests-cpp/big): a generated standalone context
# linked and run, the nano context, concurrent init, the C API split init.
# Their binaries are in the default build every lane makes, but every
# per-PR ctest is -L small, so only this step executes a generated
# context. memory_model_4gb allocates a real 4 GB chunk and stays
# local-only.
if: matrix.cmake_preset == 'Release' && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
run: |
set -eux
Expand All @@ -451,6 +457,7 @@ jobs:
cmake --build ./build --config ${{ matrix.cmake_preset }} --target run_tests_aot
;;
esac
ctest --test-dir build --build-config ${{ matrix.cmake_preset }} -L big -E memory_model_4gb --output-on-failure

###########################################################
build_windows_relwithdebinfo_nightly:
Expand Down
10 changes: 5 additions & 5 deletions daslib/lint_config.das
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,15 @@ def public is_lint_fixture_name(base : string) : bool {

let public LINT_SKIP_HEADER_LINES = 16

//! Content-based skip probe shared by the CLI runner and the MCP lint tool: ``expect <code>``
//! files declare intentional compile errors (dastest), and a header ``// lint-skip-file: <reason>``
//! opts a policy-conflicted file out entirely. Returns the skip reason, or "" to lint the file.
def public lint_file_skip_reason(file : string) : string {
//! Content-based skip probe shared by the CLI runner and the MCP lint tool. An ``expect <code>`` file
//! (intentional compile errors) skips while ``expect_skips`` holds - a caller linting rule fixtures passes false;
//! a header ``// lint-skip-file: <reason>`` opts a file out whatever the caller. Returns the skip reason, or "" to lint.
def public lint_file_skip_reason(file : string; expect_skips : bool = true) : string {
let text = fread(file)
return "" if (empty(text))
for (line, ln in split(text, "\n"), count()) {
let trimmed = line |> strip
return "(intentional compile errors via `expect`)" if (trimmed |> starts_with("expect "))
return "(intentional compile errors via `expect`)" if (expect_skips && trimmed |> starts_with("expect "))
if (ln < LINT_SKIP_HEADER_LINES && trimmed |> starts_with("// lint-skip-file")) {
let colon = find(trimmed, ":")
let reason = colon >= 0 ? strip(slice(trimmed, colon + 1)) : ""
Expand Down
2 changes: 1 addition & 1 deletion skills/internal/writing_cpp_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Big tests that are C++ executables **don't include doctest** - they keep their o

**A big test's `int main()` owns its module lifetime** - nothing runs `doctest_main.cpp` for it. An exe that resolves modules through the registry calls `Module::Initialize()` / `Module::Shutdown()` itself. An exe whose only context comes from a generated standalone AOT constructor calls neither: a context that reaches no C++ module beyond the builtin one consults no registry (example: `big/standalone_ctx/test_standalone_ctx.cpp`), and one that does registers what it links itself and shuts it down when the last context is destroyed (example: `examples/standalone/06_full_runtime/`, which doubles as a small-lane test; `big/standalone_ctx/test_standalone_modules.cpp` puts two such contexts in one binary). A test that registered the builtin module - `NEED_ALL_DEFAULT_MODULES` or `NEED_MODULE(Module_BuiltIn)` - owns the registry: it registers every module the context links and calls `Module::Initialize()` before constructing it; a module it missed stops the program at construction, by name (`standalone_modules_host_partial` pins that as a `WILL_FAIL` test).

A big-labelled test is not gated by CI - only the small suite runs there. Run `ninja test-big` locally before pushing one.
A big-labelled test runs in CI only on the nightly and on a manual full-workflow run (`ctest -L big -E memory_model_4gb` on the Release cells); every per-PR ctest is `-L small`. Run `ctest -L big` locally before pushing one and say so in the PR (`tests-cpp/big/REVIEW.md`).

## Doctest assertion cheat sheet

Expand Down
4 changes: 2 additions & 2 deletions tests-cpp/big/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ doc: `skills/internal/writing_cpp_tests.md` (repo root).

**A diff that touches a test whose ctest labels include `big` says in the PR that the test
ran and passed on the author's machine, naming the command - `ctest -L big` or the test's
own binary.** CI runs `ctest -L small` only, so no other run shows that a big-labelled test
passes.
own binary.** Per-PR CI runs `ctest -L small` only; `-L big` runs on the nightly and on a
manual full-workflow run, so a PR's own lanes never show that a big-labelled test passes.
11 changes: 6 additions & 5 deletions tests-cpp/big/style_lint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Big test: utils/lint must surface STYLE014/STYLE015 on the canonical
# comment-hygiene fixtures. Catches regressions in the option/flag plumbing
# and the scan_long_comment_blocks pass.
# utils/lint must surface STYLE014/STYLE015 on the canonical comment-hygiene
# fixtures. Catches regressions in the option/flag plumbing and the
# scan_long_comment_blocks pass. Labelled small: each run is one lint of one
# fixture, well under a second, so every per-PR ctest runs it.

file(GLOB STYLE_LINT_FIXTURES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/utils/lint/tests/style014_*.das
Expand All @@ -15,8 +16,8 @@ foreach(_fixture ${STYLE_LINT_FIXTURES})
-- --comment-hygiene true --lint-fixtures true ${_fixture}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
set_tests_properties(style_lint_${_name} PROPERTIES
LABELS "big;style_lint"
LABELS "small;style_lint"
PASS_REGULAR_EXPRESSION "STYLE014|STYLE015")
endforeach()

add_dependencies(test-big daslang)
add_dependencies(test-small daslang)
5 changes: 3 additions & 2 deletions utils/lint/main.das
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,16 @@ def normalize_rule_list(raw : array<string>; var dest : table<string>) : string
}

def set_skip_reason(file : string; lint_fixtures : bool; var result : LintResult) : bool {
let content_skip = lint_file_skip_reason(file)
// --lint-fixtures lifts the `expect` skip; a lint-skip-file directive always wins
let content_skip = lint_file_skip_reason(file, !lint_fixtures)
if (!empty(content_skip)) {
result.skip_reason = content_skip
return true
}
// the lint tool's own rule fixtures violate rules BY DESIGN (warning-expectation
// files carry no `expect` directive, so the content skip above misses them).
// --lint-fixtures is how this tool's OWN tests ask to see those findings, so it
// lifts both arms; normalize() emits the platform's preferred separator.
// lifts this arm too; normalize() emits the platform's preferred separator.
if (!lint_fixtures && (normalize(file) |> replace("\\", "/") |> find("utils/lint/tests/") >= 0
|| is_lint_fixture_name(base_name(file)))) {
result.skip_reason = "(lint rule fixture)"
Expand Down
Loading