Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,40 @@ impl Compiler<'_> {
Ok(project_path)
}
}

#[cfg(test)]
mod test {
use std::path::Path;

use bstr::ByteSlice;
use rstest::rstest;

use crate::{CPP, JAVA, Language, PYTHON, RUST, test::read_code};

const EXAMPLE_CODE_DIR: &str = "tests/data/timeout";

#[rstest]
#[tokio::test]
async fn should_create_valid_project_directory(
#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>,
) {
let code = read_code(language, Path::new(EXAMPLE_CODE_DIR));
let project_path = language
.compiler
.create_project(code.as_bytes())
.await
.unwrap();
let main_path = project_path.join(language.compiler.main_file);

assert!(main_path.exists())
}

#[rstest]
#[tokio::test]
async fn should_compile_successfully(
#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>,
) {
let code = read_code(language, Path::new(EXAMPLE_CODE_DIR));
assert!(language.compiler.compile(code.as_bytes()).await.is_ok());
}
}
34 changes: 34 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,37 @@ pub struct Language<'a> {
pub compiler: Compiler<'a>,
pub runner_args: CommandArgs<'a>,
}

#[cfg(test)]
mod test {
use std::{fs, path::Path};

use crate::Language;

pub fn read_test_cases(problem_path: &Path) -> Vec<(Vec<u8>, Vec<u8>)> {
let test_cases: Vec<_> = fs::read_dir(problem_path)
.unwrap()
.filter_map(|entry| {
let entry = entry.unwrap();
let path = entry.path();
if !path.is_dir() {
return None;
}

let input_path = path.join("in.txt");
let input = fs::read(input_path).unwrap();

let output_path = path.join("out.txt");
let output = fs::read(output_path).unwrap();

Some((input, output))
})
.collect();

test_cases
}

pub fn read_code(language: Language, problem_path: &Path) -> Vec<u8> {
fs::read(problem_path.join(language.compiler.main_file)).unwrap()
}
}
63 changes: 63 additions & 0 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,66 @@ impl<'a> Runner<'a> {
})
}
}

#[cfg(test)]
mod test {
use std::{
path::{Path, PathBuf},
time::Duration,
};

use bstr::ByteSlice;
use rstest::rstest;

use crate::{
CPP, ExitStatus, JAVA, Language, PYTHON, RUST, Runner,
test::{read_code, read_test_cases},
};

#[rstest]
#[tokio::test]
async fn should_output_correct(
#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>,
#[files("tests/data/problem/*")] problem_path: PathBuf,
) {
let test_cases = read_test_cases(&problem_path);

let code = read_code(language, &problem_path);
let project_path = language.compiler.compile(&code).await.unwrap();

let runner = Runner::new(
language.runner_args,
&project_path,
Duration::from_secs(2),
i64::MAX,
512,
)
.unwrap();
for (input, output) in test_cases {
let metrics = runner.run(&input).await.unwrap();
let metrics_out = metrics.stdout.trim();
let test_case_out = output.trim();
assert_eq!(metrics_out, test_case_out);
}
}

#[rstest]
#[tokio::test]
async fn should_timeout(#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>) {
let code = read_code(language, Path::new("tests/data/timeout"));
let project_path = language.compiler.compile(code.as_bytes()).await.unwrap();

let runner = Runner::new(
language.runner_args,
&project_path,
Duration::from_secs(2),
i64::MAX,
512,
)
.unwrap();

let metrics = runner.run(b"").await.unwrap();

assert_eq!(metrics.exit_status, ExitStatus::Timeout)
}
}
5 changes: 5 additions & 0 deletions tests/data/timeout/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Main {
public static void main(String[] args) {
while(true) {}
}
}
7 changes: 7 additions & 0 deletions tests/data/timeout/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <bits/stdc++.h>

using namespace std;

int main() {
while(true) {}
}
2 changes: 2 additions & 0 deletions tests/data/timeout/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
while True:
continue
3 changes: 3 additions & 0 deletions tests/data/timeout/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
loop {}
}
2 changes: 1 addition & 1 deletion tests/should_output_correct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use util::{Problem, read_code};
#[tokio::test]
async fn should_output_correct(
#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>,
#[files("tests/problem/*")] problem_path: PathBuf,
#[files("tests/data/problem/*")] problem_path: PathBuf,
) {
let problem: Problem = problem_path.as_path().into();

Expand Down
48 changes: 7 additions & 41 deletions tests/should_timeout.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,17 @@
use std::time::Duration;
mod util;

use std::{path::Path, time::Duration};

use bstr::ByteSlice;
use code_executor::*;
use rstest::rstest;

fn get_timeout_code(language: Language<'static>) -> &'static str {
match language {
CPP => {
r#"
#include <bits/stdc++.h>

using namespace std;

int main() {
while(true) {}
}
"#
}
RUST => {
r#"
fn main() {
loop {}
}
"#
}
JAVA => {
r#"
class Main {
public static void main(String[] args) {
while(true) {}
}
}
"#
}
PYTHON => {
r#"
while True:
continue
"#
}
_ => unreachable!(),
}
}
use util::read_code;

#[rstest]
#[tokio::test]
async fn should_output_correct(#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>) {
let code = get_timeout_code(language);
async fn should_timeout(#[values(CPP, RUST, JAVA, PYTHON)] language: Language<'static>) {
let code = read_code(language, Path::new("tests/data/timeout"));
let project_path = language.compiler.compile(code.as_bytes()).await.unwrap();

let runner = Runner::new(
Expand Down
3 changes: 3 additions & 0 deletions tests/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use std::{fs, path::Path};

use code_executor::Language;

#[allow(unused)]
pub struct TestCase {
pub input: Vec<u8>,
pub output: Vec<u8>,
}

#[allow(unused)]
pub struct Problem {
pub test_cases: Vec<TestCase>,
}
Expand Down Expand Up @@ -36,6 +38,7 @@ impl From<&Path> for Problem {
}
}

#[allow(unused)]
pub fn read_code(language: Language, problem_path: &Path) -> Vec<u8> {
fs::read(problem_path.join(language.compiler.main_file)).unwrap()
}
Loading