def test_continue_after_skip_exists(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test entry addition continues after skipping over existing entry. Regression test against #83 Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ with tempfile.NamedTemporaryFile("w") as file: with open(EXAMPLE_DUPLICATE_ENTRY_BIB, "r", encoding="utf-8") as existing: file.writelines(existing.readlines()) file.writelines(["@article{dummy,\nauthor = {Dummy},\n}"]) file.flush() AddCommand().execute(["--skip-existing", "-b", file.name]) assert ( "cobib.commands.add", 30, "You tried to add a new entry 'einstein' which already exists!", ) in caplog.record_tuples assert ( "cobib.commands.add", 30, "Please use `cobib edit einstein` instead!", ) in caplog.record_tuples assert ( "cobib.database.database", 10, "Updating entry dummy", ) in caplog.record_tuples
def test_command(self, setup: Any, more_args: List[str], entry_kwargs: Dict[str, Any]) -> None: """Test the command itself. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. more_args: additional arguments to be passed to the command. entry_kwargs: the expected contents of the resulting `Entry`. """ git = setup.get("git", False) try: label = more_args[more_args.index("-l") + 1] except ValueError: label = "example_multi_file_entry" args = ["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB] + more_args AddCommand().execute(args) assert Database()[label] if entry_kwargs or label != "example_multi_file_entry": self._assert_entry(label, **entry_kwargs) else: # only when we don't use extra arguments the files will match self._assert(EXAMPLE_MULTI_FILE_ENTRY_YAML) if git: # assert the git commit message # Note: we do not assert the arguments, because they depend on the available parsers self.assert_git_commit_message("add", None)
def test_tui(self, setup: Any) -> None: """Test the TUI access of the command. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. """ def assertion(screen, logs, **kwargs): # type: ignore # check that the undone entry has actually been present in the buffer before assert ( "cobib.tui.buffer", 10, "Appending string to text buffer: example_multi_file_entry", ) in logs # but is no longer there, now assert "example_multi_file_entry" not in screen.display[1] expected_log = [ ("cobib.commands.undo", 10, "Undo command triggered from TUI."), ("cobib.commands.undo", 10, "Starting Undo command."), ("cobib.commands.undo", 10, "Obtaining git log."), ] # we only assert the first three messages because the following ones will contain always # changing commit SHAs assert [log for log in logs if log[0] == "cobib.commands.undo"][0:3] == expected_log AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) self.run_tui("u", assertion, {})
def test_add_skip_download(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test adding a new entry and skipping the automatic download. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ path = RelPath("/tmp/Cao2018.pdf") try: args = ["-a", "1812.09976", "--skip-download"] AddCommand().execute(args) if ( "cobib.parsers.arxiv", logging.ERROR, "An Exception occurred while trying to query the arXiv ID: 1812.09976.", ) in caplog.record_tuples: pytest.skip("The requests API encountered an error. Skipping test.") entry = Database()["Cao2018"] assert entry.label == "Cao2018" assert entry.data["archivePrefix"] == "arXiv" assert entry.data["arxivid"].startswith("1812.09976") assert "_download" not in entry.data.keys() assert not os.path.exists(path.path) finally: try: os.remove(path.path) except FileNotFoundError: pass
def test_disambiguate_label(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test label disambiguation if the provided one already exists. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ git = setup.get("git", False) AddCommand().execute(["-b", EXAMPLE_DUPLICATE_ENTRY_BIB]) assert ( "cobib.commands.add", 30, "You tried to add a new entry 'einstein' which already exists!", ) in caplog.record_tuples assert ( "cobib.commands.add", 30, "The label will be disambiguated based on the configuration option: " "config.database.format.label_suffix", ) in caplog.record_tuples assert Database()["einstein_a"] if git: # assert the git commit message self.assert_git_commit_message("add", None)
def test_skipping_undone_commits(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test skipping already undone commits. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) AddCommand().execute(["-b", get_resource("example_entry.bib")]) UndoCommand().execute([]) caplog.clear() UndoCommand().execute([]) self._assert() assert "Storing undone commit" in caplog.record_tuples[4][2] assert "Skipping" in caplog.record_tuples[6][2]
def test_command( self, setup: Any, expected_exit: bool, caplog: pytest.LogCaptureFixture ) -> None: """Test the command itself. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. expected_exit: whether to expect an early exit. caplog: the built-in pytest fixture. """ git = setup.get("git", False) if not git: RedoCommand().execute([]) for (source, level, message) in caplog.record_tuples: if ("cobib.commands.redo", logging.ERROR) == ( source, level, ) and "git-tracking" in message: break else: pytest.fail("No Error logged from RedoCommand.") elif expected_exit: # Regression test against #65 AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) with pytest.raises(SystemExit): RedoCommand().execute([]) for (source, level, message) in caplog.record_tuples: if ("cobib.commands.redo", logging.WARNING) == ( source, level, ) and "Could not find a commit to redo." in message: break else: pytest.fail("No Error logged from UndoCommand.") else: AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) if Database().get("example_multi_file_entry", None) is not None: pytest.skip("UndoCommand failed. No point in attempting Redo.") RedoCommand().execute([]) self._assert()
def assert_delete(screen): """Asserts entry is deleted. This also ensures it is added again after successful deletion. """ try: assert f"CoBib v{version} - 3 Entries" in screen.display[0] assert not any("dummy_entry_for_scroll_testing" in line for line in screen.display[4:21]) finally: AddCommand().execute(['-b', './test/dummy_scrolling_entry.bib'])
def test_event_post_add_command(self, setup: Any) -> None: """Tests the PostAddCommand event.""" @Event.PostAddCommand.subscribe def hook(new_entries: Dict[str, Entry]) -> None: new_entries["dummy"] = new_entries.pop("einstein_a") assert Event.PostAddCommand.validate() AddCommand().execute(["-b", EXAMPLE_DUPLICATE_ENTRY_BIB]) assert "dummy" in Database().keys()
def setup(): """Setup.""" # ensure configuration is empty CONFIG.config = {} root = os.path.abspath(os.path.dirname(__file__)) CONFIG.set_config(Path(root + '/../cobib/docs/debug.ini')) # NOTE: normally you would never trigger an Add command before reading the database but in this # controlled testing scenario we can be certain that this is fine AddCommand().execute(['-b', './test/dummy_scrolling_entry.bib']) read_database() yield setup DeleteCommand().execute(['dummy_entry_for_scroll_testing'])
def test_event_pre_add_command(self, setup: Any) -> None: """Tests the PreAddCommand event.""" @Event.PreAddCommand.subscribe def hook(largs: Namespace) -> None: largs.label = "dummy" assert Event.PreAddCommand.validate() AddCommand().execute(["-b", EXAMPLE_DUPLICATE_ENTRY_BIB]) assert "dummy" in Database().keys()
def test_warning_missing_label(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test warning for missing label and any other input. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ AddCommand().execute([""]) assert ( "cobib.commands.add", 40, "Neither an input to parse nor a label for manual creation specified!", ) in caplog.record_tuples
def test_cmdline(self, setup: Any, monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture) -> None: """Test the command-line access of the command. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. monkeypatch: the built-in pytest fixture. caplog: the built-in pytest fixture. """ AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) self.run_module(monkeypatch, "main", ["cobib", "undo"]) self._assert()
def test_tui_open_menu(): """Test the open prompt menu for multiple associated files.""" # ensure configuration is empty CONFIG.config = {} root = os.path.abspath(os.path.dirname(__file__)) CONFIG.set_config(Path(root + '/../cobib/docs/debug.ini')) # NOTE: normally you would never trigger an Add command before reading the database but in this # controlled testing scenario we can be certain that this is fine AddCommand().execute(['-b', './test/dummy_multi_file_entry.bib']) read_database() try: test_tui(None, 'o', assert_open, {}) finally: DeleteCommand().execute(['dummy_multi_file_entry'])
def test_event_post_undo_command(self, setup: Any) -> None: """Tests the PostUndoCommand event.""" @Event.PostUndoCommand.subscribe def hook(root: Path, sha: str) -> None: print(root) assert Event.PostUndoCommand.validate() with contextlib.redirect_stdout(StringIO()) as out: AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) self._assert() assert out.getvalue() == f"{self.COBIB_TEST_DIR}\n"
def test_tui_config_keys(command, key): """Test TUI key binding configuration.""" # ensure configuration is empty CONFIG.config = {} root = os.path.abspath(os.path.dirname(__file__)) CONFIG.set_config(Path(root + '/../cobib/docs/debug.ini')) # overwrite key binding configuration CONFIG.config['KEY_BINDINGS'][command] = key # NOTE: normally you would never trigger an Add command before reading the database but in this # controlled testing scenario we can be certain that this is fine AddCommand().execute(['-b', './test/dummy_scrolling_entry.bib']) read_database() try: test_tui(None, key, assert_show, {}) finally: DeleteCommand().execute(['dummy_entry_for_scroll_testing'])
def test_configured_label_default(self, setup: Any) -> None: """Test add command when a `label_default` is pre-configured. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. """ config.database.format.label_default = "{author.split()[1]}{year}" git = setup.get("git", False) AddCommand().execute(["-b", EXAMPLE_DUPLICATE_ENTRY_BIB]) assert Database()["Einstein1905"] if git: # assert the git commit message self.assert_git_commit_message("add", None)
def test_add_with_download( self, folder: Optional[str], setup: Any, capsys: pytest.CaptureFixture[str], caplog: pytest.LogCaptureFixture, ) -> None: """Test adding a new entry with an associated file automatically downloaded. Args: folder: the folder for the downloaded file. setup: the `tests.commands.command_test.CommandTest.setup` fixture. capsys: the built-in pytest fixture. caplog: the built-in pytest fixture. """ path = RelPath(f"{'/tmp' if folder is None else folder}/Cao2018.pdf") try: # ensure file does not exist yet os.remove(path.path) except FileNotFoundError: pass try: args = ["-a", "1812.09976"] if folder: args += ["-p", folder] AddCommand().execute(args) if ( "cobib.parsers.arxiv", logging.ERROR, "An Exception occurred while trying to query the arXiv ID: 1812.09976.", ) in caplog.record_tuples: pytest.skip("The requests API encountered an error. Skipping test.") entry = Database()["Cao2018"] assert entry.label == "Cao2018" assert entry.data["archivePrefix"] == "arXiv" assert entry.data["arxivid"].startswith("1812.09976") assert "_download" not in entry.data.keys() assert f"Successfully downloaded {path}" in capsys.readouterr().out assert os.path.exists(path.path) finally: try: os.remove(path.path) except FileNotFoundError: pass
def test_skip_manual_add_if_exists(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test manual addition is skipped if the label exists already. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ AddCommand().execute(["-l", "einstein"]) assert ( "cobib.commands.add", 30, "You tried to add a new entry 'einstein' which already exists!", ) in caplog.record_tuples assert ( "cobib.commands.add", 30, "Please use `cobib edit einstein` instead!", ) in caplog.record_tuples
def test_cmdline( self, setup: Any, monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture ) -> None: """Test the command-line access of the command. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. monkeypatch: the built-in pytest fixture. caplog: the built-in pytest fixture. """ AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) if Database().get("example_multi_file_entry", None) is not None: pytest.skip("UndoCommand failed. No point in attempting Redo.") self.run_module(monkeypatch, "main", ["cobib", "redo"]) self._assert()
def test_add_new_entry(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test adding a new plain entry. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ AddCommand().execute(["-l", "dummy"]) assert ( "cobib.commands.add", 30, "No input to parse. Creating new entry 'dummy' manually.", ) in caplog.record_tuples with open(config.database.file, "r", encoding="utf-8") as file: lines = file.readlines() dummy_start = lines.index("dummy:\n") assert dummy_start > 0 assert lines[dummy_start - 1] == "---\n" assert lines[dummy_start + 1] == " ENTRYTYPE: article\n" assert lines[dummy_start + 2] == "...\n"
def test_event_post_redo_command(self, setup: Any) -> None: """Tests the PostRedoCommand event.""" @Event.PostRedoCommand.subscribe def hook(root: Path, sha: str) -> None: print(root) assert Event.PostRedoCommand.validate() with contextlib.redirect_stdout(StringIO()) as out: AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) if Database().get("example_multi_file_entry", None) is not None: pytest.skip("UndoCommand failed. No point in attempting Redo.") RedoCommand().execute([]) self._assert() assert out.getvalue() == f"{self.COBIB_TEST_DIR}\n"
def test_tui(self, setup: Any) -> None: """Test the TUI access of the command. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. """ def assertion(screen, logs, **kwargs): # type: ignore assert "example_multi_file_entry" in screen.display[1] expected_log = [ ("cobib.commands.redo", 10, "Redo command triggered from TUI."), ("cobib.commands.redo", 10, "Starting Redo command."), ("cobib.commands.redo", 10, "Obtaining git log."), ] # we only assert the first three messages because the following ones will contain always # changing commit SHAs assert [log for log in logs if log[0] == "cobib.commands.redo"][0:3] == expected_log AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) self.run_tui("r", assertion, {})
def test_overwrite_label(self, setup: Any) -> None: """Test add command while specifying a label manually. Regression test against #4. The duplicate entry has been adapted to also assert the elongation of Journal names. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. """ config.utils.journal_abbreviations = [("Annalen der Physik", "Ann. Phys.")] git = setup.get("git", False) # add potentially duplicate entry AddCommand().execute(["-b", EXAMPLE_DUPLICATE_ENTRY_BIB, "--label", "duplicate_resolver"]) assert Database()["duplicate_resolver"] self._assert(EXAMPLE_DUPLICATE_ENTRY_YAML) if git: # assert the git commit message self.assert_git_commit_message("add", None)
def test_command(self, setup: Any, expected_exit: bool, caplog: pytest.LogCaptureFixture) -> None: """Test the command itself. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. expected_exit: whether to expect an early exit. caplog: the built-in pytest fixture. """ git = setup.get("git", False) if not git: UndoCommand().execute([]) for (source, level, message) in caplog.record_tuples: if ("cobib.commands.undo", logging.ERROR) == ( source, level, ) and "git-tracking" in message: break else: pytest.fail("No Error logged from UndoCommand.") elif expected_exit: # Regression test related to #65 with pytest.raises(SystemExit): UndoCommand().execute([]) for (source, level, message) in caplog.record_tuples: if ("cobib.commands.undo", logging.WARNING) == ( source, level, ) and "Could not find a commit to undo." in message: break else: pytest.fail("No Error logged from UndoCommand.") else: AddCommand().execute(["-b", EXAMPLE_MULTI_FILE_ENTRY_BIB]) UndoCommand().execute([]) self._assert()
def test_add_with_update(self, setup: Any, caplog: pytest.LogCaptureFixture) -> None: """Test update option of AddCommand. Args: setup: the `tests.commands.command_test.CommandTest.setup` fixture. caplog: the built-in pytest fixture. """ git = setup.get("git", False) AddCommand().execute(["-a", "1812.09976", "--skip-download"]) if ( "cobib.parsers.arxiv", logging.ERROR, "An Exception occurred while trying to query the arXiv ID: 1812.09976.", ) in caplog.record_tuples: pytest.skip("The requests API encountered an error. Skipping test.") # assert initial state entry = Database()["Cao2018"] assert entry.data["author"].startswith("Yudong Cao") assert entry.data["title"].startswith("Quantum Chemistry in the Age of Quantum Computing") assert entry.data["arxivid"].startswith("1812.09976") assert entry.data["doi"] == "10.1021/acs.chemrev.8b00803" assert entry.data["primaryClass"] == "quant-ph" assert entry.data["archivePrefix"] == "arXiv" assert entry.data["abstract"] != "" assert entry.data["year"] == 2018 assert "journal" not in entry.data.keys() assert "month" not in entry.data.keys() assert "number" not in entry.data.keys() assert "pages" not in entry.data.keys() assert "volume" not in entry.data.keys() args = ["-d", "10.1021/acs.chemrev.8b00803", "-l", "Cao2018", "--skip-download", "--update"] AddCommand().execute(args) if ( "cobib.parsers.doi", logging.ERROR, "An Exception occurred while trying to query the DOI: 10.1021/acs.chemrev.8b00803.", ) in caplog.record_tuples: pytest.skip("The requests API encountered an error. Skipping test.") # assert final state entry = Database()["Cao2018"] assert entry.data["author"].startswith("Yudong Cao") assert entry.data["title"].startswith("Quantum Chemistry in the Age of Quantum Computing") assert entry.data["arxivid"].startswith("1812.09976") assert entry.data["primaryClass"] == "quant-ph" assert entry.data["archivePrefix"] == "arXiv" assert entry.data["abstract"] != "" assert entry.data["journal"] == "Chemical Reviews" assert entry.data["doi"] == "10.1021/acs.chemrev.8b00803" assert entry.data["month"] == "aug" assert entry.data["number"] == 19 assert entry.data["pages"] == "10856--10915" assert entry.data["volume"] == 119 assert entry.data["year"] == 2019 if git: # assert the git commit message # Note: we do not assert the arguments, because they depend on the available parsers self.assert_git_commit_message("add", None)