From a9c539821f127c0bda93e35617858e3b73b717fe Mon Sep 17 00:00:00 2001 From: Ben Beasley Date: Sat, 3 Jul 2021 18:20:52 -0400 Subject: [PATCH 01/74] Remove useless shebangs and executable permissions (#1283) * Remove executable permissions from non-script files * Remove harmless-but-useless shebang lines --- docs_theme/index.html | 0 jrnl/DayOneJournal.py | 2 -- jrnl/Entry.py | 1 - jrnl/FolderJournal.py | 1 - jrnl/Journal.py | 1 - jrnl/__init__.py | 1 - jrnl/__main__.py | 1 - jrnl/cli.py | 1 - jrnl/color.py | 1 - jrnl/install.py | 1 - jrnl/plugins/__init__.py | 1 - jrnl/plugins/dates_exporter.py | 1 - jrnl/plugins/fancy_exporter.py | 1 - jrnl/plugins/jrnl_importer.py | 1 - jrnl/plugins/json_exporter.py | 1 - jrnl/plugins/markdown_exporter.py | 1 - jrnl/plugins/tag_exporter.py | 1 - jrnl/plugins/template_exporter.py | 1 - jrnl/plugins/text_exporter.py | 1 - jrnl/plugins/util.py | 1 - jrnl/plugins/xml_exporter.py | 1 - jrnl/plugins/yaml_exporter.py | 1 - 22 files changed, 22 deletions(-) mode change 100755 => 100644 docs_theme/index.html mode change 100755 => 100644 jrnl/Entry.py diff --git a/docs_theme/index.html b/docs_theme/index.html old mode 100755 new mode 100644 diff --git a/jrnl/DayOneJournal.py b/jrnl/DayOneJournal.py index 6e1b8345..61a60ca0 100644 --- a/jrnl/DayOneJournal.py +++ b/jrnl/DayOneJournal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - from datetime import datetime import fnmatch import os diff --git a/jrnl/Entry.py b/jrnl/Entry.py old mode 100755 new mode 100644 index 67ba84f3..e227794f --- a/jrnl/Entry.py +++ b/jrnl/Entry.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/FolderJournal.py b/jrnl/FolderJournal.py index e727cdf0..954a9436 100644 --- a/jrnl/FolderJournal.py +++ b/jrnl/FolderJournal.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 4196571d..b889c0d3 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/__init__.py b/jrnl/__init__.py index 8f4dc3ec..550d580f 100644 --- a/jrnl/__init__.py +++ b/jrnl/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/__main__.py b/jrnl/__main__.py index e977369f..49497161 100644 --- a/jrnl/__main__.py +++ b/jrnl/__main__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/cli.py b/jrnl/cli.py index 93a7e899..6a1c6a0f 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/color.py b/jrnl/color.py index 3bdd4149..691cce9c 100644 --- a/jrnl/color.py +++ b/jrnl/color.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import re from string import punctuation from string import whitespace diff --git a/jrnl/install.py b/jrnl/install.py index db4c0fba..b0ae2aa1 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/__init__.py b/jrnl/plugins/__init__.py index 3eb4d5a2..da6199fb 100644 --- a/jrnl/plugins/__init__.py +++ b/jrnl/plugins/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/dates_exporter.py b/jrnl/plugins/dates_exporter.py index d11e527c..e032b652 100644 --- a/jrnl/plugins/dates_exporter.py +++ b/jrnl/plugins/dates_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/fancy_exporter.py b/jrnl/plugins/fancy_exporter.py index 15efc19b..2cb27eca 100644 --- a/jrnl/plugins/fancy_exporter.py +++ b/jrnl/plugins/fancy_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/jrnl_importer.py b/jrnl/plugins/jrnl_importer.py index af5ea6ce..214fc70b 100644 --- a/jrnl/plugins/jrnl_importer.py +++ b/jrnl/plugins/jrnl_importer.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/json_exporter.py b/jrnl/plugins/json_exporter.py index dd07b0ce..666d9a3d 100644 --- a/jrnl/plugins/json_exporter.py +++ b/jrnl/plugins/json_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/markdown_exporter.py b/jrnl/plugins/markdown_exporter.py index 693f2fa5..11f748b6 100644 --- a/jrnl/plugins/markdown_exporter.py +++ b/jrnl/plugins/markdown_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/tag_exporter.py b/jrnl/plugins/tag_exporter.py index bc3736eb..1153fa01 100644 --- a/jrnl/plugins/tag_exporter.py +++ b/jrnl/plugins/tag_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/template_exporter.py b/jrnl/plugins/template_exporter.py index af081f8c..d2e5ce3e 100644 --- a/jrnl/plugins/template_exporter.py +++ b/jrnl/plugins/template_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/text_exporter.py b/jrnl/plugins/text_exporter.py index 7714606c..c9eaaf14 100644 --- a/jrnl/plugins/text_exporter.py +++ b/jrnl/plugins/text_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/util.py b/jrnl/plugins/util.py index 04159ca4..ae49a2a8 100644 --- a/jrnl/plugins/util.py +++ b/jrnl/plugins/util.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/xml_exporter.py b/jrnl/plugins/xml_exporter.py index b9467912..9901f4b7 100644 --- a/jrnl/plugins/xml_exporter.py +++ b/jrnl/plugins/xml_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/jrnl/plugins/yaml_exporter.py b/jrnl/plugins/yaml_exporter.py index 7716c6c1..887fdaf1 100644 --- a/jrnl/plugins/yaml_exporter.py +++ b/jrnl/plugins/yaml_exporter.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # encoding: utf-8 # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html From ace6b8004c44a5db66c90f82e1e68015b2b7be8b Mon Sep 17 00:00:00 2001 From: Jrnl Bot Date: Sat, 3 Jul 2021 22:22:37 +0000 Subject: [PATCH 02/74] Update changelog [ci skip] --- CHANGELOG.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d28c70..c8f71a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,9 @@ [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.1...HEAD) -**Implemented enhancements:** - -- Multiple entries with same timestamp should be grouped together [\#1247](https://github.com/jrnl-org/jrnl/issues/1247) - **Build:** +- Remove useless shebangs and executable permissions [\#1283](https://github.com/jrnl-org/jrnl/pull/1283) ([musicinmybrain](https://github.com/musicinmybrain)) - Remove `--version` from brew release workflow [\#1233](https://github.com/jrnl-org/jrnl/pull/1233) ([wren](https://github.com/wren)) **Packaging:** @@ -17,6 +14,7 @@ - Bump black from 21.5b1 to 21.5b2 [\#1254](https://github.com/jrnl-org/jrnl/pull/1254) ([dependabot[bot]](https://github.com/apps/dependabot)) - Bump black from 21.5b0 to 21.5b1 [\#1244](https://github.com/jrnl-org/jrnl/pull/1244) ([dependabot[bot]](https://github.com/apps/dependabot)) - Bump black from 20.8b1 to 21.5b0 [\#1241](https://github.com/jrnl-org/jrnl/pull/1241) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump pytest from 6.2.3 to 6.2.4 [\#1240](https://github.com/jrnl-org/jrnl/pull/1240) ([dependabot[bot]](https://github.com/apps/dependabot)) ## [v2.8.1](https://pypi.org/project/jrnl/v2.8.1/) (2021-04-24) From 1390493a29e734f6507407137da4d4dd0f22a84c Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Mon, 28 Dec 2020 09:45:22 -0800 Subject: [PATCH 03/74] Install pytest-bdd (which will eventually replace behave) - Copy over the current tests from behave into the new directory that pytest-bdd will use them in Co-authored-by: Micah Jerome Ellison --- __init__.py | 3 + poetry.lock | 639 ++++++++---------- pyproject.toml | 4 + tests/features/build.feature | 8 + tests/features/configs/basic_dayone.yaml | 17 + tests/features/configs/basic_encrypted.yaml | 17 + tests/features/configs/basic_folder.yaml | 17 + tests/features/configs/basic_onefile.yaml | 17 + tests/features/configs/brackets.yaml | 12 + tests/features/configs/bug153.yaml | 17 + tests/features/configs/bug343.yaml | 13 + tests/features/configs/bug780.yaml | 12 + tests/features/configs/dayone.yaml | 12 + tests/features/configs/dayone_empty.yaml | 17 + tests/features/configs/deletion.yaml | 12 + tests/features/configs/deletion_filters.yaml | 12 + tests/features/configs/editor-args.yaml | 12 + tests/features/configs/editor.yaml | 12 + .../features/configs/editor_empty_folder.yaml | 12 + tests/features/configs/editor_encrypted.yaml | 17 + .../configs/editor_markdown_extension.yaml | 18 + tests/features/configs/empty_folder.yaml | 12 + tests/features/configs/encrypted.yaml | 12 + tests/features/configs/encrypted_old.json | 13 + tests/features/configs/encrypted_old.yaml | 11 + tests/features/configs/format_md.yaml | 19 + tests/features/configs/format_text.yaml | 19 + tests/features/configs/invalid_color.yaml | 17 + .../features/configs/little_endian_dates.yaml | 12 + .../configs/markdown-headings-335.yaml | 17 + tests/features/configs/missing_directory.yaml | 17 + tests/features/configs/missing_journal.yaml | 17 + .../features/configs/mostlyreadabledates.yaml | 12 + tests/features/configs/multiline-tags.yaml | 17 + tests/features/configs/multiline.yaml | 17 + tests/features/configs/multiple.yaml | 18 + tests/features/configs/no_colors.yaml | 12 + tests/features/configs/simple.yaml | 18 + tests/features/configs/tags-216.yaml | 17 + tests/features/configs/tags-237.yaml | 17 + tests/features/configs/tags.yaml | 17 + tests/features/configs/unreadabledates.yaml | 17 + tests/features/configs/upgrade_from_195.json | 11 + .../upgrade_from_195_little_endian_dates.json | 11 + ...om_195_with_missing_encrypted_journal.json | 11 + ...upgrade_from_195_with_missing_journal.json | 11 + tests/features/core.feature | 7 + tests/features/data/configs/basic_dayone.yaml | 17 + .../data/configs/basic_encrypted.yaml | 17 + tests/features/data/configs/basic_folder.yaml | 17 + .../features/data/configs/basic_onefile.yaml | 17 + tests/features/data/configs/brackets.yaml | 12 + tests/features/data/configs/bug153.yaml | 17 + tests/features/data/configs/bug343.yaml | 13 + tests/features/data/configs/bug780.yaml | 12 + tests/features/data/configs/dayone.yaml | 12 + tests/features/data/configs/dayone_empty.yaml | 17 + tests/features/data/configs/deletion.yaml | 12 + .../data/configs/deletion_filters.yaml | 12 + tests/features/data/configs/editor-args.yaml | 12 + tests/features/data/configs/editor.yaml | 12 + .../data/configs/editor_empty_folder.yaml | 12 + .../data/configs/editor_encrypted.yaml | 17 + tests/features/data/configs/empty_folder.yaml | 12 + tests/features/data/configs/encrypted.yaml | 12 + .../features/data/configs/encrypted_old.json | 13 + .../features/data/configs/encrypted_old.yaml | 11 + tests/features/data/configs/format_md.yaml | 19 + tests/features/data/configs/format_text.yaml | 19 + .../features/data/configs/invalid_color.yaml | 17 + .../data/configs/little_endian_dates.yaml | 12 + .../data/configs/markdown-headings-335.yaml | 17 + .../data/configs/missing_directory.yaml | 17 + .../data/configs/missing_journal.yaml | 17 + .../data/configs/mostlyreadabledates.yaml | 12 + .../features/data/configs/multiline-tags.yaml | 17 + tests/features/data/configs/multiline.yaml | 17 + tests/features/data/configs/multiple.yaml | 18 + tests/features/data/configs/no_colors.yaml | 12 + tests/features/data/configs/simple.yaml | 17 + tests/features/data/configs/tags-216.yaml | 17 + tests/features/data/configs/tags-237.yaml | 17 + tests/features/data/configs/tags.yaml | 17 + .../data/configs/unreadabledates.yaml | 17 + .../data/configs/upgrade_from_195.json | 11 + .../upgrade_from_195_little_endian_dates.json | 11 + ...om_195_with_missing_encrypted_journal.json | 11 + ...upgrade_from_195_with_missing_journal.json | 11 + .../D04D335AFED711EABA18FAFFC2100C3D.doentry | 53 ++ .../FC8A86CAFED711EA8892FAFFC2100C3D.doentry | 55 ++ .../FD8ABC8EFED711EABC35FAFFC2100C3D.doentry | 44 ++ .../data/journals/basic_encrypted.journal | 1 + .../data/journals/basic_folder/2020/08/29.txt | 19 + .../data/journals/basic_folder/2020/08/31.txt | 23 + .../data/journals/basic_folder/2020/09/24.txt | 11 + .../data/journals/basic_onefile.journal | 58 ++ tests/features/data/journals/brackets.journal | 2 + .../B40EE704E15846DE8D45C44118A4D511.doentry | 56 ++ .../B40EE704E15846DE8D45C44118A4D512.doentry | 52 ++ .../48A25033B34047C591160A4480197D8B.doentry | 33 + .../044F3747A38546168B572C2E3F217FA2.doentry | 34 + .../0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry | 46 ++ .../422BC895507944A291E6FC44FC6B8BFC.doentry | 31 + .../4BB1F46946AD439996C9B59DE7C4DDC1.doentry | 29 + .../dayone_empty.dayone/entries/empty.txt | 1 + tests/features/data/journals/deletion.journal | 5 + .../data/journals/deletion_filters.journal | 14 + .../features/data/journals/empty_folder/empty | 1 + .../features/data/journals/encrypted.journal | 1 + .../journals/encrypted_jrnl-1-9-5.journal | Bin 0 -> 128 bytes .../data/journals/little_endian_dates.journal | 5 + .../journals/markdown-headings-335.journal | 42 ++ .../data/journals/mostlyreadabledates.journal | 8 + .../data/journals/multiline-tags.journal | 7 + .../features/data/journals/multiline.journal | 5 + tests/features/data/journals/simple.journal | 5 + .../data/journals/simple_jrnl-1-9-5.journal | 13 + ...ple_jrnl-1-9-5_little_endian_dates.journal | 13 + tests/features/data/journals/tags-216.journal | 2 + tests/features/data/journals/tags-237.journal | 3 + tests/features/data/journals/tags.journal | 8 + .../data/journals/unreadabledates.journal | 5 + tests/features/data/journals/work.journal | 0 tests/features/data/templates/sample.template | 19 + tests/features/datetime.feature | 155 +++++ tests/features/delete.feature | 229 +++++++ tests/features/encrypt.feature | 35 + tests/features/environment.py | 0 tests/features/file_storage.feature | 56 ++ tests/features/format.feature | 579 ++++++++++++++++ tests/features/import.feature | 93 +++ .../D04D335AFED711EABA18FAFFC2100C3D.doentry | 53 ++ .../FC8A86CAFED711EA8892FAFFC2100C3D.doentry | 55 ++ .../FD8ABC8EFED711EABC35FAFFC2100C3D.doentry | 44 ++ .../features/journals/basic_encrypted.journal | 1 + .../journals/basic_folder/2020/08/29.txt | 19 + .../journals/basic_folder/2020/08/31.txt | 23 + .../journals/basic_folder/2020/09/24.txt | 11 + tests/features/journals/basic_onefile.journal | 58 ++ tests/features/journals/brackets.journal | 2 + .../B40EE704E15846DE8D45C44118A4D511.doentry | 56 ++ .../B40EE704E15846DE8D45C44118A4D512.doentry | 52 ++ .../48A25033B34047C591160A4480197D8B.doentry | 33 + .../044F3747A38546168B572C2E3F217FA2.doentry | 34 + .../0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry | 46 ++ .../422BC895507944A291E6FC44FC6B8BFC.doentry | 31 + .../4BB1F46946AD439996C9B59DE7C4DDC1.doentry | 29 + .../dayone_empty.dayone/entries/empty.txt | 1 + tests/features/journals/deletion.journal | 5 + .../journals/deletion_filters.journal | 14 + tests/features/journals/empty_folder/empty | 1 + tests/features/journals/encrypted.journal | 1 + .../journals/encrypted_jrnl-1-9-5.journal | Bin 0 -> 128 bytes .../journals/little_endian_dates.journal | 5 + .../journals/markdown-headings-335.journal | 42 ++ .../journals/mostlyreadabledates.journal | 8 + .../features/journals/multiline-tags.journal | 7 + tests/features/journals/multiline.journal | 5 + tests/features/journals/simple.journal | 5 + .../journals/simple_jrnl-1-9-5.journal | 13 + ...ple_jrnl-1-9-5_little_endian_dates.journal | 13 + tests/features/journals/tags-216.journal | 2 + tests/features/journals/tags-237.journal | 3 + tests/features/journals/tags.journal | 8 + .../features/journals/unreadabledates.journal | 5 + tests/features/journals/work.journal | 0 tests/features/multiple_journals.feature | 65 ++ tests/features/password.feature | 116 ++++ tests/features/search.feature | 318 +++++++++ tests/features/star.feature | 35 + tests/features/tag.feature | 53 ++ tests/features/templates/extension.md | 0 tests/features/upgrade.feature | 71 ++ tests/features/write.feature | 216 ++++++ tests/step_defs/__init__.py | 3 + tests/step_defs/conftest.py | 111 +++ tests/step_defs/test_features.py | 3 + 177 files changed, 5065 insertions(+), 340 deletions(-) create mode 100644 __init__.py create mode 100644 tests/features/build.feature create mode 100644 tests/features/configs/basic_dayone.yaml create mode 100644 tests/features/configs/basic_encrypted.yaml create mode 100644 tests/features/configs/basic_folder.yaml create mode 100644 tests/features/configs/basic_onefile.yaml create mode 100644 tests/features/configs/brackets.yaml create mode 100644 tests/features/configs/bug153.yaml create mode 100644 tests/features/configs/bug343.yaml create mode 100644 tests/features/configs/bug780.yaml create mode 100644 tests/features/configs/dayone.yaml create mode 100644 tests/features/configs/dayone_empty.yaml create mode 100644 tests/features/configs/deletion.yaml create mode 100644 tests/features/configs/deletion_filters.yaml create mode 100644 tests/features/configs/editor-args.yaml create mode 100644 tests/features/configs/editor.yaml create mode 100644 tests/features/configs/editor_empty_folder.yaml create mode 100644 tests/features/configs/editor_encrypted.yaml create mode 100644 tests/features/configs/editor_markdown_extension.yaml create mode 100644 tests/features/configs/empty_folder.yaml create mode 100644 tests/features/configs/encrypted.yaml create mode 100644 tests/features/configs/encrypted_old.json create mode 100644 tests/features/configs/encrypted_old.yaml create mode 100644 tests/features/configs/format_md.yaml create mode 100644 tests/features/configs/format_text.yaml create mode 100644 tests/features/configs/invalid_color.yaml create mode 100644 tests/features/configs/little_endian_dates.yaml create mode 100644 tests/features/configs/markdown-headings-335.yaml create mode 100644 tests/features/configs/missing_directory.yaml create mode 100644 tests/features/configs/missing_journal.yaml create mode 100644 tests/features/configs/mostlyreadabledates.yaml create mode 100644 tests/features/configs/multiline-tags.yaml create mode 100644 tests/features/configs/multiline.yaml create mode 100644 tests/features/configs/multiple.yaml create mode 100644 tests/features/configs/no_colors.yaml create mode 100644 tests/features/configs/simple.yaml create mode 100644 tests/features/configs/tags-216.yaml create mode 100644 tests/features/configs/tags-237.yaml create mode 100644 tests/features/configs/tags.yaml create mode 100644 tests/features/configs/unreadabledates.yaml create mode 100644 tests/features/configs/upgrade_from_195.json create mode 100644 tests/features/configs/upgrade_from_195_little_endian_dates.json create mode 100644 tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json create mode 100644 tests/features/configs/upgrade_from_195_with_missing_journal.json create mode 100644 tests/features/core.feature create mode 100644 tests/features/data/configs/basic_dayone.yaml create mode 100644 tests/features/data/configs/basic_encrypted.yaml create mode 100644 tests/features/data/configs/basic_folder.yaml create mode 100644 tests/features/data/configs/basic_onefile.yaml create mode 100644 tests/features/data/configs/brackets.yaml create mode 100644 tests/features/data/configs/bug153.yaml create mode 100644 tests/features/data/configs/bug343.yaml create mode 100644 tests/features/data/configs/bug780.yaml create mode 100644 tests/features/data/configs/dayone.yaml create mode 100644 tests/features/data/configs/dayone_empty.yaml create mode 100644 tests/features/data/configs/deletion.yaml create mode 100644 tests/features/data/configs/deletion_filters.yaml create mode 100644 tests/features/data/configs/editor-args.yaml create mode 100644 tests/features/data/configs/editor.yaml create mode 100644 tests/features/data/configs/editor_empty_folder.yaml create mode 100644 tests/features/data/configs/editor_encrypted.yaml create mode 100644 tests/features/data/configs/empty_folder.yaml create mode 100644 tests/features/data/configs/encrypted.yaml create mode 100644 tests/features/data/configs/encrypted_old.json create mode 100644 tests/features/data/configs/encrypted_old.yaml create mode 100644 tests/features/data/configs/format_md.yaml create mode 100644 tests/features/data/configs/format_text.yaml create mode 100644 tests/features/data/configs/invalid_color.yaml create mode 100644 tests/features/data/configs/little_endian_dates.yaml create mode 100644 tests/features/data/configs/markdown-headings-335.yaml create mode 100644 tests/features/data/configs/missing_directory.yaml create mode 100644 tests/features/data/configs/missing_journal.yaml create mode 100644 tests/features/data/configs/mostlyreadabledates.yaml create mode 100644 tests/features/data/configs/multiline-tags.yaml create mode 100644 tests/features/data/configs/multiline.yaml create mode 100644 tests/features/data/configs/multiple.yaml create mode 100644 tests/features/data/configs/no_colors.yaml create mode 100644 tests/features/data/configs/simple.yaml create mode 100644 tests/features/data/configs/tags-216.yaml create mode 100644 tests/features/data/configs/tags-237.yaml create mode 100644 tests/features/data/configs/tags.yaml create mode 100644 tests/features/data/configs/unreadabledates.yaml create mode 100644 tests/features/data/configs/upgrade_from_195.json create mode 100644 tests/features/data/configs/upgrade_from_195_little_endian_dates.json create mode 100644 tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json create mode 100644 tests/features/data/configs/upgrade_from_195_with_missing_journal.json create mode 100644 tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry create mode 100644 tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry create mode 100644 tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry create mode 100644 tests/features/data/journals/basic_encrypted.journal create mode 100644 tests/features/data/journals/basic_folder/2020/08/29.txt create mode 100644 tests/features/data/journals/basic_folder/2020/08/31.txt create mode 100644 tests/features/data/journals/basic_folder/2020/09/24.txt create mode 100644 tests/features/data/journals/basic_onefile.journal create mode 100644 tests/features/data/journals/brackets.journal create mode 100644 tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry create mode 100644 tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry create mode 100644 tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry create mode 100644 tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry create mode 100644 tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry create mode 100644 tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry create mode 100644 tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry create mode 100644 tests/features/data/journals/dayone_empty.dayone/entries/empty.txt create mode 100644 tests/features/data/journals/deletion.journal create mode 100644 tests/features/data/journals/deletion_filters.journal create mode 100644 tests/features/data/journals/empty_folder/empty create mode 100644 tests/features/data/journals/encrypted.journal create mode 100644 tests/features/data/journals/encrypted_jrnl-1-9-5.journal create mode 100644 tests/features/data/journals/little_endian_dates.journal create mode 100644 tests/features/data/journals/markdown-headings-335.journal create mode 100644 tests/features/data/journals/mostlyreadabledates.journal create mode 100644 tests/features/data/journals/multiline-tags.journal create mode 100644 tests/features/data/journals/multiline.journal create mode 100644 tests/features/data/journals/simple.journal create mode 100644 tests/features/data/journals/simple_jrnl-1-9-5.journal create mode 100644 tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal create mode 100644 tests/features/data/journals/tags-216.journal create mode 100644 tests/features/data/journals/tags-237.journal create mode 100644 tests/features/data/journals/tags.journal create mode 100644 tests/features/data/journals/unreadabledates.journal create mode 100644 tests/features/data/journals/work.journal create mode 100644 tests/features/data/templates/sample.template create mode 100644 tests/features/datetime.feature create mode 100644 tests/features/delete.feature create mode 100644 tests/features/encrypt.feature create mode 100644 tests/features/environment.py create mode 100644 tests/features/file_storage.feature create mode 100644 tests/features/format.feature create mode 100644 tests/features/import.feature create mode 100644 tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry create mode 100644 tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry create mode 100644 tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry create mode 100644 tests/features/journals/basic_encrypted.journal create mode 100644 tests/features/journals/basic_folder/2020/08/29.txt create mode 100644 tests/features/journals/basic_folder/2020/08/31.txt create mode 100644 tests/features/journals/basic_folder/2020/09/24.txt create mode 100644 tests/features/journals/basic_onefile.journal create mode 100644 tests/features/journals/brackets.journal create mode 100644 tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry create mode 100644 tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry create mode 100644 tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry create mode 100644 tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry create mode 100644 tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry create mode 100644 tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry create mode 100644 tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry create mode 100644 tests/features/journals/dayone_empty.dayone/entries/empty.txt create mode 100644 tests/features/journals/deletion.journal create mode 100644 tests/features/journals/deletion_filters.journal create mode 100644 tests/features/journals/empty_folder/empty create mode 100644 tests/features/journals/encrypted.journal create mode 100644 tests/features/journals/encrypted_jrnl-1-9-5.journal create mode 100644 tests/features/journals/little_endian_dates.journal create mode 100644 tests/features/journals/markdown-headings-335.journal create mode 100644 tests/features/journals/mostlyreadabledates.journal create mode 100644 tests/features/journals/multiline-tags.journal create mode 100644 tests/features/journals/multiline.journal create mode 100644 tests/features/journals/simple.journal create mode 100644 tests/features/journals/simple_jrnl-1-9-5.journal create mode 100644 tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal create mode 100644 tests/features/journals/tags-216.journal create mode 100644 tests/features/journals/tags-237.journal create mode 100644 tests/features/journals/tags.journal create mode 100644 tests/features/journals/unreadabledates.journal create mode 100644 tests/features/journals/work.journal create mode 100644 tests/features/multiple_journals.feature create mode 100644 tests/features/password.feature create mode 100644 tests/features/search.feature create mode 100644 tests/features/star.feature create mode 100644 tests/features/tag.feature create mode 100644 tests/features/templates/extension.md create mode 100644 tests/features/upgrade.feature create mode 100644 tests/features/write.feature create mode 100644 tests/step_defs/__init__.py create mode 100644 tests/step_defs/conftest.py create mode 100644 tests/step_defs/test_features.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000..46468510 --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +import sys + +sys.path.append("..") diff --git a/poetry.lock b/poetry.lock index 238b977c..e999d3af 100644 --- a/poetry.lock +++ b/poetry.lock @@ -19,14 +19,14 @@ python-versions = "*" [[package]] name = "argcomplete" -version = "1.12.2" +version = "1.12.3" description = "Bash tab completion for argparse" category = "dev" optional = false python-versions = "*" [package.dependencies] -importlib-metadata = {version = ">=0.23,<4", markers = "python_version == \"3.7\""} +importlib-metadata = {version = ">=0.23,<5", markers = "python_version == \"3.7\""} [package.extras] test = ["coverage", "flake8", "pexpect", "wheel"] @@ -49,17 +49,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "20.3.0" +version = "21.2.0" description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] name = "behave" @@ -80,7 +80,7 @@ docs = ["sphinx (>=1.6)", "sphinx-bootstrap-theme (>=0.6)"] [[package]] name = "black" -version = "21.5b2" +version = "21.6b0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -104,7 +104,7 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "cffi" -version = "1.14.4" +version = "1.14.5" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -115,11 +115,15 @@ pycparser = "*" [[package]] name = "click" -version = "7.1.2" +version = "8.0.1" description = "Composable command line interface toolkit" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" @@ -149,16 +153,30 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] -name = "future" -version = "0.18.2" -description = "Clean single-source support for Python 3 and 2" +name = "ghp-import" +version = "2.0.1" +description = "Copy your docs directly to the gh-pages branch." category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "*" + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["twine", "markdown", "flake8"] + +[[package]] +name = "glob2" +version = "0.7" +description = "Version of the glob module that can capture patterns and supports recursive wildcards" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "importlib-metadata" -version = "3.7.2" +version = "4.5.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -170,7 +188,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -193,25 +211,17 @@ test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio"] [[package]] name = "jinja2" -version = "2.11.2" +version = "3.0.1" description = "A very fast and expressive template engine." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [package.dependencies] -MarkupSafe = ">=0.23" +MarkupSafe = ">=2.0" [package.extras] -i18n = ["Babel (>=0.8)"] - -[[package]] -name = "joblib" -version = "0.17.0" -description = "Lightweight pipelining: using Python functions as pipeline jobs." -category = "dev" -optional = false -python-versions = ">=3.6" +i18n = ["Babel (>=2.7)"] [[package]] name = "keyring" @@ -232,36 +242,23 @@ docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] -name = "livereload" -version = "2.6.3" -description = "Python LiveReload is an awesome tool for web developers" +name = "mako" +version = "1.1.4" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "dev" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] -six = "*" -tornado = {version = "*", markers = "python_version > \"2.7\""} - -[[package]] -name = "lunr" -version = "0.5.8" -description = "A Python implementation of Lunr.js" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -future = ">=0.16.0" -nltk = {version = ">=3.2.5", optional = true, markers = "python_version > \"2.7\" and extra == \"languages\""} -six = ">=1.11.0" +MarkupSafe = ">=0.9.2" [package.extras] -languages = ["nltk (>=3.2.5,<3.5)", "nltk (>=3.2.5)"] +babel = ["babel"] +lingua = ["lingua"] [[package]] name = "markdown" -version = "3.3.3" +version = "3.3.4" description = "Python implementation of Markdown." category = "dev" optional = false @@ -275,28 +272,42 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "1.1.1" +version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = ">=3.6" + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +category = "dev" +optional = false +python-versions = ">=3.6" [[package]] name = "mkdocs" -version = "1.1.2" +version = "1.2.1" description = "Project documentation with Markdown." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] click = ">=3.3" +ghp-import = ">=1.0" +importlib-metadata = ">=3.10" Jinja2 = ">=2.10.1" -livereload = ">=2.5.1" -lunr = {version = "0.5.8", extras = ["languages"]} Markdown = ">=3.2.1" +mergedeep = ">=1.3.4" +packaging = ">=20.5" PyYAML = ">=3.10" -tornado = ">=5.0" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] [[package]] name = "mypy-extensions" @@ -306,31 +317,9 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "nltk" -version = "3.5" -description = "Natural Language Toolkit" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -click = "*" -joblib = "*" -regex = "*" -tqdm = "*" - -[package.extras] -all = ["requests", "numpy", "python-crfsuite", "scikit-learn", "twython", "pyparsing", "scipy", "matplotlib", "gensim"] -corenlp = ["requests"] -machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"] -plot = ["matplotlib"] -tgrep = ["pyparsing"] -twitter = ["twython"] - [[package]] name = "packaging" -version = "20.8" +version = "20.9" description = "Core utilities for Python packages" category = "dev" optional = false @@ -341,7 +330,7 @@ pyparsing = ">=2.0.2" [[package]] name = "parse" -version = "1.18.0" +version = "1.19.0" description = "parse() is the opposite of format()" category = "dev" optional = false @@ -447,6 +436,23 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "pytest-bdd" +version = "4.0.2" +description = "BDD for pytest" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +glob2 = "*" +Mako = "*" +parse = "*" +parse-type = "*" +py = "*" +pytest = ">=4.3" +six = ">=1.9.0" + [[package]] name = "python-dateutil" version = "2.8.1" @@ -490,9 +496,20 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyyaml = "*" + [[package]] name = "regex" -version = "2020.11.13" +version = "2021.4.4" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -500,7 +517,7 @@ python-versions = "*" [[package]] name = "secretstorage" -version = "3.3.0" +version = "3.3.1" description = "Python bindings to FreeDesktop.org Secret Service API" category = "main" optional = false @@ -512,7 +529,7 @@ jeepney = ">=0.6" [[package]] name = "six" -version = "1.15.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" category = "main" optional = false @@ -534,25 +551,6 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -[[package]] -name = "tornado" -version = "6.1" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "dev" -optional = false -python-versions = ">= 3.5" - -[[package]] -name = "tqdm" -version = "4.54.1" -description = "Fast, Extensible Progress Meter" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" - -[package.extras] -dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown", "wheel"] - [[package]] name = "typed-ast" version = "1.4.3" @@ -563,7 +561,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.7.4.3" +version = "3.10.0.0" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -580,6 +578,17 @@ python-versions = "*" [package.dependencies] pytz = "*" +[[package]] +name = "watchdog" +version = "2.1.2" +description = "Filesystem events monitoring" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] + [[package]] name = "xmltodict" version = "0.12.0" @@ -590,7 +599,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "yq" -version = "2.12.0" +version = "2.12.2" description = "Command-line YAML/XML processor - jq wrapper for YAML/XML documents" category = "dev" optional = false @@ -607,20 +616,20 @@ test = ["coverage", "flake8", "wheel"] [[package]] name = "zipp" -version = "3.4.0" +version = "3.4.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = ">=3.7.0, <3.10" -content-hash = "4d9054a240b279da990b8038623d8b2025487ef37162f7f7ef4a4ff8cbae872b" +content-hash = "4bb72b50e012bd9b58e47835e1fd5d767ce68ac869505f77bb6ad9d564dbf139" [metadata.files] ansiwrap = [ @@ -632,8 +641,8 @@ appdirs = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] argcomplete = [ - {file = "argcomplete-1.12.2-py2.py3-none-any.whl", hash = "sha256:17f01a9b9b9ece3e6b07058eae737ad6e10de8b4e149105f84614783913aba71"}, - {file = "argcomplete-1.12.2.tar.gz", hash = "sha256:de0e1282330940d52ea92a80fea2e4b9e0da1932aaa570f84d268939d1897b04"}, + {file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"}, + {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, ] asteval = [ {file = "asteval-0.9.23.tar.gz", hash = "sha256:f5096a924b1d2f147e70327245d95fc8f534dbe94277b6828ce2a8c049d3a438"}, @@ -643,59 +652,59 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, - {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] behave = [ {file = "behave-1.2.6-py2.py3-none-any.whl", hash = "sha256:ebda1a6c9e5bfe95c5f9f0a2794e01c7098b3dde86c10a95d8621c5907ff6f1c"}, {file = "behave-1.2.6.tar.gz", hash = "sha256:b9662327aa53294c1351b0a9c369093ccec1d21026f050c3bd9b3e5cccf81a86"}, ] black = [ - {file = "black-21.5b2-py3-none-any.whl", hash = "sha256:e5cf21ebdffc7a9b29d73912b6a6a9a4df4ce70220d523c21647da2eae0751ef"}, - {file = "black-21.5b2.tar.gz", hash = "sha256:1fc0e0a2c8ae7d269dfcf0c60a89afa299664f3e811395d40b1922dff8f854b5"}, + {file = "black-21.6b0-py3-none-any.whl", hash = "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"}, + {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"}, ] cffi = [ - {file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"}, - {file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"}, - {file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"}, - {file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"}, - {file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"}, - {file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"}, - {file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"}, - {file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"}, - {file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"}, - {file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"}, - {file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"}, - {file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"}, - {file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"}, - {file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"}, - {file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"}, - {file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e"}, - {file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"}, - {file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"}, - {file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"}, + {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, + {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, + {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, + {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, + {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, + {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, + {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, + {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, + {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, + {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, + {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, + {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, + {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, + {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, + {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, + {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, + {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, + {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, + {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, ] click = [ - {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, - {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, @@ -715,12 +724,15 @@ cryptography = [ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"}, {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, ] -future = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +ghp-import = [ + {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, +] +glob2 = [ + {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.7.2-py3-none-any.whl", hash = "sha256:407d13f55dc6f2a844e62325d18ad7019a436c4bfcaee34cda35f2be6e7c3e34"}, - {file = "importlib_metadata-3.7.2.tar.gz", hash = "sha256:18d5ff601069f98d5d605b6a4b50c18a34811d655c55548adc833e687289acde"}, + {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, + {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -731,99 +743,74 @@ jeepney = [ {file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"}, ] jinja2 = [ - {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, - {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, -] -joblib = [ - {file = "joblib-0.17.0-py3-none-any.whl", hash = "sha256:698c311779f347cf6b7e6b8a39bb682277b8ee4aba8cf9507bc0cf4cd4737b72"}, - {file = "joblib-0.17.0.tar.gz", hash = "sha256:9e284edd6be6b71883a63c9b7f124738a3c16195513ad940eae7e3438de885d5"}, + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, ] keyring = [ {file = "keyring-23.0.1-py3-none-any.whl", hash = "sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48"}, {file = "keyring-23.0.1.tar.gz", hash = "sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8"}, ] -livereload = [ - {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, -] -lunr = [ - {file = "lunr-0.5.8-py2.py3-none-any.whl", hash = "sha256:aab3f489c4d4fab4c1294a257a30fec397db56f0a50273218ccc3efdbf01d6ca"}, - {file = "lunr-0.5.8.tar.gz", hash = "sha256:c4fb063b98eff775dd638b3df380008ae85e6cb1d1a24d1cd81a10ef6391c26e"}, +mako = [ + {file = "Mako-1.1.4.tar.gz", hash = "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab"}, ] markdown = [ - {file = "Markdown-3.3.3-py3-none-any.whl", hash = "sha256:c109c15b7dc20a9ac454c9e6025927d44460b85bd039da028d85e2b6d0bcc328"}, - {file = "Markdown-3.3.3.tar.gz", hash = "sha256:5d9f2b5ca24bc4c7a390d22323ca4bad200368612b5aaa7796babf971d2b2f18"}, + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, ] markupsafe = [ - {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, - {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +mergedeep = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, ] mkdocs = [ - {file = "mkdocs-1.1.2-py3-none-any.whl", hash = "sha256:096f52ff52c02c7e90332d2e53da862fde5c062086e1b5356a6e392d5d60f5e9"}, - {file = "mkdocs-1.1.2.tar.gz", hash = "sha256:f0b61e5402b99d7789efa032c7a74c90a20220a9c81749da06dbfbcbd52ffb39"}, + {file = "mkdocs-1.2.1-py3-none-any.whl", hash = "sha256:11141126e5896dd9d279b3e4814eb488e409a0990fb638856255020406a8e2e7"}, + {file = "mkdocs-1.2.1.tar.gz", hash = "sha256:6e0ea175366e3a50d334597b0bc042b8cebd512398cdd3f6f34842d0ef524905"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] -nltk = [ - {file = "nltk-3.5.zip", hash = "sha256:845365449cd8c5f9731f7cb9f8bd6fd0767553b9d53af9eb1b3abf7700936b35"}, -] packaging = [ - {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, - {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] parse = [ - {file = "parse-1.18.0.tar.gz", hash = "sha256:91666032d6723dc5905248417ef0dc9e4c51df9526aaeef271eacad6491f06a4"}, + {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, ] parse-type = [ {file = "parse_type-0.5.2-py2.py3-none-any.whl", hash = "sha256:089a471b06327103865dfec2dd844230c3c658a4a1b5b4c8b6c16c8f77577f9e"}, @@ -861,6 +848,10 @@ pytest = [ {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, ] +pytest-bdd = [ + {file = "pytest-bdd-4.0.2.tar.gz", hash = "sha256:982489f2f036c7561affe4eeb5b392a37e1ace2a9f260cad747b1c8119e63cfd"}, + {file = "pytest_bdd-4.0.2-py2.py3-none-any.whl", hash = "sha256:74ea5a147ea558c99ae83d838e6acbe5c9e6843884a958f8231615d96838733d"}, +] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, @@ -884,80 +875,76 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] +pyyaml-env-tag = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] regex = [ - {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, - {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, - {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, - {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, - {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, - {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, - {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, - {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, - {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, - {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, - {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, - {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, - {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, + {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"}, + {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"}, + {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"}, + {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"}, + {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"}, + {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"}, + {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"}, + {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"}, + {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"}, + {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"}, + {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"}, + {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"}, + {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"}, ] secretstorage = [ - {file = "SecretStorage-3.3.0-py3-none-any.whl", hash = "sha256:5c36f6537a523ec5f969ef9fad61c98eb9e017bc601d811e53aa25bece64892f"}, - {file = "SecretStorage-3.3.0.tar.gz", hash = "sha256:30cfdef28829dad64d6ea1ed08f8eff6aa115a77068926bcc9f5225d5a3246aa"}, + {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, + {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] textwrap3 = [ {file = "textwrap3-0.9.2-py2.py3-none-any.whl", hash = "sha256:bf5f4c40faf2a9ff00a9e0791fed5da7415481054cef45bb4a3cfb1f69044ae0"}, @@ -967,53 +954,6 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -tornado = [ - {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"}, - {file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"}, - {file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"}, - {file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"}, - {file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"}, - {file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"}, - {file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"}, - {file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"}, - {file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"}, - {file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"}, - {file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"}, - {file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"}, - {file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"}, - {file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"}, - {file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"}, - {file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"}, - {file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"}, - {file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"}, - {file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"}, - {file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"}, - {file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"}, - {file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"}, - {file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"}, - {file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"}, - {file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"}, - {file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"}, - {file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"}, - {file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"}, - {file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"}, - {file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"}, - {file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"}, - {file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"}, - {file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"}, - {file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"}, - {file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"}, - {file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"}, - {file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"}, - {file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"}, - {file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"}, - {file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"}, - {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"}, -] -tqdm = [ - {file = "tqdm-4.54.1-py2.py3-none-any.whl", hash = "sha256:d4f413aecb61c9779888c64ddf0c62910ad56dcbe857d8922bb505d4dbff0df1"}, - {file = "tqdm-4.54.1.tar.gz", hash = "sha256:38b658a3e4ecf9b4f6f8ff75ca16221ae3378b2e175d846b6b33ea3a20852cf5"}, -] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, @@ -1047,23 +987,42 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, - {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, - {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] tzlocal = [ {file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"}, {file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"}, ] +watchdog = [ + {file = "watchdog-2.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:581e3548159fe7d2a9f377a1fbcb41bdcee46849cca8ab803c7ac2e5e04ec77c"}, + {file = "watchdog-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:edcd9ef3fd460bb8a98eb1fcf99941e9fd9f275f45f1a82cb1359ec92975d647"}, + {file = "watchdog-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d34ce2261f118ecd57eedeef95fc2a495fc4a40b3ed7b3bf0bd7a8ccc1ab4f8f"}, + {file = "watchdog-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668391e6c32742d76e5be5db6bf95c455fa4b3d11e76a77c13b39bccb3a47a72"}, + {file = "watchdog-2.1.2-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6ef9fe57162c4c361692620e1d9167574ba1975ee468b24051ca11c9bba6438e"}, + {file = "watchdog-2.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:58ebb1095ee493008a7789d47dd62e4999505d82be89fc884d473086fccc6ebd"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:91387ee2421f30b75f7ff632c9d48f76648e56bf346a7c805c0a34187a93aab4"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:a6471517315a8541a943c00b45f1d252e36898a3ae963d2d52509b89a50cb2b9"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_i686.whl", hash = "sha256:a42e6d652f820b2b94cd03156c62559a2ea68d476476dfcd77d931e7f1012d4a"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:3d6405681471ebe0beb3aa083998c4870e48b57f8afdb45ea1b5957cc5cf1014"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:598d772beeaf9c98d0df946fbabf0c8365dd95ea46a250c224c725fe0c4730bc"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:4b219d46d89cfa49af1d73175487c14a318a74cb8c5442603fd13c6a5b418c86"}, + {file = "watchdog-2.1.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:188145185c08c73c56f1478ccf1f0f0f85101191439679b35b6b100886ce0b39"}, + {file = "watchdog-2.1.2-py3-none-win32.whl", hash = "sha256:255a32d44bbbe62e52874ff755e2eefe271b150e0ec240ad7718a62a7a7a73c4"}, + {file = "watchdog-2.1.2-py3-none-win_amd64.whl", hash = "sha256:1a62a4671796dc93d1a7262286217d9e75823c63d4c42782912d39a506d30046"}, + {file = "watchdog-2.1.2-py3-none-win_ia64.whl", hash = "sha256:104266a778906ae0e971368d368a65c4cd032a490a9fca5ba0b78c6c7ae11720"}, + {file = "watchdog-2.1.2.tar.gz", hash = "sha256:0237db4d9024859bea27d0efb59fe75eef290833fd988b8ead7a879b0308c2db"}, +] xmltodict = [ {file = "xmltodict-0.12.0-py2.py3-none-any.whl", hash = "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051"}, {file = "xmltodict-0.12.0.tar.gz", hash = "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21"}, ] yq = [ - {file = "yq-2.12.0-py2.py3-none-any.whl", hash = "sha256:1f124f48dee77ad5e0be8607777fed183e96c8d31fa577de14201c7a614e4819"}, - {file = "yq-2.12.0.tar.gz", hash = "sha256:1d2ad403504d306b5258b86c698f9856d7ad58b7bb17a2b875691a6a7b8c4c20"}, + {file = "yq-2.12.2-py2.py3-none-any.whl", hash = "sha256:9fdf4487a6dbf985ca1d357ec93f926d982813e8e896e8892bae95162b6defe3"}, + {file = "yq-2.12.2.tar.gz", hash = "sha256:2f156d0724b61487ac8752ed4eaa702a5737b804d5afa46fa55866951cd106d2"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] diff --git a/pyproject.toml b/pyproject.toml index 8a46fe34..b8c4731e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ black = {version = "^21.5b2",allow-prereleases = true} toml = ">=0.10" pyflakes = ">=2.2.0" pytest = ">=6.2" +pytest-bdd = "^4.0.1" yq = ">=2.11" [tool.poetry.scripts] @@ -62,6 +63,9 @@ line_length = 88 known_first_party = ["jrnl"] force_sort_within_sections = true +[tool.pytest.ini_options] +minversion = "6.0" + [build-system] requires = ["poetry>=1.1"] build-backend = "poetry.masonry.api" diff --git a/tests/features/build.feature b/tests/features/build.feature new file mode 100644 index 00000000..4725ea85 --- /dev/null +++ b/tests/features/build.feature @@ -0,0 +1,8 @@ +Feature: Build process + + @deployment_tests + Scenario: Version numbers should stay in sync + Given we use the config "simple.yaml" + When we run "jrnl --version" + Then we should get no error + And the output should contain pyproject.toml version diff --git a/tests/features/configs/basic_dayone.yaml b/tests/features/configs/basic_dayone.yaml new file mode 100644 index 00000000..0209f2f7 --- /dev/null +++ b/tests/features/configs/basic_dayone.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_dayone.dayone +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/basic_encrypted.yaml b/tests/features/configs/basic_encrypted.yaml new file mode 100644 index 00000000..77f4e48d --- /dev/null +++ b/tests/features/configs/basic_encrypted.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: true +highlight: true +journals: + default: features/journals/basic_encrypted.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/basic_folder.yaml b/tests/features/configs/basic_folder.yaml new file mode 100644 index 00000000..ba0de638 --- /dev/null +++ b/tests/features/configs/basic_folder.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_folder +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/basic_onefile.yaml b/tests/features/configs/basic_onefile.yaml new file mode 100644 index 00000000..fb48c6f8 --- /dev/null +++ b/tests/features/configs/basic_onefile.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_onefile.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/brackets.yaml b/tests/features/configs/brackets.yaml new file mode 100644 index 00000000..e658947c --- /dev/null +++ b/tests/features/configs/brackets.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/brackets.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/bug153.yaml b/tests/features/configs/bug153.yaml new file mode 100644 index 00000000..ff645ab6 --- /dev/null +++ b/tests/features/configs/bug153.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +journals: + default: features/journals/bug153.dayone +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/bug343.yaml b/tests/features/configs/bug343.yaml new file mode 100644 index 00000000..a4e25d8a --- /dev/null +++ b/tests/features/configs/bug343.yaml @@ -0,0 +1,13 @@ +default_hour: 9 +default_minute: 0 +editor: '' +template: false +encrypt: false +highlight: true +journals: + simple: features/journals/simple.journal + work: features/journals/work.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/bug780.yaml b/tests/features/configs/bug780.yaml new file mode 100644 index 00000000..e1d830c2 --- /dev/null +++ b/tests/features/configs/bug780.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +journals: + default: features/journals/bug780.dayone +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/dayone.yaml b/tests/features/configs/dayone.yaml new file mode 100644 index 00000000..894cb911 --- /dev/null +++ b/tests/features/configs/dayone.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: noop +template: false +encrypt: false +highlight: true +journals: + default: features/journals/dayone.dayone +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/dayone_empty.yaml b/tests/features/configs/dayone_empty.yaml new file mode 100644 index 00000000..7750d389 --- /dev/null +++ b/tests/features/configs/dayone_empty.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: noop +template: false +encrypt: false +highlight: true +journals: + default: features/journals/dayone_empty.dayone +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/deletion.yaml b/tests/features/configs/deletion.yaml new file mode 100644 index 00000000..d4155260 --- /dev/null +++ b/tests/features/configs/deletion.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/deletion.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/deletion_filters.yaml b/tests/features/configs/deletion_filters.yaml new file mode 100644 index 00000000..73a88e4d --- /dev/null +++ b/tests/features/configs/deletion_filters.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/deletion_filters.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/editor-args.yaml b/tests/features/configs/editor-args.yaml new file mode 100644 index 00000000..12c5bd9c --- /dev/null +++ b/tests/features/configs/editor-args.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: vim -f -c 'setf markdown' +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/editor.yaml b/tests/features/configs/editor.yaml new file mode 100644 index 00000000..8a06f916 --- /dev/null +++ b/tests/features/configs/editor.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "vim" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/editor_empty_folder.yaml b/tests/features/configs/editor_empty_folder.yaml new file mode 100644 index 00000000..1724bbfb --- /dev/null +++ b/tests/features/configs/editor_empty_folder.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: 'vim' +template: false +encrypt: false +highlight: true +journals: + default: features/journals/empty_folder +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/editor_encrypted.yaml b/tests/features/configs/editor_encrypted.yaml new file mode 100644 index 00000000..75273c96 --- /dev/null +++ b/tests/features/configs/editor_encrypted.yaml @@ -0,0 +1,17 @@ +colors: + body: green + date: blue + tags: none + title: yellow +default_hour: 9 +default_minute: 0 +editor: "vim" +encrypt: true +template: false +highlight: true +journals: + default: features/journals/encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/editor_markdown_extension.yaml b/tests/features/configs/editor_markdown_extension.yaml new file mode 100644 index 00000000..bf3b8d8e --- /dev/null +++ b/tests/features/configs/editor_markdown_extension.yaml @@ -0,0 +1,18 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +editor: "vim" +journals: + default: features/journals/editor_markdown_extension.journal +linewrap: 80 +tagsymbols: "@" +template: features/templates/extension.md +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/empty_folder.yaml b/tests/features/configs/empty_folder.yaml new file mode 100644 index 00000000..52a21854 --- /dev/null +++ b/tests/features/configs/empty_folder.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +template: false +encrypt: false +highlight: true +journals: + default: features/journals/empty_folder +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/encrypted.yaml b/tests/features/configs/encrypted.yaml new file mode 100644 index 00000000..4d50b607 --- /dev/null +++ b/tests/features/configs/encrypted.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: true +template: false +highlight: true +journals: + default: features/journals/encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/encrypted_old.json b/tests/features/configs/encrypted_old.json new file mode 100644 index 00000000..e69d9b79 --- /dev/null +++ b/tests/features/configs/encrypted_old.json @@ -0,0 +1,13 @@ +{ + "default_hour": 9, + "default_minute": 0, + "editor": "", + "encrypt": true, + "highlight": true, + "journals": { + "default": "features/journals/encrypted_jrnl-1-9-5.journal" + }, + "linewrap": 80, + "tagsymbols": "@", + "timeformat": "%Y-%m-%d %H:%M" +} diff --git a/tests/features/configs/encrypted_old.yaml b/tests/features/configs/encrypted_old.yaml new file mode 100644 index 00000000..bc7b1440 --- /dev/null +++ b/tests/features/configs/encrypted_old.yaml @@ -0,0 +1,11 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: true +highlight: true +journals: + default: features/journals/encrypted_jrnl1-9-5.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/format_md.yaml b/tests/features/configs/format_md.yaml new file mode 100644 index 00000000..0b9f1c3b --- /dev/null +++ b/tests/features/configs/format_md.yaml @@ -0,0 +1,19 @@ +colors: + body: none + date: none + tags: none + title: none +default_hour: 9 +default_minute: 0 +display_format: markdown +editor: '' +encrypt: false +highlight: true +indent_character: '|' +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +version: v2.4.5 diff --git a/tests/features/configs/format_text.yaml b/tests/features/configs/format_text.yaml new file mode 100644 index 00000000..c82ff7a7 --- /dev/null +++ b/tests/features/configs/format_text.yaml @@ -0,0 +1,19 @@ +colors: + body: none + date: none + tags: none + title: none +default_hour: 9 +default_minute: 0 +display_format: text +editor: '' +encrypt: false +highlight: true +indent_character: '|' +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +version: v2.4.5 diff --git a/tests/features/configs/invalid_color.yaml b/tests/features/configs/invalid_color.yaml new file mode 100644 index 00000000..25c0e58d --- /dev/null +++ b/tests/features/configs/invalid_color.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: not-a-color + title: also-not-a-color + body: still-no-color + tags: me-too diff --git a/tests/features/configs/little_endian_dates.yaml b/tests/features/configs/little_endian_dates.yaml new file mode 100644 index 00000000..223c820d --- /dev/null +++ b/tests/features/configs/little_endian_dates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/little_endian_dates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%d.%m.%Y %H:%M" +indent_character: "|" diff --git a/tests/features/configs/markdown-headings-335.yaml b/tests/features/configs/markdown-headings-335.yaml new file mode 100644 index 00000000..4368f641 --- /dev/null +++ b/tests/features/configs/markdown-headings-335.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/markdown-headings-335.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/missing_directory.yaml b/tests/features/configs/missing_directory.yaml new file mode 100644 index 00000000..d600404c --- /dev/null +++ b/tests/features/configs/missing_directory.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/missing_directory/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/missing_journal.yaml b/tests/features/configs/missing_journal.yaml new file mode 100644 index 00000000..a1f6f8cf --- /dev/null +++ b/tests/features/configs/missing_journal.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/missing.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/mostlyreadabledates.yaml b/tests/features/configs/mostlyreadabledates.yaml new file mode 100644 index 00000000..5e3e1a15 --- /dev/null +++ b/tests/features/configs/mostlyreadabledates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/mostlyreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/multiline-tags.yaml b/tests/features/configs/multiline-tags.yaml new file mode 100644 index 00000000..033aaa27 --- /dev/null +++ b/tests/features/configs/multiline-tags.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/multiline-tags.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/multiline.yaml b/tests/features/configs/multiline.yaml new file mode 100644 index 00000000..aa35b3f5 --- /dev/null +++ b/tests/features/configs/multiline.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/multiline.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/multiple.yaml b/tests/features/configs/multiple.yaml new file mode 100644 index 00000000..65f2c256 --- /dev/null +++ b/tests/features/configs/multiple.yaml @@ -0,0 +1,18 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/simple.journal + ideas: features/journals/nothing.journal + simple: features/journals/simple.journal + work: features/journals/work.journal + new_encrypted: + encrypt: true + journal: features/journals/new_encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/configs/no_colors.yaml b/tests/features/configs/no_colors.yaml new file mode 100644 index 00000000..9111b561 --- /dev/null +++ b/tests/features/configs/no_colors.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/configs/simple.yaml b/tests/features/configs/simple.yaml new file mode 100644 index 00000000..f8739142 --- /dev/null +++ b/tests/features/configs/simple.yaml @@ -0,0 +1,18 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none +version: v2.5 \ No newline at end of file diff --git a/tests/features/configs/tags-216.yaml b/tests/features/configs/tags-216.yaml new file mode 100644 index 00000000..81b3865f --- /dev/null +++ b/tests/features/configs/tags-216.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags-216.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/tags-237.yaml b/tests/features/configs/tags-237.yaml new file mode 100644 index 00000000..5aecd61e --- /dev/null +++ b/tests/features/configs/tags-237.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags-237.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/tags.yaml b/tests/features/configs/tags.yaml new file mode 100644 index 00000000..4b55952c --- /dev/null +++ b/tests/features/configs/tags.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/unreadabledates.yaml b/tests/features/configs/unreadabledates.yaml new file mode 100644 index 00000000..99304e5a --- /dev/null +++ b/tests/features/configs/unreadabledates.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/unreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/configs/upgrade_from_195.json b/tests/features/configs/upgrade_from_195.json new file mode 100644 index 00000000..ec380372 --- /dev/null +++ b/tests/features/configs/upgrade_from_195.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/configs/upgrade_from_195_little_endian_dates.json b/tests/features/configs/upgrade_from_195_little_endian_dates.json new file mode 100644 index 00000000..7d3c470c --- /dev/null +++ b/tests/features/configs/upgrade_from_195_little_endian_dates.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%d.%m.%Y %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5_little_endian_dates.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json b/tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json new file mode 100644 index 00000000..5bbfb5b1 --- /dev/null +++ b/tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": true, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/encrypted_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/configs/upgrade_from_195_with_missing_journal.json b/tests/features/configs/upgrade_from_195_with_missing_journal.json new file mode 100644 index 00000000..8d456159 --- /dev/null +++ b/tests/features/configs/upgrade_from_195_with_missing_journal.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/core.feature b/tests/features/core.feature new file mode 100644 index 00000000..3115fd57 --- /dev/null +++ b/tests/features/core.feature @@ -0,0 +1,7 @@ +Feature: Functionality of jrnl outside of actually handling journals + + Scenario: Displaying the version number + Given we use the config "simple.yaml" + When we run "jrnl --version" + Then we should get no error + Then the output should match "^jrnl version v\d+\.\d+(\.\d+)?(-(alpha|beta)\d*)?" diff --git a/tests/features/data/configs/basic_dayone.yaml b/tests/features/data/configs/basic_dayone.yaml new file mode 100644 index 00000000..0209f2f7 --- /dev/null +++ b/tests/features/data/configs/basic_dayone.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_dayone.dayone +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/basic_encrypted.yaml b/tests/features/data/configs/basic_encrypted.yaml new file mode 100644 index 00000000..77f4e48d --- /dev/null +++ b/tests/features/data/configs/basic_encrypted.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: true +highlight: true +journals: + default: features/journals/basic_encrypted.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/basic_folder.yaml b/tests/features/data/configs/basic_folder.yaml new file mode 100644 index 00000000..ba0de638 --- /dev/null +++ b/tests/features/data/configs/basic_folder.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_folder +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/basic_onefile.yaml b/tests/features/data/configs/basic_onefile.yaml new file mode 100644 index 00000000..fb48c6f8 --- /dev/null +++ b/tests/features/data/configs/basic_onefile.yaml @@ -0,0 +1,17 @@ +colors: + date: none + title: none + body: none + tags: none +default_hour: 9 +default_minute: 0 +editor: noop +encrypt: false +highlight: true +journals: + default: features/journals/basic_onefile.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/brackets.yaml b/tests/features/data/configs/brackets.yaml new file mode 100644 index 00000000..e658947c --- /dev/null +++ b/tests/features/data/configs/brackets.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/brackets.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/bug153.yaml b/tests/features/data/configs/bug153.yaml new file mode 100644 index 00000000..ff645ab6 --- /dev/null +++ b/tests/features/data/configs/bug153.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +journals: + default: features/journals/bug153.dayone +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/bug343.yaml b/tests/features/data/configs/bug343.yaml new file mode 100644 index 00000000..a4e25d8a --- /dev/null +++ b/tests/features/data/configs/bug343.yaml @@ -0,0 +1,13 @@ +default_hour: 9 +default_minute: 0 +editor: '' +template: false +encrypt: false +highlight: true +journals: + simple: features/journals/simple.journal + work: features/journals/work.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/bug780.yaml b/tests/features/data/configs/bug780.yaml new file mode 100644 index 00000000..e1d830c2 --- /dev/null +++ b/tests/features/data/configs/bug780.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +journals: + default: features/journals/bug780.dayone +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/dayone.yaml b/tests/features/data/configs/dayone.yaml new file mode 100644 index 00000000..894cb911 --- /dev/null +++ b/tests/features/data/configs/dayone.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: noop +template: false +encrypt: false +highlight: true +journals: + default: features/journals/dayone.dayone +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/dayone_empty.yaml b/tests/features/data/configs/dayone_empty.yaml new file mode 100644 index 00000000..7750d389 --- /dev/null +++ b/tests/features/data/configs/dayone_empty.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: noop +template: false +encrypt: false +highlight: true +journals: + default: features/journals/dayone_empty.dayone +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/deletion.yaml b/tests/features/data/configs/deletion.yaml new file mode 100644 index 00000000..d4155260 --- /dev/null +++ b/tests/features/data/configs/deletion.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/deletion.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/deletion_filters.yaml b/tests/features/data/configs/deletion_filters.yaml new file mode 100644 index 00000000..73a88e4d --- /dev/null +++ b/tests/features/data/configs/deletion_filters.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/deletion_filters.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/editor-args.yaml b/tests/features/data/configs/editor-args.yaml new file mode 100644 index 00000000..12c5bd9c --- /dev/null +++ b/tests/features/data/configs/editor-args.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: vim -f -c 'setf markdown' +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/editor.yaml b/tests/features/data/configs/editor.yaml new file mode 100644 index 00000000..8a06f916 --- /dev/null +++ b/tests/features/data/configs/editor.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "vim" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/editor_empty_folder.yaml b/tests/features/data/configs/editor_empty_folder.yaml new file mode 100644 index 00000000..1724bbfb --- /dev/null +++ b/tests/features/data/configs/editor_empty_folder.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: 'vim' +template: false +encrypt: false +highlight: true +journals: + default: features/journals/empty_folder +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/editor_encrypted.yaml b/tests/features/data/configs/editor_encrypted.yaml new file mode 100644 index 00000000..75273c96 --- /dev/null +++ b/tests/features/data/configs/editor_encrypted.yaml @@ -0,0 +1,17 @@ +colors: + body: green + date: blue + tags: none + title: yellow +default_hour: 9 +default_minute: 0 +editor: "vim" +encrypt: true +template: false +highlight: true +journals: + default: features/journals/encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/empty_folder.yaml b/tests/features/data/configs/empty_folder.yaml new file mode 100644 index 00000000..52a21854 --- /dev/null +++ b/tests/features/data/configs/empty_folder.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +template: false +encrypt: false +highlight: true +journals: + default: features/journals/empty_folder +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/encrypted.yaml b/tests/features/data/configs/encrypted.yaml new file mode 100644 index 00000000..4d50b607 --- /dev/null +++ b/tests/features/data/configs/encrypted.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: true +template: false +highlight: true +journals: + default: features/journals/encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/encrypted_old.json b/tests/features/data/configs/encrypted_old.json new file mode 100644 index 00000000..e69d9b79 --- /dev/null +++ b/tests/features/data/configs/encrypted_old.json @@ -0,0 +1,13 @@ +{ + "default_hour": 9, + "default_minute": 0, + "editor": "", + "encrypt": true, + "highlight": true, + "journals": { + "default": "features/journals/encrypted_jrnl-1-9-5.journal" + }, + "linewrap": 80, + "tagsymbols": "@", + "timeformat": "%Y-%m-%d %H:%M" +} diff --git a/tests/features/data/configs/encrypted_old.yaml b/tests/features/data/configs/encrypted_old.yaml new file mode 100644 index 00000000..bc7b1440 --- /dev/null +++ b/tests/features/data/configs/encrypted_old.yaml @@ -0,0 +1,11 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: true +highlight: true +journals: + default: features/journals/encrypted_jrnl1-9-5.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/format_md.yaml b/tests/features/data/configs/format_md.yaml new file mode 100644 index 00000000..0b9f1c3b --- /dev/null +++ b/tests/features/data/configs/format_md.yaml @@ -0,0 +1,19 @@ +colors: + body: none + date: none + tags: none + title: none +default_hour: 9 +default_minute: 0 +display_format: markdown +editor: '' +encrypt: false +highlight: true +indent_character: '|' +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +version: v2.4.5 diff --git a/tests/features/data/configs/format_text.yaml b/tests/features/data/configs/format_text.yaml new file mode 100644 index 00000000..c82ff7a7 --- /dev/null +++ b/tests/features/data/configs/format_text.yaml @@ -0,0 +1,19 @@ +colors: + body: none + date: none + tags: none + title: none +default_hour: 9 +default_minute: 0 +display_format: text +editor: '' +encrypt: false +highlight: true +indent_character: '|' +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: '@' +template: false +timeformat: '%Y-%m-%d %H:%M' +version: v2.4.5 diff --git a/tests/features/data/configs/invalid_color.yaml b/tests/features/data/configs/invalid_color.yaml new file mode 100644 index 00000000..25c0e58d --- /dev/null +++ b/tests/features/data/configs/invalid_color.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: not-a-color + title: also-not-a-color + body: still-no-color + tags: me-too diff --git a/tests/features/data/configs/little_endian_dates.yaml b/tests/features/data/configs/little_endian_dates.yaml new file mode 100644 index 00000000..223c820d --- /dev/null +++ b/tests/features/data/configs/little_endian_dates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/little_endian_dates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%d.%m.%Y %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/markdown-headings-335.yaml b/tests/features/data/configs/markdown-headings-335.yaml new file mode 100644 index 00000000..4368f641 --- /dev/null +++ b/tests/features/data/configs/markdown-headings-335.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/markdown-headings-335.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/missing_directory.yaml b/tests/features/data/configs/missing_directory.yaml new file mode 100644 index 00000000..d600404c --- /dev/null +++ b/tests/features/data/configs/missing_directory.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/missing_directory/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/missing_journal.yaml b/tests/features/data/configs/missing_journal.yaml new file mode 100644 index 00000000..a1f6f8cf --- /dev/null +++ b/tests/features/data/configs/missing_journal.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/missing.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/mostlyreadabledates.yaml b/tests/features/data/configs/mostlyreadabledates.yaml new file mode 100644 index 00000000..5e3e1a15 --- /dev/null +++ b/tests/features/data/configs/mostlyreadabledates.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/mostlyreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/multiline-tags.yaml b/tests/features/data/configs/multiline-tags.yaml new file mode 100644 index 00000000..033aaa27 --- /dev/null +++ b/tests/features/data/configs/multiline-tags.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/multiline-tags.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/multiline.yaml b/tests/features/data/configs/multiline.yaml new file mode 100644 index 00000000..aa35b3f5 --- /dev/null +++ b/tests/features/data/configs/multiline.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/multiline.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/multiple.yaml b/tests/features/data/configs/multiple.yaml new file mode 100644 index 00000000..65f2c256 --- /dev/null +++ b/tests/features/data/configs/multiple.yaml @@ -0,0 +1,18 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/simple.journal + ideas: features/journals/nothing.journal + simple: features/journals/simple.journal + work: features/journals/work.journal + new_encrypted: + encrypt: true + journal: features/journals/new_encrypted.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" diff --git a/tests/features/data/configs/no_colors.yaml b/tests/features/data/configs/no_colors.yaml new file mode 100644 index 00000000..9111b561 --- /dev/null +++ b/tests/features/data/configs/no_colors.yaml @@ -0,0 +1,12 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" diff --git a/tests/features/data/configs/simple.yaml b/tests/features/data/configs/simple.yaml new file mode 100644 index 00000000..020bab18 --- /dev/null +++ b/tests/features/data/configs/simple.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/simple.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/tags-216.yaml b/tests/features/data/configs/tags-216.yaml new file mode 100644 index 00000000..81b3865f --- /dev/null +++ b/tests/features/data/configs/tags-216.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags-216.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/tags-237.yaml b/tests/features/data/configs/tags-237.yaml new file mode 100644 index 00000000..5aecd61e --- /dev/null +++ b/tests/features/data/configs/tags-237.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags-237.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/tags.yaml b/tests/features/data/configs/tags.yaml new file mode 100644 index 00000000..4b55952c --- /dev/null +++ b/tests/features/data/configs/tags.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +journals: + default: features/journals/tags.journal +linewrap: 80 +tagsymbols: '@' +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/unreadabledates.yaml b/tests/features/data/configs/unreadabledates.yaml new file mode 100644 index 00000000..99304e5a --- /dev/null +++ b/tests/features/data/configs/unreadabledates.yaml @@ -0,0 +1,17 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +journals: + default: features/journals/unreadabledates.journal +linewrap: 80 +tagsymbols: "@" +template: false +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none diff --git a/tests/features/data/configs/upgrade_from_195.json b/tests/features/data/configs/upgrade_from_195.json new file mode 100644 index 00000000..ec380372 --- /dev/null +++ b/tests/features/data/configs/upgrade_from_195.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/data/configs/upgrade_from_195_little_endian_dates.json b/tests/features/data/configs/upgrade_from_195_little_endian_dates.json new file mode 100644 index 00000000..7d3c470c --- /dev/null +++ b/tests/features/data/configs/upgrade_from_195_little_endian_dates.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%d.%m.%Y %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5_little_endian_dates.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json b/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json new file mode 100644 index 00000000..5bbfb5b1 --- /dev/null +++ b/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": true, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/encrypted_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/data/configs/upgrade_from_195_with_missing_journal.json b/tests/features/data/configs/upgrade_from_195_with_missing_journal.json new file mode 100644 index 00000000..8d456159 --- /dev/null +++ b/tests/features/data/configs/upgrade_from_195_with_missing_journal.json @@ -0,0 +1,11 @@ +{ +"default_hour": 9, +"timeformat": "%Y-%m-%d %H:%M", +"linewrap": 80, +"encrypt": false, +"editor": "", +"default_minute": 0, +"highlight": true, +"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, +"tagsymbols": "@" +} diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry b/tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry new file mode 100644 index 00000000..9721dd55 --- /dev/null +++ b/tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry @@ -0,0 +1,53 @@ + + + + + Creation Date + 2020-08-29T18:11:00Z + Starred + + Entry Text + Entry the first. +Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. + Time Zone + America/Los_Angeles + UUID + D04D335AFED711EABA18FAFFC2100C3D + Tags + + ipsum + tagone + tagtwo + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:35:45Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry b/tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry new file mode 100644 index 00000000..8c2f3c52 --- /dev/null +++ b/tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry @@ -0,0 +1,55 @@ + + + + + Creation Date + 2020-08-31T21:32:00Z + Starred + + Entry Text + A second entry in what I hope to be a long series. +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. + Time Zone + America/Los_Angeles + UUID + FC8A86CAFED711EA8892FAFFC2100C3D + Tags + + tagtwo + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:36:59Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry b/tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry new file mode 100644 index 00000000..d998c36b --- /dev/null +++ b/tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry @@ -0,0 +1,44 @@ + + + + + Creation Date + 2020-09-24T16:14:00Z + Starred + + Entry Text + The third entry finally after weeks without writing. +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 + Time Zone + America/Los_Angeles + UUID + FD8ABC8EFED711EABC35FAFFC2100C3D + Tags + + tagthree + tagone + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:37:01Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/data/journals/basic_encrypted.journal b/tests/features/data/journals/basic_encrypted.journal new file mode 100644 index 00000000..ffc122df --- /dev/null +++ b/tests/features/data/journals/basic_encrypted.journal @@ -0,0 +1 @@ +gAAAAABfb4gQBMqqGn_W8v_s7qCi14bX7inuCOKbsBqIUf7_ch14vTUp7lrysPFvhBp5vGijTwDIbk4LKoIISj8NwM31I8L0zEbMx9y6iyF_zseGGNxBvNN0wzAXa67bs-ohiQhhebcdIc_52sltxL2ELh8JAKUaXRwyapgnMgJ7z6deJppLK-B7RE7BiT0eKjWTDMd2x6cZDswvHs9opDp5yjuKWV5m7x6ggCKYgHT3savT9Tg7V0Fq6K3LGWaE59lCrqlAB0u6dnrDX3qcF4SKyckaniXzRShZGebdkUKDcLFun2V2syZwYQN772xjznIsJ16iXicox2uYKg8CnTefsyCwaOZyBvySGEy3CrlBiuIRIcxCtjKbYJ2B-Aq7LZitnBR7Ny_6_Wm8HsBf3N-cFCp4GShiCKrxuXKcOZ7vszG5EKb78JS85bb0mswU5CSdgp6UAHjIZqfJq00qQsViBCbXq3oklCPZXdQkOf5U0KpG2MVUiD-Zcn5Qj3gnUhSEr-5wKU9tWrE63MGPyE6KjZlArZX2W2LeGnW2CEYw9eREGon06AzLJ4mj3BgtjVWLIdGcCwORXvHRjUqazWgbEmXNVTbtp_cKnkW-rFzRBrUoVme9v-1Y3sH0VvHBq7QIj915VzBklzWs1qzIyTPZG5Db9LvdQ7SiV8slf1Jo7l-ayUUdVj6igvKZcgfB4RUHolJoMps5p4lZ5sPqv59KtSa8DCpuoRczIj71OCpuRVARZgy1m5sUD9xSMxOBdy46u1Jnry6iMtzXWI3mEZe5m7UhmW_L4Zcv4bbk8XjkBeHjPdgm2B69jkLmCBFecD5ztoGesCGt_pNo_sWSKqLHV1-coKFB2Nn__a4utU9NJNdeNRkr8_ahU6tn3jmaFjfQ7cKfrXG_NCcYBRX9fja8EQIeBEp_3TCoXQqhuV_bGsNPA2qL63Pt6YiRaUf1g9FNBqJRlKCSOYNixSXQZN_rTePzx0SQ0aIQhADWls62WX-LG5-byJcB6W2P_cH21hDOXkoNEIyLnCz9HQ6Yd6Fbv7298ps3F6jiUDdWES23zv8sDgBuKUN94qSN34j6MDYGFnGI9zsJ-Y-I2frdlLfWPx3pUL7afcKh1nRgXdjctsTSxU2BDrsu03eBz2IoZjoOR0U51IrNMOD1NNT3kctXxHLuOHSEkwAzS3doncQbdRLi5Gc1dQuOUa4sC-p8gVjUKXO-oi_49kp9Km2Ay9wFg0epBbXx2QMzyMsN2dXeSbHF-BDXD6sULaq5syC0fOHqaMLycTCMk2wLfNyXgEt05WvAiDn-LDsRdylMRW2hXp5HWq3Poaul-7VNg6UEMlwVfgJ-7hNreuO6IRtwmx6YdqMscw0ms6mU_MQZU_dTIPg3JU4KL0YyMqPBPSGNCx3gMp41O05Ubir45FoJSnT5Dkj4v3N0S87Ys3HuFLverASsGt9bkcSzd2uMKCJjkspemPPi9VhrY4IOO03DWSWbHmxYzFc1SJ-24WM8Ch404QKpe1qy5LNzFgLvDwQhSIHjluezHXqrD-DVh1lWNNY3WmHI2ubOZfaorvLKqzBPZ6AhpIa60rKjm0OZIQOmJwWXwkdnzut6m8PtoiLzRN897YMgeztf1nmDwp0xE-EhknVZ3WV3TeqgZJ5ykfHQ5BU8x0Db57-UtKSuesKbqPPdBe91OdsPpkGlyl6psHj1_gPm4nLvzXQePwiPaEemR_gYCWGPvl9l1ANJufgCV9qQTmZGof3fb9mjv-9lS-9l_m8KirPPRpSBToNeDtk50ceYUsOlDGzIyusppG9pOcIGyiln1IO5aZ8d4_1E83qjcHTSaKGizICZU7a-pt5STBPMesy3JgBm23A2jO4m68ayBRMcLnw_RirHvvBaj0C6UR2tac45F0Ob3PpXcvFuK0g54ziIAhzGqwF9I-LZ6asXQWMW4y4EBOak8JJBorkfztzfkMaIgGu-4ZoRKOkVfdr4uzcghk3r6KUxD4-nv1ioX69-G5RwhMHppYk7z8RXS1cq5FkvzXbfEQ-Uv6M-sx32DcUy9dH-ZYhc7UWm75JJfiNXLaXT_bsc6VqQ7KPkg2-RA7CywUFCW9S0S-XdO03VdwqlUVo7fp1SKywEfhZv_9bhDCdMJBwZmigv2KP9Iz7fF6LrpLwZkzHuQGFPcyTHFpsVIFrFyJjNYCXpET9y0Q5Vt4fnea5fy-9ZiCt3S8aS0YOFJ35_kM5i3ss8eFPL0v7fIQS3ZilzdGB3bWL0J7kppHN_ekHu-wVk3UZxauoFh7hXLjPcipua-FYUIklLjcK6DG1bYP7_q6OnkC8Jl650FNezeWPomHEv7l_DO3y0tjI6SGdWvL3ZJns7Xp3ew8KsCREAUO7ffqumD03uF9N-9uWbDDjM7rk0vcg0ggfOs9Ni725mxqYpu4R285XCOVWHDvw7iU6eAvE6ry8TDXQBbNgGjTuTYFYYli7GuOqMxFIe1op2s7sRnoJE8O0J76S6APhjhjcnZRSuONWkVG_5o83uFMPSF8DtqLwuRA5E8AGfIwAUcj324sw-DA0ixBGUqomb-osUIisv3x0b044xn-FvD-8R3PZDnPbPsao8XYNxfQWStrNcZSrX2Ua-WAcv9qbQ73_57RKW4pao4ajOu7K5800D231WGiIa6aJzDnFUlzXEzYxFQyx7qegkm_9rrEp_v8TC9mfAcjWX5DMrCkxUskx9YKDfpFYq4NuxO_414gReKzd-lmorfigvttgS10N1XD74SwFluXJv-bqTbI5-SuYAhDGMv1dqrn38i3rOMQqqnQomvaUJRprqxUsKz14sSE1Y-cNqq1FXzZ6vIJq-K3YTfFWPRLeqi6gHzqS_R2YBXXUduKuYgmakiVdP3bWc-Ca8WKh5sVi6P51MO-cS7i9AZWOaOz7F8PsB4JZxAJjSOr3NBmv3EEve9auTFCudRjfC6668I_NMHaTP5CCV4cuhuAxUuKUGgd6WFjDcvoYPyn_lu3bQiqD9MEag4CaJYI9PlraRv5mbqptwxv3pca7usd0GmXN_2No_nwxB4gVb48LsBBkH35njCa5iv2EKXUSOf0k3swaTSEahqbyI4EDzPXtU5uBO39iQzNpgfV_sUpnGdysjqueUVcdWGI_s5CnrNJ-_yDAY06AoXfLrjP8_3NXB2058xZ2rfmTNJNCULz9634dICJReXNnmplxIg3i6GbzFvjfNtqjrWr_iqBShyIwuOUJRbXzdJNggx2BDNG-PEWDXl89SaudFICkDvyZKEcATIss6ZXfULIMfCrqmWmFwgXfNEd9TuvjqoxFlLSaY4UfDMiYa_arUMblFfoo5nV07GANhUoQd-6HRe7LjYeX5VRodOx6ZmZjIAUq-DYr-hatJJFR2tjT_qZht2MJeYT3GZ3o54m8zBBt0JTN7HVpKaOaM3A2hEM_Ah0QZ-DkLDxtCzMuv987GDiLT2-Riya97a47yHIJhZFzFpflW2FcuC8RFWXlfUKTQfZkFmxh3MUekUuS4yu4Z121xojVswk_4P7-FqLaSnGT2epI69I_cvalRx3wjds9-5TFYqf4GridlFBRx6Fv2fpNB9Zvp9k7NQ9oYcPuXGLoXH5kmWBagPhEGKHA_pjFUZmCuwUIoeP4nP8lhFrX8OGezsbSBG773CRJzEdfcgAc5G-p6M_24WZLZHDrsVBAvgrNt6R9eQbEviWU28t_417QCp-or9qqt4OTKv1dp_4MlZh8YBg2-dtpvzSc1l5e4kQFJu7oWlpbgsjB6pl1oRRKp1maedX-gOAf559zC4l85gfEpPln9Cnl6xvERQzfO0Ey4q91SdsgK7i7FBrKKmi2wGiemFvnaQsrjZ_IFujLo8-2c8g9zTiyH1knyoVOAAnQxqGpsz6z6PNfSxr3_G8tOlNFTV-yqN_LdVHMgXtXjn3U9koGsfMulyUcBDdR3d_0Yn6iEjBt77tbxKi2ry-0gQrB1fdGsgKjyE_tMrW8D_lQz0IXsVOzd2ixsFVXMFzD6OOD8JldV0FbA-VDAS-Tp_ezIZVp6lRq54XBgvsjzDyOmOgDbSOQN6SQmvxPnIsml1wgmtm80z-9gHBqmimHBtLKB6L7CtLmmPICMS2pX3eWOmakxscxqs8AVjijJdz_NYNfcdBeDj_fhm6dqD6iwk3EBZZfsrmMGdXtAMqf1r9ng9tsz-FriXwQiJ3IM3loBsk5DKr9CcaJtKSPuwDDlRynD2vwcD-XyF6YTQdSJa9fEcq-qXya2Scj4mqQ4RDemJgErdradRfwJfII3fWHh18XxmYVqi9Bwn3YRgwEadyo0-HjbNq6vJXi12igmP99ciRAfMVQLjfUfTwoOHj44Y2Ru_hPjJcvB6FIn6KLrrCSrZnrshFdFn4L36z1CrS8fbtdvrG3kdZQxsUJnMqttuwKRpLnDWTWkIwj_GRBFrzCFgbwGp1XYhemxggyKVuhZPfyyTIM9rhlPth6eGyrpYfap24Av_mGPRBLnzcjtpGbACGdKQL034kVmI7yENGvmY40KSrWsVG_BE9bSJhx0EptFsT2IxnxbuFD4hGb4fFag9V0BDiKpUoOZqIVqVO8cAp-5w4twvWZKkrhu16JNlLoXWMoFANrw-tp5LKSin1CUeRa4LWVI1GR8tRkIad_GnCHRv9JEMswlNy9wi2sDNsSxWT7WNasUW5-glgK9pR7d2pXGGOWfHj1U6CKIqmAiO3iw8igzhvyx_dAxMxPo \ No newline at end of file diff --git a/tests/features/data/journals/basic_folder/2020/08/29.txt b/tests/features/data/journals/basic_folder/2020/08/29.txt new file mode 100644 index 00000000..c8af54ca --- /dev/null +++ b/tests/features/data/journals/basic_folder/2020/08/29.txt @@ -0,0 +1,19 @@ +[2020-08-29 11:11:00 AM] Entry the first. +Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. diff --git a/tests/features/data/journals/basic_folder/2020/08/31.txt b/tests/features/data/journals/basic_folder/2020/08/31.txt new file mode 100644 index 00000000..826e7cdb --- /dev/null +++ b/tests/features/data/journals/basic_folder/2020/08/31.txt @@ -0,0 +1,23 @@ +[2020-08-31 02:32:00 PM] A second entry in what I hope to be a long series. * +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. diff --git a/tests/features/data/journals/basic_folder/2020/09/24.txt b/tests/features/data/journals/basic_folder/2020/09/24.txt new file mode 100644 index 00000000..2bd885ce --- /dev/null +++ b/tests/features/data/journals/basic_folder/2020/09/24.txt @@ -0,0 +1,11 @@ +[2020-09-24 09:14:00 AM] The third entry finally after weeks without writing. +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 diff --git a/tests/features/data/journals/basic_onefile.journal b/tests/features/data/journals/basic_onefile.journal new file mode 100644 index 00000000..0d988049 --- /dev/null +++ b/tests/features/data/journals/basic_onefile.journal @@ -0,0 +1,58 @@ +[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 pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. + +[2020-08-31 14:32] A second entry in what I hope to be a long series. * + +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. + +[2020-09-24 09:14] The third entry finally after weeks without writing. + +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 diff --git a/tests/features/data/journals/brackets.journal b/tests/features/data/journals/brackets.journal new file mode 100644 index 00000000..4649ea3e --- /dev/null +++ b/tests/features/data/journals/brackets.journal @@ -0,0 +1,2 @@ +[2019-07-08 05:42] Entry subject +[1] line starting with 1 diff --git a/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry b/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry new file mode 100644 index 00000000..066821bb --- /dev/null +++ b/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry @@ -0,0 +1,56 @@ + + + + + Creation Date + 2013-10-27T02:27:27Z + Creator + + Device Agent + iPhone/iPhone3,1 + Generation Date + 2013-10-27T07:02:27Z + Host Name + omrt104001 + OS Agent + iOS/7.0.3 + Software Agent + Day One (iOS)/1.11.4 + + Entry Text + Some text. + Location + + Administrative Area + Östergötlands län + Country + Sverige + Latitude + 58.383400000000000 + Locality + City + Longitude + 15.577170000000000 + Place Name + Street + + Starred + + Time Zone + Europe/Stockholm + UUID + B40EE704E15846DE8D45C44118A4D511 + Weather + + Celsius + 12 + Description + Clear + Fahrenheit + 54 + IconName + sunnyn.png + + + diff --git a/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry b/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry new file mode 100644 index 00000000..ea3efec5 --- /dev/null +++ b/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry @@ -0,0 +1,52 @@ + + Creation Date + 2013-10-27T02:27:27Z + Creator + + Device Agent + iPhone/iPhone3,1 + Generation Date + 2013-10-27T07:02:27Z + Host Name + omrt104001 + OS Agent + iOS/7.0.3 + Software Agent + Day One (iOS)/1.11.4 + + Entry Text + This is not a valid plist. + Location + + Administrative Area + Östergötlands län + Country + Sverige + Latitude + 58.383400000000000 + Locality + City + Longitude + 15.577170000000000 + Place Name + Street + + Starred + + Time Zone + Europe/Stockholm + UUID + B40EE704E15846DE8D45C44118A4D511 + Weather + + Celsius + 12 + Description + Clear + Fahrenheit + 54 + IconName + sunnyn.png + + + diff --git a/tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry b/tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry new file mode 100644 index 00000000..426f1ea8 --- /dev/null +++ b/tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry @@ -0,0 +1,33 @@ + + + + + Activity + Stationary + Creation Date + 2019-12-30T21:28:54Z + Entry Text + + Starred + + UUID + 48A25033B34047C591160A4480197D8B + Creator + + Device Agent + PC + Generation Date + 2019-12-30T21:28:54Z + Host Name + LE-TREPORT + OS Agent + Microsoft Windows/10 Home + Software Agent + Journaley/2.1 + + Tags + + i_have_no_body + + + diff --git a/tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry b/tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry new file mode 100644 index 00000000..1ac26242 --- /dev/null +++ b/tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry @@ -0,0 +1,34 @@ + + + + + Creation Date + 2013-05-17T18:39:20Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:39:20Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry has tags! + Starred + + Tags + + work + PLaY + + Time Zone + America/Los_Angeles + UUID + 044F3747A38546168B572C2E3F217FA2 + + diff --git a/tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry b/tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry new file mode 100644 index 00000000..927de884 --- /dev/null +++ b/tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry @@ -0,0 +1,46 @@ + + + + + Creation Date + 2013-06-17T18:38:29Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:38:29Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry has a location. + Location + + Administrative Area + California + Country + Germany + Latitude + 52.4979764 + Locality + Berlin + Longitude + 13.2404758 + Place Name + Abandoned Spy Tower + + Starred + + Tags + + Time Zone + Europe/Berlin + UUID + 0BDDD6CDA43C4A9AA2681517CC35AD9D + + diff --git a/tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry b/tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry new file mode 100644 index 00000000..16260763 --- /dev/null +++ b/tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry @@ -0,0 +1,31 @@ + + + + + Creation Date + 2013-07-17T18:38:08Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:38:08Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry is starred! + Starred + + Tags + + Time Zone + America/Los_Angeles + UUID + 422BC895507944A291E6FC44FC6B8BFC + + diff --git a/tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry b/tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry new file mode 100644 index 00000000..9ebaf538 --- /dev/null +++ b/tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry @@ -0,0 +1,29 @@ + + + + + Creation Date + 2013-01-17T18:37:50Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:37:50Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This is a DayOne entry without Timezone. + Starred + + Tags + + UUID + 4BB1F46946AD439996C9B59DE7C4DDC1 + + diff --git a/tests/features/data/journals/dayone_empty.dayone/entries/empty.txt b/tests/features/data/journals/dayone_empty.dayone/entries/empty.txt new file mode 100644 index 00000000..c86b8f66 --- /dev/null +++ b/tests/features/data/journals/dayone_empty.dayone/entries/empty.txt @@ -0,0 +1 @@ +This file exists to preserve the directory structure, but should be ignored by jrnl. diff --git a/tests/features/data/journals/deletion.journal b/tests/features/data/journals/deletion.journal new file mode 100644 index 00000000..c0fa689d --- /dev/null +++ b/tests/features/data/journals/deletion.journal @@ -0,0 +1,5 @@ +[2019-10-29 11:11] First entry. + +[2019-10-29 11:11] Second entry. + +[2019-10-29 11:13] Third entry. \ No newline at end of file diff --git a/tests/features/data/journals/deletion_filters.journal b/tests/features/data/journals/deletion_filters.journal new file mode 100644 index 00000000..9a3747db --- /dev/null +++ b/tests/features/data/journals/deletion_filters.journal @@ -0,0 +1,14 @@ +[2019-10-01 08:00] It's just another day in October. +Not much to write about. + +[2020-01-01 08:00] Happy New Year! +So this is the New Year. @holidays + +[2020-03-01 08:00] It's just another day in March. +A stick, a stone, it's the end of the road. + +[2020-05-01 09:00] Happy May Day! +@holidays @springtime Several holidays fall on this date. + +[2020-05-02 12:10] Writing tests. * +@springtime They will help prevent bugs. diff --git a/tests/features/data/journals/empty_folder/empty b/tests/features/data/journals/empty_folder/empty new file mode 100644 index 00000000..175b82b5 --- /dev/null +++ b/tests/features/data/journals/empty_folder/empty @@ -0,0 +1 @@ +Nothing to see here diff --git a/tests/features/data/journals/encrypted.journal b/tests/features/data/journals/encrypted.journal new file mode 100644 index 00000000..d2a5fcbe --- /dev/null +++ b/tests/features/data/journals/encrypted.journal @@ -0,0 +1 @@ +gAAAAABVIHB7tnwKExG7aC5ZbAbBL9SG2oY2GENeoOJ22i1PZigOvCYvrQN3kpsu0KGr7ay5K-_46R5YFlqJvtQ8anPH2FSITsaZy-l5Lz_5quw3rmzhLwAR1tc0icgtR4MEpXEdsuQ7cyb12Xq-JLDrnATs0id5Vow9Ri_tE7Xe4BXgXaySn3aRPwWKoninVxVPVvETY3MXHSUEXV9OZ-pH5kYBLGYbLA== diff --git a/tests/features/data/journals/encrypted_jrnl-1-9-5.journal b/tests/features/data/journals/encrypted_jrnl-1-9-5.journal new file mode 100644 index 0000000000000000000000000000000000000000..339b47baf9671f4550efeb9b6a0cfcd5032255d6 GIT binary patch literal 128 zcmV-`0Du3(bJIGVsY(mXmoW-2hF&*L`0NbJTYlTUr8*^Qm97}8E^3^1bZ$P^M literal 0 HcmV?d00001 diff --git a/tests/features/data/journals/little_endian_dates.journal b/tests/features/data/journals/little_endian_dates.journal new file mode 100644 index 00000000..d7492969 --- /dev/null +++ b/tests/features/data/journals/little_endian_dates.journal @@ -0,0 +1,5 @@ +[09.06.2013 15:39] My first entry. +Everything is alright + +[10.07.2013 15:40] Life is good. +But I'm better. diff --git a/tests/features/data/journals/markdown-headings-335.journal b/tests/features/data/journals/markdown-headings-335.journal new file mode 100644 index 00000000..30f592ef --- /dev/null +++ b/tests/features/data/journals/markdown-headings-335.journal @@ -0,0 +1,42 @@ +[2015-04-14 13:23] Heading Test + +H1-1 += + +H1-2 +=== + +H1-3 +============================ + +H2-1 +- + +H2-2 +--- + +H2-3 +---------------------------------- + +Horizontal Rules (ignore) + +--- + +=== + +# ATX H1 + +## ATX H2 + +### ATX H3 + +#### ATX H4 + +##### ATX H5 + +###### ATX H6 + +Stuff + +More stuff +more stuff again diff --git a/tests/features/data/journals/mostlyreadabledates.journal b/tests/features/data/journals/mostlyreadabledates.journal new file mode 100644 index 00000000..bd211bf5 --- /dev/null +++ b/tests/features/data/journals/mostlyreadabledates.journal @@ -0,0 +1,8 @@ +[2019-07-18 14:23] Entry subject +Time machines are possible. I know, because I've built one in my garage. + +[2019-07-19 14:23] Entry subject +I'm going to activate the machine. Nobody knows what comes next after this. Or before this? + +[2019-07 14:23] Entry subject +I've crossed so many timelines. Is there any going back? diff --git a/tests/features/data/journals/multiline-tags.journal b/tests/features/data/journals/multiline-tags.journal new file mode 100644 index 00000000..1fb8706f --- /dev/null +++ b/tests/features/data/journals/multiline-tags.journal @@ -0,0 +1,7 @@ +[2013-06-09 15:39] Multiple @line entry with @tags. +Tag with @punctuation. afterwards +@TagOnLineAloneWithOutPunctuation +@TagOnLineAloneWithPunctuation. +Text before @tag. And After. +@hi. Hello +hi Hello \ No newline at end of file diff --git a/tests/features/data/journals/multiline.journal b/tests/features/data/journals/multiline.journal new file mode 100644 index 00000000..294ed141 --- /dev/null +++ b/tests/features/data/journals/multiline.journal @@ -0,0 +1,5 @@ +[2013-06-09 15:39] Multiple line entry. +This is the first line. +This line doesn't have any ending punctuation + +There is a blank line above this. diff --git a/tests/features/data/journals/simple.journal b/tests/features/data/journals/simple.journal new file mode 100644 index 00000000..8336068e --- /dev/null +++ b/tests/features/data/journals/simple.journal @@ -0,0 +1,5 @@ +[2013-06-09 15:39] My first entry. +Everything is alright + +[2013-06-10 15:40] Life is good. +But I'm better. diff --git a/tests/features/data/journals/simple_jrnl-1-9-5.journal b/tests/features/data/journals/simple_jrnl-1-9-5.journal new file mode 100644 index 00000000..7bb6c5ac --- /dev/null +++ b/tests/features/data/journals/simple_jrnl-1-9-5.journal @@ -0,0 +1,13 @@ +2010-06-10 15:00 A life without chocolate is like a bad analogy. + +2013-06-10 15:40 He said "[this] is the best time to be alive". +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. + +[2019-08-03 12:55] Some chat log or something + +Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, +elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus +placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor +dui. diff --git a/tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal b/tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal new file mode 100644 index 00000000..328b23f4 --- /dev/null +++ b/tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal @@ -0,0 +1,13 @@ +10.06.2010 15:00 A life without chocolate is like a bad analogy. + +10.06.2013 15:40 He said "[this] is the best time to be alive". +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. + +[03.08.2019 12:55] Some chat log or something + +Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, +elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus +placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor +dui. diff --git a/tests/features/data/journals/tags-216.journal b/tests/features/data/journals/tags-216.journal new file mode 100644 index 00000000..08b6d630 --- /dev/null +++ b/tests/features/data/journals/tags-216.journal @@ -0,0 +1,2 @@ +[2013-06-10 15:40] I programmed for @OS/2. +Almost makes me want to go back to @C++, though. (Still better than @C#). diff --git a/tests/features/data/journals/tags-237.journal b/tests/features/data/journals/tags-237.journal new file mode 100644 index 00000000..be050652 --- /dev/null +++ b/tests/features/data/journals/tags-237.journal @@ -0,0 +1,3 @@ +[2014-07-22 11:11] This entry has an email. +@Newline tag should show as a tag. +Kyla's @email is kyla@clevelandunderdog.org and Guinness's is guinness@fortheloveofpits.org. diff --git a/tests/features/data/journals/tags.journal b/tests/features/data/journals/tags.journal new file mode 100644 index 00000000..a28f3159 --- /dev/null +++ b/tests/features/data/journals/tags.journal @@ -0,0 +1,8 @@ +[2013-04-09 15:39] I have an @idea: +(1) write a command line @journal software +(2) ??? +(3) PROFIT! + +[2013-06-10 15:40] I met with @dan. +As alway's he shared his latest @idea on how to rule the world with me. +inst diff --git a/tests/features/data/journals/unreadabledates.journal b/tests/features/data/journals/unreadabledates.journal new file mode 100644 index 00000000..53ef1d60 --- /dev/null +++ b/tests/features/data/journals/unreadabledates.journal @@ -0,0 +1,5 @@ +[ashasd7zdskhz7asdkjasd] Entry subject +I've lost track of time. + +[sadfhakjsdf88sdf7sdff] Entry subject +Time has no meaning. diff --git a/tests/features/data/journals/work.journal b/tests/features/data/journals/work.journal new file mode 100644 index 00000000..e69de29b diff --git a/tests/features/data/templates/sample.template b/tests/features/data/templates/sample.template new file mode 100644 index 00000000..a356d823 --- /dev/null +++ b/tests/features/data/templates/sample.template @@ -0,0 +1,19 @@ +--- +extension: txt +--- + +{% block journal %} +{% for entry in entries %} +{% include entry %} +{% endfor %} + +{% endblock %} + +{% block entry %} +{{ entry.title }} +{{ "-" * len(entry.title) }} + +{{ entry.body }} + +{% endblock %} +` diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature new file mode 100644 index 00000000..8fe335c9 --- /dev/null +++ b/tests/features/datetime.feature @@ -0,0 +1,155 @@ +Feature: Reading and writing to journal with custom date formats + + Scenario: Dates can include a time + # https://github.com/jrnl-org/jrnl/issues/117 + Given we use the config "simple.yaml" + When we run "jrnl 2013-11-30 15:42: Project Started." + Then we should see the message "Entry added" + And the journal should contain "[2013-11-30 15:42] Project Started." + + Scenario: Dates can be in the future + # https://github.com/jrnl-org/jrnl/issues/185 + Given we use the config "simple.yaml" + When we run "jrnl 26/06/2099: Planet? Earth. Year? 2099." + Then we should see the message "Entry added" + And the journal should contain "[2099-06-26 09:00] Planet?" + + Scenario: Loading a sample journal with custom date + Given we use the config "little_endian_dates.yaml" + When we run "jrnl -n 2" + Then we should get no error + And the output should be + """ + 09.06.2013 15:39 My first entry. + | Everything is alright + + 10.07.2013 15:40 Life is good. + | But I'm better. + """ + + Scenario Outline: Writing an entry from command line with custom date + Given we use the config ".yaml" + When we run "jrnl " + Then we should see the message "Entry added" + When we run "jrnl -n 1" + Then the output should contain "" + + Examples: Day-first Dates + | config | input | output | + | little_endian_dates | 2020-09-19: My first entry. | 19.09.2020 09:00 My first entry. | + | little_endian_dates | 2020-08-09: My second entry. | 09.08.2020 09:00 My second entry. | + | little_endian_dates | 2020-02-29: Test. | 29.02.2020 09:00 Test. | + | little_endian_dates | 2019-02-29: Test. | 2019-02-29: Test. | + | little_endian_dates | 2020-08-32: Test. | 2020-08-32: Test. | + | little_endian_dates | 2032-02-01: Test. | 01.02.2032 09:00 Test. | + | little_endian_dates | 2020-01-01: Test. | 01.01.2020 09:00 Test. | + | little_endian_dates | 2020-12-31: Test. | 31.12.2020 09:00 Test. | + + Scenario Outline: Searching for dates with custom date + Given we use the config ".yaml" + When we run "jrnl -on '' --short" + Then the output should be "" + + Examples: Day-first Dates + | config | input | output | + | little_endian_dates | 2013-07-10 | 10.07.2013 15:40 Life is good. | + | little_endian_dates | june 9 2013 | 09.06.2013 15:39 My first entry. | + | little_endian_dates | july 10 2013 | 10.07.2013 15:40 Life is good. | + | little_endian_dates | june 2013 | 09.06.2013 15:39 My first entry. | + | little_endian_dates | july 2013 | 10.07.2013 15:40 Life is good. | + # @todo month alone with no year should work + # | little_endian_dates | june | 09.06.2013 15:39 My first entry. | + # | little_endian_dates | july | 10.07.2013 15:40 Life is good. | + + Scenario: Writing an entry at the prompt with custom date + Given we use the config "little_endian_dates.yaml" + When we run "jrnl" and enter "2013-05-10: I saw Elvis. He's alive." + Then we should get no error + And the journal should contain "[10.05.2013 09:00] I saw Elvis." + And the journal should contain "He's alive." + + Scenario: Viewing today's entries does not print the entire journal + # https://github.com/jrnl-org/jrnl/issues/741 + Given we use the config "simple.yaml" + When we run "jrnl -on today" + Then the output should not contain "Life is good" + And the output should not contain "But I'm better." + + Scenario Outline: Create entry using day of the week as entry date. + Given we use the config "simple.yaml" + When we run "jrnl : This is an entry on a ." + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should contain " at 9am" in the local time + And the output should contain "This is an entry on a ." + + Examples: Days of the week + | day | + | Monday | + | Tuesday | + | Wednesday | + | Thursday | + | Friday | + | Saturday | + | Sunday | + | sunday | + | sUndAy | + + Scenario Outline: Create entry using day of the week abbreviations as entry date. + Given we use the config "simple.yaml" + When we run "jrnl : This is an entry on a ." + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should contain " at 9am" in the local time + + Examples: Days of the week + | day | weekday | + | mon | Monday | + | tue | Tuesday | + | wed | Wednesday | + | thu | Thursday | + | fri | Friday | + | sat | Saturday | + | sun | Sunday | + + Scenario: Journals with unreadable dates should still be loaded + Given we use the config "unreadabledates.yaml" + When we run "jrnl -2" + Then the output should contain "I've lost track of time." + And the output should contain "Time has no meaning." + + Scenario: Journals with readable dates AND unreadable dates should still contain all data. + Given we use the config "mostlyreadabledates.yaml" + When we run "jrnl -3" + Then the output should contain "Time machines are possible." + Then the output should contain "I'm going to activate the machine." + And the output should contain "I've crossed so many timelines. Is there any going back?" + And the journal should have 3 entries + + Scenario: Update near-valid dates after journal is edited + Given we use the config "mostlyreadabledates.yaml" + When we run "jrnl 2222-08-19: I have made it exactly one month into the future." + Then the journal should contain "[2019-07-01 14:23] Entry subject" + + Scenario: Integers in square brackets should not be read as dates + Given we use the config "brackets.yaml" + When we run "jrnl -1" + Then the output should contain "[1] line starting with 1" + + # broken still + @skip + Scenario: Dayone entries without timezone information are interpreted in current timezone + Given we use the config "dayone.yaml" + When we run "jrnl -until 'feb 2013'" + Then we should get no error + And the output should contain "2013-01-17T18:37Z" in the local time + + Scenario: Loading entry with ambiguous time stamp in timezone-aware journal (like Dayone) + #https://github.com/jrnl-org/jrnl/issues/153 + Given we use the config "bug153.yaml" + When we run "jrnl -1" + Then we should get no error + And the output should be + """ + 2013-10-27 03:27 Some text. + """ diff --git a/tests/features/delete.feature b/tests/features/delete.feature new file mode 100644 index 00000000..2fc3f8f7 --- /dev/null +++ b/tests/features/delete.feature @@ -0,0 +1,229 @@ +Feature: Delete entries from journal + Scenario Outline: Delete flag allows deletion of single entry + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl -1" + Then the output should contain "2020-09-24 09:14 The third entry finally" + When we run "jrnl --delete" and enter + """ + N + N + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 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 | @todo + # | basic_dayone | @todo + + Scenario Outline: Backing out of interactive delete does not change journal + Given we use the config ".yaml" + When we run "jrnl --delete -n 1" and enter + """ + N + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + + Scenario Outline: Delete flag with nonsense input deletes nothing (issue #932) + Given we use the config ".yaml" + When we run "jrnl --delete asdfasdf" + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Delete flag with tag only deletes tagged entries + Given we use the config ".yaml" + When we run "jrnl --delete @ipsum" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + + Scenario Outline: Delete flag with multiple tags deletes all entries matching any of the tags + Given we use the config ".yaml" + When we run "jrnl --delete @ipsum @tagthree" and enter + """ + Y + Y + """ + Then we flush the output + When we run "jrnl -99 --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_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: Delete flag with -and deletes boolean AND of tagged entries + Given we use the config ".yaml" + When we run "jrnl --delete -and @tagone @tagtwo" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: Delete flag with -not does not delete entries from given tag + Given we use the config ".yaml" + When we run "jrnl --delete @tagone -not @ipsum" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: Delete flag with -from search operator only deletes entries since that date + Given we use the config ".yaml" + When we run "jrnl --delete -from 2020-09-01" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: Delete flag with -to only deletes entries up to specified date + Given we use the config ".yaml" + When we run "jrnl --delete -to 2020-08-31" and enter + """ + Y + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + + Scenario Outline: Delete flag with -starred only deletes starred entries + Given we use the config ".yaml" + When we run "jrnl --delete -starred" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-29 11:11 Entry the first. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: Delete flag with -contains only entries containing expression + Given we use the config ".yaml" + When we run "jrnl --delete -contains dignissim" and enter + """ + Y + """ + Then we flush the output + When we run "jrnl -99 --short" + Then the output should be + """ + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + """ + + Examples: Configs + | config | + | basic_onefile | + # | basic_folder | @todo + # | basic_dayone | @todo + diff --git a/tests/features/encrypt.feature b/tests/features/encrypt.feature new file mode 100644 index 00000000..f2d0a62f --- /dev/null +++ b/tests/features/encrypt.feature @@ -0,0 +1,35 @@ +Feature: Encrypting and decrypting journals + + Scenario: Decrypting a journal + Given we use the config "encrypted.yaml" + When we run "jrnl --decrypt" and enter "bad doggie no biscuit" + Then the config for journal "default" should have "encrypt" set to "bool:False" + And we should see the message "Journal decrypted" + And the journal should have 2 entries + + @todo + Scenario: Trying to decrypt an already unencrypted journal + # This should warn the user that the journal is already encrypted + Given we use the config "simple.yaml" + When we run "jrnl --decrypt" + Then the config for journal "default" should have "encrypt" set to "bool:False" + And the journal should have 2 entries + + @todo + Scenario: Trying to encrypt an already encrypted journal + # This should warn the user that the journal is already encrypted + + Scenario: Encrypting a journal + Given we use the config "simple.yaml" + When we run "jrnl --encrypt" and enter + """ + swordfish + swordfish + n + """ + Then we should see the message "Journal encrypted" + And the config for journal "default" should have "encrypt" set to "bool:True" + When we run "jrnl -n 1" and enter "swordfish" + Then we should be prompted for a password + And the output should contain "2013-06-10 15:40 Life is good" + diff --git a/tests/features/environment.py b/tests/features/environment.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/features/file_storage.feature b/tests/features/file_storage.feature new file mode 100644 index 00000000..33619365 --- /dev/null +++ b/tests/features/file_storage.feature @@ -0,0 +1,56 @@ +Feature: Journals iteracting with the file system in a way that users can see + + Scenario: Adding entries to a Folder journal should generate date files + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 July 2013: Testing folder journal." + Then we should see the message "Entry added" + When the journal directory is listed + Then the output should contain "2013/07/23.txt" or "2013\07\23.txt" + + Scenario: Adding multiple entries to a Folder journal should generate multiple date files + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 July 2013: Testing folder journal." + And we run "jrnl 3/7/2014: Second entry of journal." + Then we should see the message "Entry added" + When the journal directory is listed + Then the output should contain "2013/07/23.txt" or "2013\07\23.txt" + Then the output should contain "2014/03/07.txt" or "2014\03\07.txt" + + Scenario: If the journal and its parent directory don't exist, they should be created + Given we use the config "missing_directory.yaml" + Then the journal should not exist + When we run "jrnl This is a new entry in my journal" + Then the journal should exist + When we run "jrnl -n 1" + Then the output should contain "This is a new entry in my journal" + And the journal should have 1 entry + + Scenario: If the journal file doesn't exist, then it should be created + Given we use the config "missing_journal.yaml" + Then the journal should not exist + When we run "jrnl This is a new entry in my journal" + Then the journal should exist + When we run "jrnl -n 1" + Then the output should contain "This is a new entry in my journal" + And the journal should have 1 entry + + Scenario: Creating journal with relative path should update to absolute path + Given we use the config "missingconfig" + When we run "jrnl hello world" and enter + """ + test.txt + n + """ + And we change directory to "features" + And we run "jrnl -n 1" + Then the output should contain "hello world" + + Scenario: the temporary filename suffix should default to ".jrnl" + Given we use the config "editor.yaml" + When we run "jrnl --edit" + Then the temporary filename suffix should be ".jrnl" + + Scenario: the temporary filename suffix should be "-{template_filename}" + Given we use the config "editor_markdown_extension.yaml" + When we run "jrnl --edit" + Then the temporary filename suffix should be "-extension.md" diff --git a/tests/features/format.feature b/tests/features/format.feature new file mode 100644 index 00000000..4981f685 --- /dev/null +++ b/tests/features/format.feature @@ -0,0 +1,579 @@ +Feature: Custom formats + + Scenario Outline: JSON format + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl --format json" + Then we should get no error + And the output should be parsable as json + And "entries" in the json output should have 3 elements + And "tags" in the json output should contain "@ipsum" + And "tags" in the json output should contain "@tagone" + And "tags" in the json output should contain "@tagthree" + And "tags" in the json output should contain "@tagtwo" + And entry 1 should have an array "tags" with 3 elements + And entry 2 should have an array "tags" with 1 elements + And entry 3 should have an array "tags" with 2 elements + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario: Exporting dayone to json + Given we use the config "dayone.yaml" + When we run "jrnl --export json" + Then we should get no error + And the output should be parsable as json + 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 ".yaml" + 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 + | pellentesque + | augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu + | consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In + | commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget + | venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + | + | Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo + | ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse + | potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget + | molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus + | hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis + | feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum + | urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. + | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget + | 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 | + + Scenario Outline: Exporting using filters should only export parts of the journal + Given we use the config ".yaml" + 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 + Then we should get no error + And the output should be parsable as json + And "entries" in the json output should have 2 elements + And "tags" in the json output should contain "@ipsum" + And "tags" in the json output should contain "@tagone" + And "tags" in the json output should contain "@tagtwo" + And entry 1 should have an array "tags" with 3 elements + And entry 2 should have an array "tags" with 1 elements + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: Exporting using custom templates + Given we use the config ".yaml" + 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. + ---------------------------------------------------- + + I'm so excited about emojis. 💯 🎶 💩 + + Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. + Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla + eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis + dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. + Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis + 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 | + + Scenario Outline: Increasing Headings on Markdown export + Given we use the config ".yaml" + And we use the password "test" if prompted + When we open the editor and append + """ + [2020-10-14 13:23] Heading Test + + H1-1 + = + + H1-2 + === + + H1-3 + ============================ + + H2-1 + - + + H2-2 + --- + + H2-3 + ---------------------------------- + + Horizontal Rules (ignore) + + --- + + === + + # ATX H1 + + ## ATX H2 + + ### ATX H3 + + #### ATX H4 + + ##### ATX H5 + + ###### ATX H6 + + Stuff + + More stuff + more stuff again + """ + Then we flush the output + When we run "jrnl -1 --export markdown" + Then the output should be + """ + # 2020 + + ## October + + ### 2020-10-14 13:23 Heading Test + + #### H1-1 + + #### H1-2 + + #### H1-3 + + ##### H2-1 + + ##### H2-2 + + ##### H2-3 + + Horizontal Rules (ignore) + + --- + + === + + #### ATX H1 + + ##### ATX H2 + + ###### ATX H3 + + ####### ATX H4 + + ######## ATX H5 + + ######### ATX H6 + + Stuff + + More stuff + more stuff again + """ + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + # | basic_dayone | @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 ".yaml" + 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 + + ### 2020-10-29 11:11 First entry. + + + ### 2020-10-29 11:11 Second entry. + + + ### 2020-10-29 11:13 Third entry. + + """ + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + # | basic_dayone | @todo + + @skip + Scenario Outline: Exporting to XML + Given we use the config ".yaml" + 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 there should be 10 "tag" elements + + Examples: configs + | config | + # | basic_onefile | @todo + # | basic_encrypted | @todo + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario: Exporting to XML + Given we use the config "tags.yaml" + 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 2 elements + 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 ".yaml" + 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 | + + @todo + Scenario Outline: Exporting fancy + # Needs better emoji support + Given we use the config ".yaml" + 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. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada │ + ┃ quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus │ + ┃ pellentesque │ + ┃ augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu │ + ┃ consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In │ + ┃ commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget │ + ┃ venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. │ + ┃ │ + ┃ Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo │ + ┃ ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. │ + ┃ Suspendisse │ + ┃ potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas │ + ┃ eget │ + ┃ molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed │ + ┃ lectus │ + ┃ hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis │ + ┃ feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, │ + ┃ vestibulum │ + ┃ urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod │ + ┃ enim. │ + ┃ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget │ + ┃ 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. │ + ┖──────────────────────────────────────────────────────────────────────────────┘ + ┎──────────────────────────────────────────────────────────────╮2020-08-31 14:32 + ┃ A second entry in what I hope to be a long series. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis │ + ┃ leo │ + ┃ vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit │ + ┃ amet, │ + ┃ consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl │ + ┃ lorem, │ + ┃ vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum │ + ┃ lectus, │ + ┃ eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium │ + ┃ id │ + ┃ lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, │ + ┃ egestas at efficitur et, ultrices vel est. Sed commodo et nibh non │ + ┃ elementum. │ + ┃ Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. │ + ┃ │ + ┃ Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel │ + ┃ vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum │ + ┃ et │ + ┃ malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis │ + ┃ sem, │ + ┃ non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel │ + ┃ ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a │ + ┃ commodo │ + ┃ eros. │ + ┃ │ + ┃ Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non │ + ┃ tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. │ + ┃ Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum │ + ┃ quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum │ + ┃ interdum. Integer id justo dui. Integer eu tellus in turpis bibendum │ + ┃ blandit. │ + ┃ Quisque auctor lacinia consectetur. │ + ┖──────────────────────────────────────────────────────────────────────────────┘ + ┎──────────────────────────────────────────────────────────────╮2020-09-24 09:14 + ┃ The third entry finally after weeks without writing. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ I'm so excited about emojis. 💯 🎶 💩 │ + ┃ │ + ┃ Donec semper pellentesque iaculis. Nullam cursus et justo sit amet │ + ┃ venenatis. │ + ┃ Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. │ + ┃ Nulla │ + ┃ eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis │ + ┃ dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh │ + ┃ malesuada. │ + ┃ Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis │ + ┃ 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 | + + @skip_win + Scenario Outline: Export to yaml + Given we use the config ".yaml" + 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-08-29_entry-the-first.md" in the cache should be + """ + --- + title: Entry the first. + date: 2020-08-29 11:11 + starred: False + tags: tagone, ipsum, tagtwo + body: | + Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada + quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque + augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu + consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In + commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget + venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + + Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo + ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse + potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget + molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus + hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis + feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum + urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget + 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 | + + @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 ".yaml" + 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 + starred: False + tags: tagone, tagthree + body: | + I'm so excited about emojis. 💯 🎶 💩 + + Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. + Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla + eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis + dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. + Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis + 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 | @todo + + Scenario: Empty DayOne entry bodies should not error + # https://github.com/jrnl-org/jrnl/issues/780 + Given we use the config "bug780.yaml" + When we run "jrnl --short" + Then we should get no error + + Scenario Outline: --short displays the short version of entries (only the title) + Given we use the config ".yaml" + 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 | + + Scenario Outline: -s displays the short version of entries (only the title) + Given we use the config ".yaml" + 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 | + + 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 + + ### 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 ".yaml" + 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 | + + Scenario Outline: Export date counts + Given we use the config ".yaml" + 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 | diff --git a/tests/features/import.feature b/tests/features/import.feature new file mode 100644 index 00000000..63b042fc --- /dev/null +++ b/tests/features/import.feature @@ -0,0 +1,93 @@ +Feature: Importing data + + Scenario Outline: --import allows new entry from stdin + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl --import" and pipe "[2020-07-05 15:00] Observe and import." + Then we flush the output + When we run "jrnl -c import" + Then the output should contain "Observe and import" + + Examples: Configs + | config | + | basic_onefile | + | basic_encrypted | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: --import allows new large entry from stdin + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl --import" and pipe + """ + [2020-07-05 15:00] Observe and import. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis + est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue + et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu consequat. + Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec + tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at + dolor dui end of entry. + """ + Then we flush the output + When we run "jrnl -on 2020-07-05" + Then the output should contain "2020-07-05 15:00 Observe and import." + And the output should contain "Lorem ipsum" + And the output should contain "end of entry." + + Examples: Configs + | config | + | basic_onefile | + | basic_encrypted | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario Outline: --import allows multiple new entries from stdin + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl --import" and pipe + """ + [2020-07-05 15:00] Observe and import. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + [2020-07-05 15:01] Twice as nice. + Sed dignissim sed nisl eu consequat. + """ + Then we flush the output + When we run "jrnl -on 2020-07-05" + Then the output should contain "2020-07-05 15:00 Observe and import." + And the output should contain "Lorem ipsum" + And the output should contain "2020-07-05 15:01 Twice as nice." + And the output should contain "Sed dignissim" + + Examples: Configs + | config | + | basic_onefile | + | basic_encrypted | + # | basic_folder | @todo + # | basic_dayone | @todo + + Scenario: --import allows import new entries from file + Given we use the config "simple.yaml" + Then the journal should contain "My first entry." + And the journal should contain "Life is good." + But the journal should not contain "I have an @idea" + And the journal should not contain "I met with" + When we run "jrnl --import --file features/journals/tags.journal" + Then the journal should contain "My first entry." + And the journal should contain "Life is good." + And the journal should contain "PROFIT!" + + Scenario: --import prioritizes --file over pipe data if both are given + Given we use the config "simple.yaml" + Then the journal should contain "My first entry." + And the journal should contain "Life is good." + But the journal should not contain "I have an @idea" + And the journal should not contain "I met with" + When we run "jrnl --import --file features/journals/tags.journal" and pipe + """ + [2020-07-05 15:00] I should not exist! + """ + Then the journal should contain "My first entry." + And the journal should contain "PROFIT!" + But the journal should not contain "I should not exist!" + diff --git a/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry new file mode 100644 index 00000000..9721dd55 --- /dev/null +++ b/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry @@ -0,0 +1,53 @@ + + + + + Creation Date + 2020-08-29T18:11:00Z + Starred + + Entry Text + Entry the first. +Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. + Time Zone + America/Los_Angeles + UUID + D04D335AFED711EABA18FAFFC2100C3D + Tags + + ipsum + tagone + tagtwo + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:35:45Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry new file mode 100644 index 00000000..8c2f3c52 --- /dev/null +++ b/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry @@ -0,0 +1,55 @@ + + + + + Creation Date + 2020-08-31T21:32:00Z + Starred + + Entry Text + A second entry in what I hope to be a long series. +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. + Time Zone + America/Los_Angeles + UUID + FC8A86CAFED711EA8892FAFFC2100C3D + Tags + + tagtwo + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:36:59Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry new file mode 100644 index 00000000..d998c36b --- /dev/null +++ b/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry @@ -0,0 +1,44 @@ + + + + + Creation Date + 2020-09-24T16:14:00Z + Starred + + Entry Text + The third entry finally after weeks without writing. +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 + Time Zone + America/Los_Angeles + UUID + FD8ABC8EFED711EABC35FAFFC2100C3D + Tags + + tagthree + tagone + + Creator + + Device Agent + + Generation Date + 2020-09-25T02:37:01Z + Host Name + iris.lan + OS Agent + Darwin/19.3.0 + Software Agent + jrnl/v2.4.5 + + + diff --git a/tests/features/journals/basic_encrypted.journal b/tests/features/journals/basic_encrypted.journal new file mode 100644 index 00000000..ffc122df --- /dev/null +++ b/tests/features/journals/basic_encrypted.journal @@ -0,0 +1 @@ +gAAAAABfb4gQBMqqGn_W8v_s7qCi14bX7inuCOKbsBqIUf7_ch14vTUp7lrysPFvhBp5vGijTwDIbk4LKoIISj8NwM31I8L0zEbMx9y6iyF_zseGGNxBvNN0wzAXa67bs-ohiQhhebcdIc_52sltxL2ELh8JAKUaXRwyapgnMgJ7z6deJppLK-B7RE7BiT0eKjWTDMd2x6cZDswvHs9opDp5yjuKWV5m7x6ggCKYgHT3savT9Tg7V0Fq6K3LGWaE59lCrqlAB0u6dnrDX3qcF4SKyckaniXzRShZGebdkUKDcLFun2V2syZwYQN772xjznIsJ16iXicox2uYKg8CnTefsyCwaOZyBvySGEy3CrlBiuIRIcxCtjKbYJ2B-Aq7LZitnBR7Ny_6_Wm8HsBf3N-cFCp4GShiCKrxuXKcOZ7vszG5EKb78JS85bb0mswU5CSdgp6UAHjIZqfJq00qQsViBCbXq3oklCPZXdQkOf5U0KpG2MVUiD-Zcn5Qj3gnUhSEr-5wKU9tWrE63MGPyE6KjZlArZX2W2LeGnW2CEYw9eREGon06AzLJ4mj3BgtjVWLIdGcCwORXvHRjUqazWgbEmXNVTbtp_cKnkW-rFzRBrUoVme9v-1Y3sH0VvHBq7QIj915VzBklzWs1qzIyTPZG5Db9LvdQ7SiV8slf1Jo7l-ayUUdVj6igvKZcgfB4RUHolJoMps5p4lZ5sPqv59KtSa8DCpuoRczIj71OCpuRVARZgy1m5sUD9xSMxOBdy46u1Jnry6iMtzXWI3mEZe5m7UhmW_L4Zcv4bbk8XjkBeHjPdgm2B69jkLmCBFecD5ztoGesCGt_pNo_sWSKqLHV1-coKFB2Nn__a4utU9NJNdeNRkr8_ahU6tn3jmaFjfQ7cKfrXG_NCcYBRX9fja8EQIeBEp_3TCoXQqhuV_bGsNPA2qL63Pt6YiRaUf1g9FNBqJRlKCSOYNixSXQZN_rTePzx0SQ0aIQhADWls62WX-LG5-byJcB6W2P_cH21hDOXkoNEIyLnCz9HQ6Yd6Fbv7298ps3F6jiUDdWES23zv8sDgBuKUN94qSN34j6MDYGFnGI9zsJ-Y-I2frdlLfWPx3pUL7afcKh1nRgXdjctsTSxU2BDrsu03eBz2IoZjoOR0U51IrNMOD1NNT3kctXxHLuOHSEkwAzS3doncQbdRLi5Gc1dQuOUa4sC-p8gVjUKXO-oi_49kp9Km2Ay9wFg0epBbXx2QMzyMsN2dXeSbHF-BDXD6sULaq5syC0fOHqaMLycTCMk2wLfNyXgEt05WvAiDn-LDsRdylMRW2hXp5HWq3Poaul-7VNg6UEMlwVfgJ-7hNreuO6IRtwmx6YdqMscw0ms6mU_MQZU_dTIPg3JU4KL0YyMqPBPSGNCx3gMp41O05Ubir45FoJSnT5Dkj4v3N0S87Ys3HuFLverASsGt9bkcSzd2uMKCJjkspemPPi9VhrY4IOO03DWSWbHmxYzFc1SJ-24WM8Ch404QKpe1qy5LNzFgLvDwQhSIHjluezHXqrD-DVh1lWNNY3WmHI2ubOZfaorvLKqzBPZ6AhpIa60rKjm0OZIQOmJwWXwkdnzut6m8PtoiLzRN897YMgeztf1nmDwp0xE-EhknVZ3WV3TeqgZJ5ykfHQ5BU8x0Db57-UtKSuesKbqPPdBe91OdsPpkGlyl6psHj1_gPm4nLvzXQePwiPaEemR_gYCWGPvl9l1ANJufgCV9qQTmZGof3fb9mjv-9lS-9l_m8KirPPRpSBToNeDtk50ceYUsOlDGzIyusppG9pOcIGyiln1IO5aZ8d4_1E83qjcHTSaKGizICZU7a-pt5STBPMesy3JgBm23A2jO4m68ayBRMcLnw_RirHvvBaj0C6UR2tac45F0Ob3PpXcvFuK0g54ziIAhzGqwF9I-LZ6asXQWMW4y4EBOak8JJBorkfztzfkMaIgGu-4ZoRKOkVfdr4uzcghk3r6KUxD4-nv1ioX69-G5RwhMHppYk7z8RXS1cq5FkvzXbfEQ-Uv6M-sx32DcUy9dH-ZYhc7UWm75JJfiNXLaXT_bsc6VqQ7KPkg2-RA7CywUFCW9S0S-XdO03VdwqlUVo7fp1SKywEfhZv_9bhDCdMJBwZmigv2KP9Iz7fF6LrpLwZkzHuQGFPcyTHFpsVIFrFyJjNYCXpET9y0Q5Vt4fnea5fy-9ZiCt3S8aS0YOFJ35_kM5i3ss8eFPL0v7fIQS3ZilzdGB3bWL0J7kppHN_ekHu-wVk3UZxauoFh7hXLjPcipua-FYUIklLjcK6DG1bYP7_q6OnkC8Jl650FNezeWPomHEv7l_DO3y0tjI6SGdWvL3ZJns7Xp3ew8KsCREAUO7ffqumD03uF9N-9uWbDDjM7rk0vcg0ggfOs9Ni725mxqYpu4R285XCOVWHDvw7iU6eAvE6ry8TDXQBbNgGjTuTYFYYli7GuOqMxFIe1op2s7sRnoJE8O0J76S6APhjhjcnZRSuONWkVG_5o83uFMPSF8DtqLwuRA5E8AGfIwAUcj324sw-DA0ixBGUqomb-osUIisv3x0b044xn-FvD-8R3PZDnPbPsao8XYNxfQWStrNcZSrX2Ua-WAcv9qbQ73_57RKW4pao4ajOu7K5800D231WGiIa6aJzDnFUlzXEzYxFQyx7qegkm_9rrEp_v8TC9mfAcjWX5DMrCkxUskx9YKDfpFYq4NuxO_414gReKzd-lmorfigvttgS10N1XD74SwFluXJv-bqTbI5-SuYAhDGMv1dqrn38i3rOMQqqnQomvaUJRprqxUsKz14sSE1Y-cNqq1FXzZ6vIJq-K3YTfFWPRLeqi6gHzqS_R2YBXXUduKuYgmakiVdP3bWc-Ca8WKh5sVi6P51MO-cS7i9AZWOaOz7F8PsB4JZxAJjSOr3NBmv3EEve9auTFCudRjfC6668I_NMHaTP5CCV4cuhuAxUuKUGgd6WFjDcvoYPyn_lu3bQiqD9MEag4CaJYI9PlraRv5mbqptwxv3pca7usd0GmXN_2No_nwxB4gVb48LsBBkH35njCa5iv2EKXUSOf0k3swaTSEahqbyI4EDzPXtU5uBO39iQzNpgfV_sUpnGdysjqueUVcdWGI_s5CnrNJ-_yDAY06AoXfLrjP8_3NXB2058xZ2rfmTNJNCULz9634dICJReXNnmplxIg3i6GbzFvjfNtqjrWr_iqBShyIwuOUJRbXzdJNggx2BDNG-PEWDXl89SaudFICkDvyZKEcATIss6ZXfULIMfCrqmWmFwgXfNEd9TuvjqoxFlLSaY4UfDMiYa_arUMblFfoo5nV07GANhUoQd-6HRe7LjYeX5VRodOx6ZmZjIAUq-DYr-hatJJFR2tjT_qZht2MJeYT3GZ3o54m8zBBt0JTN7HVpKaOaM3A2hEM_Ah0QZ-DkLDxtCzMuv987GDiLT2-Riya97a47yHIJhZFzFpflW2FcuC8RFWXlfUKTQfZkFmxh3MUekUuS4yu4Z121xojVswk_4P7-FqLaSnGT2epI69I_cvalRx3wjds9-5TFYqf4GridlFBRx6Fv2fpNB9Zvp9k7NQ9oYcPuXGLoXH5kmWBagPhEGKHA_pjFUZmCuwUIoeP4nP8lhFrX8OGezsbSBG773CRJzEdfcgAc5G-p6M_24WZLZHDrsVBAvgrNt6R9eQbEviWU28t_417QCp-or9qqt4OTKv1dp_4MlZh8YBg2-dtpvzSc1l5e4kQFJu7oWlpbgsjB6pl1oRRKp1maedX-gOAf559zC4l85gfEpPln9Cnl6xvERQzfO0Ey4q91SdsgK7i7FBrKKmi2wGiemFvnaQsrjZ_IFujLo8-2c8g9zTiyH1knyoVOAAnQxqGpsz6z6PNfSxr3_G8tOlNFTV-yqN_LdVHMgXtXjn3U9koGsfMulyUcBDdR3d_0Yn6iEjBt77tbxKi2ry-0gQrB1fdGsgKjyE_tMrW8D_lQz0IXsVOzd2ixsFVXMFzD6OOD8JldV0FbA-VDAS-Tp_ezIZVp6lRq54XBgvsjzDyOmOgDbSOQN6SQmvxPnIsml1wgmtm80z-9gHBqmimHBtLKB6L7CtLmmPICMS2pX3eWOmakxscxqs8AVjijJdz_NYNfcdBeDj_fhm6dqD6iwk3EBZZfsrmMGdXtAMqf1r9ng9tsz-FriXwQiJ3IM3loBsk5DKr9CcaJtKSPuwDDlRynD2vwcD-XyF6YTQdSJa9fEcq-qXya2Scj4mqQ4RDemJgErdradRfwJfII3fWHh18XxmYVqi9Bwn3YRgwEadyo0-HjbNq6vJXi12igmP99ciRAfMVQLjfUfTwoOHj44Y2Ru_hPjJcvB6FIn6KLrrCSrZnrshFdFn4L36z1CrS8fbtdvrG3kdZQxsUJnMqttuwKRpLnDWTWkIwj_GRBFrzCFgbwGp1XYhemxggyKVuhZPfyyTIM9rhlPth6eGyrpYfap24Av_mGPRBLnzcjtpGbACGdKQL034kVmI7yENGvmY40KSrWsVG_BE9bSJhx0EptFsT2IxnxbuFD4hGb4fFag9V0BDiKpUoOZqIVqVO8cAp-5w4twvWZKkrhu16JNlLoXWMoFANrw-tp5LKSin1CUeRa4LWVI1GR8tRkIad_GnCHRv9JEMswlNy9wi2sDNsSxWT7WNasUW5-glgK9pR7d2pXGGOWfHj1U6CKIqmAiO3iw8igzhvyx_dAxMxPo \ No newline at end of file diff --git a/tests/features/journals/basic_folder/2020/08/29.txt b/tests/features/journals/basic_folder/2020/08/29.txt new file mode 100644 index 00000000..c8af54ca --- /dev/null +++ b/tests/features/journals/basic_folder/2020/08/29.txt @@ -0,0 +1,19 @@ +[2020-08-29 11:11:00 AM] Entry the first. +Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. diff --git a/tests/features/journals/basic_folder/2020/08/31.txt b/tests/features/journals/basic_folder/2020/08/31.txt new file mode 100644 index 00000000..826e7cdb --- /dev/null +++ b/tests/features/journals/basic_folder/2020/08/31.txt @@ -0,0 +1,23 @@ +[2020-08-31 02:32:00 PM] A second entry in what I hope to be a long series. * +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. diff --git a/tests/features/journals/basic_folder/2020/09/24.txt b/tests/features/journals/basic_folder/2020/09/24.txt new file mode 100644 index 00000000..2bd885ce --- /dev/null +++ b/tests/features/journals/basic_folder/2020/09/24.txt @@ -0,0 +1,11 @@ +[2020-09-24 09:14:00 AM] The third entry finally after weeks without writing. +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 diff --git a/tests/features/journals/basic_onefile.journal b/tests/features/journals/basic_onefile.journal new file mode 100644 index 00000000..0d988049 --- /dev/null +++ b/tests/features/journals/basic_onefile.journal @@ -0,0 +1,58 @@ +[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 pellentesque +augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu +consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In +commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget +venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + +Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo +ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse +potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget +molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus +hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis +feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum +urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget +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. + +[2020-08-31 14:32] A second entry in what I hope to be a long series. * + +Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo +vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, +vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, +eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id +lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, +egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. +Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. + +Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel +vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, +non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel +ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo +eros. + +Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non +tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. +Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum +quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum +interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. +Quisque auctor lacinia consectetur. + +[2020-09-24 09:14] The third entry finally after weeks without writing. + +I'm so excited about emojis. 💯 🎶 💩 + +Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. +Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla +eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis +dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. +Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis +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 diff --git a/tests/features/journals/brackets.journal b/tests/features/journals/brackets.journal new file mode 100644 index 00000000..4649ea3e --- /dev/null +++ b/tests/features/journals/brackets.journal @@ -0,0 +1,2 @@ +[2019-07-08 05:42] Entry subject +[1] line starting with 1 diff --git a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry new file mode 100644 index 00000000..066821bb --- /dev/null +++ b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry @@ -0,0 +1,56 @@ + + + + + Creation Date + 2013-10-27T02:27:27Z + Creator + + Device Agent + iPhone/iPhone3,1 + Generation Date + 2013-10-27T07:02:27Z + Host Name + omrt104001 + OS Agent + iOS/7.0.3 + Software Agent + Day One (iOS)/1.11.4 + + Entry Text + Some text. + Location + + Administrative Area + Östergötlands län + Country + Sverige + Latitude + 58.383400000000000 + Locality + City + Longitude + 15.577170000000000 + Place Name + Street + + Starred + + Time Zone + Europe/Stockholm + UUID + B40EE704E15846DE8D45C44118A4D511 + Weather + + Celsius + 12 + Description + Clear + Fahrenheit + 54 + IconName + sunnyn.png + + + diff --git a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry new file mode 100644 index 00000000..ea3efec5 --- /dev/null +++ b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry @@ -0,0 +1,52 @@ + + Creation Date + 2013-10-27T02:27:27Z + Creator + + Device Agent + iPhone/iPhone3,1 + Generation Date + 2013-10-27T07:02:27Z + Host Name + omrt104001 + OS Agent + iOS/7.0.3 + Software Agent + Day One (iOS)/1.11.4 + + Entry Text + This is not a valid plist. + Location + + Administrative Area + Östergötlands län + Country + Sverige + Latitude + 58.383400000000000 + Locality + City + Longitude + 15.577170000000000 + Place Name + Street + + Starred + + Time Zone + Europe/Stockholm + UUID + B40EE704E15846DE8D45C44118A4D511 + Weather + + Celsius + 12 + Description + Clear + Fahrenheit + 54 + IconName + sunnyn.png + + + diff --git a/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry b/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry new file mode 100644 index 00000000..426f1ea8 --- /dev/null +++ b/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry @@ -0,0 +1,33 @@ + + + + + Activity + Stationary + Creation Date + 2019-12-30T21:28:54Z + Entry Text + + Starred + + UUID + 48A25033B34047C591160A4480197D8B + Creator + + Device Agent + PC + Generation Date + 2019-12-30T21:28:54Z + Host Name + LE-TREPORT + OS Agent + Microsoft Windows/10 Home + Software Agent + Journaley/2.1 + + Tags + + i_have_no_body + + + diff --git a/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry b/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry new file mode 100644 index 00000000..1ac26242 --- /dev/null +++ b/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry @@ -0,0 +1,34 @@ + + + + + Creation Date + 2013-05-17T18:39:20Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:39:20Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry has tags! + Starred + + Tags + + work + PLaY + + Time Zone + America/Los_Angeles + UUID + 044F3747A38546168B572C2E3F217FA2 + + diff --git a/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry b/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry new file mode 100644 index 00000000..927de884 --- /dev/null +++ b/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry @@ -0,0 +1,46 @@ + + + + + Creation Date + 2013-06-17T18:38:29Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:38:29Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry has a location. + Location + + Administrative Area + California + Country + Germany + Latitude + 52.4979764 + Locality + Berlin + Longitude + 13.2404758 + Place Name + Abandoned Spy Tower + + Starred + + Tags + + Time Zone + Europe/Berlin + UUID + 0BDDD6CDA43C4A9AA2681517CC35AD9D + + diff --git a/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry b/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry new file mode 100644 index 00000000..16260763 --- /dev/null +++ b/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry @@ -0,0 +1,31 @@ + + + + + Creation Date + 2013-07-17T18:38:08Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:38:08Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This entry is starred! + Starred + + Tags + + Time Zone + America/Los_Angeles + UUID + 422BC895507944A291E6FC44FC6B8BFC + + diff --git a/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry b/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry new file mode 100644 index 00000000..9ebaf538 --- /dev/null +++ b/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry @@ -0,0 +1,29 @@ + + + + + Creation Date + 2013-01-17T18:37:50Z + Creator + + Device Agent + Macintosh/MacBookAir5,2 + Generation Date + 2013-08-17T18:37:50Z + Host Name + Egeria + OS Agent + Mac OS X/10.8.4 + Software Agent + Day One (Mac)/1.8 + + Entry Text + This is a DayOne entry without Timezone. + Starred + + Tags + + UUID + 4BB1F46946AD439996C9B59DE7C4DDC1 + + diff --git a/tests/features/journals/dayone_empty.dayone/entries/empty.txt b/tests/features/journals/dayone_empty.dayone/entries/empty.txt new file mode 100644 index 00000000..c86b8f66 --- /dev/null +++ b/tests/features/journals/dayone_empty.dayone/entries/empty.txt @@ -0,0 +1 @@ +This file exists to preserve the directory structure, but should be ignored by jrnl. diff --git a/tests/features/journals/deletion.journal b/tests/features/journals/deletion.journal new file mode 100644 index 00000000..c0fa689d --- /dev/null +++ b/tests/features/journals/deletion.journal @@ -0,0 +1,5 @@ +[2019-10-29 11:11] First entry. + +[2019-10-29 11:11] Second entry. + +[2019-10-29 11:13] Third entry. \ No newline at end of file diff --git a/tests/features/journals/deletion_filters.journal b/tests/features/journals/deletion_filters.journal new file mode 100644 index 00000000..9a3747db --- /dev/null +++ b/tests/features/journals/deletion_filters.journal @@ -0,0 +1,14 @@ +[2019-10-01 08:00] It's just another day in October. +Not much to write about. + +[2020-01-01 08:00] Happy New Year! +So this is the New Year. @holidays + +[2020-03-01 08:00] It's just another day in March. +A stick, a stone, it's the end of the road. + +[2020-05-01 09:00] Happy May Day! +@holidays @springtime Several holidays fall on this date. + +[2020-05-02 12:10] Writing tests. * +@springtime They will help prevent bugs. diff --git a/tests/features/journals/empty_folder/empty b/tests/features/journals/empty_folder/empty new file mode 100644 index 00000000..175b82b5 --- /dev/null +++ b/tests/features/journals/empty_folder/empty @@ -0,0 +1 @@ +Nothing to see here diff --git a/tests/features/journals/encrypted.journal b/tests/features/journals/encrypted.journal new file mode 100644 index 00000000..d2a5fcbe --- /dev/null +++ b/tests/features/journals/encrypted.journal @@ -0,0 +1 @@ +gAAAAABVIHB7tnwKExG7aC5ZbAbBL9SG2oY2GENeoOJ22i1PZigOvCYvrQN3kpsu0KGr7ay5K-_46R5YFlqJvtQ8anPH2FSITsaZy-l5Lz_5quw3rmzhLwAR1tc0icgtR4MEpXEdsuQ7cyb12Xq-JLDrnATs0id5Vow9Ri_tE7Xe4BXgXaySn3aRPwWKoninVxVPVvETY3MXHSUEXV9OZ-pH5kYBLGYbLA== diff --git a/tests/features/journals/encrypted_jrnl-1-9-5.journal b/tests/features/journals/encrypted_jrnl-1-9-5.journal new file mode 100644 index 0000000000000000000000000000000000000000..339b47baf9671f4550efeb9b6a0cfcd5032255d6 GIT binary patch literal 128 zcmV-`0Du3(bJIGVsY(mXmoW-2hF&*L`0NbJTYlTUr8*^Qm97}8E^3^1bZ$P^M literal 0 HcmV?d00001 diff --git a/tests/features/journals/little_endian_dates.journal b/tests/features/journals/little_endian_dates.journal new file mode 100644 index 00000000..d7492969 --- /dev/null +++ b/tests/features/journals/little_endian_dates.journal @@ -0,0 +1,5 @@ +[09.06.2013 15:39] My first entry. +Everything is alright + +[10.07.2013 15:40] Life is good. +But I'm better. diff --git a/tests/features/journals/markdown-headings-335.journal b/tests/features/journals/markdown-headings-335.journal new file mode 100644 index 00000000..30f592ef --- /dev/null +++ b/tests/features/journals/markdown-headings-335.journal @@ -0,0 +1,42 @@ +[2015-04-14 13:23] Heading Test + +H1-1 += + +H1-2 +=== + +H1-3 +============================ + +H2-1 +- + +H2-2 +--- + +H2-3 +---------------------------------- + +Horizontal Rules (ignore) + +--- + +=== + +# ATX H1 + +## ATX H2 + +### ATX H3 + +#### ATX H4 + +##### ATX H5 + +###### ATX H6 + +Stuff + +More stuff +more stuff again diff --git a/tests/features/journals/mostlyreadabledates.journal b/tests/features/journals/mostlyreadabledates.journal new file mode 100644 index 00000000..bd211bf5 --- /dev/null +++ b/tests/features/journals/mostlyreadabledates.journal @@ -0,0 +1,8 @@ +[2019-07-18 14:23] Entry subject +Time machines are possible. I know, because I've built one in my garage. + +[2019-07-19 14:23] Entry subject +I'm going to activate the machine. Nobody knows what comes next after this. Or before this? + +[2019-07 14:23] Entry subject +I've crossed so many timelines. Is there any going back? diff --git a/tests/features/journals/multiline-tags.journal b/tests/features/journals/multiline-tags.journal new file mode 100644 index 00000000..1fb8706f --- /dev/null +++ b/tests/features/journals/multiline-tags.journal @@ -0,0 +1,7 @@ +[2013-06-09 15:39] Multiple @line entry with @tags. +Tag with @punctuation. afterwards +@TagOnLineAloneWithOutPunctuation +@TagOnLineAloneWithPunctuation. +Text before @tag. And After. +@hi. Hello +hi Hello \ No newline at end of file diff --git a/tests/features/journals/multiline.journal b/tests/features/journals/multiline.journal new file mode 100644 index 00000000..294ed141 --- /dev/null +++ b/tests/features/journals/multiline.journal @@ -0,0 +1,5 @@ +[2013-06-09 15:39] Multiple line entry. +This is the first line. +This line doesn't have any ending punctuation + +There is a blank line above this. diff --git a/tests/features/journals/simple.journal b/tests/features/journals/simple.journal new file mode 100644 index 00000000..8336068e --- /dev/null +++ b/tests/features/journals/simple.journal @@ -0,0 +1,5 @@ +[2013-06-09 15:39] My first entry. +Everything is alright + +[2013-06-10 15:40] Life is good. +But I'm better. diff --git a/tests/features/journals/simple_jrnl-1-9-5.journal b/tests/features/journals/simple_jrnl-1-9-5.journal new file mode 100644 index 00000000..7bb6c5ac --- /dev/null +++ b/tests/features/journals/simple_jrnl-1-9-5.journal @@ -0,0 +1,13 @@ +2010-06-10 15:00 A life without chocolate is like a bad analogy. + +2013-06-10 15:40 He said "[this] is the best time to be alive". +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. + +[2019-08-03 12:55] Some chat log or something + +Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, +elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus +placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor +dui. diff --git a/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal b/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal new file mode 100644 index 00000000..328b23f4 --- /dev/null +++ b/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal @@ -0,0 +1,13 @@ +10.06.2010 15:00 A life without chocolate is like a bad analogy. + +10.06.2013 15:40 He said "[this] is the best time to be alive". +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada +quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque +augue et venenatis facilisis. + +[03.08.2019 12:55] Some chat log or something + +Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, +elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus +placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor +dui. diff --git a/tests/features/journals/tags-216.journal b/tests/features/journals/tags-216.journal new file mode 100644 index 00000000..08b6d630 --- /dev/null +++ b/tests/features/journals/tags-216.journal @@ -0,0 +1,2 @@ +[2013-06-10 15:40] I programmed for @OS/2. +Almost makes me want to go back to @C++, though. (Still better than @C#). diff --git a/tests/features/journals/tags-237.journal b/tests/features/journals/tags-237.journal new file mode 100644 index 00000000..be050652 --- /dev/null +++ b/tests/features/journals/tags-237.journal @@ -0,0 +1,3 @@ +[2014-07-22 11:11] This entry has an email. +@Newline tag should show as a tag. +Kyla's @email is kyla@clevelandunderdog.org and Guinness's is guinness@fortheloveofpits.org. diff --git a/tests/features/journals/tags.journal b/tests/features/journals/tags.journal new file mode 100644 index 00000000..a28f3159 --- /dev/null +++ b/tests/features/journals/tags.journal @@ -0,0 +1,8 @@ +[2013-04-09 15:39] I have an @idea: +(1) write a command line @journal software +(2) ??? +(3) PROFIT! + +[2013-06-10 15:40] I met with @dan. +As alway's he shared his latest @idea on how to rule the world with me. +inst diff --git a/tests/features/journals/unreadabledates.journal b/tests/features/journals/unreadabledates.journal new file mode 100644 index 00000000..53ef1d60 --- /dev/null +++ b/tests/features/journals/unreadabledates.journal @@ -0,0 +1,5 @@ +[ashasd7zdskhz7asdkjasd] Entry subject +I've lost track of time. + +[sadfhakjsdf88sdf7sdff] Entry subject +Time has no meaning. diff --git a/tests/features/journals/work.journal b/tests/features/journals/work.journal new file mode 100644 index 00000000..e69de29b diff --git a/tests/features/multiple_journals.feature b/tests/features/multiple_journals.feature new file mode 100644 index 00000000..222be100 --- /dev/null +++ b/tests/features/multiple_journals.feature @@ -0,0 +1,65 @@ +Feature: Multiple journals + + Scenario: Loading a config with two journals + Given we use the config "multiple.yaml" + Then journal "default" should have 2 entries + And journal "work" should have 0 entries + + Scenario: Write to default config by default + Given we use the config "multiple.yaml" + When we run "jrnl this goes to default" + Then journal "default" should have 3 entries + And journal "work" should have 0 entries + + Scenario: Write to specified journal + Given we use the config "multiple.yaml" + When we run "jrnl work a long day in the office" + Then journal "default" should have 2 entries + And journal "work" should have 1 entry + + Scenario: Tell user which journal was used + Given we use the config "multiple.yaml" + When we run "jrnl work a long day in the office" + Then we should see the message "Entry added to work journal" + + Scenario: Write to specified journal with a timestamp + Given we use the config "multiple.yaml" + When we run "jrnl work 23 july 2012: a long day in the office" + Then journal "default" should have 2 entries + And journal "work" should have 1 entry + And journal "work" should contain "2012-07-23" + + Scenario: Write to specified journal without a timestamp but with colon + Given we use the config "multiple.yaml" + When we run "jrnl work : a long day in the office" + Then journal "default" should have 2 entries + And journal "work" should have 1 entry + And journal "work" should contain "a long day in the office" + + Scenario: Write to specified journal without a timestamp but with colon + Given we use the config "multiple.yaml" + When we run "jrnl work: a long day in the office" + Then journal "default" should have 2 entries + And journal "work" should have 1 entry + And journal "work" should contain "a long day in the office" + + Scenario: Create new journals as required + Given we use the config "multiple.yaml" + Then journal "ideas" should not exist + When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money" + Then journal "ideas" should have 1 entry + + Scenario: Don't crash if no default journal is specified + Given we use the config "bug343.yaml" + When we run "jrnl a long day in the office" + Then we should see the message "No default journal configured" + + Scenario: Don't crash if no file exists for a configured encrypted journal + Given we use the config "multiple.yaml" + When we run "jrnl new_encrypted Adding first entry" and enter + """ + these three eyes + these three eyes + n + """ + Then we should see the message "Encrypted journal 'new_encrypted' created" diff --git a/tests/features/password.feature b/tests/features/password.feature new file mode 100644 index 00000000..332ba86e --- /dev/null +++ b/tests/features/password.feature @@ -0,0 +1,116 @@ +Feature: Using the installed keyring + + Scenario: Storing a password in keyring + Given we use the config "multiple.yaml" + And we have a keyring + When we run "jrnl simple --encrypt" and enter + """ + sabertooth + sabertooth + y + """ + Then the config for journal "simple" should have "encrypt" set to "bool:True" + When we run "jrnl simple -n 1" + Then the output should contain "2013-06-10 15:40 Life is good" + + Scenario: Encrypt journal with no keyring backend and do not store in keyring + Given we use the config "simple.yaml" + And we do not have a keyring + When we run "jrnl test entry" + And we run "jrnl --encrypt" and enter + """ + password + password + n + """ + Then we should get no error + And we should not see the message "Failed to retrieve keyring" + + Scenario: Encrypt journal with no keyring backend and do store in keyring + Given we use the config "simple.yaml" + And we do not have a keyring + When we run "jrnl test entry" + And we run "jrnl --encrypt" and enter + """ + password + password + y + """ + Then we should get no error + And we should not see the message "Failed to retrieve keyring" + # @todo add step to check contents of keyring + + @todo + Scenario: Open an encrypted journal with wrong password in keyring + # This should ask the user for the password after the keyring fails + + @todo + Scenario: Decrypt journal with password in keyring + + @todo + Scenario: Decrypt journal without a keyring + + Scenario: Encrypt journal when keyring exists but fails + Given we use the config "simple.yaml" + And we have a failed keyring + When we run "jrnl --encrypt" and enter + """ + this password will not be saved in keyring + this password will not be saved in keyring + y + """ + Then we should see the message "Failed to retrieve keyring" + And we should get no error + And we should be prompted for a password + And the config for journal "default" should have "encrypt" set to "bool:True" + + Scenario: Decrypt journal when keyring exists but fails + Given we use the config "encrypted.yaml" + And we have a failed keyring + When we run "jrnl --decrypt" and enter "bad doggie no biscuit" + Then we should see the message "Failed to retrieve keyring" + And we should get no error + And we should be prompted for a password + And we should see the message "Journal decrypted" + And the config for journal "default" should have "encrypt" set to "bool:False" + And the journal should have 2 entries + + Scenario: Open encrypted journal when keyring exists but fails + # This should ask the user for the password after the keyring fails + Given we use the config "encrypted.yaml" + And we have a failed keyring + When we run "jrnl -n 1" and enter "bad doggie no biscuit" + Then we should see the message "Failed to retrieve keyring" + And we should get no error + And we should be prompted for a password + And the output should contain "2013-06-10 15:40 Life is good" + + Scenario: Mistyping your password + Given we use the config "simple.yaml" + When we run "jrnl --encrypt" and enter + """ + swordfish + sordfish + """ + Then we should be prompted for a password + And we should see the message "Passwords did not match" + And the config for journal "default" should not have "encrypt" set + And the journal should have 2 entries + + Scenario: Mistyping your password, then getting it right + Given we use the config "simple.yaml" + When we run "jrnl --encrypt" and enter + """ + swordfish + sordfish + swordfish + swordfish + n + """ + Then we should be prompted for a password + And we should see the message "Passwords did not match" + And we should see the message "Journal encrypted" + And the config for journal "default" should have "encrypt" set to "bool:True" + When we run "jrnl -n 1" and enter "swordfish" + Then we should be prompted for a password + And the output should contain "2013-06-10 15:40 Life is good" diff --git a/tests/features/search.feature b/tests/features/search.feature new file mode 100644 index 00000000..22351b7e --- /dev/null +++ b/tests/features/search.feature @@ -0,0 +1,318 @@ +Feature: Searching in a journal + + Scenario Outline: Displaying entries using -on today should display entries created today + Given we use the config ".yaml" + When we run "jrnl today: Adding an entry right now." + Then we should see the message "Entry added" + When we run "jrnl -on today" + Then the output should contain "Adding an entry right now." + But the output should not contain "Everything is alright" + And the output should not contain "Life is good" + + Examples: configs + | config | + | simple | + | empty_folder | + | dayone | + + Scenario Outline: Displaying entries using -from day should display correct entries + Given we use the config ".yaml" + When we run "jrnl yesterday: This thing happened yesterday" + Then we should see the message "Entry added" + When we run "jrnl today at 11:59pm: Adding an entry right now." + Then we should see the message "Entry added" + When we run "jrnl tomorrow: A future entry." + Then we should see the message "Entry added" + When we run "jrnl -from today" + Then the output should contain "Adding an entry right now." + And the output should contain "A future entry." + And the output should not contain "This thing happened yesterday" + + Examples: configs + | config | + | simple | + | empty_folder | + | dayone | + + Scenario Outline: Displaying entries using -from and -to day should display correct entries + Given we use the config ".yaml" + When we run "jrnl yesterday: This thing happened yesterday" + Then we should see the message "Entry added" + When we run "jrnl today at 11:59pm: Adding an entry right now." + Then we should see the message "Entry added" + When we run "jrnl tomorrow: A future entry." + Then we should see the message "Entry added" + When we run "jrnl -from yesterday -to today" + Then the output should contain "This thing happened yesterday" + And the output should contain "Adding an entry right now." + And the output should not contain "A future entry." + + Examples: configs + | config | + | simple | + | empty_folder | + | dayone | + + Scenario Outline: Searching for a string + Given we use the config ".yaml" + When we run "jrnl -contains first --short" + Then we should get no error + And the output should be + """ + 2020-08-29 11:11 Entry the first. + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching for a string within tag results + Given we use the config ".yaml" + When we run "jrnl @tagone -contains maybe" + Then we should get no error + And the output should contain "maybe" + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching for a string within AND tag results + Given we use the config ".yaml" + When we run "jrnl -and @tagone @tagtwo -contains maybe" + Then we should get no error + And the output should contain "maybe" + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching for a string within NOT tag results + Given we use the config ".yaml" + When we run "jrnl -not @tagone -contains lonesome" + Then we should get no error + And the output should contain "lonesome" + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching for dates + Given we use the config ".yaml" + 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." + Then we flush the output + When we run "jrnl -on 'august 31 2020' --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_folder | + | basic_dayone | + + Scenario: Out of order entries to a Folder journal should be listed in date order + Given we use the config "empty_folder.yaml" + When we run "jrnl 3/7/2014 4:37pm: Second entry of journal." + Then we should see the message "Entry added" + When we run "jrnl 23 July 2013: Testing folder journal." + Then we should see the message "Entry added" + When we run "jrnl -2" + Then the output should be + """ + 2013-07-23 09:00 Testing folder journal. + + 2014-03-07 16:37 Second entry of journal. + """ + + Scenario Outline: Searching for all tags should show counts of each tag + Given we use the config ".yaml" + When we run "jrnl --tags" + Then we should get no error + And the output should be + """ + @tagtwo : 2 + @tagone : 2 + @tagthree : 1 + @ipsum : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Filtering journals should also filter tags + Given we use the config ".yaml" + When we run "jrnl -from 'september 2020' --tags" + Then we should get no error + And the output should be + """ + @tagthree : 1 + @tagone : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Excluding a tag should filter out all entries with that tag + Given we use the config ".yaml" + When we run "jrnl --tags -not @tagtwo" + Then the output should be + """ + @tagthree : 1 + @tagone : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Excluding multiple tags should filter out all entries with those tags + Given we use the config ".yaml" + When we run "jrnl --tags -not @tagone -not @tagthree" + Then the output should be + """ + @tagtwo : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario: DayOne tag searching should work with tags containing a mixture of upper and lower case. + # https://github.com/jrnl-org/jrnl/issues/354 + Given we use the config "dayone.yaml" + When we run "jrnl @plAy" + Then the output should contain "2013-05-17 11:39 This entry has tags!" + + Scenario: Loading a sample journal + Given we use the config "simple.yaml" + When we run "jrnl -2" + Then we should get no error + And the output should be + """ + 2013-06-09 15:39 My first entry. + | Everything is alright + + 2013-06-10 15:40 Life is good. + | But I'm better. + """ + + Scenario Outline: Searching by month + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl -month 9 --short" + Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." + And we flush the output + When we run "jrnl -month Sept --short" + Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." + And we flush the output + When we run "jrnl -month September --short" + Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching by day + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl -day 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 | + + Scenario Outline: Searching by year + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl 2019-01-01 01:01: I like this year." + And we run "jrnl -year 2019 --short" + Then the output should be "2019-01-01 01:01 I like this year." + And we flush the output + When we run "jrnl -year 19 --short" + Then the output should be "2019-01-01 01:01 I like this year." + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: Combining month, day, and year search terms + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl -month 08 -day 29 --short" + Then the output should be "2020-08-29 11:11 Entry the first." + And we flush the output + When we run "jrnl -day 29 -year 2020 --short" + Then the output should be "2020-08-29 11:11 Entry the first." + And we flush the output + When we run "jrnl -month 09 -year 2020 --short" + Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." + And we flush the output + When we run "jrnl -month 08 -day 29 -year 2020 --short" + Then the output should be "2020-08-29 11:11 Entry the first." + + Examples: configs + | config | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: Searching today in history + Given we use the config ".yaml" + And we use the password "test" if prompted + And we set current date and time to "2020-08-31 14:32" + When we run "jrnl 2019-08-31 01:01: Hi, from last year." + And we run "jrnl -today-in-history --short" + Then the output should be + """ + 2019-08-31 01:01 Hi, from last year. + 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 | + + Scenario: Loading a DayOne Journal + Given we use the config "dayone.yaml" + When we run "jrnl -from 'feb 2013'" + Then we should get no error + And the output should be + """ + 2013-05-17 11:39 This entry has tags! + + 2013-06-17 20:38 This entry has a location. + + 2013-07-17 11:38 This entry is starred! + """ diff --git a/tests/features/star.feature b/tests/features/star.feature new file mode 100644 index 00000000..f0188056 --- /dev/null +++ b/tests/features/star.feature @@ -0,0 +1,35 @@ +Feature: Starring entries + + Scenario Outline: Starring an entry will mark it in the journal file + Given we use the config ".yaml" + When we run "jrnl 20 july 2013 *: Best day of my life!" + Then we should see the message "Entry added" + When we run "jrnl -on 2013-07-20 -starred" + Then the output should contain "2013-07-20 09:00 Best day of my life!" + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone | + + Scenario Outline: Filtering by starred entries will show only starred entries + Given we use the config ".yaml" + When we run "jrnl -starred" + Then the output should be empty + When we run "jrnl 20 july 2013 *: Best day of my life!" + When we run "jrnl -starred" + Then the output should be "2013-07-20 09:00 Best day of my life!" + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone_empty | + + Scenario: Starring an entry will mark it in an encrypted journal + Given we use the config "encrypted.yaml" + When we run "jrnl 20 july 2013 *: Best day of my life!" and enter "bad doggie no biscuit" + Then we should see the message "Entry added" + When we run "jrnl -on 2013-07-20 -starred" and enter "bad doggie no biscuit" + Then the output should contain "2013-07-20 09:00 Best day of my life!" diff --git a/tests/features/tag.feature b/tests/features/tag.feature new file mode 100644 index 00000000..b7b687b5 --- /dev/null +++ b/tests/features/tag.feature @@ -0,0 +1,53 @@ +Feature: Tagging +# See search.feature for tag-related searches +# And format.feature for tag-related output + + Scenario Outline: Tags should allow certain special characters such as /, +, # + Given we use the config ".yaml" + When we run "jrnl 2020-09-26: This is an entry about @os/2 and @c++ and @c#" + When we run "jrnl --tags -on 2020-09-26" + Then we should get no error + And the output should be + """ + @os/2 : 1 + @c++ : 1 + @c# : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Emails addresses should not be parsed as tags + Given we use the config ".yaml" + When we run "jrnl 2020-09-26: The email address test@example.com does not seem to work for me" + When we run "jrnl 2020-09-26: The email address test@example.org also does not work for me" + When we run "jrnl 2020-09-26: I tried test@example.org and test@example.edu too" + Then we flush the output + When we run "jrnl --tags -on 2020-09-26" + Then we should get no error + And the output should be "[No tags found in journal.]" + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | + + Scenario Outline: Entry can start and end with tags + Given we use the config ".yaml" + When we run "jrnl 2020-09-26: @foo came over, we went to a @bar" + When we run "jrnl --tags -on 2020-09-26" + Then the output should be + """ + @foo : 1 + @bar : 1 + """ + + Examples: configs + | config | + | basic_onefile | + | basic_folder | + | basic_dayone | diff --git a/tests/features/templates/extension.md b/tests/features/templates/extension.md new file mode 100644 index 00000000..e69de29b diff --git a/tests/features/upgrade.feature b/tests/features/upgrade.feature new file mode 100644 index 00000000..fda47363 --- /dev/null +++ b/tests/features/upgrade.feature @@ -0,0 +1,71 @@ +Feature: Upgrading Journals from 1.x.x to 2.x.x + + Scenario: Upgrade and parse journals with square brackets + Given we use the config "upgrade_from_195.json" + When we run "jrnl -9" and enter "Y" + Then the journal should have 2 entries + And the output should contain + """ + 2010-06-10 15:00 A life without chocolate is like a bad analogy. + """ + And the output should contain + """ + 2013-06-10 15:40 He said "[this] is the best time to be alive". + """ + + Scenario: Upgrading a journal encrypted with jrnl 1.x + Given we use the config "encrypted_old.json" + When we run "jrnl -n 1" and enter + """ + Y + bad doggie no biscuit + bad doggie no biscuit + """ + Then we should be prompted for a password + And the output should contain "2013-06-10 15:40 Life is good" + + Scenario: Upgrading a config without colors to colors + Given we use the config "no_colors.yaml" + When we run "jrnl -n 1" + Then the config should have "colors" set to + """ + { + 'date':'none', + 'title':'none', + 'body':'none', + 'tags':'none' + } + """ + + Scenario: Upgrade and parse journals with little endian date format + Given we use the config "upgrade_from_195_little_endian_dates.json" + When we run "jrnl -9" and enter "Y" + Then the journal should have 2 entries + And the output should contain + """ + 10.06.2010 15:00 A life without chocolate is like a bad analogy. + """ + And the output should contain + """ + 10.06.2013 15:40 He said "[this] is the best time to be alive". + """ + + Scenario: Upgrade with missing journal + Given we use the config "upgrade_from_195_with_missing_journal.json" + When we run "jrnl -ls" and enter + """" + Y + """ + Then the output should contain "Error: features/journals/missing.journal does not exist." + And we should get no error + + Scenario: Upgrade with missing encrypted journal + Given we use the config "upgrade_from_195_with_missing_encrypted_journal.json" + When we run "jrnl -ls" and enter + """ + Y + bad doggie no biscuit + """ + Then the output should contain "Error: features/journals/missing.journal does not exist." + And the error output should contain "We're all done" + And we should get no error diff --git a/tests/features/write.feature b/tests/features/write.feature new file mode 100644 index 00000000..eb22e480 --- /dev/null +++ b/tests/features/write.feature @@ -0,0 +1,216 @@ +Feature: Writing new entries. + + Scenario Outline: Multiline entry with punctuation should keep title punctuation + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl This is. the title\\n This is the second line" + And we run "jrnl -n 1" + Then the output should contain "This is. the title" + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone | + | encrypted | + + Scenario Outline: Single line entry with period should be split at period + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl This is. the title" + And we run "jrnl -1" + Then the output should contain "| the title" + + Examples: configs + | config_file | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: CJK entry should be split at fullwidth period without following space. + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl 七転び。八起き" + And we run "jrnl -1" + Then the output should contain "| 八起き" + + Examples: configs + | config_file | + | basic_onefile | + | basic_encrypted | + | basic_folder | + | basic_dayone | + + Scenario Outline: Writing an entry from command line should store the entry + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." + Then we should see the message "Entry added" + When we run "jrnl -n 1" + Then the output should contain "2013-07-23 09:00 A cold and stormy day." + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone | + | encrypted | + + Scenario Outline: Writing a partial entry from command line with edit flag should go to the editor + Given we use the config ".yaml" + And we use the password "test" if prompted + When we run "jrnl this is a partial --edit" + Then we should see the message "Entry added" + Then the editor should have been called + And the editor file content should be + """ + this is a partial + """ + When we run "jrnl -n 1" + Then the output should contain "this is a partial" + + Examples: configs + | config_file | + | basic_onefile | + | basic_encrypted | + | basic_dayone | + | basic_folder | + + Scenario Outline: Writing an empty entry from the editor should yield "Nothing saved to file" message + Given we use the config ".yaml" + And we use the password "test" if prompted + When we open the editor and enter nothing + Then the error output should contain "[Nothing saved to file]" + + Examples: configs + | config_file | + | editor | + | editor_empty_folder | + | dayone | + | basic_encrypted | + | basic_onefile | + + @skip + Scenario Outline: Writing an empty entry from the command line with no editor should yield nothing + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl" and enter nothing + Then the output should be empty + And the error output should contain "Writing Entry; on a blank line" + And the editor should not have been called + + Examples: configs + | config_file | + | simple | + | empty_folder | + | encrypted | + # | dayone | @todo + + Scenario Outline: Writing an entry does not print the entire journal + # https://github.com/jrnl-org/jrnl/issues/87 + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." + Then we should see the message "Entry added" + When we run "jrnl -n 1" + Then the output should not contain "Life is good" + + Examples: configs + | config_file | + | editor | + | editor_empty_folder | + | dayone | + | encrypted | + + Scenario Outline: Embedded period stays in title + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic." + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should be + """ + 2014-04-24 09:00 Created a new website - empty.com. + | Hope to get a lot of traffic. + """ + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone | + | encrypted | + + Scenario Outline: Write and read emoji support + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘" + Then we should see the message "Entry added" + When we run "jrnl -n 1" + Then the output should contain "🌞" + And the output should contain "🐘" + + Examples: configs + | config_file | + | simple | + | empty_folder | + | dayone | + | encrypted | + + Scenario Outline: Writing an entry at the prompt (no editor) should store the entry + Given we use the config ".yaml" + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive." + Then we should get no error + When we run "jrnl -on '2013-07-25'" + Then the output should contain "2013-07-25 09:00 I saw Elvis." + And the output should contain "| He's alive." + + Examples: configs + | config_file | + | simple | + | empty_folder | + | encrypted | + + @todo + Scenario: Writing an entry at the prompt (no editor) in DayOne journal + # Need to test DayOne w/out an editor + + Scenario: Writing into Dayone + Given we use the config "dayone.yaml" + When we run "jrnl 01 may 1979: Being born hurts." + And we run "jrnl -until 1980" + Then the output should be "1979-05-01 09:00 Being born hurts." + + Scenario: Writing into Dayone adds extended metadata + Given we use the config "dayone.yaml" + When we run "jrnl 01 may 1979: Being born hurts." + And we run "jrnl --export json" + Then "entries" in the json output should have 5 elements + And the json output should contain entries.0.creator.software_agent + And the json output should contain entries.0.creator.os_agent + And the json output should contain entries.0.creator.host_name + And the json output should contain entries.0.creator.generation_date + And the json output should contain entries.0.creator.device_agent + And "entries.0.creator.software_agent" in the json output should contain "jrnl" + + # fails when system time is UTC (as on Travis-CI) + @skip + Scenario: Title with an embedded period on DayOne journal + Given we use the config "dayone.yaml" + When we run "jrnl 04-24-2014: "Ran 6.2 miles today in 1:02:03. I'm feeling sore because I forgot to stretch."" + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should be + """ + 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. + | I'm feeling sore because I forgot to stretch. + """ + + Scenario: Opening an folder that's not a DayOne folder should treat as folder journal + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 july 2013: Testing folder journal." + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should be "2013-07-23 09:00 Testing folder journal." diff --git a/tests/step_defs/__init__.py b/tests/step_defs/__init__.py new file mode 100644 index 00000000..46468510 --- /dev/null +++ b/tests/step_defs/__init__.py @@ -0,0 +1,3 @@ +import sys + +sys.path.append("..") diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py new file mode 100644 index 00000000..cf6a2d5e --- /dev/null +++ b/tests/step_defs/conftest.py @@ -0,0 +1,111 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import shutil +import os +import re + +import pytest +from pytest_bdd import given +from pytest_bdd import then +from pytest_bdd import when +from pytest_bdd.parsers import parse +from unittest.mock import patch + +from jrnl import __version__ +from jrnl.os_compat import split_args +from jrnl.cli import cli + +WORKING_DIR = '' +TEMP_DIR = '' + +# ----- FIXTURES ----- # +@pytest.fixture +def cli_run(): + return dict(status=0, stdout=None, stderr=None) + + +def get_working_dirs(request): + CWD = request.config.rootpath + return os.path.join(CWD, 'tests', '.current_test'), CWD + + +# ----- HOOKS ----- # +def pytest_bdd_before_scenario(request, feature, scenario): + """Before each scenario, backup all config and journal test data.""" + global TEMP_DIR + global WORKING_DIR + TEMP_DIR, WORKING_DIR = get_working_dirs(request) + + if not os.path.exists(TEMP_DIR): + os.mkdir(TEMP_DIR) + + +def pytest_bdd_after_scenario(request, feature, scenario): + """After each scenario, restore all test data and remove working_dirs.""" + TEMP_DIR, WORKING_DIR = get_working_dirs(request) + + if os.path.exists(TEMP_DIR): + shutil.rmtree(TEMP_DIR) + + +# ----- STEPS ----- # +@given(parse('we use the config "{config_file}"'), target_fixture="config_path") +def set_config(config_file): + # Copy the config file over + config_source = os.path.join(WORKING_DIR, 'features', 'data', 'configs', config_file) + config_dest = os.path.join(TEMP_DIR, config_file) + shutil.copy2(config_source, config_dest) + + # @todo make this only copy some journals over + # Copy all of the journals over + journal_source = os.path.join(WORKING_DIR, 'features', 'data', 'journals') + journal_dest = os.path.join(TEMP_DIR, 'features', 'journals') + shutil.copytree(journal_source, journal_dest, dirs_exist_ok=True) + + # @todo get rid of this by using default config values + # merge in version number + if config_file.endswith("yaml") and os.path.exists(config_dest): + # Add jrnl version to file for 2.x journals + with open(config_dest, "a") as cf: + cf.write("version: {}".format(__version__)) + + return config_dest + + +@when(parse('we run "{command}"')) +def run(command, config_path, cli_run, capsys): + args = split_args(command) + status = 0 + + # fmt: off + # see: https://github.com/psf/black/issues/664 + with \ + patch("sys.argv", args), \ + patch("jrnl.config.get_config_path", side_effect=lambda: config_path), \ + patch("jrnl.install.get_config_path", side_effect=lambda: config_path) \ + : + try: + cli(args[1:]) + except SystemExit as e: + status = e.code + # fmt: on + + cli_run['status'] = status + captured = capsys.readouterr() + cli_run['stdout'] = captured.out + cli_run['stderr'] = captured.err + + +@then("we should get no error") +def no_error(cli_run): + assert cli_run['status'] == 0, cli_run['status'] + + +@then(parse('the output should match "{regex}"')) +def matches_std_output(regex, cli_run): + out = cli_run['stdout'] + matches = re.findall(regex, out) + assert ( + matches + ), f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py new file mode 100644 index 00000000..d670f9c9 --- /dev/null +++ b/tests/step_defs/test_features.py @@ -0,0 +1,3 @@ +from pytest_bdd import scenarios + +scenarios("../features/core.feature") From 530190df7adff163c48ad7fd33d14d6ad1d877cc Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 13 Feb 2021 17:43:42 -0800 Subject: [PATCH 04/74] Implement handling of temp and working dirs Pytest-bdd uses fixtures to handle most things. This makes a fixture that will create a temp directory for the tests to run in. Co-authored-by: Micah Jerome Ellison --- tests/step_defs/conftest.py | 66 ++++++++++++++----------------------- 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index cf6a2d5e..93482ce9 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -4,8 +4,9 @@ import shutil import os import re +import tempfile -import pytest +from pytest import fixture from pytest_bdd import given from pytest_bdd import then from pytest_bdd import when @@ -16,52 +17,35 @@ from jrnl import __version__ from jrnl.os_compat import split_args from jrnl.cli import cli -WORKING_DIR = '' -TEMP_DIR = '' - # ----- FIXTURES ----- # -@pytest.fixture +@fixture def cli_run(): - return dict(status=0, stdout=None, stderr=None) + return {"status": 0, "stdout": None, "stderr": None} +@fixture +def temp_dir(): + return tempfile.TemporaryDirectory() -def get_working_dirs(request): - CWD = request.config.rootpath - return os.path.join(CWD, 'tests', '.current_test'), CWD - - -# ----- HOOKS ----- # -def pytest_bdd_before_scenario(request, feature, scenario): - """Before each scenario, backup all config and journal test data.""" - global TEMP_DIR - global WORKING_DIR - TEMP_DIR, WORKING_DIR = get_working_dirs(request) - - if not os.path.exists(TEMP_DIR): - os.mkdir(TEMP_DIR) - - -def pytest_bdd_after_scenario(request, feature, scenario): - """After each scenario, restore all test data and remove working_dirs.""" - TEMP_DIR, WORKING_DIR = get_working_dirs(request) - - if os.path.exists(TEMP_DIR): - shutil.rmtree(TEMP_DIR) +@fixture +def working_dir(request): + return os.path.join(request.config.rootpath, "tests") # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") -def set_config(config_file): +def set_config(config_file, temp_dir, working_dir): # Copy the config file over - config_source = os.path.join(WORKING_DIR, 'features', 'data', 'configs', config_file) - config_dest = os.path.join(TEMP_DIR, config_file) + config_source = os.path.join( + working_dir, "features", "data", "configs", config_file + ) + config_dest = os.path.join(temp_dir.name, config_file) shutil.copy2(config_source, config_dest) # @todo make this only copy some journals over # Copy all of the journals over - journal_source = os.path.join(WORKING_DIR, 'features', 'data', 'journals') - journal_dest = os.path.join(TEMP_DIR, 'features', 'journals') - shutil.copytree(journal_source, journal_dest, dirs_exist_ok=True) + journal_source = os.path.join(working_dir, "features", "data", "journals") + journal_dest = os.path.join(temp_dir.name, "features", "journals") + shutil.copytree(journal_source, journal_dest) # @todo get rid of this by using default config values # merge in version number @@ -91,21 +75,19 @@ def run(command, config_path, cli_run, capsys): status = e.code # fmt: on - cli_run['status'] = status + cli_run["status"] = status captured = capsys.readouterr() - cli_run['stdout'] = captured.out - cli_run['stderr'] = captured.err + cli_run["stdout"] = captured.out + cli_run["stderr"] = captured.err @then("we should get no error") def no_error(cli_run): - assert cli_run['status'] == 0, cli_run['status'] + assert cli_run["status"] == 0, cli_run["status"] @then(parse('the output should match "{regex}"')) def matches_std_output(regex, cli_run): - out = cli_run['stdout'] + out = cli_run["stdout"] matches = re.findall(regex, out) - assert ( - matches - ), f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" + assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" From 0b50ae1be064e32ca07470fe1b9020627a52dea7 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 13 Feb 2021 17:53:32 -0800 Subject: [PATCH 05/74] Rename features directory to data This is more inline with pytest standards Co-authored-by: Micah Jerome Ellison --- .../configs/basic_dayone.yaml | 0 .../configs/basic_encrypted.yaml | 0 .../configs/basic_folder.yaml | 0 .../configs/basic_onefile.yaml | 0 .../{features => data}/configs/brackets.yaml | 0 tests/{features => data}/configs/bug153.yaml | 0 tests/{features => data}/configs/bug343.yaml | 0 tests/{features => data}/configs/bug780.yaml | 0 tests/{features => data}/configs/dayone.yaml | 0 .../configs/dayone_empty.yaml | 0 .../{features => data}/configs/deletion.yaml | 0 .../configs/deletion_filters.yaml | 0 .../configs/editor-args.yaml | 0 tests/{features => data}/configs/editor.yaml | 0 .../configs/editor_empty_folder.yaml | 0 .../configs/editor_encrypted.yaml | 0 .../configs/empty_folder.yaml | 0 .../{features => data}/configs/encrypted.yaml | 0 .../configs/encrypted_old.json | 0 .../configs/encrypted_old.yaml | 0 .../{features => data}/configs/format_md.yaml | 0 .../configs/format_text.yaml | 0 .../configs/invalid_color.yaml | 0 .../configs/little_endian_dates.yaml | 0 .../configs/markdown-headings-335.yaml | 0 .../configs/missing_directory.yaml | 0 .../configs/missing_journal.yaml | 0 .../configs/mostlyreadabledates.yaml | 0 .../configs/multiline-tags.yaml | 0 .../{features => data}/configs/multiline.yaml | 0 .../{features => data}/configs/multiple.yaml | 0 .../{features => data}/configs/no_colors.yaml | 0 tests/{features => }/data/configs/simple.yaml | 0 .../{features => data}/configs/tags-216.yaml | 0 .../{features => data}/configs/tags-237.yaml | 0 tests/{features => data}/configs/tags.yaml | 0 .../configs/unreadabledates.yaml | 0 .../configs/upgrade_from_195.json | 0 .../upgrade_from_195_little_endian_dates.json | 0 ...om_195_with_missing_encrypted_journal.json | 0 ...upgrade_from_195_with_missing_journal.json | 0 .../D04D335AFED711EABA18FAFFC2100C3D.doentry | 0 .../FC8A86CAFED711EA8892FAFFC2100C3D.doentry | 0 .../FD8ABC8EFED711EABC35FAFFC2100C3D.doentry | 0 .../data/journals/basic_encrypted.journal | 0 .../data/journals/basic_folder/2020/08/29.txt | 0 .../data/journals/basic_folder/2020/08/31.txt | 0 .../data/journals/basic_folder/2020/09/24.txt | 0 .../data/journals/basic_onefile.journal | 0 .../data/journals/brackets.journal | 0 .../B40EE704E15846DE8D45C44118A4D511.doentry | 0 .../B40EE704E15846DE8D45C44118A4D512.doentry | 0 .../48A25033B34047C591160A4480197D8B.doentry | 0 .../044F3747A38546168B572C2E3F217FA2.doentry | 0 .../0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry | 0 .../422BC895507944A291E6FC44FC6B8BFC.doentry | 0 .../4BB1F46946AD439996C9B59DE7C4DDC1.doentry | 0 .../dayone_empty.dayone/entries/empty.txt | 0 .../data/journals/deletion.journal | 0 .../data/journals/deletion_filters.journal | 0 .../data/journals/empty_folder/empty | 0 .../data/journals/encrypted.journal | 0 .../journals/encrypted_jrnl-1-9-5.journal | Bin .../data/journals/little_endian_dates.journal | 0 .../journals/markdown-headings-335.journal | 0 .../data/journals/mostlyreadabledates.journal | 0 .../data/journals/multiline-tags.journal | 0 .../data/journals/multiline.journal | 0 .../data/journals/simple.journal | 0 .../data/journals/simple_jrnl-1-9-5.journal | 0 ...ple_jrnl-1-9-5_little_endian_dates.journal | 0 .../data/journals/tags-216.journal | 0 .../data/journals/tags-237.journal | 0 .../{features => }/data/journals/tags.journal | 0 .../data/journals/unreadabledates.journal | 0 .../{features => }/data/journals/work.journal | 0 .../data/templates/sample.template | 0 .../configs/editor_markdown_extension.yaml | 18 ------ tests/features/configs/simple.yaml | 18 ------ tests/features/core.feature | 1 + tests/features/data/configs/basic_dayone.yaml | 17 ----- .../data/configs/basic_encrypted.yaml | 17 ----- tests/features/data/configs/basic_folder.yaml | 17 ----- .../features/data/configs/basic_onefile.yaml | 17 ----- tests/features/data/configs/brackets.yaml | 12 ---- tests/features/data/configs/bug153.yaml | 17 ----- tests/features/data/configs/bug343.yaml | 13 ---- tests/features/data/configs/bug780.yaml | 12 ---- tests/features/data/configs/dayone.yaml | 12 ---- tests/features/data/configs/dayone_empty.yaml | 17 ----- tests/features/data/configs/deletion.yaml | 12 ---- .../data/configs/deletion_filters.yaml | 12 ---- tests/features/data/configs/editor-args.yaml | 12 ---- tests/features/data/configs/editor.yaml | 12 ---- .../data/configs/editor_empty_folder.yaml | 12 ---- .../data/configs/editor_encrypted.yaml | 17 ----- tests/features/data/configs/empty_folder.yaml | 12 ---- tests/features/data/configs/encrypted.yaml | 12 ---- .../features/data/configs/encrypted_old.json | 13 ---- .../features/data/configs/encrypted_old.yaml | 11 ---- tests/features/data/configs/format_md.yaml | 19 ------ tests/features/data/configs/format_text.yaml | 19 ------ .../features/data/configs/invalid_color.yaml | 17 ----- .../data/configs/little_endian_dates.yaml | 12 ---- .../data/configs/markdown-headings-335.yaml | 17 ----- .../data/configs/missing_directory.yaml | 17 ----- .../data/configs/missing_journal.yaml | 17 ----- .../data/configs/mostlyreadabledates.yaml | 12 ---- .../features/data/configs/multiline-tags.yaml | 17 ----- tests/features/data/configs/multiline.yaml | 17 ----- tests/features/data/configs/multiple.yaml | 18 ------ tests/features/data/configs/no_colors.yaml | 12 ---- tests/features/data/configs/tags-216.yaml | 17 ----- tests/features/data/configs/tags-237.yaml | 17 ----- tests/features/data/configs/tags.yaml | 17 ----- .../data/configs/unreadabledates.yaml | 17 ----- .../data/configs/upgrade_from_195.json | 11 ---- .../upgrade_from_195_little_endian_dates.json | 11 ---- ...om_195_with_missing_encrypted_journal.json | 11 ---- ...upgrade_from_195_with_missing_journal.json | 11 ---- tests/features/environment.py | 0 .../D04D335AFED711EABA18FAFFC2100C3D.doentry | 53 ---------------- .../FC8A86CAFED711EA8892FAFFC2100C3D.doentry | 55 ----------------- .../FD8ABC8EFED711EABC35FAFFC2100C3D.doentry | 44 ------------- .../features/journals/basic_encrypted.journal | 1 - .../journals/basic_folder/2020/08/29.txt | 19 ------ .../journals/basic_folder/2020/08/31.txt | 23 ------- .../journals/basic_folder/2020/09/24.txt | 11 ---- tests/features/journals/basic_onefile.journal | 58 ------------------ tests/features/journals/brackets.journal | 2 - .../B40EE704E15846DE8D45C44118A4D511.doentry | 56 ----------------- .../B40EE704E15846DE8D45C44118A4D512.doentry | 52 ---------------- .../48A25033B34047C591160A4480197D8B.doentry | 33 ---------- .../044F3747A38546168B572C2E3F217FA2.doentry | 34 ---------- .../0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry | 46 -------------- .../422BC895507944A291E6FC44FC6B8BFC.doentry | 31 ---------- .../4BB1F46946AD439996C9B59DE7C4DDC1.doentry | 29 --------- .../dayone_empty.dayone/entries/empty.txt | 1 - tests/features/journals/deletion.journal | 5 -- .../journals/deletion_filters.journal | 14 ----- tests/features/journals/empty_folder/empty | 1 - tests/features/journals/encrypted.journal | 1 - .../journals/encrypted_jrnl-1-9-5.journal | Bin 128 -> 0 bytes .../journals/little_endian_dates.journal | 5 -- .../journals/markdown-headings-335.journal | 42 ------------- .../journals/mostlyreadabledates.journal | 8 --- .../features/journals/multiline-tags.journal | 7 --- tests/features/journals/multiline.journal | 5 -- tests/features/journals/simple.journal | 5 -- .../journals/simple_jrnl-1-9-5.journal | 13 ---- ...ple_jrnl-1-9-5_little_endian_dates.journal | 13 ---- tests/features/journals/tags-216.journal | 2 - tests/features/journals/tags-237.journal | 3 - tests/features/journals/tags.journal | 8 --- .../features/journals/unreadabledates.journal | 5 -- tests/features/journals/work.journal | 0 tests/features/templates/extension.md | 0 tests/step_defs/conftest.py | 6 +- 158 files changed, 4 insertions(+), 1306 deletions(-) rename tests/{features => data}/configs/basic_dayone.yaml (100%) rename tests/{features => data}/configs/basic_encrypted.yaml (100%) rename tests/{features => data}/configs/basic_folder.yaml (100%) rename tests/{features => data}/configs/basic_onefile.yaml (100%) rename tests/{features => data}/configs/brackets.yaml (100%) rename tests/{features => data}/configs/bug153.yaml (100%) rename tests/{features => data}/configs/bug343.yaml (100%) rename tests/{features => data}/configs/bug780.yaml (100%) rename tests/{features => data}/configs/dayone.yaml (100%) rename tests/{features => data}/configs/dayone_empty.yaml (100%) rename tests/{features => data}/configs/deletion.yaml (100%) rename tests/{features => data}/configs/deletion_filters.yaml (100%) rename tests/{features => data}/configs/editor-args.yaml (100%) rename tests/{features => data}/configs/editor.yaml (100%) rename tests/{features => data}/configs/editor_empty_folder.yaml (100%) rename tests/{features => data}/configs/editor_encrypted.yaml (100%) rename tests/{features => data}/configs/empty_folder.yaml (100%) rename tests/{features => data}/configs/encrypted.yaml (100%) rename tests/{features => data}/configs/encrypted_old.json (100%) rename tests/{features => data}/configs/encrypted_old.yaml (100%) rename tests/{features => data}/configs/format_md.yaml (100%) rename tests/{features => data}/configs/format_text.yaml (100%) rename tests/{features => data}/configs/invalid_color.yaml (100%) rename tests/{features => data}/configs/little_endian_dates.yaml (100%) rename tests/{features => data}/configs/markdown-headings-335.yaml (100%) rename tests/{features => data}/configs/missing_directory.yaml (100%) rename tests/{features => data}/configs/missing_journal.yaml (100%) rename tests/{features => data}/configs/mostlyreadabledates.yaml (100%) rename tests/{features => data}/configs/multiline-tags.yaml (100%) rename tests/{features => data}/configs/multiline.yaml (100%) rename tests/{features => data}/configs/multiple.yaml (100%) rename tests/{features => data}/configs/no_colors.yaml (100%) rename tests/{features => }/data/configs/simple.yaml (100%) rename tests/{features => data}/configs/tags-216.yaml (100%) rename tests/{features => data}/configs/tags-237.yaml (100%) rename tests/{features => data}/configs/tags.yaml (100%) rename tests/{features => data}/configs/unreadabledates.yaml (100%) rename tests/{features => data}/configs/upgrade_from_195.json (100%) rename tests/{features => data}/configs/upgrade_from_195_little_endian_dates.json (100%) rename tests/{features => data}/configs/upgrade_from_195_with_missing_encrypted_journal.json (100%) rename tests/{features => data}/configs/upgrade_from_195_with_missing_journal.json (100%) rename tests/{features => }/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry (100%) rename tests/{features => }/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry (100%) rename tests/{features => }/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry (100%) rename tests/{features => }/data/journals/basic_encrypted.journal (100%) rename tests/{features => }/data/journals/basic_folder/2020/08/29.txt (100%) rename tests/{features => }/data/journals/basic_folder/2020/08/31.txt (100%) rename tests/{features => }/data/journals/basic_folder/2020/09/24.txt (100%) rename tests/{features => }/data/journals/basic_onefile.journal (100%) rename tests/{features => }/data/journals/brackets.journal (100%) rename tests/{features => }/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry (100%) rename tests/{features => }/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry (100%) rename tests/{features => }/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry (100%) rename tests/{features => }/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry (100%) rename tests/{features => }/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry (100%) rename tests/{features => }/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry (100%) rename tests/{features => }/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry (100%) rename tests/{features => }/data/journals/dayone_empty.dayone/entries/empty.txt (100%) rename tests/{features => }/data/journals/deletion.journal (100%) rename tests/{features => }/data/journals/deletion_filters.journal (100%) rename tests/{features => }/data/journals/empty_folder/empty (100%) rename tests/{features => }/data/journals/encrypted.journal (100%) rename tests/{features => }/data/journals/encrypted_jrnl-1-9-5.journal (100%) rename tests/{features => }/data/journals/little_endian_dates.journal (100%) rename tests/{features => }/data/journals/markdown-headings-335.journal (100%) rename tests/{features => }/data/journals/mostlyreadabledates.journal (100%) rename tests/{features => }/data/journals/multiline-tags.journal (100%) rename tests/{features => }/data/journals/multiline.journal (100%) rename tests/{features => }/data/journals/simple.journal (100%) rename tests/{features => }/data/journals/simple_jrnl-1-9-5.journal (100%) rename tests/{features => }/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal (100%) rename tests/{features => }/data/journals/tags-216.journal (100%) rename tests/{features => }/data/journals/tags-237.journal (100%) rename tests/{features => }/data/journals/tags.journal (100%) rename tests/{features => }/data/journals/unreadabledates.journal (100%) rename tests/{features => }/data/journals/work.journal (100%) rename tests/{features => }/data/templates/sample.template (100%) delete mode 100644 tests/features/configs/editor_markdown_extension.yaml delete mode 100644 tests/features/configs/simple.yaml delete mode 100644 tests/features/data/configs/basic_dayone.yaml delete mode 100644 tests/features/data/configs/basic_encrypted.yaml delete mode 100644 tests/features/data/configs/basic_folder.yaml delete mode 100644 tests/features/data/configs/basic_onefile.yaml delete mode 100644 tests/features/data/configs/brackets.yaml delete mode 100644 tests/features/data/configs/bug153.yaml delete mode 100644 tests/features/data/configs/bug343.yaml delete mode 100644 tests/features/data/configs/bug780.yaml delete mode 100644 tests/features/data/configs/dayone.yaml delete mode 100644 tests/features/data/configs/dayone_empty.yaml delete mode 100644 tests/features/data/configs/deletion.yaml delete mode 100644 tests/features/data/configs/deletion_filters.yaml delete mode 100644 tests/features/data/configs/editor-args.yaml delete mode 100644 tests/features/data/configs/editor.yaml delete mode 100644 tests/features/data/configs/editor_empty_folder.yaml delete mode 100644 tests/features/data/configs/editor_encrypted.yaml delete mode 100644 tests/features/data/configs/empty_folder.yaml delete mode 100644 tests/features/data/configs/encrypted.yaml delete mode 100644 tests/features/data/configs/encrypted_old.json delete mode 100644 tests/features/data/configs/encrypted_old.yaml delete mode 100644 tests/features/data/configs/format_md.yaml delete mode 100644 tests/features/data/configs/format_text.yaml delete mode 100644 tests/features/data/configs/invalid_color.yaml delete mode 100644 tests/features/data/configs/little_endian_dates.yaml delete mode 100644 tests/features/data/configs/markdown-headings-335.yaml delete mode 100644 tests/features/data/configs/missing_directory.yaml delete mode 100644 tests/features/data/configs/missing_journal.yaml delete mode 100644 tests/features/data/configs/mostlyreadabledates.yaml delete mode 100644 tests/features/data/configs/multiline-tags.yaml delete mode 100644 tests/features/data/configs/multiline.yaml delete mode 100644 tests/features/data/configs/multiple.yaml delete mode 100644 tests/features/data/configs/no_colors.yaml delete mode 100644 tests/features/data/configs/tags-216.yaml delete mode 100644 tests/features/data/configs/tags-237.yaml delete mode 100644 tests/features/data/configs/tags.yaml delete mode 100644 tests/features/data/configs/unreadabledates.yaml delete mode 100644 tests/features/data/configs/upgrade_from_195.json delete mode 100644 tests/features/data/configs/upgrade_from_195_little_endian_dates.json delete mode 100644 tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json delete mode 100644 tests/features/data/configs/upgrade_from_195_with_missing_journal.json delete mode 100644 tests/features/environment.py delete mode 100644 tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry delete mode 100644 tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry delete mode 100644 tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry delete mode 100644 tests/features/journals/basic_encrypted.journal delete mode 100644 tests/features/journals/basic_folder/2020/08/29.txt delete mode 100644 tests/features/journals/basic_folder/2020/08/31.txt delete mode 100644 tests/features/journals/basic_folder/2020/09/24.txt delete mode 100644 tests/features/journals/basic_onefile.journal delete mode 100644 tests/features/journals/brackets.journal delete mode 100644 tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry delete mode 100644 tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry delete mode 100644 tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry delete mode 100644 tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry delete mode 100644 tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry delete mode 100644 tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry delete mode 100644 tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry delete mode 100644 tests/features/journals/dayone_empty.dayone/entries/empty.txt delete mode 100644 tests/features/journals/deletion.journal delete mode 100644 tests/features/journals/deletion_filters.journal delete mode 100644 tests/features/journals/empty_folder/empty delete mode 100644 tests/features/journals/encrypted.journal delete mode 100644 tests/features/journals/encrypted_jrnl-1-9-5.journal delete mode 100644 tests/features/journals/little_endian_dates.journal delete mode 100644 tests/features/journals/markdown-headings-335.journal delete mode 100644 tests/features/journals/mostlyreadabledates.journal delete mode 100644 tests/features/journals/multiline-tags.journal delete mode 100644 tests/features/journals/multiline.journal delete mode 100644 tests/features/journals/simple.journal delete mode 100644 tests/features/journals/simple_jrnl-1-9-5.journal delete mode 100644 tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal delete mode 100644 tests/features/journals/tags-216.journal delete mode 100644 tests/features/journals/tags-237.journal delete mode 100644 tests/features/journals/tags.journal delete mode 100644 tests/features/journals/unreadabledates.journal delete mode 100644 tests/features/journals/work.journal delete mode 100644 tests/features/templates/extension.md diff --git a/tests/features/configs/basic_dayone.yaml b/tests/data/configs/basic_dayone.yaml similarity index 100% rename from tests/features/configs/basic_dayone.yaml rename to tests/data/configs/basic_dayone.yaml diff --git a/tests/features/configs/basic_encrypted.yaml b/tests/data/configs/basic_encrypted.yaml similarity index 100% rename from tests/features/configs/basic_encrypted.yaml rename to tests/data/configs/basic_encrypted.yaml diff --git a/tests/features/configs/basic_folder.yaml b/tests/data/configs/basic_folder.yaml similarity index 100% rename from tests/features/configs/basic_folder.yaml rename to tests/data/configs/basic_folder.yaml diff --git a/tests/features/configs/basic_onefile.yaml b/tests/data/configs/basic_onefile.yaml similarity index 100% rename from tests/features/configs/basic_onefile.yaml rename to tests/data/configs/basic_onefile.yaml diff --git a/tests/features/configs/brackets.yaml b/tests/data/configs/brackets.yaml similarity index 100% rename from tests/features/configs/brackets.yaml rename to tests/data/configs/brackets.yaml diff --git a/tests/features/configs/bug153.yaml b/tests/data/configs/bug153.yaml similarity index 100% rename from tests/features/configs/bug153.yaml rename to tests/data/configs/bug153.yaml diff --git a/tests/features/configs/bug343.yaml b/tests/data/configs/bug343.yaml similarity index 100% rename from tests/features/configs/bug343.yaml rename to tests/data/configs/bug343.yaml diff --git a/tests/features/configs/bug780.yaml b/tests/data/configs/bug780.yaml similarity index 100% rename from tests/features/configs/bug780.yaml rename to tests/data/configs/bug780.yaml diff --git a/tests/features/configs/dayone.yaml b/tests/data/configs/dayone.yaml similarity index 100% rename from tests/features/configs/dayone.yaml rename to tests/data/configs/dayone.yaml diff --git a/tests/features/configs/dayone_empty.yaml b/tests/data/configs/dayone_empty.yaml similarity index 100% rename from tests/features/configs/dayone_empty.yaml rename to tests/data/configs/dayone_empty.yaml diff --git a/tests/features/configs/deletion.yaml b/tests/data/configs/deletion.yaml similarity index 100% rename from tests/features/configs/deletion.yaml rename to tests/data/configs/deletion.yaml diff --git a/tests/features/configs/deletion_filters.yaml b/tests/data/configs/deletion_filters.yaml similarity index 100% rename from tests/features/configs/deletion_filters.yaml rename to tests/data/configs/deletion_filters.yaml diff --git a/tests/features/configs/editor-args.yaml b/tests/data/configs/editor-args.yaml similarity index 100% rename from tests/features/configs/editor-args.yaml rename to tests/data/configs/editor-args.yaml diff --git a/tests/features/configs/editor.yaml b/tests/data/configs/editor.yaml similarity index 100% rename from tests/features/configs/editor.yaml rename to tests/data/configs/editor.yaml diff --git a/tests/features/configs/editor_empty_folder.yaml b/tests/data/configs/editor_empty_folder.yaml similarity index 100% rename from tests/features/configs/editor_empty_folder.yaml rename to tests/data/configs/editor_empty_folder.yaml diff --git a/tests/features/configs/editor_encrypted.yaml b/tests/data/configs/editor_encrypted.yaml similarity index 100% rename from tests/features/configs/editor_encrypted.yaml rename to tests/data/configs/editor_encrypted.yaml diff --git a/tests/features/configs/empty_folder.yaml b/tests/data/configs/empty_folder.yaml similarity index 100% rename from tests/features/configs/empty_folder.yaml rename to tests/data/configs/empty_folder.yaml diff --git a/tests/features/configs/encrypted.yaml b/tests/data/configs/encrypted.yaml similarity index 100% rename from tests/features/configs/encrypted.yaml rename to tests/data/configs/encrypted.yaml diff --git a/tests/features/configs/encrypted_old.json b/tests/data/configs/encrypted_old.json similarity index 100% rename from tests/features/configs/encrypted_old.json rename to tests/data/configs/encrypted_old.json diff --git a/tests/features/configs/encrypted_old.yaml b/tests/data/configs/encrypted_old.yaml similarity index 100% rename from tests/features/configs/encrypted_old.yaml rename to tests/data/configs/encrypted_old.yaml diff --git a/tests/features/configs/format_md.yaml b/tests/data/configs/format_md.yaml similarity index 100% rename from tests/features/configs/format_md.yaml rename to tests/data/configs/format_md.yaml diff --git a/tests/features/configs/format_text.yaml b/tests/data/configs/format_text.yaml similarity index 100% rename from tests/features/configs/format_text.yaml rename to tests/data/configs/format_text.yaml diff --git a/tests/features/configs/invalid_color.yaml b/tests/data/configs/invalid_color.yaml similarity index 100% rename from tests/features/configs/invalid_color.yaml rename to tests/data/configs/invalid_color.yaml diff --git a/tests/features/configs/little_endian_dates.yaml b/tests/data/configs/little_endian_dates.yaml similarity index 100% rename from tests/features/configs/little_endian_dates.yaml rename to tests/data/configs/little_endian_dates.yaml diff --git a/tests/features/configs/markdown-headings-335.yaml b/tests/data/configs/markdown-headings-335.yaml similarity index 100% rename from tests/features/configs/markdown-headings-335.yaml rename to tests/data/configs/markdown-headings-335.yaml diff --git a/tests/features/configs/missing_directory.yaml b/tests/data/configs/missing_directory.yaml similarity index 100% rename from tests/features/configs/missing_directory.yaml rename to tests/data/configs/missing_directory.yaml diff --git a/tests/features/configs/missing_journal.yaml b/tests/data/configs/missing_journal.yaml similarity index 100% rename from tests/features/configs/missing_journal.yaml rename to tests/data/configs/missing_journal.yaml diff --git a/tests/features/configs/mostlyreadabledates.yaml b/tests/data/configs/mostlyreadabledates.yaml similarity index 100% rename from tests/features/configs/mostlyreadabledates.yaml rename to tests/data/configs/mostlyreadabledates.yaml diff --git a/tests/features/configs/multiline-tags.yaml b/tests/data/configs/multiline-tags.yaml similarity index 100% rename from tests/features/configs/multiline-tags.yaml rename to tests/data/configs/multiline-tags.yaml diff --git a/tests/features/configs/multiline.yaml b/tests/data/configs/multiline.yaml similarity index 100% rename from tests/features/configs/multiline.yaml rename to tests/data/configs/multiline.yaml diff --git a/tests/features/configs/multiple.yaml b/tests/data/configs/multiple.yaml similarity index 100% rename from tests/features/configs/multiple.yaml rename to tests/data/configs/multiple.yaml diff --git a/tests/features/configs/no_colors.yaml b/tests/data/configs/no_colors.yaml similarity index 100% rename from tests/features/configs/no_colors.yaml rename to tests/data/configs/no_colors.yaml diff --git a/tests/features/data/configs/simple.yaml b/tests/data/configs/simple.yaml similarity index 100% rename from tests/features/data/configs/simple.yaml rename to tests/data/configs/simple.yaml diff --git a/tests/features/configs/tags-216.yaml b/tests/data/configs/tags-216.yaml similarity index 100% rename from tests/features/configs/tags-216.yaml rename to tests/data/configs/tags-216.yaml diff --git a/tests/features/configs/tags-237.yaml b/tests/data/configs/tags-237.yaml similarity index 100% rename from tests/features/configs/tags-237.yaml rename to tests/data/configs/tags-237.yaml diff --git a/tests/features/configs/tags.yaml b/tests/data/configs/tags.yaml similarity index 100% rename from tests/features/configs/tags.yaml rename to tests/data/configs/tags.yaml diff --git a/tests/features/configs/unreadabledates.yaml b/tests/data/configs/unreadabledates.yaml similarity index 100% rename from tests/features/configs/unreadabledates.yaml rename to tests/data/configs/unreadabledates.yaml diff --git a/tests/features/configs/upgrade_from_195.json b/tests/data/configs/upgrade_from_195.json similarity index 100% rename from tests/features/configs/upgrade_from_195.json rename to tests/data/configs/upgrade_from_195.json diff --git a/tests/features/configs/upgrade_from_195_little_endian_dates.json b/tests/data/configs/upgrade_from_195_little_endian_dates.json similarity index 100% rename from tests/features/configs/upgrade_from_195_little_endian_dates.json rename to tests/data/configs/upgrade_from_195_little_endian_dates.json diff --git a/tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json b/tests/data/configs/upgrade_from_195_with_missing_encrypted_journal.json similarity index 100% rename from tests/features/configs/upgrade_from_195_with_missing_encrypted_journal.json rename to tests/data/configs/upgrade_from_195_with_missing_encrypted_journal.json diff --git a/tests/features/configs/upgrade_from_195_with_missing_journal.json b/tests/data/configs/upgrade_from_195_with_missing_journal.json similarity index 100% rename from tests/features/configs/upgrade_from_195_with_missing_journal.json rename to tests/data/configs/upgrade_from_195_with_missing_journal.json diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry b/tests/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry similarity index 100% rename from tests/features/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry rename to tests/data/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry b/tests/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry similarity index 100% rename from tests/features/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry rename to tests/data/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry diff --git a/tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry b/tests/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry similarity index 100% rename from tests/features/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry rename to tests/data/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry diff --git a/tests/features/data/journals/basic_encrypted.journal b/tests/data/journals/basic_encrypted.journal similarity index 100% rename from tests/features/data/journals/basic_encrypted.journal rename to tests/data/journals/basic_encrypted.journal diff --git a/tests/features/data/journals/basic_folder/2020/08/29.txt b/tests/data/journals/basic_folder/2020/08/29.txt similarity index 100% rename from tests/features/data/journals/basic_folder/2020/08/29.txt rename to tests/data/journals/basic_folder/2020/08/29.txt diff --git a/tests/features/data/journals/basic_folder/2020/08/31.txt b/tests/data/journals/basic_folder/2020/08/31.txt similarity index 100% rename from tests/features/data/journals/basic_folder/2020/08/31.txt rename to tests/data/journals/basic_folder/2020/08/31.txt diff --git a/tests/features/data/journals/basic_folder/2020/09/24.txt b/tests/data/journals/basic_folder/2020/09/24.txt similarity index 100% rename from tests/features/data/journals/basic_folder/2020/09/24.txt rename to tests/data/journals/basic_folder/2020/09/24.txt diff --git a/tests/features/data/journals/basic_onefile.journal b/tests/data/journals/basic_onefile.journal similarity index 100% rename from tests/features/data/journals/basic_onefile.journal rename to tests/data/journals/basic_onefile.journal diff --git a/tests/features/data/journals/brackets.journal b/tests/data/journals/brackets.journal similarity index 100% rename from tests/features/data/journals/brackets.journal rename to tests/data/journals/brackets.journal diff --git a/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry b/tests/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry similarity index 100% rename from tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry rename to tests/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry diff --git a/tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry b/tests/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry similarity index 100% rename from tests/features/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry rename to tests/data/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry diff --git a/tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry b/tests/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry similarity index 100% rename from tests/features/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry rename to tests/data/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry diff --git a/tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry b/tests/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry similarity index 100% rename from tests/features/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry rename to tests/data/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry diff --git a/tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry b/tests/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry similarity index 100% rename from tests/features/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry rename to tests/data/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry diff --git a/tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry b/tests/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry similarity index 100% rename from tests/features/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry rename to tests/data/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry diff --git a/tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry b/tests/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry similarity index 100% rename from tests/features/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry rename to tests/data/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry diff --git a/tests/features/data/journals/dayone_empty.dayone/entries/empty.txt b/tests/data/journals/dayone_empty.dayone/entries/empty.txt similarity index 100% rename from tests/features/data/journals/dayone_empty.dayone/entries/empty.txt rename to tests/data/journals/dayone_empty.dayone/entries/empty.txt diff --git a/tests/features/data/journals/deletion.journal b/tests/data/journals/deletion.journal similarity index 100% rename from tests/features/data/journals/deletion.journal rename to tests/data/journals/deletion.journal diff --git a/tests/features/data/journals/deletion_filters.journal b/tests/data/journals/deletion_filters.journal similarity index 100% rename from tests/features/data/journals/deletion_filters.journal rename to tests/data/journals/deletion_filters.journal diff --git a/tests/features/data/journals/empty_folder/empty b/tests/data/journals/empty_folder/empty similarity index 100% rename from tests/features/data/journals/empty_folder/empty rename to tests/data/journals/empty_folder/empty diff --git a/tests/features/data/journals/encrypted.journal b/tests/data/journals/encrypted.journal similarity index 100% rename from tests/features/data/journals/encrypted.journal rename to tests/data/journals/encrypted.journal diff --git a/tests/features/data/journals/encrypted_jrnl-1-9-5.journal b/tests/data/journals/encrypted_jrnl-1-9-5.journal similarity index 100% rename from tests/features/data/journals/encrypted_jrnl-1-9-5.journal rename to tests/data/journals/encrypted_jrnl-1-9-5.journal diff --git a/tests/features/data/journals/little_endian_dates.journal b/tests/data/journals/little_endian_dates.journal similarity index 100% rename from tests/features/data/journals/little_endian_dates.journal rename to tests/data/journals/little_endian_dates.journal diff --git a/tests/features/data/journals/markdown-headings-335.journal b/tests/data/journals/markdown-headings-335.journal similarity index 100% rename from tests/features/data/journals/markdown-headings-335.journal rename to tests/data/journals/markdown-headings-335.journal diff --git a/tests/features/data/journals/mostlyreadabledates.journal b/tests/data/journals/mostlyreadabledates.journal similarity index 100% rename from tests/features/data/journals/mostlyreadabledates.journal rename to tests/data/journals/mostlyreadabledates.journal diff --git a/tests/features/data/journals/multiline-tags.journal b/tests/data/journals/multiline-tags.journal similarity index 100% rename from tests/features/data/journals/multiline-tags.journal rename to tests/data/journals/multiline-tags.journal diff --git a/tests/features/data/journals/multiline.journal b/tests/data/journals/multiline.journal similarity index 100% rename from tests/features/data/journals/multiline.journal rename to tests/data/journals/multiline.journal diff --git a/tests/features/data/journals/simple.journal b/tests/data/journals/simple.journal similarity index 100% rename from tests/features/data/journals/simple.journal rename to tests/data/journals/simple.journal diff --git a/tests/features/data/journals/simple_jrnl-1-9-5.journal b/tests/data/journals/simple_jrnl-1-9-5.journal similarity index 100% rename from tests/features/data/journals/simple_jrnl-1-9-5.journal rename to tests/data/journals/simple_jrnl-1-9-5.journal diff --git a/tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal b/tests/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal similarity index 100% rename from tests/features/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal rename to tests/data/journals/simple_jrnl-1-9-5_little_endian_dates.journal diff --git a/tests/features/data/journals/tags-216.journal b/tests/data/journals/tags-216.journal similarity index 100% rename from tests/features/data/journals/tags-216.journal rename to tests/data/journals/tags-216.journal diff --git a/tests/features/data/journals/tags-237.journal b/tests/data/journals/tags-237.journal similarity index 100% rename from tests/features/data/journals/tags-237.journal rename to tests/data/journals/tags-237.journal diff --git a/tests/features/data/journals/tags.journal b/tests/data/journals/tags.journal similarity index 100% rename from tests/features/data/journals/tags.journal rename to tests/data/journals/tags.journal diff --git a/tests/features/data/journals/unreadabledates.journal b/tests/data/journals/unreadabledates.journal similarity index 100% rename from tests/features/data/journals/unreadabledates.journal rename to tests/data/journals/unreadabledates.journal diff --git a/tests/features/data/journals/work.journal b/tests/data/journals/work.journal similarity index 100% rename from tests/features/data/journals/work.journal rename to tests/data/journals/work.journal diff --git a/tests/features/data/templates/sample.template b/tests/data/templates/sample.template similarity index 100% rename from tests/features/data/templates/sample.template rename to tests/data/templates/sample.template diff --git a/tests/features/configs/editor_markdown_extension.yaml b/tests/features/configs/editor_markdown_extension.yaml deleted file mode 100644 index bf3b8d8e..00000000 --- a/tests/features/configs/editor_markdown_extension.yaml +++ /dev/null @@ -1,18 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -editor: "vim" -journals: - default: features/journals/editor_markdown_extension.journal -linewrap: 80 -tagsymbols: "@" -template: features/templates/extension.md -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/configs/simple.yaml b/tests/features/configs/simple.yaml deleted file mode 100644 index f8739142..00000000 --- a/tests/features/configs/simple.yaml +++ /dev/null @@ -1,18 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none -version: v2.5 \ No newline at end of file diff --git a/tests/features/core.feature b/tests/features/core.feature index 3115fd57..67a73a12 100644 --- a/tests/features/core.feature +++ b/tests/features/core.feature @@ -5,3 +5,4 @@ Feature: Functionality of jrnl outside of actually handling journals When we run "jrnl --version" Then we should get no error Then the output should match "^jrnl version v\d+\.\d+(\.\d+)?(-(alpha|beta)\d*)?" + diff --git a/tests/features/data/configs/basic_dayone.yaml b/tests/features/data/configs/basic_dayone.yaml deleted file mode 100644 index 0209f2f7..00000000 --- a/tests/features/data/configs/basic_dayone.yaml +++ /dev/null @@ -1,17 +0,0 @@ -colors: - date: none - title: none - body: none - tags: none -default_hour: 9 -default_minute: 0 -editor: noop -encrypt: false -highlight: true -journals: - default: features/journals/basic_dayone.dayone -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/basic_encrypted.yaml b/tests/features/data/configs/basic_encrypted.yaml deleted file mode 100644 index 77f4e48d..00000000 --- a/tests/features/data/configs/basic_encrypted.yaml +++ /dev/null @@ -1,17 +0,0 @@ -colors: - date: none - title: none - body: none - tags: none -default_hour: 9 -default_minute: 0 -editor: noop -encrypt: true -highlight: true -journals: - default: features/journals/basic_encrypted.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/basic_folder.yaml b/tests/features/data/configs/basic_folder.yaml deleted file mode 100644 index ba0de638..00000000 --- a/tests/features/data/configs/basic_folder.yaml +++ /dev/null @@ -1,17 +0,0 @@ -colors: - date: none - title: none - body: none - tags: none -default_hour: 9 -default_minute: 0 -editor: noop -encrypt: false -highlight: true -journals: - default: features/journals/basic_folder -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/basic_onefile.yaml b/tests/features/data/configs/basic_onefile.yaml deleted file mode 100644 index fb48c6f8..00000000 --- a/tests/features/data/configs/basic_onefile.yaml +++ /dev/null @@ -1,17 +0,0 @@ -colors: - date: none - title: none - body: none - tags: none -default_hour: 9 -default_minute: 0 -editor: noop -encrypt: false -highlight: true -journals: - default: features/journals/basic_onefile.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/brackets.yaml b/tests/features/data/configs/brackets.yaml deleted file mode 100644 index e658947c..00000000 --- a/tests/features/data/configs/brackets.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/brackets.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/bug153.yaml b/tests/features/data/configs/bug153.yaml deleted file mode 100644 index ff645ab6..00000000 --- a/tests/features/data/configs/bug153.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -journals: - default: features/journals/bug153.dayone -linewrap: 80 -tagsymbols: '@' -template: false -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/bug343.yaml b/tests/features/data/configs/bug343.yaml deleted file mode 100644 index a4e25d8a..00000000 --- a/tests/features/data/configs/bug343.yaml +++ /dev/null @@ -1,13 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -template: false -encrypt: false -highlight: true -journals: - simple: features/journals/simple.journal - work: features/journals/work.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/bug780.yaml b/tests/features/data/configs/bug780.yaml deleted file mode 100644 index e1d830c2..00000000 --- a/tests/features/data/configs/bug780.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -journals: - default: features/journals/bug780.dayone -linewrap: 80 -tagsymbols: '@' -template: false -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/dayone.yaml b/tests/features/data/configs/dayone.yaml deleted file mode 100644 index 894cb911..00000000 --- a/tests/features/data/configs/dayone.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: noop -template: false -encrypt: false -highlight: true -journals: - default: features/journals/dayone.dayone -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/dayone_empty.yaml b/tests/features/data/configs/dayone_empty.yaml deleted file mode 100644 index 7750d389..00000000 --- a/tests/features/data/configs/dayone_empty.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: noop -template: false -encrypt: false -highlight: true -journals: - default: features/journals/dayone_empty.dayone -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/deletion.yaml b/tests/features/data/configs/deletion.yaml deleted file mode 100644 index d4155260..00000000 --- a/tests/features/data/configs/deletion.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/deletion.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/deletion_filters.yaml b/tests/features/data/configs/deletion_filters.yaml deleted file mode 100644 index 73a88e4d..00000000 --- a/tests/features/data/configs/deletion_filters.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/deletion_filters.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/editor-args.yaml b/tests/features/data/configs/editor-args.yaml deleted file mode 100644 index 12c5bd9c..00000000 --- a/tests/features/data/configs/editor-args.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: vim -f -c 'setf markdown' -encrypt: false -highlight: true -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/editor.yaml b/tests/features/data/configs/editor.yaml deleted file mode 100644 index 8a06f916..00000000 --- a/tests/features/data/configs/editor.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "vim" -encrypt: false -highlight: true -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/editor_empty_folder.yaml b/tests/features/data/configs/editor_empty_folder.yaml deleted file mode 100644 index 1724bbfb..00000000 --- a/tests/features/data/configs/editor_empty_folder.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: 'vim' -template: false -encrypt: false -highlight: true -journals: - default: features/journals/empty_folder -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/editor_encrypted.yaml b/tests/features/data/configs/editor_encrypted.yaml deleted file mode 100644 index 75273c96..00000000 --- a/tests/features/data/configs/editor_encrypted.yaml +++ /dev/null @@ -1,17 +0,0 @@ -colors: - body: green - date: blue - tags: none - title: yellow -default_hour: 9 -default_minute: 0 -editor: "vim" -encrypt: true -template: false -highlight: true -journals: - default: features/journals/encrypted.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/empty_folder.yaml b/tests/features/data/configs/empty_folder.yaml deleted file mode 100644 index 52a21854..00000000 --- a/tests/features/data/configs/empty_folder.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -template: false -encrypt: false -highlight: true -journals: - default: features/journals/empty_folder -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/encrypted.yaml b/tests/features/data/configs/encrypted.yaml deleted file mode 100644 index 4d50b607..00000000 --- a/tests/features/data/configs/encrypted.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: true -template: false -highlight: true -journals: - default: features/journals/encrypted.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/encrypted_old.json b/tests/features/data/configs/encrypted_old.json deleted file mode 100644 index e69d9b79..00000000 --- a/tests/features/data/configs/encrypted_old.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "default_hour": 9, - "default_minute": 0, - "editor": "", - "encrypt": true, - "highlight": true, - "journals": { - "default": "features/journals/encrypted_jrnl-1-9-5.journal" - }, - "linewrap": 80, - "tagsymbols": "@", - "timeformat": "%Y-%m-%d %H:%M" -} diff --git a/tests/features/data/configs/encrypted_old.yaml b/tests/features/data/configs/encrypted_old.yaml deleted file mode 100644 index bc7b1440..00000000 --- a/tests/features/data/configs/encrypted_old.yaml +++ /dev/null @@ -1,11 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: true -highlight: true -journals: - default: features/journals/encrypted_jrnl1-9-5.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/format_md.yaml b/tests/features/data/configs/format_md.yaml deleted file mode 100644 index 0b9f1c3b..00000000 --- a/tests/features/data/configs/format_md.yaml +++ /dev/null @@ -1,19 +0,0 @@ -colors: - body: none - date: none - tags: none - title: none -default_hour: 9 -default_minute: 0 -display_format: markdown -editor: '' -encrypt: false -highlight: true -indent_character: '|' -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: '@' -template: false -timeformat: '%Y-%m-%d %H:%M' -version: v2.4.5 diff --git a/tests/features/data/configs/format_text.yaml b/tests/features/data/configs/format_text.yaml deleted file mode 100644 index c82ff7a7..00000000 --- a/tests/features/data/configs/format_text.yaml +++ /dev/null @@ -1,19 +0,0 @@ -colors: - body: none - date: none - tags: none - title: none -default_hour: 9 -default_minute: 0 -display_format: text -editor: '' -encrypt: false -highlight: true -indent_character: '|' -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: '@' -template: false -timeformat: '%Y-%m-%d %H:%M' -version: v2.4.5 diff --git a/tests/features/data/configs/invalid_color.yaml b/tests/features/data/configs/invalid_color.yaml deleted file mode 100644 index 25c0e58d..00000000 --- a/tests/features/data/configs/invalid_color.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: not-a-color - title: also-not-a-color - body: still-no-color - tags: me-too diff --git a/tests/features/data/configs/little_endian_dates.yaml b/tests/features/data/configs/little_endian_dates.yaml deleted file mode 100644 index 223c820d..00000000 --- a/tests/features/data/configs/little_endian_dates.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/little_endian_dates.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%d.%m.%Y %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/markdown-headings-335.yaml b/tests/features/data/configs/markdown-headings-335.yaml deleted file mode 100644 index 4368f641..00000000 --- a/tests/features/data/configs/markdown-headings-335.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -template: false -journals: - default: features/journals/markdown-headings-335.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/missing_directory.yaml b/tests/features/data/configs/missing_directory.yaml deleted file mode 100644 index d600404c..00000000 --- a/tests/features/data/configs/missing_directory.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/missing_directory/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/missing_journal.yaml b/tests/features/data/configs/missing_journal.yaml deleted file mode 100644 index a1f6f8cf..00000000 --- a/tests/features/data/configs/missing_journal.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/missing.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/mostlyreadabledates.yaml b/tests/features/data/configs/mostlyreadabledates.yaml deleted file mode 100644 index 5e3e1a15..00000000 --- a/tests/features/data/configs/mostlyreadabledates.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/mostlyreadabledates.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/multiline-tags.yaml b/tests/features/data/configs/multiline-tags.yaml deleted file mode 100644 index 033aaa27..00000000 --- a/tests/features/data/configs/multiline-tags.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/multiline-tags.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/multiline.yaml b/tests/features/data/configs/multiline.yaml deleted file mode 100644 index aa35b3f5..00000000 --- a/tests/features/data/configs/multiline.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/multiline.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/multiple.yaml b/tests/features/data/configs/multiple.yaml deleted file mode 100644 index 65f2c256..00000000 --- a/tests/features/data/configs/multiple.yaml +++ /dev/null @@ -1,18 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -template: false -journals: - default: features/journals/simple.journal - ideas: features/journals/nothing.journal - simple: features/journals/simple.journal - work: features/journals/work.journal - new_encrypted: - encrypt: true - journal: features/journals/new_encrypted.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" diff --git a/tests/features/data/configs/no_colors.yaml b/tests/features/data/configs/no_colors.yaml deleted file mode 100644 index 9111b561..00000000 --- a/tests/features/data/configs/no_colors.yaml +++ /dev/null @@ -1,12 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/simple.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" diff --git a/tests/features/data/configs/tags-216.yaml b/tests/features/data/configs/tags-216.yaml deleted file mode 100644 index 81b3865f..00000000 --- a/tests/features/data/configs/tags-216.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -template: false -journals: - default: features/journals/tags-216.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/tags-237.yaml b/tests/features/data/configs/tags-237.yaml deleted file mode 100644 index 5aecd61e..00000000 --- a/tests/features/data/configs/tags-237.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -template: false -journals: - default: features/journals/tags-237.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/tags.yaml b/tests/features/data/configs/tags.yaml deleted file mode 100644 index 4b55952c..00000000 --- a/tests/features/data/configs/tags.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: '' -encrypt: false -highlight: true -template: false -journals: - default: features/journals/tags.journal -linewrap: 80 -tagsymbols: '@' -timeformat: '%Y-%m-%d %H:%M' -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/unreadabledates.yaml b/tests/features/data/configs/unreadabledates.yaml deleted file mode 100644 index 99304e5a..00000000 --- a/tests/features/data/configs/unreadabledates.yaml +++ /dev/null @@ -1,17 +0,0 @@ -default_hour: 9 -default_minute: 0 -editor: "" -encrypt: false -highlight: true -journals: - default: features/journals/unreadabledates.journal -linewrap: 80 -tagsymbols: "@" -template: false -timeformat: "%Y-%m-%d %H:%M" -indent_character: "|" -colors: - date: none - title: none - body: none - tags: none diff --git a/tests/features/data/configs/upgrade_from_195.json b/tests/features/data/configs/upgrade_from_195.json deleted file mode 100644 index ec380372..00000000 --- a/tests/features/data/configs/upgrade_from_195.json +++ /dev/null @@ -1,11 +0,0 @@ -{ -"default_hour": 9, -"timeformat": "%Y-%m-%d %H:%M", -"linewrap": 80, -"encrypt": false, -"editor": "", -"default_minute": 0, -"highlight": true, -"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal"}, -"tagsymbols": "@" -} diff --git a/tests/features/data/configs/upgrade_from_195_little_endian_dates.json b/tests/features/data/configs/upgrade_from_195_little_endian_dates.json deleted file mode 100644 index 7d3c470c..00000000 --- a/tests/features/data/configs/upgrade_from_195_little_endian_dates.json +++ /dev/null @@ -1,11 +0,0 @@ -{ -"default_hour": 9, -"timeformat": "%d.%m.%Y %H:%M", -"linewrap": 80, -"encrypt": false, -"editor": "", -"default_minute": 0, -"highlight": true, -"journals": {"default": "features/journals/simple_jrnl-1-9-5_little_endian_dates.journal"}, -"tagsymbols": "@" -} diff --git a/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json b/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json deleted file mode 100644 index 5bbfb5b1..00000000 --- a/tests/features/data/configs/upgrade_from_195_with_missing_encrypted_journal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ -"default_hour": 9, -"timeformat": "%Y-%m-%d %H:%M", -"linewrap": 80, -"encrypt": true, -"editor": "", -"default_minute": 0, -"highlight": true, -"journals": {"default": "features/journals/encrypted_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, -"tagsymbols": "@" -} diff --git a/tests/features/data/configs/upgrade_from_195_with_missing_journal.json b/tests/features/data/configs/upgrade_from_195_with_missing_journal.json deleted file mode 100644 index 8d456159..00000000 --- a/tests/features/data/configs/upgrade_from_195_with_missing_journal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ -"default_hour": 9, -"timeformat": "%Y-%m-%d %H:%M", -"linewrap": 80, -"encrypt": false, -"editor": "", -"default_minute": 0, -"highlight": true, -"journals": {"default": "features/journals/simple_jrnl-1-9-5.journal", "missing": "features/journals/missing.journal"}, -"tagsymbols": "@" -} diff --git a/tests/features/environment.py b/tests/features/environment.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry deleted file mode 100644 index 9721dd55..00000000 --- a/tests/features/journals/basic_dayone.dayone/entries/D04D335AFED711EABA18FAFFC2100C3D.doentry +++ /dev/null @@ -1,53 +0,0 @@ - - - - - Creation Date - 2020-08-29T18:11:00Z - Starred - - Entry Text - Entry the first. -Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada -quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque -augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu -consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In -commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget -venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - -Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo -ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse -potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget -molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus -hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis -feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum -urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget -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. - Time Zone - America/Los_Angeles - UUID - D04D335AFED711EABA18FAFFC2100C3D - Tags - - ipsum - tagone - tagtwo - - Creator - - Device Agent - - Generation Date - 2020-09-25T02:35:45Z - Host Name - iris.lan - OS Agent - Darwin/19.3.0 - Software Agent - jrnl/v2.4.5 - - - diff --git a/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry deleted file mode 100644 index 8c2f3c52..00000000 --- a/tests/features/journals/basic_dayone.dayone/entries/FC8A86CAFED711EA8892FAFFC2100C3D.doentry +++ /dev/null @@ -1,55 +0,0 @@ - - - - - Creation Date - 2020-08-31T21:32:00Z - Starred - - Entry Text - A second entry in what I hope to be a long series. -Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo -vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, -consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, -vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, -eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id -lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, -egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. -Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. - -Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel -vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et -malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, -non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel -ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo -eros. - -Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non -tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. -Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum -quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum -interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. -Quisque auctor lacinia consectetur. - Time Zone - America/Los_Angeles - UUID - FC8A86CAFED711EA8892FAFFC2100C3D - Tags - - tagtwo - - Creator - - Device Agent - - Generation Date - 2020-09-25T02:36:59Z - Host Name - iris.lan - OS Agent - Darwin/19.3.0 - Software Agent - jrnl/v2.4.5 - - - diff --git a/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry b/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry deleted file mode 100644 index d998c36b..00000000 --- a/tests/features/journals/basic_dayone.dayone/entries/FD8ABC8EFED711EABC35FAFFC2100C3D.doentry +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Creation Date - 2020-09-24T16:14:00Z - Starred - - Entry Text - The third entry finally after weeks without writing. -I'm so excited about emojis. 💯 🎶 💩 - -Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. -Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla -eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis -dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. -Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis -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 - Time Zone - America/Los_Angeles - UUID - FD8ABC8EFED711EABC35FAFFC2100C3D - Tags - - tagthree - tagone - - Creator - - Device Agent - - Generation Date - 2020-09-25T02:37:01Z - Host Name - iris.lan - OS Agent - Darwin/19.3.0 - Software Agent - jrnl/v2.4.5 - - - diff --git a/tests/features/journals/basic_encrypted.journal b/tests/features/journals/basic_encrypted.journal deleted file mode 100644 index ffc122df..00000000 --- a/tests/features/journals/basic_encrypted.journal +++ /dev/null @@ -1 +0,0 @@ -gAAAAABfb4gQBMqqGn_W8v_s7qCi14bX7inuCOKbsBqIUf7_ch14vTUp7lrysPFvhBp5vGijTwDIbk4LKoIISj8NwM31I8L0zEbMx9y6iyF_zseGGNxBvNN0wzAXa67bs-ohiQhhebcdIc_52sltxL2ELh8JAKUaXRwyapgnMgJ7z6deJppLK-B7RE7BiT0eKjWTDMd2x6cZDswvHs9opDp5yjuKWV5m7x6ggCKYgHT3savT9Tg7V0Fq6K3LGWaE59lCrqlAB0u6dnrDX3qcF4SKyckaniXzRShZGebdkUKDcLFun2V2syZwYQN772xjznIsJ16iXicox2uYKg8CnTefsyCwaOZyBvySGEy3CrlBiuIRIcxCtjKbYJ2B-Aq7LZitnBR7Ny_6_Wm8HsBf3N-cFCp4GShiCKrxuXKcOZ7vszG5EKb78JS85bb0mswU5CSdgp6UAHjIZqfJq00qQsViBCbXq3oklCPZXdQkOf5U0KpG2MVUiD-Zcn5Qj3gnUhSEr-5wKU9tWrE63MGPyE6KjZlArZX2W2LeGnW2CEYw9eREGon06AzLJ4mj3BgtjVWLIdGcCwORXvHRjUqazWgbEmXNVTbtp_cKnkW-rFzRBrUoVme9v-1Y3sH0VvHBq7QIj915VzBklzWs1qzIyTPZG5Db9LvdQ7SiV8slf1Jo7l-ayUUdVj6igvKZcgfB4RUHolJoMps5p4lZ5sPqv59KtSa8DCpuoRczIj71OCpuRVARZgy1m5sUD9xSMxOBdy46u1Jnry6iMtzXWI3mEZe5m7UhmW_L4Zcv4bbk8XjkBeHjPdgm2B69jkLmCBFecD5ztoGesCGt_pNo_sWSKqLHV1-coKFB2Nn__a4utU9NJNdeNRkr8_ahU6tn3jmaFjfQ7cKfrXG_NCcYBRX9fja8EQIeBEp_3TCoXQqhuV_bGsNPA2qL63Pt6YiRaUf1g9FNBqJRlKCSOYNixSXQZN_rTePzx0SQ0aIQhADWls62WX-LG5-byJcB6W2P_cH21hDOXkoNEIyLnCz9HQ6Yd6Fbv7298ps3F6jiUDdWES23zv8sDgBuKUN94qSN34j6MDYGFnGI9zsJ-Y-I2frdlLfWPx3pUL7afcKh1nRgXdjctsTSxU2BDrsu03eBz2IoZjoOR0U51IrNMOD1NNT3kctXxHLuOHSEkwAzS3doncQbdRLi5Gc1dQuOUa4sC-p8gVjUKXO-oi_49kp9Km2Ay9wFg0epBbXx2QMzyMsN2dXeSbHF-BDXD6sULaq5syC0fOHqaMLycTCMk2wLfNyXgEt05WvAiDn-LDsRdylMRW2hXp5HWq3Poaul-7VNg6UEMlwVfgJ-7hNreuO6IRtwmx6YdqMscw0ms6mU_MQZU_dTIPg3JU4KL0YyMqPBPSGNCx3gMp41O05Ubir45FoJSnT5Dkj4v3N0S87Ys3HuFLverASsGt9bkcSzd2uMKCJjkspemPPi9VhrY4IOO03DWSWbHmxYzFc1SJ-24WM8Ch404QKpe1qy5LNzFgLvDwQhSIHjluezHXqrD-DVh1lWNNY3WmHI2ubOZfaorvLKqzBPZ6AhpIa60rKjm0OZIQOmJwWXwkdnzut6m8PtoiLzRN897YMgeztf1nmDwp0xE-EhknVZ3WV3TeqgZJ5ykfHQ5BU8x0Db57-UtKSuesKbqPPdBe91OdsPpkGlyl6psHj1_gPm4nLvzXQePwiPaEemR_gYCWGPvl9l1ANJufgCV9qQTmZGof3fb9mjv-9lS-9l_m8KirPPRpSBToNeDtk50ceYUsOlDGzIyusppG9pOcIGyiln1IO5aZ8d4_1E83qjcHTSaKGizICZU7a-pt5STBPMesy3JgBm23A2jO4m68ayBRMcLnw_RirHvvBaj0C6UR2tac45F0Ob3PpXcvFuK0g54ziIAhzGqwF9I-LZ6asXQWMW4y4EBOak8JJBorkfztzfkMaIgGu-4ZoRKOkVfdr4uzcghk3r6KUxD4-nv1ioX69-G5RwhMHppYk7z8RXS1cq5FkvzXbfEQ-Uv6M-sx32DcUy9dH-ZYhc7UWm75JJfiNXLaXT_bsc6VqQ7KPkg2-RA7CywUFCW9S0S-XdO03VdwqlUVo7fp1SKywEfhZv_9bhDCdMJBwZmigv2KP9Iz7fF6LrpLwZkzHuQGFPcyTHFpsVIFrFyJjNYCXpET9y0Q5Vt4fnea5fy-9ZiCt3S8aS0YOFJ35_kM5i3ss8eFPL0v7fIQS3ZilzdGB3bWL0J7kppHN_ekHu-wVk3UZxauoFh7hXLjPcipua-FYUIklLjcK6DG1bYP7_q6OnkC8Jl650FNezeWPomHEv7l_DO3y0tjI6SGdWvL3ZJns7Xp3ew8KsCREAUO7ffqumD03uF9N-9uWbDDjM7rk0vcg0ggfOs9Ni725mxqYpu4R285XCOVWHDvw7iU6eAvE6ry8TDXQBbNgGjTuTYFYYli7GuOqMxFIe1op2s7sRnoJE8O0J76S6APhjhjcnZRSuONWkVG_5o83uFMPSF8DtqLwuRA5E8AGfIwAUcj324sw-DA0ixBGUqomb-osUIisv3x0b044xn-FvD-8R3PZDnPbPsao8XYNxfQWStrNcZSrX2Ua-WAcv9qbQ73_57RKW4pao4ajOu7K5800D231WGiIa6aJzDnFUlzXEzYxFQyx7qegkm_9rrEp_v8TC9mfAcjWX5DMrCkxUskx9YKDfpFYq4NuxO_414gReKzd-lmorfigvttgS10N1XD74SwFluXJv-bqTbI5-SuYAhDGMv1dqrn38i3rOMQqqnQomvaUJRprqxUsKz14sSE1Y-cNqq1FXzZ6vIJq-K3YTfFWPRLeqi6gHzqS_R2YBXXUduKuYgmakiVdP3bWc-Ca8WKh5sVi6P51MO-cS7i9AZWOaOz7F8PsB4JZxAJjSOr3NBmv3EEve9auTFCudRjfC6668I_NMHaTP5CCV4cuhuAxUuKUGgd6WFjDcvoYPyn_lu3bQiqD9MEag4CaJYI9PlraRv5mbqptwxv3pca7usd0GmXN_2No_nwxB4gVb48LsBBkH35njCa5iv2EKXUSOf0k3swaTSEahqbyI4EDzPXtU5uBO39iQzNpgfV_sUpnGdysjqueUVcdWGI_s5CnrNJ-_yDAY06AoXfLrjP8_3NXB2058xZ2rfmTNJNCULz9634dICJReXNnmplxIg3i6GbzFvjfNtqjrWr_iqBShyIwuOUJRbXzdJNggx2BDNG-PEWDXl89SaudFICkDvyZKEcATIss6ZXfULIMfCrqmWmFwgXfNEd9TuvjqoxFlLSaY4UfDMiYa_arUMblFfoo5nV07GANhUoQd-6HRe7LjYeX5VRodOx6ZmZjIAUq-DYr-hatJJFR2tjT_qZht2MJeYT3GZ3o54m8zBBt0JTN7HVpKaOaM3A2hEM_Ah0QZ-DkLDxtCzMuv987GDiLT2-Riya97a47yHIJhZFzFpflW2FcuC8RFWXlfUKTQfZkFmxh3MUekUuS4yu4Z121xojVswk_4P7-FqLaSnGT2epI69I_cvalRx3wjds9-5TFYqf4GridlFBRx6Fv2fpNB9Zvp9k7NQ9oYcPuXGLoXH5kmWBagPhEGKHA_pjFUZmCuwUIoeP4nP8lhFrX8OGezsbSBG773CRJzEdfcgAc5G-p6M_24WZLZHDrsVBAvgrNt6R9eQbEviWU28t_417QCp-or9qqt4OTKv1dp_4MlZh8YBg2-dtpvzSc1l5e4kQFJu7oWlpbgsjB6pl1oRRKp1maedX-gOAf559zC4l85gfEpPln9Cnl6xvERQzfO0Ey4q91SdsgK7i7FBrKKmi2wGiemFvnaQsrjZ_IFujLo8-2c8g9zTiyH1knyoVOAAnQxqGpsz6z6PNfSxr3_G8tOlNFTV-yqN_LdVHMgXtXjn3U9koGsfMulyUcBDdR3d_0Yn6iEjBt77tbxKi2ry-0gQrB1fdGsgKjyE_tMrW8D_lQz0IXsVOzd2ixsFVXMFzD6OOD8JldV0FbA-VDAS-Tp_ezIZVp6lRq54XBgvsjzDyOmOgDbSOQN6SQmvxPnIsml1wgmtm80z-9gHBqmimHBtLKB6L7CtLmmPICMS2pX3eWOmakxscxqs8AVjijJdz_NYNfcdBeDj_fhm6dqD6iwk3EBZZfsrmMGdXtAMqf1r9ng9tsz-FriXwQiJ3IM3loBsk5DKr9CcaJtKSPuwDDlRynD2vwcD-XyF6YTQdSJa9fEcq-qXya2Scj4mqQ4RDemJgErdradRfwJfII3fWHh18XxmYVqi9Bwn3YRgwEadyo0-HjbNq6vJXi12igmP99ciRAfMVQLjfUfTwoOHj44Y2Ru_hPjJcvB6FIn6KLrrCSrZnrshFdFn4L36z1CrS8fbtdvrG3kdZQxsUJnMqttuwKRpLnDWTWkIwj_GRBFrzCFgbwGp1XYhemxggyKVuhZPfyyTIM9rhlPth6eGyrpYfap24Av_mGPRBLnzcjtpGbACGdKQL034kVmI7yENGvmY40KSrWsVG_BE9bSJhx0EptFsT2IxnxbuFD4hGb4fFag9V0BDiKpUoOZqIVqVO8cAp-5w4twvWZKkrhu16JNlLoXWMoFANrw-tp5LKSin1CUeRa4LWVI1GR8tRkIad_GnCHRv9JEMswlNy9wi2sDNsSxWT7WNasUW5-glgK9pR7d2pXGGOWfHj1U6CKIqmAiO3iw8igzhvyx_dAxMxPo \ No newline at end of file diff --git a/tests/features/journals/basic_folder/2020/08/29.txt b/tests/features/journals/basic_folder/2020/08/29.txt deleted file mode 100644 index c8af54ca..00000000 --- a/tests/features/journals/basic_folder/2020/08/29.txt +++ /dev/null @@ -1,19 +0,0 @@ -[2020-08-29 11:11:00 AM] Entry the first. -Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada -quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque -augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu -consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In -commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget -venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - -Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo -ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse -potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget -molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus -hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis -feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum -urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget -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. diff --git a/tests/features/journals/basic_folder/2020/08/31.txt b/tests/features/journals/basic_folder/2020/08/31.txt deleted file mode 100644 index 826e7cdb..00000000 --- a/tests/features/journals/basic_folder/2020/08/31.txt +++ /dev/null @@ -1,23 +0,0 @@ -[2020-08-31 02:32:00 PM] A second entry in what I hope to be a long series. * -Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo -vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, -consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, -vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, -eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id -lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, -egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. -Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. - -Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel -vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et -malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, -non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel -ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo -eros. - -Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non -tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. -Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum -quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum -interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. -Quisque auctor lacinia consectetur. diff --git a/tests/features/journals/basic_folder/2020/09/24.txt b/tests/features/journals/basic_folder/2020/09/24.txt deleted file mode 100644 index 2bd885ce..00000000 --- a/tests/features/journals/basic_folder/2020/09/24.txt +++ /dev/null @@ -1,11 +0,0 @@ -[2020-09-24 09:14:00 AM] The third entry finally after weeks without writing. -I'm so excited about emojis. 💯 🎶 💩 - -Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. -Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla -eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis -dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. -Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis -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 diff --git a/tests/features/journals/basic_onefile.journal b/tests/features/journals/basic_onefile.journal deleted file mode 100644 index 0d988049..00000000 --- a/tests/features/journals/basic_onefile.journal +++ /dev/null @@ -1,58 +0,0 @@ -[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 pellentesque -augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu -consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In -commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget -venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - -Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo -ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse -potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget -molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus -hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis -feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum -urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget -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. - -[2020-08-31 14:32] A second entry in what I hope to be a long series. * - -Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis leo -vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit amet, -consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl lorem, -vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum lectus, -eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium id -lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, -egestas at efficitur et, ultrices vel est. Sed commodo et nibh non elementum. -Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. - -Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel -vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum et -malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis sem, -non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel -ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a commodo -eros. - -Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non -tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. -Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum -quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum -interdum. Integer id justo dui. Integer eu tellus in turpis bibendum blandit. -Quisque auctor lacinia consectetur. - -[2020-09-24 09:14] The third entry finally after weeks without writing. - -I'm so excited about emojis. 💯 🎶 💩 - -Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. -Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla -eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis -dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. -Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis -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 diff --git a/tests/features/journals/brackets.journal b/tests/features/journals/brackets.journal deleted file mode 100644 index 4649ea3e..00000000 --- a/tests/features/journals/brackets.journal +++ /dev/null @@ -1,2 +0,0 @@ -[2019-07-08 05:42] Entry subject -[1] line starting with 1 diff --git a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry deleted file mode 100644 index 066821bb..00000000 --- a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D511.doentry +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Creation Date - 2013-10-27T02:27:27Z - Creator - - Device Agent - iPhone/iPhone3,1 - Generation Date - 2013-10-27T07:02:27Z - Host Name - omrt104001 - OS Agent - iOS/7.0.3 - Software Agent - Day One (iOS)/1.11.4 - - Entry Text - Some text. - Location - - Administrative Area - Östergötlands län - Country - Sverige - Latitude - 58.383400000000000 - Locality - City - Longitude - 15.577170000000000 - Place Name - Street - - Starred - - Time Zone - Europe/Stockholm - UUID - B40EE704E15846DE8D45C44118A4D511 - Weather - - Celsius - 12 - Description - Clear - Fahrenheit - 54 - IconName - sunnyn.png - - - diff --git a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry b/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry deleted file mode 100644 index ea3efec5..00000000 --- a/tests/features/journals/bug153.dayone/entries/B40EE704E15846DE8D45C44118A4D512.doentry +++ /dev/null @@ -1,52 +0,0 @@ - - Creation Date - 2013-10-27T02:27:27Z - Creator - - Device Agent - iPhone/iPhone3,1 - Generation Date - 2013-10-27T07:02:27Z - Host Name - omrt104001 - OS Agent - iOS/7.0.3 - Software Agent - Day One (iOS)/1.11.4 - - Entry Text - This is not a valid plist. - Location - - Administrative Area - Östergötlands län - Country - Sverige - Latitude - 58.383400000000000 - Locality - City - Longitude - 15.577170000000000 - Place Name - Street - - Starred - - Time Zone - Europe/Stockholm - UUID - B40EE704E15846DE8D45C44118A4D511 - Weather - - Celsius - 12 - Description - Clear - Fahrenheit - 54 - IconName - sunnyn.png - - - diff --git a/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry b/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry deleted file mode 100644 index 426f1ea8..00000000 --- a/tests/features/journals/bug780.dayone/entries/48A25033B34047C591160A4480197D8B.doentry +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Activity - Stationary - Creation Date - 2019-12-30T21:28:54Z - Entry Text - - Starred - - UUID - 48A25033B34047C591160A4480197D8B - Creator - - Device Agent - PC - Generation Date - 2019-12-30T21:28:54Z - Host Name - LE-TREPORT - OS Agent - Microsoft Windows/10 Home - Software Agent - Journaley/2.1 - - Tags - - i_have_no_body - - - diff --git a/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry b/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry deleted file mode 100644 index 1ac26242..00000000 --- a/tests/features/journals/dayone.dayone/entries/044F3747A38546168B572C2E3F217FA2.doentry +++ /dev/null @@ -1,34 +0,0 @@ - - - - - Creation Date - 2013-05-17T18:39:20Z - Creator - - Device Agent - Macintosh/MacBookAir5,2 - Generation Date - 2013-08-17T18:39:20Z - Host Name - Egeria - OS Agent - Mac OS X/10.8.4 - Software Agent - Day One (Mac)/1.8 - - Entry Text - This entry has tags! - Starred - - Tags - - work - PLaY - - Time Zone - America/Los_Angeles - UUID - 044F3747A38546168B572C2E3F217FA2 - - diff --git a/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry b/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry deleted file mode 100644 index 927de884..00000000 --- a/tests/features/journals/dayone.dayone/entries/0BDDD6CDA43C4A9AA2681517CC35AD9D.doentry +++ /dev/null @@ -1,46 +0,0 @@ - - - - - Creation Date - 2013-06-17T18:38:29Z - Creator - - Device Agent - Macintosh/MacBookAir5,2 - Generation Date - 2013-08-17T18:38:29Z - Host Name - Egeria - OS Agent - Mac OS X/10.8.4 - Software Agent - Day One (Mac)/1.8 - - Entry Text - This entry has a location. - Location - - Administrative Area - California - Country - Germany - Latitude - 52.4979764 - Locality - Berlin - Longitude - 13.2404758 - Place Name - Abandoned Spy Tower - - Starred - - Tags - - Time Zone - Europe/Berlin - UUID - 0BDDD6CDA43C4A9AA2681517CC35AD9D - - diff --git a/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry b/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry deleted file mode 100644 index 16260763..00000000 --- a/tests/features/journals/dayone.dayone/entries/422BC895507944A291E6FC44FC6B8BFC.doentry +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Creation Date - 2013-07-17T18:38:08Z - Creator - - Device Agent - Macintosh/MacBookAir5,2 - Generation Date - 2013-08-17T18:38:08Z - Host Name - Egeria - OS Agent - Mac OS X/10.8.4 - Software Agent - Day One (Mac)/1.8 - - Entry Text - This entry is starred! - Starred - - Tags - - Time Zone - America/Los_Angeles - UUID - 422BC895507944A291E6FC44FC6B8BFC - - diff --git a/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry b/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry deleted file mode 100644 index 9ebaf538..00000000 --- a/tests/features/journals/dayone.dayone/entries/4BB1F46946AD439996C9B59DE7C4DDC1.doentry +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Creation Date - 2013-01-17T18:37:50Z - Creator - - Device Agent - Macintosh/MacBookAir5,2 - Generation Date - 2013-08-17T18:37:50Z - Host Name - Egeria - OS Agent - Mac OS X/10.8.4 - Software Agent - Day One (Mac)/1.8 - - Entry Text - This is a DayOne entry without Timezone. - Starred - - Tags - - UUID - 4BB1F46946AD439996C9B59DE7C4DDC1 - - diff --git a/tests/features/journals/dayone_empty.dayone/entries/empty.txt b/tests/features/journals/dayone_empty.dayone/entries/empty.txt deleted file mode 100644 index c86b8f66..00000000 --- a/tests/features/journals/dayone_empty.dayone/entries/empty.txt +++ /dev/null @@ -1 +0,0 @@ -This file exists to preserve the directory structure, but should be ignored by jrnl. diff --git a/tests/features/journals/deletion.journal b/tests/features/journals/deletion.journal deleted file mode 100644 index c0fa689d..00000000 --- a/tests/features/journals/deletion.journal +++ /dev/null @@ -1,5 +0,0 @@ -[2019-10-29 11:11] First entry. - -[2019-10-29 11:11] Second entry. - -[2019-10-29 11:13] Third entry. \ No newline at end of file diff --git a/tests/features/journals/deletion_filters.journal b/tests/features/journals/deletion_filters.journal deleted file mode 100644 index 9a3747db..00000000 --- a/tests/features/journals/deletion_filters.journal +++ /dev/null @@ -1,14 +0,0 @@ -[2019-10-01 08:00] It's just another day in October. -Not much to write about. - -[2020-01-01 08:00] Happy New Year! -So this is the New Year. @holidays - -[2020-03-01 08:00] It's just another day in March. -A stick, a stone, it's the end of the road. - -[2020-05-01 09:00] Happy May Day! -@holidays @springtime Several holidays fall on this date. - -[2020-05-02 12:10] Writing tests. * -@springtime They will help prevent bugs. diff --git a/tests/features/journals/empty_folder/empty b/tests/features/journals/empty_folder/empty deleted file mode 100644 index 175b82b5..00000000 --- a/tests/features/journals/empty_folder/empty +++ /dev/null @@ -1 +0,0 @@ -Nothing to see here diff --git a/tests/features/journals/encrypted.journal b/tests/features/journals/encrypted.journal deleted file mode 100644 index d2a5fcbe..00000000 --- a/tests/features/journals/encrypted.journal +++ /dev/null @@ -1 +0,0 @@ -gAAAAABVIHB7tnwKExG7aC5ZbAbBL9SG2oY2GENeoOJ22i1PZigOvCYvrQN3kpsu0KGr7ay5K-_46R5YFlqJvtQ8anPH2FSITsaZy-l5Lz_5quw3rmzhLwAR1tc0icgtR4MEpXEdsuQ7cyb12Xq-JLDrnATs0id5Vow9Ri_tE7Xe4BXgXaySn3aRPwWKoninVxVPVvETY3MXHSUEXV9OZ-pH5kYBLGYbLA== diff --git a/tests/features/journals/encrypted_jrnl-1-9-5.journal b/tests/features/journals/encrypted_jrnl-1-9-5.journal deleted file mode 100644 index 339b47baf9671f4550efeb9b6a0cfcd5032255d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128 zcmV-`0Du3(bJIGVsY(mXmoW-2hF&*L`0NbJTYlTUr8*^Qm97}8E^3^1bZ$P^M diff --git a/tests/features/journals/little_endian_dates.journal b/tests/features/journals/little_endian_dates.journal deleted file mode 100644 index d7492969..00000000 --- a/tests/features/journals/little_endian_dates.journal +++ /dev/null @@ -1,5 +0,0 @@ -[09.06.2013 15:39] My first entry. -Everything is alright - -[10.07.2013 15:40] Life is good. -But I'm better. diff --git a/tests/features/journals/markdown-headings-335.journal b/tests/features/journals/markdown-headings-335.journal deleted file mode 100644 index 30f592ef..00000000 --- a/tests/features/journals/markdown-headings-335.journal +++ /dev/null @@ -1,42 +0,0 @@ -[2015-04-14 13:23] Heading Test - -H1-1 -= - -H1-2 -=== - -H1-3 -============================ - -H2-1 -- - -H2-2 ---- - -H2-3 ----------------------------------- - -Horizontal Rules (ignore) - ---- - -=== - -# ATX H1 - -## ATX H2 - -### ATX H3 - -#### ATX H4 - -##### ATX H5 - -###### ATX H6 - -Stuff - -More stuff -more stuff again diff --git a/tests/features/journals/mostlyreadabledates.journal b/tests/features/journals/mostlyreadabledates.journal deleted file mode 100644 index bd211bf5..00000000 --- a/tests/features/journals/mostlyreadabledates.journal +++ /dev/null @@ -1,8 +0,0 @@ -[2019-07-18 14:23] Entry subject -Time machines are possible. I know, because I've built one in my garage. - -[2019-07-19 14:23] Entry subject -I'm going to activate the machine. Nobody knows what comes next after this. Or before this? - -[2019-07 14:23] Entry subject -I've crossed so many timelines. Is there any going back? diff --git a/tests/features/journals/multiline-tags.journal b/tests/features/journals/multiline-tags.journal deleted file mode 100644 index 1fb8706f..00000000 --- a/tests/features/journals/multiline-tags.journal +++ /dev/null @@ -1,7 +0,0 @@ -[2013-06-09 15:39] Multiple @line entry with @tags. -Tag with @punctuation. afterwards -@TagOnLineAloneWithOutPunctuation -@TagOnLineAloneWithPunctuation. -Text before @tag. And After. -@hi. Hello -hi Hello \ No newline at end of file diff --git a/tests/features/journals/multiline.journal b/tests/features/journals/multiline.journal deleted file mode 100644 index 294ed141..00000000 --- a/tests/features/journals/multiline.journal +++ /dev/null @@ -1,5 +0,0 @@ -[2013-06-09 15:39] Multiple line entry. -This is the first line. -This line doesn't have any ending punctuation - -There is a blank line above this. diff --git a/tests/features/journals/simple.journal b/tests/features/journals/simple.journal deleted file mode 100644 index 8336068e..00000000 --- a/tests/features/journals/simple.journal +++ /dev/null @@ -1,5 +0,0 @@ -[2013-06-09 15:39] My first entry. -Everything is alright - -[2013-06-10 15:40] Life is good. -But I'm better. diff --git a/tests/features/journals/simple_jrnl-1-9-5.journal b/tests/features/journals/simple_jrnl-1-9-5.journal deleted file mode 100644 index 7bb6c5ac..00000000 --- a/tests/features/journals/simple_jrnl-1-9-5.journal +++ /dev/null @@ -1,13 +0,0 @@ -2010-06-10 15:00 A life without chocolate is like a bad analogy. - -2013-06-10 15:40 He said "[this] is the best time to be alive". -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada -quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque -augue et venenatis facilisis. - -[2019-08-03 12:55] Some chat log or something - -Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, -elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus -placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor -dui. diff --git a/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal b/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal deleted file mode 100644 index 328b23f4..00000000 --- a/tests/features/journals/simple_jrnl-1-9-5_little_endian_dates.journal +++ /dev/null @@ -1,13 +0,0 @@ -10.06.2010 15:00 A life without chocolate is like a bad analogy. - -10.06.2013 15:40 He said "[this] is the best time to be alive". -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada -quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque -augue et venenatis facilisis. - -[03.08.2019 12:55] Some chat log or something - -Suspendisse potenti. Sed dignissim sed nisl eu consequat. Aenean ante ex, -elementum ut interdum et, mattis eget lacus. In commodo nulla nec tellus -placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at dolor -dui. diff --git a/tests/features/journals/tags-216.journal b/tests/features/journals/tags-216.journal deleted file mode 100644 index 08b6d630..00000000 --- a/tests/features/journals/tags-216.journal +++ /dev/null @@ -1,2 +0,0 @@ -[2013-06-10 15:40] I programmed for @OS/2. -Almost makes me want to go back to @C++, though. (Still better than @C#). diff --git a/tests/features/journals/tags-237.journal b/tests/features/journals/tags-237.journal deleted file mode 100644 index be050652..00000000 --- a/tests/features/journals/tags-237.journal +++ /dev/null @@ -1,3 +0,0 @@ -[2014-07-22 11:11] This entry has an email. -@Newline tag should show as a tag. -Kyla's @email is kyla@clevelandunderdog.org and Guinness's is guinness@fortheloveofpits.org. diff --git a/tests/features/journals/tags.journal b/tests/features/journals/tags.journal deleted file mode 100644 index a28f3159..00000000 --- a/tests/features/journals/tags.journal +++ /dev/null @@ -1,8 +0,0 @@ -[2013-04-09 15:39] I have an @idea: -(1) write a command line @journal software -(2) ??? -(3) PROFIT! - -[2013-06-10 15:40] I met with @dan. -As alway's he shared his latest @idea on how to rule the world with me. -inst diff --git a/tests/features/journals/unreadabledates.journal b/tests/features/journals/unreadabledates.journal deleted file mode 100644 index 53ef1d60..00000000 --- a/tests/features/journals/unreadabledates.journal +++ /dev/null @@ -1,5 +0,0 @@ -[ashasd7zdskhz7asdkjasd] Entry subject -I've lost track of time. - -[sadfhakjsdf88sdf7sdff] Entry subject -Time has no meaning. diff --git a/tests/features/journals/work.journal b/tests/features/journals/work.journal deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/features/templates/extension.md b/tests/features/templates/extension.md deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 93482ce9..fb3b1da1 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -36,15 +36,15 @@ def working_dir(request): def set_config(config_file, temp_dir, working_dir): # Copy the config file over config_source = os.path.join( - working_dir, "features", "data", "configs", config_file + working_dir, "data", "configs", config_file ) config_dest = os.path.join(temp_dir.name, config_file) shutil.copy2(config_source, config_dest) # @todo make this only copy some journals over # Copy all of the journals over - journal_source = os.path.join(working_dir, "features", "data", "journals") - journal_dest = os.path.join(temp_dir.name, "features", "journals") + journal_source = os.path.join(working_dir, "data", "journals") + journal_dest = os.path.join(temp_dir.name, "journals") shutil.copytree(journal_source, journal_dest) # @todo get rid of this by using default config values From 3055cca76795e92e55b5e4044baf1a095fb1a6c5 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 13 Feb 2021 18:38:27 -0800 Subject: [PATCH 06/74] Add tests for core feature to pytest-bdd - Implement "the output should contain" step Co-authored-by: Micah Jerome Ellison --- pyproject.toml | 4 ++++ tests/features/core.feature | 10 ++++++++++ tests/step_defs/conftest.py | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b8c4731e..37a2f6b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,10 @@ force_sort_within_sections = true [tool.pytest.ini_options] minversion = "6.0" +markers = [ + "todo", +] + [build-system] requires = ["poetry>=1.1"] diff --git a/tests/features/core.feature b/tests/features/core.feature index 67a73a12..4399341d 100644 --- a/tests/features/core.feature +++ b/tests/features/core.feature @@ -6,3 +6,13 @@ Feature: Functionality of jrnl outside of actually handling journals Then we should get no error Then the output should match "^jrnl version v\d+\.\d+(\.\d+)?(-(alpha|beta)\d*)?" + Scenario: Running the diagnostic command + Given we use the config "simple.yaml" + When we run "jrnl --diagnostic" + Then the output should contain "jrnl" + And the output should contain "Python" + And the output should contain "OS" + + @todo + Scenario: Listing available journals + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index fb3b1da1..2e62c561 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -91,3 +91,10 @@ def matches_std_output(regex, cli_run): out = cli_run["stdout"] matches = re.findall(regex, out) assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" + + +@then(parse("the output should contain\n{text}")) +@then(parse('the output should contain "{text}"')) +def check_output_inline(text, cli_run): + assert text and text in cli_run['stdout'] + From 7657bd7221b8f42bff66e1896b867659045b26f5 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 13 Feb 2021 19:10:22 -0800 Subject: [PATCH 07/74] Implement version-checking test - Add new step definition Co-authored-by: Micah Jerome Ellison --- tests/step_defs/conftest.py | 12 ++++++++++++ tests/step_defs/test_features.py | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 2e62c561..1ebfe974 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -5,6 +5,7 @@ import shutil import os import re import tempfile +import toml from pytest import fixture from pytest_bdd import given @@ -30,6 +31,11 @@ def temp_dir(): def working_dir(request): return os.path.join(request.config.rootpath, "tests") +@fixture +def toml_version(working_dir): + pyproject = os.path.join(working_dir, "..", "pyproject.toml") + pyproject_contents = toml.load(pyproject) + return pyproject_contents["tool"]["poetry"]["version"] # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @@ -98,3 +104,9 @@ def matches_std_output(regex, cli_run): def check_output_inline(text, cli_run): assert text and text in cli_run['stdout'] + +@then("the output should contain pyproject.toml version") +def check_output_version_inline(cli_run, toml_version): + out = cli_run['stdout'] + assert toml_version in out, toml_version + diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index d670f9c9..b93f2140 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -1,3 +1,19 @@ from pytest_bdd import scenarios +scenarios("../features/build.feature") scenarios("../features/core.feature") +# scenarios("../features/datetime.feature") +# scenarios("../features/delete.feature") +# scenarios("../features/encrypt.feature") +# scenarios("../features/file_storage.feature") +# scenarios("../features/format.feature") +# scenarios("../features/import.feature") +# scenarios("../features/multiple_journals.feature") +# scenarios("../features/password.feature") +# scenarios("../features/search.feature") +# scenarios("../features/star.feature") +# scenarios("../features/tag.feature") +# scenarios("../features/upgrade.feature") +# scenarios("../features/write.feature") + + From c500730ae646d747e49677fbbb38870c1f3d4533 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 12:28:48 -0800 Subject: [PATCH 08/74] Implement and add datetime tests - Deletes most of the datetime tests so that they can be re-added as they are implemented in pytest-bdd - Implements steps that check the journal and output for strings - Get rid of deployment tag (we're not using it, anyway) Co-authored-by: Micah Jerome Ellison --- tests/features/build.feature | 1 - tests/features/datetime.feature | 148 +------------------------------ tests/step_defs/conftest.py | 43 ++++++--- tests/step_defs/test_features.py | 4 +- 4 files changed, 36 insertions(+), 160 deletions(-) diff --git a/tests/features/build.feature b/tests/features/build.feature index 4725ea85..e9b47b49 100644 --- a/tests/features/build.feature +++ b/tests/features/build.feature @@ -1,6 +1,5 @@ Feature: Build process - @deployment_tests Scenario: Version numbers should stay in sync Given we use the config "simple.yaml" When we run "jrnl --version" diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 8fe335c9..cbb31ff4 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -5,151 +5,7 @@ Feature: Reading and writing to journal with custom date formats Given we use the config "simple.yaml" When we run "jrnl 2013-11-30 15:42: Project Started." Then we should see the message "Entry added" - And the journal should contain "[2013-11-30 15:42] Project Started." + When we run "jrnl -999" + Then the output should contain "2013-11-30 15:42 Project Started." - Scenario: Dates can be in the future - # https://github.com/jrnl-org/jrnl/issues/185 - Given we use the config "simple.yaml" - When we run "jrnl 26/06/2099: Planet? Earth. Year? 2099." - Then we should see the message "Entry added" - And the journal should contain "[2099-06-26 09:00] Planet?" - Scenario: Loading a sample journal with custom date - Given we use the config "little_endian_dates.yaml" - When we run "jrnl -n 2" - Then we should get no error - And the output should be - """ - 09.06.2013 15:39 My first entry. - | Everything is alright - - 10.07.2013 15:40 Life is good. - | But I'm better. - """ - - Scenario Outline: Writing an entry from command line with custom date - Given we use the config ".yaml" - When we run "jrnl " - Then we should see the message "Entry added" - When we run "jrnl -n 1" - Then the output should contain "" - - Examples: Day-first Dates - | config | input | output | - | little_endian_dates | 2020-09-19: My first entry. | 19.09.2020 09:00 My first entry. | - | little_endian_dates | 2020-08-09: My second entry. | 09.08.2020 09:00 My second entry. | - | little_endian_dates | 2020-02-29: Test. | 29.02.2020 09:00 Test. | - | little_endian_dates | 2019-02-29: Test. | 2019-02-29: Test. | - | little_endian_dates | 2020-08-32: Test. | 2020-08-32: Test. | - | little_endian_dates | 2032-02-01: Test. | 01.02.2032 09:00 Test. | - | little_endian_dates | 2020-01-01: Test. | 01.01.2020 09:00 Test. | - | little_endian_dates | 2020-12-31: Test. | 31.12.2020 09:00 Test. | - - Scenario Outline: Searching for dates with custom date - Given we use the config ".yaml" - When we run "jrnl -on '' --short" - Then the output should be "" - - Examples: Day-first Dates - | config | input | output | - | little_endian_dates | 2013-07-10 | 10.07.2013 15:40 Life is good. | - | little_endian_dates | june 9 2013 | 09.06.2013 15:39 My first entry. | - | little_endian_dates | july 10 2013 | 10.07.2013 15:40 Life is good. | - | little_endian_dates | june 2013 | 09.06.2013 15:39 My first entry. | - | little_endian_dates | july 2013 | 10.07.2013 15:40 Life is good. | - # @todo month alone with no year should work - # | little_endian_dates | june | 09.06.2013 15:39 My first entry. | - # | little_endian_dates | july | 10.07.2013 15:40 Life is good. | - - Scenario: Writing an entry at the prompt with custom date - Given we use the config "little_endian_dates.yaml" - When we run "jrnl" and enter "2013-05-10: I saw Elvis. He's alive." - Then we should get no error - And the journal should contain "[10.05.2013 09:00] I saw Elvis." - And the journal should contain "He's alive." - - Scenario: Viewing today's entries does not print the entire journal - # https://github.com/jrnl-org/jrnl/issues/741 - Given we use the config "simple.yaml" - When we run "jrnl -on today" - Then the output should not contain "Life is good" - And the output should not contain "But I'm better." - - Scenario Outline: Create entry using day of the week as entry date. - Given we use the config "simple.yaml" - When we run "jrnl : This is an entry on a ." - Then we should see the message "Entry added" - When we run "jrnl -1" - Then the output should contain " at 9am" in the local time - And the output should contain "This is an entry on a ." - - Examples: Days of the week - | day | - | Monday | - | Tuesday | - | Wednesday | - | Thursday | - | Friday | - | Saturday | - | Sunday | - | sunday | - | sUndAy | - - Scenario Outline: Create entry using day of the week abbreviations as entry date. - Given we use the config "simple.yaml" - When we run "jrnl : This is an entry on a ." - Then we should see the message "Entry added" - When we run "jrnl -1" - Then the output should contain " at 9am" in the local time - - Examples: Days of the week - | day | weekday | - | mon | Monday | - | tue | Tuesday | - | wed | Wednesday | - | thu | Thursday | - | fri | Friday | - | sat | Saturday | - | sun | Sunday | - - Scenario: Journals with unreadable dates should still be loaded - Given we use the config "unreadabledates.yaml" - When we run "jrnl -2" - Then the output should contain "I've lost track of time." - And the output should contain "Time has no meaning." - - Scenario: Journals with readable dates AND unreadable dates should still contain all data. - Given we use the config "mostlyreadabledates.yaml" - When we run "jrnl -3" - Then the output should contain "Time machines are possible." - Then the output should contain "I'm going to activate the machine." - And the output should contain "I've crossed so many timelines. Is there any going back?" - And the journal should have 3 entries - - Scenario: Update near-valid dates after journal is edited - Given we use the config "mostlyreadabledates.yaml" - When we run "jrnl 2222-08-19: I have made it exactly one month into the future." - Then the journal should contain "[2019-07-01 14:23] Entry subject" - - Scenario: Integers in square brackets should not be read as dates - Given we use the config "brackets.yaml" - When we run "jrnl -1" - Then the output should contain "[1] line starting with 1" - - # broken still - @skip - Scenario: Dayone entries without timezone information are interpreted in current timezone - Given we use the config "dayone.yaml" - When we run "jrnl -until 'feb 2013'" - Then we should get no error - And the output should contain "2013-01-17T18:37Z" in the local time - - Scenario: Loading entry with ambiguous time stamp in timezone-aware journal (like Dayone) - #https://github.com/jrnl-org/jrnl/issues/153 - Given we use the config "bug153.yaml" - When we run "jrnl -1" - Then we should get no error - And the output should be - """ - 2013-10-27 03:27 Some text. - """ diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 1ebfe974..a764d090 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,49 +1,60 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -import shutil import os import re +import shutil import tempfile -import toml +from unittest.mock import patch -from pytest import fixture from pytest_bdd import given from pytest_bdd import then from pytest_bdd import when from pytest_bdd.parsers import parse -from unittest.mock import patch +from pytest import fixture +import toml from jrnl import __version__ -from jrnl.os_compat import split_args from jrnl.cli import cli +from jrnl.os_compat import split_args + # ----- FIXTURES ----- # @fixture def cli_run(): return {"status": 0, "stdout": None, "stderr": None} + @fixture def temp_dir(): return tempfile.TemporaryDirectory() + @fixture def working_dir(request): return os.path.join(request.config.rootpath, "tests") + @fixture def toml_version(working_dir): pyproject = os.path.join(working_dir, "..", "pyproject.toml") pyproject_contents = toml.load(pyproject) return pyproject_contents["tool"]["poetry"]["version"] + +@fixture +def read_journal(journal_name="default"): + configuration = load_config(context.config_path) + with open(configuration["journals"][journal_name]) as journal_file: + journal = journal_file.read() + return journal + + # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") def set_config(config_file, temp_dir, working_dir): # Copy the config file over - config_source = os.path.join( - working_dir, "data", "configs", config_file - ) + config_source = os.path.join(working_dir, "data", "configs", config_file) config_dest = os.path.join(temp_dir.name, config_file) shutil.copy2(config_source, config_dest) @@ -102,11 +113,23 @@ def matches_std_output(regex, cli_run): @then(parse("the output should contain\n{text}")) @then(parse('the output should contain "{text}"')) def check_output_inline(text, cli_run): - assert text and text in cli_run['stdout'] + assert text and text in cli_run["stdout"] @then("the output should contain pyproject.toml version") def check_output_version_inline(cli_run, toml_version): - out = cli_run['stdout'] + out = cli_run["stdout"] assert toml_version in out, toml_version + +@then(parse('we should see the message "{text}"')) +def check_message(text, cli_run): + out = cli_run["stderr"] + assert text in out, [text, out] + + +@then(parse('the journal should contain "{text}"')) +@then(parse('journal "{journal_name}" should contain "{text}"')) +def check_journal_content(context, text, journal_name="default"): + journal = read_journal(context, journal_name) + assert text in journal, journal diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index b93f2140..5426d0c0 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -2,7 +2,7 @@ from pytest_bdd import scenarios scenarios("../features/build.feature") scenarios("../features/core.feature") -# scenarios("../features/datetime.feature") +scenarios("../features/datetime.feature") # scenarios("../features/delete.feature") # scenarios("../features/encrypt.feature") # scenarios("../features/file_storage.feature") @@ -15,5 +15,3 @@ scenarios("../features/core.feature") # scenarios("../features/tag.feature") # scenarios("../features/upgrade.feature") # scenarios("../features/write.feature") - - From 7974f3026160caa9e6d0fe7e5fdb9c7d04e42f95 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 13:18:35 -0800 Subject: [PATCH 09/74] Make tests move into temp dir as they run This will prevent any unexpected files from showing up anywhere outside the temp dir Co-authored-by: Micah Jerome Ellison --- tests/features/datetime.feature | 22 ++++++++++++++++++++++ tests/step_defs/conftest.py | 20 +++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index cbb31ff4..ca82e8c0 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -9,3 +9,25 @@ Feature: Reading and writing to journal with custom date formats Then the output should contain "2013-11-30 15:42 Project Started." + Scenario: Dates can be in the future + # https://github.com/jrnl-org/jrnl/issues/185 + Given we use the config "simple.yaml" + When we run "jrnl 26/06/2099: Planet? Earth. Year? 2099." + Then we should see the message "Entry added" + When we run "jrnl -999" + Then the output should contain "2099-06-26 09:00 Planet?" + + + Scenario: Loading a sample journal with custom date + Given we use the config "little_endian_dates.yaml" + When we run "jrnl -n 2" + Then we should get no error + When we run "jrnl -n 999" + Then the output should be + 09.06.2013 15:39 My first entry. + | Everything is alright + + 10.07.2013 15:40 Life is good. + | But I'm better. + + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index a764d090..0eec48ed 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -53,6 +53,9 @@ def read_journal(journal_name="default"): # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") def set_config(config_file, temp_dir, working_dir): + # Move into temp dir as cwd + os.chdir(temp_dir.name) + # Copy the config file over config_source = os.path.join(working_dir, "data", "configs", config_file) config_dest = os.path.join(temp_dir.name, config_file) @@ -61,7 +64,7 @@ def set_config(config_file, temp_dir, working_dir): # @todo make this only copy some journals over # Copy all of the journals over journal_source = os.path.join(working_dir, "data", "journals") - journal_dest = os.path.join(temp_dir.name, "journals") + journal_dest = os.path.join(temp_dir.name, "features", "journals") shutil.copytree(journal_source, journal_dest) # @todo get rid of this by using default config values @@ -116,6 +119,15 @@ def check_output_inline(text, cli_run): assert text and text in cli_run["stdout"] +@then(parse('the output should be "{expected_out}"')) +@then(parse("the output should be\n{expected_out}")) +def check_output(cli_run, expected_out): + expected_out = expected_out.strip() + actual_out = cli_run["stdout"].strip() + assert expected_out == actual_out, \ + f"Output does not match.\nExpected:\n{expected_out}\n---end---\nActual:\n{actual_out}\n---end---\n" + + @then("the output should contain pyproject.toml version") def check_output_version_inline(cli_run, toml_version): out = cli_run["stdout"] @@ -127,9 +139,3 @@ def check_message(text, cli_run): out = cli_run["stderr"] assert text in out, [text, out] - -@then(parse('the journal should contain "{text}"')) -@then(parse('journal "{journal_name}" should contain "{text}"')) -def check_journal_content(context, text, journal_name="default"): - journal = read_journal(context, journal_name) - assert text in journal, journal From e257194d177c8590accaef0c5f5f508c848028b7 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 14:00:40 -0800 Subject: [PATCH 10/74] Add scenario outline test to datetime - Allow config step to support scenario outlines - Add another datetime test - Get rid of read journal step since it doesn't work with other journal types (we should rely on jrnl knowing how to parse each jrnl type for better tests) Co-authored-by: Micah Jerome Ellison --- tests/features/datetime.feature | 17 +++++++++++++++++ tests/step_defs/conftest.py | 31 +++++++++++++------------------ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index ca82e8c0..d28092ce 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -31,3 +31,20 @@ Feature: Reading and writing to journal with custom date formats | But I'm better. + Scenario Outline: Writing an entry from command line with custom date + Given we use the config "" + When we run "jrnl " + Then we should see the message "Entry added" + When we run "jrnl -n 1" + Then the output should contain "" + + Examples: Day-first Dates + | config_file | command | output | + | little_endian_dates.yaml | 2020-09-19: My first entry. | 19.09.2020 09:00 My first entry. | + | little_endian_dates.yaml | 2020-08-09: My second entry. | 09.08.2020 09:00 My second entry. | + | little_endian_dates.yaml | 2020-02-29: Test. | 29.02.2020 09:00 Test. | + | little_endian_dates.yaml | 2019-02-29: Test. | 2019-02-29: Test. | + | little_endian_dates.yaml | 2020-08-32: Test. | 2020-08-32: Test. | + | little_endian_dates.yaml | 2032-02-01: Test. | 01.02.2032 09:00 Test. | + | little_endian_dates.yaml | 2020-01-01: Test. | 01.01.2020 09:00 Test. | + | little_endian_dates.yaml | 2020-12-31: Test. | 31.12.2020 09:00 Test. | diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 0eec48ed..99825ff8 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -42,16 +42,9 @@ def toml_version(working_dir): return pyproject_contents["tool"]["poetry"]["version"] -@fixture -def read_journal(journal_name="default"): - configuration = load_config(context.config_path) - with open(configuration["journals"][journal_name]) as journal_file: - journal = journal_file.read() - return journal - - # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") +@given('we use the config ""', target_fixture="config_path") def set_config(config_file, temp_dir, working_dir): # Move into temp dir as cwd os.chdir(temp_dir.name) @@ -77,7 +70,8 @@ def set_config(config_file, temp_dir, working_dir): return config_dest -@when(parse('we run "{command}"')) +@when(parse('we run "jrnl {command}"')) +@when('we run "jrnl "') def run(command, config_path, cli_run, capsys): args = split_args(command) status = 0 @@ -85,12 +79,12 @@ def run(command, config_path, cli_run, capsys): # fmt: off # see: https://github.com/psf/black/issues/664 with \ - patch("sys.argv", args), \ + patch("sys.argv", ['jrnl'] + args), \ patch("jrnl.config.get_config_path", side_effect=lambda: config_path), \ patch("jrnl.install.get_config_path", side_effect=lambda: config_path) \ : try: - cli(args[1:]) + cli(args) except SystemExit as e: status = e.code # fmt: on @@ -113,10 +107,11 @@ def matches_std_output(regex, cli_run): assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" -@then(parse("the output should contain\n{text}")) -@then(parse('the output should contain "{text}"')) -def check_output_inline(text, cli_run): - assert text and text in cli_run["stdout"] +@then(parse("the output should contain\n{output}")) +@then(parse('the output should contain "{output}"')) +@then('the output should contain ""') +def check_output_inline(output, cli_run): + assert output and output in cli_run["stdout"] @then(parse('the output should be "{expected_out}"')) @@ -124,8 +119,9 @@ def check_output_inline(text, cli_run): def check_output(cli_run, expected_out): expected_out = expected_out.strip() actual_out = cli_run["stdout"].strip() - assert expected_out == actual_out, \ - f"Output does not match.\nExpected:\n{expected_out}\n---end---\nActual:\n{actual_out}\n---end---\n" + assert ( + expected_out == actual_out + ), f"Output does not match.\nExpected:\n{expected_out}\n---end---\nActual:\n{actual_out}\n---end---\n" @then("the output should contain pyproject.toml version") @@ -138,4 +134,3 @@ def check_output_version_inline(cli_run, toml_version): def check_message(text, cli_run): out = cli_run["stderr"] assert text in out, [text, out] - From 6b096761e070f705ba810acfd41b68b0c4614b65 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 14:15:26 -0800 Subject: [PATCH 11/74] Re-enable test for windows on python 3.9 Co-authored-by: Micah Jerome Ellison --- .github/workflows/testing.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index c5015d5f..a90b939a 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -27,9 +27,6 @@ jobs: matrix: python-version: [ 3.7, 3.8, 3.9 ] os: [ ubuntu-latest, macos-latest, windows-latest ] - exclude: # Added for GitHub Actions PR problem 2020-12-19 -- remove later! - - os: windows-latest - python-version: 3.9 steps: - uses: actions/checkout@v2 From be05f96c2671104253a4bf21ec289fd76c31915c Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 15:12:17 -0800 Subject: [PATCH 12/74] Implement "the output should be" step - Add another datetime test Co-authored-by: Micah Jerome Ellison --- tests/features/datetime.feature | 19 +++++++++++++++++++ tests/step_defs/conftest.py | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index d28092ce..5c66b093 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -48,3 +48,22 @@ Feature: Reading and writing to journal with custom date formats | little_endian_dates.yaml | 2032-02-01: Test. | 01.02.2032 09:00 Test. | | little_endian_dates.yaml | 2020-01-01: Test. | 01.01.2020 09:00 Test. | | little_endian_dates.yaml | 2020-12-31: Test. | 31.12.2020 09:00 Test. | + + + Scenario Outline: Searching for dates with custom date + Given we use the config "" + When we run "jrnl " + Then the output should be "" + + Examples: Day-first Dates + | config_file | command | output | + | little_endian_dates.yaml | -on '2013-07-10' --short | 10.07.2013 15:40 Life is good. | + | little_endian_dates.yaml | -on 'june 9 2013' --short | 09.06.2013 15:39 My first entry. | + | little_endian_dates.yaml | -on 'july 10 2013' --short | 10.07.2013 15:40 Life is good. | + | little_endian_dates.yaml | -on 'june 2013' --short | 09.06.2013 15:39 My first entry. | + | little_endian_dates.yaml | -on 'july 2013' --short | 10.07.2013 15:40 Life is good. | + # @todo month alone with no year should work + # | little_endian_dates.yaml | -on 'june' --short | 09.06.2013 15:39 My first entry. | + # | little_endian_dates.yaml | -on 'july' --short | 10.07.2013 15:40 Life is good. | + + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 99825ff8..c6ad8d6a 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -114,6 +114,17 @@ def check_output_inline(output, cli_run): assert output and output in cli_run["stdout"] +@then(parse("the output should be\n{output}")) +@then(parse('the output should be "{output}"')) +@then('the output should be ""') +def test_check_output_inline(output, cli_run): + actual_out = cli_run["stdout"].strip() + output = output.strip() + assert ( + output and output == actual_out + ), f"Output does not match.\nExpected:\n{output}\n---end---\nActual:\n{actual_out}\n---end---\n" + + @then(parse('the output should be "{expected_out}"')) @then(parse("the output should be\n{expected_out}")) def check_output(cli_run, expected_out): From 74ae5f039b5e9d3c017f60296b253567d6229230 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 15:20:02 -0800 Subject: [PATCH 13/74] Rename test functions for clarity Co-authored-by: Micah Jerome Ellison --- tests/step_defs/conftest.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index c6ad8d6a..3c2c0287 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -19,6 +19,11 @@ from jrnl.cli import cli from jrnl.os_compat import split_args +# ----- UTILS ----- # +def failed_msg(msg, expected, actual): + return f"{msg}\nExpected:\n{expected}\n---end---\nActual:\n{actual}\n---end---\n" + + # ----- FIXTURES ----- # @fixture def cli_run(): @@ -45,7 +50,7 @@ def toml_version(working_dir): # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given('we use the config ""', target_fixture="config_path") -def set_config(config_file, temp_dir, working_dir): +def we_use_the_config(config_file, temp_dir, working_dir): # Move into temp dir as cwd os.chdir(temp_dir.name) @@ -72,7 +77,7 @@ def set_config(config_file, temp_dir, working_dir): @when(parse('we run "jrnl {command}"')) @when('we run "jrnl "') -def run(command, config_path, cli_run, capsys): +def we_run(command, config_path, cli_run, capsys): args = split_args(command) status = 0 @@ -96,12 +101,12 @@ def run(command, config_path, cli_run, capsys): @then("we should get no error") -def no_error(cli_run): +def should_get_no_error(cli_run): assert cli_run["status"] == 0, cli_run["status"] @then(parse('the output should match "{regex}"')) -def matches_std_output(regex, cli_run): +def output_should_match(regex, cli_run): out = cli_run["stdout"] matches = re.findall(regex, out) assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" @@ -110,38 +115,28 @@ def matches_std_output(regex, cli_run): @then(parse("the output should contain\n{output}")) @then(parse('the output should contain "{output}"')) @then('the output should contain ""') -def check_output_inline(output, cli_run): +def output_should_contain(output, cli_run): assert output and output in cli_run["stdout"] @then(parse("the output should be\n{output}")) @then(parse('the output should be "{output}"')) @then('the output should be ""') -def test_check_output_inline(output, cli_run): +def output_should_be(output, cli_run): actual_out = cli_run["stdout"].strip() output = output.strip() assert ( output and output == actual_out - ), f"Output does not match.\nExpected:\n{output}\n---end---\nActual:\n{actual_out}\n---end---\n" - - -@then(parse('the output should be "{expected_out}"')) -@then(parse("the output should be\n{expected_out}")) -def check_output(cli_run, expected_out): - expected_out = expected_out.strip() - actual_out = cli_run["stdout"].strip() - assert ( - expected_out == actual_out - ), f"Output does not match.\nExpected:\n{expected_out}\n---end---\nActual:\n{actual_out}\n---end---\n" + ), failed_msg('Output does not match.', output, actual_out) @then("the output should contain pyproject.toml version") -def check_output_version_inline(cli_run, toml_version): +def output_should_contain_version(cli_run, toml_version): out = cli_run["stdout"] assert toml_version in out, toml_version @then(parse('we should see the message "{text}"')) -def check_message(text, cli_run): +def should_see_the_message(text, cli_run): out = cli_run["stderr"] assert text in out, [text, out] From 72170304efa14509df9f387ba292139dc626a0d1 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Feb 2021 18:41:07 -0800 Subject: [PATCH 14/74] Expand "we run" step in pytest-bdd - Add some necessary fixtures - Add datetime test - Implement "the output should not contain" step - Implement "the output should contain the date" step Co-authored-by: Micah Jerome Ellison --- tests/features/datetime.feature | 36 +++++++++++++++++++++++++++++++++ tests/step_defs/conftest.py | 30 ++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 5c66b093..0dd02b86 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -67,3 +67,39 @@ Feature: Reading and writing to journal with custom date formats # | little_endian_dates.yaml | -on 'july' --short | 10.07.2013 15:40 Life is good. | + Scenario: Writing an entry at the prompt with custom date + Given we use the config "little_endian_dates.yaml" + When we run "jrnl" and enter "2013-05-10: I saw Elvis. He's alive." + Then we should get no error + When we run "jrnl -999" + Then the output should contain "10.05.2013 09:00 I saw Elvis." + And the output should contain "He's alive." + + + Scenario: Viewing today's entries does not print the entire journal + # see: https://github.com/jrnl-org/jrnl/issues/741 + Given we use the config "simple.yaml" + When we run "jrnl -on today" + Then the output should not contain "Life is good" + And the output should not contain "But I'm better." + + + Scenario Outline: Create entry using day of the week as entry date. + Given we use the config "simple.yaml" + When we run "jrnl " + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should contain "" + Then the output should contain the date "" + + Examples: Days of the week + | command | output | date | + | Monday: entry on a monday | entry on a monday | monday at 9am | + | Tuesday: entry on a tuesday | entry on a tuesday | tuesday at 9am | + | Wednesday: entry on a wednesday | entry on a wednesday | wednesday at 9am | + | Thursday: entry on a thursday | entry on a thursday | thursday at 9am | + | Friday: entry on a friday | entry on a friday | friday at 9am | + | Saturday: entry on a saturday | entry on a saturday | saturday at 9am | + | Sunday: entry on a sunday | entry on a sunday | sunday at 9am | + | sunday: entry on a sunday | entry on a sunday | sunday at 9am | + | sUndAy: entry on a sunday | entry on a sunday | sunday at 9am | diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 3c2c0287..995b5154 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -47,6 +47,16 @@ def toml_version(working_dir): return pyproject_contents["tool"]["poetry"]["version"] +@fixture +def command(): + return '' + + +@fixture +def user_input(): + return '' + + # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given('we use the config ""', target_fixture="config_path") @@ -77,7 +87,9 @@ def we_use_the_config(config_file, temp_dir, working_dir): @when(parse('we run "jrnl {command}"')) @when('we run "jrnl "') -def we_run(command, config_path, cli_run, capsys): +@when('we run "jrnl"') +@when(parse('we run "jrnl" and enter "{user_input}"')) +def we_run(command, config_path, user_input, cli_run, capsys): args = split_args(command) status = 0 @@ -85,8 +97,8 @@ def we_run(command, config_path, cli_run, capsys): # see: https://github.com/psf/black/issues/664 with \ patch("sys.argv", ['jrnl'] + args), \ - patch("jrnl.config.get_config_path", side_effect=lambda: config_path), \ - patch("jrnl.install.get_config_path", side_effect=lambda: config_path) \ + patch("sys.stdin.read", return_value=user_input) as mock_read, \ + patch("jrnl.install.get_config_path", return_value=config_path) \ : try: cli(args) @@ -119,6 +131,13 @@ def output_should_contain(output, cli_run): assert output and output in cli_run["stdout"] +@then(parse("the output should not contain\n{output}")) +@then(parse('the output should not contain "{output}"')) +@then('the output should not contain ""') +def output_should_contain(output, cli_run): + assert output not in cli_run["stdout"] + + @then(parse("the output should be\n{output}")) @then(parse('the output should be "{output}"')) @then('the output should be ""') @@ -130,6 +149,11 @@ def output_should_be(output, cli_run): ), failed_msg('Output does not match.', output, actual_out) +@then('the output should contain the date ""') +def output_should_contain(output, cli_run): + assert output and output in cli_run["stdout"] + + @then("the output should contain pyproject.toml version") def output_should_contain_version(cli_run, toml_version): out = cli_run["stdout"] From 7d04fb904a8698e872cb175ae0d16e9fcae10615 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 18:23:48 -0800 Subject: [PATCH 15/74] Add abbreviated weekday test Co-authored-by: Jonathan Wren --- tests/features/datetime.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 0dd02b86..8191f772 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -103,3 +103,23 @@ Feature: Reading and writing to journal with custom date formats | Sunday: entry on a sunday | entry on a sunday | sunday at 9am | | sunday: entry on a sunday | entry on a sunday | sunday at 9am | | sUndAy: entry on a sunday | entry on a sunday | sunday at 9am | + + Scenario Outline: Create entry using day of the week as entry date. + Given we use the config "simple.yaml" + When we run "jrnl " + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should contain "" + Then the output should contain the date "" + + Examples: Days of the week + | command | output | date | + | Mon: entry on a monday | entry on a monday | monday at 9am | + | Tue: entry on a tuesday | entry on a tuesday | tuesday at 9am | + | Wed: entry on a wednesday | entry on a wednesday | wednesday at 9am | + | Thu: entry on a thursday | entry on a thursday | thursday at 9am | + | Fri: entry on a friday | entry on a friday | friday at 9am | + | Sat: entry on a saturday | entry on a saturday | saturday at 9am | + | Sun: entry on a sunday | entry on a sunday | sunday at 9am | + | sun: entry on a sunday | entry on a sunday | sunday at 9am | + | sUn: entry on a sunday | entry on a sunday | sunday at 9am | From 7e6dd354cf09faf3d641e7dff36f100d558b717c Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 18:26:21 -0800 Subject: [PATCH 16/74] Add unreadable date test Co-authored-by: Jonathan Wren --- tests/features/datetime.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 8191f772..0bccfd65 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -123,3 +123,9 @@ Feature: Reading and writing to journal with custom date formats | Sun: entry on a sunday | entry on a sunday | sunday at 9am | | sun: entry on a sunday | entry on a sunday | sunday at 9am | | sUn: entry on a sunday | entry on a sunday | sunday at 9am | + + Scenario: Journals with unreadable dates should still be loaded + Given we use the config "unreadabledates.yaml" + When we run "jrnl -2" + Then the output should contain "I've lost track of time." + And the output should contain "Time has no meaning." From f686e2b9f0d9ad684c41fa2bff295ce0c45f11b3 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 18:40:56 -0800 Subject: [PATCH 17/74] Fix local config overwrite when running pytest bdd Co-authored-by: Jonathan Wren --- tests/step_defs/conftest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 995b5154..4933a3eb 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -98,8 +98,9 @@ def we_run(command, config_path, user_input, cli_run, capsys): with \ patch("sys.argv", ['jrnl'] + args), \ patch("sys.stdin.read", return_value=user_input) as mock_read, \ - patch("jrnl.install.get_config_path", return_value=config_path) \ - : + patch("jrnl.install.get_config_path", return_value=config_path), \ + patch("jrnl.config.get_config_path", return_value=config_path) \ + : # @TODO: single point of truth for get_config_path (move from all calls from install to config) try: cli(args) except SystemExit as e: From 0c9b6cf85f5b91dca1913cd50d48cb1acd228c97 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 18:56:10 -0800 Subject: [PATCH 18/74] Add unreadable date test Co-authored-by: Jonathan Wren --- tests/data/journals/mostlyreadabledates.journal | 6 +++--- tests/features/datetime.feature | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/data/journals/mostlyreadabledates.journal b/tests/data/journals/mostlyreadabledates.journal index bd211bf5..625ebcf2 100644 --- a/tests/data/journals/mostlyreadabledates.journal +++ b/tests/data/journals/mostlyreadabledates.journal @@ -1,8 +1,8 @@ -[2019-07-18 14:23] Entry subject +[2019-07-18 14:23] The first entry Time machines are possible. I know, because I've built one in my garage. -[2019-07-19 14:23] Entry subject +[2019-07-19 14:23] The second entry I'm going to activate the machine. Nobody knows what comes next after this. Or before this? -[2019-07 14:23] Entry subject +[2019-07 14:23] The third entry I've crossed so many timelines. Is there any going back? diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 0bccfd65..c269c188 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -129,3 +129,11 @@ Feature: Reading and writing to journal with custom date formats When we run "jrnl -2" Then the output should contain "I've lost track of time." And the output should contain "Time has no meaning." + + Scenario: Journals with readable dates AND unreadable dates should still contain all data. + Given we use the config "mostlyreadabledates.yaml" + When we run "jrnl --short" + Then the output should be + 2019-07-01 14:23 The third entry + 2019-07-18 14:23 The first entry + 2019-07-19 14:23 The second entry From a529ee5d066c79cf3c9fccad8fdbe0c2d1dde66f Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 19:01:59 -0800 Subject: [PATCH 19/74] Add another unreadable/readable date test Co-authored-by: Jonathan Wren --- tests/features/datetime.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index c269c188..d6025a4a 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -137,3 +137,9 @@ Feature: Reading and writing to journal with custom date formats 2019-07-01 14:23 The third entry 2019-07-18 14:23 The first entry 2019-07-19 14:23 The second entry + + Scenario: Update near-valid dates after journal is edited + Given we use the config "mostlyreadabledates.yaml" + When we run "jrnl 2222-08-19: I have made it exactly one month into the future." + When we run "jrnl -2" + Then the output should contain "2019-07-19 14:23 The second entry" From 7ccadebca0c6c489e7717e1fcccbb69f7e2037fe Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 19:03:57 -0800 Subject: [PATCH 20/74] Finish migrating datetime.feature to pytest bdd Co-authored-by: Jonathan Wren --- tests/features/datetime.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index d6025a4a..b0f9d2b0 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -143,3 +143,24 @@ Feature: Reading and writing to journal with custom date formats When we run "jrnl 2222-08-19: I have made it exactly one month into the future." When we run "jrnl -2" Then the output should contain "2019-07-19 14:23 The second entry" + + Scenario: Integers in square brackets should not be read as dates + Given we use the config "brackets.yaml" + When we run "jrnl -1" + Then the output should contain "[1] line starting with 1" + + # broken still + @skip + Scenario: Dayone entries without timezone information are interpreted in current timezone + Given we use the config "dayone.yaml" + When we run "jrnl -until 'feb 2013'" + Then we should get no error + And the output should contain "2013-01-17T18:37Z" in the local time + + Scenario: Loading entry with ambiguous time stamp in timezone-aware journal (like Dayone) + #https://github.com/jrnl-org/jrnl/issues/153 + Given we use the config "bug153.yaml" + When we run "jrnl -1" + Then we should get no error + And the output should be + 2013-10-27 03:27 Some text. From 8754837f157c4e02c931a6280756f58c1f32ce43 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 19:54:41 -0800 Subject: [PATCH 21/74] Add some functioning delete tests Co-authored-by: Jonathan Wren --- tests/features/delete.feature | 236 ++++--------------------------- tests/step_defs/conftest.py | 17 ++- tests/step_defs/test_features.py | 2 +- 3 files changed, 45 insertions(+), 210 deletions(-) diff --git a/tests/features/delete.feature b/tests/features/delete.feature index 2fc3f8f7..0613c826 100644 --- a/tests/features/delete.feature +++ b/tests/features/delete.feature @@ -1,229 +1,53 @@ Feature: Delete entries from journal Scenario Outline: Delete flag allows deletion of single entry - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl -1" Then the output should contain "2020-09-24 09:14 The third entry finally" When we run "jrnl --delete" and enter - """ - N - N - Y - """ - Then we flush the output + N + N + Y When we run "jrnl -99 --short" Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - """ + 2020-08-29 11:11 Entry the first. + 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 | @todo - # | basic_dayone | @todo - + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + Scenario Outline: Backing out of interactive delete does not change journal - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl --delete -n 1" and enter - """ - N - """ - Then we flush the output + N When we run "jrnl -99 --short" Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. Examples: Configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | - + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | + Scenario Outline: Delete flag with nonsense input deletes nothing (issue #932) - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl --delete asdfasdf" - Then we flush the output When we run "jrnl -99 --short" Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. Examples: Configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | - - Scenario Outline: Delete flag with tag only deletes tagged entries - Given we use the config ".yaml" - When we run "jrnl --delete @ipsum" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-31 14:32 A second entry in what I hope to be a long series. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - - Scenario Outline: Delete flag with multiple tags deletes all entries matching any of the tags - Given we use the config ".yaml" - When we run "jrnl --delete @ipsum @tagthree" and enter - """ - Y - Y - """ - Then we flush the output - When we run "jrnl -99 --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_folder | @todo - # | basic_dayone | @todo - - Scenario Outline: Delete flag with -and deletes boolean AND of tagged entries - Given we use the config ".yaml" - When we run "jrnl --delete -and @tagone @tagtwo" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-31 14:32 A second entry in what I hope to be a long series. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - Scenario Outline: Delete flag with -not does not delete entries from given tag - Given we use the config ".yaml" - When we run "jrnl --delete @tagone -not @ipsum" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - Scenario Outline: Delete flag with -from search operator only deletes entries since that date - Given we use the config ".yaml" - When we run "jrnl --delete -from 2020-09-01" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - Scenario Outline: Delete flag with -to only deletes entries up to specified date - Given we use the config ".yaml" - When we run "jrnl --delete -to 2020-08-31" and enter - """ - Y - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - - Scenario Outline: Delete flag with -starred only deletes starred entries - Given we use the config ".yaml" - When we run "jrnl --delete -starred" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-29 11:11 Entry the first. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - - Scenario Outline: Delete flag with -contains only entries containing expression - Given we use the config ".yaml" - When we run "jrnl --delete -contains dignissim" and enter - """ - Y - """ - Then we flush the output - When we run "jrnl -99 --short" - Then the output should be - """ - 2020-08-31 14:32 A second entry in what I hope to be a long series. - 2020-09-24 09:14 The third entry finally after weeks without writing. - """ - - Examples: Configs - | config | - | basic_onefile | - # | basic_folder | @todo - # | basic_dayone | @todo - + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | \ No newline at end of file diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 4933a3eb..2f81cd02 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -46,6 +46,10 @@ def toml_version(working_dir): pyproject_contents = toml.load(pyproject) return pyproject_contents["tool"]["poetry"]["version"] +@fixture +def password(): + return '' + @fixture def command(): @@ -56,7 +60,6 @@ def command(): def user_input(): return '' - # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given('we use the config ""', target_fixture="config_path") @@ -85,11 +88,17 @@ def we_use_the_config(config_file, temp_dir, working_dir): return config_dest +@given(parse('we use the password "{pw}" if prompted'), target_fixture="password") +def use_password_forever(pw): + return pw + + @when(parse('we run "jrnl {command}"')) @when('we run "jrnl "') @when('we run "jrnl"') @when(parse('we run "jrnl" and enter "{user_input}"')) -def we_run(command, config_path, user_input, cli_run, capsys): +@when(parse('we run "jrnl {command}" and enter\n{user_input}')) +def we_run(command, config_path, user_input, cli_run, capsys, password): args = split_args(command) status = 0 @@ -97,7 +106,9 @@ def we_run(command, config_path, user_input, cli_run, capsys): # see: https://github.com/psf/black/issues/664 with \ patch("sys.argv", ['jrnl'] + args), \ - patch("sys.stdin.read", return_value=user_input) as mock_read, \ + patch("sys.stdin.read", side_effect=user_input.splitlines()) as mock_read, \ + patch("builtins.input", side_effect=user_input.splitlines()) as mock_read, \ + patch("getpass.getpass", side_effect=password.splitlines()) as mock_getpass, \ patch("jrnl.install.get_config_path", return_value=config_path), \ patch("jrnl.config.get_config_path", return_value=config_path) \ : # @TODO: single point of truth for get_config_path (move from all calls from install to config) diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index 5426d0c0..6afd5c84 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -3,7 +3,7 @@ from pytest_bdd import scenarios scenarios("../features/build.feature") scenarios("../features/core.feature") scenarios("../features/datetime.feature") -# scenarios("../features/delete.feature") +scenarios("../features/delete.feature") # scenarios("../features/encrypt.feature") # scenarios("../features/file_storage.feature") # scenarios("../features/format.feature") From 40a1a871cbed2f6afd520aaa464e347a4d2dc37f Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 20:10:19 -0800 Subject: [PATCH 22/74] Migrate the rest of the delete tests from behave to pytest bdd Co-authored-by: Jonathan Wren --- tests/features/delete.feature | 135 +++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 3 deletions(-) diff --git a/tests/features/delete.feature b/tests/features/delete.feature index 0613c826..f46ef866 100644 --- a/tests/features/delete.feature +++ b/tests/features/delete.feature @@ -19,7 +19,8 @@ Feature: Delete entries from journal | basic_encrypted.yaml | # | basic_folder.yaml | @todo # | basic_dayone.yaml | @todo - + + Scenario Outline: Backing out of interactive delete does not change journal Given we use the config "" When we run "jrnl --delete -n 1" and enter @@ -36,7 +37,7 @@ Feature: Delete entries from journal | basic_folder.yaml | | basic_dayone.yaml | - + Scenario Outline: Delete flag with nonsense input deletes nothing (issue #932) Given we use the config "" When we run "jrnl --delete asdfasdf" @@ -50,4 +51,132 @@ Feature: Delete entries from journal | config_file | | basic_onefile.yaml | | basic_folder.yaml | - | basic_dayone.yaml | \ No newline at end of file + | basic_dayone.yaml | + + + Scenario Outline: Delete flag with tag only deletes tagged entries + Given we use the config "" + When we run "jrnl --delete @ipsum" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with multiple tags deletes all entries matching any of the tags + Given we use the config "" + When we run "jrnl --delete @ipsum @tagthree" and enter + Y + Y + When we run "jrnl -99 --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_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -and deletes boolean AND of tagged entries + Given we use the config "" + When we run "jrnl --delete -and @tagone @tagtwo" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -not does not delete entries from given tag + Given we use the config "" + When we run "jrnl --delete @tagone -not @ipsum" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -from search operator only deletes entries since that date + Given we use the config "" + When we run "jrnl --delete -from 2020-09-01" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -to only deletes entries up to specified date + Given we use the config "" + When we run "jrnl --delete -to 2020-08-31" and enter + Y + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -starred only deletes starred entries + Given we use the config "" + When we run "jrnl --delete -starred" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Delete flag with -contains only entries containing expression + Given we use the config "" + When we run "jrnl --delete -contains dignissim" and enter + Y + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo From 5ad5bac786e5d0a243c3c6ea0fcc99afd17549d4 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Tue, 23 Feb 2021 20:11:26 -0800 Subject: [PATCH 23/74] Standardize line breaks in datetime tests Co-authored-by: Jonathan Wren --- tests/features/datetime.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index b0f9d2b0..0a3f5155 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -104,6 +104,7 @@ Feature: Reading and writing to journal with custom date formats | sunday: entry on a sunday | entry on a sunday | sunday at 9am | | sUndAy: entry on a sunday | entry on a sunday | sunday at 9am | + Scenario Outline: Create entry using day of the week as entry date. Given we use the config "simple.yaml" When we run "jrnl " @@ -124,12 +125,14 @@ Feature: Reading and writing to journal with custom date formats | sun: entry on a sunday | entry on a sunday | sunday at 9am | | sUn: entry on a sunday | entry on a sunday | sunday at 9am | + Scenario: Journals with unreadable dates should still be loaded Given we use the config "unreadabledates.yaml" When we run "jrnl -2" Then the output should contain "I've lost track of time." And the output should contain "Time has no meaning." + Scenario: Journals with readable dates AND unreadable dates should still contain all data. Given we use the config "mostlyreadabledates.yaml" When we run "jrnl --short" @@ -138,17 +141,20 @@ Feature: Reading and writing to journal with custom date formats 2019-07-18 14:23 The first entry 2019-07-19 14:23 The second entry + Scenario: Update near-valid dates after journal is edited Given we use the config "mostlyreadabledates.yaml" When we run "jrnl 2222-08-19: I have made it exactly one month into the future." When we run "jrnl -2" Then the output should contain "2019-07-19 14:23 The second entry" + Scenario: Integers in square brackets should not be read as dates Given we use the config "brackets.yaml" When we run "jrnl -1" Then the output should contain "[1] line starting with 1" + # broken still @skip Scenario: Dayone entries without timezone information are interpreted in current timezone @@ -157,6 +163,7 @@ Feature: Reading and writing to journal with custom date formats Then we should get no error And the output should contain "2013-01-17T18:37Z" in the local time + Scenario: Loading entry with ambiguous time stamp in timezone-aware journal (like Dayone) #https://github.com/jrnl-org/jrnl/issues/153 Given we use the config "bug153.yaml" From 921ebdcdd53537741eda33ec945722f823368e20 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 27 Feb 2021 14:10:08 -0800 Subject: [PATCH 24/74] Update mocks in "we run" step Co-authored-by: Micah Jerome Ellison --- tests/step_defs/conftest.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 2f81cd02..031b96bd 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -60,6 +60,7 @@ def command(): def user_input(): return '' + # ----- STEPS ----- # @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given('we use the config ""', target_fixture="config_path") @@ -106,8 +107,8 @@ def we_run(command, config_path, user_input, cli_run, capsys, password): # see: https://github.com/psf/black/issues/664 with \ patch("sys.argv", ['jrnl'] + args), \ - patch("sys.stdin.read", side_effect=user_input.splitlines()) as mock_read, \ - patch("builtins.input", side_effect=user_input.splitlines()) as mock_read, \ + patch("sys.stdin.read", side_effect=user_input.splitlines()) as mock_stdin, \ + patch("builtins.input", side_effect=user_input.splitlines()) as mock_input, \ patch("getpass.getpass", side_effect=password.splitlines()) as mock_getpass, \ patch("jrnl.install.get_config_path", return_value=config_path), \ patch("jrnl.config.get_config_path", return_value=config_path) \ @@ -118,10 +119,16 @@ def we_run(command, config_path, user_input, cli_run, capsys, password): status = e.code # fmt: on - cli_run["status"] = status captured = capsys.readouterr() + + cli_run["status"] = status cli_run["stdout"] = captured.out cli_run["stderr"] = captured.err + cli_run["mocks"] = { + "stdin": mock_stdin, + "input": mock_input, + "getpass": mock_getpass, + } @then("we should get no error") From 1c78a305354c0fb84ea36c8bd72d5443aea3c226 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Tue, 2 Mar 2021 19:32:02 -0800 Subject: [PATCH 25/74] Fix bug in makefile - Makefile no longer runs on virtual env modules - Update some function names so pyflakes doesn't error Co-authored-by: Micah Jerome Ellison --- Makefile | 2 +- tests/step_defs/conftest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1c8a52a6..8130dade 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ format: ## Format files to match style lint: ## Check style with various tools poetry check - poetry run pyflakes . + poetry run pyflakes jrnl tests poetry run black --check --diff . test: lint ## Run unit tests and behave tests diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 031b96bd..6f86124b 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -153,7 +153,7 @@ def output_should_contain(output, cli_run): @then(parse("the output should not contain\n{output}")) @then(parse('the output should not contain "{output}"')) @then('the output should not contain ""') -def output_should_contain(output, cli_run): +def output_should_not_contain(output, cli_run): assert output not in cli_run["stdout"] @@ -169,7 +169,7 @@ def output_should_be(output, cli_run): @then('the output should contain the date ""') -def output_should_contain(output, cli_run): +def output_should_contain_date(output, cli_run): assert output and output in cli_run["stdout"] From fe018ee2412f629f093d41d03023b91f88f0b4c9 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Tue, 2 Mar 2021 20:44:26 -0800 Subject: [PATCH 26/74] Implement test keyrings and add password tests - Implement TestKeyring - Implement NoKeyring - Implement FailedKeyring - Copy in `read_value_from_string` function from old tests (will probably rewrite this later) - Add fixtures for keyrings - Implement "we have a keyring" step - Implement step to check specific config values for tests Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 110 +----------------------------- tests/step_defs/conftest.py | 113 +++++++++++++++++++++++++++++-- tests/step_defs/test_features.py | 2 +- 3 files changed, 110 insertions(+), 115 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index 332ba86e..304f51c5 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -4,113 +4,9 @@ Feature: Using the installed keyring Given we use the config "multiple.yaml" And we have a keyring When we run "jrnl simple --encrypt" and enter - """ - sabertooth - sabertooth - y - """ + sabertooth + sabertooth + Y Then the config for journal "simple" should have "encrypt" set to "bool:True" When we run "jrnl simple -n 1" Then the output should contain "2013-06-10 15:40 Life is good" - - Scenario: Encrypt journal with no keyring backend and do not store in keyring - Given we use the config "simple.yaml" - And we do not have a keyring - When we run "jrnl test entry" - And we run "jrnl --encrypt" and enter - """ - password - password - n - """ - Then we should get no error - And we should not see the message "Failed to retrieve keyring" - - Scenario: Encrypt journal with no keyring backend and do store in keyring - Given we use the config "simple.yaml" - And we do not have a keyring - When we run "jrnl test entry" - And we run "jrnl --encrypt" and enter - """ - password - password - y - """ - Then we should get no error - And we should not see the message "Failed to retrieve keyring" - # @todo add step to check contents of keyring - - @todo - Scenario: Open an encrypted journal with wrong password in keyring - # This should ask the user for the password after the keyring fails - - @todo - Scenario: Decrypt journal with password in keyring - - @todo - Scenario: Decrypt journal without a keyring - - Scenario: Encrypt journal when keyring exists but fails - Given we use the config "simple.yaml" - And we have a failed keyring - When we run "jrnl --encrypt" and enter - """ - this password will not be saved in keyring - this password will not be saved in keyring - y - """ - Then we should see the message "Failed to retrieve keyring" - And we should get no error - And we should be prompted for a password - And the config for journal "default" should have "encrypt" set to "bool:True" - - Scenario: Decrypt journal when keyring exists but fails - Given we use the config "encrypted.yaml" - And we have a failed keyring - When we run "jrnl --decrypt" and enter "bad doggie no biscuit" - Then we should see the message "Failed to retrieve keyring" - And we should get no error - And we should be prompted for a password - And we should see the message "Journal decrypted" - And the config for journal "default" should have "encrypt" set to "bool:False" - And the journal should have 2 entries - - Scenario: Open encrypted journal when keyring exists but fails - # This should ask the user for the password after the keyring fails - Given we use the config "encrypted.yaml" - And we have a failed keyring - When we run "jrnl -n 1" and enter "bad doggie no biscuit" - Then we should see the message "Failed to retrieve keyring" - And we should get no error - And we should be prompted for a password - And the output should contain "2013-06-10 15:40 Life is good" - - Scenario: Mistyping your password - Given we use the config "simple.yaml" - When we run "jrnl --encrypt" and enter - """ - swordfish - sordfish - """ - Then we should be prompted for a password - And we should see the message "Passwords did not match" - And the config for journal "default" should not have "encrypt" set - And the journal should have 2 entries - - Scenario: Mistyping your password, then getting it right - Given we use the config "simple.yaml" - When we run "jrnl --encrypt" and enter - """ - swordfish - sordfish - swordfish - swordfish - n - """ - Then we should be prompted for a password - And we should see the message "Passwords did not match" - And we should see the message "Journal encrypted" - And the config for journal "default" should have "encrypt" set to "bool:True" - When we run "jrnl -n 1" and enter "swordfish" - Then we should be prompted for a password - And the output should contain "2013-06-10 15:40 Life is good" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 6f86124b..2544c470 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,7 +1,12 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html +import ast import os +from collections import defaultdict +from keyring import backend +from keyring import set_keyring +from keyring import errors import re import shutil import tempfile @@ -16,14 +21,75 @@ import toml from jrnl import __version__ from jrnl.cli import cli +from jrnl.config import load_config from jrnl.os_compat import split_args +class TestKeyring(backend.KeyringBackend): + """A test keyring that just stores its values in a hash""" + + priority = 1 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + self.keys[servicename][username] = password + + def get_password(self, servicename, username): + return self.keys[servicename].get(username) + + def delete_password(self, servicename, username): + self.keys[servicename][username] = None + + +class NoKeyring(backend.KeyringBackend): + """A keyring that simulated an environment with no keyring backend.""" + + priority = 2 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + raise errors.NoKeyringError + + def get_password(self, servicename, username): + raise errors.NoKeyringError + + def delete_password(self, servicename, username): + raise errors.NoKeyringError + + +class FailedKeyring(backend.KeyringBackend): + """ + A keyring that cannot be retrieved. + """ + + priority = 2 + + def set_password(self, servicename, username, password): + raise errors.KeyringError + + def get_password(self, servicename, username): + raise errors.KeyringError + + def delete_password(self, servicename, username): + raise errors.KeyringError + + # ----- UTILS ----- # def failed_msg(msg, expected, actual): return f"{msg}\nExpected:\n{expected}\n---end---\nActual:\n{actual}\n---end---\n" +def read_value_from_string(string): + if string[0] == "{": + # Handle value being a dictionary + return ast.literal_eval(string) + + # Takes strings like "bool:true" or "int:32" and coerces them into proper type + t, value = string.split(":") + value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](value) + return value + + # ----- FIXTURES ----- # @fixture def cli_run(): @@ -46,22 +112,38 @@ def toml_version(working_dir): pyproject_contents = toml.load(pyproject) return pyproject_contents["tool"]["poetry"]["version"] + @fixture def password(): - return '' + return "" @fixture def command(): - return '' + return "" @fixture def user_input(): - return '' + return "" + + +@fixture +def keyring(): + set_keyring(NoKeyring()) + + +@fixture +def config_data(config_path): + return load_config(config_path) # ----- STEPS ----- # +@given("we have a keyring", target_fixture="keyring") +def we_have_keyring(): + set_keyring(FailedKeyring()) + + @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @given('we use the config ""', target_fixture="config_path") def we_use_the_config(config_file, temp_dir, working_dir): @@ -99,10 +181,13 @@ def use_password_forever(pw): @when('we run "jrnl"') @when(parse('we run "jrnl" and enter "{user_input}"')) @when(parse('we run "jrnl {command}" and enter\n{user_input}')) -def we_run(command, config_path, user_input, cli_run, capsys, password): +def we_run(command, config_path, user_input, cli_run, capsys, password, keyring): args = split_args(command) status = 0 + if not password and user_input: + password = user_input + # fmt: off # see: https://github.com/psf/black/issues/664 with \ @@ -163,9 +248,9 @@ def output_should_not_contain(output, cli_run): def output_should_be(output, cli_run): actual_out = cli_run["stdout"].strip() output = output.strip() - assert ( - output and output == actual_out - ), failed_msg('Output does not match.', output, actual_out) + assert output and output == actual_out, failed_msg( + "Output does not match.", output, actual_out + ) @then('the output should contain the date ""') @@ -183,3 +268,17 @@ def output_should_contain_version(cli_run, toml_version): def should_see_the_message(text, cli_run): out = cli_run["stderr"] assert text in out, [text, out] + + +@then(parse('the config should have "{key}" set to')) +@then(parse('the config should have "{key}" set to "{value}"')) +@then(parse('the config for journal "{journal}" should have "{key}" set to "{value}"')) +def config_var(config_data, key, value="", journal=None): + value = read_value_from_string(value) + + configuration = config_data + if journal: + configuration = configuration["journals"][journal] + + assert key in configuration + assert configuration[key] == value diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index 6afd5c84..0860059b 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -9,7 +9,7 @@ scenarios("../features/delete.feature") # scenarios("../features/format.feature") # scenarios("../features/import.feature") # scenarios("../features/multiple_journals.feature") -# scenarios("../features/password.feature") +scenarios("../features/password.feature") # scenarios("../features/search.feature") # scenarios("../features/star.feature") # scenarios("../features/tag.feature") From d0f92113f4adb1d66d4f69bac7232c4f153d1b97 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Tue, 2 Mar 2021 20:56:55 -0800 Subject: [PATCH 27/74] Add no keyring encryption test to pytest-bdd Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/features/password.feature b/tests/features/password.feature index 304f51c5..cccb94ab 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -10,3 +10,15 @@ Feature: Using the installed keyring Then the config for journal "simple" should have "encrypt" set to "bool:True" When we run "jrnl simple -n 1" Then the output should contain "2013-06-10 15:40 Life is good" + + + Scenario: Encrypt journal with no keyring backend and do not store in keyring + Given we use the config "simple.yaml" + When we run "jrnl test entry" + And we run "jrnl --encrypt" and enter + password + password + n + Then we should get no error + And the output should not contain "Failed to retrieve keyring" + From 6b27126c37a460fffdf375c887db181231d1f91d Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Tue, 2 Mar 2021 21:09:33 -0800 Subject: [PATCH 28/74] Implement password prompt steps in pytest-bdd - Scaffold some tests that will be added later - Add fixtures for journal name and keyring type - Add "we should be prompted for a password" step - Add "we should not be prompted for a password" step Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 38 +++++++++++++++++++++++++++++++++ tests/step_defs/conftest.py | 38 +++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index cccb94ab..c8d885f6 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -22,3 +22,41 @@ Feature: Using the installed keyring Then we should get no error And the output should not contain "Failed to retrieve keyring" + + Scenario: Encrypt journal with no keyring backend and do store in keyring + Given we use the config "simple.yaml" + When we run "jrnl test entry" + And we run "jrnl --encrypt" and enter + password + password + y + Then we should get no error + And the output should not contain "Failed to retrieve keyring" + # @todo add step to check contents of keyring + + + @todo + Scenario: Open an encrypted journal with wrong password in keyring + # This should ask the user for the password after the keyring fails + + + @todo + Scenario: Decrypt journal with password in keyring + + + @todo + Scenario: Decrypt journal without a keyring + + + Scenario: Encrypt journal when keyring exists but fails + Given we use the config "simple.yaml" + And we have a failed keyring + When we run "jrnl --encrypt" and enter + this password will not be saved in keyring + this password will not be saved in keyring + y + Then we should see the message "Failed to retrieve keyring" + And we should get no error + And we should be prompted for a password + And the config for journal "default" should have "encrypt" set to "bool:True" + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 2544c470..e8309b69 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -133,15 +133,28 @@ def keyring(): set_keyring(NoKeyring()) +@fixture +def keyring_type(): + return "default" + + @fixture def config_data(config_path): return load_config(config_path) +@fixture +def journal_name(): + return None + # ----- STEPS ----- # @given("we have a keyring", target_fixture="keyring") -def we_have_keyring(): - set_keyring(FailedKeyring()) +@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") +def we_have_type_of_keyring(keyring_type): + if keyring_type == "failed": + set_keyring(FailedKeyring()) + else: + set_keyring(TestKeyring()) @given(parse('we use the config "{config_file}"'), target_fixture="config_path") @@ -270,15 +283,26 @@ def should_see_the_message(text, cli_run): assert text in out, [text, out] -@then(parse('the config should have "{key}" set to')) +@then(parse('the config should have "{key}" set to\n{value}')) @then(parse('the config should have "{key}" set to "{value}"')) -@then(parse('the config for journal "{journal}" should have "{key}" set to "{value}"')) -def config_var(config_data, key, value="", journal=None): +@then(parse('the config for journal "{journal_name}" should have "{key}" set to "{value}"')) +def config_var(config_data, key, value, journal_name): value = read_value_from_string(value) configuration = config_data - if journal: - configuration = configuration["journals"][journal] + if journal_name: + configuration = configuration["journals"][journal_name] assert key in configuration assert configuration[key] == value + + +@then("we should be prompted for a password") +def password_was_called(cli_run): + assert cli_run["mocks"]["getpass"].called + + +@then("we should not be prompted for a password") +def password_was_not_called(cli_run): + assert not cli_run["mocks"]["getpass"].called + From 10b604ef8923c05fefaaaf0e641558dcf9b3db8a Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 6 Mar 2021 12:03:05 -0800 Subject: [PATCH 29/74] Add more password tests to pytest-bdd - Fix some input handling in steps (especially for passwords) - Fix some formatting issues Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 17 +++++++++++++++++ tests/step_defs/conftest.py | 34 ++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index c8d885f6..a5cbb0e1 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -60,3 +60,20 @@ Feature: Using the installed keyring And we should be prompted for a password And the config for journal "default" should have "encrypt" set to "bool:True" + + Scenario: Decrypt journal when keyring exists but fails + Given we use the config "encrypted.yaml" + And we have a failed keyring + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl --decrypt" + Then the error output should contain "Failed to retrieve keyring" + And we should get no error + And we should be prompted for a password + And we should see the message "Journal decrypted" + And the config for journal "default" should have "encrypt" set to "bool:False" + When we run "jrnl --short" + Then we should not be prompted for a password + And the output should be + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index e8309b69..c1046ef3 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -147,6 +147,12 @@ def config_data(config_path): def journal_name(): return None + +@fixture +def output_to_error(): + return False + + # ----- STEPS ----- # @given("we have a keyring", target_fixture="keyring") @given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") @@ -198,6 +204,12 @@ def we_run(command, config_path, user_input, cli_run, capsys, password, keyring) args = split_args(command) status = 0 + if user_input: + user_input = user_input.splitlines() + + if password: + password = password.splitlines() + if not password and user_input: password = user_input @@ -205,9 +217,9 @@ def we_run(command, config_path, user_input, cli_run, capsys, password, keyring) # see: https://github.com/psf/black/issues/664 with \ patch("sys.argv", ['jrnl'] + args), \ - patch("sys.stdin.read", side_effect=user_input.splitlines()) as mock_stdin, \ - patch("builtins.input", side_effect=user_input.splitlines()) as mock_input, \ - patch("getpass.getpass", side_effect=password.splitlines()) as mock_getpass, \ + patch("sys.stdin.read", side_effect=user_input) as mock_stdin, \ + patch("builtins.input", side_effect=user_input) as mock_input, \ + patch("getpass.getpass", side_effect=password) as mock_getpass, \ patch("jrnl.install.get_config_path", return_value=config_path), \ patch("jrnl.config.get_config_path", return_value=config_path) \ : # @TODO: single point of truth for get_config_path (move from all calls from install to config) @@ -244,8 +256,13 @@ def output_should_match(regex, cli_run): @then(parse("the output should contain\n{output}")) @then(parse('the output should contain "{output}"')) @then('the output should contain ""') -def output_should_contain(output, cli_run): - assert output and output in cli_run["stdout"] +@then(parse("the {output_to_error} output should contain\n{output}")) +@then(parse('the {output_to_error} output should contain "{output}"')) +def output_should_contain(output, output_to_error, cli_run): + assert output and ( + (output_to_error and output in cli_run["stderr"]) + or (not output_to_error and output in cli_run["stdout"]) + ) @then(parse("the output should not contain\n{output}")) @@ -285,7 +302,11 @@ def should_see_the_message(text, cli_run): @then(parse('the config should have "{key}" set to\n{value}')) @then(parse('the config should have "{key}" set to "{value}"')) -@then(parse('the config for journal "{journal_name}" should have "{key}" set to "{value}"')) +@then( + parse( + 'the config for journal "{journal_name}" should have "{key}" set to "{value}"' + ) +) def config_var(config_data, key, value, journal_name): value = read_value_from_string(value) @@ -305,4 +326,3 @@ 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 - From c76ee8cd4fe2ce73533f11a8657c4501d034a663 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 6 Mar 2021 13:35:42 -0800 Subject: [PATCH 30/74] Add more password tests to pytest-bdd Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 12 ++++++++++++ tests/step_defs/conftest.py | 26 +++++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index a5cbb0e1..23287b7c 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -77,3 +77,15 @@ Feature: Using the installed keyring 2013-06-09 15:39 My first entry. 2013-06-10 15:40 Life is good. + + Scenario: Open encrypted journal when keyring exists but fails + # This should ask the user for the password after the keyring fails + Given we use the config "encrypted.yaml" + And we have a failed keyring + And we use the password "bad doggie no biscuit" if prompted + When we run "jrnl -n 1" + Then we should get no error + And we should be prompted for a password + And the output should contain "Failed to retrieve keyring" + And the output should contain "2013-06-10 15:40 Life is good" + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index c1046ef3..e15f265f 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -149,8 +149,8 @@ def journal_name(): @fixture -def output_to_error(): - return False +def which_output_stream(): + return None # ----- STEPS ----- # @@ -256,13 +256,21 @@ def output_should_match(regex, cli_run): @then(parse("the output should contain\n{output}")) @then(parse('the output should contain "{output}"')) @then('the output should contain ""') -@then(parse("the {output_to_error} output should contain\n{output}")) -@then(parse('the {output_to_error} output should contain "{output}"')) -def output_should_contain(output, output_to_error, cli_run): - assert output and ( - (output_to_error and output in cli_run["stderr"]) - or (not output_to_error and output in cli_run["stdout"]) - ) +@then(parse("the {which_output_stream} output should contain\n{output}")) +@then(parse('the {which_output_stream} output should contain "{output}"')) +def output_should_contain(output, which_output_stream, cli_run): + assert output + if which_output_stream is None: + assert (output in cli_run["stdout"]) or (output in cli_run["stderr"]) + + elif which_output_stream == "standard": + assert output in cli_run["stdout"] + + elif which_output_stream == "error": + assert output in cli_run["stderr"] + + else: + assert output in cli_run[which_output_stream] @then(parse("the output should not contain\n{output}")) From e720430aa498634dd6c13d58434504a8b9f81eb4 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 20 Mar 2021 15:52:23 -0700 Subject: [PATCH 31/74] Implement "should" and "should not" handling - Handling should and should not like this should reduce the amount of fixtures we need for the test suite - Add more password tests Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 14 +++++++++++ tests/step_defs/conftest.py | 42 +++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index 23287b7c..6cd2d2b6 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -89,3 +89,17 @@ Feature: Using the installed keyring And the output should contain "Failed to retrieve keyring" And the output should contain "2013-06-10 15:40 Life is good" + + Scenario: Mistyping your password + Given we use the config "simple.yaml" + When we run "jrnl --encrypt" and enter + swordfish + sordfish + Then we should be prompted for a password + And we should see the message "Passwords did not match" + And the config for journal "default" should not have "encrypt" set + When we run "jrnl --short" + Then the output should be + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index e15f265f..47aa7882 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -118,11 +118,21 @@ def password(): return "" +@fixture +def str_value(): + return "" + + @fixture def command(): return "" +@fixture +def should_not(): + return False + + @fixture def user_input(): return "" @@ -225,6 +235,9 @@ def we_run(command, config_path, user_input, cli_run, capsys, password, keyring) : # @TODO: single point of truth for get_config_path (move from all calls from install to config) try: cli(args) + except StopIteration: + # This happens when input is expected, but don't have any input left + pass except SystemExit as e: status = e.code # fmt: on @@ -308,22 +321,37 @@ def should_see_the_message(text, cli_run): assert text in out, [text, out] -@then(parse('the config should have "{key}" set to\n{value}')) -@then(parse('the config should have "{key}" set to "{value}"')) +@then(parse('the config should have "{key}" set to\n{str_value}')) +@then(parse('the config should have "{key}" set to "{str_value}"')) @then( parse( - 'the config for journal "{journal_name}" should have "{key}" set to "{value}"' + 'the config for journal "{journal_name}" should have "{key}" set to "{str_value}"' ) ) -def config_var(config_data, key, value, journal_name): - value = read_value_from_string(value) +@then(parse('the config should {should_not} have "{key}" set')) +@then(parse('the config should {should_not} have "{key}" set')) +@then( + parse( + 'the config for journal "{journal_name}" should {should_not} have "{key}" set' + ) +) +def config_var(config_data, key, str_value, journal_name, should_not): + str_value = read_value_from_string(str_value) if len(str_value) else str_value configuration = config_data if journal_name: configuration = configuration["journals"][journal_name] - assert key in configuration - assert configuration[key] == value + # is the config a string? + # @todo this should probably be a function + if type(configuration) is str: + configuration = {"journal": configuration} + + if should_not: + assert key not in configuration + else: + assert key in configuration + assert configuration[key] == str_value @then("we should be prompted for a password") From 3d3bd917009cde7d29e558e8108a72114269d55d Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Apr 2021 14:06:53 -0700 Subject: [PATCH 32/74] Expand "we run" step to handling input better - Use regex parser in pytest-bdd to support "we run" steps that also have user input ("and enter") Co-authored-by: Micah Jerome Ellison --- tests/features/password.feature | 17 +++++++++++++++++ tests/step_defs/conftest.py | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/features/password.feature b/tests/features/password.feature index 6cd2d2b6..d3116fed 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -103,3 +103,20 @@ Feature: Using the installed keyring 2013-06-09 15:39 My first entry. 2013-06-10 15:40 Life is good. + + Scenario: Mistyping your password, then getting it right + Given we use the config "simple.yaml" + When we run "jrnl --encrypt" and enter + swordfish + sordfish + swordfish + swordfish + n + Then we should be prompted for a password + And we should see the message "Passwords did not match" + And we should see the message "Journal encrypted" + And the config for journal "default" should have "encrypt" set to "bool:True" + When we run "jrnl -1" and enter "swordfish" + Then we should be prompted for a password + And the output should contain "2013-06-10 15:40 Life is good" + diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 47aa7882..dd08502f 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -16,6 +16,7 @@ from pytest_bdd import given from pytest_bdd import then from pytest_bdd import when from pytest_bdd.parsers import parse +from pytest_bdd import parsers from pytest import fixture import toml @@ -205,11 +206,12 @@ def use_password_forever(pw): return pw +@when(parse('we run "jrnl {command}" and enter\n{user_input}')) +@when(parsers.re('we run "jrnl (?P[^"]+)" and enter "(?P[^"]+)"')) @when(parse('we run "jrnl {command}"')) +@when(parse('we run "jrnl" and enter "{user_input}"')) @when('we run "jrnl "') @when('we run "jrnl"') -@when(parse('we run "jrnl" and enter "{user_input}"')) -@when(parse('we run "jrnl {command}" and enter\n{user_input}')) def we_run(command, config_path, user_input, cli_run, capsys, password, keyring): args = split_args(command) status = 0 From e2bb8cf0deb9f3e5fdfb482006bd45c280031c4c Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Apr 2021 14:15:43 -0700 Subject: [PATCH 33/74] Add encryption test to pytest-bdd - Clean up some formatting Co-authored-by: Micah Jerome Ellison --- tests/features/encrypt.feature | 21 ++++++++++++++------- tests/step_defs/test_features.py | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/features/encrypt.feature b/tests/features/encrypt.feature index f2d0a62f..b9b9ff5a 100644 --- a/tests/features/encrypt.feature +++ b/tests/features/encrypt.feature @@ -5,7 +5,11 @@ Feature: Encrypting and decrypting journals When we run "jrnl --decrypt" and enter "bad doggie no biscuit" Then the config for journal "default" should have "encrypt" set to "bool:False" And we should see the message "Journal decrypted" - And the journal should have 2 entries + When we run "jrnl -99 --short" + Then the output should be + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. + @todo Scenario: Trying to decrypt an already unencrypted journal @@ -13,20 +17,23 @@ Feature: Encrypting and decrypting journals Given we use the config "simple.yaml" When we run "jrnl --decrypt" Then the config for journal "default" should have "encrypt" set to "bool:False" - And the journal should have 2 entries + When we run "jrnl -99 --short" + Then the output should be + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. + @todo Scenario: Trying to encrypt an already encrypted journal # This should warn the user that the journal is already encrypted + Scenario: Encrypting a journal Given we use the config "simple.yaml" When we run "jrnl --encrypt" and enter - """ - swordfish - swordfish - n - """ + swordfish + swordfish + n Then we should see the message "Journal encrypted" And the config for journal "default" should have "encrypt" set to "bool:True" When we run "jrnl -n 1" and enter "swordfish" diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index 0860059b..d04928be 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -4,7 +4,7 @@ scenarios("../features/build.feature") scenarios("../features/core.feature") scenarios("../features/datetime.feature") scenarios("../features/delete.feature") -# scenarios("../features/encrypt.feature") +scenarios("../features/encrypt.feature") # scenarios("../features/file_storage.feature") # scenarios("../features/format.feature") # scenarios("../features/import.feature") From b8c7a7c7e560d7720bb4fcfb3583b080622fbf51 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Apr 2021 15:51:19 -0700 Subject: [PATCH 34/74] 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 --- tests/features/format.feature | 892 +++++++++++++++---------------- tests/step_defs/conftest.py | 123 ++++- tests/step_defs/test_features.py | 2 +- 3 files changed, 557 insertions(+), 460 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 4981f685..2ac5cdf2 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -1,7 +1,7 @@ Feature: Custom formats Scenario Outline: JSON format - Given we use the config ".yaml" + Given we use the config "" 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,43 +30,41 @@ 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 ".yaml" + Given we use the config "" 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 - | pellentesque - | augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu - | consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In - | commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget - | venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - | - | Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo - | ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse - | potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget - | molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus - | hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis - | feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum - | urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. - | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget - | 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. - """ + 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 + | pellentesque + | augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu + | consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In + | commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget + | venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + | + | Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo + | ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse + | potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget + | molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus + | hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis + | feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum + | urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. + | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget + | 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 ".yaml" + Given we use the config "" 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,392 +78,21 @@ 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 ".yaml" + Given we use the config "" 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. - ---------------------------------------------------- + The third entry finally after weeks without writing. + ---------------------------------------------------- - I'm so excited about emojis. 💯 🎶 💩 - - Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. - Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla - eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis - dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. - Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis - 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 | - - Scenario Outline: Increasing Headings on Markdown export - Given we use the config ".yaml" - And we use the password "test" if prompted - When we open the editor and append - """ - [2020-10-14 13:23] Heading Test - - H1-1 - = - - H1-2 - === - - H1-3 - ============================ - - H2-1 - - - - H2-2 - --- - - H2-3 - ---------------------------------- - - Horizontal Rules (ignore) - - --- - - === - - # ATX H1 - - ## ATX H2 - - ### ATX H3 - - #### ATX H4 - - ##### ATX H5 - - ###### ATX H6 - - Stuff - - More stuff - more stuff again - """ - Then we flush the output - When we run "jrnl -1 --export markdown" - Then the output should be - """ - # 2020 - - ## October - - ### 2020-10-14 13:23 Heading Test - - #### H1-1 - - #### H1-2 - - #### H1-3 - - ##### H2-1 - - ##### H2-2 - - ##### H2-3 - - Horizontal Rules (ignore) - - --- - - === - - #### ATX H1 - - ##### ATX H2 - - ###### ATX H3 - - ####### ATX H4 - - ######## ATX H5 - - ######### ATX H6 - - Stuff - - More stuff - more stuff again - """ - - Examples: configs - | config | - | basic_onefile | - | basic_encrypted | - | basic_folder | - # | basic_dayone | @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 ".yaml" - 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 - - ### 2020-10-29 11:11 First entry. - - - ### 2020-10-29 11:11 Second entry. - - - ### 2020-10-29 11:13 Third entry. - - """ - - Examples: configs - | config | - | basic_onefile | - | basic_encrypted | - | basic_folder | - # | basic_dayone | @todo - - @skip - Scenario Outline: Exporting to XML - Given we use the config ".yaml" - 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 there should be 10 "tag" elements - - Examples: configs - | config | - # | basic_onefile | @todo - # | basic_encrypted | @todo - # | basic_folder | @todo - # | basic_dayone | @todo - - Scenario: Exporting to XML - Given we use the config "tags.yaml" - 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 2 elements - 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 ".yaml" - 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 | - - @todo - Scenario Outline: Exporting fancy - # Needs better emoji support - Given we use the config ".yaml" - 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. ╘═══════════════╕ - ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ - ┃ Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada │ - ┃ quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus │ - ┃ pellentesque │ - ┃ augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu │ - ┃ consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In │ - ┃ commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget │ - ┃ venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. │ - ┃ │ - ┃ Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo │ - ┃ ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. │ - ┃ Suspendisse │ - ┃ potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas │ - ┃ eget │ - ┃ molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed │ - ┃ lectus │ - ┃ hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis │ - ┃ feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, │ - ┃ vestibulum │ - ┃ urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod │ - ┃ enim. │ - ┃ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget │ - ┃ 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. │ - ┖──────────────────────────────────────────────────────────────────────────────┘ - ┎──────────────────────────────────────────────────────────────╮2020-08-31 14:32 - ┃ A second entry in what I hope to be a long series. ╘═══════════════╕ - ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ - ┃ Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis │ - ┃ leo │ - ┃ vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit │ - ┃ amet, │ - ┃ consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl │ - ┃ lorem, │ - ┃ vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum │ - ┃ lectus, │ - ┃ eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium │ - ┃ id │ - ┃ lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, │ - ┃ egestas at efficitur et, ultrices vel est. Sed commodo et nibh non │ - ┃ elementum. │ - ┃ Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. │ - ┃ │ - ┃ Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel │ - ┃ vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum │ - ┃ et │ - ┃ malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis │ - ┃ sem, │ - ┃ non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel │ - ┃ ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a │ - ┃ commodo │ - ┃ eros. │ - ┃ │ - ┃ Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non │ - ┃ tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. │ - ┃ Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum │ - ┃ quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum │ - ┃ interdum. Integer id justo dui. Integer eu tellus in turpis bibendum │ - ┃ blandit. │ - ┃ Quisque auctor lacinia consectetur. │ - ┖──────────────────────────────────────────────────────────────────────────────┘ - ┎──────────────────────────────────────────────────────────────╮2020-09-24 09:14 - ┃ The third entry finally after weeks without writing. ╘═══════════════╕ - ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ - ┃ I'm so excited about emojis. 💯 🎶 💩 │ - ┃ │ - ┃ Donec semper pellentesque iaculis. Nullam cursus et justo sit amet │ - ┃ venenatis. │ - ┃ Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. │ - ┃ Nulla │ - ┃ eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis │ - ┃ dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh │ - ┃ malesuada. │ - ┃ Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis │ - ┃ 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 | - - @skip_win - Scenario Outline: Export to yaml - Given we use the config ".yaml" - 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-08-29_entry-the-first.md" in the cache should be - """ - --- - title: Entry the first. - date: 2020-08-29 11:11 - starred: False - tags: tagone, ipsum, tagtwo - body: | - Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada - quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque - augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu - consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In - commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget - venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - - Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo - ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse - potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget - molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus - hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis - feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum - urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget - 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 | - - @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 ".yaml" - 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 - starred: False - tags: tagone, tagthree - body: | I'm so excited about emojis. 💯 🎶 💩 Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. @@ -475,16 +102,373 @@ Feature: Custom formats Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis 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 - ... - """ + 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 | + + Scenario Outline: Increasing Headings on Markdown export + Given we use the config "" + And we use the password "test" if prompted + When we open the editor and append + [2020-10-14 13:23] Heading Test + + H1-1 + = + + H1-2 + === + + H1-3 + ============================ + + H2-1 + - + + H2-2 + --- + + H2-3 + ---------------------------------- + + Horizontal Rules (ignore) + + --- + + === + + # ATX H1 + + ## ATX H2 + + ### ATX H3 + + #### ATX H4 + + ##### ATX H5 + + ###### ATX H6 + + Stuff + + More stuff + more stuff again + Then we flush the output + When we run "jrnl -1 --export markdown" + Then the output should be + # 2020 + + ## October + + ### 2020-10-14 13:23 Heading Test + + #### H1-1 + + #### H1-2 + + #### H1-3 + + ##### H2-1 + + ##### H2-2 + + ##### H2-3 + + Horizontal Rules (ignore) + + --- + + === + + #### ATX H1 + + ##### ATX H2 + + ###### ATX H3 + + ####### ATX H4 + + ######## ATX H5 + + ######### ATX H6 + + Stuff + + More stuff + more stuff again + + Examples: configs + | 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 "" + 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 + + ### 2020-10-29 11:11 First entry. + + + ### 2020-10-29 11:11 Second entry. + + + ### 2020-10-29 11:13 Third entry. + + + Examples: configs + | 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 "" + 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 there should be 10 "tag" elements + + Examples: configs + | 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" + 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 2 elements + 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 "" + 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_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 "" + 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. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada │ + ┃ quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus │ + ┃ pellentesque │ + ┃ augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu │ + ┃ consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In │ + ┃ commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget │ + ┃ venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. │ + ┃ │ + ┃ Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo │ + ┃ ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. │ + ┃ Suspendisse │ + ┃ potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas │ + ┃ eget │ + ┃ molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed │ + ┃ lectus │ + ┃ hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis │ + ┃ feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, │ + ┃ vestibulum │ + ┃ urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod │ + ┃ enim. │ + ┃ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget │ + ┃ 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. │ + ┖──────────────────────────────────────────────────────────────────────────────┘ + ┎──────────────────────────────────────────────────────────────╮2020-08-31 14:32 + ┃ A second entry in what I hope to be a long series. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ Sed sit amet metus et sapien feugiat elementum. Aliquam bibendum lobortis │ + ┃ leo │ + ┃ vitae tempus. Donec eleifend nec mi non volutpat. Lorem ipsum dolor sit │ + ┃ amet, │ + ┃ consectetur adipiscing elit. Praesent ut sodales libero. Maecenas nisl │ + ┃ lorem, │ + ┃ vestibulum in tempus sit amet, fermentum ut arcu. Donec vel vestibulum │ + ┃ lectus, │ + ┃ eget pretium enim. Maecenas diam nunc, imperdiet vitae pharetra sed, pretium │ + ┃ id │ + ┃ lectus. Donec eu metus et turpis tempor tristique ac non ex. In tellus arcu, │ + ┃ egestas at efficitur et, ultrices vel est. Sed commodo et nibh non │ + ┃ elementum. │ + ┃ Mauris tempus vitae neque vel viverra. @tagtwo all by its lonesome. │ + ┃ │ + ┃ Nulla mattis elementum magna, viverra pretium dui fermentum et. Cras vel │ + ┃ vestibulum odio. Quisque sit amet turpis et urna finibus maximus. Interdum │ + ┃ et │ + ┃ malesuada fames ac ante ipsum primis in faucibus. Fusce porttitor iaculis │ + ┃ sem, │ + ┃ non dictum ipsum varius nec. Nulla eu erat at risus gravida blandit non vel │ + ┃ ante. Nam egestas ipsum leo, eu ultricies ipsum tincidunt vel. Morbi a │ + ┃ commodo │ + ┃ eros. │ + ┃ │ + ┃ Nullam dictum, nisl ac varius tempus, ex tortor fermentum nisl, non │ + ┃ tempus dolor neque a lorem. Suspendisse a faucibus ex, vel ornare tortor. │ + ┃ Maecenas tincidunt id felis quis semper. Pellentesque enim libero, fermentum │ + ┃ quis metus id, rhoncus euismod magna. Nulla finibus velit eu purus bibendum │ + ┃ interdum. Integer id justo dui. Integer eu tellus in turpis bibendum │ + ┃ blandit. │ + ┃ Quisque auctor lacinia consectetur. │ + ┖──────────────────────────────────────────────────────────────────────────────┘ + ┎──────────────────────────────────────────────────────────────╮2020-09-24 09:14 + ┃ The third entry finally after weeks without writing. ╘═══════════════╕ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ I'm so excited about emojis. 💯 🎶 💩 │ + ┃ │ + ┃ Donec semper pellentesque iaculis. Nullam cursus et justo sit amet │ + ┃ venenatis. │ + ┃ Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. │ + ┃ Nulla │ + ┃ eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis │ + ┃ dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh │ + ┃ malesuada. │ + ┃ Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis │ + ┃ 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_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 "" + And we use the password "test" if prompted + And we create a cache directory + 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 + starred: False + tags: tagone, ipsum, tagtwo + body: | + Lorem @ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada + quis est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque + augue et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu + consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In + commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget + venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. + + Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo + ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse + potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget + molestie metus. Mauris porttitor dui ornare gravida porta. Quisque sed lectus + hendrerit, lacinia ante eget, vulputate ante. Aliquam vitae erat non felis + feugiat sagittis. Phasellus quis arcu fringilla, mattis ligula id, vestibulum + urna. Vivamus facilisis leo a mi tincidunt condimentum. Donec eu euismod enim. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eu ligula eget + 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_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 "" + 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 + starred: False + tags: tagone, tagthree + body: | + I'm so excited about emojis. 💯 🎶 💩 + + Donec semper pellentesque iaculis. Nullam cursus et justo sit amet venenatis. + Vivamus tempus ex dictum metus vehicula gravida. Aliquam sed sem dolor. Nulla + eget ultrices purus. Quisque at nunc at quam pharetra consectetur vitae quis + dolor. Fusce ultricies purus eu est feugiat, quis scelerisque nibh malesuada. + Quisque egestas semper nibh in hendrerit. Nam finibus ex in mi mattis + 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_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 ".yaml" + Given we use the config "" 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 ".yaml" + Given we use the config "" 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 ".yaml" + Given we use the config "" 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 - """ + 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 ".yaml" + Given we use the config "" 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 - """ + 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 | diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index dd08502f..e0c60a5e 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -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 "') @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 diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index d04928be..145f8ed6 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -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") From 3b044e3044e572f50a3f97a043e10f4911d07987 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Apr 2021 12:19:49 -0700 Subject: [PATCH 35/74] Ignore IO errors on Windows Co-authored-by: Jonathan Wren --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 37a2f6b3..cb905a23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,12 @@ markers = [ "todo", ] +filterwarnings = [ + "ignore::DeprecationWarning", + "ignore:Flag style will be deprecated in.*", + "ignore:[WinError 32].*", + "ignore:[WinError 5].*" +] [build-system] requires = ["poetry>=1.1"] From ef6ed93ecdc8cbbaedf8937f0a2b0a34c755fe86 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Apr 2021 12:43:51 -0700 Subject: [PATCH 36/74] Add JSON parsing test and combine it with XML parsing test Co-authored-by: Jonathan Wren --- tests/features/format.feature | 8 ++++---- tests/step_defs/conftest.py | 18 +++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 2ac5cdf2..8d3b0765 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -5,7 +5,7 @@ Feature: Custom formats And we use the password "test" if prompted When we run "jrnl --format json" Then we should get no error - And the output should be parsable as json + And the output should be valid JSON And "entries" in the json output should have 3 elements And "tags" in the json output should contain "@ipsum" And "tags" in the json output should contain "@tagone" @@ -26,7 +26,7 @@ Feature: Custom formats Given we use the config "dayone.yaml" When we run "jrnl --export json" Then we should get no error - And the output should be parsable as json + And the output should be valid JSON And the json output should contain entries.0.uuid = "4BB1F46946AD439996C9B59DE7C4DDC1" Scenario Outline: Printing a journal that has multiline entries with tags @@ -67,9 +67,9 @@ Feature: Custom formats Given we use the config "" 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 + Then the output should be valid JSON Then we should get no error - And the output should be parsable as json + And the output should be valid JSON And "entries" in the json output should have 2 elements And "tags" in the json output should contain "@ipsum" And "tags" in the json output should contain "@tagone" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index e0c60a5e..b9eeec20 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -2,6 +2,7 @@ # License: https://www.gnu.org/licenses/gpl-3.0.html import ast +import json import os from collections import defaultdict from keyring import backend @@ -446,13 +447,16 @@ def cache_dir_contains_files(file_list, cache_dir): 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("the output should be valid {language_name}")) +def assert_output_is_valid_language(cli_run, language_name): + language_name = language_name.upper() + if language_name == "XML": + xml_tree = ElementTree.fromstring(cli_run["stdout"]) + assert xml_tree, "Invalid XML" + elif language_name == "JSON": + assert json.loads(cli_run["stdout"]), "Invalid JSON" + else: + assert False, f"Language name {language_name} not recognized" @then(parse('"{item}" node in the xml output should have {number:d} elements')) def assert_xml_output_entries_count(item, number, cli_run): From 3cc3e387c5d90165390e921fddb5970324bef2ae Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Apr 2021 14:26:23 -0700 Subject: [PATCH 37/74] Combine JSON and XML parsing tests Co-authored-by: Jonathan Wren --- tests/features/format.feature | 7 ++-- tests/step_defs/conftest.py | 66 +++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 8d3b0765..a06d4c95 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -265,9 +265,10 @@ Feature: Custom formats Given we use the config "tags.yaml" 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 2 elements - And "tags" in the xml output should contain + Then the output should be valid XML + Given we parse the output as XML + Then "entries" node in the parsed output should have 2 elements + And "tags" in the parsed output should be @idea @journal @dan diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index b9eeec20..1cc14f5a 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -173,6 +173,11 @@ def which_output_stream(): return None +@fixture +def parsed_output(): + return {"lang": None, "obj": None} + + # ----- STEPS ----- # @given("we have a keyring", target_fixture="keyring") @given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") @@ -447,6 +452,7 @@ def cache_dir_contains_files(file_list, cache_dir): assert actual_files == expected_files, [actual_files, expected_files] + @then(parse("the output should be valid {language_name}")) def assert_output_is_valid_language(cli_run, language_name): language_name = language_name.upper() @@ -458,30 +464,60 @@ def assert_output_is_valid_language(cli_run, language_name): else: assert False, f"Language name {language_name} not recognized" -@then(parse('"{item}" node in the xml output should have {number:d} elements')) -def assert_xml_output_entries_count(item, number, cli_run): + +@given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") +def parse_output_as_language(cli_run, language_name): + language_name = language_name.upper() 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)) + if language_name == "XML": + parsed_output = ElementTree.fromstring(output) + elif language_name == "JSON": + parsed_output = json.loads(output) + else: + assert False, f"Language name {language_name} not recognized" - actual_entry_count = len(xml_tree.find(item)) - assert actual_entry_count == number, actual_entry_count + return {"lang": language_name, "obj": parsed_output} -@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"] +@then(parse('"{node_name}" node in the parsed output should have {number:d} elements')) +def assert_parsed_output_item_count(node_name, number, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] + + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert node_name in xml_node_names, str(list(xml_node_names)) + + actual_entry_count = len(obj.find(node_name)) + assert actual_entry_count == number, actual_entry_count + + elif lang == "JSON": + assert node_name in obj, [node_name, obj] + assert len(obj[node_name]) == number, len(obj[node_name]) + + else: + assert False, f"Language name {lang} not recognized" + + +@then(parse('"tags" in the parsed output should be\n{expected_tags}')) +def assert_xml_output_tags(expected_tags, cli_run, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] expected_tags = expected_tags.split("\n") - xml_tree = ElementTree.fromstring(output) + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert "tags" in xml_node_names, str(list(xml_node_names)) - 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 obj.find("tags")) + assert actual_tags == set(expected_tags), [actual_tags, set(expected_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)] + elif lang == "JSON": + assert False, "JSON not implemented in this step" + + else: + assert False, f"Language name {lang} not recognized" @then(parse('there should be {number:d} "{item}" elements')) From 48c9d9fa166ed0a48adf719f5d447bdc5073b1df Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Apr 2021 14:58:10 -0700 Subject: [PATCH 38/74] Implement tag tests in JSON Co-authored-by: Jonathan Wren --- tests/features/format.feature | 12 +++++++----- tests/step_defs/conftest.py | 26 ++++++++++++++++++-------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index a06d4c95..811e0d5e 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -6,11 +6,13 @@ Feature: Custom formats When we run "jrnl --format json" Then we should get no error And the output should be valid JSON - And "entries" in the json output should have 3 elements - And "tags" in the json output should contain "@ipsum" - And "tags" in the json output should contain "@tagone" - And "tags" in the json output should contain "@tagthree" - And "tags" in the json output should contain "@tagtwo" + Given we parse the output as JSON + Then "entries" node in the parsed output should have 3 elements + And "tags" in the parsed output should be + @ipsum + @tagone + @tagtwo + @tagthree And entry 1 should have an array "tags" with 3 elements And entry 2 should have an array "tags" with 1 elements And entry 3 should have an array "tags" with 2 elements diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 1cc14f5a..c7732656 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -499,23 +499,33 @@ def assert_parsed_output_item_count(node_name, number, parsed_output): else: assert False, f"Language name {lang} not recognized" - -@then(parse('"tags" in the parsed output should be\n{expected_tags}')) -def assert_xml_output_tags(expected_tags, cli_run, parsed_output): +@then(parse('"{field_name}" in the parsed output should be\n{expected_keys}')) +def assert_xml_output_tags(field_name, expected_keys, cli_run, parsed_output): lang = parsed_output["lang"] obj = parsed_output["obj"] - expected_tags = expected_tags.split("\n") + expected_keys = expected_keys.split("\n") if lang == "XML": xml_node_names = (node.tag for node in obj) - assert "tags" in xml_node_names, str(list(xml_node_names)) + assert field_name in xml_node_names, str(list(xml_node_names)) - actual_tags = set(t.attrib["name"] for t in obj.find("tags")) - assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)] + if field_name == "tags": + actual_tags = set(t.attrib["name"] for t in obj.find("tags")) + assert set(actual_tags) == set(expected_keys), [actual_tags, set(expected_keys)] + else: + assert False, "This test only works for tags in XML" elif lang == "JSON": - assert False, "JSON not implemented in this step" + my_obj = obj + for node in field_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert field_name in my_obj + my_obj = my_obj[node] + + assert set(expected_keys) == set(my_obj) else: assert False, f"Language name {lang} not recognized" From 430182a0a55f0fd5ac6d8a800a71b46346737569 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Apr 2021 15:26:26 -0700 Subject: [PATCH 39/74] Implement JSON tests and remove "node" nomenclature from tests Co-authored-by: Jonathan Wren --- tests/features/format.feature | 18 ++++++++++-------- tests/step_defs/conftest.py | 29 ++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 811e0d5e..9c38216f 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -7,15 +7,15 @@ Feature: Custom formats Then we should get no error And the output should be valid JSON Given we parse the output as JSON - Then "entries" node in the parsed output should have 3 elements + Then "entries" in the parsed output should have 3 elements And "tags" in the parsed output should be @ipsum @tagone @tagtwo @tagthree - And entry 1 should have an array "tags" with 3 elements - And entry 2 should have an array "tags" with 1 elements - And entry 3 should have an array "tags" with 2 elements + And "entries.0.tags" in the parsed output should have 3 elements + And "entries.1.tags" in the parsed output should have 1 elements + And "entries.2.tags" in the parsed output should have 2 elements Examples: configs | config_file | @@ -24,12 +24,14 @@ Feature: Custom formats | basic_folder.yaml | | basic_dayone.yaml | - Scenario: Exporting dayone to json + Scenario: Exporting dayone to json should include UUID Given we use the config "dayone.yaml" When we run "jrnl --export json" Then we should get no error And the output should be valid JSON - And the json output should contain entries.0.uuid = "4BB1F46946AD439996C9B59DE7C4DDC1" + Given we parse the output as JSON + Then "entries.0.uuid" in the parsed output should be + 4BB1F46946AD439996C9B59DE7C4DDC1 Scenario Outline: Printing a journal that has multiline entries with tags Given we use the config "" @@ -248,7 +250,7 @@ Feature: Custom formats 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 "entries" in the xml output should have 3 elements And "tags" in the xml output should contain @ipsum @tagone @@ -269,7 +271,7 @@ Feature: Custom formats When we run "jrnl --export xml" Then the output should be valid XML Given we parse the output as XML - Then "entries" node in the parsed output should have 2 elements + Then "entries" in the parsed output should have 2 elements And "tags" in the parsed output should be @idea @journal diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index c7732656..7a651093 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -480,7 +480,7 @@ def parse_output_as_language(cli_run, language_name): return {"lang": language_name, "obj": parsed_output} -@then(parse('"{node_name}" node in the parsed output should have {number:d} elements')) +@then(parse('"{node_name}" in the parsed output should have {number:d} elements')) def assert_parsed_output_item_count(node_name, number, parsed_output): lang = parsed_output["lang"] obj = parsed_output["obj"] @@ -493,14 +493,23 @@ def assert_parsed_output_item_count(node_name, number, parsed_output): assert actual_entry_count == number, actual_entry_count elif lang == "JSON": - assert node_name in obj, [node_name, obj] - assert len(obj[node_name]) == number, len(obj[node_name]) + my_obj = obj + + for node in node_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert node in my_obj + my_obj = my_obj[node] + + assert len(my_obj) == number, len(my_obj) else: assert False, f"Language name {lang} not recognized" + @then(parse('"{field_name}" in the parsed output should be\n{expected_keys}')) -def assert_xml_output_tags(field_name, expected_keys, cli_run, parsed_output): +def assert_output_field_content(field_name, expected_keys, cli_run, parsed_output): lang = parsed_output["lang"] obj = parsed_output["obj"] expected_keys = expected_keys.split("\n") @@ -511,7 +520,10 @@ def assert_xml_output_tags(field_name, expected_keys, cli_run, parsed_output): if field_name == "tags": actual_tags = set(t.attrib["name"] for t in obj.find("tags")) - assert set(actual_tags) == set(expected_keys), [actual_tags, set(expected_keys)] + assert set(actual_tags) == set(expected_keys), [ + actual_tags, + set(expected_keys), + ] else: assert False, "This test only works for tags in XML" @@ -522,10 +534,13 @@ def assert_xml_output_tags(field_name, expected_keys, cli_run, parsed_output): try: my_obj = my_obj[int(node)] except ValueError: - assert field_name in my_obj + assert node in my_obj, [my_obj.keys(), node] my_obj = my_obj[node] - assert set(expected_keys) == set(my_obj) + if type(my_obj) is str: + my_obj = [my_obj] + + assert set(expected_keys) == set(my_obj), [set(my_obj), set(expected_keys)] else: assert False, f"Language name {lang} not recognized" From 11e0e84dcf5f6f56afbb24a99f7654faa5ff8d33 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 20:06:44 -0700 Subject: [PATCH 40/74] Fix test failing from lack of whitespace Co-authored-by: Jonathan Wren --- tests/features/format.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 9c38216f..d8454ce0 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -47,7 +47,7 @@ Feature: Custom formats | consequat. Aenean ante ex, elementum ut interdum et, mattis eget lacus. In | commodo nulla nec tellus placerat, sed ultricies metus bibendum. Duis eget | venenatis erat. In at dolor dui. @tagone and maybe also @tagtwo. - | + | | Curabitur accumsan nunc ac neque tristique, eleifend faucibus justo | ullamcorper. Suspendisse at mattis nunc. Nullam eget lacinia urna. Suspendisse | potenti. Ut urna est, venenatis sed ante in, ultrices congue mi. Maecenas eget From 849ed16d67f163a14f210348d0808f8519e10842 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 20:12:14 -0700 Subject: [PATCH 41/74] Install pytest-icdiff and run poetry lock Co-authored-by: Jonathan Wren --- poetry.lock | 41 ++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index e999d3af..34184977 100644 --- a/poetry.lock +++ b/poetry.lock @@ -174,6 +174,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "icdiff" +version = "1.9.1" +description = "improved colored diff" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "importlib-metadata" version = "4.5.0" @@ -382,6 +390,14 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] +[[package]] +name = "pprintpp" +version = "0.4.0" +description = "A drop-in replacement for pprint that's actually pretty" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "py" version = "1.10.0" @@ -453,6 +469,19 @@ py = "*" pytest = ">=4.3" six = ">=1.9.0" +[[package]] +name = "pytest-icdiff" +version = "0.5" +description = "use icdiff for better error messages in pytest assertions" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +icdiff = "*" +pprintpp = "*" +pytest = "*" + [[package]] name = "python-dateutil" version = "2.8.1" @@ -629,7 +658,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = ">=3.7.0, <3.10" -content-hash = "4bb72b50e012bd9b58e47835e1fd5d767ce68ac869505f77bb6ad9d564dbf139" +content-hash = "a0d3f3e30dbe80528547b49ae7bb39c6c1a911e2552d8b10d409daf81cdb28d1" [metadata.files] ansiwrap = [ @@ -730,6 +759,9 @@ ghp-import = [ glob2 = [ {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, ] +icdiff = [ + {file = "icdiff-1.9.1.tar.gz", hash = "sha256:66972dd03318da55280991db375d3ef6b66d948c67af96c1ebdb21587e86655e"}, +] importlib-metadata = [ {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, @@ -828,6 +860,10 @@ pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] +pprintpp = [ + {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, + {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, +] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, @@ -852,6 +888,9 @@ pytest-bdd = [ {file = "pytest-bdd-4.0.2.tar.gz", hash = "sha256:982489f2f036c7561affe4eeb5b392a37e1ace2a9f260cad747b1c8119e63cfd"}, {file = "pytest_bdd-4.0.2-py2.py3-none-any.whl", hash = "sha256:74ea5a147ea558c99ae83d838e6acbe5c9e6843884a958f8231615d96838733d"}, ] +pytest-icdiff = [ + {file = "pytest-icdiff-0.5.tar.gz", hash = "sha256:3a14097f4385665cb04330e6ae09a3dd430375f717e94482af6944470ad5f100"}, +] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, diff --git a/pyproject.toml b/pyproject.toml index cb905a23..eac62079 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ toml = ">=0.10" pyflakes = ">=2.2.0" pytest = ">=6.2" pytest-bdd = "^4.0.1" +pytest-icdiff = "^0.5" yq = ">=2.11" [tool.poetry.scripts] From a6a4417eff33a66c18b5545550b2a30851de5c9e Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 20:12:43 -0700 Subject: [PATCH 42/74] Fix annoying poetry-generated Windows line endings Co-authored-by: Jonathan Wren --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index d47e847c..540af298 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ *.journal text eol=lf *.feature text eol=lf +poetry.lock text eol=lf +pyrpoject.toml text eol=lf From 148d3fdb18f8378bf447052268635a5367de7ec0 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 20:16:37 -0700 Subject: [PATCH 43/74] Update test w/ new steps Co-authored-by: Jonathan Wren --- tests/features/format.feature | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index d8454ce0..330c3a06 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -74,12 +74,14 @@ Feature: Custom formats Then the output should be valid JSON Then we should get no error And the output should be valid JSON - And "entries" in the json output should have 2 elements - And "tags" in the json output should contain "@ipsum" - And "tags" in the json output should contain "@tagone" - And "tags" in the json output should contain "@tagtwo" - And entry 1 should have an array "tags" with 3 elements - And entry 2 should have an array "tags" with 1 elements + Given we parse the output as JSON + Then "entries" in the parsed output should have 2 elements + And "tags" in the parsed output should be + @ipsum + @tagone + @tagtwo + And "entries.0.tags" in the parsed output should have 3 elements + And "entries.1.tags" in the parsed output should have 1 elements Examples: configs | config_file | From 36dc01bf306f18a5379f4c508172825a342d7c31 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 20:50:33 -0700 Subject: [PATCH 44/74] Fixing custom template test and skipping some broken tests Co-authored-by: Jonathan Wren --- tests/features/format.feature | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 330c3a06..ef126a5b 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -92,7 +92,6 @@ Feature: Custom formats Scenario Outline: Exporting using custom templates Given we use the config "" - 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 @@ -117,6 +116,7 @@ Feature: Custom formats | basic_folder.yaml | | basic_dayone.yaml | + @skip # .TODO return after editor steps implemented Scenario Outline: Increasing Headings on Markdown export Given we use the config "" And we use the password "test" if prompted @@ -214,6 +214,7 @@ Feature: Custom formats | basic_folder.yaml | # | basic_dayone.yaml | @todo + @skip # .TODO return after editor steps implemented 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 @@ -431,7 +432,7 @@ Feature: Custom formats porta sapien accumsan. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. ... - + Examples: configs | config_file | | basic_onefile.yaml | From ce64d7973bf7a7e09b3d61593fe392f763b6cbca Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Mon, 19 Apr 2021 21:12:37 -0700 Subject: [PATCH 45/74] Implement @skip_win and @skip_editor Co-authored-by: Jonathan Wren --- tests/features/format.feature | 4 ++-- tests/step_defs/conftest.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index ef126a5b..648b4dd0 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -116,7 +116,7 @@ Feature: Custom formats | basic_folder.yaml | | basic_dayone.yaml | - @skip # .TODO return after editor steps implemented + @skip_editor # .TODO return after editor steps implemented Scenario Outline: Increasing Headings on Markdown export Given we use the config "" And we use the password "test" if prompted @@ -214,7 +214,7 @@ Feature: Custom formats | basic_folder.yaml | # | basic_dayone.yaml | @todo - @skip # .TODO return after editor steps implemented + @skip_editor # .TODO return after editor steps implemented 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 diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 7a651093..7e10883e 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -22,12 +22,14 @@ from pytest_bdd import when from pytest_bdd.parsers import parse from pytest_bdd import parsers from pytest import fixture +from pytest import mark import toml from jrnl import __version__ from jrnl.cli import cli from jrnl.config import load_config from jrnl.os_compat import split_args +from jrnl.os_compat import on_windows class TestKeyring(backend.KeyringBackend): @@ -79,6 +81,22 @@ class FailedKeyring(backend.KeyringBackend): raise errors.KeyringError +# ----- MARKERS ----- # +def pytest_bdd_apply_tag(tag, function): + if tag == "skip_win": + marker = mark.skipif(on_windows, reason="Skip test on Windows") + elif tag == "skip_editor": + marker = mark.skip( + reason="Skipping editor-related test. We should come back to this!" + ) + else: + # Fall back to pytest-bdd's default behavior + return None + + marker(function) + return True + + # ----- UTILS ----- # def failed_msg(msg, expected, actual): return f"{msg}\nExpected:\n{expected}\n---end---\nActual:\n{actual}\n---end---\n" From 3ddfb4d5949eb687605b1b27246a69ba8a7e2ba8 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 24 Apr 2021 14:47:52 -0700 Subject: [PATCH 46/74] Implement editor-related steps in pytest-bdd - Implement mock editor fixture - Add fixture to keep track of editor state - Implement various steps to check editor state Co-authored-by: Micah Jerome Ellison --- jrnl/editor.py | 2 +- poetry.lock | 287 ++++++++++++++++++++++++++++--- pyproject.toml | 9 +- tests/features/write.feature | 175 ++++++++++--------- tests/step_defs/conftest.py | 119 ++++++++++++- tests/step_defs/test_features.py | 16 +- 6 files changed, 475 insertions(+), 133 deletions(-) diff --git a/jrnl/editor.py b/jrnl/editor.py index 086d84db..7c7413e8 100644 --- a/jrnl/editor.py +++ b/jrnl/editor.py @@ -26,7 +26,7 @@ def get_text_from_editor(config, template=""): try: subprocess.call(split_args(config["editor"]) + [tmpfile]) - except Exception as e: + except FileNotFoundError as e: error_msg = f""" {ERROR_COLOR}{str(e)}{RESET_COLOR} diff --git a/poetry.lock b/poetry.lock index 34184977..65670545 100644 --- a/poetry.lock +++ b/poetry.lock @@ -17,6 +17,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "appnope" +version = "0.1.2" +description = "Disable App Nap on macOS >= 10.9" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "argcomplete" version = "1.12.3" @@ -61,6 +69,14 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "behave" version = "1.2.6" @@ -152,6 +168,14 @@ sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +[[package]] +name = "decorator" +version = "5.0.9" +description = "Decorators for Humans" +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "ghp-import" version = "2.0.1" @@ -174,14 +198,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "icdiff" -version = "1.9.1" -description = "improved colored diff" -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "importlib-metadata" version = "4.5.0" @@ -206,6 +222,74 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "ipdb" +version = "0.13.9" +description = "IPython-enabled pdb" +category = "dev" +optional = false +python-versions = ">=2.7" + +[package.dependencies] +decorator = {version = "*", markers = "python_version > \"3.6\""} +ipython = {version = ">=7.17.0", markers = "python_version > \"3.6\""} +toml = {version = ">=0.10.2", markers = "python_version > \"3.6\""} + +[[package]] +name = "ipython" +version = "7.24.1" +description = "IPython: Productive Interactive Computing" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" +traitlets = ">=4.2" + +[package.extras] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["notebook", "ipywidgets"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.17)"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "jedi" +version = "0.18.0" +description = "An autocompletion tool for Python that can be used for text editors." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +parso = ">=0.8.0,<0.9.0" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] + [[package]] name = "jeepney" version = "0.6.0" @@ -286,6 +370,17 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "matplotlib-inline" +version = "0.1.2" +description = "Inline Matplotlib backend for Jupyter" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +traitlets = "*" + [[package]] name = "mergedeep" version = "1.3.4" @@ -368,6 +463,18 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "parso" +version = "0.8.2" +description = "A Python Parser" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + [[package]] name = "pathspec" version = "0.8.1" @@ -376,6 +483,25 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "pluggy" version = "0.13.1" @@ -391,9 +517,20 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} dev = ["pre-commit", "tox"] [[package]] -name = "pprintpp" -version = "0.4.0" -description = "A drop-in replacement for pprint that's actually pretty" +name = "prompt-toolkit" +version = "3.0.19" +description = "Library for building powerful interactive command lines in Python" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" category = "dev" optional = false python-versions = "*" @@ -422,6 +559,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pygments" +version = "2.9.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "pyparsing" version = "2.4.7" @@ -470,17 +615,16 @@ pytest = ">=4.3" six = ">=1.9.0" [[package]] -name = "pytest-icdiff" -version = "0.5" -description = "use icdiff for better error messages in pytest assertions" +name = "pytest-clarity" +version = "0.3.0a0" +description = "A plugin providing an alternative, colourful diff output for failing assertions." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] -icdiff = "*" -pprintpp = "*" -pytest = "*" +pytest = ">=3.5.0" +termcolor = "1.1.0" [[package]] name = "python-dateutil" @@ -564,6 +708,14 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "termcolor" +version = "1.1.0" +description = "ANSII Color formatting for output in terminal." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "textwrap3" version = "0.9.2" @@ -580,6 +732,20 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "traitlets" +version = "5.0.5" +description = "Traitlets Python configuration system" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ipython-genutils = "*" + +[package.extras] +test = ["pytest"] + [[package]] name = "typed-ast" version = "1.4.3" @@ -618,6 +784,14 @@ python-versions = ">=3.6" [package.extras] watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "xmltodict" version = "0.12.0" @@ -658,7 +832,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = ">=3.7.0, <3.10" -content-hash = "a0d3f3e30dbe80528547b49ae7bb39c6c1a911e2552d8b10d409daf81cdb28d1" +content-hash = "d9a47064f2050860c955a0871b2bd8899c2f24aaf6482f6a742316fd1fd95ba3" [metadata.files] ansiwrap = [ @@ -669,6 +843,10 @@ appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +appnope = [ + {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, + {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, +] argcomplete = [ {file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"}, {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, @@ -684,6 +862,10 @@ attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +backcall = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] behave = [ {file = "behave-1.2.6-py2.py3-none-any.whl", hash = "sha256:ebda1a6c9e5bfe95c5f9f0a2794e01c7098b3dde86c10a95d8621c5907ff6f1c"}, {file = "behave-1.2.6.tar.gz", hash = "sha256:b9662327aa53294c1351b0a9c369093ccec1d21026f050c3bd9b3e5cccf81a86"}, @@ -753,15 +935,16 @@ cryptography = [ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"}, {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"}, ] +decorator = [ + {file = "decorator-5.0.9-py3-none-any.whl", hash = "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323"}, + {file = "decorator-5.0.9.tar.gz", hash = "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"}, +] ghp-import = [ {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, ] glob2 = [ {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, ] -icdiff = [ - {file = "icdiff-1.9.1.tar.gz", hash = "sha256:66972dd03318da55280991db375d3ef6b66d948c67af96c1ebdb21587e86655e"}, -] importlib-metadata = [ {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, @@ -770,6 +953,21 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +ipdb = [ + {file = "ipdb-0.13.9.tar.gz", hash = "sha256:951bd9a64731c444fd907a5ce268543020086a697f6be08f7cc2c9a752a278c5"}, +] +ipython = [ + {file = "ipython-7.24.1-py3-none-any.whl", hash = "sha256:d513e93327cf8657d6467c81f1f894adc125334ffe0e4ddd1abbb1c78d828703"}, + {file = "ipython-7.24.1.tar.gz", hash = "sha256:9bc24a99f5d19721fb8a2d1408908e9c0520a17fff2233ffe82620847f17f1b6"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +jedi = [ + {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, + {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, +] jeepney = [ {file = "jeepney-0.6.0-py3-none-any.whl", hash = "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae"}, {file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"}, @@ -825,6 +1023,10 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] +matplotlib-inline = [ + {file = "matplotlib-inline-0.1.2.tar.gz", hash = "sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"}, + {file = "matplotlib_inline-0.1.2-py3-none-any.whl", hash = "sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811"}, +] mergedeep = [ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, @@ -852,17 +1054,33 @@ parsedatetime = [ {file = "parsedatetime-2.6-py3-none-any.whl", hash = "sha256:cb96edd7016872f58479e35879294258c71437195760746faffedb692aef000b"}, {file = "parsedatetime-2.6.tar.gz", hash = "sha256:4cb368fbb18a0b7231f4d76119165451c8d2e35951455dfee97c62a87b04d455"}, ] +parso = [ + {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, + {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, +] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, ] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] -pprintpp = [ - {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, - {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"}, + {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"}, +] +ptyprocess = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, ] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, @@ -876,6 +1094,10 @@ pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] +pygments = [ + {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, + {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -888,8 +1110,8 @@ pytest-bdd = [ {file = "pytest-bdd-4.0.2.tar.gz", hash = "sha256:982489f2f036c7561affe4eeb5b392a37e1ace2a9f260cad747b1c8119e63cfd"}, {file = "pytest_bdd-4.0.2-py2.py3-none-any.whl", hash = "sha256:74ea5a147ea558c99ae83d838e6acbe5c9e6843884a958f8231615d96838733d"}, ] -pytest-icdiff = [ - {file = "pytest-icdiff-0.5.tar.gz", hash = "sha256:3a14097f4385665cb04330e6ae09a3dd430375f717e94482af6944470ad5f100"}, +pytest-clarity = [ + {file = "pytest-clarity-0.3.0a0.tar.gz", hash = "sha256:5cc99e3d9b7969dfe17e5f6072d45a917c59d363b679686d3c958a1ded2e4dcf"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, @@ -985,6 +1207,9 @@ six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +termcolor = [ + {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, +] textwrap3 = [ {file = "textwrap3-0.9.2-py2.py3-none-any.whl", hash = "sha256:bf5f4c40faf2a9ff00a9e0791fed5da7415481054cef45bb4a3cfb1f69044ae0"}, {file = "textwrap3-0.9.2.zip", hash = "sha256:5008eeebdb236f6303dcd68f18b856d355f6197511d952ba74bc75e40e0c3414"}, @@ -993,6 +1218,10 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +traitlets = [ + {file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"}, + {file = "traitlets-5.0.5.tar.gz", hash = "sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396"}, +] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, @@ -1053,6 +1282,10 @@ watchdog = [ {file = "watchdog-2.1.2-py3-none-win_ia64.whl", hash = "sha256:104266a778906ae0e971368d368a65c4cd032a490a9fca5ba0b78c6c7ae11720"}, {file = "watchdog-2.1.2.tar.gz", hash = "sha256:0237db4d9024859bea27d0efb59fe75eef290833fd988b8ead7a879b0308c2db"}, ] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] xmltodict = [ {file = "xmltodict-0.12.0-py2.py3-none-any.whl", hash = "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051"}, {file = "xmltodict-0.12.0.tar.gz", hash = "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21"}, diff --git a/pyproject.toml b/pyproject.toml index eac62079..2719b954 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,8 +51,9 @@ toml = ">=0.10" pyflakes = ">=2.2.0" pytest = ">=6.2" pytest-bdd = "^4.0.1" -pytest-icdiff = "^0.5" yq = ">=2.11" +ipdb = ">=0.13" +pytest-clarity = "^0.3.0-alpha.0" [tool.poetry.scripts] jrnl = 'jrnl.cli:cli' @@ -66,9 +67,15 @@ force_sort_within_sections = true [tool.pytest.ini_options] minversion = "6.0" +required_plugins = [ + "pytest-bdd" +] markers = [ "todo", ] +addopts = [ + "--pdbcls=IPython.terminal.debugger:Pdb" +] filterwarnings = [ "ignore::DeprecationWarning", diff --git a/tests/features/write.feature b/tests/features/write.feature index eb22e480..aec325d5 100644 --- a/tests/features/write.feature +++ b/tests/features/write.feature @@ -1,49 +1,49 @@ Feature: Writing new entries. Scenario Outline: Multiline entry with punctuation should keep title punctuation - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl This is. the title\\n This is the second line" And we run "jrnl -n 1" Then the output should contain "This is. the title" Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone | - | encrypted | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | + | encrypted.yaml | Scenario Outline: Single line entry with period should be split at period - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl This is. the title" And we run "jrnl -1" Then the output should contain "| the title" Examples: configs - | config_file | - | basic_onefile | - | basic_encrypted | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: CJK entry should be split at fullwidth period without following space. - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl 七転び。八起き" And we run "jrnl -1" Then the output should contain "| 八起き" Examples: configs - | config_file | - | basic_onefile | - | basic_encrypted | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Writing an entry from command line should store the entry - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." Then we should see the message "Entry added" @@ -51,49 +51,47 @@ Feature: Writing new entries. Then the output should contain "2013-07-23 09:00 A cold and stormy day." Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone | - | encrypted | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | + | encrypted.yaml | Scenario Outline: Writing a partial entry from command line with edit flag should go to the editor - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl this is a partial --edit" Then we should see the message "Entry added" Then the editor should have been called And the editor file content should be - """ - this is a partial - """ - When we run "jrnl -n 1" - Then the output should contain "this is a partial" + this is a partial Examples: configs - | config_file | - | basic_onefile | - | basic_encrypted | - | basic_dayone | - | basic_folder | + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + | basic_dayone.yaml | + | basic_folder.yaml | Scenario Outline: Writing an empty entry from the editor should yield "Nothing saved to file" message - Given we use the config ".yaml" + Given we use the config "" + And we write nothing to the editor if opened And we use the password "test" if prompted - When we open the editor and enter nothing + When we run "jrnl --edit" Then the error output should contain "[Nothing saved to file]" + And the editor should have been called Examples: configs - | config_file | - | editor | - | editor_empty_folder | - | dayone | - | basic_encrypted | - | basic_onefile | + | config_file | + | editor.yaml | + | editor_empty_folder.yaml | + | dayone.yaml | + | basic_encrypted.yaml | + | basic_onefile.yaml | @skip Scenario Outline: Writing an empty entry from the command line with no editor should yield nothing - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl" and enter nothing Then the output should be empty @@ -101,15 +99,15 @@ Feature: Writing new entries. And the editor should not have been called Examples: configs - | config_file | - | simple | - | empty_folder | - | encrypted | - # | dayone | @todo + | config_file | + | config_simple.yaml | + | empty_folder.yaml | + | encrypted.yaml | + # | dayone | @todo Scenario Outline: Writing an entry does not print the entire journal # https://github.com/jrnl-org/jrnl/issues/87 - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." Then we should see the message "Entry added" @@ -117,33 +115,31 @@ Feature: Writing new entries. Then the output should not contain "Life is good" Examples: configs - | config_file | - | editor | - | editor_empty_folder | - | dayone | - | encrypted | + | config_file | + | editor.yaml | + | editor_empty_folder.yaml | + | dayone.yaml | + | encrypted.yaml | Scenario Outline: Embedded period stays in title - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic." Then we should see the message "Entry added" When we run "jrnl -1" Then the output should be - """ - 2014-04-24 09:00 Created a new website - empty.com. - | Hope to get a lot of traffic. - """ + 2014-04-24 09:00 Created a new website - empty.com. + | Hope to get a lot of traffic. Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone | - | encrypted | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | + | encrypted.yaml | Scenario Outline: Write and read emoji support - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘" Then we should see the message "Entry added" @@ -152,14 +148,14 @@ Feature: Writing new entries. And the output should contain "🐘" Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone | - | encrypted | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | + | encrypted.yaml | Scenario Outline: Writing an entry at the prompt (no editor) should store the entry - Given we use the config ".yaml" + Given we use the config "" And we use the password "bad doggie no biscuit" if prompted When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive." Then we should get no error @@ -168,10 +164,10 @@ Feature: Writing new entries. And the output should contain "| He's alive." Examples: configs - | config_file | - | simple | - | empty_folder | - | encrypted | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | encrypted.yaml | @todo Scenario: Writing an entry at the prompt (no editor) in DayOne journal @@ -187,26 +183,29 @@ Feature: Writing new entries. Given we use the config "dayone.yaml" When we run "jrnl 01 may 1979: Being born hurts." And we run "jrnl --export json" - Then "entries" in the json output should have 5 elements - And the json output should contain entries.0.creator.software_agent - And the json output should contain entries.0.creator.os_agent - And the json output should contain entries.0.creator.host_name - And the json output should contain entries.0.creator.generation_date - And the json output should contain entries.0.creator.device_agent - And "entries.0.creator.software_agent" in the json output should contain "jrnl" + Then we should get no error + And the output should be valid JSON + Given we parse the output as JSON + Then "entries" in the parsed output should have 5 elements + And "entries.0.creator" in the parsed output should be + software_agent + os_agent + host_name + generation_date + device_agent + And "entries.0.creator.software_agent" in the parsed output should contain + jrnl # fails when system time is UTC (as on Travis-CI) - @skip + # @skip Scenario: Title with an embedded period on DayOne journal Given we use the config "dayone.yaml" When we run "jrnl 04-24-2014: "Ran 6.2 miles today in 1:02:03. I'm feeling sore because I forgot to stretch."" Then we should see the message "Entry added" When we run "jrnl -1" Then the output should be - """ - 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. - | I'm feeling sore because I forgot to stretch. - """ + 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. + | I'm feeling sore because I forgot to stretch. Scenario: Opening an folder that's not a DayOne folder should treat as folder journal Given we use the config "empty_folder.yaml" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 7e10883e..4c1d42d4 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -8,6 +8,7 @@ from collections import defaultdict from keyring import backend from keyring import set_keyring from keyring import errors +from pathlib import Path import random import string import re @@ -191,12 +192,88 @@ def which_output_stream(): return None +@fixture +def editor_input(): + return None + + +@fixture +def num_args(): + return None + + @fixture def parsed_output(): return {"lang": None, "obj": None} +@fixture +def editor_state(): + return { + "command": "", + "intent": {"method": "r", "input": None}, + "tmpfile": {"name": None, "content": None}, + } + + +@fixture +def editor(editor_state): + def _mock_editor(editor_command): + tmpfile = editor_command[-1] + + editor_state["command"] = editor_command + editor_state["tmpfile"]["name"] = tmpfile + + Path(tmpfile).touch() + with open(tmpfile, editor_state["intent"]["method"]) as f: + # Touch the file so jrnl knows it was edited + if editor_state["intent"]["input"] != None: + f.write(editor_state["intent"]["input"]) + + file_content = f.read() + editor_state["tmpfile"]["content"] = file_content + + return _mock_editor + + # ----- STEPS ----- # +@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) +@given(parse("we {editor_method} nothing to the editor if opened")) +def we_enter_editor(editor_method, editor_input, editor_state): + file_method = editor_state["intent"]["method"] + if editor_method == "write": + file_method = "w+" + elif editor_method == "append": + file_method = "a+" + else: + assert False, f"Method '{editor_method}' not supported" + + editor_state["intent"] = {"method": file_method, "input": editor_input} + + +@then(parse("the editor should have been called")) +@then(parse("the editor should have been called with {num_args} arguments")) +def count_editor_args(num_args, cli_run, editor_state): + assert cli_run["mocks"]["editor"].called + + if isinstance(num_args, int): + assert len(editor_state["command"]) == int(num_args) + + +@then(parse('the editor file content should {comparison} "{str_value}"')) +@then(parse("the editor file content should {comparison} empty")) +@then(parse("the editor file content should {comparison}\n{str_value}")) +def contains_editor_file(comparison, str_value, editor_state): + content = editor_state["tmpfile"]["content"] + # content = f'\n"""\n{content}\n"""\n' + if comparison == "be": + assert content == str_value + elif comparison == "contain": + assert str_value in content + else: + assert False, f"Comparison '{comparison}' not supported" + + @given("we have a keyring", target_fixture="keyring") @given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") def we_have_type_of_keyring(keyring_type): @@ -245,7 +322,15 @@ def use_password_forever(pw): @when('we run "jrnl "') @when('we run "jrnl"') def we_run( - command, config_path, user_input, cli_run, capsys, password, keyring, cache_dir + command, + config_path, + user_input, + cli_run, + capsys, + password, + keyring, + cache_dir, + editor, ): if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -270,7 +355,8 @@ def we_run( patch("builtins.input", side_effect=user_input) as mock_input, \ patch("getpass.getpass", side_effect=password) as mock_getpass, \ patch("jrnl.install.get_config_path", return_value=config_path), \ - patch("jrnl.config.get_config_path", return_value=config_path) \ + patch("jrnl.config.get_config_path", return_value=config_path), \ + patch("subprocess.call", side_effect=editor) as mock_editor \ : # @TODO: single point of truth for get_config_path (move from all calls from install to config) try: cli(args) @@ -290,6 +376,7 @@ def we_run( "stdin": mock_stdin, "input": mock_input, "getpass": mock_getpass, + "editor": mock_editor, } @@ -526,11 +613,15 @@ def assert_parsed_output_item_count(node_name, number, parsed_output): assert False, f"Language name {lang} not recognized" -@then(parse('"{field_name}" in the parsed output should be\n{expected_keys}')) -def assert_output_field_content(field_name, expected_keys, cli_run, parsed_output): +@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) +def assert_output_field_content( + field_name, comparison, expected_keys, cli_run, parsed_output +): lang = parsed_output["lang"] obj = parsed_output["obj"] expected_keys = expected_keys.split("\n") + if len(expected_keys) == 1: + expected_keys = expected_keys[0] if lang == "XML": xml_node_names = (node.tag for node in obj) @@ -555,10 +646,22 @@ def assert_output_field_content(field_name, expected_keys, cli_run, parsed_outpu assert node in my_obj, [my_obj.keys(), node] my_obj = my_obj[node] - if type(my_obj) is str: - my_obj = [my_obj] - - assert set(expected_keys) == set(my_obj), [set(my_obj), set(expected_keys)] + if comparison == "be": + if type(my_obj) is str: + assert expected_keys == my_obj, [my_obj, expected_keys] + else: + assert set(expected_keys) == set(my_obj), [ + set(my_obj), + set(expected_keys), + ] + elif comparison == "contain": + if type(my_obj) is str: + assert expected_keys in my_obj, [my_obj, expected_keys] + else: + assert all(elem in my_obj for elem in expected_keys), [ + my_obj, + expected_keys, + ] else: assert False, f"Language name {lang} not recognized" diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py index 145f8ed6..4c8d5ef9 100644 --- a/tests/step_defs/test_features.py +++ b/tests/step_defs/test_features.py @@ -5,13 +5,13 @@ scenarios("../features/core.feature") scenarios("../features/datetime.feature") scenarios("../features/delete.feature") scenarios("../features/encrypt.feature") -# scenarios("../features/file_storage.feature") +scenarios("../features/file_storage.feature") scenarios("../features/format.feature") -# scenarios("../features/import.feature") -# scenarios("../features/multiple_journals.feature") +scenarios("../features/import.feature") +scenarios("../features/multiple_journals.feature") scenarios("../features/password.feature") -# scenarios("../features/search.feature") -# scenarios("../features/star.feature") -# scenarios("../features/tag.feature") -# scenarios("../features/upgrade.feature") -# scenarios("../features/write.feature") +scenarios("../features/search.feature") +scenarios("../features/star.feature") +scenarios("../features/tag.feature") +scenarios("../features/upgrade.feature") +scenarios("../features/write.feature") From d15e6839556bc19774743f749dba5b4ad56f6acf Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 24 Apr 2021 15:06:54 -0700 Subject: [PATCH 47/74] Update search features to use new steps Co-authored-by: Jonathan Wren --- tests/features/search.feature | 247 +++++++++++++++------------------- 1 file changed, 111 insertions(+), 136 deletions(-) diff --git a/tests/features/search.feature b/tests/features/search.feature index 22351b7e..0bd0fb79 100644 --- a/tests/features/search.feature +++ b/tests/features/search.feature @@ -1,7 +1,7 @@ Feature: Searching in a journal Scenario Outline: Displaying entries using -on today should display entries created today - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl today: Adding an entry right now." Then we should see the message "Entry added" When we run "jrnl -on today" @@ -10,13 +10,13 @@ Feature: Searching in a journal And the output should not contain "Life is good" Examples: configs - | config | - | simple | - | empty_folder | - | dayone | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | Scenario Outline: Displaying entries using -from day should display correct entries - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl yesterday: This thing happened yesterday" Then we should see the message "Entry added" When we run "jrnl today at 11:59pm: Adding an entry right now." @@ -29,13 +29,13 @@ Feature: Searching in a journal And the output should not contain "This thing happened yesterday" Examples: configs - | config | - | simple | - | empty_folder | - | dayone | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | Scenario Outline: Displaying entries using -from and -to day should display correct entries - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl yesterday: This thing happened yesterday" Then we should see the message "Entry added" When we run "jrnl today at 11:59pm: Adding an entry right now." @@ -48,75 +48,72 @@ Feature: Searching in a journal And the output should not contain "A future entry." Examples: configs - | config | - | simple | - | empty_folder | - | dayone | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | Scenario Outline: Searching for a string - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl -contains first --short" Then we should get no error And the output should be - """ - 2020-08-29 11:11 Entry the first. - """ + 2020-08-29 11:11 Entry the first. Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Searching for a string within tag results - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl @tagone -contains maybe" Then we should get no error And the output should contain "maybe" Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Searching for a string within AND tag results - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl -and @tagone @tagtwo -contains maybe" Then we should get no error And the output should contain "maybe" Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Searching for a string within NOT tag results - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl -not @tagone -contains lonesome" Then we should get no error And the output should contain "lonesome" Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Searching for dates - Given we use the config ".yaml" + Given we use the config "" 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." - Then we flush the output When we run "jrnl -on 'august 31 2020' --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_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario: Out of order entries to a Folder journal should be listed in date order Given we use the config "empty_folder.yaml" @@ -126,74 +123,64 @@ Feature: Searching in a journal Then we should see the message "Entry added" When we run "jrnl -2" Then the output should be - """ - 2013-07-23 09:00 Testing folder journal. + 2013-07-23 09:00 Testing folder journal. - 2014-03-07 16:37 Second entry of journal. - """ + 2014-03-07 16:37 Second entry of journal. Scenario Outline: Searching for all tags should show counts of each tag - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl --tags" Then we should get no error And the output should be - """ - @tagtwo : 2 - @tagone : 2 - @tagthree : 1 - @ipsum : 1 - """ + @tagtwo : 2 + @tagone : 2 + @tagthree : 1 + @ipsum : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Filtering journals should also filter tags - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl -from 'september 2020' --tags" Then we should get no error And the output should be - """ - @tagthree : 1 - @tagone : 1 - """ + @tagthree : 1 + @tagone : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Excluding a tag should filter out all entries with that tag - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl --tags -not @tagtwo" Then the output should be - """ - @tagthree : 1 - @tagone : 1 - """ + @tagthree : 1 + @tagone : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Excluding multiple tags should filter out all entries with those tags - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl --tags -not @tagone -not @tagthree" Then the output should be - """ - @tagtwo : 1 - """ + @tagtwo : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario: DayOne tag searching should work with tags containing a mixture of upper and lower case. # https://github.com/jrnl-org/jrnl/issues/354 @@ -206,113 +193,101 @@ Feature: Searching in a journal When we run "jrnl -2" Then we should get no error And the output should be - """ - 2013-06-09 15:39 My first entry. - | Everything is alright + 2013-06-09 15:39 My first entry. + | Everything is alright - 2013-06-10 15:40 Life is good. - | But I'm better. - """ + 2013-06-10 15:40 Life is good. + | But I'm better. Scenario Outline: Searching by month - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl -month 9 --short" Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." - And we flush the output When we run "jrnl -month Sept --short" Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." - And we flush the output When we run "jrnl -month September --short" Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." 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: Searching by day - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl -day 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: Searching by year - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl 2019-01-01 01:01: I like this year." And we run "jrnl -year 2019 --short" Then the output should be "2019-01-01 01:01 I like this year." - And we flush the output When we run "jrnl -year 19 --short" Then the output should be "2019-01-01 01:01 I like this year." 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: Combining month, day, and year search terms - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl -month 08 -day 29 --short" Then the output should be "2020-08-29 11:11 Entry the first." - And we flush the output When we run "jrnl -day 29 -year 2020 --short" Then the output should be "2020-08-29 11:11 Entry the first." - And we flush the output When we run "jrnl -month 09 -year 2020 --short" Then the output should be "2020-09-24 09:14 The third entry finally after weeks without writing." - And we flush the output When we run "jrnl -month 08 -day 29 -year 2020 --short" Then the output should be "2020-08-29 11:11 Entry the first." 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: Searching today in history - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted And we set current date and time to "2020-08-31 14:32" When we run "jrnl 2019-08-31 01:01: Hi, from last year." And we run "jrnl -today-in-history --short" Then the output should be - """ - 2019-08-31 01:01 Hi, from last year. - 2020-08-31 14:32 A second entry in what I hope to be a long series. - """ + 2019-08-31 01:01 Hi, from last year. + 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: Loading a DayOne Journal Given we use the config "dayone.yaml" When we run "jrnl -from 'feb 2013'" Then we should get no error And the output should be - """ - 2013-05-17 11:39 This entry has tags! + 2013-05-17 11:39 This entry has tags! - 2013-06-17 20:38 This entry has a location. + 2013-06-17 20:38 This entry has a location. - 2013-07-17 11:38 This entry is starred! - """ + 2013-07-17 11:38 This entry is starred! From 8faa3ae32d876163eb3380fb9907ec8564f9f031 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 24 Apr 2021 15:06:10 -0700 Subject: [PATCH 48/74] Update tests to use new steps Co-authored-by: Micah Jerome Ellison --- tests/features/file_storage.feature | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/features/file_storage.feature b/tests/features/file_storage.feature index 33619365..24407fa1 100644 --- a/tests/features/file_storage.feature +++ b/tests/features/file_storage.feature @@ -4,43 +4,38 @@ Feature: Journals iteracting with the file system in a way that users can see Given we use the config "empty_folder.yaml" When we run "jrnl 23 July 2013: Testing folder journal." Then we should see the message "Entry added" - When the journal directory is listed - Then the output should contain "2013/07/23.txt" or "2013\07\23.txt" + And the journal directory should contain + 2013/07/23.txt Scenario: Adding multiple entries to a Folder journal should generate multiple date files Given we use the config "empty_folder.yaml" When we run "jrnl 23 July 2013: Testing folder journal." And we run "jrnl 3/7/2014: Second entry of journal." Then we should see the message "Entry added" - When the journal directory is listed - Then the output should contain "2013/07/23.txt" or "2013\07\23.txt" - Then the output should contain "2014/03/07.txt" or "2014\03\07.txt" + And the journal directory should contain + 2013/07/23.txt Scenario: If the journal and its parent directory don't exist, they should be created Given we use the config "missing_directory.yaml" Then the journal should not exist When we run "jrnl This is a new entry in my journal" Then the journal should exist - When we run "jrnl -n 1" + When we run "jrnl -99 --short" Then the output should contain "This is a new entry in my journal" - And the journal should have 1 entry Scenario: If the journal file doesn't exist, then it should be created Given we use the config "missing_journal.yaml" Then the journal should not exist When we run "jrnl This is a new entry in my journal" Then the journal should exist - When we run "jrnl -n 1" + When we run "jrnl -99 --short" Then the output should contain "This is a new entry in my journal" - And the journal should have 1 entry Scenario: Creating journal with relative path should update to absolute path Given we use the config "missingconfig" When we run "jrnl hello world" and enter - """ - test.txt - n - """ + test.txt + n And we change directory to "features" And we run "jrnl -n 1" Then the output should contain "hello world" @@ -48,6 +43,7 @@ Feature: Journals iteracting with the file system in a way that users can see Scenario: the temporary filename suffix should default to ".jrnl" Given we use the config "editor.yaml" When we run "jrnl --edit" + Then the editor should have been called Then the temporary filename suffix should be ".jrnl" Scenario: the temporary filename suffix should be "-{template_filename}" From 3d29b6b6a1cf6e35278339d0ef8f39667208da5f Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 24 Apr 2021 15:18:11 -0700 Subject: [PATCH 49/74] Fix star and tag feature language and add output should be empty test Co-authored-by: Jonathan Wren --- tests/features/star.feature | 20 ++++++++--------- tests/features/tag.feature | 45 +++++++++++++++++-------------------- tests/step_defs/conftest.py | 15 +++++++------ 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/tests/features/star.feature b/tests/features/star.feature index f0188056..7b1b42f1 100644 --- a/tests/features/star.feature +++ b/tests/features/star.feature @@ -1,20 +1,20 @@ Feature: Starring entries Scenario Outline: Starring an entry will mark it in the journal file - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl 20 july 2013 *: Best day of my life!" Then we should see the message "Entry added" When we run "jrnl -on 2013-07-20 -starred" Then the output should contain "2013-07-20 09:00 Best day of my life!" Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone.yaml | Scenario Outline: Filtering by starred entries will show only starred entries - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl -starred" Then the output should be empty When we run "jrnl 20 july 2013 *: Best day of my life!" @@ -22,10 +22,10 @@ Feature: Starring entries Then the output should be "2013-07-20 09:00 Best day of my life!" Examples: configs - | config_file | - | simple | - | empty_folder | - | dayone_empty | + | config_file | + | simple.yaml | + | empty_folder.yaml | + | dayone_empty.yaml | Scenario: Starring an entry will mark it in an encrypted journal Given we use the config "encrypted.yaml" diff --git a/tests/features/tag.feature b/tests/features/tag.feature index b7b687b5..a62b5ac8 100644 --- a/tests/features/tag.feature +++ b/tests/features/tag.feature @@ -3,51 +3,46 @@ Feature: Tagging # And format.feature for tag-related output Scenario Outline: Tags should allow certain special characters such as /, +, # - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl 2020-09-26: This is an entry about @os/2 and @c++ and @c#" When we run "jrnl --tags -on 2020-09-26" Then we should get no error And the output should be - """ - @os/2 : 1 - @c++ : 1 - @c# : 1 - """ + @os/2 : 1 + @c++ : 1 + @c# : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Emails addresses should not be parsed as tags - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl 2020-09-26: The email address test@example.com does not seem to work for me" When we run "jrnl 2020-09-26: The email address test@example.org also does not work for me" When we run "jrnl 2020-09-26: I tried test@example.org and test@example.edu too" - Then we flush the output When we run "jrnl --tags -on 2020-09-26" Then we should get no error And the output should be "[No tags found in journal.]" Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | Scenario Outline: Entry can start and end with tags - Given we use the config ".yaml" + Given we use the config "" When we run "jrnl 2020-09-26: @foo came over, we went to a @bar" When we run "jrnl --tags -on 2020-09-26" Then the output should be - """ - @foo : 1 - @bar : 1 - """ + @foo : 1 + @bar : 1 Examples: configs - | config | - | basic_onefile | - | basic_folder | - | basic_dayone | + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 4c1d42d4..ea561ba0 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -419,14 +419,15 @@ def output_should_not_contain(output, cli_run): assert output not in cli_run["stdout"] -@then(parse("the output should be\n{output}")) -@then(parse('the output should be "{output}"')) -@then('the output should be ""') -def output_should_be(output, cli_run): +@then(parse("the output should be\n{str_value}")) +@then(parse('the output should be "{str_value}"')) +@then('the output should be ""') +@then("the output should be empty") +def output_should_be(str_value, cli_run): actual_out = cli_run["stdout"].strip() - output = output.strip() - assert output and output == actual_out, failed_msg( - "Output does not match.", output, actual_out + expected = str_value.strip() + assert expected == actual_out, failed_msg( + "Output does not match.", expected, actual_out ) From e0980cf39624bec5e379df6296146e5655fabd1e Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 24 Apr 2021 15:26:13 -0700 Subject: [PATCH 50/74] Update tests to use more scenario outlines Co-authored-by: Micah Jerome Ellison --- tests/features/import.feature | 100 +++++++++++------------ tests/features/multiple_journals.feature | 66 +++++++++------ 2 files changed, 91 insertions(+), 75 deletions(-) diff --git a/tests/features/import.feature b/tests/features/import.feature index 63b042fc..ef2e62d0 100644 --- a/tests/features/import.feature +++ b/tests/features/import.feature @@ -1,7 +1,7 @@ Feature: Importing data Scenario Outline: --import allows new entry from stdin - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl --import" and pipe "[2020-07-05 15:00] Observe and import." Then we flush the output @@ -9,50 +9,44 @@ Feature: Importing data Then the output should contain "Observe and import" Examples: Configs - | config | - | basic_onefile | - | basic_encrypted | - # | basic_folder | @todo - # | basic_dayone | @todo + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo Scenario Outline: --import allows new large entry from stdin - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl --import" and pipe - """ - [2020-07-05 15:00] Observe and import. - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis - est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue - et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu consequat. - Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec - tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at - dolor dui end of entry. - """ - Then we flush the output + [2020-07-05 15:00] Observe and import. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis + est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue + et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu consequat. + Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec + tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at + dolor dui end of entry. When we run "jrnl -on 2020-07-05" Then the output should contain "2020-07-05 15:00 Observe and import." And the output should contain "Lorem ipsum" And the output should contain "end of entry." Examples: Configs - | config | - | basic_onefile | - | basic_encrypted | - # | basic_folder | @todo - # | basic_dayone | @todo + | config | + | basic_onefile.yaml | + | basic_encrypted.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo Scenario Outline: --import allows multiple new entries from stdin - Given we use the config ".yaml" + Given we use the config "" And we use the password "test" if prompted When we run "jrnl --import" and pipe - """ - [2020-07-05 15:00] Observe and import. - Lorem ipsum dolor sit amet, consectetur adipiscing elit. + [2020-07-05 15:00] Observe and import. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. - [2020-07-05 15:01] Twice as nice. - Sed dignissim sed nisl eu consequat. - """ - Then we flush the output + [2020-07-05 15:01] Twice as nice. + Sed dignissim sed nisl eu consequat. When we run "jrnl -on 2020-07-05" Then the output should contain "2020-07-05 15:00 Observe and import." And the output should contain "Lorem ipsum" @@ -60,34 +54,36 @@ Feature: Importing data And the output should contain "Sed dignissim" Examples: Configs - | config | - | basic_onefile | - | basic_encrypted | - # | basic_folder | @todo - # | basic_dayone | @todo + | config | + | basic_onefile.yaml | + | basic_encrypted.yaml | + # | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo Scenario: --import allows import new entries from file Given we use the config "simple.yaml" - Then the journal should contain "My first entry." - And the journal should contain "Life is good." - But the journal should not contain "I have an @idea" - And the journal should not contain "I met with" + When we run "jrnl -99" + Then the output should contain "My first entry." + And the output should contain "Life is good." + But the output should not contain "I have an @idea" + And the output should not contain "I met with" When we run "jrnl --import --file features/journals/tags.journal" - Then the journal should contain "My first entry." - And the journal should contain "Life is good." - And the journal should contain "PROFIT!" + And we run "jrnl -99" + Then the output should contain "My first entry." + And the output should contain "Life is good." + And the output should contain "PROFIT!" Scenario: --import prioritizes --file over pipe data if both are given Given we use the config "simple.yaml" - Then the journal should contain "My first entry." - And the journal should contain "Life is good." - But the journal should not contain "I have an @idea" - And the journal should not contain "I met with" + When we run "jrnl -99" + Then the output should contain "My first entry." + And the output should contain "Life is good." + But the output should not contain "I have an @idea" + And the output should not contain "I met with" When we run "jrnl --import --file features/journals/tags.journal" and pipe - """ - [2020-07-05 15:00] I should not exist! - """ - Then the journal should contain "My first entry." - And the journal should contain "PROFIT!" - But the journal should not contain "I should not exist!" + [2020-07-05 15:00] I should not exist! + And we run "jrnl -99" + Then the output should contain "My first entry." + And the output should contain "PROFIT!" + But the output should not contain "I should not exist!" diff --git a/tests/features/multiple_journals.feature b/tests/features/multiple_journals.feature index 222be100..4be3ab1c 100644 --- a/tests/features/multiple_journals.feature +++ b/tests/features/multiple_journals.feature @@ -2,20 +2,32 @@ Feature: Multiple journals Scenario: Loading a config with two journals Given we use the config "multiple.yaml" - Then journal "default" should have 2 entries - And journal "work" should have 0 entries + When we run "jrnl -99 --short" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Write to default config by default Given we use the config "multiple.yaml" When we run "jrnl this goes to default" - Then journal "default" should have 3 entries - And journal "work" should have 0 entries + When we run "jrnl -99 --short" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Write to specified journal Given we use the config "multiple.yaml" When we run "jrnl work a long day in the office" - Then journal "default" should have 2 entries - And journal "work" should have 1 entry + When we run "jrnl -99 --short" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Tell user which journal was used Given we use the config "multiple.yaml" @@ -25,41 +37,49 @@ Feature: Multiple journals Scenario: Write to specified journal with a timestamp Given we use the config "multiple.yaml" When we run "jrnl work 23 july 2012: a long day in the office" - Then journal "default" should have 2 entries - And journal "work" should have 1 entry - And journal "work" should contain "2012-07-23" + When we run "jrnl -99 --short" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Write to specified journal without a timestamp but with colon Given we use the config "multiple.yaml" When we run "jrnl work : a long day in the office" - Then journal "default" should have 2 entries - And journal "work" should have 1 entry - And journal "work" should contain "a long day in the office" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Write to specified journal without a timestamp but with colon Given we use the config "multiple.yaml" When we run "jrnl work: a long day in the office" - Then journal "default" should have 2 entries - And journal "work" should have 1 entry - And journal "work" should contain "a long day in the office" + When we run "jrnl -99 --short" + Then the output should be + @todo something + When we run "jrnl work -99 --short" + Then the output should be + @todo something Scenario: Create new journals as required Given we use the config "multiple.yaml" Then journal "ideas" should not exist When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money" - Then journal "ideas" should have 1 entry + When we run "jrnl ideas -99 --short" + Then the output should be + @todo something Scenario: Don't crash if no default journal is specified Given we use the config "bug343.yaml" When we run "jrnl a long day in the office" - Then we should see the message "No default journal configured" + Then the output should contain "No default journal configured" Scenario: Don't crash if no file exists for a configured encrypted journal Given we use the config "multiple.yaml" When we run "jrnl new_encrypted Adding first entry" and enter - """ - these three eyes - these three eyes - n - """ - Then we should see the message "Encrypted journal 'new_encrypted' created" + these three eyes + these three eyes + n + Then the output should contain "Encrypted journal 'new_encrypted' created" From e19fab0615fafa26a0262145ed0febaffe3db1c0 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 24 Apr 2021 15:44:19 -0700 Subject: [PATCH 51/74] Add new config file (for use in pytest-bdd) Co-authored-by: Micah Jerome Ellison --- .../configs/editor_markdown_extension.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/data/configs/editor_markdown_extension.yaml diff --git a/tests/data/configs/editor_markdown_extension.yaml b/tests/data/configs/editor_markdown_extension.yaml new file mode 100644 index 00000000..bf3b8d8e --- /dev/null +++ b/tests/data/configs/editor_markdown_extension.yaml @@ -0,0 +1,18 @@ +default_hour: 9 +default_minute: 0 +editor: "" +encrypt: false +highlight: true +editor: "vim" +journals: + default: features/journals/editor_markdown_extension.journal +linewrap: 80 +tagsymbols: "@" +template: features/templates/extension.md +timeformat: "%Y-%m-%d %H:%M" +indent_character: "|" +colors: + date: none + title: none + body: none + tags: none From cda07bf8d925653845f930708cc122a0e26b07c8 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 24 Apr 2021 15:44:29 -0700 Subject: [PATCH 52/74] Make steps use new config file Co-authored-by: Micah Jerome Ellison --- tests/features/import.feature | 4 +-- tests/features/upgrade.feature | 62 ++++++++++++---------------------- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/tests/features/import.feature b/tests/features/import.feature index ef2e62d0..9de8e216 100644 --- a/tests/features/import.feature +++ b/tests/features/import.feature @@ -32,7 +32,7 @@ Feature: Importing data And the output should contain "end of entry." Examples: Configs - | config | + | config_file | | basic_onefile.yaml | | basic_encrypted.yaml | # | basic_folder.yaml | @todo @@ -54,7 +54,7 @@ Feature: Importing data And the output should contain "Sed dignissim" Examples: Configs - | config | + | config_file | | basic_onefile.yaml | | basic_encrypted.yaml | # | basic_folder.yaml | @todo diff --git a/tests/features/upgrade.feature b/tests/features/upgrade.feature index fda47363..115eb8ff 100644 --- a/tests/features/upgrade.feature +++ b/tests/features/upgrade.feature @@ -3,24 +3,20 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x Scenario: Upgrade and parse journals with square brackets Given we use the config "upgrade_from_195.json" When we run "jrnl -9" and enter "Y" - Then the journal should have 2 entries + When we run "jrnl -99 --short" + Then the output should be + @todo something And the output should contain - """ - 2010-06-10 15:00 A life without chocolate is like a bad analogy. - """ + 2010-06-10 15:00 A life without chocolate is like a bad analogy. And the output should contain - """ - 2013-06-10 15:40 He said "[this] is the best time to be alive". - """ + 2013-06-10 15:40 He said "[this] is the best time to be alive". Scenario: Upgrading a journal encrypted with jrnl 1.x Given we use the config "encrypted_old.json" When we run "jrnl -n 1" and enter - """ - Y - bad doggie no biscuit - bad doggie no biscuit - """ + Y + bad doggie no biscuit + bad doggie no biscuit Then we should be prompted for a password And the output should contain "2013-06-10 15:40 Life is good" @@ -28,44 +24,30 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x Given we use the config "no_colors.yaml" When we run "jrnl -n 1" Then the config should have "colors" set to - """ - { - 'date':'none', - 'title':'none', - 'body':'none', - 'tags':'none' - } - """ + date: none + title: none + body: none + tags: none Scenario: Upgrade and parse journals with little endian date format Given we use the config "upgrade_from_195_little_endian_dates.json" When we run "jrnl -9" and enter "Y" - Then the journal should have 2 entries - And the output should contain - """ - 10.06.2010 15:00 A life without chocolate is like a bad analogy. - """ - And the output should contain - """ - 10.06.2013 15:40 He said "[this] is the best time to be alive". - """ + Then the output should be + 10.06.2010 15:00 A life without chocolate is like a bad analogy. + 10.06.2013 15:40 He said "[this] is the best time to be alive". Scenario: Upgrade with missing journal Given we use the config "upgrade_from_195_with_missing_journal.json" - When we run "jrnl -ls" and enter - """" - Y - """ - Then the output should contain "Error: features/journals/missing.journal does not exist." + When we run "jrnl --list" and enter + Y + Then the error output should contain "Error: features/journals/missing.journal does not exist." And we should get no error Scenario: Upgrade with missing encrypted journal Given we use the config "upgrade_from_195_with_missing_encrypted_journal.json" - When we run "jrnl -ls" and enter - """ - Y - bad doggie no biscuit - """ - Then the output should contain "Error: features/journals/missing.journal does not exist." + When we run "jrnl --list" and enter + Y + bad doggie no biscuit + Then the error output should contain "Error: features/journals/missing.journal does not exist." And the error output should contain "We're all done" And we should get no error From 4aabb73847a4bb7a6e56ef7b324c22b15eac3e80 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 1 May 2021 15:57:16 -0700 Subject: [PATCH 53/74] Implement datetime handling in pytest-bdd - This was awful and convoluted Co-authored-by: Micah Jerome Ellison --- Makefile | 13 +++- jrnl/DayOneJournal.py | 4 +- jrnl/Entry.py | 4 +- jrnl/Journal.py | 10 +-- jrnl/time.py | 22 +++--- tests/features/datetime.feature | 59 +++++++-------- tests/step_defs/conftest.py | 108 ++++++++++++++++++---------- tests/{ => unit}/test_color.py | 0 tests/{ => unit}/test_display.py | 0 tests/{ => unit}/test_exception.py | 0 tests/{ => unit}/test_export.py | 0 tests/{ => unit}/test_install.py | 0 tests/{ => unit}/test_os_compat.py | 0 tests/{ => unit}/test_override.py | 0 tests/{ => unit}/test_parse_args.py | 0 tests/{ => unit}/test_time.py | 0 16 files changed, 133 insertions(+), 87 deletions(-) rename tests/{ => unit}/test_color.py (100%) rename tests/{ => unit}/test_display.py (100%) rename tests/{ => unit}/test_exception.py (100%) rename tests/{ => unit}/test_export.py (100%) rename tests/{ => unit}/test_install.py (100%) rename tests/{ => unit}/test_os_compat.py (100%) rename tests/{ => unit}/test_override.py (100%) rename tests/{ => unit}/test_parse_args.py (100%) rename tests/{ => unit}/test_time.py (100%) diff --git a/Makefile b/Makefile index 8130dade..454702c6 100644 --- a/Makefile +++ b/Makefile @@ -21,9 +21,16 @@ lint: ## Check style with various tools poetry run pyflakes jrnl tests poetry run black --check --diff . -test: lint ## Run unit tests and behave tests - poetry run pytest - poetry run behave --no-skipped --format progress2 +unit: # unit tests + poetry run pytest tests/unit + +e2e: # end-to-end tests + poetry run pytest tests/step_defs --gherkin-terminal-reporter --tb=native --diff-type=unified + +e2e-debug: # end-to-end tests + poetry run pytest tests/step_defs --gherkin-terminal-reporter --tb=native --diff-type=unified -x -vv + +test: lint unit e2e ## Run unit tests and behave tests build: poetry build diff --git a/jrnl/DayOneJournal.py b/jrnl/DayOneJournal.py index 61a60ca0..00271875 100644 --- a/jrnl/DayOneJournal.py +++ b/jrnl/DayOneJournal.py @@ -1,4 +1,4 @@ -from datetime import datetime +import datetime import fnmatch import os from pathlib import Path @@ -116,7 +116,7 @@ class DayOne(Journal.Journal): """Writes only the entries that have been modified into plist files.""" for entry in self.entries: if entry.modified: - utc_time = datetime.utcfromtimestamp( + utc_time = datetime.datetime.utcfromtimestamp( time.mktime(entry.date.timetuple()) ) diff --git a/jrnl/Entry.py b/jrnl/Entry.py index e227794f..56347770 100644 --- a/jrnl/Entry.py +++ b/jrnl/Entry.py @@ -2,7 +2,7 @@ # License: https://www.gnu.org/licenses/gpl-3.0.html -from datetime import datetime +import datetime import re import ansiwrap @@ -14,7 +14,7 @@ from .color import highlight_tags_with_background_color class Entry: def __init__(self, journal, date=None, text="", starred=False): self.journal = journal # Reference to journal mainly to access its config - self.date = date or datetime.now() + self.date = date or datetime.datetime.now() self.text = text self._title = None self._body = None diff --git a/jrnl/Journal.py b/jrnl/Journal.py index b889c0d3..181d85c4 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -2,7 +2,7 @@ # License: https://www.gnu.org/licenses/gpl-3.0.html -from datetime import datetime +import datetime import logging import os import re @@ -134,7 +134,9 @@ class Journal: for match in date_blob_re.finditer(journal_txt): date_blob = match.groups()[0] try: - new_date = datetime.strptime(date_blob, self.config["timeformat"]) + new_date = datetime.datetime.strptime( + date_blob, self.config["timeformat"] + ) except ValueError: # Passing in a date that had brackets around it new_date = time.parse(date_blob, bracketed=True) @@ -347,7 +349,7 @@ class LegacyJournal(Journal): """Parses a journal that's stored in a string and returns a list of entries""" # Entries start with a line that looks like 'date title' - let's figure out how # long the date will be by constructing one - date_length = len(datetime.today().strftime(self.config["timeformat"])) + date_length = len(datetime.datetime.today().strftime(self.config["timeformat"])) # Initialise our current entry entries = [] @@ -357,7 +359,7 @@ class LegacyJournal(Journal): line = line.rstrip() try: # try to parse line as date => new entry begins - new_date = datetime.strptime( + new_date = datetime.datetime.strptime( line[:date_length], self.config["timeformat"] ) diff --git a/jrnl/time.py b/jrnl/time.py index b9ea8e84..f4e7319d 100644 --- a/jrnl/time.py +++ b/jrnl/time.py @@ -1,11 +1,11 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -from datetime import datetime +import datetime FAKE_YEAR = 9999 -DEFAULT_FUTURE = datetime(FAKE_YEAR, 12, 31, 23, 59, 59) -DEFAULT_PAST = datetime(FAKE_YEAR, 1, 1, 0, 0) +DEFAULT_FUTURE = datetime.datetime(FAKE_YEAR, 12, 31, 23, 59, 59) +DEFAULT_PAST = datetime.datetime(FAKE_YEAR, 1, 1, 0, 0) def __get_pdt_calendar(): @@ -27,7 +27,7 @@ def parse( """Parses a string containing a fuzzy date and returns a datetime.datetime object""" if not date_str: return None - elif isinstance(date_str, datetime): + elif isinstance(date_str, datetime.datetime): return date_str # Don't try to parse anything with 6 or less characters and was parsed from the existing journal. @@ -44,7 +44,9 @@ def parse( date = dateparse(date_str, default=default_date) if date.year == FAKE_YEAR: - date = datetime(datetime.now().year, date.timetuple()[1:6]) + date = datetime.datetime( + datetime.datetime.now().year, date.timetuple()[1:6] + ) else: year_present = True flag = 1 if date.hour == date.minute == 0 else 2 @@ -52,7 +54,7 @@ def parse( except Exception as e: if e.args[0] == "day is out of range for month": y, m, d, H, M, S = default_date.timetuple()[:6] - default_date = datetime(y, m, d - 1, H, M, S) + default_date = datetime.datetime(y, m, d - 1, H, M, S) else: calendar = __get_pdt_calendar() date, flag = calendar.parse(date_str) @@ -60,26 +62,26 @@ def parse( if not flag: # Oops, unparsable. try: # Try and parse this as a single year year = int(date_str) - return datetime(year, 1, 1) + return datetime.datetime(year, 1, 1) except ValueError: return None except TypeError: return None if flag == 1: # Date found, but no time. Use the default time. - date = datetime( + date = datetime.datetime( *date[:3], hour=23 if inclusive else default_hour or 0, minute=59 if inclusive else default_minute or 0, second=59 if inclusive else 0 ) else: - date = datetime(*date[:6]) + date = datetime.datetime(*date[:6]) # Ugly heuristic: if the date is more than 4 weeks in the future, we got the year wrong. # Rather then this, we would like to see parsedatetime patched so we can tell it to prefer # past dates - dt = datetime.now() - date + dt = datetime.datetime.now() - date if dt.days < -28 and not year_present: date = date.replace(date.year - 1) return date diff --git a/tests/features/datetime.feature b/tests/features/datetime.feature index 0a3f5155..0da3027f 100644 --- a/tests/features/datetime.feature +++ b/tests/features/datetime.feature @@ -36,10 +36,10 @@ Feature: Reading and writing to journal with custom date formats When we run "jrnl " Then we should see the message "Entry added" When we run "jrnl -n 1" - Then the output should contain "" + Then the output should contain "" Examples: Day-first Dates - | config_file | command | output | + | config_file | command | expected_output | | little_endian_dates.yaml | 2020-09-19: My first entry. | 19.09.2020 09:00 My first entry. | | little_endian_dates.yaml | 2020-08-09: My second entry. | 09.08.2020 09:00 My second entry. | | little_endian_dates.yaml | 2020-02-29: Test. | 29.02.2020 09:00 Test. | @@ -53,10 +53,10 @@ Feature: Reading and writing to journal with custom date formats Scenario Outline: Searching for dates with custom date Given we use the config "" When we run "jrnl " - Then the output should be "" + Then the output should be "" Examples: Day-first Dates - | config_file | command | output | + | config_file | command | expected_output | | little_endian_dates.yaml | -on '2013-07-10' --short | 10.07.2013 15:40 Life is good. | | little_endian_dates.yaml | -on 'june 9 2013' --short | 09.06.2013 15:39 My first entry. | | little_endian_dates.yaml | -on 'july 10 2013' --short | 10.07.2013 15:40 Life is good. | @@ -83,47 +83,48 @@ Feature: Reading and writing to journal with custom date formats Then the output should not contain "Life is good" And the output should not contain "But I'm better." - - Scenario Outline: Create entry using day of the week as entry date. + Scenario Outline: Create entry using day of the week as entry date one. Given we use the config "simple.yaml" + And now is "2019-03-12 01:30:32 PM" When we run "jrnl " Then we should see the message "Entry added" When we run "jrnl -1" - Then the output should contain "" + Then the output should contain "" Then the output should contain the date "" Examples: Days of the week - | command | output | date | - | Monday: entry on a monday | entry on a monday | monday at 9am | - | Tuesday: entry on a tuesday | entry on a tuesday | tuesday at 9am | - | Wednesday: entry on a wednesday | entry on a wednesday | wednesday at 9am | - | Thursday: entry on a thursday | entry on a thursday | thursday at 9am | - | Friday: entry on a friday | entry on a friday | friday at 9am | - | Saturday: entry on a saturday | entry on a saturday | saturday at 9am | - | Sunday: entry on a sunday | entry on a sunday | sunday at 9am | - | sunday: entry on a sunday | entry on a sunday | sunday at 9am | - | sUndAy: entry on a sunday | entry on a sunday | sunday at 9am | + | command | expected_output | date | + | Monday: entry on a monday | entry on a monday | 2019-03-11 09:00 | + | Tuesday: entry on a tuesday | entry on a tuesday | 2019-03-05 09:00 | + | Wednesday: entry on a wednesday | entry on a wednesday | 2019-03-06 09:00 | + | Thursday: entry on a thursday | entry on a thursday | 2019-03-07 09:00 | + | Friday: entry on a friday | entry on a friday | 2019-03-08 09:00 | + | Saturday: entry on a saturday | entry on a saturday | 2019-03-09 09:00 | + | Sunday: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | + | sunday: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | + | sUndAy: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | - Scenario Outline: Create entry using day of the week as entry date. + Scenario Outline: Create entry using day of the week as entry date two. Given we use the config "simple.yaml" + And now is "2019-03-12 01:30:32 PM" When we run "jrnl " Then we should see the message "Entry added" When we run "jrnl -1" - Then the output should contain "" + Then the output should contain "" Then the output should contain the date "" Examples: Days of the week - | command | output | date | - | Mon: entry on a monday | entry on a monday | monday at 9am | - | Tue: entry on a tuesday | entry on a tuesday | tuesday at 9am | - | Wed: entry on a wednesday | entry on a wednesday | wednesday at 9am | - | Thu: entry on a thursday | entry on a thursday | thursday at 9am | - | Fri: entry on a friday | entry on a friday | friday at 9am | - | Sat: entry on a saturday | entry on a saturday | saturday at 9am | - | Sun: entry on a sunday | entry on a sunday | sunday at 9am | - | sun: entry on a sunday | entry on a sunday | sunday at 9am | - | sUn: entry on a sunday | entry on a sunday | sunday at 9am | + | command | expected_output | date | + | Mon: entry on a monday | entry on a monday | 2019-03-11 09:00 | + | Tue: entry on a tuesday | entry on a tuesday | 2019-03-05 09:00 | + | Wed: entry on a wednesday | entry on a wednesday | 2019-03-06 09:00 | + | Thu: entry on a thursday | entry on a thursday | 2019-03-07 09:00 | + | Fri: entry on a friday | entry on a friday | 2019-03-08 09:00 | + | Sat: entry on a saturday | entry on a saturday | 2019-03-09 09:00 | + | Sun: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | + | sun: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | + | sUn: entry on a sunday | entry on a sunday | 2019-03-10 09:00 | Scenario: Journals with unreadable dates should still be loaded diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index ea561ba0..e49b8217 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -4,6 +4,7 @@ import ast import json import os +from datetime import datetime from collections import defaultdict from keyring import backend from keyring import set_keyring @@ -15,6 +16,7 @@ import re import shutil import tempfile from unittest.mock import patch +from unittest.mock import MagicMock from xml.etree import ElementTree from pytest_bdd import given @@ -31,6 +33,7 @@ from jrnl.cli import cli from jrnl.config import load_config from jrnl.os_compat import split_args from jrnl.os_compat import on_windows +from jrnl.time import __get_pdt_calendar class TestKeyring(backend.KeyringBackend): @@ -99,10 +102,6 @@ def pytest_bdd_apply_tag(tag, function): # ----- UTILS ----- # -def failed_msg(msg, expected, actual): - return f"{msg}\nExpected:\n{expected}\n---end---\nActual:\n{actual}\n---end---\n" - - def read_value_from_string(string): if string[0] == "{": # Handle value being a dictionary @@ -142,6 +141,11 @@ def password(): return "" +@fixture +def now_date(): + return {"datetime": datetime, "calendar_parse": __get_pdt_calendar()} + + @fixture def cache_dir(): return {"exists": False, "path": ""} @@ -251,6 +255,29 @@ def we_enter_editor(editor_method, editor_input, editor_state): editor_state["intent"] = {"method": file_method, "input": editor_input} +@given(parse('now is ""'), target_fixture="now_date") +@given(parse('now is "{date_str}"'), target_fixture="now_date") +def now_is_str(date_str): + class DatetimeMagicMock(MagicMock): + # needed because jrnl does some reflection on datetime + def __instancecheck__(self, subclass): + return isinstance(subclass, datetime) + + my_date = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") + + # jrnl uses two different classes to parse dates, so both must be mocked + datetime_mock = DatetimeMagicMock(wraps=datetime) + datetime_mock.now.return_value = my_date + + pdt = __get_pdt_calendar() + calendar_mock = MagicMock(wraps=pdt) + calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( + date_str_input, my_date + ) + + return {"datetime": datetime_mock, "calendar_parse": calendar_mock} + + @then(parse("the editor should have been called")) @then(parse("the editor should have been called with {num_args} arguments")) def count_editor_args(num_args, cli_run, editor_state): @@ -328,9 +355,9 @@ def we_run( cli_run, capsys, password, - keyring, cache_dir, editor, + now_date, ): if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -354,6 +381,8 @@ def we_run( patch("sys.stdin.read", side_effect=user_input) as mock_stdin, \ patch("builtins.input", side_effect=user_input) as mock_input, \ patch("getpass.getpass", side_effect=password) as mock_getpass, \ + patch("datetime.datetime", new=now_date["datetime"]), \ + patch("jrnl.time.__get_pdt_calendar", return_value=now_date["calendar_parse"]), \ patch("jrnl.install.get_config_path", return_value=config_path), \ patch("jrnl.config.get_config_path", return_value=config_path), \ patch("subprocess.call", side_effect=editor) as mock_editor \ @@ -392,48 +421,53 @@ def output_should_match(regex, cli_run): assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" -@then(parse("the output should contain\n{output}")) -@then(parse('the output should contain "{output}"')) -@then('the output should contain ""') -@then(parse("the {which_output_stream} output should contain\n{output}")) -@then(parse('the {which_output_stream} output should contain "{output}"')) -def output_should_contain(output, which_output_stream, cli_run): - assert output +@then(parse("the output should contain\n{expected_output}")) +@then(parse('the output should contain "{expected_output}"')) +@then('the output should contain ""') +@then(parse("the {which_output_stream} output should contain\n{expected_output}")) +@then(parse('the {which_output_stream} output should contain "{expected_output}"')) +def output_should_contain(expected_output, which_output_stream, cli_run): + assert expected_output if which_output_stream is None: - assert (output in cli_run["stdout"]) or (output in cli_run["stderr"]) + assert (expected_output in cli_run["stdout"]) or ( + expected_output in cli_run["stderr"] + ) elif which_output_stream == "standard": - assert output in cli_run["stdout"] + assert expected_output in cli_run["stdout"] elif which_output_stream == "error": - assert output in cli_run["stderr"] + assert expected_output in cli_run["stderr"] else: - assert output in cli_run[which_output_stream] + assert expected_output in cli_run[which_output_stream] -@then(parse("the output should not contain\n{output}")) -@then(parse('the output should not contain "{output}"')) -@then('the output should not contain ""') -def output_should_not_contain(output, cli_run): - assert output not in cli_run["stdout"] +@then(parse("the output should not contain\n{expected_output}")) +@then(parse('the output should not contain "{expected_output}"')) +@then('the output should not contain ""') +def output_should_not_contain(expected_output, cli_run): + assert expected_output not in cli_run["stdout"] + + +@then(parse("the output should be\n{expected_output}")) +@then(parse('the output should be "{expected_output}"')) +@then('the output should be ""') +def output_should_be(expected_output, cli_run): + actual = cli_run["stdout"].strip() + expected = expected_output.strip() + assert expected == actual -@then(parse("the output should be\n{str_value}")) -@then(parse('the output should be "{str_value}"')) -@then('the output should be ""') @then("the output should be empty") -def output_should_be(str_value, cli_run): - actual_out = cli_run["stdout"].strip() - expected = str_value.strip() - assert expected == actual_out, failed_msg( - "Output does not match.", expected, actual_out - ) +def output_should_be_empty(cli_run): + actual = cli_run["stdout"].strip() + assert actual == "" @then('the output should contain the date ""') -def output_should_contain_date(output, cli_run): - assert output and output in cli_run["stdout"] +def output_should_contain_date(date, cli_run): + assert date and date in cli_run["stdout"] @then("the output should contain pyproject.toml version") @@ -574,12 +608,12 @@ def assert_output_is_valid_language(cli_run, language_name): @given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") def parse_output_as_language(cli_run, language_name): language_name = language_name.upper() - output = cli_run["stdout"] + actual_output = cli_run["stdout"] if language_name == "XML": - parsed_output = ElementTree.fromstring(output) + parsed_output = ElementTree.fromstring(actual_output) elif language_name == "JSON": - parsed_output = json.loads(output) + parsed_output = json.loads(actual_output) else: assert False, f"Language name {language_name} not recognized" @@ -669,6 +703,6 @@ def assert_output_field_content( @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) + actual_output = cli_run["stdout"] + xml_tree = ElementTree.fromstring(actual_output) assert len(xml_tree.findall(".//" + item)) == number diff --git a/tests/test_color.py b/tests/unit/test_color.py similarity index 100% rename from tests/test_color.py rename to tests/unit/test_color.py diff --git a/tests/test_display.py b/tests/unit/test_display.py similarity index 100% rename from tests/test_display.py rename to tests/unit/test_display.py diff --git a/tests/test_exception.py b/tests/unit/test_exception.py similarity index 100% rename from tests/test_exception.py rename to tests/unit/test_exception.py diff --git a/tests/test_export.py b/tests/unit/test_export.py similarity index 100% rename from tests/test_export.py rename to tests/unit/test_export.py diff --git a/tests/test_install.py b/tests/unit/test_install.py similarity index 100% rename from tests/test_install.py rename to tests/unit/test_install.py diff --git a/tests/test_os_compat.py b/tests/unit/test_os_compat.py similarity index 100% rename from tests/test_os_compat.py rename to tests/unit/test_os_compat.py diff --git a/tests/test_override.py b/tests/unit/test_override.py similarity index 100% rename from tests/test_override.py rename to tests/unit/test_override.py diff --git a/tests/test_parse_args.py b/tests/unit/test_parse_args.py similarity index 100% rename from tests/test_parse_args.py rename to tests/unit/test_parse_args.py diff --git a/tests/test_time.py b/tests/unit/test_time.py similarity index 100% rename from tests/test_time.py rename to tests/unit/test_time.py From ef25c50e16087ec4ea0fff2e16b837385743fcd6 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 15 May 2021 14:50:49 -0700 Subject: [PATCH 54/74] Implement step for directory journals Co-authored-by: Jonathan Wren --- tests/step_defs/conftest.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index e49b8217..3d3b6246 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -31,6 +31,7 @@ import toml from jrnl import __version__ from jrnl.cli import cli from jrnl.config import load_config +from jrnl.config import scope_config from jrnl.os_compat import split_args from jrnl.os_compat import on_windows from jrnl.time import __get_pdt_calendar @@ -112,6 +113,13 @@ def read_value_from_string(string): value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](value) return value +def assert_directory_contains_files(file_list, directory_path): + assert os.path.isdir(directory_path), "Directory path is not a directory" + + for file in file_list.split("\n"): + fullpath = directory_path + '/' + file + assert os.path.isfile(fullpath) + # ----- FIXTURES ----- # @fixture @@ -358,6 +366,7 @@ def we_run( cache_dir, editor, now_date, + keyring ): if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -527,15 +536,17 @@ def password_was_not_called(cli_run): @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") + assert_directory_contains_files(file_list, cache_dir["path"]) - # sort to deal with inconsistent default file ordering on different OS's - actual_files.sort() - expected_files.sort() +@then(parse("the journal directory should contain\n{file_list}")) +def journal_directory_should_contain(config_data, file_list, journal_name): + if not journal_name: + journal_name = "default" - assert actual_files == expected_files, [actual_files, expected_files] + scoped_config = scope_config(config_data, journal_name) + journal_path = scoped_config["journal"] + assert_directory_contains_files(file_list, journal_path) @given("we create a cache directory", target_fixture="cache_dir") def create_cache_dir(temp_dir): @@ -706,3 +717,4 @@ def count_elements(number, item, cli_run): actual_output = cli_run["stdout"] xml_tree = ElementTree.fromstring(actual_output) assert len(xml_tree.findall(".//" + item)) == number + From 7647755e964ac06e93ae5d48e78876be7df59ecd Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 15 May 2021 15:31:23 -0700 Subject: [PATCH 55/74] Implement journal existence check Co-authored-by: Jonathan Wren --- tests/step_defs/conftest.py | 45 ++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 3d3b6246..b64d9965 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -113,12 +113,17 @@ def read_value_from_string(string): value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](value) return value -def assert_directory_contains_files(file_list, directory_path): - assert os.path.isdir(directory_path), "Directory path is not a directory" + +def does_directory_contain_files(file_list, directory_path): + if not os.path.isdir(directory_path): + return False for file in file_list.split("\n"): - fullpath = directory_path + '/' + file - assert os.path.isfile(fullpath) + fullpath = directory_path + "/" + file + if not os.path.isfile(fullpath): + return False + + return True # ----- FIXTURES ----- # @@ -366,7 +371,7 @@ def we_run( cache_dir, editor, now_date, - keyring + keyring, ): if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -536,17 +541,32 @@ def password_was_not_called(cli_run): @then(parse("the cache directory should contain the files\n{file_list}")) def assert_dir_contains_files(file_list, cache_dir): - assert_directory_contains_files(file_list, cache_dir["path"]) + assert does_directory_contain_files(file_list, cache_dir["path"]) + @then(parse("the journal directory should contain\n{file_list}")) -def journal_directory_should_contain(config_data, file_list, journal_name): - if not journal_name: - journal_name = "default" +def journal_directory_should_contain(config_data, file_list): + scoped_config = scope_config(config_data, "default") - scoped_config = scope_config(config_data, journal_name) - journal_path = scoped_config["journal"] + assert does_directory_contain_files(file_list, scoped_config["journal"]) + + +@then(parse("the journal {should_or_should_not} exist")) +def journal_should_not_exist(config_data, should_or_should_not): + scoped_config = scope_config(config_data, "default") + expected_path = scoped_config["journal"] + + contains_files = does_directory_contain_files(expected_path, ".") + + if should_or_should_not == "should": + assert contains_files + elif should_or_should_not == "should not": + assert not contains_files + else: + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) - assert_directory_contains_files(file_list, journal_path) @given("we create a cache directory", target_fixture="cache_dir") def create_cache_dir(temp_dir): @@ -717,4 +737,3 @@ def count_elements(number, item, cli_run): actual_output = cli_run["stdout"] xml_tree = ElementTree.fromstring(actual_output) assert len(xml_tree.findall(".//" + item)) == number - From 5d4d68fe327159340a81b2c2fffc95c449a7e8db Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 15 May 2021 16:41:43 -0700 Subject: [PATCH 56/74] Implement directory changing and relative directory test Co-authored-by: Jonathan Wren --- tests/features/file_storage.feature | 4 ++-- tests/step_defs/conftest.py | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/features/file_storage.feature b/tests/features/file_storage.feature index 24407fa1..dc6fd535 100644 --- a/tests/features/file_storage.feature +++ b/tests/features/file_storage.feature @@ -32,11 +32,11 @@ Feature: Journals iteracting with the file system in a way that users can see Then the output should contain "This is a new entry in my journal" Scenario: Creating journal with relative path should update to absolute path - Given we use the config "missingconfig" When we run "jrnl hello world" and enter test.txt n - And we change directory to "features" + Then the output should contain "Journal 'default' created" + When we change directory to "subfolder" And we run "jrnl -n 1" Then the output should contain "hello world" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index b64d9965..2c58c382 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -141,6 +141,10 @@ def temp_dir(): def working_dir(request): return os.path.join(request.config.rootpath, "tests") +@fixture +def config_path(temp_dir): + os.chdir(temp_dir.name) + return temp_dir.name + "/jrnl.yaml" @fixture def toml_version(working_dir): @@ -197,7 +201,7 @@ def keyring_type(): @fixture def config_data(config_path): return load_config(config_path) - + @fixture def journal_name(): @@ -551,6 +555,14 @@ def journal_directory_should_contain(config_data, file_list): assert does_directory_contain_files(file_list, scoped_config["journal"]) +@when(parse('we change directory to "{directory_name}"')) +def when_we_change_directory(directory_name): + if not os.path.isdir(directory_name): + os.mkdir(directory_name) + + os.chdir(directory_name) + + @then(parse("the journal {should_or_should_not} exist")) def journal_should_not_exist(config_data, should_or_should_not): scoped_config = scope_config(config_data, "default") From 512fb63e1f9a84ba6322c0e2888ac95e28f2563b Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 15 May 2021 16:51:40 -0700 Subject: [PATCH 57/74] Implement test to check editor temporary filename Co-authored-by: Jonathan Wren --- tests/features/file_storage.feature | 4 ++-- tests/step_defs/conftest.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/features/file_storage.feature b/tests/features/file_storage.feature index dc6fd535..f81f2710 100644 --- a/tests/features/file_storage.feature +++ b/tests/features/file_storage.feature @@ -44,9 +44,9 @@ Feature: Journals iteracting with the file system in a way that users can see Given we use the config "editor.yaml" When we run "jrnl --edit" Then the editor should have been called - Then the temporary filename suffix should be ".jrnl" + Then the editor filename should end with ".jrnl" Scenario: the temporary filename suffix should be "-{template_filename}" Given we use the config "editor_markdown_extension.yaml" When we run "jrnl --edit" - Then the temporary filename suffix should be "-extension.md" + Then the editor filename should end with "-extension.md" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 2c58c382..57a0de03 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -141,11 +141,13 @@ def temp_dir(): def working_dir(request): return os.path.join(request.config.rootpath, "tests") + @fixture def config_path(temp_dir): os.chdir(temp_dir.name) return temp_dir.name + "/jrnl.yaml" + @fixture def toml_version(working_dir): pyproject = os.path.join(working_dir, "..", "pyproject.toml") @@ -201,7 +203,7 @@ def keyring_type(): @fixture def config_data(config_path): return load_config(config_path) - + @fixture def journal_name(): @@ -304,6 +306,13 @@ def count_editor_args(num_args, cli_run, editor_state): assert len(editor_state["command"]) == int(num_args) +@then(parse('the editor filename should end with "{suffix}"')) +def editor_filename_suffix(suffix, editor_state): + editor_filename = editor_state["tmpfile"]["name"] + + assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix) + + @then(parse('the editor file content should {comparison} "{str_value}"')) @then(parse("the editor file content should {comparison} empty")) @then(parse("the editor file content should {comparison}\n{str_value}")) From 44b1762b7d947ab93ec123e48e50b4392ec04ece Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 22 May 2021 12:32:59 -0700 Subject: [PATCH 58/74] Implement stream redirection in pytest-bdd - Take out old steps from format and input tests Co-authored-by: Micah Jerome Ellison --- tests/features/format.feature | 2 -- tests/features/import.feature | 3 +-- tests/step_defs/conftest.py | 17 +++++++++++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/features/format.feature b/tests/features/format.feature index 648b4dd0..b9e2e384 100644 --- a/tests/features/format.feature +++ b/tests/features/format.feature @@ -163,7 +163,6 @@ 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 @@ -224,7 +223,6 @@ Feature: Custom formats [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 diff --git a/tests/features/import.feature b/tests/features/import.feature index 9de8e216..d75d6017 100644 --- a/tests/features/import.feature +++ b/tests/features/import.feature @@ -4,8 +4,7 @@ Feature: Importing data Given we use the config "" And we use the password "test" if prompted When we run "jrnl --import" and pipe "[2020-07-05 15:00] Observe and import." - Then we flush the output - When we run "jrnl -c import" + When we run "jrnl -9 --short" Then the output should contain "Observe and import" Examples: Configs diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 57a0de03..9e482737 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -160,6 +160,10 @@ def password(): return "" +@fixture +def input_method(): + return "" + @fixture def now_date(): return {"datetime": datetime, "calendar_parse": __get_pdt_calendar()} @@ -368,10 +372,10 @@ def use_password_forever(pw): return pw -@when(parse('we run "jrnl {command}" and enter\n{user_input}')) -@when(parsers.re('we run "jrnl (?P[^"]+)" and enter "(?P[^"]+)"')) +@when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) +@when(parsers.re('we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"')) +@when(parse('we run "jrnl" and {input_method} "{user_input}"')) @when(parse('we run "jrnl {command}"')) -@when(parse('we run "jrnl" and enter "{user_input}"')) @when('we run "jrnl "') @when('we run "jrnl"') def we_run( @@ -385,7 +389,11 @@ def we_run( editor, now_date, keyring, + input_method, ): + assert input_method in ['', 'enter', 'pipe'] + is_tty = input_method != 'pipe' + if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -393,7 +401,7 @@ def we_run( status = 0 if user_input: - user_input = user_input.splitlines() + user_input = user_input.splitlines() if is_tty else [user_input] if password: password = password.splitlines() @@ -406,6 +414,7 @@ def we_run( with \ patch("sys.argv", ['jrnl'] + args), \ patch("sys.stdin.read", side_effect=user_input) as mock_stdin, \ + patch("sys.stdin.isatty", return_value=is_tty), \ patch("builtins.input", side_effect=user_input) as mock_input, \ patch("getpass.getpass", side_effect=password) as mock_getpass, \ patch("datetime.datetime", new=now_date["datetime"]), \ From b7b7bad2fbc49bd74674140484683dfb1350e42b Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 22 May 2021 14:15:43 -0700 Subject: [PATCH 59/74] Clarify and cleanup tests - Run formatter - Take out old tags - Use new steps on tests Co-authored-by: Micah Jerome Ellison --- tests/data/configs/multiple.yaml | 2 +- tests/features/encrypt.feature | 2 +- tests/features/multiple_journals.feature | 43 +++++++++++++----------- tests/features/search.feature | 2 +- tests/step_defs/conftest.py | 20 +++++++++-- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/tests/data/configs/multiple.yaml b/tests/data/configs/multiple.yaml index 65f2c256..1501b383 100644 --- a/tests/data/configs/multiple.yaml +++ b/tests/data/configs/multiple.yaml @@ -6,7 +6,7 @@ highlight: true template: false journals: default: features/journals/simple.journal - ideas: features/journals/nothing.journal + ideas: features/journals/does-not-exist.journal simple: features/journals/simple.journal work: features/journals/work.journal new_encrypted: diff --git a/tests/features/encrypt.feature b/tests/features/encrypt.feature index b9b9ff5a..daa9f109 100644 --- a/tests/features/encrypt.feature +++ b/tests/features/encrypt.feature @@ -3,8 +3,8 @@ Feature: Encrypting and decrypting journals Scenario: Decrypting a journal Given we use the config "encrypted.yaml" When we run "jrnl --decrypt" and enter "bad doggie no biscuit" + Then we should see the message "Journal decrypted" Then the config for journal "default" should have "encrypt" set to "bool:False" - And we should see the message "Journal decrypted" When we run "jrnl -99 --short" Then the output should be 2013-06-09 15:39 My first entry. diff --git a/tests/features/multiple_journals.feature b/tests/features/multiple_journals.feature index 4be3ab1c..cd531ee2 100644 --- a/tests/features/multiple_journals.feature +++ b/tests/features/multiple_journals.feature @@ -4,30 +4,32 @@ Feature: Multiple journals Given we use the config "multiple.yaml" When we run "jrnl -99 --short" Then the output should be - @todo something + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. When we run "jrnl work -99 --short" - Then the output should be - @todo something + Then the output should be empty Scenario: Write to default config by default Given we use the config "multiple.yaml" When we run "jrnl this goes to default" When we run "jrnl -99 --short" - Then the output should be - @todo something + Then the output should contain + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. + Then the output should contain + this goes to default When we run "jrnl work -99 --short" - Then the output should be - @todo something + Then the output should be empty Scenario: Write to specified journal Given we use the config "multiple.yaml" When we run "jrnl work a long day in the office" When we run "jrnl -99 --short" Then the output should be - @todo something + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. When we run "jrnl work -99 --short" - Then the output should be - @todo something + Then the output should contain "a long day in the office" Scenario: Tell user which journal was used Given we use the config "multiple.yaml" @@ -39,29 +41,32 @@ Feature: Multiple journals When we run "jrnl work 23 july 2012: a long day in the office" When we run "jrnl -99 --short" Then the output should be - @todo something + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. When we run "jrnl work -99 --short" Then the output should be - @todo something + 2012-07-23 09:00 a long day in the office Scenario: Write to specified journal without a timestamp but with colon Given we use the config "multiple.yaml" When we run "jrnl work : a long day in the office" Then the output should be - @todo something + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. When we run "jrnl work -99 --short" - Then the output should be - @todo something + Then the output should be contain + a long day in the office Scenario: Write to specified journal without a timestamp but with colon Given we use the config "multiple.yaml" When we run "jrnl work: a long day in the office" When we run "jrnl -99 --short" Then the output should be - @todo something + 2013-06-09 15:39 My first entry. + 2013-06-10 15:40 Life is good. When we run "jrnl work -99 --short" - Then the output should be - @todo something + Then the output should contain + a long day in the office Scenario: Create new journals as required Given we use the config "multiple.yaml" @@ -69,7 +74,7 @@ Feature: Multiple journals When we run "jrnl ideas 23 july 2012: sell my junk on ebay and make lots of money" When we run "jrnl ideas -99 --short" Then the output should be - @todo something + 2012-07-23 09:00 sell my junk on ebay and make lots of money Scenario: Don't crash if no default journal is specified Given we use the config "bug343.yaml" diff --git a/tests/features/search.feature b/tests/features/search.feature index 0bd0fb79..8d951aaf 100644 --- a/tests/features/search.feature +++ b/tests/features/search.feature @@ -267,7 +267,7 @@ Feature: Searching in a journal Scenario Outline: Searching today in history Given we use the config "" And we use the password "test" if prompted - And we set current date and time to "2020-08-31 14:32" + And now is "2020-08-31 02:32:00 PM" When we run "jrnl 2019-08-31 01:01: Hi, from last year." And we run "jrnl -today-in-history --short" Then the output should be diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 9e482737..c6d36f89 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -164,6 +164,7 @@ def password(): def input_method(): return "" + @fixture def now_date(): return {"datetime": datetime, "calendar_parse": __get_pdt_calendar()} @@ -373,7 +374,11 @@ def use_password_forever(pw): @when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) -@when(parsers.re('we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"')) +@when( + parsers.re( + 'we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"' + ) +) @when(parse('we run "jrnl" and {input_method} "{user_input}"')) @when(parse('we run "jrnl {command}"')) @when('we run "jrnl "') @@ -391,8 +396,8 @@ def we_run( keyring, input_method, ): - assert input_method in ['', 'enter', 'pipe'] - is_tty = input_method != 'pipe' + assert input_method in ["", "enter", "pipe"] + is_tty = input_method != "pipe" if cache_dir["exists"]: command = command.format(cache_dir=cache_dir["path"]) @@ -573,6 +578,15 @@ def journal_directory_should_contain(config_data, file_list): assert does_directory_contain_files(file_list, scoped_config["journal"]) +@then(parse('journal "{journal_name}" should not exist')) +def journal_directory_should_contain(config_data, journal_name): + scoped_config = scope_config(config_data, journal_name) + + assert not does_directory_contain_files( + scoped_config["journal"], "." + ), f'Journal "{journal_name}" does exist' + + @when(parse('we change directory to "{directory_name}"')) def when_we_change_directory(directory_name): if not os.path.isdir(directory_name): From 5572833652bef5473ee53910d57739839be0c223 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 22 May 2021 17:11:14 -0700 Subject: [PATCH 60/74] Rewrite config checking steps in pytest-bdd - Take out old type coersion (it was causing needles complexity) - Take out `read_value_from_string` function - Use taml parser to parse yaml instead of using custom function - Update tests to use new implementation Co-authored-by: Micah Jerome Ellison --- tests/features/encrypt.feature | 6 +-- tests/features/password.feature | 10 ++-- tests/features/upgrade.feature | 14 +++--- tests/step_defs/conftest.py | 81 ++++++++++++++++----------------- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/tests/features/encrypt.feature b/tests/features/encrypt.feature index daa9f109..31d53520 100644 --- a/tests/features/encrypt.feature +++ b/tests/features/encrypt.feature @@ -4,7 +4,7 @@ Feature: Encrypting and decrypting journals Given we use the config "encrypted.yaml" When we run "jrnl --decrypt" and enter "bad doggie no biscuit" Then we should see the message "Journal decrypted" - Then the config for journal "default" should have "encrypt" set to "bool:False" + And the config for journal "default" should contain "encrypt: false" When we run "jrnl -99 --short" Then the output should be 2013-06-09 15:39 My first entry. @@ -16,7 +16,7 @@ Feature: Encrypting and decrypting journals # This should warn the user that the journal is already encrypted Given we use the config "simple.yaml" When we run "jrnl --decrypt" - Then the config for journal "default" should have "encrypt" set to "bool:False" + Then the config for journal "default" should contain "encrypt: false" When we run "jrnl -99 --short" Then the output should be 2013-06-09 15:39 My first entry. @@ -35,7 +35,7 @@ Feature: Encrypting and decrypting journals swordfish n Then we should see the message "Journal encrypted" - And the config for journal "default" should have "encrypt" set to "bool:True" + And the config for journal "default" should contain "encrypt: true" When we run "jrnl -n 1" and enter "swordfish" Then we should be prompted for a password And the output should contain "2013-06-10 15:40 Life is good" diff --git a/tests/features/password.feature b/tests/features/password.feature index d3116fed..ed8aea5f 100644 --- a/tests/features/password.feature +++ b/tests/features/password.feature @@ -7,7 +7,7 @@ Feature: Using the installed keyring sabertooth sabertooth Y - Then the config for journal "simple" should have "encrypt" set to "bool:True" + Then the config for journal "simple" should contain "encrypt: true" When we run "jrnl simple -n 1" Then the output should contain "2013-06-10 15:40 Life is good" @@ -58,7 +58,7 @@ Feature: Using the installed keyring Then we should see the message "Failed to retrieve keyring" And we should get no error And we should be prompted for a password - And the config for journal "default" should have "encrypt" set to "bool:True" + And the config for journal "default" should contain "encrypt: true" Scenario: Decrypt journal when keyring exists but fails @@ -70,7 +70,7 @@ Feature: Using the installed keyring And we should get no error And we should be prompted for a password And we should see the message "Journal decrypted" - And the config for journal "default" should have "encrypt" set to "bool:False" + And the config for journal "default" should contain "encrypt: false" When we run "jrnl --short" Then we should not be prompted for a password And the output should be @@ -97,7 +97,7 @@ Feature: Using the installed keyring sordfish Then we should be prompted for a password And we should see the message "Passwords did not match" - And the config for journal "default" should not have "encrypt" set + And the config for journal "default" should not contain "encrypt: true" When we run "jrnl --short" Then the output should be 2013-06-09 15:39 My first entry. @@ -115,7 +115,7 @@ Feature: Using the installed keyring Then we should be prompted for a password And we should see the message "Passwords did not match" And we should see the message "Journal encrypted" - And the config for journal "default" should have "encrypt" set to "bool:True" + And the config for journal "default" should contain "encrypt: true" When we run "jrnl -1" and enter "swordfish" Then we should be prompted for a password And the output should contain "2013-06-10 15:40 Life is good" diff --git a/tests/features/upgrade.feature b/tests/features/upgrade.feature index 115eb8ff..bb050fa1 100644 --- a/tests/features/upgrade.feature +++ b/tests/features/upgrade.feature @@ -5,7 +5,8 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x When we run "jrnl -9" and enter "Y" When we run "jrnl -99 --short" Then the output should be - @todo something + 2010-06-10 15:00 A life without chocolate is like a bad analogy. + 2013-06-10 15:40 He said "[this] is the best time to be alive".Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada And the output should contain 2010-06-10 15:00 A life without chocolate is like a bad analogy. And the output should contain @@ -23,11 +24,12 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x Scenario: Upgrading a config without colors to colors Given we use the config "no_colors.yaml" When we run "jrnl -n 1" - Then the config should have "colors" set to - date: none - title: none - body: none - tags: none + Then the config should contain + colors: + date: none + title: none + body: none + tags: none Scenario: Upgrade and parse journals with little endian date format Given we use the config "upgrade_from_195_little_endian_dates.json" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index c6d36f89..4f934d31 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -15,6 +15,7 @@ import string import re import shutil import tempfile +import yaml from unittest.mock import patch from unittest.mock import MagicMock from xml.etree import ElementTree @@ -103,17 +104,6 @@ def pytest_bdd_apply_tag(tag, function): # ----- UTILS ----- # -def read_value_from_string(string): - if string[0] == "{": - # Handle value being a dictionary - return ast.literal_eval(string) - - # Takes strings like "bool:true" or "int:32" and coerces them into proper type - t, value = string.split(":") - value = {"bool": lambda v: v.lower() == "true", "int": int, "str": str}[t](value) - return value - - def does_directory_contain_files(file_list, directory_path): if not os.path.isdir(directory_path): return False @@ -523,37 +513,46 @@ def should_see_the_message(text, cli_run): assert text in out, [text, out] -@then(parse('the config should have "{key}" set to\n{str_value}')) -@then(parse('the config should have "{key}" set to "{str_value}"')) -@then( - parse( - 'the config for journal "{journal_name}" should have "{key}" set to "{str_value}"' - ) -) -@then(parse('the config should {should_not} have "{key}" set')) -@then(parse('the config should {should_not} have "{key}" set')) -@then( - parse( - 'the config for journal "{journal_name}" should {should_not} have "{key}" set' - ) -) -def config_var(config_data, key, str_value, journal_name, should_not): - str_value = read_value_from_string(str_value) if len(str_value) else str_value - - configuration = config_data - if journal_name: - configuration = configuration["journals"][journal_name] - - # is the config a string? - # @todo this should probably be a function - if type(configuration) is str: - configuration = {"journal": configuration} - - if should_not: - assert key not in configuration +def parse_should_or_should_not(should_or_should_not): + if should_or_should_not == "should": + return True + elif should_or_should_not == "should not": + return False else: - assert key in configuration - assert configuration[key] == str_value + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) + + +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' + ) +) +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain\n{some_yaml}' + ) +) +@then(parse('the config {should_or_should_not} contain "{some_yaml}"')) +@then(parse("the config {should_or_should_not} contain\n{some_yaml}")) +def config_var(config_data, journal_name, should_or_should_not, some_yaml): + we_should = parse_should_or_should_not(should_or_should_not) + + actual = config_data + if journal_name: + actual = actual["journals"][journal_name] + + expected = yaml.load(some_yaml, Loader=yaml.FullLoader) + + actual_slice = actual + if type(actual) is dict: + actual_slice = {key: actual.get(key, None) for key in expected.keys()} + + if we_should: + assert expected == actual_slice + else: + assert expected != actual_slice @then("we should be prompted for a password") From 0c8efd5331b0f9d73bb7cee7b44ddc18d76846cb Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 22 May 2021 17:25:40 -0700 Subject: [PATCH 61/74] Cleanup last few tests - Misc linting issues - Whitespace cleanup - Entire test suite is now passing - Add misc todo items in comments Co-authored-by: Micah Jerome Ellison --- tests/features/upgrade.feature | 13 ++++++------- tests/step_defs/conftest.py | 8 +++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/features/upgrade.feature b/tests/features/upgrade.feature index bb050fa1..e5714a82 100644 --- a/tests/features/upgrade.feature +++ b/tests/features/upgrade.feature @@ -33,16 +33,15 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x Scenario: Upgrade and parse journals with little endian date format Given we use the config "upgrade_from_195_little_endian_dates.json" - When we run "jrnl -9" and enter "Y" - Then the output should be + When we run "jrnl -9 --short" and enter "Y" + Then the output should contain 10.06.2010 15:00 A life without chocolate is like a bad analogy. 10.06.2013 15:40 He said "[this] is the best time to be alive". Scenario: Upgrade with missing journal Given we use the config "upgrade_from_195_with_missing_journal.json" - When we run "jrnl --list" and enter - Y - Then the error output should contain "Error: features/journals/missing.journal does not exist." + When we run "jrnl --list" and enter "Y" + Then the output should contain "Error: features/journals/missing.journal does not exist." And we should get no error Scenario: Upgrade with missing encrypted journal @@ -50,6 +49,6 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x When we run "jrnl --list" and enter Y bad doggie no biscuit - Then the error output should contain "Error: features/journals/missing.journal does not exist." - And the error output should contain "We're all done" + Then the output should contain "Error: features/journals/missing.journal does not exist." + And the output should contain "We're all done" And we should get no error diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 4f934d31..12eb948c 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,7 +1,6 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -import ast import json import os from datetime import datetime @@ -406,6 +405,7 @@ def we_run( # fmt: off # see: https://github.com/psf/black/issues/664 + # @todo https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack with \ patch("sys.argv", ['jrnl'] + args), \ patch("sys.stdin.read", side_effect=user_input) as mock_stdin, \ @@ -578,7 +578,7 @@ def journal_directory_should_contain(config_data, file_list): @then(parse('journal "{journal_name}" should not exist')) -def journal_directory_should_contain(config_data, journal_name): +def journal_directory_should_not_exist(config_data, journal_name): scoped_config = scope_config(config_data, journal_name) assert not does_directory_contain_files( @@ -723,9 +723,7 @@ def assert_parsed_output_item_count(node_name, number, parsed_output): @then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) -def assert_output_field_content( - field_name, comparison, expected_keys, cli_run, parsed_output -): +def assert_output_field_content(field_name, comparison, expected_keys, parsed_output): lang = parsed_output["lang"] obj = parsed_output["obj"] expected_keys = expected_keys.split("\n") From fd349fb0fcdfd356a02065bcc733172b10f9d32c Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 5 Jun 2021 15:54:28 -0700 Subject: [PATCH 62/74] Implement ExitStack to handle mocks in pytest-bdd - Fix failing DayOne test - Make format and clean up extraneous comment Co-authored-by: Jonathan Wren --- tests/features/write.feature | 6 +-- tests/step_defs/conftest.py | 83 +++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/tests/features/write.feature b/tests/features/write.feature index aec325d5..1cb822b5 100644 --- a/tests/features/write.feature +++ b/tests/features/write.feature @@ -196,16 +196,14 @@ Feature: Writing new entries. And "entries.0.creator.software_agent" in the parsed output should contain jrnl - # fails when system time is UTC (as on Travis-CI) - # @skip Scenario: Title with an embedded period on DayOne journal Given we use the config "dayone.yaml" - When we run "jrnl 04-24-2014: "Ran 6.2 miles today in 1:02:03. I'm feeling sore because I forgot to stretch."" + When we run "jrnl 04-24-2014: Ran 6.2 miles today in 1:02:03. I am feeling sore because I forgot to stretch." Then we should see the message "Entry added" When we run "jrnl -1" Then the output should be 2014-04-24 09:00 Ran 6.2 miles today in 1:02:03. - | I'm feeling sore because I forgot to stretch. + | I am feeling sore because I forgot to stretch. Scenario: Opening an folder that's not a DayOne folder should treat as folder journal Given we use the config "empty_folder.yaml" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 12eb948c..45fd73eb 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -5,6 +5,7 @@ import json import os from datetime import datetime from collections import defaultdict +from contextlib import ExitStack from keyring import backend from keyring import set_keyring from keyring import errors @@ -121,6 +122,11 @@ def cli_run(): return {"status": 0, "stdout": None, "stderr": None} +@fixture +def mocks(): + return dict() + + @fixture def temp_dir(): return tempfile.TemporaryDirectory() @@ -154,11 +160,6 @@ def input_method(): return "" -@fixture -def now_date(): - return {"datetime": datetime, "calendar_parse": __get_pdt_calendar()} - - @fixture def cache_dir(): return {"exists": False, "path": ""} @@ -268,27 +269,37 @@ def we_enter_editor(editor_method, editor_input, editor_state): editor_state["intent"] = {"method": file_method, "input": editor_input} -@given(parse('now is ""'), target_fixture="now_date") -@given(parse('now is "{date_str}"'), target_fixture="now_date") -def now_is_str(date_str): +@given(parse('now is ""')) +@given(parse('now is "{date_str}"')) +def now_is_str(date_str, mocks): class DatetimeMagicMock(MagicMock): # needed because jrnl does some reflection on datetime def __instancecheck__(self, subclass): return isinstance(subclass, datetime) - my_date = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") + def mocked_now(tz=None): + now = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") + + if tz: + time_zone = datetime.utcnow().astimezone().tzinfo + now = now.replace(tzinfo=time_zone) + + return now # jrnl uses two different classes to parse dates, so both must be mocked datetime_mock = DatetimeMagicMock(wraps=datetime) - datetime_mock.now.return_value = my_date + datetime_mock.now.side_effect = mocked_now pdt = __get_pdt_calendar() calendar_mock = MagicMock(wraps=pdt) calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( - date_str_input, my_date + date_str_input, mocked_now() ) - return {"datetime": datetime_mock, "calendar_parse": calendar_mock} + mocks["datetime"] = patch("datetime.datetime", new=datetime_mock) + mocks["calendar_parse"] = patch( + "jrnl.time.__get_pdt_calendar", return_value=calendar_mock + ) @then(parse("the editor should have been called")) @@ -381,9 +392,9 @@ def we_run( password, cache_dir, editor, - now_date, keyring, input_method, + mocks, ): assert input_method in ["", "enter", "pipe"] is_tty = input_method != "pipe" @@ -403,21 +414,36 @@ def we_run( if not password and user_input: password = user_input - # fmt: off - # see: https://github.com/psf/black/issues/664 - # @todo https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack - with \ - patch("sys.argv", ['jrnl'] + args), \ - patch("sys.stdin.read", side_effect=user_input) as mock_stdin, \ - patch("sys.stdin.isatty", return_value=is_tty), \ - patch("builtins.input", side_effect=user_input) as mock_input, \ - patch("getpass.getpass", side_effect=password) as mock_getpass, \ - patch("datetime.datetime", new=now_date["datetime"]), \ - patch("jrnl.time.__get_pdt_calendar", return_value=now_date["calendar_parse"]), \ - patch("jrnl.install.get_config_path", return_value=config_path), \ - patch("jrnl.config.get_config_path", return_value=config_path), \ - patch("subprocess.call", side_effect=editor) as mock_editor \ - : # @TODO: single point of truth for get_config_path (move from all calls from install to config) + with ExitStack() as stack: + + stack.enter_context(patch("sys.argv", ["jrnl"] + args)) + + mock_stdin = stack.enter_context( + patch("sys.stdin.read", side_effect=user_input) + ) + stack.enter_context(patch("sys.stdin.isatty", return_value=is_tty)) + mock_input = stack.enter_context( + patch("builtins.input", side_effect=user_input) + ) + mock_getpass = stack.enter_context( + patch("getpass.getpass", side_effect=password) + ) + + if "datetime" in mocks: + stack.enter_context(mocks["datetime"]) + stack.enter_context(mocks["calendar_parse"]) + + # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) + # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) + + stack.enter_context( + patch("jrnl.install.get_config_path", return_value=config_path) + ) + stack.enter_context( + patch("jrnl.config.get_config_path", return_value=config_path) + ) + mock_editor = stack.enter_context(patch("subprocess.call", side_effect=editor)) + try: cli(args) except StopIteration: @@ -425,7 +451,6 @@ def we_run( pass except SystemExit as e: status = e.code - # fmt: on captured = capsys.readouterr() From 54e5e96ad28de4555659352ca8742194269feb4b Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 5 Jun 2021 16:35:09 -0700 Subject: [PATCH 63/74] Force GitHub Actions to preserve line endings Co-authored-by: Jonathan Wren --- .github/workflows/testing.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index a90b939a..47710ca2 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -29,6 +29,7 @@ jobs: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: + - run: git config --global core.autocrlf false - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From c5a7d7027ced56c2175326ad7b7d8d5ab4086302 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 19 Jun 2021 16:39:30 -0700 Subject: [PATCH 64/74] Move pytest-bdd code into separate files Now that all the tests are passing, this breaks them up into a few different files to make everything more organized. Note: Pyflakes is complaining about some unused import statements. --- tests/step_defs/conftest.py | 794 +-------------------------------- tests/step_defs/fixtures.py | 202 +++++++++ tests/step_defs/given_steps.py | 133 ++++++ tests/step_defs/helpers.py | 41 ++ tests/step_defs/then_steps.py | 331 ++++++++++++++ tests/step_defs/when_steps.py | 113 +++++ 6 files changed, 827 insertions(+), 787 deletions(-) create mode 100644 tests/step_defs/fixtures.py create mode 100644 tests/step_defs/given_steps.py create mode 100644 tests/step_defs/helpers.py create mode 100644 tests/step_defs/then_steps.py create mode 100644 tests/step_defs/when_steps.py diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index 45fd73eb..d73fcec4 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,96 +1,18 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -import json -import os -from datetime import datetime -from collections import defaultdict -from contextlib import ExitStack -from keyring import backend -from keyring import set_keyring -from keyring import errors -from pathlib import Path -import random -import string -import re -import shutil -import tempfile -import yaml -from unittest.mock import patch -from unittest.mock import MagicMock -from xml.etree import ElementTree - -from pytest_bdd import given -from pytest_bdd import then -from pytest_bdd import when -from pytest_bdd.parsers import parse -from pytest_bdd import parsers -from pytest import fixture -from pytest import mark -import toml - -from jrnl import __version__ -from jrnl.cli import cli -from jrnl.config import load_config -from jrnl.config import scope_config -from jrnl.os_compat import split_args from jrnl.os_compat import on_windows -from jrnl.time import __get_pdt_calendar +from pytest import mark + +from .fixtures import * +from .given_steps import * +from .when_steps import * +from .then_steps import * -class TestKeyring(backend.KeyringBackend): - """A test keyring that just stores its values in a hash""" - - priority = 1 - keys = defaultdict(dict) - - def set_password(self, servicename, username, password): - self.keys[servicename][username] = password - - def get_password(self, servicename, username): - return self.keys[servicename].get(username) - - def delete_password(self, servicename, username): - self.keys[servicename][username] = None - - -class NoKeyring(backend.KeyringBackend): - """A keyring that simulated an environment with no keyring backend.""" - - priority = 2 - keys = defaultdict(dict) - - def set_password(self, servicename, username, password): - raise errors.NoKeyringError - - def get_password(self, servicename, username): - raise errors.NoKeyringError - - def delete_password(self, servicename, username): - raise errors.NoKeyringError - - -class FailedKeyring(backend.KeyringBackend): - """ - A keyring that cannot be retrieved. - """ - - priority = 2 - - def set_password(self, servicename, username, password): - raise errors.KeyringError - - def get_password(self, servicename, username): - raise errors.KeyringError - - def delete_password(self, servicename, username): - raise errors.KeyringError - - -# ----- MARKERS ----- # def pytest_bdd_apply_tag(tag, function): if tag == "skip_win": - marker = mark.skipif(on_windows, reason="Skip test on Windows") + marker = mark.skipif(on_windows(), reason="Skip test on Windows") elif tag == "skip_editor": marker = mark.skip( reason="Skipping editor-related test. We should come back to this!" @@ -101,705 +23,3 @@ def pytest_bdd_apply_tag(tag, function): marker(function) return True - - -# ----- UTILS ----- # -def does_directory_contain_files(file_list, directory_path): - if not os.path.isdir(directory_path): - return False - - for file in file_list.split("\n"): - fullpath = directory_path + "/" + file - if not os.path.isfile(fullpath): - return False - - return True - - -# ----- FIXTURES ----- # -@fixture -def cli_run(): - return {"status": 0, "stdout": None, "stderr": None} - - -@fixture -def mocks(): - return dict() - - -@fixture -def temp_dir(): - return tempfile.TemporaryDirectory() - - -@fixture -def working_dir(request): - return os.path.join(request.config.rootpath, "tests") - - -@fixture -def config_path(temp_dir): - os.chdir(temp_dir.name) - return temp_dir.name + "/jrnl.yaml" - - -@fixture -def toml_version(working_dir): - pyproject = os.path.join(working_dir, "..", "pyproject.toml") - pyproject_contents = toml.load(pyproject) - return pyproject_contents["tool"]["poetry"]["version"] - - -@fixture -def password(): - return "" - - -@fixture -def input_method(): - return "" - - -@fixture -def cache_dir(): - return {"exists": False, "path": ""} - - -@fixture -def str_value(): - return "" - - -@fixture -def command(): - return "" - - -@fixture -def should_not(): - return False - - -@fixture -def user_input(): - return "" - - -@fixture -def keyring(): - set_keyring(NoKeyring()) - - -@fixture -def keyring_type(): - return "default" - - -@fixture -def config_data(config_path): - return load_config(config_path) - - -@fixture -def journal_name(): - return None - - -@fixture -def which_output_stream(): - return None - - -@fixture -def editor_input(): - return None - - -@fixture -def num_args(): - return None - - -@fixture -def parsed_output(): - return {"lang": None, "obj": None} - - -@fixture -def editor_state(): - return { - "command": "", - "intent": {"method": "r", "input": None}, - "tmpfile": {"name": None, "content": None}, - } - - -@fixture -def editor(editor_state): - def _mock_editor(editor_command): - tmpfile = editor_command[-1] - - editor_state["command"] = editor_command - editor_state["tmpfile"]["name"] = tmpfile - - Path(tmpfile).touch() - with open(tmpfile, editor_state["intent"]["method"]) as f: - # Touch the file so jrnl knows it was edited - if editor_state["intent"]["input"] != None: - f.write(editor_state["intent"]["input"]) - - file_content = f.read() - editor_state["tmpfile"]["content"] = file_content - - return _mock_editor - - -# ----- STEPS ----- # -@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) -@given(parse("we {editor_method} nothing to the editor if opened")) -def we_enter_editor(editor_method, editor_input, editor_state): - file_method = editor_state["intent"]["method"] - if editor_method == "write": - file_method = "w+" - elif editor_method == "append": - file_method = "a+" - else: - assert False, f"Method '{editor_method}' not supported" - - editor_state["intent"] = {"method": file_method, "input": editor_input} - - -@given(parse('now is ""')) -@given(parse('now is "{date_str}"')) -def now_is_str(date_str, mocks): - class DatetimeMagicMock(MagicMock): - # needed because jrnl does some reflection on datetime - def __instancecheck__(self, subclass): - return isinstance(subclass, datetime) - - def mocked_now(tz=None): - now = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") - - if tz: - time_zone = datetime.utcnow().astimezone().tzinfo - now = now.replace(tzinfo=time_zone) - - return now - - # jrnl uses two different classes to parse dates, so both must be mocked - datetime_mock = DatetimeMagicMock(wraps=datetime) - datetime_mock.now.side_effect = mocked_now - - pdt = __get_pdt_calendar() - calendar_mock = MagicMock(wraps=pdt) - calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( - date_str_input, mocked_now() - ) - - mocks["datetime"] = patch("datetime.datetime", new=datetime_mock) - mocks["calendar_parse"] = patch( - "jrnl.time.__get_pdt_calendar", return_value=calendar_mock - ) - - -@then(parse("the editor should have been called")) -@then(parse("the editor should have been called with {num_args} arguments")) -def count_editor_args(num_args, cli_run, editor_state): - assert cli_run["mocks"]["editor"].called - - if isinstance(num_args, int): - assert len(editor_state["command"]) == int(num_args) - - -@then(parse('the editor filename should end with "{suffix}"')) -def editor_filename_suffix(suffix, editor_state): - editor_filename = editor_state["tmpfile"]["name"] - - assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix) - - -@then(parse('the editor file content should {comparison} "{str_value}"')) -@then(parse("the editor file content should {comparison} empty")) -@then(parse("the editor file content should {comparison}\n{str_value}")) -def contains_editor_file(comparison, str_value, editor_state): - content = editor_state["tmpfile"]["content"] - # content = f'\n"""\n{content}\n"""\n' - if comparison == "be": - assert content == str_value - elif comparison == "contain": - assert str_value in content - else: - assert False, f"Comparison '{comparison}' not supported" - - -@given("we have a keyring", target_fixture="keyring") -@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") -def we_have_type_of_keyring(keyring_type): - if keyring_type == "failed": - set_keyring(FailedKeyring()) - else: - set_keyring(TestKeyring()) - - -@given(parse('we use the config "{config_file}"'), target_fixture="config_path") -@given('we use the config ""', target_fixture="config_path") -def we_use_the_config(config_file, temp_dir, working_dir): - # Move into temp dir as cwd - os.chdir(temp_dir.name) - - # Copy the config file over - config_source = os.path.join(working_dir, "data", "configs", config_file) - config_dest = os.path.join(temp_dir.name, config_file) - shutil.copy2(config_source, config_dest) - - # @todo make this only copy some journals over - # Copy all of the journals over - journal_source = os.path.join(working_dir, "data", "journals") - journal_dest = os.path.join(temp_dir.name, "features", "journals") - shutil.copytree(journal_source, journal_dest) - - # @todo get rid of this by using default config values - # merge in version number - if config_file.endswith("yaml") and os.path.exists(config_dest): - # Add jrnl version to file for 2.x journals - with open(config_dest, "a") as cf: - cf.write("version: {}".format(__version__)) - - return config_dest - - -@given(parse('we use the password "{pw}" if prompted'), target_fixture="password") -def use_password_forever(pw): - return pw - - -@when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) -@when( - parsers.re( - 'we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"' - ) -) -@when(parse('we run "jrnl" and {input_method} "{user_input}"')) -@when(parse('we run "jrnl {command}"')) -@when('we run "jrnl "') -@when('we run "jrnl"') -def we_run( - command, - config_path, - user_input, - cli_run, - capsys, - password, - cache_dir, - editor, - keyring, - input_method, - mocks, -): - assert input_method in ["", "enter", "pipe"] - is_tty = input_method != "pipe" - - if cache_dir["exists"]: - command = command.format(cache_dir=cache_dir["path"]) - - args = split_args(command) - status = 0 - - if user_input: - user_input = user_input.splitlines() if is_tty else [user_input] - - if password: - password = password.splitlines() - - if not password and user_input: - password = user_input - - with ExitStack() as stack: - - stack.enter_context(patch("sys.argv", ["jrnl"] + args)) - - mock_stdin = stack.enter_context( - patch("sys.stdin.read", side_effect=user_input) - ) - stack.enter_context(patch("sys.stdin.isatty", return_value=is_tty)) - mock_input = stack.enter_context( - patch("builtins.input", side_effect=user_input) - ) - mock_getpass = stack.enter_context( - patch("getpass.getpass", side_effect=password) - ) - - if "datetime" in mocks: - stack.enter_context(mocks["datetime"]) - stack.enter_context(mocks["calendar_parse"]) - - # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) - # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) - - stack.enter_context( - patch("jrnl.install.get_config_path", return_value=config_path) - ) - stack.enter_context( - patch("jrnl.config.get_config_path", return_value=config_path) - ) - mock_editor = stack.enter_context(patch("subprocess.call", side_effect=editor)) - - try: - cli(args) - except StopIteration: - # This happens when input is expected, but don't have any input left - pass - except SystemExit as e: - status = e.code - - captured = capsys.readouterr() - - cli_run["status"] = status - cli_run["stdout"] = captured.out - cli_run["stderr"] = captured.err - cli_run["mocks"] = { - "stdin": mock_stdin, - "input": mock_input, - "getpass": mock_getpass, - "editor": mock_editor, - } - - -@then("we should get no error") -def should_get_no_error(cli_run): - assert cli_run["status"] == 0, cli_run["status"] - - -@then(parse('the output should match "{regex}"')) -def output_should_match(regex, cli_run): - out = cli_run["stdout"] - matches = re.findall(regex, out) - assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" - - -@then(parse("the output should contain\n{expected_output}")) -@then(parse('the output should contain "{expected_output}"')) -@then('the output should contain ""') -@then(parse("the {which_output_stream} output should contain\n{expected_output}")) -@then(parse('the {which_output_stream} output should contain "{expected_output}"')) -def output_should_contain(expected_output, which_output_stream, cli_run): - assert expected_output - if which_output_stream is None: - assert (expected_output in cli_run["stdout"]) or ( - expected_output in cli_run["stderr"] - ) - - elif which_output_stream == "standard": - assert expected_output in cli_run["stdout"] - - elif which_output_stream == "error": - assert expected_output in cli_run["stderr"] - - else: - assert expected_output in cli_run[which_output_stream] - - -@then(parse("the output should not contain\n{expected_output}")) -@then(parse('the output should not contain "{expected_output}"')) -@then('the output should not contain ""') -def output_should_not_contain(expected_output, cli_run): - assert expected_output not in cli_run["stdout"] - - -@then(parse("the output should be\n{expected_output}")) -@then(parse('the output should be "{expected_output}"')) -@then('the output should be ""') -def output_should_be(expected_output, cli_run): - actual = cli_run["stdout"].strip() - expected = expected_output.strip() - assert expected == actual - - -@then("the output should be empty") -def output_should_be_empty(cli_run): - actual = cli_run["stdout"].strip() - assert actual == "" - - -@then('the output should contain the date ""') -def output_should_contain_date(date, cli_run): - assert date and date in cli_run["stdout"] - - -@then("the output should contain pyproject.toml version") -def output_should_contain_version(cli_run, toml_version): - out = cli_run["stdout"] - assert toml_version in out, toml_version - - -@then(parse('we should see the message "{text}"')) -def should_see_the_message(text, cli_run): - out = cli_run["stderr"] - assert text in out, [text, out] - - -def parse_should_or_should_not(should_or_should_not): - if should_or_should_not == "should": - return True - elif should_or_should_not == "should not": - return False - else: - raise Exception( - "should_or_should_not valid values are 'should' or 'should not'" - ) - - -@then( - parse( - 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' - ) -) -@then( - parse( - 'the config for journal "{journal_name}" {should_or_should_not} contain\n{some_yaml}' - ) -) -@then(parse('the config {should_or_should_not} contain "{some_yaml}"')) -@then(parse("the config {should_or_should_not} contain\n{some_yaml}")) -def config_var(config_data, journal_name, should_or_should_not, some_yaml): - we_should = parse_should_or_should_not(should_or_should_not) - - actual = config_data - if journal_name: - actual = actual["journals"][journal_name] - - expected = yaml.load(some_yaml, Loader=yaml.FullLoader) - - actual_slice = actual - if type(actual) is dict: - actual_slice = {key: actual.get(key, None) for key in expected.keys()} - - if we_should: - assert expected == actual_slice - else: - assert expected != actual_slice - - -@then("we should be prompted for a password") -def password_was_called(cli_run): - assert cli_run["mocks"]["getpass"].called - - -@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): - assert does_directory_contain_files(file_list, cache_dir["path"]) - - -@then(parse("the journal directory should contain\n{file_list}")) -def journal_directory_should_contain(config_data, file_list): - scoped_config = scope_config(config_data, "default") - - assert does_directory_contain_files(file_list, scoped_config["journal"]) - - -@then(parse('journal "{journal_name}" should not exist')) -def journal_directory_should_not_exist(config_data, journal_name): - scoped_config = scope_config(config_data, journal_name) - - assert not does_directory_contain_files( - scoped_config["journal"], "." - ), f'Journal "{journal_name}" does exist' - - -@when(parse('we change directory to "{directory_name}"')) -def when_we_change_directory(directory_name): - if not os.path.isdir(directory_name): - os.mkdir(directory_name) - - os.chdir(directory_name) - - -@then(parse("the journal {should_or_should_not} exist")) -def journal_should_not_exist(config_data, should_or_should_not): - scoped_config = scope_config(config_data, "default") - expected_path = scoped_config["journal"] - - contains_files = does_directory_contain_files(expected_path, ".") - - if should_or_should_not == "should": - assert contains_files - elif should_or_should_not == "should not": - assert not contains_files - else: - raise Exception( - "should_or_should_not valid values are 'should' or 'should not'" - ) - - -@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(parse("the output should be valid {language_name}")) -def assert_output_is_valid_language(cli_run, language_name): - language_name = language_name.upper() - if language_name == "XML": - xml_tree = ElementTree.fromstring(cli_run["stdout"]) - assert xml_tree, "Invalid XML" - elif language_name == "JSON": - assert json.loads(cli_run["stdout"]), "Invalid JSON" - else: - assert False, f"Language name {language_name} not recognized" - - -@given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") -def parse_output_as_language(cli_run, language_name): - language_name = language_name.upper() - actual_output = cli_run["stdout"] - - if language_name == "XML": - parsed_output = ElementTree.fromstring(actual_output) - elif language_name == "JSON": - parsed_output = json.loads(actual_output) - else: - assert False, f"Language name {language_name} not recognized" - - return {"lang": language_name, "obj": parsed_output} - - -@then(parse('"{node_name}" in the parsed output should have {number:d} elements')) -def assert_parsed_output_item_count(node_name, number, parsed_output): - lang = parsed_output["lang"] - obj = parsed_output["obj"] - - if lang == "XML": - xml_node_names = (node.tag for node in obj) - assert node_name in xml_node_names, str(list(xml_node_names)) - - actual_entry_count = len(obj.find(node_name)) - assert actual_entry_count == number, actual_entry_count - - elif lang == "JSON": - my_obj = obj - - for node in node_name.split("."): - try: - my_obj = my_obj[int(node)] - except ValueError: - assert node in my_obj - my_obj = my_obj[node] - - assert len(my_obj) == number, len(my_obj) - - else: - assert False, f"Language name {lang} not recognized" - - -@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) -def assert_output_field_content(field_name, comparison, expected_keys, parsed_output): - lang = parsed_output["lang"] - obj = parsed_output["obj"] - expected_keys = expected_keys.split("\n") - if len(expected_keys) == 1: - expected_keys = expected_keys[0] - - if lang == "XML": - xml_node_names = (node.tag for node in obj) - assert field_name in xml_node_names, str(list(xml_node_names)) - - if field_name == "tags": - actual_tags = set(t.attrib["name"] for t in obj.find("tags")) - assert set(actual_tags) == set(expected_keys), [ - actual_tags, - set(expected_keys), - ] - else: - assert False, "This test only works for tags in XML" - - elif lang == "JSON": - my_obj = obj - - for node in field_name.split("."): - try: - my_obj = my_obj[int(node)] - except ValueError: - assert node in my_obj, [my_obj.keys(), node] - my_obj = my_obj[node] - - if comparison == "be": - if type(my_obj) is str: - assert expected_keys == my_obj, [my_obj, expected_keys] - else: - assert set(expected_keys) == set(my_obj), [ - set(my_obj), - set(expected_keys), - ] - elif comparison == "contain": - if type(my_obj) is str: - assert expected_keys in my_obj, [my_obj, expected_keys] - else: - assert all(elem in my_obj for elem in expected_keys), [ - my_obj, - expected_keys, - ] - else: - assert False, f"Language name {lang} not recognized" - - -@then(parse('there should be {number:d} "{item}" elements')) -def count_elements(number, item, cli_run): - actual_output = cli_run["stdout"] - xml_tree = ElementTree.fromstring(actual_output) - assert len(xml_tree.findall(".//" + item)) == number diff --git a/tests/step_defs/fixtures.py b/tests/step_defs/fixtures.py new file mode 100644 index 00000000..a8e243ae --- /dev/null +++ b/tests/step_defs/fixtures.py @@ -0,0 +1,202 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import os +from collections import defaultdict +from keyring import backend +from keyring import set_keyring +from keyring import errors +from pathlib import Path +import tempfile + +from pytest import fixture +import toml + +from jrnl.config import load_config + + +# --- Keyring --- # +@fixture +def keyring(): + set_keyring(NoKeyring()) + + +@fixture +def keyring_type(): + return "default" + + +class TestKeyring(backend.KeyringBackend): + """A test keyring that just stores its values in a hash""" + + priority = 1 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + self.keys[servicename][username] = password + + def get_password(self, servicename, username): + return self.keys[servicename].get(username) + + def delete_password(self, servicename, username): + self.keys[servicename][username] = None + + +class NoKeyring(backend.KeyringBackend): + """A keyring that simulated an environment with no keyring backend.""" + + priority = 2 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + raise errors.NoKeyringError + + def get_password(self, servicename, username): + raise errors.NoKeyringError + + def delete_password(self, servicename, username): + raise errors.NoKeyringError + + +class FailedKeyring(backend.KeyringBackend): + """ A keyring that cannot be retrieved. """ + + priority = 2 + + def set_password(self, servicename, username, password): + raise errors.KeyringError + + def get_password(self, servicename, username): + raise errors.KeyringError + + def delete_password(self, servicename, username): + raise errors.KeyringError + + +# ----- Misc ----- # +@fixture +def cli_run(): + return {"status": 0, "stdout": None, "stderr": None} + + +@fixture +def mocks(): + return dict() + + +@fixture +def temp_dir(): + return tempfile.TemporaryDirectory() + + +@fixture +def working_dir(request): + return os.path.join(request.config.rootpath, "tests") + + +@fixture +def config_path(temp_dir): + os.chdir(temp_dir.name) + return temp_dir.name + "/jrnl.yaml" + + +@fixture +def toml_version(working_dir): + pyproject = os.path.join(working_dir, "..", "pyproject.toml") + pyproject_contents = toml.load(pyproject) + return pyproject_contents["tool"]["poetry"]["version"] + + +@fixture +def password(): + return "" + + +@fixture +def input_method(): + return "" + + +@fixture +def cache_dir(): + return {"exists": False, "path": ""} + + +@fixture +def str_value(): + return "" + + +@fixture +def command(): + return "" + + +@fixture +def should_not(): + return False + + +@fixture +def user_input(): + return "" + + +@fixture +def config_data(config_path): + return load_config(config_path) + + +@fixture +def journal_name(): + return None + + +@fixture +def which_output_stream(): + return None + + +@fixture +def editor_input(): + return None + + +@fixture +def num_args(): + return None + + +@fixture +def parsed_output(): + return {"lang": None, "obj": None} + + +@fixture +def editor_state(): + return { + "command": "", + "intent": {"method": "r", "input": None}, + "tmpfile": {"name": None, "content": None}, + } + + +@fixture +def editor(editor_state): + def _mock_editor(editor_command): + tmpfile = editor_command[-1] + + editor_state["command"] = editor_command + editor_state["tmpfile"]["name"] = tmpfile + + Path(tmpfile).touch() + with open(tmpfile, editor_state["intent"]["method"]) as f: + # Touch the file so jrnl knows it was edited + if editor_state["intent"]["input"] != None: + f.write(editor_state["intent"]["input"]) + + file_content = f.read() + editor_state["tmpfile"]["content"] = file_content + + return _mock_editor + diff --git a/tests/step_defs/given_steps.py b/tests/step_defs/given_steps.py new file mode 100644 index 00000000..8db8fa1c --- /dev/null +++ b/tests/step_defs/given_steps.py @@ -0,0 +1,133 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import json +import os +from datetime import datetime +from keyring import set_keyring +import random +import string +import shutil +from unittest.mock import patch +from unittest.mock import MagicMock +from xml.etree import ElementTree + +from jrnl import __version__ +from jrnl.time import __get_pdt_calendar + +from pytest_bdd import given +from pytest_bdd.parsers import parse +from .fixtures import FailedKeyring +from .fixtures import TestKeyring + + +@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) +@given(parse("we {editor_method} nothing to the editor if opened")) +def we_enter_editor(editor_method, editor_input, editor_state): + file_method = editor_state["intent"]["method"] + if editor_method == "write": + file_method = "w+" + elif editor_method == "append": + file_method = "a+" + else: + assert False, f"Method '{editor_method}' not supported" + + editor_state["intent"] = {"method": file_method, "input": editor_input} + + +@given(parse('now is ""')) +@given(parse('now is "{date_str}"')) +def now_is_str(date_str, mocks): + class DatetimeMagicMock(MagicMock): + # needed because jrnl does some reflection on datetime + def __instancecheck__(self, subclass): + return isinstance(subclass, datetime) + + def mocked_now(tz=None): + now = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") + + if tz: + time_zone = datetime.utcnow().astimezone().tzinfo + now = now.replace(tzinfo=time_zone) + + return now + + # jrnl uses two different classes to parse dates, so both must be mocked + datetime_mock = DatetimeMagicMock(wraps=datetime) + datetime_mock.now.side_effect = mocked_now + + pdt = __get_pdt_calendar() + calendar_mock = MagicMock(wraps=pdt) + calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( + date_str_input, mocked_now() + ) + + mocks["datetime"] = patch("datetime.datetime", new=datetime_mock) + mocks["calendar_parse"] = patch( + "jrnl.time.__get_pdt_calendar", return_value=calendar_mock + ) + + +@given("we have a keyring", target_fixture="keyring") +@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") +def we_have_type_of_keyring(keyring_type): + if keyring_type == "failed": + set_keyring(FailedKeyring()) + else: + set_keyring(TestKeyring()) + + +@given(parse('we use the config "{config_file}"'), target_fixture="config_path") +@given('we use the config ""', target_fixture="config_path") +def we_use_the_config(config_file, temp_dir, working_dir): + # Move into temp dir as cwd + os.chdir(temp_dir.name) + + # Copy the config file over + config_source = os.path.join(working_dir, "data", "configs", config_file) + config_dest = os.path.join(temp_dir.name, config_file) + shutil.copy2(config_source, config_dest) + + # @todo make this only copy some journals over + # Copy all of the journals over + journal_source = os.path.join(working_dir, "data", "journals") + journal_dest = os.path.join(temp_dir.name, "features", "journals") + shutil.copytree(journal_source, journal_dest) + + # @todo get rid of this by using default config values + # merge in version number + if config_file.endswith("yaml") and os.path.exists(config_dest): + # Add jrnl version to file for 2.x journals + with open(config_dest, "a") as cf: + cf.write("version: {}".format(__version__)) + + return config_dest + + +@given(parse('we use the password "{pw}" if prompted'), target_fixture="password") +def use_password_forever(pw): + return pw + + +@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} + + +@given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") +def parse_output_as_language(cli_run, language_name): + language_name = language_name.upper() + actual_output = cli_run["stdout"] + + if language_name == "XML": + parsed_output = ElementTree.fromstring(actual_output) + elif language_name == "JSON": + parsed_output = json.loads(actual_output) + else: + assert False, f"Language name {language_name} not recognized" + + return {"lang": language_name, "obj": parsed_output} diff --git a/tests/step_defs/helpers.py b/tests/step_defs/helpers.py new file mode 100644 index 00000000..e2ea91c9 --- /dev/null +++ b/tests/step_defs/helpers.py @@ -0,0 +1,41 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import os + + + +def does_directory_contain_files(file_list, directory_path): + if not os.path.isdir(directory_path): + return False + + for file in file_list.split("\n"): + fullpath = directory_path + "/" + file + if not os.path.isfile(fullpath): + return False + + return True + + +def parse_should_or_should_not(should_or_should_not): + if should_or_should_not == "should": + return True + elif should_or_should_not == "should not": + return False + else: + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) + + +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], + ] diff --git a/tests/step_defs/then_steps.py b/tests/step_defs/then_steps.py new file mode 100644 index 00000000..4bcf1c56 --- /dev/null +++ b/tests/step_defs/then_steps.py @@ -0,0 +1,331 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import json +import os +import re +import yaml +from xml.etree import ElementTree + +from pytest_bdd import then +from pytest_bdd.parsers import parse + +from jrnl.config import scope_config + +from .helpers import parse_should_or_should_not +from .helpers import does_directory_contain_files +from .helpers import assert_equal_tags_ignoring_order + + +@then("we should get no error") +def should_get_no_error(cli_run): + assert cli_run["status"] == 0, cli_run["status"] + + +@then(parse('the output should match "{regex}"')) +def output_should_match(regex, cli_run): + out = cli_run["stdout"] + matches = re.findall(regex, out) + assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" + + +@then(parse("the output should contain\n{expected_output}")) +@then(parse('the output should contain "{expected_output}"')) +@then('the output should contain ""') +@then(parse("the {which_output_stream} output should contain\n{expected_output}")) +@then(parse('the {which_output_stream} output should contain "{expected_output}"')) +def output_should_contain(expected_output, which_output_stream, cli_run): + assert expected_output + if which_output_stream is None: + assert (expected_output in cli_run["stdout"]) or ( + expected_output in cli_run["stderr"] + ) + + elif which_output_stream == "standard": + assert expected_output in cli_run["stdout"] + + elif which_output_stream == "error": + assert expected_output in cli_run["stderr"] + + else: + assert expected_output in cli_run[which_output_stream] + + +@then(parse("the output should not contain\n{expected_output}")) +@then(parse('the output should not contain "{expected_output}"')) +@then('the output should not contain ""') +def output_should_not_contain(expected_output, cli_run): + assert expected_output not in cli_run["stdout"] + + +@then(parse("the output should be\n{expected_output}")) +@then(parse('the output should be "{expected_output}"')) +@then('the output should be ""') +def output_should_be(expected_output, cli_run): + actual = cli_run["stdout"].strip() + expected = expected_output.strip() + assert expected == actual + + +@then("the output should be empty") +def output_should_be_empty(cli_run): + actual = cli_run["stdout"].strip() + assert actual == "" + + +@then('the output should contain the date ""') +def output_should_contain_date(date, cli_run): + assert date and date in cli_run["stdout"] + + +@then("the output should contain pyproject.toml version") +def output_should_contain_version(cli_run, toml_version): + out = cli_run["stdout"] + assert toml_version in out, toml_version + + +@then(parse('we should see the message "{text}"')) +def should_see_the_message(text, cli_run): + out = cli_run["stderr"] + assert text in out, [text, out] + + +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' + ) +) +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain\n{some_yaml}' + ) +) +@then(parse('the config {should_or_should_not} contain "{some_yaml}"')) +@then(parse("the config {should_or_should_not} contain\n{some_yaml}")) +def config_var(config_data, journal_name, should_or_should_not, some_yaml): + we_should = parse_should_or_should_not(should_or_should_not) + + actual = config_data + if journal_name: + actual = actual["journals"][journal_name] + + expected = yaml.load(some_yaml, Loader=yaml.FullLoader) + + actual_slice = actual + if type(actual) is dict: + actual_slice = {key: actual.get(key, None) for key in expected.keys()} + + if we_should: + assert expected == actual_slice + else: + assert expected != actual_slice + + +@then("we should be prompted for a password") +def password_was_called(cli_run): + assert cli_run["mocks"]["getpass"].called + + +@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): + assert does_directory_contain_files(file_list, cache_dir["path"]) + + +@then(parse("the journal directory should contain\n{file_list}")) +def journal_directory_should_contain(config_data, file_list): + scoped_config = scope_config(config_data, "default") + + assert does_directory_contain_files(file_list, scoped_config["journal"]) + + +@then(parse('journal "{journal_name}" should not exist')) +def journal_directory_should_not_exist(config_data, journal_name): + scoped_config = scope_config(config_data, journal_name) + + assert not does_directory_contain_files( + scoped_config["journal"], "." + ), f'Journal "{journal_name}" does exist' + + +@then(parse("the journal {should_or_should_not} exist")) +def journal_should_not_exist(config_data, should_or_should_not): + scoped_config = scope_config(config_data, "default") + expected_path = scoped_config["journal"] + + contains_files = does_directory_contain_files(expected_path, ".") + + if should_or_should_not == "should": + assert contains_files + elif should_or_should_not == "should not": + assert not contains_files + else: + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) + + +@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], + ] + + +@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(parse("the output should be valid {language_name}")) +def assert_output_is_valid_language(cli_run, language_name): + language_name = language_name.upper() + if language_name == "XML": + xml_tree = ElementTree.fromstring(cli_run["stdout"]) + assert xml_tree, "Invalid XML" + elif language_name == "JSON": + assert json.loads(cli_run["stdout"]), "Invalid JSON" + else: + assert False, f"Language name {language_name} not recognized" + + +@then(parse('"{node_name}" in the parsed output should have {number:d} elements')) +def assert_parsed_output_item_count(node_name, number, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] + + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert node_name in xml_node_names, str(list(xml_node_names)) + + actual_entry_count = len(obj.find(node_name)) + assert actual_entry_count == number, actual_entry_count + + elif lang == "JSON": + my_obj = obj + + for node in node_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert node in my_obj + my_obj = my_obj[node] + + assert len(my_obj) == number, len(my_obj) + + else: + assert False, f"Language name {lang} not recognized" + + +@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) +def assert_output_field_content(field_name, comparison, expected_keys, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] + expected_keys = expected_keys.split("\n") + if len(expected_keys) == 1: + expected_keys = expected_keys[0] + + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert field_name in xml_node_names, str(list(xml_node_names)) + + if field_name == "tags": + actual_tags = set(t.attrib["name"] for t in obj.find("tags")) + assert set(actual_tags) == set(expected_keys), [ + actual_tags, + set(expected_keys), + ] + else: + assert False, "This test only works for tags in XML" + + elif lang == "JSON": + my_obj = obj + + for node in field_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert node in my_obj, [my_obj.keys(), node] + my_obj = my_obj[node] + + if comparison == "be": + if type(my_obj) is str: + assert expected_keys == my_obj, [my_obj, expected_keys] + else: + assert set(expected_keys) == set(my_obj), [ + set(my_obj), + set(expected_keys), + ] + elif comparison == "contain": + if type(my_obj) is str: + assert expected_keys in my_obj, [my_obj, expected_keys] + else: + assert all(elem in my_obj for elem in expected_keys), [ + my_obj, + expected_keys, + ] + else: + assert False, f"Language name {lang} not recognized" + + +@then(parse('there should be {number:d} "{item}" elements')) +def count_elements(number, item, cli_run): + actual_output = cli_run["stdout"] + xml_tree = ElementTree.fromstring(actual_output) + assert len(xml_tree.findall(".//" + item)) == number + + +@then(parse("the editor should have been called")) +@then(parse("the editor should have been called with {num_args} arguments")) +def count_editor_args(num_args, cli_run, editor_state): + assert cli_run["mocks"]["editor"].called + + if isinstance(num_args, int): + assert len(editor_state["command"]) == int(num_args) + + +@then(parse('the editor filename should end with "{suffix}"')) +def editor_filename_suffix(suffix, editor_state): + editor_filename = editor_state["tmpfile"]["name"] + + assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix) + + +@then(parse('the editor file content should {comparison} "{str_value}"')) +@then(parse("the editor file content should {comparison} empty")) +@then(parse("the editor file content should {comparison}\n{str_value}")) +def contains_editor_file(comparison, str_value, editor_state): + content = editor_state["tmpfile"]["content"] + # content = f'\n"""\n{content}\n"""\n' + if comparison == "be": + assert content == str_value + elif comparison == "contain": + assert str_value in content + else: + assert False, f"Comparison '{comparison}' not supported" diff --git a/tests/step_defs/when_steps.py b/tests/step_defs/when_steps.py new file mode 100644 index 00000000..a80d7525 --- /dev/null +++ b/tests/step_defs/when_steps.py @@ -0,0 +1,113 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import os +from contextlib import ExitStack +from unittest.mock import patch + +from pytest_bdd import when +from pytest_bdd.parsers import parse +from pytest_bdd import parsers + +from jrnl.cli import cli +from jrnl.os_compat import split_args + + +@when(parse('we change directory to "{directory_name}"')) +def when_we_change_directory(directory_name): + if not os.path.isdir(directory_name): + os.mkdir(directory_name) + + os.chdir(directory_name) + + +@when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) +@when( + parsers.re( + 'we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"' + ) +) +@when(parse('we run "jrnl" and {input_method} "{user_input}"')) +@when(parse('we run "jrnl {command}"')) +@when('we run "jrnl "') +@when('we run "jrnl"') +def we_run( + command, + config_path, + user_input, + cli_run, + capsys, + password, + cache_dir, + editor, + keyring, + input_method, + mocks, +): + assert input_method in ["", "enter", "pipe"] + is_tty = input_method != "pipe" + + if cache_dir["exists"]: + command = command.format(cache_dir=cache_dir["path"]) + + args = split_args(command) + status = 0 + + if user_input: + user_input = user_input.splitlines() if is_tty else [user_input] + + if password: + password = password.splitlines() + + if not password and user_input: + password = user_input + + with ExitStack() as stack: + + stack.enter_context(patch("sys.argv", ["jrnl"] + args)) + + mock_stdin = stack.enter_context( + patch("sys.stdin.read", side_effect=user_input) + ) + stack.enter_context(patch("sys.stdin.isatty", return_value=is_tty)) + mock_input = stack.enter_context( + patch("builtins.input", side_effect=user_input) + ) + mock_getpass = stack.enter_context( + patch("getpass.getpass", side_effect=password) + ) + + if "datetime" in mocks: + stack.enter_context(mocks["datetime"]) + stack.enter_context(mocks["calendar_parse"]) + + # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) + # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) + + stack.enter_context( + patch("jrnl.install.get_config_path", return_value=config_path) + ) + stack.enter_context( + patch("jrnl.config.get_config_path", return_value=config_path) + ) + mock_editor = stack.enter_context(patch("subprocess.call", side_effect=editor)) + + try: + cli(args) + except StopIteration: + # This happens when input is expected, but don't have any input left + pass + except SystemExit as e: + status = e.code + + captured = capsys.readouterr() + + cli_run["status"] = status + cli_run["stdout"] = captured.out + cli_run["stderr"] = captured.err + cli_run["mocks"] = { + "stdin": mock_stdin, + "input": mock_input, + "getpass": mock_getpass, + "editor": mock_editor, + } From cdad0d62896ff3be496ed4a76e970b9b00334554 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Thu, 24 Jun 2021 09:38:00 -0700 Subject: [PATCH 65/74] Replace pyflakes with flake8 for linting --- Makefile | 2 +- jrnl/DayOneJournal.py | 14 ++--- jrnl/Journal.py | 5 +- jrnl/exception.py | 27 ++++---- poetry.lock | 110 ++++++++++++++++++++++++++------- pyproject.toml | 6 +- tests/step_defs/conftest.py | 14 +++-- tests/step_defs/fixtures.py | 13 ++-- tests/step_defs/given_steps.py | 13 ++-- tests/step_defs/helpers.py | 1 - tests/step_defs/then_steps.py | 6 +- tests/step_defs/when_steps.py | 4 +- tests/unit/test_color.py | 3 +- tests/unit/test_display.py | 6 +- tests/unit/test_export.py | 4 +- tests/unit/test_install.py | 5 +- tests/unit/test_os_compat.py | 3 +- tests/unit/test_override.py | 14 ++--- tests/unit/test_parse_args.py | 4 +- 19 files changed, 164 insertions(+), 90 deletions(-) diff --git a/Makefile b/Makefile index 454702c6..a04a9c86 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ format: ## Format files to match style lint: ## Check style with various tools poetry check - poetry run pyflakes jrnl tests + poetry run pflake8 jrnl tests poetry run black --check --diff . unit: # unit tests diff --git a/jrnl/DayOneJournal.py b/jrnl/DayOneJournal.py index 00271875..01b934e5 100644 --- a/jrnl/DayOneJournal.py +++ b/jrnl/DayOneJournal.py @@ -78,35 +78,35 @@ class DayOne(Journal.Journal): entry.creator_device_agent = dict_entry["Creator"][ "Device Agent" ] - except: + except: # noqa: E722 pass try: entry.creator_generation_date = dict_entry["Creator"][ "Generation Date" ] - except: + except: # noqa: E722 entry.creator_generation_date = date try: entry.creator_host_name = dict_entry["Creator"]["Host Name"] - except: + except: # noqa: E722 pass try: entry.creator_os_agent = dict_entry["Creator"]["OS Agent"] - except: + except: # noqa: E722 pass try: entry.creator_software_agent = dict_entry["Creator"][ "Software Agent" ] - except: + except: # noqa: E722 pass try: entry.location = dict_entry["Location"] - except: + except: # noqa: E722 pass try: entry.weather = dict_entry["Weather"] - except: + except: # noqa: E722 pass self.entries.append(entry) self.sort() diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 181d85c4..6d3c6886 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -220,7 +220,10 @@ class Journal: # If strict mode is on, all tags have to be present in entry tagged = self.search_tags.issubset if strict else self.search_tags.intersection - excluded = lambda tags: len([tag for tag in tags if tag in excluded_tags]) > 0 + + def excluded(tags): + return 0 < len([tag for tag in tags if tag in excluded_tags]) + if contains: contains_lower = contains.casefold() diff --git a/jrnl/exception.py b/jrnl/exception.py index cb6672d7..07bf9023 100644 --- a/jrnl/exception.py +++ b/jrnl/exception.py @@ -22,25 +22,24 @@ class JrnlError(Exception): def _get_error_message(self, **kwargs): error_messages = { - "ConfigDirectoryIsFile": textwrap.dedent( - """ + "ConfigDirectoryIsFile": """ The path to your jrnl configuration directory is a file, not a directory: {config_directory_path} Removing this file will allow jrnl to save its configuration. - """ - ), - "LineWrapTooSmallForDateFormat": textwrap.dedent( - """ - The provided linewrap value of {config_linewrap} is too small by {columns} columns - to display the timestamps in the configured time format for journal {journal}. + """, + "LineWrapTooSmallForDateFormat": """ + The provided linewrap value of {config_linewrap} is too small by + {columns} columns to display the timestamps in the configured time + format for journal {journal}. - You can avoid this error by specifying a linewrap value that is larger by at least {columns} in the configuration file or by using --config-override at the command line - """ - ), + You can avoid this error by specifying a linewrap value that is larger + by at least {columns} in the configuration file or by using + --config-override at the command line + """, } - return error_messages[self.error_type].format(**kwargs) - - pass + msg = error_messages[self.error_type].format(**kwargs) + msg = textwrap.dedent(msg) + return msg diff --git a/poetry.lock b/poetry.lock index 65670545..50b41e3c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -41,7 +41,7 @@ test = ["coverage", "flake8", "pexpect", "wheel"] [[package]] name = "asteval" -version = "0.9.23" +version = "0.9.25" description = "Safe, minimalistic evaluator of python expression using ast module" category = "main" optional = false @@ -176,6 +176,20 @@ category = "dev" optional = false python-versions = ">=3.5" +[[package]] +name = "flake8" +version = "3.9.2" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" + [[package]] name = "ghp-import" version = "2.0.1" @@ -237,7 +251,7 @@ toml = {version = ">=0.10.2", markers = "python_version > \"3.6\""} [[package]] name = "ipython" -version = "7.24.1" +version = "7.25.0" description = "IPython: Productive Interactive Computing" category = "dev" optional = false @@ -381,6 +395,14 @@ python-versions = ">=3.5" [package.dependencies] traitlets = "*" +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "mergedeep" version = "1.3.4" @@ -543,6 +565,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "pycparser" version = "2.20" @@ -575,6 +605,18 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "pyproject-flake8" +version = "0.0.1a2" +description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +flake8 = "*" +toml = "*" + [[package]] name = "pytest" version = "6.2.4" @@ -775,7 +817,7 @@ pytz = "*" [[package]] name = "watchdog" -version = "2.1.2" +version = "2.1.3" description = "Filesystem events monitoring" category = "dev" optional = false @@ -832,7 +874,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = ">=3.7.0, <3.10" -content-hash = "d9a47064f2050860c955a0871b2bd8899c2f24aaf6482f6a742316fd1fd95ba3" +content-hash = "5be8c38e248b64ff4f2eacf253411b57c91352523c40674f1dec6d8c304996c2" [metadata.files] ansiwrap = [ @@ -852,7 +894,7 @@ argcomplete = [ {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, ] asteval = [ - {file = "asteval-0.9.23.tar.gz", hash = "sha256:f5096a924b1d2f147e70327245d95fc8f534dbe94277b6828ce2a8c049d3a438"}, + {file = "asteval-0.9.25.tar.gz", hash = "sha256:bea22b7d8fa16bcba95ebc72052ae5d8ca97114c9959bb47f8b8eebf30e4342f"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -939,6 +981,10 @@ decorator = [ {file = "decorator-5.0.9-py3-none-any.whl", hash = "sha256:6e5c199c16f7a9f0e3a61a4a54b3d27e7dad0dbdde92b944426cb20914376323"}, {file = "decorator-5.0.9.tar.gz", hash = "sha256:72ecfba4320a893c53f9706bebb2d55c270c1e51a28789361aa93e4a21319ed5"}, ] +flake8 = [ + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, +] ghp-import = [ {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, ] @@ -957,8 +1003,8 @@ ipdb = [ {file = "ipdb-0.13.9.tar.gz", hash = "sha256:951bd9a64731c444fd907a5ce268543020086a697f6be08f7cc2c9a752a278c5"}, ] ipython = [ - {file = "ipython-7.24.1-py3-none-any.whl", hash = "sha256:d513e93327cf8657d6467c81f1f894adc125334ffe0e4ddd1abbb1c78d828703"}, - {file = "ipython-7.24.1.tar.gz", hash = "sha256:9bc24a99f5d19721fb8a2d1408908e9c0520a17fff2233ffe82620847f17f1b6"}, + {file = "ipython-7.25.0-py3-none-any.whl", hash = "sha256:aa21412f2b04ad1a652e30564fff6b4de04726ce875eab222c8430edc6db383a"}, + {file = "ipython-7.25.0.tar.gz", hash = "sha256:54bbd1fe3882457aaf28ae060a5ccdef97f212a741754e420028d4ec5c2291dc"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -1027,6 +1073,10 @@ matplotlib-inline = [ {file = "matplotlib-inline-0.1.2.tar.gz", hash = "sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"}, {file = "matplotlib_inline-0.1.2-py3-none-any.whl", hash = "sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811"}, ] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] mergedeep = [ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, @@ -1086,6 +1136,10 @@ py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] +pycodestyle = [ + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, +] pycparser = [ {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, @@ -1102,6 +1156,10 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] +pyproject-flake8 = [ + {file = "pyproject-flake8-0.0.1a2.tar.gz", hash = "sha256:bdeca37f78ecd34bd64a49d3657d53d099f5445831071a31c46e1fe20cd61461"}, + {file = "pyproject_flake8-0.0.1a2-py2.py3-none-any.whl", hash = "sha256:e61ed1dc088e9f9f8a7170967ac4ec135acfef3a59ab9738c7b58cc11f294a7e"}, +] pytest = [ {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, @@ -1264,23 +1322,27 @@ tzlocal = [ {file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"}, ] watchdog = [ - {file = "watchdog-2.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:581e3548159fe7d2a9f377a1fbcb41bdcee46849cca8ab803c7ac2e5e04ec77c"}, - {file = "watchdog-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:edcd9ef3fd460bb8a98eb1fcf99941e9fd9f275f45f1a82cb1359ec92975d647"}, - {file = "watchdog-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d34ce2261f118ecd57eedeef95fc2a495fc4a40b3ed7b3bf0bd7a8ccc1ab4f8f"}, - {file = "watchdog-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668391e6c32742d76e5be5db6bf95c455fa4b3d11e76a77c13b39bccb3a47a72"}, - {file = "watchdog-2.1.2-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6ef9fe57162c4c361692620e1d9167574ba1975ee468b24051ca11c9bba6438e"}, - {file = "watchdog-2.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:58ebb1095ee493008a7789d47dd62e4999505d82be89fc884d473086fccc6ebd"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:91387ee2421f30b75f7ff632c9d48f76648e56bf346a7c805c0a34187a93aab4"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:a6471517315a8541a943c00b45f1d252e36898a3ae963d2d52509b89a50cb2b9"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_i686.whl", hash = "sha256:a42e6d652f820b2b94cd03156c62559a2ea68d476476dfcd77d931e7f1012d4a"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:3d6405681471ebe0beb3aa083998c4870e48b57f8afdb45ea1b5957cc5cf1014"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:598d772beeaf9c98d0df946fbabf0c8365dd95ea46a250c224c725fe0c4730bc"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:4b219d46d89cfa49af1d73175487c14a318a74cb8c5442603fd13c6a5b418c86"}, - {file = "watchdog-2.1.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:188145185c08c73c56f1478ccf1f0f0f85101191439679b35b6b100886ce0b39"}, - {file = "watchdog-2.1.2-py3-none-win32.whl", hash = "sha256:255a32d44bbbe62e52874ff755e2eefe271b150e0ec240ad7718a62a7a7a73c4"}, - {file = "watchdog-2.1.2-py3-none-win_amd64.whl", hash = "sha256:1a62a4671796dc93d1a7262286217d9e75823c63d4c42782912d39a506d30046"}, - {file = "watchdog-2.1.2-py3-none-win_ia64.whl", hash = "sha256:104266a778906ae0e971368d368a65c4cd032a490a9fca5ba0b78c6c7ae11720"}, - {file = "watchdog-2.1.2.tar.gz", hash = "sha256:0237db4d9024859bea27d0efb59fe75eef290833fd988b8ead7a879b0308c2db"}, + {file = "watchdog-2.1.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9628f3f85375a17614a2ab5eac7665f7f7be8b6b0a2a228e6f6a2e91dd4bfe26"}, + {file = "watchdog-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:acc4e2d5be6f140f02ee8590e51c002829e2c33ee199036fcd61311d558d89f4"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85b851237cf3533fabbc034ffcd84d0fa52014b3121454e5f8b86974b531560c"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a12539ecf2478a94e4ba4d13476bb2c7a2e0a2080af2bb37df84d88b1b01358a"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6fe9c8533e955c6589cfea6f3f0a1a95fb16867a211125236c82e1815932b5d7"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d9456f0433845e7153b102fffeb767bde2406b76042f2216838af3b21707894e"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd8c595d5a93abd441ee7c5bb3ff0d7170e79031520d113d6f401d0cf49d7c8f"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0bcfe904c7d404eb6905f7106c54873503b442e8e918cc226e1828f498bdc0ca"}, + {file = "watchdog-2.1.3-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bf84bd94cbaad8f6b9cbaeef43080920f4cb0e61ad90af7106b3de402f5fe127"}, + {file = "watchdog-2.1.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b8ddb2c9f92e0c686ea77341dcb58216fa5ff7d5f992c7278ee8a392a06e86bb"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8805a5f468862daf1e4f4447b0ccf3acaff626eaa57fbb46d7960d1cf09f2e6d"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:3e305ea2757f81d8ebd8559d1a944ed83e3ab1bdf68bcf16ec851b97c08dc035"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_i686.whl", hash = "sha256:431a3ea70b20962e6dee65f0eeecd768cd3085ea613ccb9b53c8969de9f6ebd2"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:e4929ac2aaa2e4f1a30a36751160be391911da463a8799460340901517298b13"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:201cadf0b8c11922f54ec97482f95b2aafca429c4c3a4bb869a14f3c20c32686"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:3a7d242a7963174684206093846537220ee37ba9986b824a326a8bb4ef329a33"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:54e057727dd18bd01a3060dbf5104eb5a495ca26316487e0f32a394fd5fe725a"}, + {file = "watchdog-2.1.3-py3-none-win32.whl", hash = "sha256:b5fc5c127bad6983eecf1ad117ab3418949f18af9c8758bd10158be3647298a9"}, + {file = "watchdog-2.1.3-py3-none-win_amd64.whl", hash = "sha256:44acad6f642996a2b50bb9ce4fb3730dde08f23e79e20cd3d8e2a2076b730381"}, + {file = "watchdog-2.1.3-py3-none-win_ia64.whl", hash = "sha256:0bcdf7b99b56a3ae069866c33d247c9994ffde91b620eaf0306b27e099bd1ae0"}, + {file = "watchdog-2.1.3.tar.gz", hash = "sha256:e5236a8e8602ab6db4b873664c2d356c365ab3cac96fbdec4970ad616415dd45"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, diff --git a/pyproject.toml b/pyproject.toml index 2719b954..36bc3d13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,12 +48,12 @@ behave = "^1.2" mkdocs = "^1.0" black = {version = "^21.5b2",allow-prereleases = true} toml = ">=0.10" -pyflakes = ">=2.2.0" pytest = ">=6.2" pytest-bdd = "^4.0.1" yq = ">=2.11" ipdb = ">=0.13" pytest-clarity = "^0.3.0-alpha.0" +pyproject-flake8 = "^0.0.1-alpha.2" [tool.poetry.scripts] jrnl = 'jrnl.cli:cli' @@ -84,6 +84,10 @@ filterwarnings = [ "ignore:[WinError 5].*" ] +[tool.flake8] +# ignore formatting warnings and errors because we use Black to autoformat +extend-ignore = "E101,E111,E114,E115,E116,E117,E12,E13,E2,E3,E401,E5,E70,W1,W2,W3,W5" + [build-system] requires = ["poetry>=1.1"] build-backend = "poetry.masonry.api" diff --git a/tests/step_defs/conftest.py b/tests/step_defs/conftest.py index d73fcec4..a3021972 100644 --- a/tests/step_defs/conftest.py +++ b/tests/step_defs/conftest.py @@ -1,13 +1,17 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -from jrnl.os_compat import on_windows from pytest import mark -from .fixtures import * -from .given_steps import * -from .when_steps import * -from .then_steps import * +from jrnl.os_compat import on_windows + + +pytest_plugins = [ + "tests.step_defs.fixtures", + "tests.step_defs.given_steps", + "tests.step_defs.when_steps", + "tests.step_defs.then_steps", +] def pytest_bdd_apply_tag(tag, function): diff --git a/tests/step_defs/fixtures.py b/tests/step_defs/fixtures.py index a8e243ae..a93a7e43 100644 --- a/tests/step_defs/fixtures.py +++ b/tests/step_defs/fixtures.py @@ -1,14 +1,14 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -import os from collections import defaultdict -from keyring import backend -from keyring import set_keyring -from keyring import errors +import os from pathlib import Path import tempfile +from keyring import backend +from keyring import errors +from keyring import set_keyring from pytest import fixture import toml @@ -59,7 +59,7 @@ class NoKeyring(backend.KeyringBackend): class FailedKeyring(backend.KeyringBackend): - """ A keyring that cannot be retrieved. """ + """A keyring that cannot be retrieved.""" priority = 2 @@ -192,11 +192,10 @@ def editor(editor_state): Path(tmpfile).touch() with open(tmpfile, editor_state["intent"]["method"]) as f: # Touch the file so jrnl knows it was edited - if editor_state["intent"]["input"] != None: + if editor_state["intent"]["input"] is not None: f.write(editor_state["intent"]["input"]) file_content = f.read() editor_state["tmpfile"]["content"] = file_content return _mock_editor - diff --git a/tests/step_defs/given_steps.py b/tests/step_defs/given_steps.py index 8db8fa1c..649d44c5 100644 --- a/tests/step_defs/given_steps.py +++ b/tests/step_defs/given_steps.py @@ -1,22 +1,23 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html +from datetime import datetime import json import os -from datetime import datetime -from keyring import set_keyring import random -import string import shutil -from unittest.mock import patch +import string from unittest.mock import MagicMock +from unittest.mock import patch from xml.etree import ElementTree +from keyring import set_keyring +from pytest_bdd import given +from pytest_bdd.parsers import parse + from jrnl import __version__ from jrnl.time import __get_pdt_calendar -from pytest_bdd import given -from pytest_bdd.parsers import parse from .fixtures import FailedKeyring from .fixtures import TestKeyring diff --git a/tests/step_defs/helpers.py b/tests/step_defs/helpers.py index e2ea91c9..7d089597 100644 --- a/tests/step_defs/helpers.py +++ b/tests/step_defs/helpers.py @@ -4,7 +4,6 @@ import os - def does_directory_contain_files(file_list, directory_path): if not os.path.isdir(directory_path): return False diff --git a/tests/step_defs/then_steps.py b/tests/step_defs/then_steps.py index 4bcf1c56..b56c203f 100644 --- a/tests/step_defs/then_steps.py +++ b/tests/step_defs/then_steps.py @@ -4,17 +4,17 @@ import json import os import re -import yaml from xml.etree import ElementTree from pytest_bdd import then from pytest_bdd.parsers import parse +import yaml from jrnl.config import scope_config -from .helpers import parse_should_or_should_not -from .helpers import does_directory_contain_files from .helpers import assert_equal_tags_ignoring_order +from .helpers import does_directory_contain_files +from .helpers import parse_should_or_should_not @then("we should get no error") diff --git a/tests/step_defs/when_steps.py b/tests/step_defs/when_steps.py index a80d7525..2e72173b 100644 --- a/tests/step_defs/when_steps.py +++ b/tests/step_defs/when_steps.py @@ -1,13 +1,13 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -import os from contextlib import ExitStack +import os from unittest.mock import patch +from pytest_bdd import parsers from pytest_bdd import when from pytest_bdd.parsers import parse -from pytest_bdd import parsers from jrnl.cli import cli from jrnl.os_compat import split_args diff --git a/tests/unit/test_color.py b/tests/unit/test_color.py index 14dc7938..527b8e89 100644 --- a/tests/unit/test_color.py +++ b/tests/unit/test_color.py @@ -1,7 +1,8 @@ +from colorama import Fore +from colorama import Style import pytest from jrnl.color import colorize -from colorama import Fore, Style @pytest.fixture() diff --git a/tests/unit/test_display.py b/tests/unit/test_display.py index 72a9c451..921d1631 100644 --- a/tests/unit/test_display.py +++ b/tests/unit/test_display.py @@ -1,7 +1,9 @@ import argparse -import jrnl -import pytest from unittest import mock + +import pytest + +import jrnl from jrnl.jrnl import _display_search_results diff --git a/tests/unit/test_export.py b/tests/unit/test_export.py index 0f494f79..8bc1b410 100644 --- a/tests/unit/test_export.py +++ b/tests/unit/test_export.py @@ -1,8 +1,8 @@ +import pytest + from jrnl.exception import JrnlError from jrnl.plugins.fancy_exporter import check_provided_linewrap_viability -import pytest - @pytest.fixture() def datestr(): diff --git a/tests/unit/test_install.py b/tests/unit/test_install.py index 31ec150c..bc36b927 100644 --- a/tests/unit/test_install.py +++ b/tests/unit/test_install.py @@ -1,6 +1,7 @@ -from unittest import mock -import pytest import sys +from unittest import mock + +import pytest @pytest.mark.filterwarnings( diff --git a/tests/unit/test_os_compat.py b/tests/unit/test_os_compat.py index f7c058f1..02d54716 100644 --- a/tests/unit/test_os_compat.py +++ b/tests/unit/test_os_compat.py @@ -1,8 +1,9 @@ from unittest import mock + import pytest -from jrnl.os_compat import on_windows from jrnl.os_compat import on_posix +from jrnl.os_compat import on_windows from jrnl.os_compat import split_args diff --git a/tests/unit/test_override.py b/tests/unit/test_override.py index 32ec0595..d22709f4 100644 --- a/tests/unit/test_override.py +++ b/tests/unit/test_override.py @@ -1,12 +1,10 @@ import pytest -from jrnl.override import ( - apply_overrides, - _recursively_apply, - _get_config_node, - _get_key_and_value_from_pair, - _convert_dots_to_list, -) +from jrnl.override import _convert_dots_to_list +from jrnl.override import _get_config_node +from jrnl.override import _get_key_and_value_from_pair +from jrnl.override import _recursively_apply +from jrnl.override import apply_overrides @pytest.fixture() @@ -56,7 +54,7 @@ def test_recursively_apply(): def test_get_config_node(minimal_config): assert len(minimal_config.keys()) == 4 assert _get_config_node(minimal_config, "editor") == "vim" - assert _get_config_node(minimal_config, "display_format") == None + assert _get_config_node(minimal_config, "display_format") is None def test_get_kv_from_pair(): diff --git a/tests/unit/test_parse_args.py b/tests/unit/test_parse_args.py index 4b140fc1..0725d33d 100644 --- a/tests/unit/test_parse_args.py +++ b/tests/unit/test_parse_args.py @@ -283,10 +283,10 @@ class TestDeserialization: assert cfg["linewrap"] == 23 cfg = make_yaml_valid_dict(["encrypt", "false"]) - assert cfg["encrypt"] == False + assert cfg["encrypt"] is False cfg = make_yaml_valid_dict(["editor", "vi -c startinsert"]) assert cfg["editor"] == "vi -c startinsert" cfg = make_yaml_valid_dict(["highlight", "true"]) - assert cfg["highlight"] == True + assert cfg["highlight"] is True From f99411f2f96620ae9683482c769f3d4f39083c8d Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Jul 2021 14:52:27 -0700 Subject: [PATCH 66/74] move some files around because pytest is being weird --- Makefile | 10 +- poetry.lock | 114 +++--- tests/{ => bdd}/features/build.feature | 0 tests/{ => bdd}/features/core.feature | 0 tests/{ => bdd}/features/datetime.feature | 0 tests/{ => bdd}/features/delete.feature | 0 tests/{ => bdd}/features/encrypt.feature | 0 tests/{ => bdd}/features/file_storage.feature | 0 tests/{ => bdd}/features/format.feature | 0 tests/{ => bdd}/features/import.feature | 0 .../features/multiple_journals.feature | 0 tests/{ => bdd}/features/password.feature | 0 tests/{ => bdd}/features/search.feature | 0 tests/{ => bdd}/features/star.feature | 0 tests/{ => bdd}/features/tag.feature | 0 tests/{ => bdd}/features/upgrade.feature | 0 tests/{ => bdd}/features/write.feature | 0 tests/bdd/test_features.py | 17 + tests/{step_defs => }/conftest.py | 8 +- tests/step_defs/__init__.py | 3 - tests/step_defs/fixtures.py | 201 ----------- tests/step_defs/given_steps.py | 134 ------- tests/step_defs/helpers.py | 40 --- tests/step_defs/test_features.py | 17 - tests/step_defs/then_steps.py | 331 ------------------ tests/step_defs/when_steps.py | 113 ------ 26 files changed, 81 insertions(+), 907 deletions(-) rename tests/{ => bdd}/features/build.feature (100%) rename tests/{ => bdd}/features/core.feature (100%) rename tests/{ => bdd}/features/datetime.feature (100%) rename tests/{ => bdd}/features/delete.feature (100%) rename tests/{ => bdd}/features/encrypt.feature (100%) rename tests/{ => bdd}/features/file_storage.feature (100%) rename tests/{ => bdd}/features/format.feature (100%) rename tests/{ => bdd}/features/import.feature (100%) rename tests/{ => bdd}/features/multiple_journals.feature (100%) rename tests/{ => bdd}/features/password.feature (100%) rename tests/{ => bdd}/features/search.feature (100%) rename tests/{ => bdd}/features/star.feature (100%) rename tests/{ => bdd}/features/tag.feature (100%) rename tests/{ => bdd}/features/upgrade.feature (100%) rename tests/{ => bdd}/features/write.feature (100%) create mode 100644 tests/bdd/test_features.py rename tests/{step_defs => }/conftest.py (81%) delete mode 100644 tests/step_defs/__init__.py delete mode 100644 tests/step_defs/fixtures.py delete mode 100644 tests/step_defs/given_steps.py delete mode 100644 tests/step_defs/helpers.py delete mode 100644 tests/step_defs/test_features.py delete mode 100644 tests/step_defs/then_steps.py delete mode 100644 tests/step_defs/when_steps.py diff --git a/Makefile b/Makefile index a04a9c86..a4494ee3 100644 --- a/Makefile +++ b/Makefile @@ -24,13 +24,13 @@ lint: ## Check style with various tools unit: # unit tests poetry run pytest tests/unit -e2e: # end-to-end tests - poetry run pytest tests/step_defs --gherkin-terminal-reporter --tb=native --diff-type=unified +bdd: # bdd tests + poetry run pytest tests/bdd --gherkin-terminal-reporter --tb=native --diff-type=unified -e2e-debug: # end-to-end tests - poetry run pytest tests/step_defs --gherkin-terminal-reporter --tb=native --diff-type=unified -x -vv +bdd-debug: # bdd tests + poetry run pytest tests/bdd --gherkin-terminal-reporter --tb=native --diff-type=unified -x -vv -test: lint unit e2e ## Run unit tests and behave tests +test: lint unit bdd ## Run unit tests and behave tests build: poetry build diff --git a/poetry.lock b/poetry.lock index 50b41e3c..2d1a8ea2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -214,7 +214,7 @@ python-versions = "*" [[package]] name = "importlib-metadata" -version = "4.5.0" +version = "4.6.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -226,7 +226,8 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -444,11 +445,11 @@ python-versions = "*" [[package]] name = "packaging" -version = "20.9" +version = "21.0" description = "Core utilities for Python packages" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2" @@ -641,11 +642,11 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-bdd" -version = "4.0.2" +version = "4.1.0" description = "BDD for pytest" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [package.dependencies] glob2 = "*" @@ -654,7 +655,6 @@ parse = "*" parse-type = "*" py = "*" pytest = ">=4.3" -six = ">=1.9.0" [[package]] name = "pytest-clarity" @@ -724,7 +724,7 @@ pyyaml = "*" [[package]] name = "regex" -version = "2021.4.4" +version = "2021.7.1" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -861,7 +861,7 @@ test = ["coverage", "flake8", "wheel"] [[package]] name = "zipp" -version = "3.4.1" +version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false @@ -869,7 +869,7 @@ python-versions = ">=3.6" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" @@ -992,8 +992,8 @@ glob2 = [ {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, - {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, + {file = "importlib_metadata-4.6.0-py3-none-any.whl", hash = "sha256:c6513572926a96458f8c8f725bf0e00108fba0c9583ade9bd15b869c9d726e33"}, + {file = "importlib_metadata-4.6.0.tar.gz", hash = "sha256:4a5611fea3768d3d967c447ab4e93f567d95db92225b43b7b238dbfb855d70bb"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1090,8 +1090,8 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ - {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, - {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] parse = [ {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, @@ -1165,8 +1165,8 @@ pytest = [ {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, ] pytest-bdd = [ - {file = "pytest-bdd-4.0.2.tar.gz", hash = "sha256:982489f2f036c7561affe4eeb5b392a37e1ace2a9f260cad747b1c8119e63cfd"}, - {file = "pytest_bdd-4.0.2-py2.py3-none-any.whl", hash = "sha256:74ea5a147ea558c99ae83d838e6acbe5c9e6843884a958f8231615d96838733d"}, + {file = "pytest-bdd-4.1.0.tar.gz", hash = "sha256:304cd2b09923b838d0c2f08331d1f4236a14ef3594efa94e3bdae0f384d3fa5d"}, + {file = "pytest_bdd-4.1.0-py3-none-any.whl", hash = "sha256:7c5221680cec9a97630e1fae6132f4a97c2f86a90914206ee06a55ae1a409fe5"}, ] pytest-clarity = [ {file = "pytest-clarity-0.3.0a0.tar.gz", hash = "sha256:5cc99e3d9b7969dfe17e5f6072d45a917c59d363b679686d3c958a1ded2e4dcf"}, @@ -1215,47 +1215,43 @@ pyyaml-env-tag = [ {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, ] regex = [ - {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"}, - {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"}, - {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"}, - {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"}, - {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"}, - {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"}, - {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"}, - {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"}, - {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"}, - {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"}, - {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"}, - {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"}, - {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"}, - {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"}, - {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"}, - {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"}, - {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"}, + {file = "regex-2021.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:494d0172774dc0beeea984b94c95389143db029575f7ca908edd74469321ea99"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8cf6728f89b071bd3ab37cb8a0e306f4de897553a0ed07442015ee65fbf53d62"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1806370b2bef4d4193eebe8ee59a9fd7547836a34917b7badbe6561a8594d9cb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0cf2651a8804f6325747c7e55e3be0f90ee2848e25d6b817aa2728d263f9abb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:268fe9dd1deb4a30c8593cabd63f7a241dfdc5bd9dd0233906c718db22cdd49a"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:7743798dfb573d006f1143d745bf17efad39775a5190b347da5d83079646be56"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0e46c1191b2eb293a6912269ed08b4512e7e241bbf591f97e527492e04c77e93"}, + {file = "regex-2021.7.1-cp36-cp36m-win32.whl", hash = "sha256:b1dbeef938281f240347d50f28ae53c4b046a23389cd1fc4acec5ea0eae646a1"}, + {file = "regex-2021.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6c72ebb72e64e9bd195cb35a9b9bbfb955fd953b295255b8ae3e4ad4a146b615"}, + {file = "regex-2021.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf819c5b77ff44accc9a24e31f1f7ceaaf6c960816913ed3ef8443b9d20d81b6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e80d2851109e56420b71f9702ad1646e2f0364528adbf6af85527bc61e49f394"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b6a3f600d6aff97e3f28c34192c9ed93fee293bd96ef327b64adb51a74b2f6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ed77b97896312bc2deafe137ca2626e8b63808f5bedb944f73665c68093688a7"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a548bb51c4476332ce4139df8e637386730f79a92652a907d12c696b6252b64d"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:210c359e6ee5b83f7d8c529ba3c75ba405481d50f35a420609b0db827e2e3bb5"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1d386402ae7f3c9b107ae5863f7ecccb0167762c82a687ae6526b040feaa5ac6"}, + {file = "regex-2021.7.1-cp37-cp37m-win32.whl", hash = "sha256:5049d00dbb78f9d166d1c704e93934d42cce0570842bb1a61695123d6b01de09"}, + {file = "regex-2021.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:361be4d311ac995a8c7ad577025a3ae3a538531b1f2cf32efd8b7e5d33a13e5a"}, + {file = "regex-2021.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f32f47fb22c988c0b35756024b61d156e5c4011cb8004aa53d93b03323c45657"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b024ee43ee6b310fad5acaee23e6485b21468718cb792a9d1693eecacc3f0b7e"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b092754c06852e8a8b022004aff56c24b06310189186805800d09313c37ce1f8"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a8a5826d8a1b64e2ff9af488cc179e1a4d0f144d11ce486a9f34ea38ccedf4ef"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:444723ebaeb7fa8125f29c01a31101a3854ac3de293e317944022ae5effa53a4"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:fdad3122b69cdabdb3da4c2a4107875913ac78dab0117fc73f988ad589c66b66"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4b1999ef60c45357598935c12508abf56edbbb9c380df6f336de38a6c3a294ae"}, + {file = "regex-2021.7.1-cp38-cp38-win32.whl", hash = "sha256:e07e92935040c67f49571779d115ecb3e727016d42fb36ee0d8757db4ca12ee0"}, + {file = "regex-2021.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:6b8b629f93246e507287ee07e26744beaffb4c56ed520576deac8b615bd76012"}, + {file = "regex-2021.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56bef6b414949e2c9acf96cb5d78de8b529c7b99752619494e78dc76f99fd005"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:78a2a885345a2d60b5e68099e877757d5ed12e46ba1e87507175f14f80892af3"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3f7a92e60930f8fca2623d9e326c173b7cf2c8b7e4fdcf984b75a1d2fb08114d"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4fc86b729ab88fe8ac3ec92287df253c64aa71560d76da5acd8a2e245839c629"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:59845101de68fd5d3a1145df9ea022e85ecd1b49300ea68307ad4302320f6f61"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ce269e903b00d1ab4746793e9c50a57eec5d5388681abef074d7b9a65748fca5"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c11f2fca544b5e30a0e813023196a63b1cb9869106ef9a26e9dae28bce3e4e26"}, + {file = "regex-2021.7.1-cp39-cp39-win32.whl", hash = "sha256:1ccbd41dbee3a31e18938096510b7d4ee53aa9fce2ee3dcc8ec82ae264f6acfd"}, + {file = "regex-2021.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:18040755606b0c21281493ec309214bd61e41a170509e5014f41d6a5a586e161"}, + {file = "regex-2021.7.1.tar.gz", hash = "sha256:849802379a660206277675aa5a5c327f5c910c690649535863ddf329b0ba8c87"}, ] secretstorage = [ {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, @@ -1357,6 +1353,6 @@ yq = [ {file = "yq-2.12.2.tar.gz", hash = "sha256:2f156d0724b61487ac8752ed4eaa702a5737b804d5afa46fa55866951cd106d2"}, ] zipp = [ - {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, - {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, ] diff --git a/tests/features/build.feature b/tests/bdd/features/build.feature similarity index 100% rename from tests/features/build.feature rename to tests/bdd/features/build.feature diff --git a/tests/features/core.feature b/tests/bdd/features/core.feature similarity index 100% rename from tests/features/core.feature rename to tests/bdd/features/core.feature diff --git a/tests/features/datetime.feature b/tests/bdd/features/datetime.feature similarity index 100% rename from tests/features/datetime.feature rename to tests/bdd/features/datetime.feature diff --git a/tests/features/delete.feature b/tests/bdd/features/delete.feature similarity index 100% rename from tests/features/delete.feature rename to tests/bdd/features/delete.feature diff --git a/tests/features/encrypt.feature b/tests/bdd/features/encrypt.feature similarity index 100% rename from tests/features/encrypt.feature rename to tests/bdd/features/encrypt.feature diff --git a/tests/features/file_storage.feature b/tests/bdd/features/file_storage.feature similarity index 100% rename from tests/features/file_storage.feature rename to tests/bdd/features/file_storage.feature diff --git a/tests/features/format.feature b/tests/bdd/features/format.feature similarity index 100% rename from tests/features/format.feature rename to tests/bdd/features/format.feature diff --git a/tests/features/import.feature b/tests/bdd/features/import.feature similarity index 100% rename from tests/features/import.feature rename to tests/bdd/features/import.feature diff --git a/tests/features/multiple_journals.feature b/tests/bdd/features/multiple_journals.feature similarity index 100% rename from tests/features/multiple_journals.feature rename to tests/bdd/features/multiple_journals.feature diff --git a/tests/features/password.feature b/tests/bdd/features/password.feature similarity index 100% rename from tests/features/password.feature rename to tests/bdd/features/password.feature diff --git a/tests/features/search.feature b/tests/bdd/features/search.feature similarity index 100% rename from tests/features/search.feature rename to tests/bdd/features/search.feature diff --git a/tests/features/star.feature b/tests/bdd/features/star.feature similarity index 100% rename from tests/features/star.feature rename to tests/bdd/features/star.feature diff --git a/tests/features/tag.feature b/tests/bdd/features/tag.feature similarity index 100% rename from tests/features/tag.feature rename to tests/bdd/features/tag.feature diff --git a/tests/features/upgrade.feature b/tests/bdd/features/upgrade.feature similarity index 100% rename from tests/features/upgrade.feature rename to tests/bdd/features/upgrade.feature diff --git a/tests/features/write.feature b/tests/bdd/features/write.feature similarity index 100% rename from tests/features/write.feature rename to tests/bdd/features/write.feature diff --git a/tests/bdd/test_features.py b/tests/bdd/test_features.py new file mode 100644 index 00000000..b824df39 --- /dev/null +++ b/tests/bdd/test_features.py @@ -0,0 +1,17 @@ +from pytest_bdd import scenarios + +scenarios("features/build.feature") +scenarios("features/core.feature") +scenarios("features/datetime.feature") +scenarios("features/delete.feature") +scenarios("features/encrypt.feature") +scenarios("features/file_storage.feature") +scenarios("features/format.feature") +scenarios("features/import.feature") +scenarios("features/multiple_journals.feature") +scenarios("features/password.feature") +scenarios("features/search.feature") +scenarios("features/star.feature") +scenarios("features/tag.feature") +scenarios("features/upgrade.feature") +scenarios("features/write.feature") diff --git a/tests/step_defs/conftest.py b/tests/conftest.py similarity index 81% rename from tests/step_defs/conftest.py rename to tests/conftest.py index a3021972..277e2602 100644 --- a/tests/step_defs/conftest.py +++ b/tests/conftest.py @@ -7,10 +7,10 @@ from jrnl.os_compat import on_windows pytest_plugins = [ - "tests.step_defs.fixtures", - "tests.step_defs.given_steps", - "tests.step_defs.when_steps", - "tests.step_defs.then_steps", + "tests.lib.fixtures", + "tests.lib.given_steps", + "tests.lib.when_steps", + "tests.lib.then_steps", ] diff --git a/tests/step_defs/__init__.py b/tests/step_defs/__init__.py deleted file mode 100644 index 46468510..00000000 --- a/tests/step_defs/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys - -sys.path.append("..") diff --git a/tests/step_defs/fixtures.py b/tests/step_defs/fixtures.py deleted file mode 100644 index a93a7e43..00000000 --- a/tests/step_defs/fixtures.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (C) 2012-2021 jrnl contributors -# License: https://www.gnu.org/licenses/gpl-3.0.html - -from collections import defaultdict -import os -from pathlib import Path -import tempfile - -from keyring import backend -from keyring import errors -from keyring import set_keyring -from pytest import fixture -import toml - -from jrnl.config import load_config - - -# --- Keyring --- # -@fixture -def keyring(): - set_keyring(NoKeyring()) - - -@fixture -def keyring_type(): - return "default" - - -class TestKeyring(backend.KeyringBackend): - """A test keyring that just stores its values in a hash""" - - priority = 1 - keys = defaultdict(dict) - - def set_password(self, servicename, username, password): - self.keys[servicename][username] = password - - def get_password(self, servicename, username): - return self.keys[servicename].get(username) - - def delete_password(self, servicename, username): - self.keys[servicename][username] = None - - -class NoKeyring(backend.KeyringBackend): - """A keyring that simulated an environment with no keyring backend.""" - - priority = 2 - keys = defaultdict(dict) - - def set_password(self, servicename, username, password): - raise errors.NoKeyringError - - def get_password(self, servicename, username): - raise errors.NoKeyringError - - def delete_password(self, servicename, username): - raise errors.NoKeyringError - - -class FailedKeyring(backend.KeyringBackend): - """A keyring that cannot be retrieved.""" - - priority = 2 - - def set_password(self, servicename, username, password): - raise errors.KeyringError - - def get_password(self, servicename, username): - raise errors.KeyringError - - def delete_password(self, servicename, username): - raise errors.KeyringError - - -# ----- Misc ----- # -@fixture -def cli_run(): - return {"status": 0, "stdout": None, "stderr": None} - - -@fixture -def mocks(): - return dict() - - -@fixture -def temp_dir(): - return tempfile.TemporaryDirectory() - - -@fixture -def working_dir(request): - return os.path.join(request.config.rootpath, "tests") - - -@fixture -def config_path(temp_dir): - os.chdir(temp_dir.name) - return temp_dir.name + "/jrnl.yaml" - - -@fixture -def toml_version(working_dir): - pyproject = os.path.join(working_dir, "..", "pyproject.toml") - pyproject_contents = toml.load(pyproject) - return pyproject_contents["tool"]["poetry"]["version"] - - -@fixture -def password(): - return "" - - -@fixture -def input_method(): - return "" - - -@fixture -def cache_dir(): - return {"exists": False, "path": ""} - - -@fixture -def str_value(): - return "" - - -@fixture -def command(): - return "" - - -@fixture -def should_not(): - return False - - -@fixture -def user_input(): - return "" - - -@fixture -def config_data(config_path): - return load_config(config_path) - - -@fixture -def journal_name(): - return None - - -@fixture -def which_output_stream(): - return None - - -@fixture -def editor_input(): - return None - - -@fixture -def num_args(): - return None - - -@fixture -def parsed_output(): - return {"lang": None, "obj": None} - - -@fixture -def editor_state(): - return { - "command": "", - "intent": {"method": "r", "input": None}, - "tmpfile": {"name": None, "content": None}, - } - - -@fixture -def editor(editor_state): - def _mock_editor(editor_command): - tmpfile = editor_command[-1] - - editor_state["command"] = editor_command - editor_state["tmpfile"]["name"] = tmpfile - - Path(tmpfile).touch() - with open(tmpfile, editor_state["intent"]["method"]) as f: - # Touch the file so jrnl knows it was edited - if editor_state["intent"]["input"] is not None: - f.write(editor_state["intent"]["input"]) - - file_content = f.read() - editor_state["tmpfile"]["content"] = file_content - - return _mock_editor diff --git a/tests/step_defs/given_steps.py b/tests/step_defs/given_steps.py deleted file mode 100644 index 649d44c5..00000000 --- a/tests/step_defs/given_steps.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (C) 2012-2021 jrnl contributors -# License: https://www.gnu.org/licenses/gpl-3.0.html - -from datetime import datetime -import json -import os -import random -import shutil -import string -from unittest.mock import MagicMock -from unittest.mock import patch -from xml.etree import ElementTree - -from keyring import set_keyring -from pytest_bdd import given -from pytest_bdd.parsers import parse - -from jrnl import __version__ -from jrnl.time import __get_pdt_calendar - -from .fixtures import FailedKeyring -from .fixtures import TestKeyring - - -@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) -@given(parse("we {editor_method} nothing to the editor if opened")) -def we_enter_editor(editor_method, editor_input, editor_state): - file_method = editor_state["intent"]["method"] - if editor_method == "write": - file_method = "w+" - elif editor_method == "append": - file_method = "a+" - else: - assert False, f"Method '{editor_method}' not supported" - - editor_state["intent"] = {"method": file_method, "input": editor_input} - - -@given(parse('now is ""')) -@given(parse('now is "{date_str}"')) -def now_is_str(date_str, mocks): - class DatetimeMagicMock(MagicMock): - # needed because jrnl does some reflection on datetime - def __instancecheck__(self, subclass): - return isinstance(subclass, datetime) - - def mocked_now(tz=None): - now = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") - - if tz: - time_zone = datetime.utcnow().astimezone().tzinfo - now = now.replace(tzinfo=time_zone) - - return now - - # jrnl uses two different classes to parse dates, so both must be mocked - datetime_mock = DatetimeMagicMock(wraps=datetime) - datetime_mock.now.side_effect = mocked_now - - pdt = __get_pdt_calendar() - calendar_mock = MagicMock(wraps=pdt) - calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( - date_str_input, mocked_now() - ) - - mocks["datetime"] = patch("datetime.datetime", new=datetime_mock) - mocks["calendar_parse"] = patch( - "jrnl.time.__get_pdt_calendar", return_value=calendar_mock - ) - - -@given("we have a keyring", target_fixture="keyring") -@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") -def we_have_type_of_keyring(keyring_type): - if keyring_type == "failed": - set_keyring(FailedKeyring()) - else: - set_keyring(TestKeyring()) - - -@given(parse('we use the config "{config_file}"'), target_fixture="config_path") -@given('we use the config ""', target_fixture="config_path") -def we_use_the_config(config_file, temp_dir, working_dir): - # Move into temp dir as cwd - os.chdir(temp_dir.name) - - # Copy the config file over - config_source = os.path.join(working_dir, "data", "configs", config_file) - config_dest = os.path.join(temp_dir.name, config_file) - shutil.copy2(config_source, config_dest) - - # @todo make this only copy some journals over - # Copy all of the journals over - journal_source = os.path.join(working_dir, "data", "journals") - journal_dest = os.path.join(temp_dir.name, "features", "journals") - shutil.copytree(journal_source, journal_dest) - - # @todo get rid of this by using default config values - # merge in version number - if config_file.endswith("yaml") and os.path.exists(config_dest): - # Add jrnl version to file for 2.x journals - with open(config_dest, "a") as cf: - cf.write("version: {}".format(__version__)) - - return config_dest - - -@given(parse('we use the password "{pw}" if prompted'), target_fixture="password") -def use_password_forever(pw): - return pw - - -@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} - - -@given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") -def parse_output_as_language(cli_run, language_name): - language_name = language_name.upper() - actual_output = cli_run["stdout"] - - if language_name == "XML": - parsed_output = ElementTree.fromstring(actual_output) - elif language_name == "JSON": - parsed_output = json.loads(actual_output) - else: - assert False, f"Language name {language_name} not recognized" - - return {"lang": language_name, "obj": parsed_output} diff --git a/tests/step_defs/helpers.py b/tests/step_defs/helpers.py deleted file mode 100644 index 7d089597..00000000 --- a/tests/step_defs/helpers.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2012-2021 jrnl contributors -# License: https://www.gnu.org/licenses/gpl-3.0.html - -import os - - -def does_directory_contain_files(file_list, directory_path): - if not os.path.isdir(directory_path): - return False - - for file in file_list.split("\n"): - fullpath = directory_path + "/" + file - if not os.path.isfile(fullpath): - return False - - return True - - -def parse_should_or_should_not(should_or_should_not): - if should_or_should_not == "should": - return True - elif should_or_should_not == "should not": - return False - else: - raise Exception( - "should_or_should_not valid values are 'should' or 'should not'" - ) - - -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], - ] diff --git a/tests/step_defs/test_features.py b/tests/step_defs/test_features.py deleted file mode 100644 index 4c8d5ef9..00000000 --- a/tests/step_defs/test_features.py +++ /dev/null @@ -1,17 +0,0 @@ -from pytest_bdd import scenarios - -scenarios("../features/build.feature") -scenarios("../features/core.feature") -scenarios("../features/datetime.feature") -scenarios("../features/delete.feature") -scenarios("../features/encrypt.feature") -scenarios("../features/file_storage.feature") -scenarios("../features/format.feature") -scenarios("../features/import.feature") -scenarios("../features/multiple_journals.feature") -scenarios("../features/password.feature") -scenarios("../features/search.feature") -scenarios("../features/star.feature") -scenarios("../features/tag.feature") -scenarios("../features/upgrade.feature") -scenarios("../features/write.feature") diff --git a/tests/step_defs/then_steps.py b/tests/step_defs/then_steps.py deleted file mode 100644 index b56c203f..00000000 --- a/tests/step_defs/then_steps.py +++ /dev/null @@ -1,331 +0,0 @@ -# Copyright (C) 2012-2021 jrnl contributors -# License: https://www.gnu.org/licenses/gpl-3.0.html - -import json -import os -import re -from xml.etree import ElementTree - -from pytest_bdd import then -from pytest_bdd.parsers import parse -import yaml - -from jrnl.config import scope_config - -from .helpers import assert_equal_tags_ignoring_order -from .helpers import does_directory_contain_files -from .helpers import parse_should_or_should_not - - -@then("we should get no error") -def should_get_no_error(cli_run): - assert cli_run["status"] == 0, cli_run["status"] - - -@then(parse('the output should match "{regex}"')) -def output_should_match(regex, cli_run): - out = cli_run["stdout"] - matches = re.findall(regex, out) - assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" - - -@then(parse("the output should contain\n{expected_output}")) -@then(parse('the output should contain "{expected_output}"')) -@then('the output should contain ""') -@then(parse("the {which_output_stream} output should contain\n{expected_output}")) -@then(parse('the {which_output_stream} output should contain "{expected_output}"')) -def output_should_contain(expected_output, which_output_stream, cli_run): - assert expected_output - if which_output_stream is None: - assert (expected_output in cli_run["stdout"]) or ( - expected_output in cli_run["stderr"] - ) - - elif which_output_stream == "standard": - assert expected_output in cli_run["stdout"] - - elif which_output_stream == "error": - assert expected_output in cli_run["stderr"] - - else: - assert expected_output in cli_run[which_output_stream] - - -@then(parse("the output should not contain\n{expected_output}")) -@then(parse('the output should not contain "{expected_output}"')) -@then('the output should not contain ""') -def output_should_not_contain(expected_output, cli_run): - assert expected_output not in cli_run["stdout"] - - -@then(parse("the output should be\n{expected_output}")) -@then(parse('the output should be "{expected_output}"')) -@then('the output should be ""') -def output_should_be(expected_output, cli_run): - actual = cli_run["stdout"].strip() - expected = expected_output.strip() - assert expected == actual - - -@then("the output should be empty") -def output_should_be_empty(cli_run): - actual = cli_run["stdout"].strip() - assert actual == "" - - -@then('the output should contain the date ""') -def output_should_contain_date(date, cli_run): - assert date and date in cli_run["stdout"] - - -@then("the output should contain pyproject.toml version") -def output_should_contain_version(cli_run, toml_version): - out = cli_run["stdout"] - assert toml_version in out, toml_version - - -@then(parse('we should see the message "{text}"')) -def should_see_the_message(text, cli_run): - out = cli_run["stderr"] - assert text in out, [text, out] - - -@then( - parse( - 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' - ) -) -@then( - parse( - 'the config for journal "{journal_name}" {should_or_should_not} contain\n{some_yaml}' - ) -) -@then(parse('the config {should_or_should_not} contain "{some_yaml}"')) -@then(parse("the config {should_or_should_not} contain\n{some_yaml}")) -def config_var(config_data, journal_name, should_or_should_not, some_yaml): - we_should = parse_should_or_should_not(should_or_should_not) - - actual = config_data - if journal_name: - actual = actual["journals"][journal_name] - - expected = yaml.load(some_yaml, Loader=yaml.FullLoader) - - actual_slice = actual - if type(actual) is dict: - actual_slice = {key: actual.get(key, None) for key in expected.keys()} - - if we_should: - assert expected == actual_slice - else: - assert expected != actual_slice - - -@then("we should be prompted for a password") -def password_was_called(cli_run): - assert cli_run["mocks"]["getpass"].called - - -@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): - assert does_directory_contain_files(file_list, cache_dir["path"]) - - -@then(parse("the journal directory should contain\n{file_list}")) -def journal_directory_should_contain(config_data, file_list): - scoped_config = scope_config(config_data, "default") - - assert does_directory_contain_files(file_list, scoped_config["journal"]) - - -@then(parse('journal "{journal_name}" should not exist')) -def journal_directory_should_not_exist(config_data, journal_name): - scoped_config = scope_config(config_data, journal_name) - - assert not does_directory_contain_files( - scoped_config["journal"], "." - ), f'Journal "{journal_name}" does exist' - - -@then(parse("the journal {should_or_should_not} exist")) -def journal_should_not_exist(config_data, should_or_should_not): - scoped_config = scope_config(config_data, "default") - expected_path = scoped_config["journal"] - - contains_files = does_directory_contain_files(expected_path, ".") - - if should_or_should_not == "should": - assert contains_files - elif should_or_should_not == "should not": - assert not contains_files - else: - raise Exception( - "should_or_should_not valid values are 'should' or 'should not'" - ) - - -@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], - ] - - -@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(parse("the output should be valid {language_name}")) -def assert_output_is_valid_language(cli_run, language_name): - language_name = language_name.upper() - if language_name == "XML": - xml_tree = ElementTree.fromstring(cli_run["stdout"]) - assert xml_tree, "Invalid XML" - elif language_name == "JSON": - assert json.loads(cli_run["stdout"]), "Invalid JSON" - else: - assert False, f"Language name {language_name} not recognized" - - -@then(parse('"{node_name}" in the parsed output should have {number:d} elements')) -def assert_parsed_output_item_count(node_name, number, parsed_output): - lang = parsed_output["lang"] - obj = parsed_output["obj"] - - if lang == "XML": - xml_node_names = (node.tag for node in obj) - assert node_name in xml_node_names, str(list(xml_node_names)) - - actual_entry_count = len(obj.find(node_name)) - assert actual_entry_count == number, actual_entry_count - - elif lang == "JSON": - my_obj = obj - - for node in node_name.split("."): - try: - my_obj = my_obj[int(node)] - except ValueError: - assert node in my_obj - my_obj = my_obj[node] - - assert len(my_obj) == number, len(my_obj) - - else: - assert False, f"Language name {lang} not recognized" - - -@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) -def assert_output_field_content(field_name, comparison, expected_keys, parsed_output): - lang = parsed_output["lang"] - obj = parsed_output["obj"] - expected_keys = expected_keys.split("\n") - if len(expected_keys) == 1: - expected_keys = expected_keys[0] - - if lang == "XML": - xml_node_names = (node.tag for node in obj) - assert field_name in xml_node_names, str(list(xml_node_names)) - - if field_name == "tags": - actual_tags = set(t.attrib["name"] for t in obj.find("tags")) - assert set(actual_tags) == set(expected_keys), [ - actual_tags, - set(expected_keys), - ] - else: - assert False, "This test only works for tags in XML" - - elif lang == "JSON": - my_obj = obj - - for node in field_name.split("."): - try: - my_obj = my_obj[int(node)] - except ValueError: - assert node in my_obj, [my_obj.keys(), node] - my_obj = my_obj[node] - - if comparison == "be": - if type(my_obj) is str: - assert expected_keys == my_obj, [my_obj, expected_keys] - else: - assert set(expected_keys) == set(my_obj), [ - set(my_obj), - set(expected_keys), - ] - elif comparison == "contain": - if type(my_obj) is str: - assert expected_keys in my_obj, [my_obj, expected_keys] - else: - assert all(elem in my_obj for elem in expected_keys), [ - my_obj, - expected_keys, - ] - else: - assert False, f"Language name {lang} not recognized" - - -@then(parse('there should be {number:d} "{item}" elements')) -def count_elements(number, item, cli_run): - actual_output = cli_run["stdout"] - xml_tree = ElementTree.fromstring(actual_output) - assert len(xml_tree.findall(".//" + item)) == number - - -@then(parse("the editor should have been called")) -@then(parse("the editor should have been called with {num_args} arguments")) -def count_editor_args(num_args, cli_run, editor_state): - assert cli_run["mocks"]["editor"].called - - if isinstance(num_args, int): - assert len(editor_state["command"]) == int(num_args) - - -@then(parse('the editor filename should end with "{suffix}"')) -def editor_filename_suffix(suffix, editor_state): - editor_filename = editor_state["tmpfile"]["name"] - - assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix) - - -@then(parse('the editor file content should {comparison} "{str_value}"')) -@then(parse("the editor file content should {comparison} empty")) -@then(parse("the editor file content should {comparison}\n{str_value}")) -def contains_editor_file(comparison, str_value, editor_state): - content = editor_state["tmpfile"]["content"] - # content = f'\n"""\n{content}\n"""\n' - if comparison == "be": - assert content == str_value - elif comparison == "contain": - assert str_value in content - else: - assert False, f"Comparison '{comparison}' not supported" diff --git a/tests/step_defs/when_steps.py b/tests/step_defs/when_steps.py deleted file mode 100644 index 2e72173b..00000000 --- a/tests/step_defs/when_steps.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (C) 2012-2021 jrnl contributors -# License: https://www.gnu.org/licenses/gpl-3.0.html - -from contextlib import ExitStack -import os -from unittest.mock import patch - -from pytest_bdd import parsers -from pytest_bdd import when -from pytest_bdd.parsers import parse - -from jrnl.cli import cli -from jrnl.os_compat import split_args - - -@when(parse('we change directory to "{directory_name}"')) -def when_we_change_directory(directory_name): - if not os.path.isdir(directory_name): - os.mkdir(directory_name) - - os.chdir(directory_name) - - -@when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) -@when( - parsers.re( - 'we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"' - ) -) -@when(parse('we run "jrnl" and {input_method} "{user_input}"')) -@when(parse('we run "jrnl {command}"')) -@when('we run "jrnl "') -@when('we run "jrnl"') -def we_run( - command, - config_path, - user_input, - cli_run, - capsys, - password, - cache_dir, - editor, - keyring, - input_method, - mocks, -): - assert input_method in ["", "enter", "pipe"] - is_tty = input_method != "pipe" - - if cache_dir["exists"]: - command = command.format(cache_dir=cache_dir["path"]) - - args = split_args(command) - status = 0 - - if user_input: - user_input = user_input.splitlines() if is_tty else [user_input] - - if password: - password = password.splitlines() - - if not password and user_input: - password = user_input - - with ExitStack() as stack: - - stack.enter_context(patch("sys.argv", ["jrnl"] + args)) - - mock_stdin = stack.enter_context( - patch("sys.stdin.read", side_effect=user_input) - ) - stack.enter_context(patch("sys.stdin.isatty", return_value=is_tty)) - mock_input = stack.enter_context( - patch("builtins.input", side_effect=user_input) - ) - mock_getpass = stack.enter_context( - patch("getpass.getpass", side_effect=password) - ) - - if "datetime" in mocks: - stack.enter_context(mocks["datetime"]) - stack.enter_context(mocks["calendar_parse"]) - - # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) - # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) - - stack.enter_context( - patch("jrnl.install.get_config_path", return_value=config_path) - ) - stack.enter_context( - patch("jrnl.config.get_config_path", return_value=config_path) - ) - mock_editor = stack.enter_context(patch("subprocess.call", side_effect=editor)) - - try: - cli(args) - except StopIteration: - # This happens when input is expected, but don't have any input left - pass - except SystemExit as e: - status = e.code - - captured = capsys.readouterr() - - cli_run["status"] = status - cli_run["stdout"] = captured.out - cli_run["stderr"] = captured.err - cli_run["mocks"] = { - "stdin": mock_stdin, - "input": mock_input, - "getpass": mock_getpass, - "editor": mock_editor, - } From d95dab9f0c7fa64c08e29118d84c6b0397a47550 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Jul 2021 15:04:39 -0700 Subject: [PATCH 67/74] add actual lib directory even though it's in gitignore for some reason --- tests/lib/fixtures.py | 201 ++++++++++++++++++++++++ tests/lib/given_steps.py | 134 ++++++++++++++++ tests/lib/helpers.py | 40 +++++ tests/lib/then_steps.py | 331 +++++++++++++++++++++++++++++++++++++++ tests/lib/when_steps.py | 113 +++++++++++++ 5 files changed, 819 insertions(+) create mode 100644 tests/lib/fixtures.py create mode 100644 tests/lib/given_steps.py create mode 100644 tests/lib/helpers.py create mode 100644 tests/lib/then_steps.py create mode 100644 tests/lib/when_steps.py diff --git a/tests/lib/fixtures.py b/tests/lib/fixtures.py new file mode 100644 index 00000000..a93a7e43 --- /dev/null +++ b/tests/lib/fixtures.py @@ -0,0 +1,201 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +from collections import defaultdict +import os +from pathlib import Path +import tempfile + +from keyring import backend +from keyring import errors +from keyring import set_keyring +from pytest import fixture +import toml + +from jrnl.config import load_config + + +# --- Keyring --- # +@fixture +def keyring(): + set_keyring(NoKeyring()) + + +@fixture +def keyring_type(): + return "default" + + +class TestKeyring(backend.KeyringBackend): + """A test keyring that just stores its values in a hash""" + + priority = 1 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + self.keys[servicename][username] = password + + def get_password(self, servicename, username): + return self.keys[servicename].get(username) + + def delete_password(self, servicename, username): + self.keys[servicename][username] = None + + +class NoKeyring(backend.KeyringBackend): + """A keyring that simulated an environment with no keyring backend.""" + + priority = 2 + keys = defaultdict(dict) + + def set_password(self, servicename, username, password): + raise errors.NoKeyringError + + def get_password(self, servicename, username): + raise errors.NoKeyringError + + def delete_password(self, servicename, username): + raise errors.NoKeyringError + + +class FailedKeyring(backend.KeyringBackend): + """A keyring that cannot be retrieved.""" + + priority = 2 + + def set_password(self, servicename, username, password): + raise errors.KeyringError + + def get_password(self, servicename, username): + raise errors.KeyringError + + def delete_password(self, servicename, username): + raise errors.KeyringError + + +# ----- Misc ----- # +@fixture +def cli_run(): + return {"status": 0, "stdout": None, "stderr": None} + + +@fixture +def mocks(): + return dict() + + +@fixture +def temp_dir(): + return tempfile.TemporaryDirectory() + + +@fixture +def working_dir(request): + return os.path.join(request.config.rootpath, "tests") + + +@fixture +def config_path(temp_dir): + os.chdir(temp_dir.name) + return temp_dir.name + "/jrnl.yaml" + + +@fixture +def toml_version(working_dir): + pyproject = os.path.join(working_dir, "..", "pyproject.toml") + pyproject_contents = toml.load(pyproject) + return pyproject_contents["tool"]["poetry"]["version"] + + +@fixture +def password(): + return "" + + +@fixture +def input_method(): + return "" + + +@fixture +def cache_dir(): + return {"exists": False, "path": ""} + + +@fixture +def str_value(): + return "" + + +@fixture +def command(): + return "" + + +@fixture +def should_not(): + return False + + +@fixture +def user_input(): + return "" + + +@fixture +def config_data(config_path): + return load_config(config_path) + + +@fixture +def journal_name(): + return None + + +@fixture +def which_output_stream(): + return None + + +@fixture +def editor_input(): + return None + + +@fixture +def num_args(): + return None + + +@fixture +def parsed_output(): + return {"lang": None, "obj": None} + + +@fixture +def editor_state(): + return { + "command": "", + "intent": {"method": "r", "input": None}, + "tmpfile": {"name": None, "content": None}, + } + + +@fixture +def editor(editor_state): + def _mock_editor(editor_command): + tmpfile = editor_command[-1] + + editor_state["command"] = editor_command + editor_state["tmpfile"]["name"] = tmpfile + + Path(tmpfile).touch() + with open(tmpfile, editor_state["intent"]["method"]) as f: + # Touch the file so jrnl knows it was edited + if editor_state["intent"]["input"] is not None: + f.write(editor_state["intent"]["input"]) + + file_content = f.read() + editor_state["tmpfile"]["content"] = file_content + + return _mock_editor diff --git a/tests/lib/given_steps.py b/tests/lib/given_steps.py new file mode 100644 index 00000000..649d44c5 --- /dev/null +++ b/tests/lib/given_steps.py @@ -0,0 +1,134 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +from datetime import datetime +import json +import os +import random +import shutil +import string +from unittest.mock import MagicMock +from unittest.mock import patch +from xml.etree import ElementTree + +from keyring import set_keyring +from pytest_bdd import given +from pytest_bdd.parsers import parse + +from jrnl import __version__ +from jrnl.time import __get_pdt_calendar + +from .fixtures import FailedKeyring +from .fixtures import TestKeyring + + +@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) +@given(parse("we {editor_method} nothing to the editor if opened")) +def we_enter_editor(editor_method, editor_input, editor_state): + file_method = editor_state["intent"]["method"] + if editor_method == "write": + file_method = "w+" + elif editor_method == "append": + file_method = "a+" + else: + assert False, f"Method '{editor_method}' not supported" + + editor_state["intent"] = {"method": file_method, "input": editor_input} + + +@given(parse('now is ""')) +@given(parse('now is "{date_str}"')) +def now_is_str(date_str, mocks): + class DatetimeMagicMock(MagicMock): + # needed because jrnl does some reflection on datetime + def __instancecheck__(self, subclass): + return isinstance(subclass, datetime) + + def mocked_now(tz=None): + now = datetime.strptime(date_str, "%Y-%m-%d %I:%M:%S %p") + + if tz: + time_zone = datetime.utcnow().astimezone().tzinfo + now = now.replace(tzinfo=time_zone) + + return now + + # jrnl uses two different classes to parse dates, so both must be mocked + datetime_mock = DatetimeMagicMock(wraps=datetime) + datetime_mock.now.side_effect = mocked_now + + pdt = __get_pdt_calendar() + calendar_mock = MagicMock(wraps=pdt) + calendar_mock.parse.side_effect = lambda date_str_input: pdt.parse( + date_str_input, mocked_now() + ) + + mocks["datetime"] = patch("datetime.datetime", new=datetime_mock) + mocks["calendar_parse"] = patch( + "jrnl.time.__get_pdt_calendar", return_value=calendar_mock + ) + + +@given("we have a keyring", target_fixture="keyring") +@given(parse("we have a {keyring_type} keyring"), target_fixture="keyring") +def we_have_type_of_keyring(keyring_type): + if keyring_type == "failed": + set_keyring(FailedKeyring()) + else: + set_keyring(TestKeyring()) + + +@given(parse('we use the config "{config_file}"'), target_fixture="config_path") +@given('we use the config ""', target_fixture="config_path") +def we_use_the_config(config_file, temp_dir, working_dir): + # Move into temp dir as cwd + os.chdir(temp_dir.name) + + # Copy the config file over + config_source = os.path.join(working_dir, "data", "configs", config_file) + config_dest = os.path.join(temp_dir.name, config_file) + shutil.copy2(config_source, config_dest) + + # @todo make this only copy some journals over + # Copy all of the journals over + journal_source = os.path.join(working_dir, "data", "journals") + journal_dest = os.path.join(temp_dir.name, "features", "journals") + shutil.copytree(journal_source, journal_dest) + + # @todo get rid of this by using default config values + # merge in version number + if config_file.endswith("yaml") and os.path.exists(config_dest): + # Add jrnl version to file for 2.x journals + with open(config_dest, "a") as cf: + cf.write("version: {}".format(__version__)) + + return config_dest + + +@given(parse('we use the password "{pw}" if prompted'), target_fixture="password") +def use_password_forever(pw): + return pw + + +@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} + + +@given(parse("we parse the output as {language_name}"), target_fixture="parsed_output") +def parse_output_as_language(cli_run, language_name): + language_name = language_name.upper() + actual_output = cli_run["stdout"] + + if language_name == "XML": + parsed_output = ElementTree.fromstring(actual_output) + elif language_name == "JSON": + parsed_output = json.loads(actual_output) + else: + assert False, f"Language name {language_name} not recognized" + + return {"lang": language_name, "obj": parsed_output} diff --git a/tests/lib/helpers.py b/tests/lib/helpers.py new file mode 100644 index 00000000..7d089597 --- /dev/null +++ b/tests/lib/helpers.py @@ -0,0 +1,40 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import os + + +def does_directory_contain_files(file_list, directory_path): + if not os.path.isdir(directory_path): + return False + + for file in file_list.split("\n"): + fullpath = directory_path + "/" + file + if not os.path.isfile(fullpath): + return False + + return True + + +def parse_should_or_should_not(should_or_should_not): + if should_or_should_not == "should": + return True + elif should_or_should_not == "should not": + return False + else: + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) + + +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], + ] diff --git a/tests/lib/then_steps.py b/tests/lib/then_steps.py new file mode 100644 index 00000000..b56c203f --- /dev/null +++ b/tests/lib/then_steps.py @@ -0,0 +1,331 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +import json +import os +import re +from xml.etree import ElementTree + +from pytest_bdd import then +from pytest_bdd.parsers import parse +import yaml + +from jrnl.config import scope_config + +from .helpers import assert_equal_tags_ignoring_order +from .helpers import does_directory_contain_files +from .helpers import parse_should_or_should_not + + +@then("we should get no error") +def should_get_no_error(cli_run): + assert cli_run["status"] == 0, cli_run["status"] + + +@then(parse('the output should match "{regex}"')) +def output_should_match(regex, cli_run): + out = cli_run["stdout"] + matches = re.findall(regex, out) + assert matches, f"\nRegex didn't match:\n{regex}\n{str(out)}\n{str(matches)}" + + +@then(parse("the output should contain\n{expected_output}")) +@then(parse('the output should contain "{expected_output}"')) +@then('the output should contain ""') +@then(parse("the {which_output_stream} output should contain\n{expected_output}")) +@then(parse('the {which_output_stream} output should contain "{expected_output}"')) +def output_should_contain(expected_output, which_output_stream, cli_run): + assert expected_output + if which_output_stream is None: + assert (expected_output in cli_run["stdout"]) or ( + expected_output in cli_run["stderr"] + ) + + elif which_output_stream == "standard": + assert expected_output in cli_run["stdout"] + + elif which_output_stream == "error": + assert expected_output in cli_run["stderr"] + + else: + assert expected_output in cli_run[which_output_stream] + + +@then(parse("the output should not contain\n{expected_output}")) +@then(parse('the output should not contain "{expected_output}"')) +@then('the output should not contain ""') +def output_should_not_contain(expected_output, cli_run): + assert expected_output not in cli_run["stdout"] + + +@then(parse("the output should be\n{expected_output}")) +@then(parse('the output should be "{expected_output}"')) +@then('the output should be ""') +def output_should_be(expected_output, cli_run): + actual = cli_run["stdout"].strip() + expected = expected_output.strip() + assert expected == actual + + +@then("the output should be empty") +def output_should_be_empty(cli_run): + actual = cli_run["stdout"].strip() + assert actual == "" + + +@then('the output should contain the date ""') +def output_should_contain_date(date, cli_run): + assert date and date in cli_run["stdout"] + + +@then("the output should contain pyproject.toml version") +def output_should_contain_version(cli_run, toml_version): + out = cli_run["stdout"] + assert toml_version in out, toml_version + + +@then(parse('we should see the message "{text}"')) +def should_see_the_message(text, cli_run): + out = cli_run["stderr"] + assert text in out, [text, out] + + +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' + ) +) +@then( + parse( + 'the config for journal "{journal_name}" {should_or_should_not} contain\n{some_yaml}' + ) +) +@then(parse('the config {should_or_should_not} contain "{some_yaml}"')) +@then(parse("the config {should_or_should_not} contain\n{some_yaml}")) +def config_var(config_data, journal_name, should_or_should_not, some_yaml): + we_should = parse_should_or_should_not(should_or_should_not) + + actual = config_data + if journal_name: + actual = actual["journals"][journal_name] + + expected = yaml.load(some_yaml, Loader=yaml.FullLoader) + + actual_slice = actual + if type(actual) is dict: + actual_slice = {key: actual.get(key, None) for key in expected.keys()} + + if we_should: + assert expected == actual_slice + else: + assert expected != actual_slice + + +@then("we should be prompted for a password") +def password_was_called(cli_run): + assert cli_run["mocks"]["getpass"].called + + +@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): + assert does_directory_contain_files(file_list, cache_dir["path"]) + + +@then(parse("the journal directory should contain\n{file_list}")) +def journal_directory_should_contain(config_data, file_list): + scoped_config = scope_config(config_data, "default") + + assert does_directory_contain_files(file_list, scoped_config["journal"]) + + +@then(parse('journal "{journal_name}" should not exist')) +def journal_directory_should_not_exist(config_data, journal_name): + scoped_config = scope_config(config_data, journal_name) + + assert not does_directory_contain_files( + scoped_config["journal"], "." + ), f'Journal "{journal_name}" does exist' + + +@then(parse("the journal {should_or_should_not} exist")) +def journal_should_not_exist(config_data, should_or_should_not): + scoped_config = scope_config(config_data, "default") + expected_path = scoped_config["journal"] + + contains_files = does_directory_contain_files(expected_path, ".") + + if should_or_should_not == "should": + assert contains_files + elif should_or_should_not == "should not": + assert not contains_files + else: + raise Exception( + "should_or_should_not valid values are 'should' or 'should not'" + ) + + +@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], + ] + + +@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(parse("the output should be valid {language_name}")) +def assert_output_is_valid_language(cli_run, language_name): + language_name = language_name.upper() + if language_name == "XML": + xml_tree = ElementTree.fromstring(cli_run["stdout"]) + assert xml_tree, "Invalid XML" + elif language_name == "JSON": + assert json.loads(cli_run["stdout"]), "Invalid JSON" + else: + assert False, f"Language name {language_name} not recognized" + + +@then(parse('"{node_name}" in the parsed output should have {number:d} elements')) +def assert_parsed_output_item_count(node_name, number, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] + + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert node_name in xml_node_names, str(list(xml_node_names)) + + actual_entry_count = len(obj.find(node_name)) + assert actual_entry_count == number, actual_entry_count + + elif lang == "JSON": + my_obj = obj + + for node in node_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert node in my_obj + my_obj = my_obj[node] + + assert len(my_obj) == number, len(my_obj) + + else: + assert False, f"Language name {lang} not recognized" + + +@then(parse('"{field_name}" in the parsed output should {comparison}\n{expected_keys}')) +def assert_output_field_content(field_name, comparison, expected_keys, parsed_output): + lang = parsed_output["lang"] + obj = parsed_output["obj"] + expected_keys = expected_keys.split("\n") + if len(expected_keys) == 1: + expected_keys = expected_keys[0] + + if lang == "XML": + xml_node_names = (node.tag for node in obj) + assert field_name in xml_node_names, str(list(xml_node_names)) + + if field_name == "tags": + actual_tags = set(t.attrib["name"] for t in obj.find("tags")) + assert set(actual_tags) == set(expected_keys), [ + actual_tags, + set(expected_keys), + ] + else: + assert False, "This test only works for tags in XML" + + elif lang == "JSON": + my_obj = obj + + for node in field_name.split("."): + try: + my_obj = my_obj[int(node)] + except ValueError: + assert node in my_obj, [my_obj.keys(), node] + my_obj = my_obj[node] + + if comparison == "be": + if type(my_obj) is str: + assert expected_keys == my_obj, [my_obj, expected_keys] + else: + assert set(expected_keys) == set(my_obj), [ + set(my_obj), + set(expected_keys), + ] + elif comparison == "contain": + if type(my_obj) is str: + assert expected_keys in my_obj, [my_obj, expected_keys] + else: + assert all(elem in my_obj for elem in expected_keys), [ + my_obj, + expected_keys, + ] + else: + assert False, f"Language name {lang} not recognized" + + +@then(parse('there should be {number:d} "{item}" elements')) +def count_elements(number, item, cli_run): + actual_output = cli_run["stdout"] + xml_tree = ElementTree.fromstring(actual_output) + assert len(xml_tree.findall(".//" + item)) == number + + +@then(parse("the editor should have been called")) +@then(parse("the editor should have been called with {num_args} arguments")) +def count_editor_args(num_args, cli_run, editor_state): + assert cli_run["mocks"]["editor"].called + + if isinstance(num_args, int): + assert len(editor_state["command"]) == int(num_args) + + +@then(parse('the editor filename should end with "{suffix}"')) +def editor_filename_suffix(suffix, editor_state): + editor_filename = editor_state["tmpfile"]["name"] + + assert editor_state["tmpfile"]["name"].endswith(suffix), (editor_filename, suffix) + + +@then(parse('the editor file content should {comparison} "{str_value}"')) +@then(parse("the editor file content should {comparison} empty")) +@then(parse("the editor file content should {comparison}\n{str_value}")) +def contains_editor_file(comparison, str_value, editor_state): + content = editor_state["tmpfile"]["content"] + # content = f'\n"""\n{content}\n"""\n' + if comparison == "be": + assert content == str_value + elif comparison == "contain": + assert str_value in content + else: + assert False, f"Comparison '{comparison}' not supported" diff --git a/tests/lib/when_steps.py b/tests/lib/when_steps.py new file mode 100644 index 00000000..2e72173b --- /dev/null +++ b/tests/lib/when_steps.py @@ -0,0 +1,113 @@ +# Copyright (C) 2012-2021 jrnl contributors +# License: https://www.gnu.org/licenses/gpl-3.0.html + +from contextlib import ExitStack +import os +from unittest.mock import patch + +from pytest_bdd import parsers +from pytest_bdd import when +from pytest_bdd.parsers import parse + +from jrnl.cli import cli +from jrnl.os_compat import split_args + + +@when(parse('we change directory to "{directory_name}"')) +def when_we_change_directory(directory_name): + if not os.path.isdir(directory_name): + os.mkdir(directory_name) + + os.chdir(directory_name) + + +@when(parse('we run "jrnl {command}" and {input_method}\n{user_input}')) +@when( + parsers.re( + 'we run "jrnl (?P[^"]+)" and (?Penter|pipe) "(?P[^"]+)"' + ) +) +@when(parse('we run "jrnl" and {input_method} "{user_input}"')) +@when(parse('we run "jrnl {command}"')) +@when('we run "jrnl "') +@when('we run "jrnl"') +def we_run( + command, + config_path, + user_input, + cli_run, + capsys, + password, + cache_dir, + editor, + keyring, + input_method, + mocks, +): + assert input_method in ["", "enter", "pipe"] + is_tty = input_method != "pipe" + + if cache_dir["exists"]: + command = command.format(cache_dir=cache_dir["path"]) + + args = split_args(command) + status = 0 + + if user_input: + user_input = user_input.splitlines() if is_tty else [user_input] + + if password: + password = password.splitlines() + + if not password and user_input: + password = user_input + + with ExitStack() as stack: + + stack.enter_context(patch("sys.argv", ["jrnl"] + args)) + + mock_stdin = stack.enter_context( + patch("sys.stdin.read", side_effect=user_input) + ) + stack.enter_context(patch("sys.stdin.isatty", return_value=is_tty)) + mock_input = stack.enter_context( + patch("builtins.input", side_effect=user_input) + ) + mock_getpass = stack.enter_context( + patch("getpass.getpass", side_effect=password) + ) + + if "datetime" in mocks: + stack.enter_context(mocks["datetime"]) + stack.enter_context(mocks["calendar_parse"]) + + # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) + # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) + + stack.enter_context( + patch("jrnl.install.get_config_path", return_value=config_path) + ) + stack.enter_context( + patch("jrnl.config.get_config_path", return_value=config_path) + ) + mock_editor = stack.enter_context(patch("subprocess.call", side_effect=editor)) + + try: + cli(args) + except StopIteration: + # This happens when input is expected, but don't have any input left + pass + except SystemExit as e: + status = e.code + + captured = capsys.readouterr() + + cli_run["status"] = status + cli_run["stdout"] = captured.out + cli_run["stderr"] = captured.err + cli_run["mocks"] = { + "stdin": mock_stdin, + "input": mock_input, + "getpass": mock_getpass, + "editor": mock_editor, + } From 495956d907486ce86106696e0ecf1fe314644dc4 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Jul 2021 15:21:41 -0700 Subject: [PATCH 68/74] remove init file that is no longer neded --- __init__.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 __init__.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index 46468510..00000000 --- a/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import sys - -sys.path.append("..") From 26484130c3214e34b15b42a494deb4532b585fa1 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 3 Jul 2021 15:21:50 -0700 Subject: [PATCH 69/74] remove old comment --- tests/lib/when_steps.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/lib/when_steps.py b/tests/lib/when_steps.py index 2e72173b..642249e9 100644 --- a/tests/lib/when_steps.py +++ b/tests/lib/when_steps.py @@ -81,9 +81,6 @@ def we_run( stack.enter_context(mocks["datetime"]) stack.enter_context(mocks["calendar_parse"]) - # stack.enter_context(patch("datetime.datetime", new=mocks["datetime"])) - # stack.enter_context(patch("jrnl.time.__get_pdt_calendar", return_value=mocks["calendar_parse"])) - stack.enter_context( patch("jrnl.install.get_config_path", return_value=config_path) ) From 9e3153453eabf0659ce47985e922cf97cc1584a1 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 3 Jul 2021 15:50:36 -0700 Subject: [PATCH 70/74] Change all instances of FullLoader to SafeLoader (#1285) --- features/steps/core.py | 8 ++++---- jrnl/config.py | 4 ++-- jrnl/plugins/template.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/steps/core.py b/features/steps/core.py index ac5d8950..2ad5bcc4 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -17,7 +17,7 @@ import keyring import toml import yaml -from yaml.loader import FullLoader +from yaml.loader import SafeLoader import jrnl.time @@ -409,7 +409,7 @@ def run(context, command, text=""): if "config_path" in context and context.config_path is not None: with open(context.config_path) as f: - context.jrnl_config = yaml.load(f, Loader=yaml.FullLoader) + context.jrnl_config = yaml.load(f, Loader=yaml.SafeLoader) else: context.jrnl_config = None @@ -418,7 +418,7 @@ def run(context, command, text=""): command = command.format(cache_dir=cache_dir) if "config_path" in context and context.config_path is not None: with open(context.config_path, "r") as f: - cfg = yaml.load(f, Loader=FullLoader) + cfg = yaml.load(f, Loader=SafeLoader) context.jrnl_config = cfg args = split_args(command) @@ -675,7 +675,7 @@ def check_journal_entries(context, number, journal_name="default"): @when("the journal directory is listed") def list_journal_directory(context, journal="default"): with open(context.config_path) as config_file: - configuration = yaml.load(config_file, Loader=yaml.FullLoader) + configuration = yaml.load(config_file, Loader=yaml.SafeLoader) journal_path = configuration["journals"][journal] for root, dirnames, f in os.walk(journal_path): for file in f: diff --git a/jrnl/config.py b/jrnl/config.py index da2df2cc..32695204 100644 --- a/jrnl/config.py +++ b/jrnl/config.py @@ -41,7 +41,7 @@ def make_yaml_valid_dict(input: list) -> dict: # yaml compatible strings are of the form Key:Value yamlstr = YAML_SEPARATOR.join(input) - runtime_modifications = yaml.load(yamlstr, Loader=yaml.FullLoader) + runtime_modifications = yaml.load(yamlstr, Loader=yaml.SafeLoader) return runtime_modifications @@ -140,7 +140,7 @@ def verify_config_colors(config): def load_config(config_path): """Tries to load a config file from YAML.""" with open(config_path) as f: - return yaml.load(f, Loader=yaml.FullLoader) + return yaml.load(f, Loader=yaml.SafeLoader) def is_config_json(config_path): diff --git a/jrnl/plugins/template.py b/jrnl/plugins/template.py index 147cd7af..cb852471 100644 --- a/jrnl/plugins/template.py +++ b/jrnl/plugins/template.py @@ -26,7 +26,7 @@ class Template: def from_file(cls, filename): with open(filename) as f: front_matter, body = f.read().strip("-\n").split("---", 2) - front_matter = yaml.load(front_matter, Loader=yaml.FullLoader) + front_matter = yaml.load(front_matter, Loader=yaml.SafeLoader) template = cls(body) template.__dict__.update(front_matter) return template From 56df419bea3750fa7156dec80a6850a6f906944c Mon Sep 17 00:00:00 2001 From: Jrnl Bot Date: Sat, 3 Jul 2021 22:52:14 +0000 Subject: [PATCH 71/74] Update changelog [ci skip] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8f71a70..e7700ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ **Build:** +- Move test suite entirely to Pytest \(replace Behave\) [\#1192](https://github.com/jrnl-org/jrnl/issues/1192) - Remove useless shebangs and executable permissions [\#1283](https://github.com/jrnl-org/jrnl/pull/1283) ([musicinmybrain](https://github.com/musicinmybrain)) - Remove `--version` from brew release workflow [\#1233](https://github.com/jrnl-org/jrnl/pull/1233) ([wren](https://github.com/wren)) +- Move test suite to Pytest \(replace Behave\) [\#1193](https://github.com/jrnl-org/jrnl/pull/1193) ([wren](https://github.com/wren)) **Packaging:** From 2723e1cfb55d2af965b8b0bded4b24ebcbffe6f1 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison Date: Sat, 10 Jul 2021 12:13:15 -0700 Subject: [PATCH 72/74] Add Python 3.10 support (#1271) * Add Python 3.10 support * Change Python 3.10 to 3.10-dev in CI * Run poetry update * Turn off fail-fast to troubleshoot Co-authored-by: Jonathan Wren * Add continue-on-error for 3.10 Co-authored-by: Jonathan Wren * use prerelease poetry for prerelease python * fix syntax error * rename steps to make more sense * remove dev dependency that breaks with python 3.10 * update tests * Change test dependencies for minimal breakage on python 3.10 - loosen the test dep requirements (so we get warned about these problems sooner) - add new extras group to provide minimal deps required for testing (we don't need to run static analysis again on every version) * change how we check if deps are installed so test don't run wild * add setuptools due to poetry bug, clean up other steps * update lock file * test * Revert "test" This reverts commit 31e538300ef7f2ab3ff84da7fe03f156e4714e06. Co-authored-by: Jonathan Wren --- .github/workflows/testing.yaml | 41 +++++- poetry.lock | 260 +++++++++++++++++---------------- pyproject.toml | 27 +++- 3 files changed, 188 insertions(+), 140 deletions(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 47710ca2..396fc854 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -23,9 +23,11 @@ jobs: if: > ! contains(github.event.head_commit.message, '[ci skip]') runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.python-version == '3.10-dev' }} strategy: + fail-fast: false matrix: - python-version: [ 3.7, 3.8, 3.9 ] + python-version: [ 3.7, 3.8, 3.9, 3.10-dev ] os: [ ubuntu-latest, macos-latest, windows-latest ] steps: @@ -44,27 +46,50 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('poetry.lock') }}-${{ matrix.python-version }}-v2 - name: Install dependencies + if: ${{ matrix.python-version != '3.10-dev' }} run: | + echo '::group::poetry' pip install poetry poetry config --local virtualenvs.in-project true + echo '::endgroup::' + + echo '::group::Other dependencies' poetry install --remove-untracked + echo '::endgroup::' + + echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV + + + - name: Install dependencies (Prerelease) + if: ${{ matrix.python-version == '3.10-dev' }} + run: | + echo '::group::poetry' + pip install poetry==1.2.0a1 + poetry config --local virtualenvs.in-project true + echo '::endgroup::' + + echo '::group::Other dependencies' + poetry install --remove-untracked --no-dev --extras testing + echo '::endgroup::' + + echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV - name: Code formatting (Black) - if: success() || failure() + if: ${{ matrix.python-version != '3.10-dev' && env.DEPS_INSTALLED == 'true' }} run: | poetry run black --version poetry run black --check --diff . - - name: Code Style (PyFlakes) - if: success() || failure() + - name: Code Style (flake8) + if: ${{ matrix.python-version != '3.10-dev' && env.DEPS_INSTALLED == 'true' }} run: | - poetry run pyflakes --version - poetry run pyflakes jrnl features tests + poetry run pflake8 --version + poetry run pflake8 jrnl features tests - name: Test with pytest - if: success() || failure() + if: ${{ env.DEPS_INSTALLED == 'true' }} run: poetry run pytest --junitxml=reports/pytest/results.xml - name: Test with behave - if: success() || failure() + if: ${{ env.DEPS_INSTALLED == 'true' }} run: poetry run behave --no-skipped --format progress2 --junit --junit-directory reports/behave diff --git a/poetry.lock b/poetry.lock index 2d1a8ea2..172a2533 100644 --- a/poetry.lock +++ b/poetry.lock @@ -25,20 +25,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "argcomplete" -version = "1.12.3" -description = "Bash tab completion for argparse" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -importlib-metadata = {version = ">=0.23,<5", markers = "python_version == \"3.7\""} - -[package.extras] -test = ["coverage", "flake8", "pexpect", "wheel"] - [[package]] name = "asteval" version = "0.9.25" @@ -51,7 +37,7 @@ python-versions = ">=3.6" name = "atomicwrites" version = "1.4.0" description = "Atomic file writes." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -59,7 +45,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" name = "attrs" version = "21.2.0" description = "Classes Without Boilerplate" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -81,7 +67,7 @@ python-versions = "*" name = "behave" version = "1.2.6" description = "behave is behaviour-driven development, Python style" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -149,6 +135,17 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "commonmark" +version = "0.9.1" +description = "Python parser for the CommonMark Markdown spec" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] + [[package]] name = "cryptography" version = "3.4.7" @@ -208,13 +205,13 @@ dev = ["twine", "markdown", "flake8"] name = "glob2" version = "0.7" description = "Version of the glob module that can capture patterns and supports recursive wildcards" -category = "dev" +category = "main" optional = false python-versions = "*" [[package]] name = "importlib-metadata" -version = "4.6.0" +version = "4.6.1" description = "Read metadata from Python packages" category = "main" optional = false @@ -233,7 +230,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -248,6 +245,7 @@ python-versions = ">=2.7" [package.dependencies] decorator = {version = "*", markers = "python_version > \"3.6\""} ipython = {version = ">=7.17.0", markers = "python_version > \"3.6\""} +setuptools = "*" toml = {version = ">=0.10.2", markers = "python_version > \"3.6\""} [[package]] @@ -269,6 +267,7 @@ pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} pickleshare = "*" prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" pygments = "*" +setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] @@ -352,7 +351,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes name = "mako" version = "1.1.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -381,7 +380,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -447,7 +446,7 @@ python-versions = "*" name = "packaging" version = "21.0" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -458,7 +457,7 @@ pyparsing = ">=2.0.2" name = "parse" version = "1.19.0" description = "parse() is the opposite of format()" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -466,7 +465,7 @@ python-versions = "*" name = "parse-type" version = "0.5.2" description = "Simplifies to build parse types based on the parse module" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" @@ -529,7 +528,7 @@ python-versions = "*" name = "pluggy" version = "0.13.1" description = "plugin and hook calling mechanisms for python" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -539,6 +538,14 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] +[[package]] +name = "pprintpp" +version = "0.4.0" +description = "A drop-in replacement for pprint that's actually pretty" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "prompt-toolkit" version = "3.0.19" @@ -562,7 +569,7 @@ python-versions = "*" name = "py" version = "1.10.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -602,7 +609,7 @@ python-versions = ">=3.5" name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -622,7 +629,7 @@ toml = "*" name = "pytest" version = "6.2.4" description = "pytest: simple powerful testing with Python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -644,7 +651,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm name = "pytest-bdd" version = "4.1.0" description = "BDD for pytest" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -658,15 +665,16 @@ pytest = ">=4.3" [[package]] name = "pytest-clarity" -version = "0.3.0a0" +version = "1.0.1" description = "A plugin providing an alternative, colourful diff output for failing assertions." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] +pprintpp = ">=0.4.0" pytest = ">=3.5.0" -termcolor = "1.1.0" +rich = ">=8.0.0" [[package]] name = "python-dateutil" @@ -724,12 +732,29 @@ pyyaml = "*" [[package]] name = "regex" -version = "2021.7.1" +version = "2021.7.6" description = "Alternative regular expression module, to replace re." category = "dev" optional = false python-versions = "*" +[[package]] +name = "rich" +version = "10.5.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" +optional = false +python-versions = ">=3.6,<4.0" + +[package.dependencies] +colorama = ">=0.4.0,<0.5.0" +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" +typing-extensions = {version = ">=3.7.4,<4.0.0", markers = "python_version < \"3.8\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] + [[package]] name = "secretstorage" version = "3.3.1" @@ -742,6 +767,18 @@ python-versions = ">=3.6" cryptography = ">=2.0" jeepney = ">=0.6" +[[package]] +name = "setuptools" +version = "57.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "pygments-github-lexers (==0.0.5)", "sphinx-inline-tabs", "sphinxcontrib-towncrier"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "mock", "flake8-2020", "virtualenv (>=13.0.0)", "pytest-virtualenv (>=1.2.7)", "wheel", "paver", "pip (>=19.1)", "jaraco.envs", "pytest-xdist", "sphinx", "jaraco.path (>=3.2.0)", "pytest-black (>=0.3.7)", "pytest-mypy"] + [[package]] name = "six" version = "1.16.0" @@ -750,14 +787,6 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -[[package]] -name = "termcolor" -version = "1.1.0" -description = "ANSII Color formatting for output in terminal." -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "textwrap3" version = "0.9.2" @@ -770,7 +799,7 @@ python-versions = "*" name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -834,31 +863,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "xmltodict" -version = "0.12.0" -description = "Makes working with XML feel like you are working with JSON" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "yq" -version = "2.12.2" -description = "Command-line YAML/XML processor - jq wrapper for YAML/XML documents" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -argcomplete = ">=1.8.1" -PyYAML = ">=3.11" -toml = ">=0.10.0" -xmltodict = ">=0.11.0" - -[package.extras] -test = ["coverage", "flake8", "wheel"] - [[package]] name = "zipp" version = "3.5.0" @@ -871,10 +875,13 @@ python-versions = ">=3.6" docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +[extras] +testing = ["behave", "pytest", "pytest-bdd", "toml"] + [metadata] lock-version = "1.1" -python-versions = ">=3.7.0, <3.10" -content-hash = "5be8c38e248b64ff4f2eacf253411b57c91352523c40674f1dec6d8c304996c2" +python-versions = ">=3.7.0, <3.11" +content-hash = "8549770f6a13b58f3baf9b434b326fc6bfc69eaccd604efcce110744fabdac64" [metadata.files] ansiwrap = [ @@ -889,10 +896,6 @@ appnope = [ {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, ] -argcomplete = [ - {file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"}, - {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, -] asteval = [ {file = "asteval-0.9.25.tar.gz", hash = "sha256:bea22b7d8fa16bcba95ebc72052ae5d8ca97114c9959bb47f8b8eebf30e4342f"}, ] @@ -963,6 +966,10 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +commonmark = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, +] cryptography = [ {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"}, {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"}, @@ -992,8 +999,8 @@ glob2 = [ {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.6.0-py3-none-any.whl", hash = "sha256:c6513572926a96458f8c8f725bf0e00108fba0c9583ade9bd15b869c9d726e33"}, - {file = "importlib_metadata-4.6.0.tar.gz", hash = "sha256:4a5611fea3768d3d967c447ab4e93f567d95db92225b43b7b238dbfb855d70bb"}, + {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"}, + {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1124,6 +1131,10 @@ pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] +pprintpp = [ + {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, + {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, +] prompt-toolkit = [ {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"}, {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"}, @@ -1169,7 +1180,7 @@ pytest-bdd = [ {file = "pytest_bdd-4.1.0-py3-none-any.whl", hash = "sha256:7c5221680cec9a97630e1fae6132f4a97c2f86a90914206ee06a55ae1a409fe5"}, ] pytest-clarity = [ - {file = "pytest-clarity-0.3.0a0.tar.gz", hash = "sha256:5cc99e3d9b7969dfe17e5f6072d45a917c59d363b679686d3c958a1ded2e4dcf"}, + {file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, @@ -1215,55 +1226,64 @@ pyyaml-env-tag = [ {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, ] regex = [ - {file = "regex-2021.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:494d0172774dc0beeea984b94c95389143db029575f7ca908edd74469321ea99"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8cf6728f89b071bd3ab37cb8a0e306f4de897553a0ed07442015ee65fbf53d62"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1806370b2bef4d4193eebe8ee59a9fd7547836a34917b7badbe6561a8594d9cb"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0cf2651a8804f6325747c7e55e3be0f90ee2848e25d6b817aa2728d263f9abb"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:268fe9dd1deb4a30c8593cabd63f7a241dfdc5bd9dd0233906c718db22cdd49a"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:7743798dfb573d006f1143d745bf17efad39775a5190b347da5d83079646be56"}, - {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0e46c1191b2eb293a6912269ed08b4512e7e241bbf591f97e527492e04c77e93"}, - {file = "regex-2021.7.1-cp36-cp36m-win32.whl", hash = "sha256:b1dbeef938281f240347d50f28ae53c4b046a23389cd1fc4acec5ea0eae646a1"}, - {file = "regex-2021.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6c72ebb72e64e9bd195cb35a9b9bbfb955fd953b295255b8ae3e4ad4a146b615"}, - {file = "regex-2021.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf819c5b77ff44accc9a24e31f1f7ceaaf6c960816913ed3ef8443b9d20d81b6"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e80d2851109e56420b71f9702ad1646e2f0364528adbf6af85527bc61e49f394"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b6a3f600d6aff97e3f28c34192c9ed93fee293bd96ef327b64adb51a74b2f6"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ed77b97896312bc2deafe137ca2626e8b63808f5bedb944f73665c68093688a7"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a548bb51c4476332ce4139df8e637386730f79a92652a907d12c696b6252b64d"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:210c359e6ee5b83f7d8c529ba3c75ba405481d50f35a420609b0db827e2e3bb5"}, - {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1d386402ae7f3c9b107ae5863f7ecccb0167762c82a687ae6526b040feaa5ac6"}, - {file = "regex-2021.7.1-cp37-cp37m-win32.whl", hash = "sha256:5049d00dbb78f9d166d1c704e93934d42cce0570842bb1a61695123d6b01de09"}, - {file = "regex-2021.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:361be4d311ac995a8c7ad577025a3ae3a538531b1f2cf32efd8b7e5d33a13e5a"}, - {file = "regex-2021.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f32f47fb22c988c0b35756024b61d156e5c4011cb8004aa53d93b03323c45657"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b024ee43ee6b310fad5acaee23e6485b21468718cb792a9d1693eecacc3f0b7e"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b092754c06852e8a8b022004aff56c24b06310189186805800d09313c37ce1f8"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a8a5826d8a1b64e2ff9af488cc179e1a4d0f144d11ce486a9f34ea38ccedf4ef"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:444723ebaeb7fa8125f29c01a31101a3854ac3de293e317944022ae5effa53a4"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:fdad3122b69cdabdb3da4c2a4107875913ac78dab0117fc73f988ad589c66b66"}, - {file = "regex-2021.7.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4b1999ef60c45357598935c12508abf56edbbb9c380df6f336de38a6c3a294ae"}, - {file = "regex-2021.7.1-cp38-cp38-win32.whl", hash = "sha256:e07e92935040c67f49571779d115ecb3e727016d42fb36ee0d8757db4ca12ee0"}, - {file = "regex-2021.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:6b8b629f93246e507287ee07e26744beaffb4c56ed520576deac8b615bd76012"}, - {file = "regex-2021.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56bef6b414949e2c9acf96cb5d78de8b529c7b99752619494e78dc76f99fd005"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:78a2a885345a2d60b5e68099e877757d5ed12e46ba1e87507175f14f80892af3"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3f7a92e60930f8fca2623d9e326c173b7cf2c8b7e4fdcf984b75a1d2fb08114d"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4fc86b729ab88fe8ac3ec92287df253c64aa71560d76da5acd8a2e245839c629"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:59845101de68fd5d3a1145df9ea022e85ecd1b49300ea68307ad4302320f6f61"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ce269e903b00d1ab4746793e9c50a57eec5d5388681abef074d7b9a65748fca5"}, - {file = "regex-2021.7.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c11f2fca544b5e30a0e813023196a63b1cb9869106ef9a26e9dae28bce3e4e26"}, - {file = "regex-2021.7.1-cp39-cp39-win32.whl", hash = "sha256:1ccbd41dbee3a31e18938096510b7d4ee53aa9fce2ee3dcc8ec82ae264f6acfd"}, - {file = "regex-2021.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:18040755606b0c21281493ec309214bd61e41a170509e5014f41d6a5a586e161"}, - {file = "regex-2021.7.1.tar.gz", hash = "sha256:849802379a660206277675aa5a5c327f5c910c690649535863ddf329b0ba8c87"}, + {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"}, + {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"}, + {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"}, + {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"}, + {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"}, + {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"}, + {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"}, + {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"}, + {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"}, + {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"}, + {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"}, + {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"}, + {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"}, +] +rich = [ + {file = "rich-10.5.0-py3-none-any.whl", hash = "sha256:d36d4dddbb6cb87cdcb2c02f8ffd7836e1b136e3ba45d4b5a4da057f3b5e7798"}, + {file = "rich-10.5.0.tar.gz", hash = "sha256:f8a16484b3d70708bdafd04f659f9ca0e2c0129b33a343c10c734838d361777f"}, ] secretstorage = [ {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, ] +setuptools = [ + {file = "setuptools-57.1.0-py3-none-any.whl", hash = "sha256:ddae4c1b9220daf1e32ba9d4e3714df6019c5b583755559be84ff8199f7e1fe3"}, + {file = "setuptools-57.1.0.tar.gz", hash = "sha256:cfca9c97e7eebbc8abe18d5e5e962a08dcad55bb63afddd82d681de4d22a597b"}, +] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -termcolor = [ - {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, -] textwrap3 = [ {file = "textwrap3-0.9.2-py2.py3-none-any.whl", hash = "sha256:bf5f4c40faf2a9ff00a9e0791fed5da7415481054cef45bb4a3cfb1f69044ae0"}, {file = "textwrap3-0.9.2.zip", hash = "sha256:5008eeebdb236f6303dcd68f18b856d355f6197511d952ba74bc75e40e0c3414"}, @@ -1344,14 +1364,6 @@ wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] -xmltodict = [ - {file = "xmltodict-0.12.0-py2.py3-none-any.whl", hash = "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051"}, - {file = "xmltodict-0.12.0.tar.gz", hash = "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21"}, -] -yq = [ - {file = "yq-2.12.2-py2.py3-none-any.whl", hash = "sha256:9fdf4487a6dbf985ca1d357ec93f926d982813e8e896e8892bae95162b6defe3"}, - {file = "yq-2.12.2.tar.gz", hash = "sha256:2f156d0724b61487ac8752ed4eaa702a5737b804d5afa46fa55866951cd106d2"}, -] zipp = [ {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, diff --git a/pyproject.toml b/pyproject.toml index 36bc3d13..3f5c5644 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ "Funding" = "https://opencollective.com/jrnl" [tool.poetry.dependencies] -python = ">=3.7.0, <3.10" +python = ">=3.7.0, <3.11" ansiwrap = "^0.8.4" asteval = "^0.9" @@ -43,17 +43,28 @@ pyyaml = ">=5.1" pytz = ">=2020" # https://pythonhosted.org/pytz/#issues-limitations tzlocal = ">2.0, <3.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt +# Minimal deps required for testing +# I don't like repeating deps here, but +# there's no other way to do this yet until poetry v1.2 releases +# see: https://github.com/python-poetry/poetry/issues/1644 +behave = { version = "^1.2" , optional = true } +pytest = { version = ">=6.2" , optional = true } +pytest-bdd = { version = ">=4.0.1" , optional = true } +toml = { version = ">=0.10" , optional = true } + [tool.poetry.dev-dependencies] behave = "^1.2" -mkdocs = "^1.0" -black = {version = "^21.5b2",allow-prereleases = true} +mkdocs = ">=1.0" +black = { version = ">=21.5b2", allow-prereleases = true } toml = ">=0.10" pytest = ">=6.2" -pytest-bdd = "^4.0.1" -yq = ">=2.11" -ipdb = ">=0.13" -pytest-clarity = "^0.3.0-alpha.0" -pyproject-flake8 = "^0.0.1-alpha.2" +pytest-bdd = ">=4.0.1" +ipdb = "*" +pytest-clarity = "*" +pyproject-flake8 = "*" + +[tool.poetry.extras] +testing = [ "behave", "pytest", "pytest-bdd", "toml" ] [tool.poetry.scripts] jrnl = 'jrnl.cli:cli' From 9bd395007fa38cbf82e2a6d6b41734cbcda40eeb Mon Sep 17 00:00:00 2001 From: Jrnl Bot Date: Sat, 10 Jul 2021 19:14:56 +0000 Subject: [PATCH 73/74] Update changelog [ci skip] --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7700ab4..f157f10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,15 @@ [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.1...HEAD) +**Implemented enhancements:** + +- Python 3.10 support [\#1270](https://github.com/jrnl-org/jrnl/issues/1270) + **Build:** - Move test suite entirely to Pytest \(replace Behave\) [\#1192](https://github.com/jrnl-org/jrnl/issues/1192) - Remove useless shebangs and executable permissions [\#1283](https://github.com/jrnl-org/jrnl/pull/1283) ([musicinmybrain](https://github.com/musicinmybrain)) +- Add Python 3.10 support [\#1271](https://github.com/jrnl-org/jrnl/pull/1271) ([micahellison](https://github.com/micahellison)) - Remove `--version` from brew release workflow [\#1233](https://github.com/jrnl-org/jrnl/pull/1233) ([wren](https://github.com/wren)) - Move test suite to Pytest \(replace Behave\) [\#1193](https://github.com/jrnl-org/jrnl/pull/1193) ([wren](https://github.com/wren)) From e771c9da8198b8979186c8ccd353b26802bb6a2a Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 10 Jul 2021 13:53:00 -0700 Subject: [PATCH 74/74] Update lock file from poetry stable version (#1298) --- poetry.lock | 104 +++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 59 deletions(-) diff --git a/poetry.lock b/poetry.lock index 172a2533..54f35f7a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -106,7 +106,7 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "cffi" -version = "1.14.5" +version = "1.14.6" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -245,7 +245,6 @@ python-versions = ">=2.7" [package.dependencies] decorator = {version = "*", markers = "python_version > \"3.6\""} ipython = {version = ">=7.17.0", markers = "python_version > \"3.6\""} -setuptools = "*" toml = {version = ">=0.10.2", markers = "python_version > \"3.6\""} [[package]] @@ -267,7 +266,6 @@ pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} pickleshare = "*" prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" pygments = "*" -setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] @@ -306,7 +304,7 @@ testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] [[package]] name = "jeepney" -version = "0.6.0" +version = "0.7.0" description = "Low-level, pure Python DBus protocol wrapper." category = "main" optional = false @@ -314,6 +312,7 @@ python-versions = ">=3.6" [package.extras] test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio"] +trio = ["trio", "async-generator"] [[package]] name = "jinja2" @@ -767,18 +766,6 @@ python-versions = ">=3.6" cryptography = ">=2.0" jeepney = ">=0.6" -[[package]] -name = "setuptools" -version = "57.1.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "pygments-github-lexers (==0.0.5)", "sphinx-inline-tabs", "sphinxcontrib-towncrier"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "mock", "flake8-2020", "virtualenv (>=13.0.0)", "pytest-virtualenv (>=1.2.7)", "wheel", "paver", "pip (>=19.1)", "jaraco.envs", "pytest-xdist", "sphinx", "jaraco.path (>=3.2.0)", "pytest-black (>=0.3.7)", "pytest-mypy"] - [[package]] name = "six" version = "1.16.0" @@ -920,43 +907,46 @@ black = [ {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"}, ] cffi = [ - {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, - {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, - {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, - {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, - {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, - {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, - {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, - {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, - {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, - {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, - {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, - {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, - {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, - {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, - {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, - {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, - {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, - {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, - {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, + {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, + {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, + {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, + {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, + {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, + {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, + {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, + {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, + {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, + {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, + {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, + {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, + {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, + {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, + {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, ] click = [ {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, @@ -1022,8 +1012,8 @@ jedi = [ {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, ] jeepney = [ - {file = "jeepney-0.6.0-py3-none-any.whl", hash = "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae"}, - {file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"}, + {file = "jeepney-0.7.0-py3-none-any.whl", hash = "sha256:71335e7a4e93817982f473f3507bffc2eff7a544119ab9b73e089c8ba1409ba3"}, + {file = "jeepney-0.7.0.tar.gz", hash = "sha256:1237cd64c8f7ac3aa4b3f332c4d0fb4a8216f39eaa662ec904302d4d77de5a54"}, ] jinja2 = [ {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, @@ -1276,10 +1266,6 @@ secretstorage = [ {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, ] -setuptools = [ - {file = "setuptools-57.1.0-py3-none-any.whl", hash = "sha256:ddae4c1b9220daf1e32ba9d4e3714df6019c5b583755559be84ff8199f7e1fe3"}, - {file = "setuptools-57.1.0.tar.gz", hash = "sha256:cfca9c97e7eebbc8abe18d5e5e962a08dcad55bb63afddd82d681de4d22a597b"}, -] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},