Skip to content

Commit 75b629e

Browse files
Add local compile tests for default templates / code generators (#92)
* #89 yaml definition to install compilers * #89 Add sudo * #89 Add unit test for cpp to check compile * #89 refactor * #89 fix mistakenly renamed var and change yaml to support c++14 * #89 Update yaml * #89 Update yaml * #89 add -y to add-apt-repository * #89 polite way to build * #89 autopep8 * Separate run_command and run_program * Remove TODO * Refactor * Fix bug of wrong generator specification * make general version of compile test * Resolve a bug of Java code generator * verify java * fix rust's constant embedding problem and make rust passing unit tests * fix broken unit test * static -> const * autopep8
1 parent ccab876 commit 75b629e

26 files changed

+883
-89
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ python:
55
- "3.6"
66
- "3.7-dev"
77

8+
before_install:
9+
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for C++14
10+
- sudo apt-get update
11+
- sudo apt-get install rustc g++-4.9 openjdk-8-jdk
12+
- sudo ln -f -s /usr/bin/g++-4.9 /usr/bin/g++
13+
814
install:
915
- pip install .
1016
- pip install flake8 autopep8

atcodertools/codegen/code_generators/java.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _generate_declaration(self, var: Variable):
4242
size=var.first_index.get_length()
4343
)
4444
elif var.dim_num() == 2:
45-
constructor = " = new {type}[int({row_size})][int({col_size})]".format(
45+
constructor = " = new {type}[(int)({row_size})][(int)({col_size})]".format(
4646
type=self._convert_type(var.type),
4747
row_size=var.first_index.get_length(),
4848
col_size=var.second_index.get_length()

atcodertools/common/language.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22
from typing import Pattern, Callable
33

4-
from atcodertools.codegen.code_generators import cpp, java
4+
from atcodertools.codegen.code_generators import cpp, java, rust
55
from atcodertools.codegen.models.code_gen_args import CodeGenArgs
66
from atcodertools.tools.templates import get_default_template_path
77

@@ -27,6 +27,10 @@ def __init__(self,
2727
self.default_code_generator = default_code_generator
2828
self.default_template_path = default_template_path
2929

30+
def source_code_name(self, name_without_extension: str) -> str:
31+
# put extension to the name
32+
return "{}.{}".format(name_without_extension, self.extension)
33+
3034
@classmethod
3135
def from_name(cls, name: str):
3236
for l in ALL_LANGUAGES:
@@ -59,7 +63,7 @@ def from_name(cls, name: str):
5963
display_name="Rust",
6064
extension="rs",
6165
submission_lang_pattern=re.compile(".*Rust \\(1.*"),
62-
default_code_generator=java.main,
66+
default_code_generator=rust.main,
6367
default_template_path=get_default_template_path('rs'),
6468
)
6569

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
import subprocess
2-
3-
4-
def _run_command(exec_cmd: str, current_working_dir: str) -> str:
5-
proc = subprocess.run(exec_cmd,
6-
shell=True,
7-
stdout=subprocess.PIPE,
8-
stderr=subprocess.STDOUT,
9-
cwd=current_working_dir)
10-
return proc.stdout.decode("utf8")
1+
from atcodertools.executils.run_command import run_command
112

123

134
class PostprocessConfig:
@@ -21,8 +12,8 @@ def __init__(self,
2112

2213
def execute_on_problem_dir(self, problem_dir: str) -> str:
2314
assert self.exec_cmd_on_problem_dir is not None
24-
return _run_command(self.exec_cmd_on_problem_dir, problem_dir)
15+
return run_command(self.exec_cmd_on_problem_dir, problem_dir)
2516

2617
def execute_on_contest_dir(self, contest_dir: str) -> str:
2718
assert self.exec_cmd_on_contest_dir is not None
28-
return _run_command(self.exec_cmd_on_contest_dir, contest_dir)
19+
return run_command(self.exec_cmd_on_contest_dir, contest_dir)

atcodertools/executils/__init__.py

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import subprocess
2+
3+
4+
def run_command(exec_cmd: str, current_working_dir: str) -> str:
5+
proc = subprocess.run(exec_cmd,
6+
shell=True,
7+
stdout=subprocess.PIPE,
8+
stderr=subprocess.STDOUT,
9+
cwd=current_working_dir)
10+
return proc.stdout.decode("utf8")
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import subprocess
2+
import time
3+
from enum import Enum
4+
5+
6+
class ExecStatus(Enum):
7+
NORMAL = "NORMAL"
8+
TLE = "TLE"
9+
RE = "RE"
10+
11+
12+
class ExecResult:
13+
14+
def __init__(self, status: ExecStatus, output: str = None, stderr: str = None, elapsed_sec: float = None):
15+
self.status = status
16+
self.output = output
17+
self.stderr = stderr
18+
19+
if elapsed_sec is not None:
20+
self.elapsed_ms = int(elapsed_sec * 1000 + 0.5)
21+
else:
22+
self.elapsed_ms = None
23+
24+
def is_correct_output(self, answer_text):
25+
return self.status == ExecStatus.NORMAL and answer_text == self.output
26+
27+
def has_stderr(self):
28+
return len(self.stderr) > 0
29+
30+
31+
def run_program(exec_file: str, input_file: str, timeout_sec: int, args=None, current_working_dir: str = None) -> ExecResult:
32+
if args is None:
33+
args = []
34+
try:
35+
elapsed_sec = -time.time()
36+
proc = subprocess.run(
37+
[exec_file] + args, stdin=open(input_file, 'r'), universal_newlines=True, timeout=timeout_sec,
38+
stdout=subprocess.PIPE,
39+
stderr=subprocess.PIPE,
40+
cwd=current_working_dir
41+
)
42+
43+
if proc.returncode == 0:
44+
code = ExecStatus.NORMAL
45+
else:
46+
code = ExecStatus.RE
47+
48+
elapsed_sec += time.time()
49+
return ExecResult(code, proc.stdout, proc.stderr, elapsed_sec=elapsed_sec)
50+
except subprocess.TimeoutExpired as e:
51+
return ExecResult(ExecStatus.TLE, e.stdout, e.stderr)
52+
except subprocess.CalledProcessError as e:
53+
return ExecResult(ExecStatus.RE, e.stdout, e.stderr)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def load_text_file(text_file: str) -> str:
2+
with open(text_file, 'r') as f:
3+
return f.read()

atcodertools/fmtprediction/models/calculator.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,31 @@ class UnknownOperatorError(Exception):
1616

1717

1818
def add(a, b):
19-
return a + b
19+
try:
20+
return a + b
21+
except TypeError as e:
22+
raise EvaluateError(e)
2023

2124

2225
def sub(a, b):
23-
return a - b
26+
try:
27+
return a - b
28+
except TypeError as e:
29+
raise EvaluateError(e)
2430

2531

2632
def mul(a, b):
27-
return a * b
33+
try:
34+
return a * b
35+
except TypeError as e:
36+
raise EvaluateError(e)
2837

2938

3039
def div(a, b):
31-
return a // b
40+
try:
41+
return a // b
42+
except TypeError as e:
43+
raise EvaluateError(e)
3244

3345

3446
def _operator_to_string(operator):

atcodertools/fmtprediction/predict_types.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import re
22
from typing import List, Dict, Any
33

4+
from atcodertools.fmtprediction.models.calculator import EvaluateError
45
from atcodertools.fmtprediction.models.type import Type
56
from atcodertools.client.models.sample import Sample
67
from atcodertools.fmtprediction.models.variable import SimpleVariable
@@ -146,7 +147,7 @@ def predict_types(simple_format: Format[SimpleVariable], samples: List[Sample])
146147
predictor.get_typing_result())
147148
except (
148149
TooLessFetchesError, TooManyFetchesError, KeyError, InvalidLoopSizeError,
149-
InvalidLoopIndexError):
150+
InvalidLoopIndexError, EvaluateError):
150151
raise TypePredictionFailedError
151152

152153
return res_type_dict

0 commit comments

Comments
 (0)