diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-09-27 18:41:02 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-09-27 18:41:02 +0200 |
| commit | 6382d2b7c1910f29556b740513421b57da9c5a97 (patch) | |
| tree | 4e79e4b13226cd1b288486e2819368c767e55259 | |
| parent | 51857521f770caae7b36e3a36a30d5b6986e66d1 (diff) | |
| download | philosophers_test-6382d2b7c1910f29556b740513421b57da9c5a97.tar.gz philosophers_test-6382d2b7c1910f29556b740513421b57da9c5a97.tar.bz2 philosophers_test-6382d2b7c1910f29556b740513421b57da9c5a97.zip | |
Added custom Exception with more descriptive error message
| -rw-r--r-- | setup.cfg | 2 | ||||
| -rw-r--r-- | src/config.py | 8 | ||||
| -rwxr-xr-x | src/main.py | 2 | ||||
| -rw-r--r-- | src/test/__init__.py | 4 | ||||
| -rw-r--r-- | src/test/philo.py | 73 | ||||
| -rw-r--r-- | src/test/test.py | 41 |
6 files changed, 63 insertions, 67 deletions
diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..2852e44 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +ignore = E501,E221,W503,E241 diff --git a/src/config.py b/src/config.py index 3da1285..1235307 100644 --- a/src/config.py +++ b/src/config.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 11:05:38 by charles #+# #+# # -# Updated: 2020/09/27 11:51:41 by charles ### ########.fr # +# Updated: 2020/09/27 18:00:53 by charles ### ########.fr # # # # ############################################################################ # @@ -23,6 +23,12 @@ BUILD_BEFORE = True # `{path}` is replaced by the philosophers directory (e.g `../philo_one` `../philo_two`) BUILD_CMD = "make --no-print-directory -C {path}" +# Timeout for non infinite test +TIMEOUT = 2 + +# Timeout for infinite test +INFINITE_TIMEOUT = 1 + ################################################################################ # Do not edit ################################################################################ diff --git a/src/main.py b/src/main.py index dbe33ea..473fc9a 100755 --- a/src/main.py +++ b/src/main.py @@ -22,7 +22,6 @@ # [x] bad output format # [x] should be dead -import os import sys import subprocess import argparse @@ -55,5 +54,6 @@ def main(): Test.run_all(config.PHILO_EXEC_PATHS[0]) # print("yo") + if __name__ == "__main__": main() diff --git a/src/test/__init__.py b/src/test/__init__.py index a6d7632..4cc06f8 100644 --- a/src/test/__init__.py +++ b/src/test/__init__.py @@ -6,8 +6,8 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 13:00:31 by charles #+# #+# # -# Updated: 2020/09/27 13:01:05 by charles ### ########.fr # +# Updated: 2020/09/27 17:56:09 by charles ### ########.fr # # # # ############################################################################ # -from test.test import Test +from test.test import Test # noqa: F401 diff --git a/src/test/philo.py b/src/test/philo.py index 743f0cb..cb8d369 100644 --- a/src/test/philo.py +++ b/src/test/philo.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 17:49:41 by charles #+# #+# # -# Updated: 2020/09/27 17:53:10 by charles ### ########.fr # +# Updated: 2020/09/27 18:35:25 by charles ### ########.fr # # # # ############################################################################ # @@ -16,6 +16,14 @@ import enum import itertools +class FormatError(Exception): + pass + + +class LogError(Exception): + pass + + class Event(enum.Enum): EATING = 1 SLEEPING = 2 @@ -23,17 +31,27 @@ class Event(enum.Enum): DIED = 4 NONE = 5 + @staticmethod + def to_verb(event): + return { + Event.EATING: "eat", + Event.SLEEPING: "sleep", + Event.THINKING: "think", + Event.DIED: "die", + Event.NONE: "none", + }[event] + class Log: - def __init__(self, log, philo_num): + def __init__(self, line, philo_num): match = re.match( - "^(?P<timestamp>\d+) " - "(?P<id>\d+) " - "(?P<event>is thinking|is eating|is sleeping|died)$", - log + r"^(?P<timestamp>\d+) " + r"(?P<id>\d+) " + r"(?P<event>is thinking|is eating|is sleeping|died)$", + line ) if match is None: - raise ValueError("Bad line format |{}|".format(log)) + raise FormatError("couldn't parse line") curr = int(time.time() * 1000) self.timestamp = Log._parse_ranged_int(match.group("timestamp"), curr - 100, curr + 100) @@ -51,13 +69,13 @@ class Log: try: value = int(s) if not (lo <= value <= hi): - raise ValueError("Invalid value range {}".format(s)) + raise FormatError("`{}` should be between {} - {}".format(s, lo, hi)) except ValueError: - raise ValueError("Invalid value {}".format(s)) + raise FormatError("`{}` sould be an integer".format(s)) return value def __repr__(self): - return "{} {} {}".format(self.timestamp, self.id, self.event) + return "Log({}ms #{} {})".format(self.timestamp, self.id, self.event) class Philo: @@ -75,30 +93,31 @@ class Philo: for e, g in grouped: if e is Event.EATING: if len(g) != self.meal_num: - raise RuntimeError("lala") + raise LogError("should eat {} times".format(self.meal_num)) else: if len(g) != 1: - raise RuntimeError("1lala") + raise LogError("should {} 1 time".format(Event.to_verb(e))) events = [e for e, _ in grouped] for e1, e2 in zip(events, events[1:]): if e2 is Event.DIED: break - if e1 is Event.THINKING and e2 is not Event.EATING: - raise RuntimeError("2lala") - elif e1 is Event.EATING and e2 is not Event.SLEEPING: - raise RuntimeError("2lala") - elif e1 is Event.SLEEPING and e2 is not Event.EATING: - raise RuntimeError("2lala") + second = { + Event.THINKING: Event.EATING, + Event.EATING: Event.SLEEPING, + Event.SLEEPING: Event.EATING + }[e1] + if second is not e2: + raise LogError("{} should switch to {}, actual {}".format(e1, second, e2)) last_eat_time = int(time.time() * 1000) - for l in reversed(self._logs): - if l.event is Event.EATING: - last_eat_time = l.timestamp + for log in reversed(self._logs): + if log.event is Event.EATING: + last_eat_time = log.timestamp break if int(time.time() * 1000) - last_eat_time > self._timeout_eat + 20: - raise RuntimeError("should be dead") + raise LogError("should be dead") @property def last_event(self): @@ -116,7 +135,7 @@ class Table: def add_log(self, log): if self.dead: - raise RuntimeError("died") + raise LogError("should not output after one died") if log.event is Event.DIED: self.dead = True self._logs.append(log) @@ -128,9 +147,9 @@ class Table: return fork_used = 2 * len([p for p in self._philos if p.last_event == Event.EATING]) if fork_used > self._philo_num: - raise RuntimeError("too much fork") - for p in self._philos: - p.check() + raise LogError("using nonexistant forks") for l1, l2 in zip(self._logs, self._logs[1:]): if l1.timestamp > l2.timestamp: - raise RuntimeError("timestamp not ordered") + raise LogError("timestamp not in ordered") + for p in self._philos: + p.check() diff --git a/src/test/test.py b/src/test/test.py index 1aa9f0a..83e2718 100644 --- a/src/test/test.py +++ b/src/test/test.py @@ -6,32 +6,25 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 11:36:32 by charles #+# #+# # -# Updated: 2020/09/27 17:51:44 by charles ### ########.fr # +# Updated: 2020/09/27 18:40:33 by charles ### ########.fr # # # # ############################################################################ # -import re -import time import subprocess -# import threading +import config import test.philo as philo - -class Test: #(threading.Thread): +class Test: _tests = [] _exec_path = None - # _stdout_lock = threading.Lock() @classmethod def run_all(cls, exec_path: str): cls._exec_path = exec_path for t in cls._tests: t.run() - # threads = [test.start() for test in cls._tests] - # for thread in threads: - # thread.join() def __init__( self, @@ -48,7 +41,6 @@ class Test: #(threading.Thread): self._timeout_sleep = timeout_sleep self._meal_num = meal_num Test._tests.append(self) - # threading.Thread.__init__(self) def run(self): argv = [ @@ -60,40 +52,17 @@ class Test: #(threading.Thread): ] if self._meal_num is not None: argv.append(str(self._meal_num)) - # try: process = subprocess.Popen( argv, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) - # output = process_result.stdout.decode() - # print(output) - # timeout=1, - # except subprocess.TimeoutExpered as err: - # return Result(err) - # except subprocess.CalledProcessError as err: - # return Result(err) - self._check_output(process.stdout) - process.wait() + process.wait(timeout=config.TIMEOUT) def _check_output(self, stream): table = philo.Table(self._philo_num, self._timeout_eat) - for line in stream: line = line.decode()[:-1] - # print(">", line) - l = philo.Log(line, self._philo_num) - print(l) - table.add_log(l) + table.add_log(philo.Log(line, self._philo_num)) table.check() - - # print(timestamp, id_, event) - - - # philo_states.append(Philo) - - # def _print(self, *args): - # Test._stdout_lock.aquire() - # print(*args) - # Test._stdout_lock.release() |
