Skip to content

Commit 82213e6

Browse files
Output stdout even when getting RE or TLE (#84)
* Update version to 1.1.0 * Update README * Update CHANGELOG.md * fix a bug of Java template (no issue) * #83 Show stdout even when getting RE or TLE * #83 Support stderr output * #83 More recognizable header color * Treat outputting stderr as special failure case * autopep * autopep8
1 parent 49f811f commit 82213e6

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

atcodertools/tools/tester.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#!/usr/bin/python3
22
import argparse
3+
import glob
34
import logging
4-
import sys
55
import os
6-
import glob
76
import subprocess
7+
import sys
88
import time
99
from enum import Enum
1010
from pathlib import Path
@@ -32,16 +32,21 @@ class ExecStatus(Enum):
3232

3333
class ExecResult:
3434

35-
def __init__(self, status: ExecStatus, output: str = None, elapsed_sec: float = None):
35+
def __init__(self, status: ExecStatus, output: str = None, stderr: str = None, elapsed_sec: float = None):
3636
self.status = status
3737
self.output = output
38+
self.stderr = stderr
39+
3840
if elapsed_sec is not None:
3941
self.elapsed_ms = int(elapsed_sec * 1000 + 0.5)
4042
else:
4143
self.elapsed_ms = None
4244

4345
def is_correct_output(self, answer_text):
44-
return answer_text == self.output
46+
return self.status == ExecStatus.NORMAL and answer_text == self.output
47+
48+
def has_stderr(self):
49+
return len(self.stderr) > 0
4550

4651

4752
def is_executable_file(file_name):
@@ -76,14 +81,23 @@ def infer_case_num(sample_filename: str):
7681
def run_program(exec_file: str, input_file: str, timeout_sec: int) -> ExecResult:
7782
try:
7883
elapsed_sec = -time.time()
79-
out_data = subprocess.check_output(
80-
[exec_file, ""], stdin=open(input_file, 'r'), universal_newlines=True, timeout=timeout_sec)
84+
proc = subprocess.run(
85+
[exec_file, ""], stdin=open(input_file, 'r'), universal_newlines=True, timeout=timeout_sec,
86+
stdout=subprocess.PIPE,
87+
stderr=subprocess.PIPE,
88+
)
89+
90+
if proc.returncode == 0:
91+
code = ExecStatus.NORMAL
92+
else:
93+
code = ExecStatus.RE
94+
8195
elapsed_sec += time.time()
82-
return ExecResult(ExecStatus.NORMAL, out_data, elapsed_sec)
83-
except subprocess.TimeoutExpired:
84-
return ExecResult(ExecStatus.TLE)
85-
except subprocess.CalledProcessError:
86-
return ExecResult(ExecStatus.RE)
96+
return ExecResult(code, proc.stdout, proc.stderr, elapsed_sec=elapsed_sec)
97+
except subprocess.TimeoutExpired as e:
98+
return ExecResult(ExecStatus.TLE, e.stdout, e.stderr)
99+
except subprocess.CalledProcessError as e:
100+
return ExecResult(ExecStatus.RE, e.stdout, e.stderr)
87101

88102

89103
def build_details_str(exec_res: ExecResult, input_file: str, output_file: str) -> str:
@@ -93,21 +107,23 @@ def append(text: str, end='\n'):
93107
nonlocal res
94108
res += text + end
95109

96-
append("[Input]")
110+
append(with_color("[Input]", Fore.LIGHTMAGENTA_EX))
97111
with open(input_file, "r") as f:
98112
append(f.read(), end='')
99113

100-
append("[Expected]")
114+
append(with_color("[Expected]", Fore.LIGHTMAGENTA_EX))
101115
with open(output_file, "r") as f:
102116
append(f.read(), end='')
103117

104-
if exec_res.status == ExecStatus.NORMAL:
105-
append("[Received]")
106-
if exec_res.status == ExecStatus.NORMAL:
107-
append(exec_res.output, end='')
108-
else:
109-
append("[Log]")
110-
append(exec_res.status.name)
118+
append(with_color("[Received]", Fore.LIGHTMAGENTA_EX))
119+
append(exec_res.output, end='')
120+
if exec_res.status != ExecStatus.NORMAL:
121+
append(with_color("Aborted ({})\n".format(
122+
exec_res.status.name), Fore.LIGHTYELLOW_EX))
123+
124+
if exec_res.has_stderr():
125+
append(with_color("[Error]", Fore.LIGHTYELLOW_EX))
126+
append(exec_res.stderr, end='')
111127
return res
112128

113129

@@ -123,24 +139,31 @@ def run_for_samples(exec_file: str, sample_pair_list: List[Tuple[str, str]], tim
123139
answer_text = f.read()
124140

125141
is_correct = exec_res.is_correct_output(answer_text)
126-
if is_correct:
142+
passed = is_correct and not exec_res.has_stderr()
143+
144+
if passed:
127145
message = "{} {elapsed} ms".format(
128146
with_color("PASSED", Fore.LIGHTGREEN_EX),
129147
elapsed=exec_res.elapsed_ms)
130148
success_count += 1
131149
else:
132-
if exec_res.status == ExecStatus.NORMAL:
133-
message = with_color("WA", Fore.LIGHTRED_EX)
150+
if is_correct:
151+
message = with_color(
152+
"CORRECT but with stderr (Please remove stderr!)", Fore.LIGHTYELLOW_EX)
134153
else:
135-
message = with_color(exec_res.status.name, Fore.LIGHTYELLOW_EX)
154+
if exec_res.status == ExecStatus.NORMAL:
155+
message = with_color("WA", Fore.LIGHTRED_EX)
156+
else:
157+
message = with_color(
158+
exec_res.status.name, Fore.LIGHTYELLOW_EX)
136159

137160
print("# {case_name} ... {message}".format(
138161
case_name=os.path.basename(in_sample_file),
139162
message=message,
140163
))
141164

142165
# Output details for incorrect results.
143-
if not is_correct:
166+
if not passed:
144167
print('{}\n'.format(build_details_str(
145168
exec_res, in_sample_file, out_sample_file)))
146169
if knock_out:

0 commit comments

Comments
 (0)