diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 7fc357f..0000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "test-collection"] - path = test-collection - url = https://github.com/OJ-lab/judger-test-collection.git - branch = main diff --git a/judge-core/src/compiler.rs b/judge-core/src/compiler.rs index cf3d39d..5e89d38 100644 --- a/judge-core/src/compiler.rs +++ b/judge-core/src/compiler.rs @@ -175,44 +175,3 @@ impl Compiler { } } } - -#[cfg(test)] -pub mod compiler { - use std::path::PathBuf; - - use super::{Compiler, Language}; - - fn init() { - let _ = env_logger::builder().is_test(true).try_init(); - } - - #[test] - fn test_compile_cpp() { - init(); - let compiler = Compiler::new(Language::Cpp, vec!["-std=c++17".to_string()]); - match compiler.compile( - &PathBuf::from("../test-collection/src/programs/infinite_loop.cpp"), - &PathBuf::from("../tmp/infinite_loop_test"), - ) { - Ok(out) => { - log::info!("{}", out); - } - Err(e) => panic!("{:?}", e), - } - } - - #[test] - fn test_compile_py() { - init(); - let compiler = Compiler::new(Language::Python, vec![]); - match compiler.compile( - &PathBuf::from("../test-collection/src/programs/read_and_write.py"), - &PathBuf::from("../tmp/read_and_write"), - ) { - Ok(out) => { - log::info!("{}", out); - } - Err(e) => panic!("{:?}", e), - } - } -} diff --git a/judge-core/src/judge/builder.rs b/judge-core/src/judge/builder.rs index 1506984..2a99ea1 100644 --- a/judge-core/src/judge/builder.rs +++ b/judge-core/src/judge/builder.rs @@ -77,46 +77,3 @@ impl JudgeBuilder { }) } } - -#[cfg(test)] -pub mod builder { - use crate::judge::{common::run_judge, JudgeConfig}; - - use super::{JudgeBuilder, JudgeBuilderInput, Language, PackageType}; - use std::path::PathBuf; - - fn init() { - let _ = env_logger::builder() - .filter_level(log::LevelFilter::Debug) - .try_init(); - } - - #[test] - fn test_build_icpc() { - init(); - let builder = JudgeBuilder::new(JudgeBuilderInput { - package_type: PackageType::ICPC, - package_path: PathBuf::from("../test-collection/packages/icpc/hello_world"), - runtime_path: PathBuf::from("../tmp/icpc"), - src_language: Language::Cpp, - src_path: PathBuf::from("../test-collection/src/programs/read_and_write.cpp"), - }) - .unwrap(); - log::info!("builder: {:?}", builder); - for idx in 0..builder.testdata_configs.len() { - log::info!("runing testdata {}", idx); - let judge_config = JudgeConfig { - test_data: builder.testdata_configs[idx].clone(), - program: builder.program_config.clone(), - checker: builder.checker_config.clone(), - runtime: builder.runtime_config.clone(), - }; - - let res = run_judge(&judge_config); - match res { - Ok(info) => log::info!("{:?}", info), - Err(e) => panic!("{:?}", e), - } - } - } -} diff --git a/judge-core/src/judge/common.rs b/judge-core/src/judge/common.rs index 79da2d6..e4acd8e 100644 --- a/judge-core/src/judge/common.rs +++ b/judge-core/src/judge/common.rs @@ -130,100 +130,3 @@ pub fn run_judge(config: &JudgeConfig) -> Result JudgeConfig { - JudgeConfig { - runtime: RuntimeConfig { - rlimit_configs: TEST_CONFIG, - }, - test_data: TestdataConfig { - input_file_path: PathBuf::from("../tmp/in"), - answer_file_path: PathBuf::from("../tmp/ans"), - }, - checker: CheckerConfig { - executor: None, - output_file_path: PathBuf::from("../tmp/check"), - }, - program: ProgramConfig { - executor: program_executor, - output_file_path: PathBuf::from("../tmp/out"), - }, - } - } - - #[test] - fn test_run_judge() { - init(); - let program_path = PathBuf::from("./../test-collection/dist/programs/read_and_write"); - let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); - - let runner_config = build_test_config(program_executor); - let result = run_judge(&runner_config); - if let Ok(result) = result { - log::debug!("{:?}", result); - assert_eq!(result.verdict, JudgeVerdict::Accepted); - } else { - log::debug!("{:?}", result); - assert!(false) - } - } - - #[test] - fn test_run_tle() { - init(); - let program_path = PathBuf::from("./../test-collection/dist/programs/infinite_loop"); - let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); - - let runner_config = build_test_config(program_executor); - let result = run_judge(&runner_config); - assert!(result.is_ok()); - if let Ok(result) = result { - log::debug!("{:?}", result); - assert_eq!(result.verdict, JudgeVerdict::TimeLimitExceeded); - } - } - - #[test] - fn test_run_mle() { - init(); - let program_path = PathBuf::from("./../test-collection/dist/programs/memory_limit"); - let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); - - let runner_config = build_test_config(program_executor); - let result = run_judge(&runner_config); - assert!(result.is_ok()); - if let Ok(result) = result { - log::debug!("{:?}", result); - assert_eq!(result.verdict, JudgeVerdict::RuntimeError); - } - } -} diff --git a/judge-core/src/judge/interact.rs b/judge-core/src/judge/interact.rs index 1e28069..1d0dbd3 100644 --- a/judge-core/src/judge/interact.rs +++ b/judge-core/src/judge/interact.rs @@ -94,7 +94,7 @@ fn add_epoll_fd(epoll: &Epoll, fd: RawFd) -> Result<(), JudgeCoreError> { pub fn run_interact( config: &JudgeConfig, mut interactor_executor: Executor, - output_path: &String, + output_path: &PathBuf, ) -> Result, JudgeCoreError> { log::debug!("Creating epoll"); let epoll = Epoll::new(EpollCreateFlags::EPOLL_CLOEXEC)?; @@ -231,94 +231,3 @@ pub fn run_interact( })) } } - -#[cfg(test)] -pub mod interact_judge_test { - use std::path::PathBuf; - - use crate::{ - compiler::Language, - judge::{ - result::JudgeVerdict, CheckerConfig, JudgeConfig, ProgramConfig, RuntimeConfig, - TestdataConfig, - }, - run::{executor::Executor, RlimitConfigs}, - }; - - use super::run_interact; - - const TEST_CONFIG: RlimitConfigs = RlimitConfigs { - stack_limit: Some((64 * 1024 * 1024, 64 * 1024 * 1024)), - as_limit: Some((64 * 1024 * 1024, 64 * 1024 * 1024)), - cpu_limit: Some((1, 2)), - nproc_limit: Some((1, 1)), - fsize_limit: Some((1024, 1024)), - }; - - fn init() { - let _ = env_logger::builder() - .filter_level(log::LevelFilter::Debug) - .try_init(); - } - - fn build_test_config(program_executor: Executor) -> JudgeConfig { - JudgeConfig { - runtime: RuntimeConfig { - rlimit_configs: TEST_CONFIG, - }, - test_data: TestdataConfig { - input_file_path: PathBuf::from("../tmp/in"), - answer_file_path: PathBuf::from("../tmp/ans"), - }, - checker: CheckerConfig { - executor: Some( - Executor::new( - Language::Cpp, - PathBuf::from("./../test-collection/dist/checkers/lcmp"), - ) - .unwrap(), - ), - output_file_path: PathBuf::from("../tmp/check"), - }, - program: ProgramConfig { - executor: program_executor, - output_file_path: PathBuf::from("../tmp/out"), - }, - } - } - - #[test] - fn test_run_interact() { - init(); - - let interactor_executor = Executor::new( - Language::Cpp, - PathBuf::from("./../test-collection/dist/checkers/interactor-echo"), - ) - .unwrap(); - let program_executor = Executor::new( - Language::Cpp, - PathBuf::from("./../test-collection/dist/programs/read_and_write"), - ) - .unwrap(); - let runner_config = build_test_config(program_executor); - let result = run_interact( - &runner_config, - interactor_executor, - &String::from("../tmp/interactor"), - ); - match result { - Ok(Some(result)) => { - log::debug!("{:?}", result); - assert!(result.verdict == JudgeVerdict::Accepted); - } - Ok(None) => { - log::debug!("Ignoring this result, for it's from a fork child process"); - } - Err(e) => { - log::error!("meet error: {:?}", e); - assert!(false); - } - } - } -} diff --git a/judge-core/tests/.gitignore b/judge-core/tests/.gitignore new file mode 100644 index 0000000..97dbe28 --- /dev/null +++ b/judge-core/tests/.gitignore @@ -0,0 +1,3 @@ +data/built-in-programs/build +data/built-in-programs/include/testlib.h +temp \ No newline at end of file diff --git a/judge-core/tests/compile_test.rs b/judge-core/tests/compile_test.rs new file mode 100644 index 0000000..831bfbe --- /dev/null +++ b/judge-core/tests/compile_test.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +use judge_core::compiler::{Compiler, Language}; + +const TEST_DATA_PATH: &str = "tests/data"; +const TEST_TEMP_PATH: &str = "tests/temp"; + +fn init() { + let _ = env_logger::builder().is_test(true).try_init(); +} + +#[test] +fn test_compile_cpp() { + init(); + let compiler = Compiler::new(Language::Cpp, vec!["-std=c++17".to_string()]); + match compiler.compile( + &PathBuf::from(TEST_DATA_PATH).join("built-in-programs/src/programs/infinite_loop.cpp"), + &PathBuf::from(TEST_TEMP_PATH).join("infinite_loop_test.o"), + ) { + Ok(out) => { + log::info!("{}", out); + } + Err(e) => panic!("{:?}", e), + } +} + +#[test] +fn test_compile_py() { + init(); + let compiler = Compiler::new(Language::Python, vec![]); + match compiler.compile( + &PathBuf::from(TEST_DATA_PATH).join("built-in-programs/src/programs/read_and_write.py"), + &PathBuf::from(TEST_TEMP_PATH).join("read_and_write.o"), + ) { + Ok(out) => { + log::info!("{}", out); + } + Err(e) => panic!("{:?}", e), + } +} diff --git a/judge-core/tests/data/built-in-programs/CMakeLists.txt b/judge-core/tests/data/built-in-programs/CMakeLists.txt new file mode 100644 index 0000000..9510a7d --- /dev/null +++ b/judge-core/tests/data/built-in-programs/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.0) + +project(judger-test VERSION 1.0) + +set(CMAKE_C_COMPILER "gcc") +set(CMAKE_CXX_COMPILER "g++") + +set(CMAKE_C_FLAGS "-Wall -O2 -std=gnu11 -static -lm") + +if (CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpfullversion -dumpversion + OUTPUT_VARIABLE GCC_VERSION) + string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) + list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) + list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) + + message(STATUS "CMAKE version is ${CMAKE_VERSION}") + + set(GCC_VERSION "${GCC_MAJOR}.${GCC_MINOR}") + message(STATUS "GCC version is ${GCC_VERSION}") + + if (GCC_VERSION GREATER_EQUAL "11") + set(CMAKE_CXX_FLAGS "-Wall -O2 -std=gnu++20 -static") + else() + set(CMAKE_CXX_FLAGS "-Wall -O2 -std=gnu++2a -static") + endif() +endif() + +include(include/testlib.cmake) + +add_subdirectory(src) diff --git a/judge-core/tests/data/built-in-programs/README.md b/judge-core/tests/data/built-in-programs/README.md new file mode 100644 index 0000000..e4d7a6a --- /dev/null +++ b/judge-core/tests/data/built-in-programs/README.md @@ -0,0 +1,40 @@ +# judger-test-collection + +## How to use test collection + +As of now, all executables need to be built prior to testing. + +use GNU make: + +```bash +mkdir -p {build,dist} +cmake -B build --install-prefix $(pwd)/dist +cmake --build build --parallel +cmake --install build +``` + +or use Ninja: + +```bash +mkdir -p {build,dist} +cmake -B build --install-prefix $(pwd)/dist -G Ninja . +cmake --build build +cmake --install build +``` + +Then you will get all test file on `dist/` + +## Trouble Shooting + +You might get errors like: +`g++: error: unrecognized command line option ‘-std=gnu++20’; did you mean ‘-std=gnu++2a’?` +While running the provided bash in this repository. + +For resolution run the following commands if you are using Ubuntu in Github Codespaces: + +``` sh +sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test +sudo apt install -y g++-11 +# Alternate the priority of g++ version usage +sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100 +``` diff --git a/judge-core/tests/data/built-in-programs/build.sh b/judge-core/tests/data/built-in-programs/build.sh new file mode 100755 index 0000000..9dec9ca --- /dev/null +++ b/judge-core/tests/data/built-in-programs/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh -e + +mkdir -p build +cmake -B build --install-prefix "$(pwd)/build" +cmake --build build --parallel +cmake --install build diff --git a/judge-core/tests/data/built-in-programs/include/testlib.cmake b/judge-core/tests/data/built-in-programs/include/testlib.cmake new file mode 100644 index 0000000..d454ccd --- /dev/null +++ b/judge-core/tests/data/built-in-programs/include/testlib.cmake @@ -0,0 +1,7 @@ +set(TESTLIB_COMMIT "0.9.12") +set(TESTLIB_SHA256 "f2fdd835c66d2578a5b0a39bb7d7dfb7126b6fc216a401d110621e214e0df643") + +file(DOWNLOAD "https://github.com/MikeMirzayanov/testlib/raw/${TESTLIB_COMMIT}/testlib.h" + "${CMAKE_SOURCE_DIR}/include/testlib.h" + SHOW_PROGRESS + EXPECTED_HASH SHA256=${TESTLIB_SHA256}) diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/.timelimit b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/.timelimit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/.timelimit @@ -0,0 +1 @@ +1 diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.ans b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.ans new file mode 100644 index 0000000..2a1588e --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.ans @@ -0,0 +1 @@ +Hello! world! diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.in b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.in new file mode 100644 index 0000000..c944ebc --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/0.in @@ -0,0 +1 @@ +world! \ No newline at end of file diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.ans b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.ans new file mode 100644 index 0000000..fb35721 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.ans @@ -0,0 +1 @@ +Hello! oj-lab! diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.in b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.in new file mode 100644 index 0000000..893a717 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/data/secret/1.in @@ -0,0 +1 @@ +oj-lab! \ No newline at end of file diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/interactor-a-plus-b b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/interactor-a-plus-b new file mode 100755 index 0000000..c237a18 Binary files /dev/null and b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/interactor-a-plus-b differ diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/lcmp b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/lcmp new file mode 100755 index 0000000..786b861 Binary files /dev/null and b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/lcmp differ diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/ncmp b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/ncmp new file mode 100755 index 0000000..8711c86 Binary files /dev/null and b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/output_validators/ncmp differ diff --git a/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/problem.yaml b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/problem.yaml new file mode 100644 index 0000000..89fe447 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/packages/icpc/hello_world/problem.yaml @@ -0,0 +1,13 @@ +name: Hello world + +limits: + time_multiplier: 5 + time_safety_margin: 2 + memory: 2048 + output: 8 + code: 128 + compilation_time: 60 + compilation_memory: 2048 + validation_time: 60 + validation_memory: 2048 + validation_output: 8 diff --git a/judge-core/tests/data/built-in-programs/src/CMakeLists.txt b/judge-core/tests/data/built-in-programs/src/CMakeLists.txt new file mode 100644 index 0000000..acfcbc0 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/CMakeLists.txt @@ -0,0 +1,25 @@ + +file(GLOB_RECURSE SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/*.py") + +include_directories(${CMAKE_SOURCE_DIR}/include) + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +foreach(SRC_FILE ${SOURCE_FILES}) + get_filename_component(BASENAME ${SRC_FILE} NAME_WE) + file(RELATIVE_PATH SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ${SRC_FILE}) + get_filename_component(BIN_DIR ${SOURCE_DIR} DIRECTORY) + + get_filename_component(FILE_SUFFIX ${SRC_FILE} EXT) + string(TOLOWER ${FILE_SUFFIX} FILE_SUFFIX) + + if (${FILE_SUFFIX} STREQUAL ".c" OR ${FILE_SUFFIX} STREQUAL ".cpp") + add_executable(${BASENAME} ${SRC_FILE}) + set_property(TARGET ${BASENAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/${BIN_DIR}) + install(TARGETS ${BASENAME} DESTINATION ${BIN_DIR}) + elseif (${FILE_SUFFIX} STREQUAL ".py") + install(FILES ${SRC_FILE} DESTINATION ${BIN_DIR}) + endif() +endforeach() diff --git a/judge-core/tests/data/built-in-programs/src/checkers/interactor-echo.cpp b/judge-core/tests/data/built-in-programs/src/checkers/interactor-echo.cpp new file mode 100644 index 0000000..ac0aad7 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/checkers/interactor-echo.cpp @@ -0,0 +1,19 @@ +#include "testlib.h" +#include + +using namespace std; + +int main(int argc, char *argv[]) { + setName("Echo interactor"); + registerInteraction(argc, argv); + + // reads string from test (input) file + string x = inf.readString(); + // write to stdout + cout << x << endl; + // write to output file + tout << ouf.readString() < +#include +#include + +using namespace std; + +bool compareWords(const string& a, const string& b) { + vector va, vb; + stringstream sa; + + sa << a; + string cur; + while (sa >> cur) + va.push_back(cur); + + stringstream sb; + sb << b; + while (sb >> cur) + vb.push_back(cur); + + return (va == vb); +} + +int main(int argc, char *argv[]) { + setName("compare files as sequence of tokens in lines"); + registerTestlibCmd(argc, argv); + + string strAnswer; + + int n = 0; + while (!ans.eof()) { + std::string j = ans.readString(); + + if (j.empty() && ans.eof()) + break; + + string p = ouf.readString(); + strAnswer = p; + + n++; + + if (!compareWords(j, p)) + quitf(_wa, "%d%s lines differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), + compress(j).c_str(), compress(p).c_str()); + } + + if (n == 1) + quitf(_ok, "single line: '%s'", compress(strAnswer).c_str()); + + quitf(_ok, "%d lines", n); +} diff --git a/judge-core/tests/data/built-in-programs/src/checkers/ncmp.cpp b/judge-core/tests/data/built-in-programs/src/checkers/ncmp.cpp new file mode 100644 index 0000000..34da263 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/checkers/ncmp.cpp @@ -0,0 +1,53 @@ +#include "testlib.h" + +using namespace std; + +int main(int argc, char *argv[]) { + setName("compare ordered sequences of signed int%d numbers", 8 * int(sizeof(long long))); + + registerTestlibCmd(argc, argv); + + int n = 0; + string firstElems; + + while (!ans.seekEof() && !ouf.seekEof()) { + n++; + long long j = ans.readLong(); + long long p = ouf.readLong(); + if (j != p) + quitf(_wa, "%d%s numbers differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), + vtos(j).c_str(), vtos(p).c_str()); + else if (n <= 5) { + if (firstElems.length() > 0) + firstElems += " "; + firstElems += vtos(j); + } + } + + int extraInAnsCount = 0; + + while (!ans.seekEof()) { + ans.readLong(); + extraInAnsCount++; + } + + int extraInOufCount = 0; + + while (!ouf.seekEof()) { + ouf.readLong(); + extraInOufCount++; + } + + if (extraInAnsCount > 0) + quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %d elements", + n + extraInAnsCount, n); + + if (extraInOufCount > 0) + quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %d elements", + n + extraInOufCount, n); + + if (n <= 5) + quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str()); + else + quitf(_ok, "%d numbers", n); +} diff --git a/judge-core/tests/data/built-in-programs/src/programs/infinite_loop.cpp b/judge-core/tests/data/built-in-programs/src/programs/infinite_loop.cpp new file mode 100644 index 0000000..950b42a --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/programs/infinite_loop.cpp @@ -0,0 +1,14 @@ +#include +#include + +int main() { + clock_t start, step; + start = clock(); + step = clock(); + while (true) { + if (clock() - step > 1000000) { + printf("%lds has passed..\n", (clock() - start) / 1000000); + step = clock(); + } + } +} diff --git a/judge-core/tests/data/built-in-programs/src/programs/memory_limit.cpp b/judge-core/tests/data/built-in-programs/src/programs/memory_limit.cpp new file mode 100644 index 0000000..6084d62 --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/programs/memory_limit.cpp @@ -0,0 +1,11 @@ +#include +#include + +using namespace std; + +const int maxn=5e7+10; +int a[maxn]; + +int main() { + for(int i=0;i + +using namespace std; + +int main() { + string s; + cin >> s; + cout << "Hello! " << s << endl; +} diff --git a/judge-core/tests/data/built-in-programs/src/programs/read_and_write.py b/judge-core/tests/data/built-in-programs/src/programs/read_and_write.py new file mode 100644 index 0000000..40f939e --- /dev/null +++ b/judge-core/tests/data/built-in-programs/src/programs/read_and_write.py @@ -0,0 +1 @@ +print("Hello! world!") diff --git a/judge-core/tests/data/packages/icpc/hello_world/.timelimit b/judge-core/tests/data/packages/icpc/hello_world/.timelimit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/.timelimit @@ -0,0 +1 @@ +1 diff --git a/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.ans b/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.ans new file mode 100644 index 0000000..2a1588e --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.ans @@ -0,0 +1 @@ +Hello! world! diff --git a/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.in b/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.in new file mode 100644 index 0000000..c944ebc --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/data/secret/0.in @@ -0,0 +1 @@ +world! \ No newline at end of file diff --git a/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.ans b/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.ans new file mode 100644 index 0000000..fb35721 --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.ans @@ -0,0 +1 @@ +Hello! oj-lab! diff --git a/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.in b/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.in new file mode 100644 index 0000000..893a717 --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/data/secret/1.in @@ -0,0 +1 @@ +oj-lab! \ No newline at end of file diff --git a/judge-core/tests/data/packages/icpc/hello_world/output_validators/interactor-a-plus-b b/judge-core/tests/data/packages/icpc/hello_world/output_validators/interactor-a-plus-b new file mode 100755 index 0000000..c237a18 Binary files /dev/null and b/judge-core/tests/data/packages/icpc/hello_world/output_validators/interactor-a-plus-b differ diff --git a/judge-core/tests/data/packages/icpc/hello_world/output_validators/lcmp b/judge-core/tests/data/packages/icpc/hello_world/output_validators/lcmp new file mode 100755 index 0000000..786b861 Binary files /dev/null and b/judge-core/tests/data/packages/icpc/hello_world/output_validators/lcmp differ diff --git a/judge-core/tests/data/packages/icpc/hello_world/output_validators/ncmp b/judge-core/tests/data/packages/icpc/hello_world/output_validators/ncmp new file mode 100755 index 0000000..8711c86 Binary files /dev/null and b/judge-core/tests/data/packages/icpc/hello_world/output_validators/ncmp differ diff --git a/judge-core/tests/data/packages/icpc/hello_world/problem.yaml b/judge-core/tests/data/packages/icpc/hello_world/problem.yaml new file mode 100644 index 0000000..89fe447 --- /dev/null +++ b/judge-core/tests/data/packages/icpc/hello_world/problem.yaml @@ -0,0 +1,13 @@ +name: Hello world + +limits: + time_multiplier: 5 + time_safety_margin: 2 + memory: 2048 + output: 8 + code: 128 + compilation_time: 60 + compilation_memory: 2048 + validation_time: 60 + validation_memory: 2048 + validation_output: 8 diff --git a/judge-core/tests/judge_test.rs b/judge-core/tests/judge_test.rs new file mode 100644 index 0000000..8f569a9 --- /dev/null +++ b/judge-core/tests/judge_test.rs @@ -0,0 +1,178 @@ +use std::path::PathBuf; + +use judge_core::{ + compiler::Language, + judge::{ + interact::run_interact, result::JudgeVerdict, CheckerConfig, JudgeConfig, ProgramConfig, + RuntimeConfig, TestdataConfig, builder::{JudgeBuilder, JudgeBuilderInput}, + }, + run::{executor::Executor, RlimitConfigs}, package::PackageType, +}; + +use judge_core::judge::common::run_judge; + +const TEST_DATA_PATH: &str = "tests/data"; +const TEST_TEMP_PATH: &str = "tests/temp"; + +const TEST_CONFIG: RlimitConfigs = RlimitConfigs { + stack_limit: Some((64 * 1024 * 1024, 64 * 1024 * 1024)), + as_limit: Some((64 * 1024 * 1024, 64 * 1024 * 1024)), + cpu_limit: Some((1, 2)), + nproc_limit: Some((1, 1)), + fsize_limit: Some((1024, 1024)), +}; + +fn init() { + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .try_init(); +} + +fn build_test_config(program_executor: Executor) -> JudgeConfig { + JudgeConfig { + runtime: RuntimeConfig { + rlimit_configs: TEST_CONFIG, + }, + test_data: TestdataConfig { + input_file_path: PathBuf::from(TEST_DATA_PATH) + .join("problem-packages/icpc/hello_world/data/secret/0.in"), + answer_file_path: PathBuf::from(TEST_DATA_PATH) + .join("problem-packages/icpc/hello_world/data/secret/0.ans"), + }, + checker: CheckerConfig { + executor: None, + output_file_path: PathBuf::from(TEST_TEMP_PATH).join("checker.out"), + }, + program: ProgramConfig { + executor: program_executor, + output_file_path: PathBuf::from(TEST_TEMP_PATH).join("program.out"), + }, + } +} + +#[test] +fn test_run_judge() { + init(); + log::debug!("current dir: {:?}", std::env::current_dir().unwrap()); + + let program_path = + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/programs/read_and_write"); + let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); + + let runner_config = build_test_config(program_executor); + let result = run_judge(&runner_config); + if let Ok(result) = result { + log::debug!("{:?}", result); + assert_eq!(result.verdict, JudgeVerdict::Accepted); + } else { + log::debug!("{:?}", result); + assert!(false) + } +} + +#[test] +fn test_run_tle() { + init(); + let program_path = + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/programs/infinite_loop"); + let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); + + let runner_config = build_test_config(program_executor); + let result = run_judge(&runner_config); + assert!(result.is_ok()); + if let Ok(result) = result { + log::debug!("{:?}", result); + assert_eq!(result.verdict, JudgeVerdict::TimeLimitExceeded); + } +} + +#[test] +fn test_run_mle() { + init(); + let program_path = + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/programs/memory_limit"); + let program_executor = Executor::new(Language::Cpp, program_path).unwrap(); + + let runner_config = build_test_config(program_executor); + let result = run_judge(&runner_config); + assert!(result.is_ok()); + if let Ok(result) = result { + log::debug!("{:?}", result); + assert_eq!(result.verdict, JudgeVerdict::RuntimeError); + } +} + +#[test] +fn test_run_interact() { + init(); + let interactor_executor = Executor::new( + Language::Cpp, + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/checkers/interactor-echo"), + ) + .unwrap(); + let program_executor = Executor::new( + Language::Cpp, + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/programs/read_and_write"), + ) + .unwrap(); + let runner_config = JudgeConfig { + checker: CheckerConfig { + executor: Some( + Executor::new( + Language::Cpp, + PathBuf::from(TEST_DATA_PATH).join("built-in-programs/build/checkers/lcmp"), + ) + .unwrap(), + ), + output_file_path: PathBuf::from(TEST_TEMP_PATH).join("checker.out"), + }, + ..build_test_config(program_executor) + }; + let result = run_interact( + &runner_config, + interactor_executor, + &PathBuf::from(TEST_TEMP_PATH).join("interact.out"), + ); + match result { + Ok(Some(result)) => { + log::debug!("{:?}", result); + assert!(result.verdict == JudgeVerdict::Accepted); + } + Ok(None) => { + log::debug!("Ignoring this result, for it's from a fork child process"); + } + Err(e) => { + log::error!("meet error: {:?}", e); + assert!(false); + } + } +} + +#[test] +fn test_build_icpc() { + init(); + let builder = JudgeBuilder::new(JudgeBuilderInput { + package_type: PackageType::ICPC, + package_path: PathBuf::from(TEST_DATA_PATH).join("problem-packages/icpc/hello_world"), + runtime_path: PathBuf::from(TEST_TEMP_PATH).join("hello_world"), + src_language: Language::Cpp, + src_path: PathBuf::from(TEST_DATA_PATH).join("built-in-programs/src/programs/read_and_write.cpp"), + }) + .unwrap(); + log::info!("builder: {:?}", builder); + for idx in 0..builder.testdata_configs.len() { + log::info!("runing testdata {}", idx); + let judge_config = JudgeConfig { + test_data: builder.testdata_configs[idx].clone(), + program: builder.program_config.clone(), + checker: builder.checker_config.clone(), + runtime: builder.runtime_config.clone(), + }; + + let res = run_judge(&judge_config); + match res { + Ok(info) => log::info!("{:?}", info), + Err(e) => panic!("{:?}", e), + } + } +}