small refactor and cleanup
This commit is contained in:
2
tests/alloc.expected
Normal file
2
tests/alloc.expected
Normal file
@@ -0,0 +1,2 @@
|
||||
111
|
||||
222
|
||||
23
tests/alloc.sl
Normal file
23
tests/alloc.sl
Normal file
@@ -0,0 +1,23 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
import ../stdlib/mem.sl
|
||||
|
||||
: test-mem-alloc
|
||||
4096 alloc dup 1337 swap ! # allocate 4096 bytes, store 1337 at start
|
||||
dup @ puti cr # print value at start
|
||||
4096 free # free the memory
|
||||
;
|
||||
|
||||
struct: Point
|
||||
field x 8
|
||||
field y 8
|
||||
;struct
|
||||
|
||||
: main
|
||||
32 alloc # allocate 32 bytes (enough for a Point struct)
|
||||
dup 111 swap Point.x!
|
||||
dup 222 swap Point.y!
|
||||
dup Point.x@ puti cr
|
||||
Point.y@ puti cr
|
||||
32 free # free the memory
|
||||
;
|
||||
1
tests/alloc.test
Normal file
1
tests/alloc.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/alloc.sl -o /tmp/alloc > /dev/null && /tmp/alloc
|
||||
2
tests/call_syntax_parens.expected
Normal file
2
tests/call_syntax_parens.expected
Normal file
@@ -0,0 +1,2 @@
|
||||
42
|
||||
3
|
||||
16
tests/call_syntax_parens.sl
Normal file
16
tests/call_syntax_parens.sl
Normal file
@@ -0,0 +1,16 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
import ../fn.sl
|
||||
|
||||
: main
|
||||
2 40 +
|
||||
puti cr
|
||||
extend-syntax
|
||||
foo(1, 2)
|
||||
puti cr
|
||||
0
|
||||
;
|
||||
|
||||
fn foo(int a, int b){
|
||||
return a + b;
|
||||
}
|
||||
1
tests/call_syntax_parens.test
Normal file
1
tests/call_syntax_parens.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/call_syntax_parens.sl -o /tmp/call_syntax_parens > /dev/null && /tmp/call_syntax_parens
|
||||
27
tests/fib.expected
Normal file
27
tests/fib.expected
Normal file
@@ -0,0 +1,27 @@
|
||||
1
|
||||
1
|
||||
2
|
||||
3
|
||||
5
|
||||
8
|
||||
13
|
||||
21
|
||||
34
|
||||
55
|
||||
89
|
||||
144
|
||||
233
|
||||
377
|
||||
610
|
||||
987
|
||||
1597
|
||||
2584
|
||||
4181
|
||||
6765
|
||||
10946
|
||||
17711
|
||||
28657
|
||||
46368
|
||||
75025
|
||||
-------
|
||||
25 numbers printed from the fibonaci sequence
|
||||
26
tests/fib.sl
Normal file
26
tests/fib.sl
Normal file
@@ -0,0 +1,26 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
import ../stdlib/debug.sl
|
||||
|
||||
: main
|
||||
1 1 2dup 2dup puti cr puti cr
|
||||
+
|
||||
dup puti cr
|
||||
rot
|
||||
22 dup >r for
|
||||
2dup + dup puti cr
|
||||
rot
|
||||
end
|
||||
"-------" puts
|
||||
r> 3 + puti
|
||||
" numbers printed from the fibonaci sequence" puts
|
||||
0
|
||||
;
|
||||
|
||||
: main2
|
||||
1 2 while over 100 < do
|
||||
over puti cr
|
||||
swap over +
|
||||
end
|
||||
;
|
||||
|
||||
1
tests/fib.test
Normal file
1
tests/fib.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/fib.sl -o /tmp/fib > /dev/null && /tmp/fib
|
||||
33
tests/integration_core.expected
Normal file
33
tests/integration_core.expected
Normal file
@@ -0,0 +1,33 @@
|
||||
12
|
||||
7
|
||||
42
|
||||
12
|
||||
1
|
||||
10
|
||||
22
|
||||
3
|
||||
123
|
||||
1337
|
||||
81
|
||||
99
|
||||
13
|
||||
111
|
||||
60
|
||||
5
|
||||
123
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
111
|
||||
222
|
||||
16
|
||||
70
|
||||
191
tests/integration_core.sl
Normal file
191
tests/integration_core.sl
Normal file
@@ -0,0 +1,191 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
import ../fn.sl
|
||||
|
||||
:asm mem-slot {
|
||||
lea rax, [rel print_buf]
|
||||
sub r12, 8
|
||||
mov [r12], rax
|
||||
}
|
||||
;
|
||||
|
||||
macro: square
|
||||
dup *
|
||||
;macro
|
||||
|
||||
macro: defconst 2
|
||||
: $1
|
||||
$2
|
||||
;
|
||||
;macro
|
||||
|
||||
macro: defadder 3
|
||||
: $1
|
||||
$2 $3 +
|
||||
;
|
||||
;macro
|
||||
|
||||
defconst MAGIC 99
|
||||
defadder add13 5 8
|
||||
|
||||
struct: Point
|
||||
field x 8
|
||||
field y 8
|
||||
;struct
|
||||
|
||||
extend-syntax
|
||||
|
||||
fn fancy_add(int a, int b){
|
||||
return (a + b) * b;
|
||||
}
|
||||
|
||||
: test-add
|
||||
5 7 + puti cr
|
||||
;
|
||||
|
||||
: test-sub
|
||||
10 3 - puti cr
|
||||
;
|
||||
|
||||
: test-mul
|
||||
6 7 * puti cr
|
||||
;
|
||||
|
||||
: test-div
|
||||
84 7 / puti cr
|
||||
;
|
||||
|
||||
: test-mod
|
||||
85 7 % puti cr
|
||||
;
|
||||
|
||||
: test-drop
|
||||
10 20 drop puti cr
|
||||
;
|
||||
|
||||
: test-dup
|
||||
11 dup + puti cr
|
||||
;
|
||||
|
||||
: test-swap
|
||||
2 5 swap - puti cr
|
||||
;
|
||||
|
||||
: test-store
|
||||
mem-slot dup
|
||||
123 swap !
|
||||
@ puti cr
|
||||
;
|
||||
|
||||
|
||||
: test-mmap
|
||||
0 # addr hint (NULL)
|
||||
4096 # length (page)
|
||||
3 # prot (PROT_READ | PROT_WRITE)
|
||||
34 # flags (MAP_PRIVATE | MAP_ANON)
|
||||
-1 # fd (ignored for MAP_ANON)
|
||||
0 # offset
|
||||
mmap
|
||||
dup
|
||||
1337 swap !
|
||||
dup
|
||||
@ puti cr
|
||||
4096 munmap drop
|
||||
;
|
||||
|
||||
: test-macro
|
||||
9 square puti cr
|
||||
MAGIC puti cr
|
||||
add13 puti cr
|
||||
;
|
||||
|
||||
: test-if
|
||||
5 5 == if
|
||||
111 puti cr
|
||||
else
|
||||
222 puti cr
|
||||
end
|
||||
;
|
||||
|
||||
: test-else-if
|
||||
2
|
||||
dup 1 == if
|
||||
50 puti cr
|
||||
else
|
||||
dup 2 == if
|
||||
60 puti cr
|
||||
else
|
||||
70 puti cr
|
||||
end
|
||||
end
|
||||
drop
|
||||
;
|
||||
|
||||
: test-for
|
||||
0
|
||||
5 for
|
||||
1 +
|
||||
end
|
||||
puti cr
|
||||
;
|
||||
|
||||
: test-for-zero
|
||||
123
|
||||
0 for
|
||||
drop
|
||||
end
|
||||
puti cr
|
||||
;
|
||||
|
||||
: test-struct
|
||||
mem-slot
|
||||
dup 111 swap Point.x!
|
||||
dup 222 swap Point.y!
|
||||
dup Point.x@ puti cr
|
||||
Point.y@ puti cr
|
||||
Point.size puti cr
|
||||
;
|
||||
|
||||
: test-cmp
|
||||
5 5 == puti cr
|
||||
5 4 == puti cr
|
||||
5 4 != puti cr
|
||||
4 4 != puti cr
|
||||
3 5 < puti cr
|
||||
5 3 < puti cr
|
||||
5 3 > puti cr
|
||||
3 5 > puti cr
|
||||
5 5 <= puti cr
|
||||
6 5 <= puti cr
|
||||
5 5 >= puti cr
|
||||
4 5 >= puti cr
|
||||
;
|
||||
|
||||
: test-c-fn
|
||||
3
|
||||
7
|
||||
fancy_add()
|
||||
puti cr
|
||||
;
|
||||
|
||||
: main
|
||||
test-add
|
||||
test-sub
|
||||
test-mul
|
||||
test-div
|
||||
test-mod
|
||||
test-drop
|
||||
test-dup
|
||||
test-swap
|
||||
test-store
|
||||
test-mmap
|
||||
test-macro
|
||||
test-if
|
||||
test-else-if
|
||||
test-for
|
||||
test-for-zero
|
||||
test-cmp
|
||||
test-struct
|
||||
test-c-fn
|
||||
0
|
||||
;
|
||||
1
tests/integration_core.test
Normal file
1
tests/integration_core.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/integration_core.sl -o /tmp/integration_core > /dev/null && /tmp/integration_core
|
||||
1
tests/io_read_file.expected
Normal file
1
tests/io_read_file.expected
Normal file
@@ -0,0 +1 @@
|
||||
read_file works
|
||||
36
tests/io_read_file.sl
Normal file
36
tests/io_read_file.sl
Normal file
@@ -0,0 +1,36 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
"/tmp/l2_read_file_test.txt"
|
||||
"read_file works\n"
|
||||
write_file drop
|
||||
|
||||
"/tmp/l2_read_file_test.txt" # (addr len)
|
||||
read_file # (file_addr file_len)
|
||||
dup 0 > if # if file_len > 0, success
|
||||
write_buf # print file contents (file_len file_addr)
|
||||
0
|
||||
exit
|
||||
end
|
||||
dup -2 == if # open() failed
|
||||
drop
|
||||
"open() failed: errno=" puts
|
||||
swap puti cr
|
||||
exit
|
||||
end
|
||||
dup -1 == if # fstat() failed
|
||||
drop
|
||||
"fstat() failed: errno=" puts
|
||||
swap puti cr
|
||||
exit
|
||||
end
|
||||
dup -3 == if # mmap() failed
|
||||
drop
|
||||
"mmap() failed" puts
|
||||
exit
|
||||
end
|
||||
"unknown read_file failure" puts
|
||||
dup # file_len file_len file_addr
|
||||
exit # Exit with returned file_len as the program exit code (debug)
|
||||
;
|
||||
1
tests/io_read_file.test
Normal file
1
tests/io_read_file.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/io_read_file.sl -o /tmp/io_read_file > /dev/null && /tmp/io_read_file
|
||||
1
tests/io_read_stdin.expected
Normal file
1
tests/io_read_stdin.expected
Normal file
@@ -0,0 +1 @@
|
||||
stdin via test
|
||||
13
tests/io_read_stdin.sl
Normal file
13
tests/io_read_stdin.sl
Normal file
@@ -0,0 +1,13 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
1024
|
||||
read_stdin # returns (addr len)
|
||||
dup 0 > if
|
||||
write_buf
|
||||
0 exit
|
||||
end
|
||||
"read_stdin failed" puts
|
||||
exit
|
||||
;
|
||||
1
tests/io_read_stdin.test
Normal file
1
tests/io_read_stdin.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/io_read_stdin.sl -o /tmp/io_read_stdin > /dev/null && printf 'stdin via test\n' | /tmp/io_read_stdin
|
||||
1
tests/io_write_buf.expected
Normal file
1
tests/io_write_buf.expected
Normal file
@@ -0,0 +1 @@
|
||||
hello from write_buf test
|
||||
8
tests/io_write_buf.sl
Normal file
8
tests/io_write_buf.sl
Normal file
@@ -0,0 +1,8 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
"hello from write_buf test\n"
|
||||
write_buf
|
||||
0
|
||||
;
|
||||
1
tests/io_write_buf.test
Normal file
1
tests/io_write_buf.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/io_write_buf.sl -o /tmp/io_write_buf > /dev/null && /tmp/io_write_buf
|
||||
2
tests/io_write_file.expected
Normal file
2
tests/io_write_file.expected
Normal file
@@ -0,0 +1,2 @@
|
||||
wrote bytes:
|
||||
27
|
||||
17
tests/io_write_file.sl
Normal file
17
tests/io_write_file.sl
Normal file
@@ -0,0 +1,17 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
"/tmp/l2_write_file_test.txt" # path
|
||||
"hello from write_file test\n" # buffer
|
||||
write_file
|
||||
dup 0 > if
|
||||
"wrote bytes: " puts
|
||||
puti cr
|
||||
0
|
||||
exit
|
||||
end
|
||||
"write failed errno=" puts
|
||||
puti cr
|
||||
exit
|
||||
;
|
||||
1
tests/io_write_file.test
Normal file
1
tests/io_write_file.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/io_write_file.sl -o /tmp/io_write_file > /dev/null && /tmp/io_write_file
|
||||
10
tests/loop_while.expected
Normal file
10
tests/loop_while.expected
Normal file
@@ -0,0 +1,10 @@
|
||||
10
|
||||
9
|
||||
8
|
||||
7
|
||||
6
|
||||
5
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
13
tests/loop_while.sl
Normal file
13
tests/loop_while.sl
Normal file
@@ -0,0 +1,13 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
10
|
||||
while
|
||||
dup 0 >
|
||||
do
|
||||
dup puti cr
|
||||
1 -
|
||||
end
|
||||
drop
|
||||
;
|
||||
1
tests/loop_while.test
Normal file
1
tests/loop_while.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/loop_while.sl -o /tmp/loop_while > /dev/null && /tmp/loop_while
|
||||
3
tests/loops_and_cmp.expected
Normal file
3
tests/loops_and_cmp.expected
Normal file
@@ -0,0 +1,3 @@
|
||||
5
|
||||
1
|
||||
0
|
||||
13
tests/loops_and_cmp.sl
Normal file
13
tests/loops_and_cmp.sl
Normal file
@@ -0,0 +1,13 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
0
|
||||
5 for
|
||||
1 +
|
||||
end
|
||||
puti cr
|
||||
5 5 == puti cr
|
||||
5 4 == puti cr
|
||||
0
|
||||
;
|
||||
1
tests/loops_and_cmp.test
Normal file
1
tests/loops_and_cmp.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/loops_and_cmp.sl -o /tmp/loops_and_cmp > /dev/null && /tmp/loops_and_cmp
|
||||
2
tests/mem.expected
Normal file
2
tests/mem.expected
Normal file
@@ -0,0 +1,2 @@
|
||||
5
|
||||
6
|
||||
9
tests/mem.sl
Normal file
9
tests/mem.sl
Normal file
@@ -0,0 +1,9 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
mem 5 swap !
|
||||
mem 8 + 6 swap !
|
||||
mem @ puti cr
|
||||
mem 8 + @ puti cr
|
||||
;
|
||||
1
tests/mem.test
Normal file
1
tests/mem.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/mem.sl -o /tmp/mem > /dev/null && /tmp/mem
|
||||
1
tests/override_dup_compile_time.expected
Normal file
1
tests/override_dup_compile_time.expected
Normal file
@@ -0,0 +1 @@
|
||||
6
|
||||
28
tests/override_dup_compile_time.sl
Normal file
28
tests/override_dup_compile_time.sl
Normal file
@@ -0,0 +1,28 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: dup
|
||||
6
|
||||
;
|
||||
compile-only
|
||||
|
||||
: emit-overridden
|
||||
"dup" use-l2-ct
|
||||
42
|
||||
dup
|
||||
int>string
|
||||
nil
|
||||
token-from-lexeme
|
||||
list-new
|
||||
swap
|
||||
list-append
|
||||
inject-tokens
|
||||
;
|
||||
immediate
|
||||
compile-only
|
||||
|
||||
: main
|
||||
emit-overridden
|
||||
puti cr
|
||||
0
|
||||
;
|
||||
1
tests/override_dup_compile_time.test
Normal file
1
tests/override_dup_compile_time.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/override_dup_compile_time.sl -o /tmp/override_dup_compile_time > /dev/null && /tmp/override_dup_compile_time
|
||||
@@ -1,171 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Simple end-to-end test runner for L2.
|
||||
|
||||
Each test case provides an L2 program source and an expected stdout. The runner
|
||||
invokes the bootstrap compiler on the fly and executes the produced binary.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
COMPILER = ROOT / "main.py"
|
||||
PYTHON = Path(sys.executable)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCase:
|
||||
name: str
|
||||
source: str
|
||||
expected_stdout: str
|
||||
|
||||
|
||||
CASES: List[TestCase] = [
|
||||
TestCase(
|
||||
name="call_syntax_parens",
|
||||
source=f"""
|
||||
import {ROOT / 'stdlib/stdlib.sl'}
|
||||
import {ROOT / 'stdlib/io.sl'}
|
||||
import {ROOT / 'fn.sl'}
|
||||
|
||||
: main
|
||||
2 40 +
|
||||
puti cr
|
||||
extend-syntax
|
||||
foo(1, 2)
|
||||
puti cr
|
||||
0
|
||||
;
|
||||
|
||||
fn foo(int a, int b){{
|
||||
return a + b;
|
||||
}}
|
||||
""",
|
||||
expected_stdout="42\n3\n",
|
||||
),
|
||||
TestCase(
|
||||
name="loops_and_cmp",
|
||||
source=f"""
|
||||
import {ROOT / 'stdlib/stdlib.sl'}
|
||||
import {ROOT / 'stdlib/io.sl'}
|
||||
|
||||
: main
|
||||
0
|
||||
5 for
|
||||
1 +
|
||||
end
|
||||
puti cr
|
||||
5 5 == puti cr
|
||||
5 4 == puti cr
|
||||
0
|
||||
;
|
||||
""",
|
||||
expected_stdout="5\n1\n0\n",
|
||||
),
|
||||
TestCase(
|
||||
name="override_dup_compile_time",
|
||||
source=f"""
|
||||
import {ROOT / 'stdlib/stdlib.sl'}
|
||||
import {ROOT / 'stdlib/io.sl'}
|
||||
|
||||
: dup
|
||||
6
|
||||
;
|
||||
compile-only
|
||||
|
||||
: emit-overridden
|
||||
"dup" use-l2-ct
|
||||
42
|
||||
dup
|
||||
int>string
|
||||
nil
|
||||
token-from-lexeme
|
||||
list-new
|
||||
swap
|
||||
list-append
|
||||
inject-tokens
|
||||
;
|
||||
immediate
|
||||
compile-only
|
||||
|
||||
: main
|
||||
emit-overridden
|
||||
puti cr
|
||||
0
|
||||
;
|
||||
""",
|
||||
expected_stdout="6\n",
|
||||
),
|
||||
TestCase(
|
||||
name="string_puts",
|
||||
source=f"""
|
||||
import {ROOT / 'stdlib/stdlib.sl'}
|
||||
import {ROOT / 'stdlib/io.sl'}
|
||||
|
||||
: main
|
||||
\"hello world\" puts
|
||||
\"line1\\nline2\" puts
|
||||
\"\" puts
|
||||
0
|
||||
;
|
||||
""",
|
||||
expected_stdout="hello world\nline1\nline2\n\n",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def run_case(case: TestCase) -> None:
|
||||
print(f"[run] {case.name}")
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
src_path = Path(tmp) / f"{case.name}.sl"
|
||||
exe_path = Path(tmp) / f"{case.name}.out"
|
||||
src_path.write_text(case.source.strip() + "\n", encoding="utf-8")
|
||||
|
||||
compile_cmd = [str(PYTHON), str(COMPILER), str(src_path), "-o", str(exe_path)]
|
||||
compile_result = subprocess.run(
|
||||
compile_cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=ROOT,
|
||||
)
|
||||
if compile_result.returncode != 0:
|
||||
sys.stderr.write("[fail] compile error\n")
|
||||
sys.stderr.write(compile_result.stdout)
|
||||
sys.stderr.write(compile_result.stderr)
|
||||
raise SystemExit(compile_result.returncode)
|
||||
|
||||
run_result = subprocess.run(
|
||||
[str(exe_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=ROOT,
|
||||
)
|
||||
if run_result.returncode != 0:
|
||||
sys.stderr.write("[fail] execution error\n")
|
||||
sys.stderr.write(run_result.stdout)
|
||||
sys.stderr.write(run_result.stderr)
|
||||
raise SystemExit(run_result.returncode)
|
||||
|
||||
if run_result.stdout != case.expected_stdout:
|
||||
sys.stderr.write(f"[fail] output mismatch for {case.name}\n")
|
||||
sys.stderr.write("expected:\n" + case.expected_stdout)
|
||||
sys.stderr.write("got:\n" + run_result.stdout)
|
||||
raise SystemExit(1)
|
||||
|
||||
print(f"[ok] {case.name}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
for case in CASES:
|
||||
run_case(case)
|
||||
print("[all tests passed]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4
tests/string_puts.expected
Normal file
4
tests/string_puts.expected
Normal file
@@ -0,0 +1,4 @@
|
||||
hello world
|
||||
line1
|
||||
line2
|
||||
|
||||
9
tests/string_puts.sl
Normal file
9
tests/string_puts.sl
Normal file
@@ -0,0 +1,9 @@
|
||||
import ../stdlib/stdlib.sl
|
||||
import ../stdlib/io.sl
|
||||
|
||||
: main
|
||||
"hello world" puts
|
||||
"line1\nline2" puts
|
||||
"" puts
|
||||
0
|
||||
;
|
||||
1
tests/string_puts.test
Normal file
1
tests/string_puts.test
Normal file
@@ -0,0 +1 @@
|
||||
python main.py tests/string_puts.sl -o /tmp/string_puts > /dev/null && /tmp/string_puts
|
||||
66
tests/test.py
Normal file
66
tests/test.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
COLORS = {
|
||||
"red": "\033[91m",
|
||||
"green": "\033[92m",
|
||||
"yellow": "\033[93m",
|
||||
"blue": "\033[94m",
|
||||
"reset": "\033[0m"
|
||||
}
|
||||
|
||||
def print_colored(text, color):
|
||||
print(COLORS.get(color, "") + text + COLORS["reset"], end="")
|
||||
|
||||
def run_tests():
|
||||
test_dir = "tests"
|
||||
any_failed = False
|
||||
|
||||
if not os.path.isdir(test_dir):
|
||||
print("No 'tests' directory found.")
|
||||
return 1
|
||||
|
||||
for file in sorted(os.listdir(test_dir)):
|
||||
if file.endswith(".test"):
|
||||
test_path = os.path.join(test_dir, file)
|
||||
expected_path = test_path.replace(".test", ".expected")
|
||||
|
||||
if not os.path.isfile(expected_path):
|
||||
print(f"Missing expected output file for {file}")
|
||||
any_failed = True
|
||||
continue
|
||||
|
||||
with open(test_path, "r") as test_file:
|
||||
command = test_file.read().strip()
|
||||
|
||||
with open(expected_path, "r") as expected_file:
|
||||
expected_output = expected_file.read().strip()
|
||||
|
||||
try:
|
||||
result = subprocess.run(command, shell=True, text=True, capture_output=True)
|
||||
actual_output = result.stdout.strip()
|
||||
stderr_output = result.stderr.strip()
|
||||
|
||||
if result.returncode == 0 and actual_output == expected_output:
|
||||
print_colored("[OK] ", "green")
|
||||
print(f"{file} passed")
|
||||
else:
|
||||
print_colored("[ERR] ", "red")
|
||||
print(f"{file} failed (exit {result.returncode})")
|
||||
print(f"Expected:\n{expected_output}")
|
||||
print(f"Got:\n{actual_output}")
|
||||
if stderr_output:
|
||||
print(f"Stderr:\n{stderr_output}")
|
||||
any_failed = True
|
||||
|
||||
except Exception as e:
|
||||
print_colored(f"Error running {file}: {e}", "red")
|
||||
any_failed = True
|
||||
|
||||
return 1 if any_failed else 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run_tests())
|
||||
|
||||
Reference in New Issue
Block a user