Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lang): support java and golang #11

Merged
merged 1 commit into from
Dec 2, 2024
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
5 changes: 5 additions & 0 deletions .changes/lang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eval-stack": patch:feat
---

Support for Java and Golang.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"covector",
"fmax",
"getuid",
"javac",
"libc",
"NEWNS",
"prctl",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Online Judge core runtime for ACMers",
"main": "index.js",
"scripts": {
"covector": "covector"
"covector": "covector",
"test": "cargo test"
},
"keywords": [
"oj",
Expand Down
3 changes: 3 additions & 0 deletions src/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ where
let exec_path = match &language {
Language::Python => which("python")?,
Language::NodeJs => which("deno")?,
Language::Java => which("java")?,
_ => workspace.join("out"),
};

Expand Down Expand Up @@ -65,9 +66,11 @@ where
"--deny-ffi=*",
source_file_path.as_str(),
];
let java_args = vec!["Main"];
let args = match language {
Language::Python => Some(&py_args),
Language::NodeJs => Some(&deno_args),
Language::Java => Some(&java_args),
_ => None,
}
.map(|v| &**v);
Expand Down
36 changes: 30 additions & 6 deletions src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,30 @@ use std::{
};

use anyhow::Result;
use tokio::process::Command;
use tokio::{fs::File, io, process::Command};

#[derive(Clone, Copy)]
#[derive(Default, Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum Language {
#[default]
Rust,
C,
CPP,
Rust,
Python,
NodeJs,
Golang,
Java,
}

pub async fn compile<B: Into<PathBuf>, E: AsRef<str>, O: AsRef<str>>(
pub async fn compile<B: Into<PathBuf>, S: Into<PathBuf>, O: AsRef<str>>(
language: Language,
base: B,
source_file: E,
source_file_path: S,
output_file: O,
) -> Result<()> {
let base_path = Into::<PathBuf>::into(base);
let source_path = base_path.join(source_file.as_ref());
let source_path = Into::<PathBuf>::into(source_file_path);
let source_path_str = source_path.to_string_lossy();
let output_path = base_path.join(output_file.as_ref());
let output_path_str = output_path.to_string_lossy();
Expand Down Expand Up @@ -84,6 +87,27 @@ pub async fn compile<B: Into<PathBuf>, E: AsRef<str>, O: AsRef<str>>(
Some(command)
}
Language::NodeJs => None,
Language::Golang => {
let mut command = Command::new("go");
command.args([
"build",
"-o",
output_path_str.as_ref(),
source_path_str.as_ref(),
]);
Some(command)
}
Language::Java => {
let java_path = base_path.join("Main.java");
let mut command = Command::new("javac");
io::copy(
&mut File::open(source_path_str.as_ref()).await?,
&mut File::create(&java_path).await?,
)
.await?;
command.arg(java_path.to_string_lossy().as_ref());
Some(command)
}
};

if let Some(mut command) = command {
Expand Down
12 changes: 12 additions & 0 deletions tests/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <stdio.h>

typedef long long int i64;

int main()
{
i64 a, b;
scanf("%lld %lld", &a, &b);
printf("%lld\n", a + b);
printf("%lld\n", a + b);
return 0;
}
17 changes: 17 additions & 0 deletions tests/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"
)

func main() {
var num1, num2 int32

fmt.Scan(&num1)

fmt.Scan(&num2)

sum := num1 + num2
fmt.Println(sum)
fmt.Println(sum)
}
17 changes: 17 additions & 0 deletions tests/test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

int num1 = scanner.nextInt();

int num2 = scanner.nextInt();

int sum = num1 + num2;
System.out.printf("%d\n", sum);
System.out.printf("%d", sum);

scanner.close();
}
}
2 changes: 1 addition & 1 deletion tests/test_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use eval_stack::{case::run_test_cases, compile::Language, config::JudgeOptions};
#[tokio::test]
async fn test_fs() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("workspace");
let workspace_path = current_dir.join("fs_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Expand Down
106 changes: 101 additions & 5 deletions tests/test_judge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use eval_stack::{case::run_test_cases, compile::Language, config::JudgeOptions};
#[tokio::test]
async fn test_rust_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("workspace");
let workspace_path = current_dir.join("rust_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Expand Down Expand Up @@ -61,7 +61,7 @@ async fn test_rust_judge() -> Result<()> {
#[tokio::test]
async fn test_cpp_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("workspace");
let workspace_path = current_dir.join("cpp_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Expand Down Expand Up @@ -90,10 +90,42 @@ async fn test_cpp_judge() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn test_c_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("c_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Language::C,
&workspace_path,
&tests_path.join("test.c"),
JudgeOptions {
time_limit: Duration::from_secs(1),
memory_limit: 128 * 1024 * 1024,
fail_fast: true,
no_startup_limits: false,
},
vec![
(tests_path.join("1.in"), tests_path.join("1.out")),
(tests_path.join("2.in"), tests_path.join("2.out")),
],
true,
)
.await?;

for result in results {
println!("{:?}", result);
assert!(result.is_accepted())
}

Ok(())
}

#[tokio::test]
async fn test_python_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("workspace");
let workspace_path = current_dir.join("python_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Expand Down Expand Up @@ -125,7 +157,7 @@ async fn test_python_judge() -> Result<()> {
#[tokio::test]
async fn test_nodejs_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("workspace");
let workspace_path = current_dir.join("nodejs_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Expand All @@ -142,7 +174,71 @@ async fn test_nodejs_judge() -> Result<()> {
(tests_path.join("1.in"), tests_path.join("1.out")),
(tests_path.join("2.in"), tests_path.join("2.out")),
],
false,
true,
)
.await?;

for result in results {
println!("{:?}", result);
assert!(result.is_accepted())
}

Ok(())
}

#[tokio::test]
async fn test_golang_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("golang_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Language::Golang,
&workspace_path,
&tests_path.join("test.go"),
JudgeOptions {
time_limit: Duration::from_secs(1),
memory_limit: 128 * 1024 * 1024,
fail_fast: true,
no_startup_limits: true,
},
vec![
(tests_path.join("1.in"), tests_path.join("1.out")),
(tests_path.join("2.in"), tests_path.join("2.out")),
],
true,
)
.await?;

for result in results {
println!("{:?}", result);
assert!(result.is_accepted())
}

Ok(())
}

#[tokio::test]
async fn test_java_judge() -> Result<()> {
let current_dir = std::env::current_dir()?;
let workspace_path = current_dir.join("java_workspace");
let tests_path = current_dir.join("tests");

let results = run_test_cases(
Language::Java,
&workspace_path,
&tests_path.join("test.java"),
JudgeOptions {
time_limit: Duration::from_secs(1),
memory_limit: 128 * 1024 * 1024,
fail_fast: true,
no_startup_limits: true,
},
vec![
(tests_path.join("1.in"), tests_path.join("1.out")),
(tests_path.join("2.in"), tests_path.join("2.out")),
],
true,
)
.await?;

Expand Down