mirror of
https://github.com/MeiK2333/river.git
synced 2025-11-04 14:49:40 +08:00
完成基本的答案对比功能
This commit is contained in:
parent
ae1dca202a
commit
353236a154
@ -28,6 +28,8 @@ pub enum Error {
|
||||
WaitError(Option<i32>),
|
||||
SystemTimeError(time::SystemTimeError),
|
||||
RemoveFileError(String, Option<i32>),
|
||||
|
||||
OpenFileError(String, Option<i32>),
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
@ -56,6 +58,10 @@ impl fmt::Display for Error {
|
||||
let reason = errno_str(errno);
|
||||
write!(f, "ReadFileError: `{}` {}", filename, reason)
|
||||
}
|
||||
Error::OpenFileError(ref filename, errno) => {
|
||||
let reason = errno_str(errno);
|
||||
write!(f, "OpenFileError: `{}` {}", filename, reason)
|
||||
}
|
||||
Error::UnknownJudgeType(ref judge_type) => {
|
||||
write!(f, "UnknownJudgeType: {}", judge_type)
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ fn main() {
|
||||
};
|
||||
println!("{}", judge_config.code.language);
|
||||
|
||||
// TODO: 处理 SE,处理交互问题
|
||||
match process::run(&judge_config) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
|
||||
@ -2,6 +2,8 @@ extern crate libc;
|
||||
|
||||
use super::error::{errno_str, Error, Result};
|
||||
use super::judger::{JudgeConfig, TestCase};
|
||||
use super::result::{ExitStatus, TestCaseResult};
|
||||
|
||||
use handlebars::Handlebars;
|
||||
use libc::{c_long, suseconds_t, time_t};
|
||||
use std::collections::BTreeMap;
|
||||
@ -131,11 +133,14 @@ pub fn run(judge_config: &JudgeConfig) -> Result<()> {
|
||||
Err(err) => return Err(Error::CopyFileError(err)),
|
||||
};
|
||||
}
|
||||
// TODO: 处理 CE 与 RE(编译期间程序运行出错为 CE,运行期间出错为 RE)
|
||||
let _ = compile(judge_config, to_dir)?;
|
||||
for test_case in &judge_config.tests {
|
||||
println!("\n----------------------------------\n");
|
||||
let _ = run_one(judge_config, test_case, to_dir)?;
|
||||
let exit_status = run_one(judge_config, test_case, to_dir)?;
|
||||
let output_file_path = to_dir.join(&test_case.output_file);
|
||||
let answer_file_path = from_dir.join(&test_case.answer_file);
|
||||
let res = TestCaseResult::standard(&output_file_path, &answer_file_path, exit_status);
|
||||
println!("{:?}", res);
|
||||
match fs::remove_file(output_file_path) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
@ -153,14 +158,6 @@ pub fn run(judge_config: &JudgeConfig) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ExitStatus {
|
||||
pub rusage: libc::rusage,
|
||||
pub status: i32,
|
||||
pub time_used: i64,
|
||||
pub real_time_used: u128,
|
||||
pub memory_used: i64,
|
||||
}
|
||||
|
||||
pub fn wait(pid: i32) -> Result<ExitStatus> {
|
||||
let start = SystemTime::now();
|
||||
let mut status = 0;
|
||||
@ -203,9 +200,6 @@ pub fn wait(pid: i32) -> Result<ExitStatus> {
|
||||
Ok(elapsed) => elapsed.as_millis(),
|
||||
Err(err) => return Err(Error::SystemTimeError(err)),
|
||||
};
|
||||
println!("time used:\t{}", time_used);
|
||||
println!("real time used:\t{}", real_time_used);
|
||||
println!("memory used:\t{}", rusage.ru_maxrss);
|
||||
Ok(ExitStatus {
|
||||
rusage,
|
||||
status,
|
||||
@ -231,8 +225,11 @@ pub unsafe fn dup(filename: &str, to: libc::c_int, flag: libc::c_int, mode: libc
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_one(judge_config: &JudgeConfig, test_case: &TestCase, workdir: &Path) -> Result<()> {
|
||||
println!("running test case: {}", test_case.index);
|
||||
pub fn run_one(
|
||||
judge_config: &JudgeConfig,
|
||||
test_case: &TestCase,
|
||||
workdir: &Path,
|
||||
) -> Result<ExitStatus> {
|
||||
let pid;
|
||||
|
||||
// 这个操作就需要 1-2ms 左右,此处预先完成,不占用子进程运行时间
|
||||
@ -255,13 +252,13 @@ pub fn run_one(judge_config: &JudgeConfig, test_case: &TestCase, workdir: &Path)
|
||||
&test_case.input_file,
|
||||
libc::STDIN_FILENO,
|
||||
libc::O_RDONLY,
|
||||
0644,
|
||||
0o644,
|
||||
);
|
||||
dup(
|
||||
&test_case.output_file,
|
||||
libc::STDOUT_FILENO,
|
||||
libc::O_CREAT | libc::O_RDWR,
|
||||
0644,
|
||||
0o644,
|
||||
);
|
||||
libc::execve(exec_args.pathname, exec_args.argv, exec_args.envp);
|
||||
}
|
||||
@ -270,12 +267,12 @@ pub fn run_one(judge_config: &JudgeConfig, test_case: &TestCase, workdir: &Path)
|
||||
panic!("How dare you!");
|
||||
} else if pid > 0 {
|
||||
// 父进程
|
||||
let _ = wait(pid)?;
|
||||
let exit_status = wait(pid)?;
|
||||
return Ok(exit_status);
|
||||
} else {
|
||||
// 异常
|
||||
return Err(Error::ForkError(io::Error::last_os_error().raw_os_error()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile(judge_config: &JudgeConfig, workdir: &Path) -> Result<()> {
|
||||
|
||||
131
src/result.rs
131
src/result.rs
@ -1,11 +1,23 @@
|
||||
use super::error::Result;
|
||||
extern crate libc;
|
||||
|
||||
use super::error::{Error, Result};
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResourceUsed {
|
||||
pub time_used: u32,
|
||||
pub memory_used: u32,
|
||||
pub time_used: i64,
|
||||
pub memory_used: i64,
|
||||
}
|
||||
|
||||
pub struct ExitStatus {
|
||||
pub rusage: libc::rusage,
|
||||
pub status: i32,
|
||||
pub time_used: i64,
|
||||
pub real_time_used: u128,
|
||||
pub memory_used: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -24,12 +36,111 @@ impl fmt::Display for TestCaseResult {
|
||||
}
|
||||
|
||||
impl TestCaseResult {
|
||||
pub fn standard<P: AsRef<Path>>(output_file: P, answer_file: P) -> Result<TestCaseResult> {
|
||||
let result = TestCaseResult::Accepted(ResourceUsed {
|
||||
time_used: 0,
|
||||
memory_used: 0,
|
||||
});
|
||||
// TODO: 对比答案文件,返回结果
|
||||
Ok(result)
|
||||
pub fn standard<P: AsRef<Path>>(
|
||||
output_file: P,
|
||||
answer_file: P,
|
||||
exit_status: ExitStatus,
|
||||
) -> Result<TestCaseResult> {
|
||||
println!("\n----------------------------------\n");
|
||||
println!("time used:\t{}", exit_status.time_used);
|
||||
println!("real time used:\t{}", exit_status.real_time_used);
|
||||
println!("memory used:\t{}", exit_status.rusage.ru_maxrss);
|
||||
let used = ResourceUsed {
|
||||
time_used: exit_status.time_used,
|
||||
memory_used: exit_status.rusage.ru_maxrss,
|
||||
};
|
||||
|
||||
let output_filename = match output_file.as_ref().to_str() {
|
||||
Some(val) => val,
|
||||
None => "",
|
||||
};
|
||||
let answer_filename = match answer_file.as_ref().to_str() {
|
||||
Some(val) => val,
|
||||
None => "",
|
||||
};
|
||||
|
||||
let output_file = match File::open(output_filename) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::OpenFileError(
|
||||
output_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let mut output_reader = BufReader::new(output_file);
|
||||
let mut output_buffer = String::new();
|
||||
let mut output_bytes;
|
||||
|
||||
let answer_file = match File::open(answer_filename) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::OpenFileError(
|
||||
answer_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let mut answer_reader = BufReader::new(answer_file);
|
||||
let mut answer_buffer = String::new();
|
||||
let mut answer_bytes;
|
||||
|
||||
loop {
|
||||
output_bytes = match output_reader.read_line(&mut output_buffer) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::ReadFileError(
|
||||
output_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
answer_bytes = match answer_reader.read_line(&mut answer_buffer) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::ReadFileError(
|
||||
answer_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
if output_bytes == 0 || answer_bytes == 0 {
|
||||
break;
|
||||
}
|
||||
if output_buffer.trim_end() != answer_buffer.trim_end() {
|
||||
return Ok(TestCaseResult::WrongAnswer(used));
|
||||
}
|
||||
}
|
||||
// 末尾的空白字符不影响结果
|
||||
while output_bytes != 0 {
|
||||
if output_buffer.trim() != "" {
|
||||
return Ok(TestCaseResult::WrongAnswer(used));
|
||||
}
|
||||
output_bytes = match output_reader.read_line(&mut output_buffer) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::ReadFileError(
|
||||
output_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
while answer_bytes != 0 {
|
||||
if answer_buffer.trim() != "" {
|
||||
return Ok(TestCaseResult::WrongAnswer(used));
|
||||
}
|
||||
answer_bytes = match answer_reader.read_line(&mut answer_buffer) {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::ReadFileError(
|
||||
answer_filename.to_string(),
|
||||
io::Error::last_os_error().raw_os_error(),
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(TestCaseResult::Accepted(used))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user