Deploy jrnl-org/jrnl to github.com/jrnl-org/jrnl.git:gh-pages

This commit is contained in:
Deployment Bot (from Travis CI) 2019-10-19 21:43:26 +00:00
commit c480368a87
104 changed files with 6140 additions and 0 deletions

60
features/core.feature Normal file
View file

@ -0,0 +1,60 @@
Feature: Basic reading and writing to a journal
Scenario: Loading a sample journal
Given we use the config "basic.yaml"
When we run "jrnl -n 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: Writing an entry from command line
Given we use the config "basic.yaml"
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."
Scenario: Filtering for dates
Given we use the config "basic.yaml"
When we run "jrnl -on 2013-06-10 --short"
Then the output should be "2013-06-10 15:40 Life is good."
When we run "jrnl -on 'june 6 2013' --short"
Then the output should be "2013-06-10 15:40 Life is good."
Scenario: Emoji support
Given we use the config "basic.yaml"
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 "🐘"
Scenario: Writing an entry at the prompt
Given we use the config "basic.yaml"
When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive."
Then we should get no error
and the journal should contain "[2013-07-25 09:00] I saw Elvis."
and the journal should contain "He's alive."
Scenario: Displaying the version number
Given we use the config "basic.yaml"
When we run "jrnl -v"
Then we should get no error
Then the output should contain "version"
Scenario: --short displays the short version of entries (only the title)
Given we use the config "basic.yaml"
When we run "jrnl -on 2013-06-10 --short"
Then the output should be "2013-06-10 15:40 Life is good."
Scenario: -s displays the short version of entries (only the title)
Given we use the config "basic.yaml"
When we run "jrnl -on 2013-06-10 -s"
Then the output should be "2013-06-10 15:40 Life is good."

View file

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

View file

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

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
journals:
default: features/journals/bug153.dayone
linewrap: 80
password: ''
tagsymbols: '@'
template: false
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

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

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
template: false
encrypt: false
highlight: true
journals:
default: features/journals/dayone.dayone
linewrap: 80
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
template: false
encrypt: false
highlight: true
journals:
default: features/journals/empty_folder
linewrap: 80
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: true
template: false
highlight: true
journals:
default: features/journals/encrypted.journal
linewrap: 80
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

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

View file

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

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
template: false
journals:
default: features/journals/markdown-headings-335.journal
linewrap: 80
password: ''
tagsymbols: '@'
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/mostlyreadabledates.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

@ -0,0 +1,19 @@
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
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
template: false
journals:
default: features/journals/tags-216.journal
linewrap: 80
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
template: false
journals:
default: features/journals/tags-237.journal
linewrap: 80
password: ''
tagsymbols: '@'
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,13 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
template: false
journals:
default: features/journals/tags.journal
linewrap: 80
password: ''
tagsymbols: '@'
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/unreadabledates.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

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

View file

@ -0,0 +1,2 @@
[2019-07-08 05:42] Entry subject
[1] line starting with 1

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Creation Date</key>
<date>2013-10-27T02:27:27Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>iPhone/iPhone3,1</string>
<key>Generation Date</key>
<date>2013-10-27T07:02:27Z</date>
<key>Host Name</key>
<string>omrt104001</string>
<key>OS Agent</key>
<string>iOS/7.0.3</string>
<key>Software Agent</key>
<string>Day One (iOS)/1.11.4</string>
</dict>
<key>Entry Text</key>
<string>Some text.</string>
<key>Location</key>
<dict>
<key>Administrative Area</key>
<string>Östergötlands län</string>
<key>Country</key>
<string>Sverige</string>
<key>Latitude</key>
<real>58.383400000000000</real>
<key>Locality</key>
<string>City</string>
<key>Longitude</key>
<real>15.577170000000000</real>
<key>Place Name</key>
<string>Street</string>
</dict>
<key>Starred</key>
<false/>
<key>Time Zone</key>
<string>Europe/Stockholm</string>
<key>UUID</key>
<string>B40EE704E15846DE8D45C44118A4D511</string>
<key>Weather</key>
<dict>
<key>Celsius</key>
<string>12</string>
<key>Description</key>
<string>Clear</string>
<key>Fahrenheit</key>
<string>54</string>
<key>IconName</key>
<string>sunnyn.png</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,52 @@
<dict>
<key>Creation Date</key>
<date>2013-10-27T02:27:27Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>iPhone/iPhone3,1</string>
<key>Generation Date</key>
<date>2013-10-27T07:02:27Z</date>
<key>Host Name</key>
<string>omrt104001</string>
<key>OS Agent</key>
<string>iOS/7.0.3</string>
<key>Software Agent</key>
<string>Day One (iOS)/1.11.4</string>
</dict>
<key>Entry Text</key>
<string>This is not a valid plist.</string>
<key>Location</key>
<dict>
<key>Administrative Area</key>
<string>Östergötlands län</string>
<key>Country</key>
<string>Sverige</string>
<key>Latitude</key>
<real>58.383400000000000</real>
<key>Locality</key>
<string>City</string>
<key>Longitude</key>
<real>15.577170000000000</real>
<key>Place Name</key>
<string>Street</string>
</dict>
<key>Starred</key>
<false/>
<key>Time Zone</key>
<string>Europe/Stockholm</string>
<key>UUID</key>
<string>B40EE704E15846DE8D45C44118A4D511</string>
<key>Weather</key>
<dict>
<key>Celsius</key>
<string>12</string>
<key>Description</key>
<string>Clear</string>
<key>Fahrenheit</key>
<string>54</string>
<key>IconName</key>
<string>sunnyn.png</string>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Creation Date</key>
<date>2013-05-17T18:39:20Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>Macintosh/MacBookAir5,2</string>
<key>Generation Date</key>
<date>2013-08-17T18:39:20Z</date>
<key>Host Name</key>
<string>Egeria</string>
<key>OS Agent</key>
<string>Mac OS X/10.8.4</string>
<key>Software Agent</key>
<string>Day One (Mac)/1.8</string>
</dict>
<key>Entry Text</key>
<string>This entry has tags!</string>
<key>Starred</key>
<false/>
<key>Tags</key>
<array>
<string>work</string>
<string>PLaY</string>
</array>
<key>Time Zone</key>
<string>America/Los_Angeles</string>
<key>UUID</key>
<string>044F3747A38546168B572C2E3F217FA2</string>
</dict>
</plist>

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Creation Date</key>
<date>2013-06-17T18:38:29Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>Macintosh/MacBookAir5,2</string>
<key>Generation Date</key>
<date>2013-08-17T18:38:29Z</date>
<key>Host Name</key>
<string>Egeria</string>
<key>OS Agent</key>
<string>Mac OS X/10.8.4</string>
<key>Software Agent</key>
<string>Day One (Mac)/1.8</string>
</dict>
<key>Entry Text</key>
<string>This entry has a location.</string>
<key>Location</key>
<dict>
<key>Administrative Area</key>
<string>California</string>
<key>Country</key>
<string>Germany</string>
<key>Latitude</key>
<real>52.4979764</real>
<key>Locality</key>
<string>Berlin</string>
<key>Longitude</key>
<real>13.2404758</real>
<key>Place Name</key>
<string>Abandoned Spy Tower</string>
</dict>
<key>Starred</key>
<false/>
<key>Tags</key>
<array/>
<key>Time Zone</key>
<string>Europe/Berlin</string>
<key>UUID</key>
<string>0BDDD6CDA43C4A9AA2681517CC35AD9D</string>
</dict>
</plist>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Creation Date</key>
<date>2013-07-17T18:38:08Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>Macintosh/MacBookAir5,2</string>
<key>Generation Date</key>
<date>2013-08-17T18:38:08Z</date>
<key>Host Name</key>
<string>Egeria</string>
<key>OS Agent</key>
<string>Mac OS X/10.8.4</string>
<key>Software Agent</key>
<string>Day One (Mac)/1.8</string>
</dict>
<key>Entry Text</key>
<string>This entry is starred!</string>
<key>Starred</key>
<true/>
<key>Tags</key>
<array/>
<key>Time Zone</key>
<string>America/Los_Angeles</string>
<key>UUID</key>
<string>422BC895507944A291E6FC44FC6B8BFC</string>
</dict>
</plist>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Creation Date</key>
<date>2013-01-17T18:37:50Z</date>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>Macintosh/MacBookAir5,2</string>
<key>Generation Date</key>
<date>2013-08-17T18:37:50Z</date>
<key>Host Name</key>
<string>Egeria</string>
<key>OS Agent</key>
<string>Mac OS X/10.8.4</string>
<key>Software Agent</key>
<string>Day One (Mac)/1.8</string>
</dict>
<key>Entry Text</key>
<string>This is a DayOne entry without Timezone.</string>
<key>Starred</key>
<false/>
<key>Tags</key>
<array/>
<key>UUID</key>
<string>4BB1F46946AD439996C9B59DE7C4DDC1</string>
</dict>
</plist>

View file

@ -0,0 +1 @@
Nothing to see here

View file

@ -0,0 +1 @@
gAAAAABVIHB7tnwKExG7aC5ZbAbBL9SG2oY2GENeoOJ22i1PZigOvCYvrQN3kpsu0KGr7ay5K-_46R5YFlqJvtQ8anPH2FSITsaZy-l5Lz_5quw3rmzhLwAR1tc0icgtR4MEpXEdsuQ7cyb12Xq-JLDrnATs0id5Vow9Ri_tE7Xe4BXgXaySn3aRPwWKoninVxVPVvETY3MXHSUEXV9OZ-pH5kYBLGYbLA==

Binary file not shown.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,5 @@
[ashasd7zdskhz7asdkjasd] Entry subject
I've lost track of time.
[sadfhakjsdf88sdf7sdff] Entry subject
Time has no meaning.

View file

View file

@ -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 %}
`

View file

@ -0,0 +1,31 @@
Feature: Encrypted journals
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"
and the output should contain "2013-06-10 15:40 Life is good"
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"
Then we should see the message "Journal decrypted"
and the journal should have 2 entries
Scenario: Encrypting a journal
Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter "swordfish"
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"
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 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"
Then we should not see the message "Password"
and the output should contain "2013-06-10 15:40 Life is good"

42
features/environment.py Normal file
View file

@ -0,0 +1,42 @@
from behave import *
import shutil
import os
import jrnl
try:
from io import StringIO
except ImportError:
from cStringIO import StringIO
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)
if os.path.exists(working_dir):
shutil.rmtree(working_dir)
for folder in ("configs", "journals"):
original = os.path.join("features", "data", folder)
working_dir = os.path.join("features", folder)
if not os.path.exists(working_dir):
os.mkdir(working_dir)
for filename in os.listdir(original):
source = os.path.join(original, filename)
if os.path.isdir(source):
shutil.copytree(source, os.path.join(working_dir, filename))
else:
shutil.copy2(source, working_dir)
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):
shutil.rmtree(working_dir)

View file

@ -0,0 +1,85 @@
Feature: Exporting a Journal
Scenario: Exporting to json
Given we use the config "tags.yaml"
When we run "jrnl --export 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 "@idea"
and "tags" in the json output should contain "@journal"
and "tags" in the json output should contain "@dan"
Scenario: Exporting using filters should only export parts of the journal
Given we use the config "tags.yaml"
When we run "jrnl -until 'may 2013' --export json"
# Then we should get no error
Then the output should be parsable as json
and "entries" in the json output should have 1 element
and "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal"
and "tags" in the json output should not contain "@dan"
Scenario: Exporting using custom templates
Given we use the config "basic.yaml"
Given we load template "sample.template"
When we run "jrnl --export sample"
Then the output should be
"""
My first entry.
---------------
Everything is alright
Life is good.
-------------
But I'm better.
"""
Scenario: Increasing Headings on Markdown export
Given we use the config "markdown-headings-335.yaml"
When we run "jrnl --export markdown"
Then the output should be
"""
# 2015
## April
### 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
"""

View file

@ -0,0 +1,46 @@
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: 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"
Then we should see the message "Journal 'new_encrypted' created"

View file

@ -0,0 +1,64 @@
Feature: Zapped bugs should stay dead.
Scenario: Writing an entry does not print the entire journal
# https://github.com/maebert/jrnl/issues/87
Given we use the config "basic.yaml"
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"
Scenario: Date with time should be parsed correctly
# https://github.com/maebert/jrnl/issues/117
Given we use the config "basic.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: Date in the future should be parsed correctly
# https://github.com/maebert/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Loading entry with ambiguous time stamp
#https://github.com/maebert/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.
"""
Scenario: Title with an embedded period.
Given we use the config "basic.yaml"
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.
"""
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"
Scenario: Journals with unreadable dates should still be viewable
Given we use the config "unreadabledates.yaml"
When we run "jrnl -2"
Then the output should contain "I've lost track of time."
Then 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."
When we run "jrnl -1"
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?"

20
features/starring.feature Normal file
View file

@ -0,0 +1,20 @@
Feature: Starring entries
Scenario: Starring an entry will mark it in the journal file
Given we use the config "basic.yaml"
When we run "jrnl 20 july 2013 *: Best day of my life!"
Then we should see the message "Entry added"
and the journal should contain "[2013-07-20 09:00] Best day of my life! *"
Scenario: Filtering by starred entries
Given we use the config "basic.yaml"
When we run "jrnl -starred"
Then the output should be
"""
"""
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!
"""

260
features/steps/core.py Normal file
View file

@ -0,0 +1,260 @@
from __future__ import unicode_literals
from __future__ import absolute_import
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
import os
import json
import yaml
import keyring
class TestKeyring(keyring.backend.KeyringBackend):
"""A test keyring that just stores its valies 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, 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)
return map(lambda s: s.decode('UTF8'), shlex.split(command.encode('utf8')))
def read_journal(journal_name="default"):
config = util.load_config(install.CONFIG_FILE_PATH)
with open(config['journals'][journal_name]) as journal_file:
journal = journal_file.read()
return journal
def open_journal(journal_name="default"):
config = util.load_config(install.CONFIG_FILE_PATH)
journal_conf = config['journals'][journal_name]
if type(journal_conf) is dict: # We can override the default config on a by-journal basis
config.update(journal_conf)
else: # But also just give them a string to point to the journal file
config['journal'] = journal_conf
return Journal.open_journal(journal_name, config)
@given('we use the config "{config_file}"')
def set_config(context, config_file):
full_path = os.path.join("features/configs", config_file)
install.CONFIG_FILE_PATH = os.path.abspath(full_path)
if config_file.endswith("yaml"):
# Add jrnl version to file for 2.x journals
with open(install.CONFIG_FILE_PATH, 'a') as cf:
cf.write("version: {}".format(__version__))
@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
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
@when('we run "{command}"')
def run(context, command):
args = ushlex(command)[1:]
try:
cli.run(args or None)
context.exit_status = 0
except SystemExit as e:
context.exit_status = e.code
@given('we load template "{filename}"')
def load_template(context, filename):
full_path = os.path.join("features/data/templates", filename)
exporter = plugins.template_exporter.__exporter_from_file(full_path)
plugins.__exporter_types[exporter.names[0]] = exporter
@when('we set the keychain password of "{journal}" to "{password}"')
def set_keychain(context, journal, password):
keyring.set_password('jrnl', journal, password)
@then('we should get an error')
def has_error(context):
assert context.exit_status != 0, context.exit_status
@then('we should get no error')
def no_error(context):
assert context.exit_status is 0, context.exit_status
@then('the output should be parsable as json')
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split('.'):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then('the output should be')
@then('the output should be "{text}"')
def check_output(context, text=None):
text = (text or context.text).strip().splitlines()
out = context.stdout_capture.getvalue().strip().splitlines()
assert len(text) == len(out), "Output has {} lines (expected: {})".format(len(out), len(text))
for line_text, line_out in zip(text, out):
assert line_text.strip() == line_out.strip(), [line_text.strip(), line_out.strip()]
@then('the output should contain "{text}" in the local time')
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
@then('the output should contain')
@then('the output should contain "{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()
assert text in out, [text, out]
@then('we should not see the message "{text}"')
def check_not_message(context, text):
out = context.messages.getvalue()
assert text not in out, [text, out]
@then('the journal should contain "{text}"')
@then('journal "{journal_name}" should contain "{text}"')
def check_journal_content(context, text, journal_name="default"):
journal = read_journal(journal_name)
assert text in journal, journal
@then('journal "{journal_name}" should not exist')
def journal_doesnt_exist(context, journal_name="default"):
with open(install.CONFIG_FILE_PATH) as config_file:
config = yaml.load(config_file, Loader=yaml.FullLoader)
journal_path = config['journals'][journal_name]
assert not os.path.exists(journal_path)
@then('the config should have "{key}" set to "{value}"')
@then('the config for journal "{journal}" should have "{key}" set to "{value}"')
def config_var(context, key, value, journal=None):
t, value = value.split(":")
value = {
"bool": lambda v: v.lower() == "true",
"int": int,
"str": str
}[t](value)
config = util.load_config(install.CONFIG_FILE_PATH)
if journal:
config = config["journals"][journal]
assert key in config
assert config[key] == value
@then('the journal should have {number:d} entries')
@then('the journal should have {number:d} entry')
@then('journal "{journal_name}" should have {number:d} entries')
@then('journal "{journal_name}" should have {number:d} entry')
def check_journal_entries(context, number, journal_name="default"):
journal = open_journal(journal_name)
assert len(journal.entries) == number
@then('fail')
def debug_fail(context):
assert False

84
features/tagging.feature Normal file
View file

@ -0,0 +1,84 @@
Feature: Tagging
Scenario: Displaying tags
Given we use the config "tags.yaml"
When we run "jrnl --tags"
Then we should get no error
and the output should be
"""
@idea : 2
@journal : 1
@dan : 1
"""
Scenario: Filtering journals should also filter tags
Given we use the config "tags.yaml"
When we run "jrnl -from 'may 2013' --tags"
Then we should get no error
and the output should be
"""
@idea : 1
@dan : 1
"""
Scenario: Tags should allow certain special characters
Given we use the config "tags-216.yaml"
When we run "jrnl --tags"
Then we should get no error
and the output should be
"""
@os/2 : 1
@c++ : 1
@c# : 1
"""
Scenario: An email should not be a tag
Given we use the config "tags-237.yaml"
When we run "jrnl --tags"
Then we should get no error
and the output should be
"""
@newline : 1
@email : 1
"""
Scenario: Entry cans start and end with tags
Given we use the config "basic.yaml"
When we run "jrnl today: @foo came over, we went to a @bar"
When we run "jrnl --tags"
Then the output should be
"""
@foo : 1
@bar : 1
"""
Scenario: Excluding a tag should filter it
Given we use the config "basic.yaml"
When we run "jrnl today: @foo came over, we went to a bar"
When we run "jrnl I have decided I did not enjoy that @bar"
When we run "jrnl --tags -not @bar"
Then the output should be
"""
@foo : 1
"""
Scenario: Excluding a tag should filter an entry, even if an unfiltered tag is in that entry
Given we use the config "basic.yaml"
When we run "jrnl today: I do @not think this will show up @thought"
When we run "jrnl today: I think this will show up @thought"
When we run "jrnl --tags -not @not"
Then the output should be
"""
@thought : 1
"""
Scenario: Excluding multiple tags should filter them
Given we use the config "basic.yaml"
When we run "jrnl today: I do @not think this will show up @thought"
When we run "jrnl today: I think this will show up @thought"
When we run "jrnl today: This should @never show up @thought"
When we run "jrnl today: What a nice day for filtering @thought"
When we run "jrnl --tags -not @not @never"
Then the output should be
"""
@thought : 2
"""

23
features/upgrade.feature Normal file
View file

@ -0,0 +1,23 @@
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 output should contain
"""
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".
"""
Then the journal should have 2 entries
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 see the message "Password"
and the output should contain "2013-06-10 15:40 Life is good"