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
12 changes: 9 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ jobs:
sudo apt-get update -y
sudo apt-get install -y build-essential llvm clang cmake python3-pip

- name: Install Python Dependencies
run: python3 -m pip install -r requirements-dev.txt

- name: Build zpiler
run: |
mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j

- name: Run Tests
run: python3 test_runner.py
run: python3 -m pytest -q

test-windows:
runs-on: windows-latest
Expand All @@ -58,7 +61,7 @@ jobs:
uses: actions/cache@v4
with:
path: C:\Users\runneradmin\AppData\Local\pip\Cache
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-

Expand All @@ -68,6 +71,9 @@ jobs:
- name: Install CMake
run: choco install --no-progress -y cmake

- name: Install Python Dependencies
run: python -m pip install -r requirements-dev.txt

- name: Build zpiler
shell: cmd
run: |
Expand All @@ -80,4 +86,4 @@ jobs:
shell: cmd
run: |
chcp 65001
python test_runner.py
python -m pytest -q
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,24 @@ Generates: `program` (executable)

### Automated Testing

Run all test cases for a specific target:
Install test dependencies:
```bash
# Test native platform (auto-detected)
python test_runner.py
python3 -m pip install -r requirements-dev.txt
```

Run strict golden-output tests with `pytest`:
```bash
# Auto-detect native target when TARGET is not set
pytest -q

# Test specific targets
TARGET=linux python test_runner.py # Linux
TARGET=windows python test_runner.py # Windows (if ml64 available)
TARGET=llvm python test_runner.py # LLVM
# Linux + LLVM
TARGET=linux,llvm pytest -q

# Test multiple targets
TARGET=linux,llvm python test_runner.py
# Windows
TARGET=windows pytest -q

# Update/create runtime goldens explicitly
TARGET=linux pytest -q --bless
```

---
Expand Down Expand Up @@ -195,7 +201,13 @@ fn main() {

## 🧪 Testing

You can add `.zz` programs inside a `tests/` folder and run them individually through the pipeline. Type errors, parsing errors, and codegen output are printed to the terminal.
Test suites are directory-based:

- `tests/runtime`: program must compile, run, and match exact `stdout`/`stderr`/exit code
- `tests/runtime_fail`: program must compile, run, and match exact failing output + nonzero exit code
- `tests/compile_fail`: program must fail compilation with expected exit code and required stderr substrings

Expected files live under `tests/expected/<mode>/...` with mirrored paths.

---

Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ int main(int argc, char *argv[]) {
cg->generate(std::move(program));
} catch (std::exception const &exc) {
std::cerr << "ERROR: " << exc.what() << "\n";
return 1;
}

return 0;
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==8.3.3
2 changes: 1 addition & 1 deletion src/parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ namespace zust
errMsg + " at line " + std::to_string(currentToken.line) +
", column " + std::to_string(currentToken.column)});
shouldTypecheck = false;
exit(0);
exit(1);
return;
}
}
Expand Down
Binary file not shown.
Binary file added tests/__pycache__/conftest.cpython-312.pyc
Binary file not shown.
Binary file not shown.
Binary file added tests/__pycache__/test_pipeline.cpython-312.pyc
Binary file not shown.
3 changes: 3 additions & 0 deletions tests/compile_fail/syntax/missing_semicolon.zz
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
let a: int64_t = 10
}
4 changes: 4 additions & 0 deletions tests/compile_fail/type/bad_assignment.zz
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extern fn foo(x: not_a_type) -> none;

fn main() {
}
102 changes: 102 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from __future__ import annotations

import os
import sys
from dataclasses import dataclass
from pathlib import Path

import pytest


@dataclass(frozen=True)
class TargetConfig:
name: str
zpiler_format: str
asm_ext: str


TARGETS: dict[str, TargetConfig] = {
"linux": TargetConfig(name="linux", zpiler_format="x86_64-linux", asm_ext=".s"),
"windows": TargetConfig(
name="windows", zpiler_format="x86_64-mswin", asm_ext=".asm"
),
"llvm": TargetConfig(name="llvm", zpiler_format="llvm-ir", asm_ext=".ll"),
}


def detect_native_target() -> str:
plat = sys.platform
if plat.startswith("linux"):
return "linux"
if plat.startswith("win32") or plat.startswith("cygwin"):
return "windows"
return "llvm"


def parse_target_env() -> list[str]:
env = os.getenv("TARGET")
if env:
wanted = [t.strip() for t in env.split(",") if t.strip() in TARGETS]
if not wanted:
raise pytest.UsageError(
f"TARGET={env} contains no known backends. "
f"Known targets: {', '.join(TARGETS)}"
)
return wanted
return [detect_native_target()]


def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--bless",
action="store_true",
default=False,
help="Create or update runtime golden output files.",
)


def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
if "target_name" in metafunc.fixturenames:
targets = parse_target_env()
metafunc.parametrize(
"target_name", targets, ids=[f"target={target}" for target in targets]
)


@pytest.fixture(scope="session")
def bless(request: pytest.FixtureRequest) -> bool:
return bool(request.config.getoption("--bless"))


@pytest.fixture(scope="session")
def project_root() -> Path:
return Path(__file__).resolve().parents[1]


@pytest.fixture(scope="session")
def zpiler_path(project_root: Path) -> Path:
candidates = [
project_root / "build" / "zpiler",
project_root / "build" / "Debug" / "zpiler.exe",
project_root / "build" / "zpiler.exe",
]
for candidate in candidates:
if candidate.exists():
return candidate

candidate_text = "\n".join(str(path) for path in candidates)
pytest.exit(
"Could not find zpiler executable. Build project first.\n"
f"Searched:\n{candidate_text}",
returncode=2,
)


@pytest.fixture(scope="session")
def artifacts_root(tmp_path_factory: pytest.TempPathFactory) -> Path:
return tmp_path_factory.mktemp("pipeline_artifacts")


@pytest.fixture
def target_config(target_name: str) -> TargetConfig:
return TARGETS[target_name]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Required syntax-failure markers
[Syntax Error]
Expected ';' after declaration
1 change: 1 addition & 0 deletions tests/expected/compile_fail/type/bad_assignment.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Required semantic/type-failure markers
[Type Error]
Undefined type 'not_a_type'
1 change: 1 addition & 0 deletions tests/expected/runtime/conditionals/if-elif-else.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/conditionals/if-elif-else.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11
1 change: 1 addition & 0 deletions tests/expected/runtime/conditionals/if-elif.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/conditionals/if-else.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/conditionals/if.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/functions/basics.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
3 changes: 3 additions & 0 deletions tests/expected/runtime/functions/basics.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
42
9.000000
true
1 change: 1 addition & 0 deletions tests/expected/runtime/functions/recursive.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
3 changes: 3 additions & 0 deletions tests/expected/runtime/functions/recursive.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
120
true
false
1 change: 1 addition & 0 deletions tests/expected/runtime/functions/scopes.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/functions/scopes.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
1 change: 1 addition & 0 deletions tests/expected/runtime/loops/control.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/operations/binary.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
24 changes: 24 additions & 0 deletions tests/expected/runtime/operations/binary.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
30
-10
200
2
12.500000
-7.500000
25.000000
4.000000
5.859500
0.423500
8.538597
1.155813
3
true
true
false
false
false
true
false
false
false
false
true
1 change: 1 addition & 0 deletions tests/expected/runtime/operations/unary.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
5 changes: 5 additions & 0 deletions tests/expected/runtime/operations/unary.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
5
255
100
0
1
1 change: 1 addition & 0 deletions tests/expected/runtime/strings/escapes.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/types.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/types.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
1 change: 1 addition & 0 deletions tests/expected/runtime/variables.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
1 change: 1 addition & 0 deletions tests/expected/runtime/variables.linux.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
It is what it is
1 change: 1 addition & 0 deletions tests/expected/runtime/variables.llvm.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
It is what it is
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime/variables.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DO_NOT_USE_SHARED_VARIABLES_STDOUT
1 change: 1 addition & 0 deletions tests/expected/runtime/variables.windows.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
It is what it is
1 change: 1 addition & 0 deletions tests/expected/runtime_fail/exit/nonzero.exitcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7
Empty file.
1 change: 1 addition & 0 deletions tests/expected/runtime_fail/exit/nonzero.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
about-to-fail
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions tests/runtime_fail/exit/nonzero.zz
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern fn printf(fmt: string, ...) -> int32_t;
extern fn exit(code: int32_t) -> none;

fn main() {
printf("about-to-fail\n");
exit(7);
}
Loading
Loading