test(test): add expected-output checks for cases
This commit is contained in:
@@ -1,4 +1,206 @@
|
||||
# Bash 测试脚本:
|
||||
# - 批量编译 test/test_case/ 下的 *.sy 用例
|
||||
# - 将产物与日志写入 test/test_result/(例如 .ll/.s、运行输出、diff 结果)
|
||||
# - 汇总通过/失败信息并给出统计
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
cases_dir="test/test_case"
|
||||
result_root="test/test_result/run_tests"
|
||||
asm_dir="$result_root/asm"
|
||||
compiler="./build/bin/compiler"
|
||||
cross_gcc="aarch64-linux-gnu-gcc"
|
||||
qemu_bin="qemu-aarch64"
|
||||
qemu_sysroot="/usr/aarch64-linux-gnu"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法: ./test/run_tests.sh [case ...]
|
||||
|
||||
参数:
|
||||
case 可选。支持以下两种写法:
|
||||
- test/test_case/foo.sy
|
||||
- foo (自动解析为 test/test_case/foo.sy)
|
||||
|
||||
行为:
|
||||
- 批量编译 test/test_case/*.sy 为 AArch64 汇编并链接可执行文件
|
||||
- 若存在同名 .in,则将其作为标准输入喂给程序
|
||||
- 采集程序标准输出,并将退出码追加为最后一行
|
||||
- 与同名 .out 做精确 diff,比对结果写入 test/test_result/run_tests/
|
||||
EOF
|
||||
}
|
||||
|
||||
require_tool() {
|
||||
local tool=$1
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "未找到依赖工具: $tool" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_case() {
|
||||
local arg=$1
|
||||
if [[ -f "$arg" ]]; then
|
||||
printf '%s\n' "$arg"
|
||||
return 0
|
||||
fi
|
||||
if [[ -f "$cases_dir/$arg.sy" ]]; then
|
||||
printf '%s\n' "$cases_dir/$arg.sy"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
append_exit_code() {
|
||||
local stdout_file=$1
|
||||
local actual_file=$2
|
||||
local status=$3
|
||||
|
||||
: > "$actual_file"
|
||||
if [[ -f "$stdout_file" ]]; then
|
||||
cat "$stdout_file" >> "$actual_file"
|
||||
if [[ -s "$stdout_file" ]]; then
|
||||
local last_byte
|
||||
last_byte=$(tail -c 1 "$stdout_file" | od -An -t x1 | tr -d ' \n')
|
||||
if [[ "$last_byte" != "0a" ]]; then
|
||||
printf '\n' >> "$actual_file"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$status" >> "$actual_file"
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local input_sy=$1
|
||||
local base stem expected input_txt case_dir asm_file exe_file
|
||||
local compile_log link_log stderr_log stdout_log actual_out diff_log
|
||||
local status
|
||||
|
||||
base=$(basename "$input_sy")
|
||||
stem=${base%.sy}
|
||||
expected="${input_sy%.sy}.out"
|
||||
input_txt="${input_sy%.sy}.in"
|
||||
|
||||
case_dir="$result_root/$stem"
|
||||
asm_file="$asm_dir/$stem.s"
|
||||
exe_file="$asm_dir/$stem"
|
||||
compile_log="$case_dir/compiler.log"
|
||||
link_log="$case_dir/link.log"
|
||||
stderr_log="$case_dir/stderr.log"
|
||||
stdout_log="$case_dir/stdout.log"
|
||||
actual_out="$case_dir/actual.out"
|
||||
diff_log="$case_dir/diff.log"
|
||||
|
||||
rm -rf "$case_dir"
|
||||
mkdir -p "$case_dir"
|
||||
rm -f "$asm_file" "$exe_file"
|
||||
|
||||
if [[ ! -f "$expected" ]]; then
|
||||
echo "[FAIL] $stem: 缺少预期输出文件 $expected"
|
||||
((missing_expected_count += 1))
|
||||
failed_cases+=("$stem")
|
||||
return
|
||||
fi
|
||||
|
||||
if ! "$compiler" --emit-asm "$input_sy" >"$asm_file" 2>"$compile_log"; then
|
||||
echo "[FAIL] $stem: 编译失败,详见 $compile_log"
|
||||
((compile_fail_count += 1))
|
||||
failed_cases+=("$stem")
|
||||
return
|
||||
fi
|
||||
|
||||
if ! "$cross_gcc" "$asm_file" -o "$exe_file" >"$link_log" 2>&1; then
|
||||
echo "[FAIL] $stem: 链接失败,详见 $link_log"
|
||||
((link_fail_count += 1))
|
||||
failed_cases+=("$stem")
|
||||
return
|
||||
fi
|
||||
|
||||
: > "$stdout_log"
|
||||
: > "$stderr_log"
|
||||
if [[ -f "$input_txt" ]]; then
|
||||
"$qemu_bin" -L "$qemu_sysroot" "$exe_file" <"$input_txt" >"$stdout_log" 2>"$stderr_log"
|
||||
status=$?
|
||||
else
|
||||
"$qemu_bin" -L "$qemu_sysroot" "$exe_file" >"$stdout_log" 2>"$stderr_log"
|
||||
status=$?
|
||||
fi
|
||||
|
||||
append_exit_code "$stdout_log" "$actual_out" "$status"
|
||||
|
||||
if diff -u "$expected" "$actual_out" >"$diff_log"; then
|
||||
rm -f "$diff_log"
|
||||
echo "[PASS] $stem"
|
||||
((pass_count += 1))
|
||||
else
|
||||
echo "[FAIL] $stem: 输出不匹配,详见 $diff_log"
|
||||
((diff_fail_count += 1))
|
||||
failed_cases+=("$stem")
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ ! -x "$compiler" ]]; then
|
||||
echo "未找到编译器: $compiler ,请先构建。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_tool "$cross_gcc"
|
||||
require_tool "$qemu_bin"
|
||||
|
||||
mkdir -p "$asm_dir"
|
||||
|
||||
declare -a cases=()
|
||||
declare -a failed_cases=()
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for arg in "$@"; do
|
||||
if ! resolved=$(resolve_case "$arg"); then
|
||||
echo "未找到测试用例: $arg" >&2
|
||||
exit 1
|
||||
fi
|
||||
cases+=("$resolved")
|
||||
done
|
||||
else
|
||||
while IFS= read -r -d '' file; do
|
||||
cases+=("$file")
|
||||
done < <(find "$cases_dir" -maxdepth 1 -type f -name '*.sy' -print0 | sort -z)
|
||||
fi
|
||||
|
||||
if [[ ${#cases[@]} -eq 0 ]]; then
|
||||
echo "未找到任何 .sy 测试用例。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pass_count=0
|
||||
compile_fail_count=0
|
||||
link_fail_count=0
|
||||
diff_fail_count=0
|
||||
missing_expected_count=0
|
||||
|
||||
for case_path in "${cases[@]}"; do
|
||||
run_case "$case_path"
|
||||
done
|
||||
|
||||
total_count=${#cases[@]}
|
||||
fail_count=$((compile_fail_count + link_fail_count + diff_fail_count + missing_expected_count))
|
||||
|
||||
echo
|
||||
echo "测试完成: $total_count 个用例"
|
||||
echo "通过: $pass_count"
|
||||
echo "失败: $fail_count"
|
||||
echo " 编译失败: $compile_fail_count"
|
||||
echo " 链接失败: $link_fail_count"
|
||||
echo " 输出不匹配: $diff_fail_count"
|
||||
echo " 缺少预期输出: $missing_expected_count"
|
||||
|
||||
if [[ ${#failed_cases[@]} -gt 0 ]]; then
|
||||
echo "失败用例: ${failed_cases[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
1
test/test_case/05_arr_defn4.out
Normal file
1
test/test_case/05_arr_defn4.out
Normal file
@@ -0,0 +1 @@
|
||||
21
|
||||
9
test/test_case/05_arr_defn4.sy
Normal file
9
test/test_case/05_arr_defn4.sy
Normal file
@@ -0,0 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
const int N = 3;
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[N + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
1
test/test_case/09_func_defn.out
Normal file
1
test/test_case/09_func_defn.out
Normal file
@@ -0,0 +1 @@
|
||||
9
|
||||
11
test/test_case/09_func_defn.sy
Normal file
11
test/test_case/09_func_defn.sy
Normal file
@@ -0,0 +1,11 @@
|
||||
int a;
|
||||
int func(int p){
|
||||
p = p - 1;
|
||||
return p;
|
||||
}
|
||||
int main(){
|
||||
int b;
|
||||
a = 10;
|
||||
b = func(a);
|
||||
return b;
|
||||
}
|
||||
1
test/test_case/11_add2.out
Normal file
1
test/test_case/11_add2.out
Normal file
@@ -0,0 +1 @@
|
||||
9
|
||||
7
test/test_case/11_add2.sy
Normal file
7
test/test_case/11_add2.sy
Normal file
@@ -0,0 +1,7 @@
|
||||
//test add
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = -1;
|
||||
return a + b;
|
||||
}
|
||||
1
test/test_case/13_sub2.out
Normal file
1
test/test_case/13_sub2.out
Normal file
@@ -0,0 +1 @@
|
||||
248
|
||||
7
test/test_case/13_sub2.sy
Normal file
7
test/test_case/13_sub2.sy
Normal file
@@ -0,0 +1,7 @@
|
||||
//test sub
|
||||
const int a = 10;
|
||||
int main(){
|
||||
int b;
|
||||
b = 2;
|
||||
return b - a;
|
||||
}
|
||||
2
test/test_case/15_graph_coloring.out
Normal file
2
test/test_case/15_graph_coloring.out
Normal file
@@ -0,0 +1,2 @@
|
||||
1 2 3 2
|
||||
0
|
||||
69
test/test_case/15_graph_coloring.sy
Normal file
69
test/test_case/15_graph_coloring.sy
Normal file
@@ -0,0 +1,69 @@
|
||||
const int V = 4;
|
||||
const int space = 32;
|
||||
const int LF = 10;
|
||||
|
||||
void printSolution(int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
putint(color[i]);
|
||||
putch(space);
|
||||
i = i + 1;
|
||||
}
|
||||
putch(LF);
|
||||
}
|
||||
|
||||
void printMessage() {
|
||||
putch(78);putch(111);putch(116);
|
||||
putch(space);
|
||||
putch(101);putch(120);putch(105);putch(115);putch(116);
|
||||
}
|
||||
|
||||
int isSafe(int graph[][V], int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
int j = i + 1;
|
||||
while (j < V) {
|
||||
if (graph[i][j] && color[j] == color[i])
|
||||
return 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int graphColoring(int graph[][V], int m, int i, int color[]) {
|
||||
if (i == V) {
|
||||
if (isSafe(graph, color)) {
|
||||
printSolution(color);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int j = 1;
|
||||
while (j <= m) {
|
||||
color[i] = j;
|
||||
if (graphColoring(graph, m, i + 1, color))
|
||||
return 1;
|
||||
color[i] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int graph[V][V] = {
|
||||
{0, 1, 1, 1},
|
||||
{1, 0, 1, 0},
|
||||
{1, 1, 0, 1},
|
||||
{1, 0, 1, 0}
|
||||
}, m = 3;
|
||||
int color[V], i = 0;
|
||||
while (i < V) {
|
||||
color[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
if (!graphColoring(graph, m, 0, color))
|
||||
printMessage();
|
||||
return 0;
|
||||
}
|
||||
10
test/test_case/22_matrix_multiply.in
Normal file
10
test/test_case/22_matrix_multiply.in
Normal file
@@ -0,0 +1,10 @@
|
||||
4 4
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
4 3
|
||||
9 5 1
|
||||
10 6 2
|
||||
11 7 3
|
||||
12 8 4
|
||||
5
test/test_case/22_matrix_multiply.out
Normal file
5
test/test_case/22_matrix_multiply.out
Normal file
@@ -0,0 +1,5 @@
|
||||
110 70 30
|
||||
278 174 70
|
||||
446 278 110
|
||||
614 382 150
|
||||
0
|
||||
60
test/test_case/22_matrix_multiply.sy
Normal file
60
test/test_case/22_matrix_multiply.sy
Normal file
@@ -0,0 +1,60 @@
|
||||
const int MAX_SIZE = 100;
|
||||
int a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE][MAX_SIZE];
|
||||
int res[MAX_SIZE][MAX_SIZE];
|
||||
int n1, m1, n2, m2;
|
||||
void matrix_multiply() {
|
||||
int i = 0;
|
||||
while (i < m1) {
|
||||
int j = 0;
|
||||
while (j < n2) {
|
||||
int k = 0;
|
||||
while (k < n1) {
|
||||
res[i][j] = res[i][j] + a[i][k] * b[k][j];
|
||||
k = k + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int i, j;
|
||||
m1 = getint();
|
||||
n1 = getint();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n1) {
|
||||
a[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
m2 = getint();
|
||||
n2 = getint();
|
||||
i = 0;
|
||||
while (i < m2) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
b[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
matrix_multiply();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
putint(res[i][j]);
|
||||
putch(32);
|
||||
j = j + 1;
|
||||
}
|
||||
putch(10);
|
||||
i = i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
2
test/test_case/25_scope3.out
Normal file
2
test/test_case/25_scope3.out
Normal file
@@ -0,0 +1,2 @@
|
||||
a
|
||||
46
|
||||
1
test/test_case/25_scope3.sy
Normal file
1
test/test_case/25_scope3.sy
Normal file
@@ -0,0 +1 @@
|
||||
int main() { /* scope test */ putch(97); putch(10); int a = 1, putch = 0; { a = a + 2; int b = a + 3; b = b + 4; putch = putch + a + b; { b = b + 5; int main = b + 6; a = a + main; putch = putch + a + b + main; { b = b + a; int a = main + 7; a = a + 8; putch = putch + a + b + main; { b = b + a; int b = main + 9; a = a + 10; const int a = 11; b = b + 12; putch = putch + a + b + main; { main = main + b; int main = b + 13; main = main + a; putch = putch + a + b + main; } putch = putch - main; } putch = putch - b; } putch = putch - a; } } return putch % 77; }
|
||||
1
test/test_case/29_break.out
Normal file
1
test/test_case/29_break.out
Normal file
@@ -0,0 +1 @@
|
||||
201
|
||||
15
test/test_case/29_break.sy
Normal file
15
test/test_case/29_break.sy
Normal file
@@ -0,0 +1,15 @@
|
||||
//test break
|
||||
int main(){
|
||||
int i;
|
||||
i = 0;
|
||||
int sum;
|
||||
sum = 0;
|
||||
while(i < 100){
|
||||
if(i == 50){
|
||||
break;
|
||||
}
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
1
test/test_case/36_op_priority2.out
Normal file
1
test/test_case/36_op_priority2.out
Normal file
@@ -0,0 +1 @@
|
||||
24
|
||||
9
test/test_case/36_op_priority2.sy
Normal file
9
test/test_case/36_op_priority2.sy
Normal file
@@ -0,0 +1,9 @@
|
||||
//test the priority of add and mul
|
||||
int main(){
|
||||
int a, b, c, d;
|
||||
a = 10;
|
||||
b = 4;
|
||||
c = 2;
|
||||
d = 2;
|
||||
return (c + a) * (b - d);
|
||||
}
|
||||
13
test/test_case/95_float.in
Normal file
13
test/test_case/95_float.in
Normal file
@@ -0,0 +1,13 @@
|
||||
10
|
||||
0x1.999999999999ap-4 0x1.999999999999ap-3 0x1.3333333333333p-2 0x1.999999999999ap-2 0x1.0000000000000p-1
|
||||
0x1.3333333333333p-1 0x1.6666666666666p-1 0x1.999999999999ap-1 0x1.ccccccccccccdp-1 0x1.0000000000000p+0
|
||||
0x1.199999999999ap+0
|
||||
0x1.199999999999ap+1
|
||||
0x1.a666666666666p+1
|
||||
0x1.199999999999ap+2
|
||||
0x1.6000000000000p+2
|
||||
0x1.a666666666666p+2
|
||||
0x1.ecccccccccccdp+2
|
||||
0x1.199999999999ap+3
|
||||
0x1.3cccccccccccdp+3
|
||||
0x1.4333333333333p+3
|
||||
19
test/test_case/95_float.out
Normal file
19
test/test_case/95_float.out
Normal file
@@ -0,0 +1,19 @@
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
0x1.e691e6p+1 3
|
||||
0x1.e691e6p+3 12
|
||||
0x1.11b21p+5 28
|
||||
0x1.e691e6p+5 50
|
||||
0x1.7c21fcp+6 78
|
||||
0x1.11b21p+7 113
|
||||
0x1.7487b2p+7 153
|
||||
0x1.e691e6p+7 201
|
||||
0x1.33e85p+8 254
|
||||
10: 0x1.333334p+0 0x1.333334p+1 0x1.ccccccp+1 0x1.333334p+2 0x1.8p+2 0x1.ccccccp+2 0x1.0cccccp+3 0x1.333334p+3 0x1.599998p+3 0x1p+0
|
||||
0
|
||||
98
test/test_case/95_float.sy
Normal file
98
test/test_case/95_float.sy
Normal file
@@ -0,0 +1,98 @@
|
||||
// float global constants
|
||||
const float RADIUS = 5.5, PI = 03.141592653589793, EPS = 1e-6;
|
||||
|
||||
// hexadecimal float constant
|
||||
const float PI_HEX = 0x1.921fb6p+1, HEX2 = 0x.AP-3;
|
||||
|
||||
// float constant evaluation
|
||||
const float FACT = -.33E+5, EVAL1 = PI * RADIUS * RADIUS, EVAL2 = 2 * PI_HEX * RADIUS, EVAL3 = PI * 2 * RADIUS;
|
||||
|
||||
// float constant implicit conversion
|
||||
const float CONV1 = 233, CONV2 = 0xfff;
|
||||
const int MAX = 1e9, TWO = 2.9, THREE = 3.2, FIVE = TWO + THREE;
|
||||
|
||||
// float -> float function
|
||||
float float_abs(float x) {
|
||||
if (x < 0) return -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
// int -> float function & float/int expression
|
||||
float circle_area(int radius) {
|
||||
return (PI * radius * radius + (radius * radius) * PI) / 2;
|
||||
}
|
||||
|
||||
// float -> float -> int function & float/int expression
|
||||
int float_eq(float a, float b) {
|
||||
if (float_abs(a - b) < EPS) {
|
||||
return 1 * 2. / 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void error() {
|
||||
putch(101);
|
||||
putch(114);
|
||||
putch(114);
|
||||
putch(111);
|
||||
putch(114);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void ok() {
|
||||
putch(111);
|
||||
putch(107);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void assert(int cond) {
|
||||
if (!cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
void assert_not(int cond) {
|
||||
if (cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert_not(float_eq(HEX2, FACT));
|
||||
assert_not(float_eq(EVAL1, EVAL2));
|
||||
assert(float_eq(EVAL2, EVAL3));
|
||||
assert(float_eq(circle_area(RADIUS) /* f->i implicit conversion */,
|
||||
circle_area(FIVE)));
|
||||
assert_not(float_eq(CONV1, CONV2) /* i->f implicit conversion */);
|
||||
|
||||
// float conditional expressions
|
||||
if (1.5) ok();
|
||||
if (!!3.3) ok();
|
||||
if (.0 && 3) error();
|
||||
if (0 || 0.3) ok();
|
||||
|
||||
// float array & I/O functions
|
||||
int i = 1, p = 0;
|
||||
float arr[10] = {1., 2};
|
||||
int len = getfarray(arr);
|
||||
while (i < MAX) {
|
||||
float input = getfloat();
|
||||
float area = PI * input * input, area_trunc = circle_area(input);
|
||||
arr[p] = arr[p] + input;
|
||||
|
||||
putfloat(area);
|
||||
putch(32);
|
||||
putint(area_trunc); // f->i implicit conversion
|
||||
putch(10);
|
||||
|
||||
i = i * - -1e1;
|
||||
p = p + 1;
|
||||
}
|
||||
putfarray(len, arr);
|
||||
return 0;
|
||||
}
|
||||
1
test/test_case/simple_add.out
Normal file
1
test/test_case/simple_add.out
Normal file
@@ -0,0 +1 @@
|
||||
3
|
||||
Reference in New Issue
Block a user