aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Cabergs <me@cacharle.xyz>2020-09-11 12:33:34 +0200
committerCharles Cabergs <me@cacharle.xyz>2020-09-11 12:33:34 +0200
commit46ba2708f83bf46186c33bf84975d39e87f467c1 (patch)
tree8275c80bba98d63e81e3af9a1df8be62e0419003
parentc0b1a90cf9c52a0c9b1623ac695516031d5ccdba (diff)
downloadminishell_test-46ba2708f83bf46186c33bf84975d39e87f467c1.tar.gz
minishell_test-46ba2708f83bf46186c33bf84975d39e87f467c1.tar.bz2
minishell_test-46ba2708f83bf46186c33bf84975d39e87f467c1.zip
Refactoring files, splited test.py and suite.py in packages
-rw-r--r--README.md6
-rw-r--r--random_status.py7
l---------[-rwxr-xr-x]run68
-rw-r--r--src/args.py (renamed from args.py)0
-rw-r--r--src/config.py (renamed from config.py)16
-rwxr-xr-xsrc/main.py67
-rw-r--r--src/suite/__init__.py2
-rw-r--r--src/suite/decorator.py27
-rw-r--r--src/suite/suite.py (renamed from suite.py)17
-rw-r--r--src/suites/__init__.py (renamed from suites/__init__.py)0
-rw-r--r--src/suites/builtin.py (renamed from suites/builtin.py)0
-rw-r--r--src/suites/cmd.py (renamed from suites/cmd.py)0
-rw-r--r--src/suites/operation.py (renamed from suites/operation.py)0
-rw-r--r--src/suites/parenthesis.py (renamed from suites/parenthesis.py)0
-rw-r--r--src/suites/path.py (renamed from suites/path.py)0
-rw-r--r--src/suites/preprocess.py (renamed from suites/preprocess.py)0
-rw-r--r--src/suites/status.py (renamed from suites/status.py)0
-rw-r--r--src/test/__init__.py13
-rw-r--r--src/test/captured.py39
-rw-r--r--src/test/result.py (renamed from test.py)133
-rw-r--r--src/test/test.py113
21 files changed, 284 insertions, 224 deletions
diff --git a/README.md b/README.md
index bacd967..33f6984 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Test for the minishell project of school 42.
## Usage
-The default path to your project is `..` but you can change it the the [configuration](config.py).
+The default path to your project is `..` but you can change it the the [configuration](src/config.py).
* `> ./run --help`
* `> ./run`
@@ -31,11 +31,11 @@ This allows you to set the prompt to whatever you want.
## Python Version
-This test works with python >= 3.4. The timeout detection only works with python >= 3.8.
+This test works with python >= 3.5.
## Configuration
-The default configuration can be changed in [config.py](config.py)
+The default configuration can be changed in [config.py](src/config.py)
## Add new tests
diff --git a/random_status.py b/random_status.py
deleted file mode 100644
index 171467f..0000000
--- a/random_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import sys
-import random
-
-if __name__ == "__main__":
- status = random.randrange(-2_000_000, 2_000_000)
- print(status)
- sys.exit(status)
diff --git a/run b/run
index a71a485..a8c92b0 100755..120000
--- a/run
+++ b/run
@@ -1,67 +1 @@
-#!/usr/bin/python3
-
-# ############################################################################ #
-# #
-# ::: :::::::: #
-# main.py :+: :+: :+: #
-# +:+ +:+ +:+ #
-# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
-# +#+#+#+#+#+ +#+ #
-# Created: 2020/07/15 15:11:52 by charles #+# #+# #
-# Updated: 2020/07/15 15:11:52 by charles ### ########.fr #
-# #
-# ############################################################################ #
-
-import os
-import sys
-import shutil
-import distutils.spawn
-import subprocess
-
-import config
-from args import parse_args
-from suite import Suite
-import suites.builtin
-import suites.cmd
-import suites.preprocess
-import suites.operation
-import suites.parenthesis
-import suites.status
-import suites.path
-
-def main():
- args = parse_args()
- if args.list:
- print("The available suites are:")
- print('\n'.join([" - " + s.name for s in Suite.available]))
- sys.exit(0)
-
- if config.MINISHELL_BUILD or args.build:
- try:
- subprocess.run(["make", "-C", config.MINISHELL_DIR], check=True)
- except subprocess.CalledProcessError:
- sys.exit(1)
- if args.build:
- sys.exit(0)
- if os.path.exists(config.EXECUTABLES_PATH):
- shutil.rmtree(config.EXECUTABLES_PATH)
- os.mkdir(config.EXECUTABLES_PATH)
- for cmd in config.AVAILABLE_COMMANDS:
- shutil.copy(distutils.spawn.find_executable(cmd), # FIXME search whole PATH
- os.path.join(config.EXECUTABLES_PATH, cmd))
-
-
- config.VERBOSE_LEVEL = args.verbose
- Suite.setup(args.suites)
- try:
- Suite.run_all()
- except KeyboardInterrupt:
- shutil.rmtree(config.SANDBOX_PATH)
-
- Suite.summarize()
- Suite.save_log()
- print("See", config.LOG_PATH, "for more information")
-
-
-if __name__ == "__main__":
- main()
+src/main.py \ No newline at end of file
diff --git a/args.py b/src/args.py
index 2d0d57a..2d0d57a 100644
--- a/args.py
+++ b/src/args.py
diff --git a/config.py b/src/config.py
index e05c36b..ca697f5 100644
--- a/config.py
+++ b/src/config.py
@@ -6,13 +6,20 @@
# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2020/07/15 18:24:19 by charles #+# #+# #
-# Updated: 2020/09/10 13:54:27 by charles ### ########.fr #
+# Updated: 2020/09/11 12:21:14 by charles ### ########.fr #
# #
# ############################################################################ #
-# Minishell configuration file
+
+################################################################################
+# Minishell configuration file #
+################################################################################
+
import os
+# run the bonus tests
+BONUS = False
+
# minishell dir path
MINISHELL_DIR = ".."
@@ -42,6 +49,9 @@ AVAILABLE_COMMANDS = ["rmdir", "env", "cat", "touch", "ls", "grep", "sh"]
# $PATH environment variable passed to the shell
PATH_VARIABLE = os.path.abspath(EXECUTABLES_PATH)
+# default test timeout
+TIMEOUT = 1
+
LOREM = """
Mollitia asperiores assumenda excepturi et ipsa. Nihil corporis facere aut a rem consequatur.
Quas molestiae corporis et quibusdam maiores. Molestiae sed unde aut at sed.
@@ -59,8 +69,6 @@ Perspiciatis ut maxime et libero quo voluptas consequatur illum. Pariatur porro
"""
LOREM = ' '.join(LOREM.split('\n'))
-TIMEOUT = 1
-
###############################################################################
# do not edit
###############################################################################
diff --git a/src/main.py b/src/main.py
new file mode 100755
index 0000000..a71a485
--- /dev/null
+++ b/src/main.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python3
+
+# ############################################################################ #
+# #
+# ::: :::::::: #
+# main.py :+: :+: :+: #
+# +:+ +:+ +:+ #
+# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
+# +#+#+#+#+#+ +#+ #
+# Created: 2020/07/15 15:11:52 by charles #+# #+# #
+# Updated: 2020/07/15 15:11:52 by charles ### ########.fr #
+# #
+# ############################################################################ #
+
+import os
+import sys
+import shutil
+import distutils.spawn
+import subprocess
+
+import config
+from args import parse_args
+from suite import Suite
+import suites.builtin
+import suites.cmd
+import suites.preprocess
+import suites.operation
+import suites.parenthesis
+import suites.status
+import suites.path
+
+def main():
+ args = parse_args()
+ if args.list:
+ print("The available suites are:")
+ print('\n'.join([" - " + s.name for s in Suite.available]))
+ sys.exit(0)
+
+ if config.MINISHELL_BUILD or args.build:
+ try:
+ subprocess.run(["make", "-C", config.MINISHELL_DIR], check=True)
+ except subprocess.CalledProcessError:
+ sys.exit(1)
+ if args.build:
+ sys.exit(0)
+ if os.path.exists(config.EXECUTABLES_PATH):
+ shutil.rmtree(config.EXECUTABLES_PATH)
+ os.mkdir(config.EXECUTABLES_PATH)
+ for cmd in config.AVAILABLE_COMMANDS:
+ shutil.copy(distutils.spawn.find_executable(cmd), # FIXME search whole PATH
+ os.path.join(config.EXECUTABLES_PATH, cmd))
+
+
+ config.VERBOSE_LEVEL = args.verbose
+ Suite.setup(args.suites)
+ try:
+ Suite.run_all()
+ except KeyboardInterrupt:
+ shutil.rmtree(config.SANDBOX_PATH)
+
+ Suite.summarize()
+ Suite.save_log()
+ print("See", config.LOG_PATH, "for more information")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/suite/__init__.py b/src/suite/__init__.py
new file mode 100644
index 0000000..55beb35
--- /dev/null
+++ b/src/suite/__init__.py
@@ -0,0 +1,2 @@
+from suite.suite import Suite
+from suite.decorator import suite
diff --git a/src/suite/decorator.py b/src/suite/decorator.py
new file mode 100644
index 0000000..55c9de6
--- /dev/null
+++ b/src/suite/decorator.py
@@ -0,0 +1,27 @@
+# ############################################################################ #
+# #
+# ::: :::::::: #
+# decorator.py :+: :+: :+: #
+# +:+ +:+ +:+ #
+# By: charles <me@cacharle.xyz> +#+ +:+ +#+ #
+# +#+#+#+#+#+ +#+ #
+# Created: 2020/09/11 12:28:00 by charles #+# #+# #
+# Updated: 2020/09/11 12:28:14 by charles ### ########.fr #
+# #
+# ############################################################################ #
+
+from suite import Suite
+from test import Test
+
+def suite(origin):
+ """ decorator for a suite function (fmt: suite_[name]) """
+
+ name = origin.__name__[len("suite_"):]
+ s = Suite(name)
+ def test_generator():
+ def test(*args, **kwargs):
+ s.add(Test(*args, **kwargs))
+ origin(test)
+ s.add_generator(test_generator)
+ Suite.available.append(s)
+ return test_generator
diff --git a/suite.py b/src/suite/suite.py
index 6b04dc5..fee4aa9 100644
--- a/suite.py
+++ b/src/suite/suite.py
@@ -6,13 +6,14 @@
# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2020/07/15 18:24:29 by charles #+# #+# #
-# Updated: 2020/07/19 15:29:36 by charles ### ########.fr #
+# Updated: 2020/09/11 12:27:47 by charles ### ########.fr #
# #
# ############################################################################ #
import config
from test import Test
+
class Suite:
available = []
@@ -91,17 +92,3 @@ class Suite:
t.result.colored = False
t.result.set_colors()
log_file.write(t.result.full_diff() + '\n')
-
-
-def suite(origin):
- """ decorator for a suite function (fmt: suite_[name]) """
-
- name = origin.__name__[len("suite_"):]
- s = Suite(name)
- def test_generator():
- def test(*args, **kwargs):
- s.add(Test(*args, **kwargs))
- origin(test)
- s.add_generator(test_generator)
- Suite.available.append(s)
- return test_generator
diff --git a/suites/__init__.py b/src/suites/__init__.py
index 68bad1f..68bad1f 100644
--- a/suites/__init__.py
+++ b/src/suites/__init__.py
diff --git a/suites/builtin.py b/src/suites/builtin.py
index 30297e0..30297e0 100644
--- a/suites/builtin.py
+++ b/src/suites/builtin.py
diff --git a/suites/cmd.py b/src/suites/cmd.py
index 1302ae3..1302ae3 100644
--- a/suites/cmd.py
+++ b/src/suites/cmd.py
diff --git a/suites/operation.py b/src/suites/operation.py
index 3c89589..3c89589 100644
--- a/suites/operation.py
+++ b/src/suites/operation.py
diff --git a/suites/parenthesis.py b/src/suites/parenthesis.py
index a06fdda..a06fdda 100644
--- a/suites/parenthesis.py
+++ b/src/suites/parenthesis.py
diff --git a/suites/path.py b/src/suites/path.py
index b30215f..b30215f 100644
--- a/suites/path.py
+++ b/src/suites/path.py
diff --git a/suites/preprocess.py b/src/suites/preprocess.py
index a34e18d..a34e18d 100644
--- a/suites/preprocess.py
+++ b/src/suites/preprocess.py
diff --git a/suites/status.py b/src/suites/status.py
index 62c076e..62c076e 100644
--- a/suites/status.py
+++ b/src/suites/status.py
diff --git a/src/test/__init__.py b/src/test/__init__.py
new file mode 100644
index 0000000..7601878
--- /dev/null
+++ b/src/test/__init__.py
@@ -0,0 +1,13 @@
+# ############################################################################ #
+# #
+# ::: :::::::: #
+# __init__.py :+: :+: :+: #
+# +:+ +:+ +:+ #
+# By: charles <me@cacharle.xyz> +#+ +:+ +#+ #
+# +#+#+#+#+#+ +#+ #
+# Created: 2020/09/11 12:18:14 by charles #+# #+# #
+# Updated: 2020/09/11 12:26:30 by charles ### ########.fr #
+# #
+# ############################################################################ #
+
+from test.test import Test
diff --git a/src/test/captured.py b/src/test/captured.py
new file mode 100644
index 0000000..e47590b
--- /dev/null
+++ b/src/test/captured.py
@@ -0,0 +1,39 @@
+# ############################################################################ #
+# #
+# ::: :::::::: #
+# captured.py :+: :+: :+: #
+# +:+ +:+ +:+ #
+# By: charles <me@cacharle.xyz> +#+ +:+ +#+ #
+# +#+#+#+#+#+ +#+ #
+# Created: 2020/09/11 12:16:25 by charles #+# #+# #
+# Updated: 2020/09/11 12:16:51 by charles ### ########.fr #
+# #
+# ############################################################################ #
+
+import config
+
+class Captured:
+ def __init__(self, output: str, status: int, files_content: [str], is_timeout: bool = False):
+ lines = output.split('\n')
+ for i, l in enumerate(lines):
+ if l.find(config.REFERENCE_ERROR_BEGIN) == 0:
+ lines[i] = l.replace(config.REFERENCE_ERROR_BEGIN, config.MINISHELL_ERROR_BEGIN, 1)
+ elif l.find(config.REFERENCE_PATH + ": ") == 0:
+ lines[i] = l.replace(config.REFERENCE_PATH + ": ", config.MINISHELL_ERROR_BEGIN, 1)
+
+ self.output = '\n'.join(lines)
+
+ self.status = status
+ self.files_content = files_content
+ self.is_timeout = is_timeout
+
+ def __eq__(self, other: 'Result') -> bool:
+ if self.is_timeout:
+ return self.is_timeout == other.is_timeout
+ return (self.output == other.output and
+ self.status == other.status and
+ all([x == y for x, y in zip(self.files_content, other.files_content)]))
+
+ @staticmethod
+ def timeout():
+ return Captured("", 0, [], is_timeout = True)
diff --git a/test.py b/src/test/result.py
index 05bd2df..5e1349d 100644
--- a/test.py
+++ b/src/test/result.py
@@ -1,49 +1,17 @@
# ############################################################################ #
# #
# ::: :::::::: #
-# test.py :+: :+: :+: #
+# result.py :+: :+: :+: #
# +:+ +:+ +:+ #
-# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
+# By: charles <me@cacharle.xyz> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
-# Created: 2020/06/16 21:48:50 by charles #+# #+# #
-# Updated: 2020/09/10 09:38:26 by charles ### ########.fr #
+# Created: 2020/09/11 12:17:34 by charles #+# #+# #
+# Updated: 2020/09/11 12:24:57 by charles ### ########.fr #
# #
# ############################################################################ #
-import os
-import sys
-import subprocess
-import shutil
-import glob
-
import config
-
-class Captured:
- def __init__(self, output: str, status: int, files_content: [str], is_timeout: bool = False):
- lines = output.split('\n')
- for i, l in enumerate(lines):
- if l.find(config.REFERENCE_ERROR_BEGIN) == 0:
- lines[i] = l.replace(config.REFERENCE_ERROR_BEGIN, config.MINISHELL_ERROR_BEGIN, 1)
- elif l.find(config.REFERENCE_PATH + ": ") == 0:
- lines[i] = l.replace(config.REFERENCE_PATH + ": ", config.MINISHELL_ERROR_BEGIN, 1)
-
- self.output = '\n'.join(lines)
-
- self.status = status
- self.files_content = files_content
- self.is_timeout = is_timeout
-
- def __eq__(self, other: 'Result') -> bool:
- if self.is_timeout:
- return self.is_timeout == other.is_timeout
- return (self.output == other.output and
- self.status == other.status and
- all([x == y for x, y in zip(self.files_content, other.files_content)]))
-
- @staticmethod
- def timeout():
- return Captured("", 0, [], is_timeout = True)
-
+from test.captured import Captured
class Result:
RED_CHARS = "\033[31m"
@@ -189,94 +157,3 @@ class Result:
.replace("\r", "\\r")
.replace("\f", "\\f")
)
-
-
-class Test:
- def __init__(self,
- cmd: str,
- setup: str = "",
- files: [str] = [],
- exports: {str: str} = {},
- timeout: float = config.TIMEOUT):
- self.cmd = cmd
- self.setup = setup
- self.files = files
- self.exports = exports
- self.result = None
- self.timeout = timeout
-
- def run(self):
- expected = self._run_sandboxed(config.REFERENCE_PATH, "-c")
- actual = self._run_sandboxed(config.MINISHELL_PATH, "-c")
- s = self.cmd
- if self.setup != "":
- s = "[SETUP {}] {}".format(self.setup, s)
- if len(self.exports) != 0:
- s = "[EXPORTS {}] {}".format(
- ' '.join(["{}='{:.20}'".format(k, v) for k, v in self.exports.items()]), s)
- self.result = Result(s, self.files, expected, actual)
- self.result.put()
-
- def _run_sandboxed(self, shell_path: str, shell_option: str) -> Captured:
- """ run the command in a sandbox environment
-
- capture the output (stdout and stderr)
- capture the content of the watched files after the command is run
- """
-
- try:
- os.mkdir(config.SANDBOX_PATH)
- except OSError:
- pass
- if self.setup != "":
- try:
- setup_status = subprocess.run(
- self.setup,
- shell=True,
- cwd=config.SANDBOX_PATH,
- stderr=subprocess.STDOUT,
- stdout=subprocess.PIPE,
- check=True
- )
- except subprocess.CalledProcessError as e:
- print("Error: `{}` setup command failed for `{}`\n\twith '{}'"
- .format(self.setup,
- self.cmd,
- "no stderr" if e.stdout is None else e.stdout.decode().strip()))
- sys.exit(1)
-
- try:
- process_status = subprocess.run(
- [shell_path, shell_option, self.cmd],
- stderr=subprocess.STDOUT,
- stdout=subprocess.PIPE,
- cwd=config.SANDBOX_PATH,
- env={
- 'PATH': config.PATH_VARIABLE,
- 'TERM': 'xterm-256color',
- **self.exports
- },
- timeout=self.timeout
- )
- except subprocess.TimeoutExpired:
- return Captured.timeout()
-
- try:
- output = process_status.stdout.decode()
- except UnicodeDecodeError:
- output = "UNICODE ERROR: {}".format(process_status.stdout)
-
- # capture watched files content
- files_content = []
- for file_name in self.files:
- try:
- with open(os.path.join(config.SANDBOX_PATH, file_name), "rb") as f:
- files_content.append(f.read().decode())
- except FileNotFoundError as e:
- files_content.append(None)
- try:
- shutil.rmtree(config.SANDBOX_PATH)
- except:
- subprocess.check_output(["chmod", "777", *glob.glob(config.SANDBOX_PATH + "/*")])
- subprocess.check_output(["rm", "-rf", config.SANDBOX_PATH])
- return Captured(output, process_status.returncode, files_content)
diff --git a/src/test/test.py b/src/test/test.py
new file mode 100644
index 0000000..9674240
--- /dev/null
+++ b/src/test/test.py
@@ -0,0 +1,113 @@
+# ############################################################################ #
+# #
+# ::: :::::::: #
+# test.py :+: :+: :+: #
+# +:+ +:+ +:+ #
+# By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ #
+# +#+#+#+#+#+ +#+ #
+# Created: 2020/06/16 21:48:50 by charles #+# #+# #
+# Updated: 2020/09/11 12:24:33 by charles ### ########.fr #
+# #
+# ############################################################################ #
+
+import os
+import sys
+import subprocess
+import shutil
+import glob
+
+import config
+from test.captured import Captured
+from test.result import Result
+
+
+class Test:
+ def __init__(self,
+ cmd: str,
+ setup: str = "",
+ files: [str] = [],
+ exports: {str: str} = {},
+ timeout: float = config.TIMEOUT):
+ self.cmd = cmd
+ self.setup = setup
+ self.files = files
+ self.exports = exports
+ self.result = None
+ self.timeout = timeout
+
+ def run(self):
+ expected = self._run_sandboxed(config.REFERENCE_PATH, "-c")
+ actual = self._run_sandboxed(config.MINISHELL_PATH, "-c")
+ s = self.cmd
+ if self.setup != "":
+ s = "[SETUP {}] {}".format(self.setup, s)
+ if len(self.exports) != 0:
+ s = "[EXPORTS {}] {}".format(
+ ' '.join(["{}='{:.20}'".format(k, v) for k, v in self.exports.items()]), s)
+ self.result = Result(s, self.files, expected, actual)
+ self.result.put()
+
+ def _run_sandboxed(self, shell_path: str, shell_option: str) -> Captured:
+ """ run the command in a sandbox environment
+
+ capture the output (stdout and stderr)
+ capture the content of the watched files after the command is run
+ """
+
+ try:
+ os.mkdir(config.SANDBOX_PATH)
+ except OSError:
+ pass
+ if self.setup != "":
+ try:
+ setup_status = subprocess.run(
+ self.setup,
+ shell=True,
+ cwd=config.SANDBOX_PATH,
+ stderr=subprocess.STDOUT,
+ stdout=subprocess.PIPE,
+ check=True
+ )
+ except subprocess.CalledProcessError as e:
+ print("Error: `{}` setup command failed for `{}`\n\twith '{}'"
+ .format(self.setup,
+ self.cmd,
+ "no stderr" if e.stdout is None else e.stdout.decode().strip()))
+ sys.exit(1)
+
+ process = subprocess.Popen(
+ [shell_path, shell_option, self.cmd],
+ stderr=subprocess.STDOUT,
+ stdout=subprocess.PIPE,
+ cwd=config.SANDBOX_PATH,
+ env={
+ 'PATH': config.PATH_VARIABLE,
+ 'TERM': 'xterm-256color',
+ **self.exports,
+ },
+ )
+ try:
+ process.wait(timeout=self.timeout)
+ except subprocess.TimeoutExpired:
+ return Captured.timeout()
+
+ try:
+ stdout, _ = process.communicate()
+ output = stdout.decode()
+ except UnicodeDecodeError:
+ output = "UNICODE ERROR: {}".format(process.stdout)
+
+ # capture watched files content
+ files_content = []
+ for file_name in self.files:
+ try:
+ with open(os.path.join(config.SANDBOX_PATH, file_name), "rb") as f:
+ files_content.append(f.read().decode())
+ except FileNotFoundError as e:
+ files_content.append(None)
+ try:
+ shutil.rmtree(config.SANDBOX_PATH)
+ except:
+ subprocess.run(["chmod", "777", *glob.glob(config.SANDBOX_PATH + "/*")], check=True)
+ subprocess.run(["rm", "-rf", config.SANDBOX_PATH], check=True)
+ return Captured(output, process.returncode, files_content)