diff --git a/tests/bdd/features/install.feature b/tests/bdd/features/install.feature new file mode 100644 index 00000000..abef3d91 --- /dev/null +++ b/tests/bdd/features/install.feature @@ -0,0 +1,45 @@ +Feature: Installing jrnl + + Scenario: Install jrnl with default options + Given we use no config + When we run "jrnl hello world" and enter + \n + \n + Then the output should contain "Journal 'default' created" + And the default journal "journal.txt" should be in the "." directory + And the config should contain "encrypt: false" + And the version in the config file should be up-to-date + + Scenario: Install jrnl with custom relative default journal path + Given we use no config + When we run "jrnl hello world" and enter + default/custom.txt + n + Then the output should contain "Journal 'default' created" + And the default journal "custom.txt" should be in the "default" directory + And the config should contain "encrypt: false" + And the version in the config file should be up-to-date + + Scenario: Install jrnl with custom expanded default journal path + Given we use no config + And the home directory is called "home" + When we run "jrnl hello world" and enter + ~/custom.txt + n + Then the output should contain "Journal 'default' created" + And the default journal "custom.txt" should be in the "home" directory + And the config should contain "encrypt: false" + And the version in the config file should be up-to-date + + Scenario: Install jrnl with encrypted default journal + Given we use no config + When we run "jrnl hello world" and enter + encrypted.txt + y + Then the output should contain "Journal will be encrypted" + And the default journal "encrypted.txt" should be in the "." directory + And the config should contain "encrypt: true" + And the version in the config file should be up-to-date + When we run "jrnl" + Then we should be prompted for a password + \ No newline at end of file diff --git a/tests/bdd/test_features.py b/tests/bdd/test_features.py index fda146e1..7f02e6b3 100644 --- a/tests/bdd/test_features.py +++ b/tests/bdd/test_features.py @@ -13,6 +13,7 @@ scenarios("features/encrypt.feature") scenarios("features/file_storage.feature") scenarios("features/format.feature") scenarios("features/import.feature") +scenarios("features/install.feature") scenarios("features/multiple_journals.feature") scenarios("features/override.feature") scenarios("features/password.feature") diff --git a/tests/lib/fixtures.py b/tests/lib/fixtures.py index 1ad17708..b5c6895f 100644 --- a/tests/lib/fixtures.py +++ b/tests/lib/fixtures.py @@ -88,6 +88,7 @@ def cli_run( mock_editor, mock_user_input, mock_overrides, + mock_default_journal_path, ): # Check if we need more mocks mock_factories.update(mock_args) @@ -96,6 +97,7 @@ def cli_run( mock_factories.update(mock_editor) mock_factories.update(mock_config_path) mock_factories.update(mock_user_input) + mock_factories.update(mock_default_journal_path) return { "status": 0, @@ -164,6 +166,19 @@ def mock_config_path(request): } +@fixture +def mock_default_journal_path(temp_dir): + journal_path = os.path.join(temp_dir.name, "journal.txt") + return { + "default_journal_path_install": lambda: patch( + "jrnl.install.get_default_journal_path", return_value=journal_path + ), + "default_journal_path_config": lambda: patch( + "jrnl.config.get_default_journal_path", return_value=journal_path + ), + } + + @fixture def temp_dir(): return tempfile.TemporaryDirectory() @@ -216,7 +231,9 @@ def mock_user_input(request, password_input, stdin_input): return password_input if isinstance(user_input, Iterable): - return next(user_input) + input_line = next(user_input) + # A raw newline is used to indicate deliberate empty input + return "" if input_line == r"\n" else input_line # exceptions return user_input if not kwargs["password"] else password_input diff --git a/tests/lib/given_steps.py b/tests/lib/given_steps.py index 6da84643..a2cdd1ea 100644 --- a/tests/lib/given_steps.py +++ b/tests/lib/given_steps.py @@ -147,3 +147,10 @@ def parse_output_as_language(cli_run, language_name): assert False, f"Language name {language_name} not recognized" return {"lang": language_name, "obj": parsed_output} + + +@given(parse('the home directory is called "{home_dir}"')) +def home_directory(temp_dir, home_dir, monkeypatch): + home_path = os.path.join(temp_dir.name, home_dir) + monkeypatch.setenv("USERPROFILE", home_path) # for windows + monkeypatch.setenv("HOME", home_path) # for *nix diff --git a/tests/lib/then_steps.py b/tests/lib/then_steps.py index 08d8ddc7..857cf1f4 100644 --- a/tests/lib/then_steps.py +++ b/tests/lib/then_steps.py @@ -97,6 +97,12 @@ def output_should_contain_version(cli_run, toml_version): assert toml_version in out, toml_version +@then("the version in the config file should be up-to-date") +def config_file_version(config_on_disk, toml_version): + config_version = config_on_disk["version"] + assert config_version == toml_version + + @then(parse("the output should be {width:d} columns wide")) def output_should_be_columns_wide(cli_run, width): out = cli_run["stdout"] @@ -105,6 +111,22 @@ def output_should_be_columns_wide(cli_run, width): assert len(line) <= width +@then( + parse( + 'the default journal "{journal_file}" should be in the "{journal_dir}" directory' + ) +) +def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir): + default_journal_path = config_on_disk["journals"]["default"] + expected_journal_path = ( + os.path.join(temp_dir.name, journal_file) + if journal_dir == "." + else os.path.join(temp_dir.name, journal_dir, journal_file) + ) + # Use os.path.samefile here because both paths might not be fully expanded. + assert os.path.samefile(default_journal_path, expected_journal_path) + + @then( parse( 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' diff --git a/tests/lib/when_steps.py b/tests/lib/when_steps.py index 759c708d..bd51b503 100644 --- a/tests/lib/when_steps.py +++ b/tests/lib/when_steps.py @@ -23,6 +23,8 @@ def when_we_change_directory(directory_name): command = '(?P[^"]*)' input_method = "(?Penter|pipe|type)" all_input = '("(?P[^"]*)")' +# Note: A line with only a raw newline r'\n' is treated as +# an empty line of input internally for testing purposes. @when(parse('we run "jrnl {command}" and {input_method}\n{all_input}'))