init commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
This directory contains stubs of Talon APIs for use in tests. It is made available by pytest's pythonpath configuration, see pyproject.toml.
|
||||
|
||||
The implementation of the stubs will mostly be noops, but some functionality (e.g. actions) are needed by tests and so are implemented to allow for easy introspection and changing.
|
||||
@@ -0,0 +1,215 @@
|
||||
import inspect
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class RegisteredActionsAccessor:
|
||||
def __init__(self, registered_actions, namespace):
|
||||
self.registered_actions = registered_actions
|
||||
self.namespace = namespace
|
||||
|
||||
def __getattr__(self, name):
|
||||
for category in ("test", "module"):
|
||||
cat_actions = self.registered_actions[category]
|
||||
if self.namespace in cat_actions:
|
||||
if name in cat_actions[self.namespace]:
|
||||
return cat_actions[self.namespace][name]
|
||||
|
||||
raise AttributeError(f"Couldn't find action {self.namespace}.{name}")
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
# Provide a useful error message if people try something like
|
||||
# actions.my_action() when they should do actions.user.my_action()
|
||||
raise RuntimeError(f"actions.{self.namespace}() is not an available action")
|
||||
|
||||
|
||||
class Actions:
|
||||
"""
|
||||
Implements something like talon.actions. You can use the register
|
||||
function to add in an action definition from your test (e.g. a mock).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.registered_actions = {
|
||||
"module": {},
|
||||
"test": {},
|
||||
}
|
||||
|
||||
# Some built in actions
|
||||
self.register_module_action("", "key", lambda x: None)
|
||||
self.register_module_action("", "insert", lambda x: None)
|
||||
self.register_module_action("", "sleep", lambda x: None)
|
||||
self.register_module_action("edit", "selected_text", lambda: "test")
|
||||
|
||||
def reset_test_actions(self):
|
||||
self.registered_actions["test"] = {}
|
||||
|
||||
def register_module_action(self, namespace: str, name: str, func: Callable):
|
||||
"""
|
||||
Registers an action to the module category. This should
|
||||
only be called by importing files containing module definitions.
|
||||
It won't be reset between test runs (or test files). Use
|
||||
register_test_action and reset_test_actions to temporarily override
|
||||
actions.
|
||||
"""
|
||||
|
||||
self._register_action("module", namespace, name, func)
|
||||
|
||||
def register_test_action(self, namespace: str, name: str, func: Callable):
|
||||
"""
|
||||
Registers the given action, use like:
|
||||
|
||||
actions.register("user.my_action", lambda: None)
|
||||
"""
|
||||
|
||||
self._register_action("test", namespace, name, func)
|
||||
|
||||
def _register_action(
|
||||
self, category: str, namespace: str, name: str, func: Callable
|
||||
):
|
||||
if namespace not in self.registered_actions[category]:
|
||||
self.registered_actions[category][namespace] = {}
|
||||
|
||||
self.registered_actions[category][namespace][name] = func
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
# If name exists as a direct property of this class, then
|
||||
# use that
|
||||
return object.__getattribute__(self, name)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Else if name is an action like actions.key
|
||||
# that has no namespace then return that.
|
||||
default_accessor = RegisteredActionsAccessor(self.registered_actions, "")
|
||||
return getattr(default_accessor, name)
|
||||
except AttributeError:
|
||||
# Otherwise treat name as an action namespace
|
||||
# (like actions.user).
|
||||
return RegisteredActionsAccessor(self.registered_actions, name)
|
||||
|
||||
|
||||
class Module:
|
||||
"""
|
||||
Implements something like the Module class built in to Talon
|
||||
"""
|
||||
|
||||
def list(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def setting(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def capture(self, rule=None):
|
||||
def __funcwrapper(func):
|
||||
def __inner(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return __inner
|
||||
|
||||
return __funcwrapper
|
||||
|
||||
def tag(self, name, desc=None):
|
||||
pass
|
||||
|
||||
def action_class(self, target_class):
|
||||
# Register all the methods on the class with our actions implementation
|
||||
for name, func in inspect.getmembers(target_class, inspect.isfunction):
|
||||
actions.register_module_action("user", name, func)
|
||||
|
||||
return target_class
|
||||
|
||||
|
||||
class Context:
|
||||
"""
|
||||
Implements something like the Context class built in to Talon
|
||||
"""
|
||||
|
||||
lists = {}
|
||||
|
||||
def action_class(self, path=None):
|
||||
def __funcwrapper(clazz):
|
||||
return clazz
|
||||
|
||||
return __funcwrapper
|
||||
|
||||
def capture(self, name: str, rule: str = None):
|
||||
def __funcwrapper(func):
|
||||
def __inner(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return __inner
|
||||
|
||||
return __funcwrapper
|
||||
|
||||
|
||||
class ImgUI:
|
||||
"""
|
||||
Stub out ImgUI so we don't get crashes
|
||||
"""
|
||||
|
||||
GUI = None
|
||||
|
||||
def open(self):
|
||||
def __funcwrapper(func):
|
||||
def __inner(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return __inner
|
||||
|
||||
return __funcwrapper
|
||||
|
||||
|
||||
class UI:
|
||||
"""
|
||||
Stub out UI so we don't get crashes
|
||||
"""
|
||||
|
||||
def register(*args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class Settings:
|
||||
"""
|
||||
Implements something like talon.settings
|
||||
"""
|
||||
|
||||
|
||||
class Registry:
|
||||
"""
|
||||
Implements something like Talon's registry
|
||||
"""
|
||||
|
||||
|
||||
class Resource:
|
||||
"""
|
||||
Implements something like the talon resource system
|
||||
"""
|
||||
|
||||
def open(self, path: str, mode: str = "r"):
|
||||
return open(path, mode, encoding="utf-8")
|
||||
|
||||
def watch(self, path: str):
|
||||
return lambda f: f
|
||||
|
||||
|
||||
class App:
|
||||
"""
|
||||
Implements something like the talon app variable
|
||||
"""
|
||||
|
||||
platform = "mac"
|
||||
|
||||
|
||||
actions = Actions()
|
||||
app = App
|
||||
clip = None
|
||||
imgui = ImgUI()
|
||||
ui = UI()
|
||||
settings = Settings()
|
||||
resource = Resource()
|
||||
registry = Registry()
|
||||
|
||||
# Indicate to test files that they should load since we're running in test mode
|
||||
test_mode = True
|
||||
@@ -0,0 +1,7 @@
|
||||
TextArea = None
|
||||
|
||||
Span = None
|
||||
|
||||
DarkThemeLabels = None
|
||||
|
||||
LightThemeLabels = None
|
||||
@@ -0,0 +1,11 @@
|
||||
# This is a class in the Talon runtime, but is only used as a type in `community`. We
|
||||
# stub it here as a blank class, since there are (for example) functions which
|
||||
# check isinstance(some_input, Phrase), and for testing we want these tests to
|
||||
# return False.
|
||||
class Phrase:
|
||||
pass
|
||||
|
||||
|
||||
# grammar.vm.Phrase is also used sometimes.
|
||||
class vm:
|
||||
Phrase = Phrase
|
||||
@@ -0,0 +1,36 @@
|
||||
import talon
|
||||
|
||||
if hasattr(talon, "test_mode"):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from talon import actions
|
||||
|
||||
def setup_function():
|
||||
# Load our code under test (register code_* actions)
|
||||
import lang.tags.functions # isort:skip
|
||||
|
||||
actions.reset_test_actions()
|
||||
|
||||
def test_calls_expected_function():
|
||||
"""
|
||||
Test that the given combination of modifiers ends up delegating to the
|
||||
correct function
|
||||
"""
|
||||
|
||||
examples = [
|
||||
(0, "code_default_function"),
|
||||
(["static"], "code_private_static_function"),
|
||||
(["private"], "code_private_function"),
|
||||
(["private", "static"], "code_private_static_function"),
|
||||
(["protected"], "code_protected_function"),
|
||||
(["protected", "static"], "code_protected_static_function"),
|
||||
(["public"], "code_public_function"),
|
||||
(["public", "static"], "code_public_static_function"),
|
||||
]
|
||||
for modifiers, target_action in examples:
|
||||
mock = MagicMock()
|
||||
actions.register_test_action("user", target_action, mock)
|
||||
|
||||
talon.actions.user.code_modified_function(modifiers, "test func")
|
||||
|
||||
mock.assert_called_once()
|
||||
@@ -0,0 +1,165 @@
|
||||
import talon
|
||||
|
||||
if hasattr(talon, "test_mode"):
|
||||
# Only include this when we're running tests
|
||||
|
||||
import itertools
|
||||
from typing import IO, Callable
|
||||
|
||||
from talon import actions
|
||||
|
||||
import core.abbreviate
|
||||
import core.user_settings
|
||||
|
||||
# we need to replace the track_csv_list decorator for unit tests.
|
||||
CallbackT = Callable[[dict[str, str]], None]
|
||||
DecoratorT = Callable[[CallbackT], CallbackT]
|
||||
|
||||
def track_csv_list_test(
|
||||
filename: str,
|
||||
headers: tuple[str, str],
|
||||
default: dict[str, str] = None,
|
||||
is_spoken_form_first: bool = False,
|
||||
) -> DecoratorT:
|
||||
def decorator(fn: CallbackT) -> CallbackT:
|
||||
extensions = {
|
||||
"dot see sharp": ".cs",
|
||||
}
|
||||
abbreviations = {"source": "src", "whats app": "WhatsApp"}
|
||||
if filename == "abbreviations.csv":
|
||||
fn(abbreviations)
|
||||
elif filename == "file_extensions.csv":
|
||||
fn(extensions)
|
||||
|
||||
return decorator
|
||||
|
||||
# replace track_csv_list before importing create_spoken_forms
|
||||
core.user_settings.track_csv_list = track_csv_list_test
|
||||
|
||||
import core.create_spoken_forms
|
||||
|
||||
def test_excludes_words():
|
||||
result = actions.user.create_spoken_forms("hi world", ["world"], 0, True)
|
||||
|
||||
assert "world" not in result
|
||||
assert "hi world" in result
|
||||
|
||||
def test_handles_empty_input():
|
||||
result = actions.user.create_spoken_forms("", None, 0, True)
|
||||
|
||||
assert result == []
|
||||
|
||||
def test_handles_minimum_term_length():
|
||||
result = actions.user.create_spoken_forms("hi world", None, 3, True)
|
||||
|
||||
assert "hi" not in result
|
||||
assert "world" in result
|
||||
|
||||
def test_handles_generate_subsequences():
|
||||
result = actions.user.create_spoken_forms("hi world", None, 0, False)
|
||||
|
||||
assert "world" not in result
|
||||
assert "hi world" in result
|
||||
|
||||
def test_expands_special_chars():
|
||||
result = actions.user.create_spoken_forms("hi $world", None, 0, True)
|
||||
|
||||
assert "hi world" in result
|
||||
|
||||
def test_expands_file_extensions():
|
||||
result = actions.user.create_spoken_forms("hi .cs", None, 0, True)
|
||||
|
||||
assert "hi dot see sharp" in result
|
||||
|
||||
def test_expands_abbreviations():
|
||||
|
||||
result = actions.user.create_spoken_forms("src", None, 0, True)
|
||||
|
||||
assert "source" in result
|
||||
assert "src" in result
|
||||
|
||||
result = actions.user.create_spoken_forms("WhatsApp", None, 0, True)
|
||||
|
||||
assert "whats app" in result
|
||||
|
||||
def test_expand_upper_case():
|
||||
result = actions.user.create_spoken_forms("LICENSE", None, 0, True)
|
||||
|
||||
assert "license" in result
|
||||
assert "L I C E N S E" in result
|
||||
|
||||
def test_small_word_to_upper_case():
|
||||
result = actions.user.create_spoken_forms("vm", None, 0, True)
|
||||
|
||||
assert "V M" in result
|
||||
|
||||
def test_explode_packed_words():
|
||||
result = actions.user.create_spoken_forms("README", None, 0, True)
|
||||
|
||||
assert "read me" in result
|
||||
|
||||
def test_email():
|
||||
result = actions.user.create_spoken_forms("stupid@test.com", None, 0, True)
|
||||
assert "stupid at test dot com" in result
|
||||
|
||||
def test_symbol_removal():
|
||||
result = actions.user.create_spoken_forms("$ this_is_a-'test'", None, 0, True)
|
||||
|
||||
assert "this is a test" in result
|
||||
|
||||
def test_and_symbol():
|
||||
result = actions.user.create_spoken_forms("movies & tv", None, 0, True)
|
||||
|
||||
assert "movies tv" in result
|
||||
assert "movies and tv" in result
|
||||
|
||||
def test_apostrophe_stripping():
|
||||
result = actions.user.create_spoken_forms("Sam's club", None, 0, True)
|
||||
|
||||
assert "sams club" in result
|
||||
|
||||
def test_properties():
|
||||
"""
|
||||
Throw some random inputs at the function to make sure it behaves itself
|
||||
"""
|
||||
|
||||
def _example_generator():
|
||||
pieces = ["hi", "world", "dollar", ".cs", "1900"]
|
||||
params = list(
|
||||
itertools.product(
|
||||
[None, ["world"], ["dot"]], # Dot is from the expanded ".cs"
|
||||
[0, 3],
|
||||
[True, False],
|
||||
)
|
||||
)
|
||||
count = 0
|
||||
while True:
|
||||
for exclude, min_count, subseq in params:
|
||||
for tokens in itertools.combinations(pieces, r=count):
|
||||
yield (tokens, exclude, min_count, subseq)
|
||||
count += 1
|
||||
|
||||
examples = itertools.islice(_example_generator(), 0, 100)
|
||||
for tokens, exclude, min_count, subseq in examples:
|
||||
source = " ".join(tokens)
|
||||
result = actions.user.create_spoken_forms(
|
||||
source, exclude, min_count, subseq
|
||||
)
|
||||
|
||||
statement = (
|
||||
f'create_spoken_forms("{source}", {exclude}, {min_count}, {subseq})'
|
||||
)
|
||||
|
||||
# No duplicates in result
|
||||
assert len(result) == len(set(result)), statement
|
||||
|
||||
# No empty strings in result
|
||||
assert "" not in result, statement
|
||||
|
||||
# Generates a form if we give it a non-empty input
|
||||
if len(tokens) > 0:
|
||||
assert len(result) >= 1, statement
|
||||
|
||||
# Generated forms at least as numerous as input if subseq is True
|
||||
if subseq:
|
||||
assert len(result) >= len(tokens), statement
|
||||
@@ -0,0 +1,58 @@
|
||||
import talon
|
||||
|
||||
PHRASE_EXAMPLES = ["", "foo", "foo bar", "lorem ipsum dolor sit amet"]
|
||||
|
||||
if hasattr(talon, "test_mode"):
|
||||
# Only include this when we're running tests
|
||||
|
||||
from core.text import text_and_dictation
|
||||
|
||||
def test_format_phrase():
|
||||
for x in PHRASE_EXAMPLES:
|
||||
assert text_and_dictation.format_phrase([x]) == x
|
||||
assert text_and_dictation.format_phrase(x.split()) == x
|
||||
|
||||
def test_capture_to_words():
|
||||
# if l is a list of strings, then (capture_to_words(l) == l) should hold.
|
||||
for s in PHRASE_EXAMPLES:
|
||||
for l in [[s], s.split(), list(s)]:
|
||||
assert text_and_dictation.capture_to_words(l) == l
|
||||
|
||||
def test_spacing_and_capitalization():
|
||||
format = text_and_dictation.DictationFormat()
|
||||
format.state = None
|
||||
result = format.format("first")
|
||||
assert result == "first"
|
||||
result = format.format("second.")
|
||||
assert result == " second."
|
||||
result = format.format("third(")
|
||||
assert result == " Third("
|
||||
result = format.format("fourth")
|
||||
assert result == "fourth"
|
||||
result = format.format("e.g.")
|
||||
assert result == " e.g."
|
||||
result = format.format("fifth")
|
||||
assert result == " fifth"
|
||||
result = format.format("i.e.")
|
||||
assert result == " i.e."
|
||||
result = format.format("sixth")
|
||||
assert result == " sixth"
|
||||
result = format.format("with.\nspace")
|
||||
assert result == " with.\nSpace"
|
||||
result = format.format("new.\nline")
|
||||
assert result == " new.\nLine"
|
||||
|
||||
def test_force_spacing_and_capitalization():
|
||||
format = text_and_dictation.DictationFormat()
|
||||
format.state = None
|
||||
format.force_capitalization = "cap"
|
||||
result = format.format("first")
|
||||
assert result == "First"
|
||||
format.force_no_space = True
|
||||
result = format.format("second.")
|
||||
assert result == "second."
|
||||
format.force_capitalization = "no cap"
|
||||
result = format.format("third(")
|
||||
assert result == " third("
|
||||
result = format.format("fourth")
|
||||
assert result == "fourth"
|
||||
@@ -0,0 +1,109 @@
|
||||
import talon
|
||||
|
||||
if hasattr(talon, "test_mode"):
|
||||
# Only include this when we're running tests
|
||||
|
||||
from talon import actions
|
||||
|
||||
from core.formatters import formatters
|
||||
|
||||
def setup_function():
|
||||
actions.reset_test_actions()
|
||||
actions.register_test_action("user", "add_phrase_to_history", lambda x: None)
|
||||
|
||||
def test_snake_case():
|
||||
result = formatters.Actions.formatted_text("hello world", "SNAKE_CASE")
|
||||
|
||||
assert result == "hello_world"
|
||||
|
||||
def test_no_spaces():
|
||||
result = formatters.Actions.formatted_text("hello world", "NO_SPACES")
|
||||
|
||||
assert result == "helloworld"
|
||||
|
||||
def test_capitalize():
|
||||
result = formatters.Actions.formatted_text("hello world", "CAPITALIZE")
|
||||
|
||||
assert result == "Hello world"
|
||||
|
||||
result = formatters.Actions.formatted_text(" hello world", "CAPITALIZE")
|
||||
|
||||
assert result == " Hello world"
|
||||
|
||||
result = formatters.Actions.formatted_text("hEllo wOrld", "CAPITALIZE")
|
||||
|
||||
assert result == "HEllo wOrld"
|
||||
|
||||
def test_capitalize_first_word():
|
||||
result = formatters.Actions.formatted_text(
|
||||
"hello world", "CAPITALIZE_FIRST_WORD"
|
||||
)
|
||||
|
||||
assert result == "Hello world"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
" hello world", "CAPITALIZE_FIRST_WORD"
|
||||
)
|
||||
|
||||
assert result == " Hello world"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"hEllo wOrld", "CAPITALIZE_FIRST_WORD"
|
||||
)
|
||||
|
||||
assert result == "hEllo wOrld"
|
||||
|
||||
def test_capitalize_all_words():
|
||||
result = formatters.Actions.formatted_text(
|
||||
"hello world", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "Hello World"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
" hello world", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == " Hello World"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"hEllo wOrld", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "hEllo wOrld"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"Hello to the world", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "Hello to the World"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"hello: the world", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "Hello: The World"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"down and up", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "Down and Up"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"down-and-up", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "Down-and-Up"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
"it's good they’re Bill’s friends", "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == "It's Good They’re Bill’s Friends"
|
||||
|
||||
result = formatters.Actions.formatted_text(
|
||||
'"how\'s it going?"', "CAPITALIZE_ALL_WORDS"
|
||||
)
|
||||
|
||||
assert result == '"How\'s It Going?"'
|
||||
@@ -0,0 +1,100 @@
|
||||
import talon
|
||||
|
||||
if hasattr(talon, "test_mode"):
|
||||
# Only include this when we're running tests
|
||||
from core.snippets import snippets_parser
|
||||
from core.snippets.snippet_types import SnippetVariable
|
||||
|
||||
def assert_body_with_final_stop_added_as_expected(body: str, expected: str):
|
||||
actual, _ = snippets_parser.add_final_stop_to_snippet_body(body, [])
|
||||
assert actual == expected
|
||||
|
||||
def test_stop_at_end():
|
||||
body = "import $0"
|
||||
assert_body_with_final_stop_added_as_expected(body, body)
|
||||
|
||||
def test_final_stop_not_at_end():
|
||||
body = "[$1]($0)"
|
||||
expected = "[$1]($2)$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_without_final_stop():
|
||||
body = "[$1]($2)"
|
||||
expected = "[$1]($2)$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_empty_body_unchanged():
|
||||
body = ""
|
||||
assert_body_with_final_stop_added_as_expected(body, body)
|
||||
|
||||
def test_number_inside_braces():
|
||||
body = "if (${1}){\n\t${0}}"
|
||||
expected = "if (${1}){\n\t${2}}$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_final_stop_with_default_value():
|
||||
body = "import ${0:default_value}"
|
||||
assert_body_with_final_stop_added_as_expected(body, body)
|
||||
|
||||
def test_final_stop_with_value_inside_braces():
|
||||
body = "import ${0}"
|
||||
assert_body_with_final_stop_added_as_expected(body, body)
|
||||
|
||||
def test_biggest_value_having_default():
|
||||
body = "from ${1:module} import $0;"
|
||||
expected = "from ${1:module} import $2;$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_three_stops():
|
||||
body = "[$0 for $2 in $1]"
|
||||
expected = "[$3 for $2 in $1]$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_multiple_final_stops():
|
||||
body = "[$0 for $0 in $1 if $2]"
|
||||
expected = "[$3 for $3 in $1 if $2]$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_multiple_final_stops_with_default():
|
||||
body = "[${0:nums} for ${0:nums} in $1 if $2]"
|
||||
expected = "[${3:nums} for ${3:nums} in $1 if $2]$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_multiple_final_stops_with_number_in_braces():
|
||||
body = "[${0} for ${0} in $1 if $2]"
|
||||
expected = "[${3} for ${3} in $1 if $2]$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def test_duplicate_proceeding_stops():
|
||||
body = "[$1 for $1 in $0]"
|
||||
expected = "[$1 for $1 in $2]$0"
|
||||
assert_body_with_final_stop_added_as_expected(body, expected)
|
||||
|
||||
def assert_variables_match_expected(
|
||||
body: str,
|
||||
variables: list[SnippetVariable],
|
||||
expected_variables: list[SnippetVariable],
|
||||
):
|
||||
_, actual = snippets_parser.add_final_stop_to_snippet_body(body, variables)
|
||||
assert actual == expected_variables
|
||||
|
||||
def create_snake_case_variable(name: str) -> SnippetVariable:
|
||||
return SnippetVariable(name, insertion_formatters=["snake"])
|
||||
|
||||
def test_formatting_gets_moved():
|
||||
body = "def $0:\n\treturn $1"
|
||||
variables = [create_snake_case_variable("0")]
|
||||
expected_variables = [create_snake_case_variable("2")]
|
||||
assert_variables_match_expected(body, variables, expected_variables)
|
||||
|
||||
def test_variables_unchanged_for_smaller_variable():
|
||||
body = "def $1:\n\treturn $0;"
|
||||
variables = [create_snake_case_variable("1")]
|
||||
expected_variables = [create_snake_case_variable("1")]
|
||||
assert_variables_match_expected(body, variables, expected_variables)
|
||||
|
||||
def test_variables_unchanged_with_stop_at_end():
|
||||
body = "def $1:\n\treturn $0"
|
||||
variables = [create_snake_case_variable("1")]
|
||||
expected_variables = [create_snake_case_variable("1")]
|
||||
assert_variables_match_expected(body, variables, expected_variables)
|
||||
Reference in New Issue
Block a user