diff --git a/patchdiff/pointer.py b/patchdiff/pointer.py index d088a2a..60e07bc 100644 --- a/patchdiff/pointer.py +++ b/patchdiff/pointer.py @@ -1,22 +1,16 @@ from __future__ import annotations -import re from typing import Any, Hashable, Iterable from .types import Diffable -tilde0_re = re.compile("~0") -tilde1_re = re.compile("~1") -tilde_re = re.compile("~") -slash_re = re.compile("/") - def unescape(token: str) -> str: - return tilde0_re.sub("~", tilde1_re.sub("/", token)) + return token.replace("~1", "/").replace("~0", "~") def escape(token: str) -> str: - return slash_re.sub("~1", tilde_re.sub("~0", token)) + return token.replace("~", "~0").replace("/", "~1") class Pointer: diff --git a/tests/test_pointer.py b/tests/test_pointer.py index 2c7e2ef..00eb985 100644 --- a/tests/test_pointer.py +++ b/tests/test_pointer.py @@ -1,6 +1,6 @@ import pytest -from patchdiff.pointer import Pointer +from patchdiff.pointer import Pointer, escape, unescape def test_pointer_get(): @@ -48,6 +48,34 @@ def test_pointer_append(): assert Pointer([1]).append("foo") == Pointer([1, "foo"]) +def test_escape_unescape_roundtrip(): + # ~01 is the tricky case: escape must produce ~001, not be confused with + # the RFC 6901 escape sequence ~0 followed by '1'. + tokens = [ + "", + "plain", + "has/slash", + "has~tilde", + "~/mix", + "///", + "~~~", + "~01", + ] + expected = { + "": "", + "plain": "plain", + "has/slash": "has~1slash", + "has~tilde": "has~0tilde", + "~/mix": "~0~1mix", + "///": "~1~1~1", + "~~~": "~0~0~0", + "~01": "~001", + } + for token in tokens: + assert escape(token) == expected[token] + assert unescape(escape(token)) == token + + def test_pointer_evaluate_raises_on_missing_dict_key(): with pytest.raises(KeyError): Pointer(["missing", "key"]).evaluate({"present": 1})