Skip to content

Commit

Permalink
CI: test multiple problems
Browse files Browse the repository at this point in the history
  • Loading branch information
byeongkeunahn committed Oct 1, 2023
1 parent 8cbc9f2 commit 5c3ed59
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 12 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ jobs:
RUSTFLAGS: ""
- name: Check C
run: |
scripts/check.sh \
"./release.sh | tee /tmp/code.c" \
"cc -w /tmp/code.c -o /tmp/bin"
python ./scripts/build-and-judge.py ${{ runner.temp }} ./release.sh C ./src/solution.rs ./tests/boj_1000.in ./tests/boj_1000.out
- name: Check Rust
run: |
scripts/check.sh \
"./release-rs.sh | tee /tmp/code.rs" \
"rustc +stable -O -A dead-code /tmp/code.rs -o /tmp/bin"
python ./scripts/build-and-judge.py ${{ runner.temp }} ./release-rs.sh Rust ./src/solution.rs ./tests/boj_1000.in ./tests/boj_1000.out
- name: Check Rust (BOJ 1001)
run: |
python ./scripts/build-and-judge.py ${{ runner.temp }} ./release-rs.sh Rust ./tests/boj_1001.rs ./tests/boj_1001.in ./tests/boj_1001.out
- name: Check Rust (BOJ 3745)
run: |
python ./scripts/build-and-judge.py ${{ runner.temp }} ./release-rs.sh Rust ./tests/boj_3745.rs ./tests/boj_3745.in ./tests/boj_3745.out
18 changes: 12 additions & 6 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jobs:
CARGO_BUILD_TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v3
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
vsversion: 2022
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
Expand All @@ -42,11 +46,13 @@ jobs:
RUSTFLAGS: ""
- name: Check C
run: |
scripts/check.sh \
"./release.sh | tee /tmp/code.c" \
"cc -w /tmp/code.c -o /tmp/bin"
python .\scripts\build-and-judge.py ${{ runner.temp }} .\release-64bit-windows.cmd C .\src\solution.rs .\tests\boj_1000.in .\tests\boj_1000.out
- name: Check Rust
run: |
scripts/check.sh \
"./release-rs.sh | tee /tmp/code.rs" \
"rustc +stable -O -A dead-code /tmp/code.rs -o /tmp/bin"
python .\scripts\build-and-judge.py ${{ runner.temp }} .\release-64bit-windows-rs.cmd Rust .\src\solution.rs .\tests\boj_1000.in .\tests\boj_1000.out
- name: Check Rust (BOJ 1001)
run: |
python .\scripts\build-and-judge.py ${{ runner.temp }} .\release-64bit-windows-rs.cmd Rust .\tests\boj_1001.rs .\tests\boj_1001.in .\tests\boj_1001.out
- name: Check Rust (BOJ 3745)
run: |
python .\scripts\build-and-judge.py ${{ runner.temp }} .\release-64bit-windows-rs.cmd Rust .\tests\boj_3745.rs .\tests\boj_3745.in .\tests\boj_3745.out
91 changes: 91 additions & 0 deletions scripts/build-and-judge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""
This script builds and tests a solution for a problem.
Developed for use in CI.
Usage:
python .\scripts\build-and-judge.py [tmp-dir] [build-cmd] [sol-path] [indata-path] [outdata-path]
Example:
python .\scripts\build-and-judge.py .\scripts\tmp .\release-64bit-windows-rs.cmd Rust .\tests\boj_3745.rs .\tests\boj_3745.in .\tests\boj_3745.out
Limitations: special judges are not yet supported.
"""

import os
import platform
import shutil
import subprocess
import sys

def try_remove(filename):
try:
os.remove(filename)
except OSError:
pass

def test_equal(x, y):
x_tok = str(x).split()
y_tok = str(y).split()
return x_tok == y_tok

if __name__ == '__main__':
tmp_dir = sys.argv[1]
build_cmd = sys.argv[2]
language = sys.argv[3]
sol_path = sys.argv[4]
indata_path = sys.argv[5]
outdata_path = sys.argv[6]
src_ext = {"C": "c", "Rust": "rs"}[language]

# Prepare environment
os.makedirs(tmp_dir, exist_ok=True)
src_path = os.path.abspath(os.path.join(tmp_dir, "output.{0}".format(src_ext)))
bin_path = os.path.abspath(os.path.join(tmp_dir, "loader.exe" if platform.system() == "Windows" else "loader"))
try_remove(src_path)
try_remove(bin_path)

# Read the input and output data in advance
with open(indata_path, mode="r", encoding="utf8") as f:
indata = f.read()
with open(outdata_path, mode="r", encoding="utf8") as f:
outdata = f.read()

# Replace the solution
shutil.copyfile(sol_path, "src/solution_new.rs")
os.rename("src/solution.rs", "src/solution_old.rs")
os.rename("src/solution_new.rs", "src/solution.rs")

# Build the project to generate the source code
try:
p = subprocess.run([build_cmd], shell=True, capture_output=True, text=True)
if p.returncode != 0:
raise Exception("Build failed. The stderr:\n{0}".format(p.stderr))
source_code = p.stdout
with open(src_path, mode="w", encoding="utf8") as f:
f.write(source_code)
print(source_code)
finally:
# Restore the original solution
try_remove("src/solution.rs")
os.rename("src/solution_old.rs", "src/solution.rs")

# Compile the source code
if language == "C":
if platform.system() == "Windows":
os.system("cl {0} /F268435456 /Fe{1} /link /SUBSYSTEM:CONSOLE".format(src_path, bin_path))
else:
os.system("gcc -o {1} -O3 {0}".format(src_path, bin_path))
else: # language == "Rust"
if platform.system() == "Windows":
os.system("rustc -C opt-level=3 -o {1} --crate-type=bin {0}".format(src_path, bin_path))
else:
os.system("rustc -C opt-level=3 -o {1} {0}".format(src_path, bin_path))

# Run the binary
with open(indata_path, mode="r", encoding="utf8") as f:
stdout = subprocess.run([bin_path], shell=False, stdin=f, capture_output=True, text=True).stdout

if test_equal(stdout, outdata):
print("Program succeeded for input {0} and output {1}".format(indata_path, outdata_path))
else:
err_msg = "Program fails to print the correct output for input {0} and output {1}\n".format(indata_path, outdata_path)
err_msg += "Input:\n{0}\nOutput (expected):\n{1}\nOutput (actual):\n{2}\n".format(indata, outdata, stdout)
raise Exception(err_msg)
1 change: 1 addition & 0 deletions tests/boj_1000.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5 3
1 change: 1 addition & 0 deletions tests/boj_1000.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8
1 change: 1 addition & 0 deletions tests/boj_1001.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3 8
1 change: 1 addition & 0 deletions tests/boj_1001.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-5
8 changes: 8 additions & 0 deletions tests/boj_1001.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use basm::platform::io::{Reader, Writer, Print};
pub fn main() {
let mut reader: Reader = Default::default();
let mut writer: Writer = Default::default();
let a = reader.i64();
let b = reader.i64();
writer.println(a - b);
}
6 changes: 6 additions & 0 deletions tests/boj_3745.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
6
5 2 1 4 5 3
3
1 1 1
4
4 3 2 1
3 changes: 3 additions & 0 deletions tests/boj_3745.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
3
1
1
25 changes: 25 additions & 0 deletions tests/boj_3745.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use basm::platform::io::{Reader, Writer, Print};
use core::cmp::max;
pub fn main() {
let mut reader: Reader = Default::default();
let mut writer: Writer = Default::default();
let mut x = [usize::MAX; 100_001]; // x[i] = minimum end-value of "len >= i" increasing seq.
while !reader.is_eof_skip_whitespace() {
let n = reader.usize();
let mut ans = 0;
x[0] = 0;
for i in 0..n {
x[i + 1] = usize::MAX;
let v = reader.usize();
let (mut lo, mut hi) = (0, i);
while lo < hi {
let mid = (lo + hi + 1) / 2;
if x[mid] < v { lo = mid; } else { hi = mid - 1; }
}
let ans_new = lo + 1;
x[ans_new] = v;
ans = max(ans, ans_new);
}
writer.println(ans);
}
}

0 comments on commit 5c3ed59

Please sign in to comment.