Merge pull request #1 from sriniv27/separate-override-behave-test-from-core

separate-override-behave-test-from-core
This commit is contained in:
Suhas 2021-01-25 07:39:17 -05:00 committed by GitHub
commit 36623c1100
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 78 deletions

View file

@ -0,0 +1,7 @@
journals:
default: /tmp/journal.jrnl
colors:
body: none
title: green
editor: "vim"
encrypt: false

View file

@ -10,6 +10,7 @@ Given we use the config "editor.yaml"
When we run "jrnl --config-override '{"editor": "nano"}'"
Then the editor "nano" should have been called
@skip_win
Scenario: Override configured linewrap with a value of 23
Given we use the config "editor.yaml"
When we run "jrnl -2 --config-override '{"linewrap": 23}' --format fancy"
@ -30,7 +31,8 @@ Then the output should be
"""
@skip_win
Scenario: Override color selections with runtime overrides
Given we use the config "editor.yaml"
When we run "jrnl -1 --config-override '{"colors.body": "blue"}' "
Given we use the config "tiny.yaml"
When we run jrnl with -1 --config-override '{"colors.body": "blue"}'
Then the runtime config should have colors.body set to blue

View file

@ -13,13 +13,13 @@ from behave import given
from behave import then
from behave import when
import keyring
import mock
import toml
import yaml
from yaml.loader import FullLoader
import jrnl.time
from jrnl import Journal, override
from jrnl import Journal
from jrnl import __version__
from jrnl import plugins
from jrnl.cli import cli
@ -215,65 +215,6 @@ def open_editor_and_enter(context, method, text=""):
# fmt: on
@then("the runtime config should have {key_as_dots} set to {override_value}")
def config_override(context, key_as_dots: str, override_value: str):
with open(context.config_path) as f:
loaded_cfg = yaml.load(f, Loader=yaml.FullLoader)
loaded_cfg["journal"] = "features/journals/simple.journal"
base_cfg = loaded_cfg.copy()
def _mock_callback(**args):
print("callback executed")
# fmt: off
try:
with \
mock.patch.object(jrnl.override,"recursively_apply",wraps=jrnl.override.recursively_apply) as mock_recurse, \
patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
:
cli(['-1','--config-override', '{"%s": "%s"}'%(key_as_dots,override_value)])
# mock_recurse.assert_any_call(base_cfg,key_as_dots.split('.'),override_value)
keys_list = key_as_dots.split('.')
callList = [
(base_cfg,keys_list,override_value),
(base_cfg,keys_list[1], override_value)
]
mock_recurse.call_args_list
except SystemExit as e :
context.exit_status = e.code
# fmt: on
@then("the editor {editor} should have been called")
def editor_override(context, editor):
def _mock_editor(command_and_journal_file):
editor = command_and_journal_file[0]
tmpfile = command_and_journal_file[-1]
context.tmpfile = tmpfile
print("%s has been launched" % editor)
return tmpfile
# fmt: off
# see: https://github.com/psf/black/issues/664
with \
patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \
patch("sys.stdin.isatty", return_value=True), \
patch("jrnl.time.parse", side_effect=_mock_time_parse(context)), \
patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
:
try :
cli(['--config-override','{"editor": "%s"}'%editor])
context.exit_status = 0
context.editor = mock_editor
assert mock_editor.assert_called_once_with(editor, context.tmpfile)
except SystemExit as e:
context.exit_status = e.code
# fmt: on
@then("the editor should have been called")
@then("the editor should have been called with {num} arguments")
def count_editor_args(context, num=None):

View file

@ -0,0 +1,88 @@
from jrnl.jrnl import run
from jrnl.os_compat import split_args
from unittest import mock
# from __future__ import with_statement
from jrnl.args import parse_args
import os
from behave import given, when, then
import yaml
from yaml.loader import FullLoader
import jrnl
from jrnl.cli import cli
@given("we use the config {config_file}")
def load_config(context, config_file):
filepath = os.path.join("features/configs", config_file)
context.config_path = os.path.abspath(filepath)
@when("we run jrnl with {args}")
def run_command(context, args):
context.args = split_args("%s" % args)
context.parser = parse_args(context.args)
with open(context.config_path, "r") as f:
cfg = yaml.load(f, Loader=FullLoader)
context.cfg = cfg
@then("the runtime config should have {key_as_dots} set to {override_value}")
def config_override(context, key_as_dots: str, override_value: str):
key_as_vec = key_as_dots.split(".")
expected_call_args_list = [
(context.cfg, key_as_vec, override_value),
(context.cfg[key_as_vec[0]], key_as_vec[1], override_value),
]
with open(context.config_path) as f:
loaded_cfg = yaml.load(f, Loader=yaml.FullLoader)
loaded_cfg["journal"] = "features/journals/simple.journal"
def _mock_callback(**args):
print("callback executed")
# fmt: off
try:
with \
mock.patch.object(jrnl.override,"_recursively_apply",wraps=jrnl.override._recursively_apply) as mock_recurse, \
mock.patch('jrnl.install.load_or_install_jrnl', return_value=context.cfg), \
mock.patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
mock.patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
:
run(context.parser)
assert mock_recurse.call_count == 2
mock_recurse.call_args_list = expected_call_args_list
except SystemExit as e :
context.exit_status = e.code
# fmt: on
@then("the editor {editor} should have been called")
def editor_override(context, editor):
def _mock_editor(command_and_journal_file):
editor = command_and_journal_file[0]
tmpfile = command_and_journal_file[-1]
context.tmpfile = tmpfile
print("%s has been launched" % editor)
return tmpfile
# fmt: off
# see: https://github.com/psf/black/issues/664
with \
mock.patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \
mock.patch("sys.stdin.isatty", return_value=True), \
mock.patch("jrnl.time.parse"), \
mock.patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \
mock.patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \
:
try :
cli(['--config-override','{"editor": "%s"}'%editor])
context.exit_status = 0
context.editor = mock_editor
assert mock_editor.assert_called_once_with(editor, context.tmpfile)
except SystemExit as e:
context.exit_status = e.code
# fmt: on

View file

@ -3,14 +3,14 @@ def apply_overrides(overrides: dict, base_config: dict) -> dict:
config = base_config.copy()
for k in overrides:
nodes = k.split(".")
config = recursively_apply(config, nodes, overrides[k])
config = _recursively_apply(config, nodes, overrides[k])
return config
def recursively_apply(config: dict, nodes: list, override_value) -> dict:
def _recursively_apply(config: dict, nodes: list, override_value) -> dict:
"""Recurse through configuration and apply overrides at the leaf of the config tree
See: https://stackoverflow.com/a/47276490 for algorithm
Credit to iJames on SO: https://stackoverflow.com/a/47276490 for algorithm
Args:
config (dict): loaded configuration from YAML
@ -18,11 +18,18 @@ def recursively_apply(config: dict, nodes: list, override_value) -> dict:
override_value (str): runtime override passed from the command-line
"""
key = nodes[0]
config[key] = (
override_value
if len(nodes) == 1
else recursively_apply(
config[key] if key in config else {}, nodes[1:], override_value
)
)
if len(nodes) == 1:
config[key] = override_value
else:
next_key = nodes[1:]
_recursively_apply(_get_config_node(config, key), next_key, override_value)
return config
def _get_config_node(config: dict, key: str):
if key in config:
pass
else:
config[key] = None
return config[key]

View file

@ -1,6 +1,6 @@
import pytest
from jrnl.override import apply_overrides, recursively_apply
from jrnl.override import apply_overrides, _recursively_apply, _get_config_node
@pytest.fixture()
@ -27,8 +27,13 @@ def test_override_dot_notation(minimal_config):
assert cfg["colors"] == {"body": "blue", "date": "green"}
def test_recursive_override(minimal_config):
def test_recursively_apply():
cfg = {"colors": {"body": "red", "title": "green"}}
cfg = recursively_apply(cfg, ["colors", "body"], "blue")
cfg = _recursively_apply(cfg, ["colors", "body"], "blue")
assert cfg["colors"]["body"] == "blue"
def test_get_config_node(minimal_config):
assert len(minimal_config.keys()) == 3
assert _get_config_node(minimal_config, "editor") == "vim"
assert _get_config_node(minimal_config, "display_format") == None