Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
d715bc0625
|
|||
|
350deb3a45
|
|||
|
8a02674af5
|
|||
|
fac84acdaa
|
|||
|
0d6a817b7c
|
|||
|
78b7b55103
|
|||
|
c8d90c2743
|
|||
|
b434be1901
|
|||
|
330d731cfe
|
@@ -17,7 +17,7 @@ jobs:
|
||||
# Not recursive, deliberately. The top-level build needs
|
||||
# deps/libakerror and deps/libakstdlib, via add_subdirectory, and
|
||||
# nothing else: the golden corpus and the Commodore font now live in
|
||||
# this repository (tests/reference/ and assets/fonts/), so
|
||||
# this repository (tests/language/ and assets/fonts/), so
|
||||
# deps/basicinterpret is no longer a build dependency at all.
|
||||
# It does *not* need deps/libakgl, which is guarded behind
|
||||
# AKBASIC_WITH_AKGL and defaults OFF -- and recursing into it would
|
||||
@@ -26,19 +26,45 @@ jobs:
|
||||
# skipped for the same reason: our CMakeLists declares akerror::akerror
|
||||
# first and libakstdlib guards on if(NOT TARGET ...).
|
||||
submodules: true
|
||||
# moreutils is load-bearing, not incidental: it supplies errno(1), which
|
||||
# deps/libakerror/scripts/generrno.sh shells out to at build time to
|
||||
# generate its errno name table and to stamp AKERR_LAST_ERRNO_VALUE into
|
||||
# the generated akerror.h.
|
||||
#
|
||||
# Its absence does not fail the build, which is what made this expensive to
|
||||
# find. The script prints "errno: command not found" twice, emits an empty
|
||||
# akerr_init_errno() so no errno ever gets a name, and substitutes an empty
|
||||
# AKERR_LAST_ERRNO_VALUE -- so every code in libakerror's reserved band
|
||||
# collapses from (134 + n) to ( + n), i.e. to n. AKERR_OUTOFBOUNDS is
|
||||
# (AKERR_LAST_ERRNO_VALUE + 2), so it becomes literally 2, and ERR(2)
|
||||
# answers "Out Of Bounds Error" where ENOENT's "No such file or directory"
|
||||
# belongs. That is the docs_examples failure at docs/15-error-codes.md:105
|
||||
# that this job carried on every run since #2.
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc
|
||||
sudo apt-get install -y cmake gcc moreutils
|
||||
# --parallel 2 rather than a bare --parallel, and that bound is measured
|
||||
# rather than cautious. All five jobs in this file say runs-on:
|
||||
# ubuntu-latest and land on the same runner, so a bare --parallel asks for
|
||||
# nproc compilers *per job* and the runner is handed five times that at
|
||||
# once. Run #30 never showed it because akgl_build and coverage were still
|
||||
# dying early; run #31 was the first push on which all five did real work
|
||||
# simultaneously, and the sanitizers job went from a 55-second link phase
|
||||
# to a 14-minute one -- individual `Linking C executable` steps taking two
|
||||
# minutes each, starting at the exact second akgl_build began its SDL tree
|
||||
# -- before the runner's Docker daemon fell over outright and took the job
|
||||
# with it. That is memory exhaustion, and the only lever on it is the
|
||||
# number of concurrent compiler and linker processes. Applied at all four
|
||||
# build sites for the same reason; mutation_test drives its own builds
|
||||
# through the harness and is not bounded here.
|
||||
- name: build
|
||||
run: |
|
||||
cmake -S . -B build
|
||||
cmake --build build --parallel
|
||||
# The suite is 78 cases: 41 golden files byte-compared against the Go
|
||||
# reference's own corpus (checked in at tests/reference/, see its README),
|
||||
# 9 local golden cases for verbs the reference never implemented, 25 unit
|
||||
# tests, 2 embedding examples, and 1 known-failing test that asserts the
|
||||
# *correct* contract for defects carried over from the reference (TODO.md
|
||||
cmake --build build --parallel 2
|
||||
# The suite is 112 cases: 65 language files with sibling expectations,
|
||||
# 43 unit tests, 3 embedding examples, and docs_examples.
|
||||
# Some unit tests assert the *correct* contract for known defects (TODO.md
|
||||
# section 6). A green run therefore does not mean defect-free -- see
|
||||
# AKBASIC_KNOWN_FAILING_TESTS.
|
||||
#
|
||||
@@ -74,7 +100,7 @@ jobs:
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc
|
||||
sudo apt-get install -y cmake gcc moreutils
|
||||
# The whole suite under ASan and UBSan, golden files included. This is the
|
||||
# gate libakstdlib's TODO.md section 1 calls its highest-value missing item
|
||||
# -- worth having here from the start, because this library is all fixed
|
||||
@@ -84,7 +110,7 @@ jobs:
|
||||
cmake -S . -B build-asan \
|
||||
-DAKBASIC_SANITIZE=ON \
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build-asan --parallel
|
||||
cmake --build build-asan --parallel 2
|
||||
ctest --test-dir build-asan --output-on-failure
|
||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||
|
||||
@@ -98,7 +124,7 @@ jobs:
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc gcovr
|
||||
sudo apt-get install -y cmake gcc gcovr moreutils
|
||||
# The gate is a ratchet, not a target: src/ sits at 94.6% of lines and
|
||||
# 98.6% of functions, so 90 fails on a real regression (a test deleted, or
|
||||
# new untested code added) without tripping over rounding.
|
||||
@@ -124,7 +150,7 @@ jobs:
|
||||
cmake -S . -B build-coverage \
|
||||
-DAKBASIC_COVERAGE=ON \
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build-coverage --parallel
|
||||
cmake --build build-coverage --parallel 2
|
||||
ctest --test-dir build-coverage --output-on-failure
|
||||
mkdir -p build-coverage/coverage
|
||||
gcovr --root . --filter 'src/.*' \
|
||||
@@ -134,9 +160,21 @@ jobs:
|
||||
--fail-under-line 90
|
||||
# Publish even when the threshold gate fails, so the uncovered lines are
|
||||
# visible -- each one is a missing test.
|
||||
#
|
||||
# @v3, not @v4, and that is Gitea rather than preference. @v4 bundles
|
||||
# @actions/artifact v2, whose isGhes() treats any GITHUB_SERVER_URL that is
|
||||
# not github.com as GitHub Enterprise Server and refuses outright:
|
||||
# "GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+
|
||||
# and download-artifact@v4+ are not currently supported on GHES". @v3 uses
|
||||
# the older artifact API, which this forge does implement.
|
||||
#
|
||||
# This never showed before because the step had nothing to upload: gcovr
|
||||
# was never reached, so the step warned "No files were found" and passed.
|
||||
# Fixing the suite is what first gave it a real file to refuse. Same class
|
||||
# of accommodation as the annotate_only flag on the junit reporter above.
|
||||
- name: upload coverage reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: code-coverage
|
||||
path: build-coverage/coverage/
|
||||
@@ -161,22 +199,56 @@ jobs:
|
||||
# embedded it takes a find_package path instead, so our CMakeLists declares
|
||||
# those targets first and needs the submodules present. Six of them, none
|
||||
# recursive. Filed upstream as libakgl API-gap item 5.
|
||||
#
|
||||
# Eight, not six: deps/libccd and deps/clay were missing and are not
|
||||
# optional. libakgl does not add_subdirectory either of them -- their own
|
||||
# CMakeLists are unusable as subprojects -- it compiles them into itself,
|
||||
# so nothing declares them and configuration dies late with "File
|
||||
# deps/libccd/src/ccd/config.h.cmake.in does not exist" at
|
||||
# deps/libakgl/CMakeLists.txt:282. clay is the same shape one step later:
|
||||
# deps/clay/clay.h is on the include path and installed.
|
||||
#
|
||||
# deps/tg is a real submodule of libakgl and is deliberately not here --
|
||||
# nothing in its CMakeLists references it. libakerror and libakstdlib are
|
||||
# skipped for the reason the checkout note above gives.
|
||||
- name: libakgl dependencies
|
||||
run: |
|
||||
git -C deps/libakgl submodule update --init \
|
||||
deps/SDL deps/SDL_image deps/SDL_mixer deps/SDL_ttf \
|
||||
deps/jansson deps/semver
|
||||
deps/jansson deps/semver deps/libccd deps/clay
|
||||
# libfreetype-dev and libharfbuzz-dev are load-bearing, not incidental.
|
||||
# SDL_ttf prefers the system copies -- it reports "Using system freetype
|
||||
# library" and links libfreetype.so.6 -- and without them it would reach
|
||||
# for deps/SDL_ttf/external/freetype, which the checkout above
|
||||
# deliberately does not clone. Installing two dev packages is much cheaper
|
||||
# than cloning freetype and harfbuzz.
|
||||
#
|
||||
# The X11 dev packages are the other half, and they are what this job has
|
||||
# been dying on since run #2 -- it has never once been green. SDL_X11 and
|
||||
# its nine sub-options default ON on Linux, and CheckX11() in
|
||||
# deps/SDL/cmake/sdlchecks.cmake calls SDL_missing_dependency() -- a hard
|
||||
# CMake error, not a downgrade -- for any one of them whose header is
|
||||
# absent. The runner image carries libx11-dev (X11/XKBlib.h resolved) but
|
||||
# none of the extension packages, so configuration stopped at the first of
|
||||
# the nine: "Couldn't find dependency package for XCURSOR".
|
||||
#
|
||||
# Turning the missing ones OFF would also configure, and is the wrong
|
||||
# answer: the point of this job is that an AKGL build is a real SDL
|
||||
# program, and a real SDL program on Linux builds the X11 backend. The
|
||||
# tests still run headless under SDL_VIDEODRIVER=dummy -- see the env block
|
||||
# below -- so this buys a faithful build, not a display.
|
||||
#
|
||||
# The list is SDL's own, from deps/SDL/docs/README-linux.md, reduced to the
|
||||
# X11 entries: the audio, Wayland, KMSDRM and Vulkan backends all degrade
|
||||
# to "not found" and skip themselves rather than erroring, so they cost
|
||||
# nothing to leave out. Nine packages, all in noble.
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc g++ pkg-config \
|
||||
libfreetype-dev libharfbuzz-dev
|
||||
sudo apt-get install -y cmake gcc g++ pkg-config moreutils \
|
||||
libfreetype-dev libharfbuzz-dev \
|
||||
libx11-dev libxext-dev libxcursor-dev libxi-dev libxfixes-dev \
|
||||
libxrandr-dev libxss-dev libxtst-dev libxkbcommon-dev
|
||||
# The akgl-backed half: the text sink and the graphics, audio and input
|
||||
# backends, the standalone SDL frontend, and the two suites that drive
|
||||
# them against a real software renderer and read the pixels back.
|
||||
@@ -194,7 +266,7 @@ jobs:
|
||||
- name: build with libakgl
|
||||
run: |
|
||||
cmake -S . -B build-akgl -DAKBASIC_WITH_AKGL=ON
|
||||
cmake --build build-akgl --parallel
|
||||
cmake --build build-akgl --parallel 2
|
||||
# Dummy video and audio drivers, set per test by CMakeLists rather than in
|
||||
# this job's environment, because an AKGL build of `basic` is now an SDL
|
||||
# program and the golden cases run *it*: forty-one real windows is not what
|
||||
@@ -256,7 +328,7 @@ jobs:
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc python3
|
||||
sudo apt-get install -y cmake gcc python3 moreutils
|
||||
# Verify the tests actually catch bugs: break the library many ways and
|
||||
# confirm the suite fails. This matters more here than in an ordinary C
|
||||
# library, because the akerror control-flow macros expand at their call
|
||||
|
||||
@@ -70,10 +70,14 @@ jobs:
|
||||
# corpus is part of what kills mutants and it is checked in now, so
|
||||
# that is libakerror and libakstdlib and nothing else.
|
||||
submodules: true
|
||||
# moreutils for errno(1), which deps/libakerror's scripts/generrno.sh needs
|
||||
# to generate its errno table. Without it the generated table is empty and
|
||||
# every AKERR_* code collapses onto a low integer -- see the long note on
|
||||
# ci.yaml's cmake_build job for what that breaks and how it presents.
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake gcc python3
|
||||
sudo apt-get install -y cmake gcc python3 moreutils
|
||||
# The whole akbasic-owned src/ tree. ci.yaml runs a two-file subset on every
|
||||
# push; this is the one that actually covers the interpreter.
|
||||
#
|
||||
|
||||
@@ -57,9 +57,9 @@ repeating where you will see them:
|
||||
`include/akgl/SDL_GameControllerDB.h`. Change the template or the generator script.
|
||||
- **Do not reformat code you are not otherwise changing.** Several files mix tabs and spaces
|
||||
and there is no repo-wide formatter; style conversions get their own commit.
|
||||
- **Do not edit `tests/reference/`.** Those expectations came from the Go implementation and
|
||||
are never edited to suit this interpreter. A deliberate divergence goes in
|
||||
`tests/reference/README.md`'s divergence table and `docs/13-differences.md`.
|
||||
- **Keep `tests/language/` editable.** Its `.bas` programs and sibling `.txt` expectations
|
||||
are changed together when behavior changes. Record deliberate language decisions in
|
||||
`TODO.md` or `docs/13-differences.md`.
|
||||
- **Open an issue for outstanding work; do not add it to `TODO.md`.**
|
||||
<https://source.starfort.tech/andrew/akbasic/issues>, or `tea issues create --repo
|
||||
andrew/akbasic`. Name the file and line, the functional consequence, and what closing it would
|
||||
|
||||
@@ -448,7 +448,7 @@ if(AKBASIC_WITH_AKGL)
|
||||
# against.
|
||||
#
|
||||
# **A byte comparison of a rendered PNG is a deliberate bet**, the same bet
|
||||
# tests/reference/ already makes about golden output: that the dummy video
|
||||
# the language corpus makes about golden output: that the dummy video
|
||||
# driver and the software renderer are reproducible. They are, run to run and
|
||||
# build to build. What is untested is an SDL upgrade that shifts one pixel of
|
||||
# a diagonal, and the answer to that is to regenerate the figures in the same
|
||||
@@ -531,63 +531,20 @@ if(AKBASIC_WILL_FAIL_TESTS OR AKBASIC_KNOWN_FAILING_TESTS)
|
||||
)
|
||||
endif()
|
||||
|
||||
# The reference's own corpus, byte-compared against the sibling .txt. One CTest
|
||||
# case per .bas so a failure names the file.
|
||||
# The editable language corpus. One CTest case per .bas so a failure names the
|
||||
# file. Each program is paired with a sibling .txt expectation; see
|
||||
# tests/language/README.md for the editing rule.
|
||||
#
|
||||
# It used to be driven in place out of deps/basicinterpret, on the reasoning that
|
||||
# copying a submodule's corpus guarantees drift. That reasoning was sound and it
|
||||
# has been overruled deliberately: the Go dependency is being deprecated, and a
|
||||
# build that cannot run its acceptance suite without cloning the implementation
|
||||
# it replaced is not finished. The copy is byte-identical to
|
||||
# basicinterpreter@d76162c and tests/reference/README.md records
|
||||
# where it came from and what the drift now costs.
|
||||
file(GLOB_RECURSE AKBASIC_GOLDEN_CASES
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/tests/reference"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/reference/*.bas"
|
||||
)
|
||||
|
||||
foreach(_case IN LISTS AKBASIC_GOLDEN_CASES)
|
||||
string(REGEX REPLACE "^tests/" "" _name "${_case}")
|
||||
string(REGEX REPLACE "\\.bas$" "" _name "${_name}")
|
||||
string(REPLACE "/" "_" _name "${_name}")
|
||||
_add_test(
|
||||
NAME golden_${_name}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DBASIC=$<TARGET_FILE:basic>
|
||||
-DCASE=${CMAKE_CURRENT_SOURCE_DIR}/tests/reference/${_case}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/golden.cmake
|
||||
)
|
||||
endforeach()
|
||||
|
||||
if(AKBASIC_GOLDEN_CASES)
|
||||
set(AKBASIC_GOLDEN_NAMES)
|
||||
foreach(_case IN LISTS AKBASIC_GOLDEN_CASES)
|
||||
string(REGEX REPLACE "^tests/" "" _name "${_case}")
|
||||
string(REGEX REPLACE "\\.bas$" "" _name "${_name}")
|
||||
string(REPLACE "/" "_" _name "${_name}")
|
||||
list(APPEND AKBASIC_GOLDEN_NAMES golden_${_name})
|
||||
endforeach()
|
||||
_set_tests_properties(${AKBASIC_GOLDEN_NAMES} PROPERTIES TIMEOUT 30)
|
||||
# An AKGL build of `basic` opens a window, and forty-one of them is not what
|
||||
# anybody running the suite wanted. The dummy driver produces the same stdout,
|
||||
# which is the only thing a golden case compares.
|
||||
if(AKBASIC_WITH_AKGL)
|
||||
_set_tests_properties(${AKBASIC_GOLDEN_NAMES} PROPERTIES
|
||||
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The local golden corpus, for verbs the reference never implemented.
|
||||
# The corpus includes programs carried over from the deprecated Go implementation
|
||||
# and cases written for this interpreter. Their provenance is useful when
|
||||
# investigating a regression, but it does not make any case immutable.
|
||||
#
|
||||
# Still separate now that the reference's corpus lives in this repository too,
|
||||
# and the reason changed rather than went away: tests/reference/ is a *record* of
|
||||
# what the Go implementation did and nothing in it should ever be edited to suit
|
||||
# this one, while tests/language/ is ours to change. Registered under local_ so a
|
||||
# failure says at a glance which of the two it came from -- and so a diff that
|
||||