Merge branch 'master' into interactive_delete

This commit is contained in:
Aaron Lichtman 2019-12-16 04:33:52 +01:00 committed by GitHub
commit 313651af11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 887 additions and 560 deletions

View file

@ -20,6 +20,19 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -n 1"
Then the output should contain "2013-07-23 09:00 A cold and stormy day."
Scenario: Writing an empty entry from the editor
Given we use the config "editor.yaml"
When we open the editor and enter ""
Then we should see the message "[Nothing saved to file]"
Scenario: Writing an empty entry from the command line
Given we use the config "basic.yaml"
When we run "jrnl" and enter ""
Then the output should be
"""
"""
Scenario: Filtering for dates
Given we use the config "basic.yaml"
When we run "jrnl -on 2013-06-10 --short"

View file

@ -0,0 +1,35 @@
Feature: Reading and writing to journal with custom date formats
Scenario: Loading a sample journal
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.06.2013 15:40 Life is good.
| But I'm better.
"""
Scenario: Writing an entry from command line
Given we use the config "little_endian_dates.yaml"
When we run "jrnl 2013-07-12: 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 "12.07.2013 09:00 A cold and stormy day."
Scenario: Filtering for dates
Given we use the config "little_endian_dates.yaml"
When we run "jrnl -on 2013-06-10 --short"
Then the output should be "10.06.2013 15:40 Life is good."
When we run "jrnl -on 'june 6 2013' --short"
Then the output should be "10.06.2013 15:40 Life is good."
Scenario: Writing an entry at the prompt
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."

View file

@ -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: "|"

View file

@ -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: "|"

View file

@ -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": "@"
}

View file

@ -0,0 +1,5 @@
[09.06.2013 15:39] My first entry.
Everything is alright
[10.06.2013 15:40] Life is good.
But I'm better.

View file

@ -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.

76
features/dayone.feature Normal file
View file

@ -0,0 +1,76 @@
Feature: Dayone specific implementation details.
# fails when system time is UTC (as on Travis-CI)
@skip
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!
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Entries without timezone information will be interpreted as in the 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
@skip
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.
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl --tags"
Then the output should be
"""
@work : 1
@play : 1
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Saving tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl A hard day at @work"
and we run "jrnl --tags"
Then the output should be
"""
@work : 2
@play : 1
"""
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Filtering by tags from a DayOne Journal
Given we use the config "dayone.yaml"
When we run "jrnl @work"
Then the output should be
"""
2013-05-17 11:39 This entry has tags!
"""
# fails when system time is UTC (as on Travis-CI)
@skip
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"

View file

@ -0,0 +1,31 @@
Feature: Zapped Dayone bugs stay dead!
# fails when system time is UTC (as on Travis-CI)
@skip
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!
"""
# 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 gives a nice error message
Given we use the config "empty_folder.yaml"
When we run "jrnl Herro"
Then we should get an error
Then we should see the message "is a directory, but doesn't seem to be a DayOne journal either"

View file

@ -2,7 +2,7 @@
Scenario: Loading an encrypted journal
Given we use the config "encrypted.yaml"
When we run "jrnl -n 1" and enter "bad doggie no biscuit"
Then we should see the message "Password"
Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good"
Scenario: Decrypting a journal
@ -14,16 +14,16 @@
Scenario: Encrypting a journal
Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter "swordfish"
When we run "jrnl --encrypt" and enter "swordfish" and "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 see the message "Password"
Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good"
Scenario: Storing a password in Keychain
Given we use the config "multiple.yaml"
When we run "jrnl simple --encrypt" and enter "sabertooth"
When we run "jrnl simple --encrypt" and enter "sabertooth" and "y"
When we set the keychain password of "simple" to "sabertooth"
Then the config for journal "simple" should have "encrypt" set to "bool:True"
When we run "jrnl simple -n 1"

View file

@ -1,19 +1,18 @@
from behave import *
import shutil
import os
import jrnl
try:
from io import StringIO
except ImportError:
from cStringIO import StringIO
def before_feature(context, feature):
# add "skip" tag
# https://stackoverflow.com/a/42721605/4276230
if "skip" in feature.tags:
feature.skip("Marked with @skip")
return
def before_scenario(context, scenario):
"""Before each scenario, backup all config and journal test data."""
context.messages = StringIO()
jrnl.util.STDERR = context.messages
jrnl.util.TEST = True
# Clean up in case something went wrong
for folder in ("configs", "journals"):
working_dir = os.path.join("features", folder)
@ -32,11 +31,15 @@ def before_scenario(context, scenario):
else:
shutil.copy2(source, working_dir)
# add "skip" tag
# https://stackoverflow.com/a/42721605/4276230
if "skip" in scenario.effective_tags:
scenario.skip("Marked with @skip")
return
def after_scenario(context, scenario):
"""After each scenario, restore all test data and remove working_dirs."""
context.messages.close()
context.messages = None
for folder in ("configs", "journals"):
working_dir = os.path.join("features", folder)
if os.path.exists(working_dir):

View file

@ -42,5 +42,5 @@ Feature: Multiple journals
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"
When we run "jrnl new_encrypted Adding first entry" and enter "these three eyes" and "y"
Then we should see the message "Journal 'new_encrypted' created"

View file

@ -62,3 +62,57 @@ Feature: Zapped bugs should stay dead.
Then the output should contain "I'm going to activate the machine."
Then the output should contain "I've crossed so many timelines. Is there any going back?"
Scenario: Viewing today's entries does not print the entire journal
# https://github.com/jrnl-org/jrnl/issues/741
Given we use the config "basic.yaml"
When we run "jrnl -on today"
Then the output should not contain "Life is good"
Then the output should not contain "But I'm better."
Scenario: Create entry using day of the week as entry date.
Given we use the config "basic.yaml"
When we run "jrnl monday: This is an entry on a Monday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should contain "monday at 9am" in the local time
Then the output should contain "This is an entry on a Monday."
Scenario: Create entry using day of the week abbreviations as entry date.
Given we use the config "basic.yaml"
When we run "jrnl fri: This is an entry on a Friday."
Then we should see the message "Entry added"
When we run "jrnl -1"
Then the output should contain "friday at 9am" in the local time
Scenario: Displaying entries using -on today should display entries created today.
Given we use the config "basic.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."
Scenario: Displaying entries using -from day should display correct entries
Given we use the config "basic.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."
Then the output should contain "A future entry."
Then the output should not contain "This thing happened yesterday"
Scenario: Displaying entries using -from and -to day should display correct entries
Given we use the config "basic.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"
Then the output should contain "Adding an entry right now."
Then the output should not contain "A future entry."

View file

@ -1,19 +1,28 @@
from __future__ import unicode_literals
from __future__ import absolute_import
from unittest.mock import patch
from behave import given, when, then
from jrnl import cli, install, Journal, util, plugins
from jrnl import __version__
from dateutil import parser as date_parser
from collections import defaultdict
try: import parsedatetime.parsedatetime_consts as pdt
except ImportError: import parsedatetime as pdt
import time
import os
import json
import yaml
import keyring
import tzlocal
import shlex
import sys
consts = pdt.Constants(usePyICU=False)
consts.DOWParseStyle = -1 # Prefers past weekdays
CALENDAR = pdt.Calendar(consts)
class TestKeyring(keyring.backend.KeyringBackend):
"""A test keyring that just stores its valies in a hash"""
"""A test keyring that just stores its values in a hash"""
priority = 1
keys = defaultdict(dict)
@ -27,19 +36,11 @@ class TestKeyring(keyring.backend.KeyringBackend):
def delete_password(self, servicename, username, password):
self.keys[servicename][username] = None
# set the keyring for keyring lib
keyring.set_keyring(TestKeyring())
try:
from io import StringIO
except ImportError:
from cStringIO import StringIO
import tzlocal
import shlex
import sys
def ushlex(command):
if sys.version_info[0] == 3:
return shlex.split(command)
@ -73,18 +74,65 @@ def set_config(context, config_file):
cf.write("version: {}".format(__version__))
@when('we open the editor and enter ""')
@when('we open the editor and enter "{text}"')
def open_editor_and_enter(context, text=""):
text = (text or context.text)
def _mock_editor_function(command):
tmpfile = command[-1]
with open(tmpfile, "w+") as f:
if text is not None:
f.write(text)
else:
f.write("")
return tmpfile
with patch('subprocess.call', side_effect=_mock_editor_function):
run(context, "jrnl")
def _mock_getpass(inputs):
def prompt_return(prompt="Password: "):
print(prompt)
return next(inputs)
return prompt_return
def _mock_input(inputs):
def prompt_return(prompt=""):
val = next(inputs)
print(prompt, val)
return val
return prompt_return
@when('we run "{command}" and enter')
@when('we run "{command}" and enter "{inputs}"')
def run_with_input(context, command, inputs=None):
text = inputs or context.text
@when('we run "{command}" and enter ""')
@when('we run "{command}" and enter "{inputs1}"')
@when('we run "{command}" and enter "{inputs1}" and "{inputs2}"')
def run_with_input(context, command, inputs1="", inputs2=""):
# create an iterator through all inputs. These inputs will be fed one by one
# to the mocked calls for 'input()', 'util.getpass()' and 'sys.stdin.read()'
if inputs1:
text = iter((inputs1, inputs2))
elif context.text:
text = iter(context.text.split("\n"))
else:
text = iter(("", ""))
args = ushlex(command)[1:]
buffer = StringIO(text.strip())
util.STDIN = buffer
try:
cli.run(args or [])
context.exit_status = 0
except SystemExit as e:
context.exit_status = e.code
with patch("builtins.input", side_effect=_mock_input(text)) as mock_input:
with patch("jrnl.util.getpass", side_effect=_mock_getpass(text)) as mock_getpass:
with patch("sys.stdin.read", side_effect=text) as mock_read:
try:
cli.run(args or [])
context.exit_status = 0
except SystemExit as e:
context.exit_status = e.code
# assert at least one of the mocked input methods got called
assert mock_input.called or mock_getpass.called or mock_read.called
@when('we run "{command}"')
@ -180,9 +228,9 @@ def check_output(context, text=None):
def check_output_time_inline(context, text):
out = context.stdout_capture.getvalue()
local_tz = tzlocal.get_localzone()
utc_time = date_parser.parse(text)
local_date = utc_time.astimezone(local_tz).strftime("%Y-%m-%d %H:%M")
assert local_date in out, local_date
date, flag = CALENDAR.parse(text)
output_date = time.strftime("%Y-%m-%d %H:%M",date)
assert output_date in out, output_date
@then('the output should contain')
@ -190,28 +238,24 @@ def check_output_time_inline(context, text):
def check_output_inline(context, text=None):
text = text or context.text
out = context.stdout_capture.getvalue()
if isinstance(out, bytes):
out = out.decode('utf-8')
assert text in out, text
@then('the output should not contain "{text}"')
def check_output_not_inline(context, text):
out = context.stdout_capture.getvalue()
if isinstance(out, bytes):
out = out.decode('utf-8')
assert text not in out
@then('we should see the message "{text}"')
def check_message(context, text):
out = context.messages.getvalue()
out = context.stderr_capture.getvalue()
assert text in out, [text, out]
@then('we should not see the message "{text}"')
def check_not_message(context, text):
out = context.messages.getvalue()
out = context.stderr_capture.getvalue()
assert text not in out, [text, out]

View file

@ -13,11 +13,22 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
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
When we run "jrnl -n 1" and enter
"""
Y
bad doggie no biscuit
bad doggie no biscuit
"""
Then we should see the message "Password"
Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good"
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 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".
"""
Then the journal should have 2 entries