{
  "schema": "https://kpointer.commonsware.com/conformance/syntax/parsing.schema.json",
  "version": "0.2.0",
  "cases": [
    {
      "name": "root-from-rfc6901",
      "description": "Empty string is the root pointer in RFC 6901 format.",
      "input": "",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "",
        "fragment": "#",
        "jsPath": "",
        "depth": 0,
        "isRoot": true
      }
    },
    {
      "name": "simple-key-from-rfc6901",
      "description": "Single-segment RFC 6901 pointer.",
      "input": "/foo",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/foo",
        "fragment": "#/foo",
        "jsPath": "foo",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "two-segments-from-rfc6901",
      "description": "Two-segment RFC 6901 pointer.",
      "input": "/foo/bar",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/foo/bar",
        "fragment": "#/foo/bar",
        "jsPath": "foo.bar",
        "depth": 2,
        "isRoot": false
      }
    },
    {
      "name": "empty-segment-key",
      "description": "A single slash '/' is a one-segment pointer whose only segment is the empty string \u2014 not the root pointer.",
      "input": "/",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/",
        "fragment": "#/",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "trailing-slash-two-segments",
      "description": "/foo/ splits into two segments \u2014 'foo' and '' (the empty string) \u2014 not one.",
      "input": "/foo/",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/foo/",
        "fragment": "#/foo/",
        "depth": 2,
        "isRoot": false
      }
    },
    {
      "name": "tilde-zero-escape",
      "description": "~0 decodes to literal tilde in the segment.",
      "input": "/a~0b",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/a~0b",
        "fragment": "#/a~0b",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "tilde-one-escape",
      "description": "~1 decodes to literal slash in the segment.",
      "input": "/a~1b",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/a~1b",
        "fragment": "#/a~1b",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "tilde-zero-one-ordering",
      "description": "~01 is ~0 followed by literal 1, so it decodes to ~1 (tilde then one) \u2014 never to / (which would require ~1).",
      "input": "/a~01b",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/a~01b",
        "fragment": "#/a~01b",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "root-from-fragment",
      "description": "Fragment '#' with no path is the root pointer.",
      "input": "#",
      "encoding": "fragment",
      "expect": {
        "type": "success",
        "rfc6901": "",
        "fragment": "#",
        "jsPath": "",
        "depth": 0,
        "isRoot": true
      }
    },
    {
      "name": "simple-key-from-fragment",
      "description": "Fragment with a single unencoded segment.",
      "input": "#/foo",
      "encoding": "fragment",
      "expect": {
        "type": "success",
        "rfc6901": "/foo",
        "fragment": "#/foo",
        "jsPath": "foo",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "percent-encoded-fragment",
      "description": "Fragment segment with percent-encoded UTF-8 bytes.",
      "input": "#/f%C3%B6%C3%B6",
      "encoding": "fragment",
      "expect": {
        "type": "success",
        "rfc6901": "/f\u00f6\u00f6",
        "fragment": "#/f%C3%B6%C3%B6",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "percent-encoded-fragment-multi-segment",
      "description": "Percent-encoded UTF-8 bytes in multiple segments of a fragment pointer are each decoded independently.",
      "input": "#/f%C3%B6%C3%B6/%C3%A9",
      "encoding": "fragment",
      "expect": {
        "type": "success",
        "rfc6901": "/f\u00f6\u00f6/\u00e9",
        "fragment": "#/f%C3%B6%C3%B6/%C3%A9",
        "depth": 2,
        "isRoot": false
      }
    },
    {
      "name": "root-from-js-path",
      "description": "The empty string is the root pointer in JavaScript access path notation.",
      "requiresCapability": "jsPath",
      "input": "",
      "encoding": "jsPath",
      "expect": {
        "type": "success",
        "rfc6901": "",
        "fragment": "#",
        "jsPath": "",
        "depth": 0,
        "isRoot": true
      }
    },
    {
      "name": "simple-key-from-js-path",
      "description": "A single identifier is a one-segment pointer in JavaScript access path notation.",
      "requiresCapability": "jsPath",
      "input": "foo",
      "encoding": "jsPath",
      "expect": {
        "type": "success",
        "rfc6901": "/foo",
        "fragment": "#/foo",
        "jsPath": "foo",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "two-segments-from-js-path",
      "description": "Dot-separated identifiers become a two-segment pointer.",
      "requiresCapability": "jsPath",
      "input": "foo.bar",
      "encoding": "jsPath",
      "expect": {
        "type": "success",
        "rfc6901": "/foo/bar",
        "fragment": "#/foo/bar",
        "jsPath": "foo.bar",
        "depth": 2,
        "isRoot": false
      }
    },
    {
      "name": "auto-dispatch-rfc6901",
      "description": "Auto-dispatch chooses RFC 6901 when input starts with '/'.",
      "input": "/x",
      "encoding": "auto",
      "expect": {
        "type": "success",
        "rfc6901": "/x",
        "fragment": "#/x",
        "jsPath": "x",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "auto-dispatch-fragment",
      "description": "Auto-dispatch chooses fragment when input starts with '#'.",
      "input": "#/x",
      "encoding": "auto",
      "expect": {
        "type": "success",
        "rfc6901": "/x",
        "fragment": "#/x",
        "jsPath": "x",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "auto-dispatch-js-path",
      "description": "Auto-dispatch falls back to JavaScript access path notation for anything else.",
      "requiresCapability": "jsPath",
      "input": "x",
      "encoding": "auto",
      "expect": {
        "type": "success",
        "rfc6901": "/x",
        "fragment": "#/x",
        "jsPath": "x",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "error-rfc6901-no-leading-slash",
      "description": "RFC 6901 strings must start with '/' (or be empty).",
      "input": "no-leading-slash",
      "encoding": "rfc6901",
      "expect": {
        "type": "error",
        "errorCode": "KP-1001"
      }
    },
    {
      "name": "error-fragment-no-hash",
      "description": "Fragment strings must start with '#'.",
      "input": "/foo",
      "encoding": "fragment",
      "expect": {
        "type": "error",
        "errorCode": "KP-1002"
      }
    },
    {
      "name": "error-js-path-empty-segment",
      "description": "Trailing dot in a JavaScript access path produces an empty segment and must be rejected.",
      "requiresCapability": "jsPath",
      "input": "foo.",
      "encoding": "jsPath",
      "expect": {
        "type": "error",
        "errorCode": "KP-1004"
      }
    },
    {
      "name": "error-fragment-malformed-percent-encoding",
      "description": "A truncated or invalid %XX sequence in a fragment is rejected.",
      "input": "#%zz",
      "encoding": "fragment",
      "expect": {
        "type": "error",
        "errorCode": "KP-1003"
      }
    },
    {
      "name": "error-tilde-invalid-escape",
      "description": "'~' followed by anything other than '0' or '1' is not a valid RFC 6901 escape sequence.",
      "input": "/a~2b",
      "encoding": "rfc6901",
      "expect": {
        "type": "error",
        "errorCode": "KP-1005"
      }
    },
    {
      "name": "error-tilde-trailing",
      "description": "A trailing '~' with no following character is not a valid RFC 6901 escape sequence.",
      "input": "/a~",
      "encoding": "rfc6901",
      "expect": {
        "type": "error",
        "errorCode": "KP-1005"
      }
    },
    {
      "name": "non-ascii-bmp-key",
      "description": "A segment made of BMP non-ASCII characters (CJK) is stored and round-tripped verbatim, never transcoded or normalized.",
      "input": "/中文",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/中文",
        "fragment": "#/%E4%B8%AD%E6%96%87",
        "jsPath": "中文",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "astral-key-emoji",
      "description": "A segment containing an astral-plane character (represented as a UTF-16 surrogate pair) round-trips through RFC 6901, fragment percent-encoding of its 4-byte UTF-8 form, and dot notation without splitting the surrogate pair.",
      "input": "/😀",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/😀",
        "fragment": "#/%F0%9F%98%80",
        "jsPath": "😀",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "percent-encoded-fragment-astral",
      "description": "A fragment whose percent-encoded bytes decode to an astral-plane character (a 4-byte UTF-8 sequence) reassembles the correct UTF-16 surrogate pair.",
      "input": "#/%F0%9F%98%80",
      "encoding": "fragment",
      "expect": {
        "type": "success",
        "rfc6901": "/😀",
        "fragment": "#/%F0%9F%98%80",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "nfc-precomposed-key",
      "description": "A precomposed (NFC) accented letter is one code point and must not be normalized to or conflated with its decomposed (NFD) equivalent — see nfd-decomposed-key.",
      "input": "/é",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/é",
        "fragment": "#/%C3%A9",
        "jsPath": "é",
        "depth": 1,
        "isRoot": false
      }
    },
    {
      "name": "nfd-decomposed-key",
      "description": "A base letter followed by a combining acute accent (NFD, two code points) is a distinct segment string from the precomposed nfc-precomposed-key case — implementations must not normalize either form.",
      "input": "/é",
      "encoding": "rfc6901",
      "expect": {
        "type": "success",
        "rfc6901": "/é",
        "fragment": "#/e%CC%81",
        "jsPath": "é",
        "depth": 1,
        "isRoot": false
      }
    }
  ]
}
