def test_staged_file_content(self): try: # initialize repo repo = BasicRepo(bare=False) # initialize git handle git_handle = GitHandle(repo.repo_path) # write file test_staged_file = path.join(repo.repo_path, "test_staged_file") with open(test_staged_file, "w") as foo: foo.write("test stage") # stage repo.repo.git.add([test_staged_file]) # edit the file again with open(test_staged_file, "a") as foo: foo.write("\nmore") # get staged file path pth = git_handle.get_staged_files_paths()[0] self.assertEqual(git_handle.get_staged_file_content(pth), b"test stage") except Exception: raise finally: repo.delete()
def test_check_path_is_allowed(self): try: # initialize repo repo = BasicRepo() # initialize git handle git_handle = GitHandle(repo.repo_path) # test some bad paths and file names... with self.assertRaises(ForbiddenCharacterError): git_handle._check_path_is_allowed("a bad/path") with self.assertRaises(ForbiddenCharacterError): git_handle._check_path_is_allowed("/a\nice/path/") with self.assertRaises(ForbiddenCharacterError): git_handle._check_path_is_allowed("this_is_/'the'/_path") with self.assertRaises(ForbiddenCharacterError): git_handle._check_path_is_allowed(path.join("\\", "a_path")) with self.assertRaises(ForbiddenCharacterError): git_handle._check_path_is_allowed( path.join("/some/path", "this is_bad.ext")) except Exception: raise finally: repo.delete()
def test_get_staged_file_paths(self): try: # initialize repo repo = BasicRepo(bare=False) # initialize git handle git_handle = GitHandle(repo.repo_path) # test staging test_staged_file = path.join(repo.repo_path, "test_staged_file") with open(test_staged_file, "w") as foo: foo.write("test stage") test_staged_file1 = path.join(repo.repo_path, "test_staged_file1") with open(test_staged_file1, "w") as foo: foo.write("test stage1") # stage repo.repo.git.add([test_staged_file, test_staged_file1]) self.assertEqual( set(git_handle.get_staged_files_paths()), set([ path.relpath(test_staged_file, repo.repo_path), path.relpath(test_staged_file1, repo.repo_path) ])) except Exception: raise finally: repo.delete()
def test_lint_multiple(self): # test ability to execute `run` method with multiple linters try: # initialize repo repo = BasicRepo(bare=False) # write a bad markdown file test_staged_file = path.join(repo.repo_path, "foo.md") w = Writer(test_staged_file) w.write("# Bad markdown") w.write("There should be an empty line before this!") w.write("Also, this is way too long" * 300) # write a bad R file test_staged_file1 = path.join(repo.repo_path, "bar.R") w1 = Writer(test_staged_file1) w1.write("# Bad R") w1.write("f=function(x) print( 'Hello' )") w1.write("a=5") # stage it repo.repo.git.add([test_staged_file, test_staged_file1]) # initialize a `GitHandle` git_handle = GitHandle(path=repo.repo_path) # initialize a `Lint` object ell = Lint(git_handle=git_handle, linters=[MarkdownLinter(), RLinter()]) # execute the main method of the `Lint` object f = StringIO() with redirect_stdout(f): n_files_with_problems = ell.run() self.assertEqual(n_files_with_problems, 2) except Exception: raise finally: # clean up w.delete() w1.delete() repo.delete()
def test_get_head_hash_bare(self): try: # initialize repo repo = BasicRepo() # initialize git handle git_handle = GitHandle(repo.repo_path) # test self.assertEqual(git_handle.get_head_hash(), "4b825dc642cb6eb9a060e54bf8d69288fbee4904") except Exception: raise finally: repo.delete()
def test_get_git_root(self): try: # initialize repo repo = BasicRepo() # initialize git handle git_handle = GitHandle(repo.repo_path) # test self.assertEqual(path.abspath(git_handle.root), path.abspath(repo.repo_path)) except Exception: raise finally: repo.delete()
def test_get_head_hash_not_bare(self): try: # initialize repo repo = BasicRepo(bare=False) # initialize git handle git_handle = GitHandle(repo.repo_path) # test commit test_commit_file = path.join(repo.repo_path, "test_commit") with open(test_commit_file, "w") as foo: foo.write("test commit") repo.repo.git.add(test_commit_file) repo.repo.git.commit("-m", "test commit") self.assertEqual(git_handle.get_head_hash(), repo.repo.head.commit.hexsha) except Exception: raise finally: repo.delete()
def test_default_install(self): try: # create a temporary directory to host the target repo tmp = TemporaryDirectory() # create a repo in the temporary directory repo = BasicRepo(path=tmp.name, bare=False) # run the installer pipe = Popen(["python", "install.py", repo.repo_path], stdout=DEVNULL) _ = pipe.communicate() # noqa # test exit code of installer self.assertEqual(pipe.returncode, 0) # test that the `pre_commit` subdirectory was created in # .git/hooks/ self.assertTrue( path.isdir( path.join(repo.repo_path, ".git", "hooks", "pre_commit"))) # test that the `pre-commit` script was created in .git/hooks/ self.assertTrue( path.exists( path.join(repo.repo_path, ".git", "hooks", "pre-commit"))) # test that all options are `True` in `linters.conf` parser = ConfigParser() parser.read( path.join(repo.repo_path, ".git", "hooks", "pre_commit", "linters.conf")) self.assertTrue( all( map(lambda lang: parser["linters"][lang] == "True", parser["linters"]))) except Exception: raise finally: tmp.cleanup()
def test_uninstall(self): try: # install first # create a temporary directory to host the target repo tmp = TemporaryDirectory() # create a bare repo in the temporary directory repo = BasicRepo(path=tmp.name, bare=False) # run the installer pipe_inst = Popen(["python", "install.py", repo.repo_path], stdout=DEVNULL) _ = pipe_inst.communicate() # noqa # uninstall pipe_uninst = Popen([ "python", path.join(repo.repo_path, ".git", "hooks", "pre_commit", "uninstall.py") ], stdout=DEVNULL) _ = pipe_uninst.communicate() # noqa # test exit code of uninstaller self.assertEqual(pipe_uninst.returncode, 0) # test that there is no `pre_commit` subdirectory in .git/hooks/ self.assertFalse( path.isdir( path.join(repo.repo_path, ".git", "hooks", "pre_commit"))) # test that there is no `pre-commit` script in .git/hooks/ self.assertFalse( path.exists( path.join(repo.repo_path, ".git", "hooks", "pre-commit"))) except Exception: raise finally: tmp.cleanup()
def test_selective_install(self): # this assumes that the installation is succesful as we already # check for that in `test_default_install` try: # create a temporary directory to host the target repo tmp = TemporaryDirectory() # create a repo in the temporary directory repo = BasicRepo(path=tmp.name, bare=False) # run the installer with selective installation of linters pipe = Popen(["python", "install.py", "-mp", repo.repo_path], stdout=DEVNULL) _ = pipe.communicate() # noqa # test that only the "markdown" and "python" options are `True` in # `linters.conf` parser = ConfigParser() parser.read( path.join(repo.repo_path, ".git", "hooks", "pre_commit", "linters.conf")) md = parser["linters"]["markdown"] py = parser["linters"]["python"] # markdown and python on self.assertTrue(md) self.assertTrue(py) # all others off others = set(parser["linters"]) - {"markdown", "python"} self.assertFalse( any([parser["linters"][lang] == "True" for lang in others])) except Exception: raise finally: tmp.cleanup()
def test_run(self): # test ability to execute `run` method with multiple linters when # only a subset of the files are staged; # also check that linting works for staged files that live in # subdirectories try: # initialize repo repo = BasicRepo(bare=False) # write a bad markdown file test_staged_file = path.join(repo.repo_path, "foo.md") w = Writer(test_staged_file) w.write("# Bad markdown") w.write("There should be an empty line before this!") w.write("Also, this is way too long" * 300) # write a bad R file test_staged_file1 = path.join(repo.repo_path, "bar.R") w1 = Writer(test_staged_file1) w1.write("# Bad R") w1.write("f=function(x) print( 'Hello' )") w1.write("a=5") # write a bad Python file test_staged_file2 = path.join(repo.repo_path, "foof.py") w2 = Writer(test_staged_file2) w2.write("# Bad Python") w2.write(" a=2") w2.write("from os import path") w2.write("a==2") # write another bad Python in a subdirectory subdir = path.join(repo.repo_path, "subdir") mkdir(subdir) test_staged_file3 = path.join(subdir, "fooffer.py") w3 = Writer(test_staged_file3) w3.write("# Bad Pyrhon") w3.write("# Wrong indentation") w3.write("class Foo(object):") w3.write(" pass") # stage these files repo.repo.git.add([ test_staged_file, test_staged_file1, test_staged_file2, test_staged_file3 ]) # write another file which is problematic but not staged! test_non_staged_file = path.join(repo.repo_path, "lmao.py") w3 = Writer(test_non_staged_file) w3.write("# An unnecessary import") w3.write("from os import getcwd") w3.write("# A test on an undefined variable") w3.write("# And missing blank line at the end") w3.write("a==3", newline=False) # initialize a `GitHandle` git_handle = GitHandle(path=repo.repo_path) # initialize a `Lint` object ell = Lint(git_handle=git_handle, linters=[MarkdownLinter(), PythonLinter(), RLinter()]) # execute the main method of the `Lint` object f = StringIO() with redirect_stdout(f): n_files_with_problems = ell.run() self.assertEqual(n_files_with_problems, 4) except Exception: raise finally: # clean up w.delete() w1.delete() w2.delete() w3.delete() repo.delete()
def test_run_with_linters_config(self): # test ability to execute `run` method with multiple linters, # honoring the linters config files try: # initialize repo repo = BasicRepo(bare=False) # write a bad markdown file test_staged_file = path.join(repo.repo_path, "foo.md") w = Writer(test_staged_file) w.write("# Bad markdown") w.write("There should be an empty line before this!") # write the .markdownlint.json config file to ignore # "MD022/blanks-around-headers" md_config_file_path = path.join(repo.repo_path, ".markdownlint.json") w_md_conf = Writer(md_config_file_path) w_md_conf.write("{") w_md_conf.write(' "MD022": false') w_md_conf.write("}") # write a bad R file test_staged_file1 = path.join(repo.repo_path, "bar.R") w1 = Writer(test_staged_file1) w1.write("# Bad R") w1.write("f <- function(x) print('Hello')") # write the .lintr config file to ignore the "single_quotes_linter" r_config_file_path = path.join(repo.repo_path, ".lintr") w_r_conf = Writer(r_config_file_path) w_r_conf.write("linters: with_defaults(single_quotes_linter=NULL)") # write a bad Python file test_staged_file2 = path.join(repo.repo_path, "foof.py") w2 = Writer(test_staged_file2) w2.write("# Bad Python") w2.write("a=2") # write the `.flake8` config file instructing to # except "E225" py_config_file_path = path.join(repo.repo_path, ".flake8") w_py_conf = Writer(py_config_file_path) w_py_conf.write("[flake8]") w_py_conf.write("ignore = E225") # stage the files repo.repo.git.add( [test_staged_file, test_staged_file1, test_staged_file2]) # initialize a `GitHandle` git_handle = GitHandle(path=repo.repo_path) # initialize a `Lint` object ell = Lint(git_handle=git_handle, linters=[ MarkdownLinter(config_path=w_md_conf.path), PythonLinter(config_path=w_py_conf.path), RLinter(config_path=w_r_conf.path) ]) # execute the main method of the `Lint` object f = StringIO() with redirect_stdout(f): n_files_with_problems = ell.run() # all linting issues should be ignored self.assertEqual(n_files_with_problems, 0) except Exception: raise finally: # clean up w.delete() w_md_conf.delete() w1.delete() w_r_conf.delete() w2.delete() w_py_conf.delete() repo.delete()