Skip to content

Commit 45b085a

Browse files
authored
feat(lang): support java and golang (#11)
1 parent bb19118 commit 45b085a

11 files changed

+190
-14
lines changed

.changes/lang.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eval-stack": patch:feat
3+
---
4+
5+
Support for Java and Golang.

.cspell.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"covector",
77
"fmax",
88
"getuid",
9+
"javac",
910
"libc",
1011
"NEWNS",
1112
"prctl",

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "Online Judge core runtime for ACMers",
55
"main": "index.js",
66
"scripts": {
7-
"covector": "covector"
7+
"covector": "covector",
8+
"test": "cargo test"
89
},
910
"keywords": [
1011
"oj",

src/case.rs

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ where
3434
let exec_path = match &language {
3535
Language::Python => which("python")?,
3636
Language::NodeJs => which("deno")?,
37+
Language::Java => which("java")?,
3738
_ => workspace.join("out"),
3839
};
3940

@@ -65,9 +66,11 @@ where
6566
"--deny-ffi=*",
6667
source_file_path.as_str(),
6768
];
69+
let java_args = vec!["Main"];
6870
let args = match language {
6971
Language::Python => Some(&py_args),
7072
Language::NodeJs => Some(&deno_args),
73+
Language::Java => Some(&java_args),
7174
_ => None,
7275
}
7376
.map(|v| &**v);

src/compile.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,30 @@ use std::{
55
};
66

77
use anyhow::Result;
8-
use tokio::process::Command;
8+
use tokio::{fs::File, io, process::Command};
99

10-
#[derive(Clone, Copy)]
10+
#[derive(Default, Debug, Clone, Copy)]
1111
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1212
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
1313
pub enum Language {
14+
#[default]
15+
Rust,
1416
C,
1517
CPP,
16-
Rust,
1718
Python,
1819
NodeJs,
20+
Golang,
21+
Java,
1922
}
2023

21-
pub async fn compile<B: Into<PathBuf>, E: AsRef<str>, O: AsRef<str>>(
24+
pub async fn compile<B: Into<PathBuf>, S: Into<PathBuf>, O: AsRef<str>>(
2225
language: Language,
2326
base: B,
24-
source_file: E,
27+
source_file_path: S,
2528
output_file: O,
2629
) -> Result<()> {
2730
let base_path = Into::<PathBuf>::into(base);
28-
let source_path = base_path.join(source_file.as_ref());
31+
let source_path = Into::<PathBuf>::into(source_file_path);
2932
let source_path_str = source_path.to_string_lossy();
3033
let output_path = base_path.join(output_file.as_ref());
3134
let output_path_str = output_path.to_string_lossy();
@@ -84,6 +87,27 @@ pub async fn compile<B: Into<PathBuf>, E: AsRef<str>, O: AsRef<str>>(
8487
Some(command)
8588
}
8689
Language::NodeJs => None,
90+
Language::Golang => {
91+
let mut command = Command::new("go");
92+
command.args([
93+
"build",
94+
"-o",
95+
output_path_str.as_ref(),
96+
source_path_str.as_ref(),
97+
]);
98+
Some(command)
99+
}
100+
Language::Java => {
101+
let java_path = base_path.join("Main.java");
102+
let mut command = Command::new("javac");
103+
io::copy(
104+
&mut File::open(source_path_str.as_ref()).await?,
105+
&mut File::create(&java_path).await?,
106+
)
107+
.await?;
108+
command.arg(java_path.to_string_lossy().as_ref());
109+
Some(command)
110+
}
87111
};
88112

89113
if let Some(mut command) = command {

tests/test.c

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdio.h>
2+
3+
typedef long long int i64;
4+
5+
int main()
6+
{
7+
i64 a, b;
8+
scanf("%lld %lld", &a, &b);
9+
printf("%lld\n", a + b);
10+
printf("%lld\n", a + b);
11+
return 0;
12+
}

tests/test.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func main() {
8+
var num1, num2 int32
9+
10+
fmt.Scan(&num1)
11+
12+
fmt.Scan(&num2)
13+
14+
sum := num1 + num2
15+
fmt.Println(sum)
16+
fmt.Println(sum)
17+
}

tests/test.java

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import java.util.Scanner;
2+
3+
public class Main {
4+
public static void main(String[] args) {
5+
Scanner scanner = new Scanner(System.in);
6+
7+
int num1 = scanner.nextInt();
8+
9+
int num2 = scanner.nextInt();
10+
11+
int sum = num1 + num2;
12+
System.out.printf("%d\n", sum);
13+
System.out.printf("%d", sum);
14+
15+
scanner.close();
16+
}
17+
}

tests/test_fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use eval_stack::{case::run_test_cases, compile::Language, config::JudgeOptions};
66
#[tokio::test]
77
async fn test_fs() -> Result<()> {
88
let current_dir = std::env::current_dir()?;
9-
let workspace_path = current_dir.join("workspace");
9+
let workspace_path = current_dir.join("fs_workspace");
1010
let tests_path = current_dir.join("tests");
1111

1212
let results = run_test_cases(

tests/test_judge.rs

+101-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use eval_stack::{case::run_test_cases, compile::Language, config::JudgeOptions};
66
#[tokio::test]
77
async fn test_rust_judge() -> Result<()> {
88
let current_dir = std::env::current_dir()?;
9-
let workspace_path = current_dir.join("workspace");
9+
let workspace_path = current_dir.join("rust_workspace");
1010
let tests_path = current_dir.join("tests");
1111

1212
let results = run_test_cases(
@@ -61,7 +61,7 @@ async fn test_rust_judge() -> Result<()> {
6161
#[tokio::test]
6262
async fn test_cpp_judge() -> Result<()> {
6363
let current_dir = std::env::current_dir()?;
64-
let workspace_path = current_dir.join("workspace");
64+
let workspace_path = current_dir.join("cpp_workspace");
6565
let tests_path = current_dir.join("tests");
6666

6767
let results = run_test_cases(
@@ -90,10 +90,42 @@ async fn test_cpp_judge() -> Result<()> {
9090
Ok(())
9191
}
9292

93+
#[tokio::test]
94+
async fn test_c_judge() -> Result<()> {
95+
let current_dir = std::env::current_dir()?;
96+
let workspace_path = current_dir.join("c_workspace");
97+
let tests_path = current_dir.join("tests");
98+
99+
let results = run_test_cases(
100+
Language::C,
101+
&workspace_path,
102+
&tests_path.join("test.c"),
103+
JudgeOptions {
104+
time_limit: Duration::from_secs(1),
105+
memory_limit: 128 * 1024 * 1024,
106+
fail_fast: true,
107+
no_startup_limits: false,
108+
},
109+
vec![
110+
(tests_path.join("1.in"), tests_path.join("1.out")),
111+
(tests_path.join("2.in"), tests_path.join("2.out")),
112+
],
113+
true,
114+
)
115+
.await?;
116+
117+
for result in results {
118+
println!("{:?}", result);
119+
assert!(result.is_accepted())
120+
}
121+
122+
Ok(())
123+
}
124+
93125
#[tokio::test]
94126
async fn test_python_judge() -> Result<()> {
95127
let current_dir = std::env::current_dir()?;
96-
let workspace_path = current_dir.join("workspace");
128+
let workspace_path = current_dir.join("python_workspace");
97129
let tests_path = current_dir.join("tests");
98130

99131
let results = run_test_cases(
@@ -125,7 +157,7 @@ async fn test_python_judge() -> Result<()> {
125157
#[tokio::test]
126158
async fn test_nodejs_judge() -> Result<()> {
127159
let current_dir = std::env::current_dir()?;
128-
let workspace_path = current_dir.join("workspace");
160+
let workspace_path = current_dir.join("nodejs_workspace");
129161
let tests_path = current_dir.join("tests");
130162

131163
let results = run_test_cases(
@@ -142,7 +174,71 @@ async fn test_nodejs_judge() -> Result<()> {
142174
(tests_path.join("1.in"), tests_path.join("1.out")),
143175
(tests_path.join("2.in"), tests_path.join("2.out")),
144176
],
145-
false,
177+
true,
178+
)
179+
.await?;
180+
181+
for result in results {
182+
println!("{:?}", result);
183+
assert!(result.is_accepted())
184+
}
185+
186+
Ok(())
187+
}
188+
189+
#[tokio::test]
190+
async fn test_golang_judge() -> Result<()> {
191+
let current_dir = std::env::current_dir()?;
192+
let workspace_path = current_dir.join("golang_workspace");
193+
let tests_path = current_dir.join("tests");
194+
195+
let results = run_test_cases(
196+
Language::Golang,
197+
&workspace_path,
198+
&tests_path.join("test.go"),
199+
JudgeOptions {
200+
time_limit: Duration::from_secs(1),
201+
memory_limit: 128 * 1024 * 1024,
202+
fail_fast: true,
203+
no_startup_limits: true,
204+
},
205+
vec![
206+
(tests_path.join("1.in"), tests_path.join("1.out")),
207+
(tests_path.join("2.in"), tests_path.join("2.out")),
208+
],
209+
true,
210+
)
211+
.await?;
212+
213+
for result in results {
214+
println!("{:?}", result);
215+
assert!(result.is_accepted())
216+
}
217+
218+
Ok(())
219+
}
220+
221+
#[tokio::test]
222+
async fn test_java_judge() -> Result<()> {
223+
let current_dir = std::env::current_dir()?;
224+
let workspace_path = current_dir.join("java_workspace");
225+
let tests_path = current_dir.join("tests");
226+
227+
let results = run_test_cases(
228+
Language::Java,
229+
&workspace_path,
230+
&tests_path.join("test.java"),
231+
JudgeOptions {
232+
time_limit: Duration::from_secs(1),
233+
memory_limit: 128 * 1024 * 1024,
234+
fail_fast: true,
235+
no_startup_limits: true,
236+
},
237+
vec![
238+
(tests_path.join("1.in"), tests_path.join("1.out")),
239+
(tests_path.join("2.in"), tests_path.join("2.out")),
240+
],
241+
true,
146242
)
147243
.await?;
148244

0 commit comments

Comments
 (0)