init commit

This commit is contained in:
unknown
2025-08-19 08:06:37 -04:00
commit 2957b5515a
743 changed files with 45495 additions and 0 deletions
+3
View File
@@ -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.
+215
View File
@@ -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
+11
View File
@@ -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()
+165
View File
@@ -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
+58
View File
@@ -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"
+109
View File
@@ -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 theyre Bills friends", "CAPITALIZE_ALL_WORDS"
)
assert result == "It's Good Theyre Bills 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)