Add format tests to pytest-bdd

- Implement cache dir fixture and step
- Implement various steps to check the cache directory (files contained,
  etc)

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
This commit is contained in:
Jonathan Wren 2021-04-03 15:51:19 -07:00
parent e2bb8cf0de
commit b8c7a7c7e5
3 changed files with 557 additions and 460 deletions

View file

@ -1,7 +1,7 @@
Feature: Custom formats
Scenario Outline: JSON format
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl --format json"
Then we should get no error
@ -16,11 +16,11 @@ Feature: Custom formats
And entry 3 should have an array "tags" with 2 elements
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario: Exporting dayone to json
Given we use the config "dayone.yaml"
@ -30,12 +30,11 @@ Feature: Custom formats
And the json output should contain entries.0.uuid = "4BB1F46946AD439996C9B59DE7C4DDC1"
Scenario Outline: Printing a journal that has multiline entries with tags
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl -n 1 @ipsum"
Then we should get no error
And the output should be
"""
2020-08-29 11:11 Entry the first.
| Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada
| quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus
@ -56,17 +55,16 @@ Feature: Custom formats
| velit scelerisque fringilla. Phasellus pharetra justo et nulla fringilla, ac
| porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
| conubia nostra, per inceptos himenaeos.
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario Outline: Exporting using filters should only export parts of the journal
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl -until 'August 2020' --format json"
Then the output should be parsable as json
@ -80,19 +78,18 @@ Feature: Custom formats
And entry 2 should have an array "tags" with 1 elements
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario Outline: Exporting using custom templates
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we load template "sample.template"
And we use the password "test" if prompted
When we run "jrnl -1 --format sample"
Then the output should be
"""
The third entry finally after weeks without writing.
----------------------------------------------------
@ -106,20 +103,18 @@ Feature: Custom formats
vulputate. Sed mauris urna, consectetur in justo eu, volutpat accumsan justo.
Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at
ante eget fringilla. @tagthree and also @tagone
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario Outline: Increasing Headings on Markdown export
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we open the editor and append
"""
[2020-10-14 13:23] Heading Test
H1-1
@ -162,11 +157,9 @@ Feature: Custom formats
More stuff
more stuff again
"""
Then we flush the output
When we run "jrnl -1 --export markdown"
Then the output should be
"""
# 2020
## October
@ -207,30 +200,26 @@ Feature: Custom formats
More stuff
more stuff again
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
# | basic_dayone | @todo
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
# | basic_dayone.yaml | @todo
Scenario Outline: Add a blank line to Markdown export if there isn't one already
# https://github.com/jrnl-org/jrnl/issues/768
# https://github.com/jrnl-org/jrnl/issues/881
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we open the editor and append
"""
[2020-10-29 11:11] First entry.
[2020-10-29 11:11] Second entry.
[2020-10-29 11:13] Third entry.
"""
Then we flush the output
When we run "jrnl -3 --format markdown"
Then the output should be
"""
# 2020
## October
@ -243,31 +232,34 @@ Feature: Custom formats
### 2020-10-29 11:13 Third entry.
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
# | basic_dayone | @todo
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
# | basic_dayone.yaml | @todo
@skip
Scenario Outline: Exporting to XML
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl --export xml"
Then the output should be a valid XML string
And "entries" node in the xml output should have 3 elements
And "tags" in the xml output should contain ["@ipsum", "@tagone", "@tagtwo", "@tagthree"]
And "tags" in the xml output should contain
@ipsum
@tagone
@tagtwo
@tagthree
And there should be 10 "tag" elements
Examples: configs
| config |
# | basic_onefile | @todo
# | basic_encrypted | @todo
# | basic_folder | @todo
# | basic_dayone | @todo
| config_file |
# | basic_onefile.yaml | @todo
# | basic_encrypted.yaml | @todo
# | basic_folder.yaml | @todo
# | basic_dayone.yaml | @todo
Scenario: Exporting to XML
Given we use the config "tags.yaml"
@ -275,36 +267,36 @@ Feature: Custom formats
When we run "jrnl --export xml"
Then the output should be a valid XML string
And "entries" node in the xml output should have 2 elements
And "tags" in the xml output should contain ["@idea", "@journal", "@dan"]
And "tags" in the xml output should contain
@idea
@journal
@dan
And there should be 7 "tag" elements
Scenario Outline: Exporting tags
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl --export tags"
Then the output should be
"""
@tagtwo : 2
@tagone : 2
@tagthree : 1
@ipsum : 1
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
@todo
Scenario Outline: Exporting fancy
# Needs better emoji support
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl --export fancy"
Then the output should be
"""
2020-08-29 11:11
Entry the first.
@ -387,29 +379,26 @@ Feature: Custom formats
Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at
ante eget fringilla. @tagthree and also @tagone
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
@skip_win
Scenario Outline: Export to yaml
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
And we create a cache directory
When we run "jrnl --export yaml -o {cache_dir}"
Then the cache should contain the files
"""
When we run "jrnl --format yaml --file {cache_dir}"
Then the cache directory should contain the files
2020-08-29_entry-the-first.md
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
"""
And the content of file "2020-08-29_entry-the-first.md" in the cache should be
"""
---
title: Entry the first.
date: 2020-08-29 11:11
@ -435,31 +424,27 @@ Feature: Custom formats
porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per
conubia nostra, per inceptos himenaeos.
...
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
# | basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
# | basic_dayone.yaml |
@skip_win # @todo YAML exporter does not correctly export emoji on Windows
Scenario Outline: Add a blank line to YAML export if there isn't one already
# https://github.com/jrnl-org/jrnl/issues/768
# https://github.com/jrnl-org/jrnl/issues/881
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
And we create a cache directory
When we run "jrnl --export yaml -o {cache_dir}"
Then the cache should contain the files
"""
2020-08-29_entry-the-first.md
2020-08-31_a-second-entry-in-what-i-hope-to-be-a-long-series.md
2020-09-24_the-third-entry-finally-after-weeks-without-writing.md
"""
And the content of file "2020-09-24_the-third-entry-finally-after-weeks-without-writing.md" in the cache should be
"""
---
title: The third entry finally after weeks without writing.
date: 2020-09-24 09:14
@ -477,14 +462,13 @@ Feature: Custom formats
Phasellus aliquam lacus placerat convallis vestibulum. Curabitur maximus at
ante eget fringilla. @tagthree and also @tagone
...
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
# | basic_dayone | @todo
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
# | basic_dayone.yaml | @todo
Scenario: Empty DayOne entry bodies should not error
# https://github.com/jrnl-org/jrnl/issues/780
@ -493,36 +477,35 @@ Feature: Custom formats
Then we should get no error
Scenario Outline: --short displays the short version of entries (only the title)
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl -on 2020-08-31 --short"
Then the output should be "2020-08-31 14:32 A second entry in what I hope to be a long series."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario Outline: -s displays the short version of entries (only the title)
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl -on 2020-08-31 -s"
Then the output should be "2020-08-31 14:32 A second entry in what I hope to be a long series."
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario: Markdown Support from config file
Given we use the config "format_md.yaml"
When we run "jrnl -n 1"
Then the output should be
"""
# 2013
## June
@ -530,50 +513,43 @@ Feature: Custom formats
### 2013-06-10 15:40 Life is good.
But I'm better.
"""
Scenario: Text Formatter from config file
Given we use the config "format_text.yaml"
When we run "jrnl -n 1"
Then the output should be
"""
[2013-06-10 15:40] Life is good.
But I'm better.
"""
Scenario Outline: Exporting entries with Cyrillic characters to directory should not fail
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
And we create a cache directory
When we run "jrnl 2020-11-21: Первая"
When we run "jrnl --format md --file {cache_dir} -on 2020-11-21"
Then the cache should contain the files
"""
2020-11-21_первая.md
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |
Scenario Outline: Export date counts
Given we use the config "<config>.yaml"
Given we use the config "<config_file>"
And we use the password "test" if prompted
When we run "jrnl 2020-08-31 01:01: Hi."
And we run "jrnl --format dates"
Then the output should be
"""
2020-08-29, 1
2020-08-31, 2
2020-09-24, 1
"""
Examples: configs
| config |
| basic_onefile |
| basic_encrypted |
| basic_folder |
| basic_dayone |
| config_file |
| basic_onefile.yaml |
| basic_encrypted.yaml |
| basic_folder.yaml |
| basic_dayone.yaml |

View file

@ -7,10 +7,13 @@ from collections import defaultdict
from keyring import backend
from keyring import set_keyring
from keyring import errors
import random
import string
import re
import shutil
import tempfile
from unittest.mock import patch
from xml.etree import ElementTree
from pytest_bdd import given
from pytest_bdd import then
@ -119,6 +122,11 @@ def password():
return ""
@fixture
def cache_dir():
return {"exists": False, "path": ""}
@fixture
def str_value():
return ""
@ -212,7 +220,12 @@ def use_password_forever(pw):
@when(parse('we run "jrnl" and enter "{user_input}"'))
@when('we run "jrnl <command>"')
@when('we run "jrnl"')
def we_run(command, config_path, user_input, cli_run, capsys, password, keyring):
def we_run(
command, config_path, user_input, cli_run, capsys, password, keyring, cache_dir
):
if cache_dir["exists"]:
command = command.format(cache_dir=cache_dir["path"])
args = split_args(command)
status = 0
@ -364,3 +377,111 @@ def password_was_called(cli_run):
@then("we should not be prompted for a password")
def password_was_not_called(cli_run):
assert not cli_run["mocks"]["getpass"].called
@then(parse("the cache directory should contain the files\n{file_list}"))
def assert_dir_contains_files(file_list, cache_dir):
actual_files = os.listdir(cache_dir["path"])
expected_files = file_list.split("\n")
# sort to deal with inconsistent default file ordering on different OS's
actual_files.sort()
expected_files.sort()
assert actual_files == expected_files, [actual_files, expected_files]
@given("we create a cache directory", target_fixture="cache_dir")
def create_cache_dir(temp_dir):
random_str = "".join(random.choices(string.ascii_uppercase + string.digits, k=20))
dir_path = os.path.join(temp_dir.name, "cache_" + random_str)
os.mkdir(dir_path)
return {"exists": True, "path": dir_path}
@then(parse('the content of file "{file_path}" in the cache should be\n{file_content}'))
def content_of_file_should_be(file_path, file_content, cache_dir):
assert cache_dir["exists"]
expected_content = file_content.strip().splitlines()
with open(os.path.join(cache_dir["path"], file_path), "r") as f:
actual_content = f.read().strip().splitlines()
for actual_line, expected_line in zip(actual_content, expected_content):
if actual_line.startswith("tags: ") and expected_line.startswith("tags: "):
assert_equal_tags_ignoring_order(
actual_line, expected_line, actual_content, expected_content
)
else:
assert actual_line.strip() == expected_line.strip(), [
[actual_line.strip(), expected_line.strip()],
[actual_content, expected_content],
]
def assert_equal_tags_ignoring_order(
actual_line, expected_line, actual_content, expected_content
):
actual_tags = set(tag.strip() for tag in actual_line[len("tags: ") :].split(","))
expected_tags = set(
tag.strip() for tag in expected_line[len("tags: ") :].split(",")
)
assert actual_tags == expected_tags, [
[actual_tags, expected_tags],
[expected_content, actual_content],
]
@then(parse("the cache should contain the files\n{file_list}"))
def cache_dir_contains_files(file_list, cache_dir):
assert cache_dir["exists"]
actual_files = os.listdir(cache_dir["path"])
expected_files = file_list.split("\n")
# sort to deal with inconsistent default file ordering on different OS's
actual_files.sort()
expected_files.sort()
assert actual_files == expected_files, [actual_files, expected_files]
@then("the output should be a valid XML string")
def assert_valid_xml_string(cli_run):
output = cli_run["stdout"]
xml_tree = ElementTree.fromstring(output)
assert xml_tree, output
@then(parse('"{item}" node in the xml output should have {number:d} elements'))
def assert_xml_output_entries_count(item, number, cli_run):
output = cli_run["stdout"]
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert item in xml_tags, str(list(xml_tags))
actual_entry_count = len(xml_tree.find(item))
assert actual_entry_count == number, actual_entry_count
@then(parse('"tags" in the xml output should contain\n{expected_tags}'))
def assert_xml_output_tags(expected_tags, cli_run):
output = cli_run["stdout"]
expected_tags = expected_tags.split("\n")
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "tags" in xml_tags, str(list(xml_tags))
actual_tags = set(t.attrib["name"] for t in xml_tree.find("tags"))
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
@then(parse('there should be {number:d} "{item}" elements'))
def count_elements(number, item, cli_run):
output = cli_run["stdout"]
xml_tree = ElementTree.fromstring(output)
assert len(xml_tree.findall(".//" + item)) == number

View file

@ -6,7 +6,7 @@ scenarios("../features/datetime.feature")
scenarios("../features/delete.feature")
scenarios("../features/encrypt.feature")
# scenarios("../features/file_storage.feature")
# scenarios("../features/format.feature")
scenarios("../features/format.feature")
# scenarios("../features/import.feature")
# scenarios("../features/multiple_journals.feature")
scenarios("../features/password.feature")