feat: normalize URLs without scheme to https://

- Add normalize_url() helper function in commands.py
- Automatically prefix URLs without scheme (e.g. github.com → https://github.com)
- Applies to both -link flag and auto-detected URLs
- Add 5 new tests for URL normalization
- Fix existing tests to handle 5-value return from parse_args()

Examples:
  /add Fix bug github.com/user/repo
  → stored as: https://github.com/user/repo
This commit is contained in:
shokollm
2026-04-09 10:10:06 +00:00
parent 4885be0752
commit 2158f71fd0
2 changed files with 46 additions and 15 deletions

View File

@@ -52,75 +52,97 @@ class TestExtractArgs:
class TestParseArgs:
def test_text_only(self):
text, link, due = parse_args(["hello", "world"])
text, link, due, _, _ = parse_args(["hello", "world"])
assert text == "hello world"
assert link is None
assert due is None
def test_link_extracted(self):
text, link, due = parse_args(["hello", "https://example.com"])
text, link, due, _, _ = parse_args(["hello", "https://example.com"])
# "hello" is non-link non-date → becomes text; only the URL becomes link
assert text == "hello"
assert link == "https://example.com"
assert due is None
def test_text_and_link(self):
text, link, due = parse_args(["hello", "world", "https://example.com"])
text, link, due, _, _ = parse_args(["hello", "world", "https://example.com"])
assert text == "hello world"
assert link == "https://example.com"
def test_due_date_parsed(self):
text, link, due = parse_args(["hello", "tomorrow"])
text, link, due, _, _ = parse_args(["hello", "tomorrow"])
assert text == "hello"
assert due is not None
# Should be some time in the future
assert due > int(time.time())
def test_all_three(self):
text, link, due = parse_args(["hello", "https://example.com", "tomorrow"])
text, link, due, _, _ = parse_args(["hello", "https://example.com", "tomorrow"])
assert text == "hello"
assert link == "https://example.com"
assert due is not None
def test_http_and_https_both_detected(self):
_, link1, _ = parse_args(["http://example.com"])
_, link2, _ = parse_args(["https://example.com"])
_, link1, _, _, _ = parse_args(["http://example.com"])
_, link2, _, _, _ = parse_args(["https://example.com"])
assert link1 == "http://example.com"
assert link2 == "https://example.com"
def test_non_url_non_date_becomes_text(self):
text, link, due = parse_args(["fix", "the", "bug"])
text, link, due, _, _ = parse_args(["fix", "the", "bug"])
assert text == "fix the bug"
assert link is None
assert due is None
def test_multiple_links_first_only(self):
_, link, _ = parse_args(["text", "https://first.com", "https://second.com"])
_, link, _, _, _ = parse_args(["text", "https://first.com", "https://second.com"])
assert link == "https://first.com"
def test_due_date_after_link(self):
text, link, due = parse_args(["task", "https://example.com", "in 5 days"])
text, link, due, _, _ = parse_args(["task", "https://example.com", "in 5 days"])
assert text == "task"
assert link == "https://example.com"
assert due is not None
def test_empty_args(self):
text, link, due = parse_args([])
text, link, due, _, _ = parse_args([])
assert text is None
assert link is None
assert due is None
def test_date_parser_failure_returns_none(self):
# "asdfjkl" is not parseable → goes to text
text, link, due = parse_args(["hello", "asdfjkl"])
text, link, due, _, _ = parse_args(["hello", "asdfjkl"])
assert text == "hello asdfjkl"
assert due is None
def test_link_takes_first_match(self):
# Even if it's not a valid URL, starts with https://
_, link, _ = parse_args(["skip", "https://not-real.but-still-a-link"])
_, link, _, _, _ = parse_args(["skip", "https://not-real.but-still-a-link"])
assert link == "https://not-real.but-still-a-link"
def test_url_without_scheme_normalized_to_https(self):
"""URLs without scheme should get https:// prefix."""
_, link, _, _, _ = parse_args(["github.com/user/repo"])
assert link == "https://github.com/user/repo"
def test_url_without_scheme_github_normalized(self):
text, link, _, _, _ = parse_args(["Fix bug", "github.com/owner/repo"])
assert text == "Fix bug"
assert link == "https://github.com/owner/repo"
def test_url_with_explicit_https_unchanged(self):
_, link, _, _, _ = parse_args(["task", "https://example.com/page"])
assert link == "https://example.com/page"
def test_url_with_http_unchanged(self):
_, link, _, _, _ = parse_args(["task", "http://example.com/page"])
assert link == "http://example.com/page"
def test_url_link_flag_without_scheme_normalized(self):
_, link, _, _, _ = parse_args(["-link", "example.com/path"])
assert link == "https://example.com/path"
class TestFormatBounty:
def _row(