def test_run_exit_code_2(self): """Test that main_entry_point returns the same exit code, as the called command""" main_entry_point(["create"]) # need venv to run with self.assertRaises(ChildExit) as ce: main_entry_point(["run", "python3", "-c", "exit(2)"]) self.assertEqual(ce.exception.code, 2)
def test_run_python_code(self): """Testing vien run python3 -c '...'""" main_entry_point(["create"]) file_to_be_created = self.projectDir / "hello.txt" self.assertFalse(file_to_be_created.exists()) # we'll ask the python residing inside the virtualenv to create a text # file and write the path to interpreter in it python_program = f""" import os, sys from pathlib import Path Path({repr(str(file_to_be_created))}).write_text(sys.executable) """ lines = [line.strip() for line in python_program.splitlines()] python_program = "; ".join(line for line in lines if line) with self.assertRaises(SystemExit) as ce: main_entry_point(["run", "python3", "-c", python_program]) self.assertIsSuccessExit(ce.exception) # check the file created (it means, the command was executed) self.assertTrue(file_to_be_created.exists()) # the file should contain the path or the python interpreter that # executed it in virtualenv interpreter_path = Path(file_to_be_created.read_text()) self.assertTrue("svetdir" in interpreter_path.parts) self.assertTrue("project_venv" in interpreter_path.parts)
def test_call_needs_venv(self): """File exists, but venv does not exist""" runme_py = self.projectDir / "runme.py" runme_py.touch() with self.assertRaises(VenvDoesNotExistExit) as ce: main_entry_point(["call", str(runme_py)]) self.assertIsErrorExit(ce.exception)
def test_shell_ok(self): main_entry_point(["create"]) with TemporaryDirectory() as td: dir_to_create = Path(td) / "to_be_or_not_to_be" self.assertFalse(dir_to_create.exists()) dir_to_create_quoted = repr(str(dir_to_create)) bash_input = f'mkdir {dir_to_create_quoted}\n' # I did not find an easy way to run an interactive sub-shell during # testing and then to kill it. Solutions that were based on # signal.SIGALRM or the subprocess.run(timeout), were harming the # MacOS terminal that started the test # # So we provide input and delay arguments to the sub-shell. It # makes the sub-shell peacefully close itself. # # It is not a clean test for "shell" though. The "shell" meant to # be run without parameters. start = timer() with TimeLimited(10): # safety net with self.assertRaises(ChildExit) as ce: main_entry_point( ["shell", "--input", bash_input, "--delay", "1"]) self.assertFalse(ce.exception.code, 0) end = timer() self.assertGreater(end - start, 0.5) self.assertLess(end - start, 3) self.assertTrue(dir_to_create.exists())
def test_shell_p(self): """Checking the -p changes both venv directory and the first item in PYTHONPATH""" main_entry_point(["create"]) with TemporaryDirectory() as temp_cwd: # we will run it NOT from the project dir as CWD os.chdir(temp_cwd) # creating .py file to run code_py = Path(temp_cwd) / "code.py" output_file = self.write_reporting_program(code_py) # running the code that will create a json file self.assertProjectDirIsNotCwd() with self.assertRaises(ChildExit) as ce: main_entry_point([ "-p", str(self.projectDir.absolute()), "shell", "--input", f'python3 "{code_py}"' ]) self.assertEqual(ce.exception.code, 0) # loading json and checking the values d = json.loads(output_file.read_text()) self.assertIn(str(self.projectDir.absolute()), d["sys.path"]) self.assertInVenv(Path(d["sys.executable"]))
def test_run(self): main_entry_point(["create"]) with self.assertRaises(ChildExit): # just check the argparser handles --version properly # (was failing with nargs='*', ok with nargs=argparse.REMAINDER) main_entry_point(["run", "python3", "--version"])
def test_create_with_argument(self): self.assertFalse(self.expectedVenvDir.exists()) self.assertFalse(self.expectedVenvBin.exists()) main_entry_point(["create", "python3"]) self.assertTrue(self.expectedVenvDir.exists()) self.assertTrue(self.expectedVenvBin.exists())
def test_reinit_wo_argument(self): self.assertFalse(self.expectedVenvDir.exists()) self.assertFalse(self.expectedVenvBin.exists()) main_entry_point(["recreate"]) self.assertTrue(self.expectedVenvDir.exists()) self.assertTrue(self.expectedVenvBin.exists())
def test_recreate_fails_with_unresolvable_argument(self): # actually this is not a good test: we are not testing whether # argument is really used and not ignored self.assertVenvNotExists() with self.assertRaises(CannotFindExecutableExit) as ce: main_entry_point(["recreate", "labuda-ladeda-hehe"]) self.assertIsErrorExit(ce.exception) self.assertVenvNotExists()
def test_call_parameters(self): """Testing that call really passes parameters to child.""" main_entry_point(["create"]) self.write_reporting_program(self.projectDir / "file.py") self.assertFalse(self.report_exists) self._run_and_check(["call", "file.py", "hello", "program"]) self.assertTrue(self.report_exists) self.assertEqual(self.reported_argv[-2], "hello") self.assertEqual(self.reported_argv[-1], "program")
def test_call_project_dir_relative_imports(self): """ Tests that modules are importable from the project dir set by -p parameter""" main_entry_point(["create"]) pkg_dir = self.projectDir / "subpkg" pkg_dir.mkdir() (pkg_dir / "__init__.py").touch() (pkg_dir / "constant.py").write_text("FIFTY_FIVE=55") run_py = (pkg_dir / "run.py") # thanks to modified PYTHONPATH, the following must work run_py.write_text("import subpkg.constant\n" "exit(subpkg.constant.FIFTY_FIVE)") run_py_str = str(run_py.absolute()) with TemporaryDirectory() as td: os.chdir(td) with self.assertRaises(ChildExit) as ce: main_entry_point(["call", "-p", "..", run_py_str]) self.assertEqual(ce.exception.code, 55)
def test_call_file_as_file(self): main_entry_point(["create"]) # creating pkg/sub/module.py file_py = self.project_pkg_sub / "module.py" self.write_reporting_program(file_py) self.assertFalse(self.report_exists) # running from random CWD with TempCwd(): self.assertProjectDirIsNotCwd() self._run_and_check([ "-p", str(self.projectDir.absolute()), "call", str(file_py.absolute()) ]) # no -m self.assertTrue(self.report_exists) self.assertInVenv(self.reported_executable) self.assertIn(str(self.projectDir.absolute()), self.reported_syspath)
def test_run_p(self): """Checking the -p changes both venv directory and the first item in PYTHONPATH""" main_entry_point(["create"]) with TemporaryDirectory() as temp_cwd: # we will run it NOT from the project dir as CWD os.chdir(temp_cwd) # creating .py file to run code_py = Path(temp_cwd) / "code.py" self.write_reporting_program(code_py) # running the code that will create a json file self.assertProjectDirIsNotCwd() self._run_and_check([ "-p", str(self.projectDir.absolute()), "run", "python3", str(code_py) ]) self.assertInVenv(self.reported_executable) self.assertIn(str(self.projectDir.absolute()), self.reported_syspath)
def test_call_project_dir_venv(self): """Tests that the -p parameter actually changes the project directory, so the correct virtual environment is found.""" main_entry_point(["create"]) pkg_dir = self.projectDir / "subpkg" pkg_dir.mkdir() (pkg_dir / "__init__.py").touch() run_py = (pkg_dir / "run.py") run_py.write_text("exit(5)") run_py_str = str(run_py.absolute()) with TemporaryDirectory() as td: os.chdir(td) # without -p we assume that the current dir is the project dir, # but the current is temp. So we must get an exception with self.assertRaises(VenvDoesNotExistExit): main_entry_point(["call", run_py_str]) # this call specifies project dir relative to run.py. # It runs the file successfully with self.assertRaises(ChildExit) as ce: main_entry_point(["call", "-p", "..", run_py_str]) self.assertEqual(ce.exception.code, 5) # this call specifies project dir relative to run.py. # It runs the file successfully with self.assertRaises(ChildExit) as ce: main_entry_point(["call", "--project-dir", "..", run_py_str]) self.assertEqual(ce.exception.code, 5) # this call specifies *incorrect* project dir relative to run.py. with self.assertRaises(VenvDoesNotExistExit): main_entry_point( ["call", "--project-dir", "../..", run_py_str])
def test_call_parameters(self): """Testing that call really passes parameters to child.""" main_entry_point(["create"]) (self.projectDir / "main.py").write_text(f"import sys; exit(len(sys.argv))") with self.assertRaises(ChildExit) as ce: main_entry_point(["call", "main.py"]) self.assertEqual(ce.exception.code, 1) # received len(argv) with self.assertRaises(ChildExit) as ce: main_entry_point(["call", "main.py", "aaa", "bbb", "ccc"]) self.assertEqual(ce.exception.code, 4) # received len(argv)
def test_recreate_with_argument(self): self.assertVenvNotExists() main_entry_point(["create", sys.executable]) self.assertTrue(self.expectedVenvDir.exists()) if self.expectedVenvBinWindows.exists(): os.remove(self.expectedVenvBinWindows) elif self.expectedVenvBinPosix.exists(): os.remove(self.expectedVenvBinPosix) else: raise AssertionError("executable not found") self.assertVenvBinNotExists() main_entry_point(["recreate", sys.executable]) self.assertVenvBinExists() main_entry_point(["recreate", sys.executable]) self.assertVenvBinExists()
def test_help(self): with self.assertRaises(SystemExit) as cp: main_entry_point(["-h"]) self.assertEqual(cp.exception.code, 0)
def test_shell_but_no_venv(self): # python3 -m unittest svet.main_test.TestsInsideTempProjectDir.test_shell with TimeLimited(10): # safety net with self.assertRaises(VenvDoesNotExistExit) as cm: main_entry_point(["shell"])
def test_no_args(self): with self.assertRaises(SystemExit) as cp: main_entry_point() self.assertEqual(cp.exception.code, 2)
def test_create_fails_if_twice(self): main_entry_point(["create"]) with self.assertRaises(VenvExistsExit) as ce: main_entry_point(["create"]) self.assertIsErrorExit(ce.exception)
def test_shell_exit_code_zero(self): main_entry_point(["create"]) with TimeLimited(10): # safety net with self.assertRaises(ChildExit) as ce: main_entry_point(["shell", "--input", "exit"]) self.assertFalse(ce.exception.code, 0)
def test_shell_fails_if_not_exist(self): self.assertVenvDoesNotExist() with self.assertRaises(VenvDoesNotExistExit) as cm: main_entry_point(["shell"]) self.assertIsErrorExit(cm.exception)
def test_create_then_delete(self): self.assertVenvDoesNotExist() main_entry_point(["create"]) self.assertVenvExists() main_entry_point(["delete"]) self.assertVenvDoesNotExist()
def test_run_needs_venv(self): with self.assertRaises(VenvDoesNotExistExit): main_entry_point(["run", "python", "--version"])
def _call_for_exit_code(self, exit_code: int): (self.projectDir / "main.py").write_text(f"exit({exit_code})") main_entry_point(["create"]) with self.assertRaises(SystemExit) as ce: main_entry_point(["call", "main.py"]) self.assertEqual(ce.exception.code, exit_code)
#!/usr/bin/env python3 from vien import main_entry_point if __name__ == "__main__": main_entry_point()
def test_path(self): os.chdir(Path(__file__).parent) main_entry_point(["path"])
def test_shell_missing_in_windows(self): with self.assertRaises(SystemExit) as cm: main_entry_point(["run", "shell"]) self.assertEqual(cm.exception.code, 2)
def test_call_nonexistent_file(self): main_entry_point(["create"]) with self.assertRaises(PyFileNotFoundExit) as ce: main_entry_point(["call", "nonexistent.py"]) self.assertIsErrorExit(ce.exception)
def test_shell_but_no_venv(self): with TimeLimited(10): # safety net with self.assertRaises(VenvDoesNotExistExit) as cm: main_entry_point(["shell"])