Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit e7a9f4e

Browse files
committed
Added test for communication task and fixed bug with pascal compilation
1 parent afc3a59 commit e7a9f4e

File tree

18 files changed

+228
-40
lines changed

18 files changed

+228
-40
lines changed

python/formats/ioi_format.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def get_official_solution() -> Optional[str]:
6161
return None
6262

6363

64-
def gen_testcases(copy_compiled: bool) -> Dict[int, Subtask]:
64+
def gen_testcases(copy_compiled: bool, task: Task) -> Dict[int, Subtask]:
6565
subtasks = {} # type: Dict[int, Subtask]
6666

6767
def create_subtask(subtask_num: int, testcases: Dict[int, TestCase],
@@ -77,15 +77,15 @@ def create_subtask(subtask_num: int, testcases: Dict[int, TestCase],
7777
else:
7878
generator = Generator(
7979
"default",
80-
SourceFile.from_file(generator, copy_compiled and "bin/generator"),
81-
None)
80+
SourceFile.from_file(generator, task.name, copy_compiled
81+
and "bin/generator"), None)
8282
validator = get_validator()
8383
if not validator:
8484
raise RuntimeError("No validator found")
8585
validator = Validator(
8686
"default",
87-
SourceFile.from_file(validator, copy_compiled and "bin/validator"),
88-
None)
87+
SourceFile.from_file(validator, task.name, copy_compiled
88+
and "bin/validator"), None)
8989

9090
current_testcases = {} # type: Dict[int, TestCase]
9191
subtask_num = -1 # the first #ST line will skip a subtask!
@@ -227,22 +227,23 @@ def create_task(config: Config):
227227
if official_solution:
228228
task.official_solution = SourceFile.from_file(
229229
official_solution,
230+
task.name,
230231
copy_compiled and "bin/official_solution",
231232
grader_map=grader_map)
232233

233234
if checker is not None:
234-
task.checker = SourceFile.from_file(checker, copy_compiled
235+
task.checker = SourceFile.from_file(checker, task.name, copy_compiled
235236
and "bin/checker")
236237
if manager is not None:
237-
task.checker = SourceFile.from_file(manager, copy_compiled
238+
task.checker = SourceFile.from_file(manager, task.name, copy_compiled
238239
and "bin/manager")
239240

240241
sols = [] # type: List[Solution]
241242
for solution in solutions:
242243
path, ext = os.path.splitext(os.path.basename(solution))
243244
bin_file = copy_compiled and "bin/" + path + "_" + ext[1:]
244245
source = SourceFile.from_file(
245-
solution, bin_file, grader_map=grader_map)
246+
solution, task.name, bin_file, grader_map=grader_map)
246247
if task.task_type == TaskType.Batch:
247248
sols.append(BatchSolution(source, task, config, task.checker))
248249
else:
@@ -255,7 +256,7 @@ def create_task(config: Config):
255256

256257
def get_request(config: Config) -> (Task, List[Solution]):
257258
task, sols = create_task(config)
258-
subtasks = gen_testcases(config.copy_exe)
259+
subtasks = gen_testcases(config.copy_exe, task)
259260
for subtask_num, subtask in subtasks.items():
260261
task.subtasks[subtask_num] = subtask
261262
return task, sols
@@ -272,8 +273,8 @@ def evaluate_task(frontend: Frontend, task: Task, solutions: List[Solution],
272273
curses_ui.start()
273274

274275
ins, outs, vals = generate_inputs(frontend, task, ui_interface, config)
275-
evaluate_solutions(frontend, ins, outs, vals, solutions,
276-
ui_interface, config)
276+
evaluate_solutions(frontend, ins, outs, vals, solutions, ui_interface,
277+
config)
277278

278279
frontend.evaluate()
279280
if config.ui == UIS.CURSES:
@@ -386,11 +387,11 @@ def add_non_solution(source: SourceFile):
386387
return inputs, outputs, validations
387388

388389

389-
def evaluate_solutions(
390-
frontend, inputs: Dict[Tuple[int, int], File],
391-
outputs: Dict[Tuple[int, int], File],
392-
validations: Dict[Tuple[int, int], File], solutions: List[Solution],
393-
interface: IOIUIInterface, config: Config):
390+
def evaluate_solutions(frontend, inputs: Dict[Tuple[int, int], File],
391+
outputs: Dict[Tuple[int, int], File],
392+
validations: Dict[Tuple[int, int], File],
393+
solutions: List[Solution], interface: IOIUIInterface,
394+
config: Config):
394395
for solution in solutions:
395396
solution.solution.prepare(frontend, config)
396397
interface.add_solution(solution.solution)

python/formats/tm_format.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from task_maker.source_file import SourceFile
1515

1616

17-
def parse_cases(gen: IO, copy_compiled) -> List[Subtask]:
17+
def parse_cases(gen: IO, copy_compiled: bool, task: Task) -> List[Subtask]:
1818
lines = [l.strip() for l in gen.readlines()]
1919

2020
subtasks = [] # type: List[Subtask]
@@ -31,13 +31,13 @@ def parse_cases(gen: IO, copy_compiled) -> List[Subtask]:
3131
if guessed_gen:
3232
default_gen = Generator(
3333
"default",
34-
SourceFile.from_file(guessed_gen, copy_compiled
34+
SourceFile.from_file(guessed_gen, task.name, copy_compiled
3535
and "bin/gen_default"), [])
3636
guessed_val = get_validator()
3737
if guessed_val:
3838
default_val = Validator(
3939
"default",
40-
SourceFile.from_file(guessed_val, copy_compiled
40+
SourceFile.from_file(guessed_val, task.name, copy_compiled
4141
and "bin/val_default"), [])
4242

4343
def is_float(s):
@@ -64,7 +64,7 @@ def process_GEN(args: List[str]):
6464
"Duplicate GEN definition at line %d" % lineno)
6565
generator = Generator(
6666
name,
67-
SourceFile.from_file(args[1], copy_compiled
67+
SourceFile.from_file(args[1], task.name, copy_compiled
6868
and "bin/gen_" + name), args[2:])
6969
generators[name] = generator
7070
if name == "default":
@@ -95,7 +95,7 @@ def process_VAL(args: List[str]):
9595
"Duplicate VAL definition at line %d" % lineno)
9696
validator = Validator(
9797
name,
98-
SourceFile.from_file(args[1], copy_compiled
98+
SourceFile.from_file(args[1], task.name, copy_compiled
9999
and "bin/val_" + name), args[2:])
100100
validators[name] = validator
101101
if name == "default":

python/languages/__init__.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ def header_extensions(self) -> List[str]:
6868
"""
6969
return []
7070

71+
@property
72+
def need_unit_name(self) -> bool:
73+
"""
74+
Whether this language needs the source file to be called in a proper
75+
way. The basename without extension is passed to get_compilation_command
76+
"""
77+
return False
78+
7179
def get_execution_command(self, exe_name: str, args: List[str],
7280
main=None) -> (CommandType, List[str]):
7381
"""
@@ -79,12 +87,16 @@ def get_execution_command(self, exe_name: str, args: List[str],
7987
return CommandType.LOCAL_FILE, [exe_name] + args
8088

8189
def get_compilation_command(self, source_filenames: List[str],
82-
exe_name: str, for_evaluation: bool,
90+
exe_name: str, unit_name: str,
91+
for_evaluation: bool,
8392
target_arch: Arch) -> (CommandType, List[str]):
8493
"""
8594
Get the command to use to compile some files from this language
8695
:param source_filenames: List of files to compile
8796
:param exe_name: Name of the executable to produce
97+
:param unit_name: Name of the source file that may be used to compile.
98+
It is used only the languages that requires a specific name of the
99+
source file. It's without the extension.
88100
:param for_evaluation: Whether to set the EVAL variable
89101
:param target_arch: Architecture to target the executable on
90102
"""

python/languages/c.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ def header_extensions(self):
4343
return [".h"]
4444

4545
def get_compilation_command(self, source_filenames: List[str],
46-
exe_name: str, for_evaluation: bool,
46+
exe_name: str, unit_name: str,
47+
for_evaluation: bool,
4748
target_arch: Arch) -> (CommandType, List[str]):
4849
cmd = ["cc"]
4950
if for_evaluation:

python/languages/cpp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ def header_extensions(self):
2121
return [".hpp"]
2222

2323
def get_compilation_command(self, source_filenames: List[str],
24-
exe_name: str, for_evaluation: bool,
24+
exe_name: str, unit_name: str,
25+
for_evaluation: bool,
2526
target_arch: Arch) -> (CommandType, List[str]):
2627
cmd = ["c++"]
2728
if for_evaluation:

python/languages/pascal.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,25 @@ def name(self):
1414
def source_extensions(self):
1515
return [".pas"]
1616

17+
@property
18+
def need_unit_name(self):
19+
return True
20+
1721
def get_compilation_command(self, source_filenames: List[str],
18-
exe_name: str, for_evaluation: bool,
22+
exe_name: str, unit_name: str,
23+
for_evaluation: bool,
1924
target_arch: Arch) -> (CommandType, List[str]):
2025
cmd = ["fpc"]
2126
if for_evaluation:
2227
cmd += ["-dEVAL"]
2328
if target_arch != Arch.DEFAULT:
2429
raise NotImplementedError(
2530
"Cannot compile %s: "
26-
"targetting Pascal executables is not supported yet"
27-
% source_filenames[0])
31+
"targetting Pascal executables is not supported yet" %
32+
source_filenames[0])
2833
cmd += ["-Fe/dev/stderr"] # fpc emits errors on stdout by default
2934
cmd += ["-O2", "-XS", "-o" + exe_name]
30-
cmd += source_filenames
35+
cmd += [unit_name + ".pas"] + source_filenames[1:]
3136
return CommandType.SYSTEM, cmd
3237

3338

python/languages/rust.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ def source_extensions(self):
1515
return [".rs"]
1616

1717
def get_compilation_command(self, source_filenames: List[str],
18-
exe_name: str, for_evaluation: bool,
18+
exe_name: str, unit_name: str,
19+
for_evaluation: bool,
1920
target_arch: Arch) -> (CommandType, List[str]):
2021
cmd = ["rustc"]
2122
if for_evaluation:
2223
cmd += ["--cfg", "EVAL"]
2324
if target_arch != Arch.DEFAULT:
2425
raise NotImplementedError(
2526
"Cannot compile %s: "
26-
"targetting Rust executables is not supported yet"
27-
% source_filenames[0])
27+
"targetting Rust executables is not supported yet" %
28+
source_filenames[0])
2829
cmd += ["-O", "-o", exe_name]
2930
# with rustc you only need to specify the main file
3031
cmd += [source_filenames[0]]

python/source_file.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class SourceFile:
1414
@staticmethod
1515
def from_file(
1616
path: str,
17+
unit_name: str,
1718
write_to: Optional[str] = None,
1819
target_arch=Arch.DEFAULT,
1920
grader_map: Dict[Language, GraderInfo] = dict()) -> "SourceFile":
@@ -23,8 +24,9 @@ def from_file(
2324
if not path:
2425
raise ValueError("Cannot find %s" % old_path)
2526
language = LanguageManager.from_file(path)
26-
source_file = SourceFile(path, language.get_dependencies(path), language, None,
27-
target_arch, grader_map.get(language))
27+
source_file = SourceFile(path, unit_name,
28+
language.get_dependencies(path), language,
29+
None, target_arch, grader_map.get(language))
2830
if write_to:
2931
if not os.path.isabs(write_to):
3032
write_to = os.path.join(os.getcwd(), write_to)
@@ -35,10 +37,12 @@ def from_file(
3537
"Please check the shebang (#!)" % path)
3638
return source_file
3739

38-
def __init__(self, path: str, dependencies: List[Dependency],
39-
language: Language, write_bin_to: Optional[str],
40-
target_arch: Arch, grader: Optional["GraderInfo"]):
40+
def __init__(self, path: str, unit_name: str,
41+
dependencies: List[Dependency], language: Language,
42+
write_bin_to: Optional[str], target_arch: Arch,
43+
grader: Optional["GraderInfo"]):
4144
self.path = path
45+
self.unit_name = unit_name
4246
self.dependencies = dependencies
4347
self.language = language
4448
self.write_bin_to = write_bin_to
@@ -66,7 +70,8 @@ def _compile(self, frontend, config: Config):
6670
if self.grader:
6771
compilation_files += [d.name for d in self.grader.files]
6872
cmd_type, cmd = self.language.get_compilation_command(
69-
compilation_files, self.exe_name, True, self.target_arch)
73+
compilation_files, self.exe_name, self.unit_name, True,
74+
self.target_arch)
7075

7176
if cmd_type != CommandType.SYSTEM:
7277
raise ValueError("Local file compilers are not supported yet")
@@ -79,7 +84,11 @@ def _compile(self, frontend, config: Config):
7984
self.compilation.disableCache()
8085
self.compilation.setExecutablePath(cmd[0])
8186
self.compilation.setArgs(cmd[1:])
82-
self.compilation.addInput(self.name, source)
87+
if self.language.need_unit_name:
88+
self.compilation.addInput(
89+
self.unit_name + self.language.source_extensions[0], source)
90+
else:
91+
self.compilation.addInput(self.name, source)
8392
for dep in self.dependencies:
8493
self.compilation.addInput(
8594
dep.name, frontend.provideFile(dep.path, dep.path, False))

python/tests/communication.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env python3
2+
3+
from task_maker.tests.test import run_tests
4+
5+
6+
def test_task():
7+
from task_maker.tests.utils import TestInterface
8+
interface = TestInterface("communication", "Testing task-maker", 1, 65536)
9+
message = "A-ha, you're the best adding program I've ever met!"
10+
interface.add_solution("solution.c", 100, [100],
11+
[(1, message)] * 3)
12+
interface.add_solution("solution.cpp", 100, [100],
13+
[(1, message)] * 3)
14+
interface.add_solution("solution.pas", 100, [100],
15+
[(1, message)] * 3)
16+
interface.run_checks()
17+
18+
19+
if __name__ == "__main__":
20+
run_tests("communication", __file__)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
#include <cstdio>
3+
#include <cstdlib>
4+
#include <signal.h>
5+
6+
using namespace std;
7+
8+
int main(int argc, char **argv) {
9+
signal(SIGPIPE, SIG_IGN);
10+
11+
FILE *fin, *fout, *fifo_in, *fifo_out;
12+
13+
fin = fopen("input.txt", "r");
14+
fout = fopen("output.txt", "w");
15+
fifo_in = fopen(argv[1], "w");
16+
fifo_out = fopen(argv[2], "r");
17+
18+
int a, b, res;
19+
fscanf(fin, "%d %d", &a, &b);
20+
fprintf(fifo_in, "%d %d\n", a, b);
21+
fflush(fifo_in);
22+
fscanf(fifo_out, "%d", &res);
23+
fprintf(fout, "%d\n", res);
24+
fflush(fout);
25+
26+
if (a+b == res) {
27+
fprintf(stderr, "A-ha, you're the best adding program I've ever met!\n");
28+
printf("1.0\n");
29+
} else {
30+
fprintf(stderr, "How dreadful, never met anyone as dumb as you...\n");
31+
printf("0.0\n");
32+
}
33+
34+
fclose(fin);
35+
fclose(fout);
36+
fclose(fifo_in);
37+
fclose(fifo_out);
38+
39+
}
40+

0 commit comments

Comments
 (0)