Skip to content

Commit 3a786f3

Browse files
committed
test: add edge-case coverage for literal handling and anchoring
Ports three test scenarios from the TypeScript SDK: - Repeated-slash literals (///{a}////{b}////) preserved exactly and rejected when slash count differs - Trailing extra path component rejected (/users/{id} vs /users/123/extra); guards against a refactor from fullmatch to match or search - Adjacent variables with prefix-overlapping names ({var}{vara}); documents the greedy capture split and confirms positional groups map to the correct dict keys
1 parent 3b8aadd commit 3a786f3

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

tests/shared/test_uri_template.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ def test_expand_rejects_invalid_value_types(value: object):
345345
("/files{/path*}/edit", "/files/a/b/edit", {"path": ["a", "b"]}),
346346
# Explode: labels
347347
("host{.labels*}", "host.example.com", {"labels": ["example", "com"]}),
348+
# Repeated-slash literals preserved exactly
349+
("///{a}////{b}////", "///x////y////", {"a": "x", "b": "y"}),
348350
],
349351
)
350352
def test_match(template: str, uri: str, expected: dict[str, str | list[str]]):
@@ -359,12 +361,29 @@ def test_match(template: str, uri: str, expected: dict[str, str | list[str]]):
359361
("file{.ext}", "file"),
360362
("search{?q}", "search"),
361363
("static", "different"),
364+
# Anchoring: trailing extra component must not match. Guards
365+
# against a refactor from fullmatch() to match() or search().
366+
("/users/{id}", "/users/123/extra"),
367+
("/users/{id}/posts/{pid}", "/users/1/posts/2/extra"),
368+
# Repeated-slash literal with wrong slash count
369+
("///{a}////{b}////", "//x////y////"),
362370
],
363371
)
364372
def test_match_no_match(template: str, uri: str):
365373
assert UriTemplate.parse(template).match(uri) is None
366374

367375

376+
def test_match_adjacent_vars_with_prefix_names():
377+
# Two adjacent simple vars where one name is a prefix of the other.
378+
# We use positional capture groups, so names only affect the result
379+
# dict keys, not the regex. Standard greedy matching: the first var
380+
# takes as much as it can while still letting the second satisfy +.
381+
t = UriTemplate.parse("{var}{vara}")
382+
assert t.match("ab") == {"var": "a", "vara": "b"}
383+
assert t.match("abc") == {"var": "ab", "vara": "c"}
384+
assert t.match("abcd") == {"var": "abc", "vara": "d"}
385+
386+
368387
def test_match_decodes_percent_encoding():
369388
t = UriTemplate.parse("file://docs/{name}")
370389
assert t.match("file://docs/hello%20world.txt") == {"name": "hello world.txt"}

0 commit comments

Comments
 (0)