# vi:set ts=2 sts=2 sw=2 et:
#
# Copyright (c) JD 2456730 Alex Kocharin <alex@kocharin.ru>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# The original file is available here:
# https://github.com/rlidwka/jju/tree/master/test/portable-json5-tests.yaml
#
# ----------------------------------------------------------------------------
#
# Portable JSON5 test suite.
#
# This file contains an actual YAML data and it may include fancy syntax.
# If your platform does not support YAML, you might wish to pre-process it
# using a generic YAML parser.
#

%YAML 1.2
---
#
# "input" is an arbitrary JSON5 you have to parse
# "output" is a normalized JSON you have to compare your result with,
#          or !error (null) if your input should result in parser error
#
# Types of tests:
#
#  - basic    - Tests that every JSON5 parser should pass.
#
#  - advanced - Tests that bring close compatibility with javascript. Not
#               strictly required, but nice to have for completeness.
#
#  - extra    - Extra test cases you can follow at your discretion.
#
# Questionable features like elisions go to extra. All valid javascript, but
# invalid json5 also goes to extra. Feel free to ignore this section if you
# want to. Thus, eval(input) is a complete json5 parser, that should pass all
# basic and advanced tests.
#

# Basic types in minimal form
# ---------------------------

type-no-data:
  type: extra
  output: !error
  input: ''

type-null:
  type: basic
  output: null
  input: >
    null

# undefined is not supported,
# null should be used instead
type-no-undefined:
  type: extra
  output: !error
  input: >
    undefined

type-no-raw:
  type: extra
  output: !error
  input: >
    foobar

type-bool-true:
  type: basic
  output: true
  input: >
    true

type-bool-false:
  type: basic
  output: false
  input: >
    false

type-number:
  type: basic
  output: 0
  input: >
    0

type-string:
  type: basic
  output: ""
  input: >
    ""

type-object:
  type: basic
  output: {}
  input: >
    {}

type-array:
  type: basic
  output: []
  input: >
    []

# Numbers: special
# ----------------

# note: it's hard to test this
# just add `1/x < 0` check in your code somewhere
num-negative-zero:
  type: extra
  output: -0.0
  input: >
    -0

num-nan:
  type: basic
  output: .nan
  input: >
    NaN

num-signed-nan:
  type: basic
  output: .nan
  input: >
    +NaN

num-positive-inf:
  type: basic
  output: +.inf
  input: >
    Infinity

num-negative-inf:
  type: basic
  output: -.inf
  input: >
    -Infinity

num-inf-exact-case:
  type: extra
  output: !error
  input: >
    INFINITY

# Numbers: hexadecimal
# --------------------

num-hex-zero:
  type: basic
  output: 0
  input: >
    0x0

num-cut-hex:
  type: basic
  output: !error
  input: >
    0x

num-all-hex:
  type: basic
  output: 12841684683518
  input: >
    0xBADF00DCAFE

num-mixed-case:
  type: basic
  output: 3735928559
  input: >
    0xDeAdBEef

num-signed-hex:
  type: advanced
  output: 31
  input: >
    +0x1F

num-negative-hex:
  type: advanced
  output: -31
  input: >
    -0x1f

num-bad-hex:
  type: advanced
  output: !error
  input: >
    0xBADxF00D

num-no-hex-float:
  type: advanced
  output: !error
  input: >
    0x12.345

# this is not actually an exponent :)
num-hex-exponent:
  type: advanced
  output: 4836
  input: >
    0x0012e4

# Numbers: octal
# --------------

# Octals are primarily used in config files
# to set up a file mask (like 0777)
#
# Note: they will have 0o12345 syntax instead
# of 012345 in the ES6, so we'll need to switch
# as well in the future

num-octal:
  type: extra
  output: 342391
  input: >
    01234567

num-octal-zeroes:
  type: extra
  output: -24000
  input: >
    -000000056700

num-bad-octal:
  type: extra
  output: !error
  input: >
    012345678

num-no-octal-float:
  type: extra
  output: !error
  input: >
    012.345

num-no-octal-exp:
  type: extra
  output: !error
  input: >
    0123e4

# Numbers: floating point
# -----------------------

num-float:
  type: basic
  output: 123.456
  input: >
    123.456

num-signed-foat:
  type: basic
  output: -0.00098765
  input: >
    -0.00098765

num-omit-trailing-mantissa:
  type: basic
  output: 1234000
  input: >
    1234.e3

num-omit-leading-mantissa:
  type: advanced
  output: -123.4
  input: >
    -.1234e3

num-bad-float:
  type: advanced
  output: !error
  input: >
    0.12.345

num-bad-sum:
  type: extra
  output: !error
  input: >
    0.12+345

num-uc-exp:
  type: advanced
  output: -1230000
  input: >
    -123E+4

num-float-exp:
  type: basic
  output: 123000
  input: >
    0.0123e7

num-bad-exp:
  type: extra
  output: !error
  input: >
    123e7.3

num-bad-char:
  type: extra
  output: !error
  input: >
    123a456

num-no-exp:
  type: advanced
  output: !error
  input: >
    123e

num-zero-exp:
  type: advanced
  output: -0.0
  input: >
    -.00e-0

num-dec-base-signed-exp:
  type: advanced
  output: 0.00000123
  input: >
    1230000E-012

# String: quotes
# --------------

string-double-quotes:
  type: basic
  output: foobar
  input: >
    "foobar"

string-single-quotes:
  type: basic
  output: foobar
  input: >
    'foobar'

string-open:
  type: basic
  output: !error
  input: >
    "\\\\\\\\\\\\\"

string-not-open:
  type: basic
  output: "\\\\\\\\\\\\\\"
  input: >
    "\\\\\\\\\\\\\\"

string-continuation:
  type: advanced
  output: "  foo    bar   "
  input: >
    "  foo \
       bar \
      "

string-win-continuation:
  type: advanced
  output: "foobar"
  input: "'foo\\\r\nbar'"

string-win-reverse-continuation:
  type: advanced
  output: !error
  input: "'foo\\\n\rbar'"

string-unicode-continuation:
  type: advanced
  output: "foobarbaz"
  input: "'foo\\\u2028bar\\\u2029baz'"

string-multi-bad-continuation:
  type: advanced
  output: !error
  input: >
    foo\

    bar

string-bad-ending:
  type: basic
  output: !error
  input: "'foo\rbar'"

string-bad-ending-2028:
  type: advanced
  output: !error
  input: "'foo\u2028bar'"

string-bad-ending-2029:
  type: advanced
  output: !error
  input: "'foo\u2029bar'"

string-literal-unicode:
  type: advanced
  output: "foo\uFEFF\u2030bar\u1234"
  input: "'foo\uFEFF\u2030bar\u1234'"

string-control-char:
  type: advanced
  output: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f"
  input: "'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f'"

# String: escape sequences
# ------------------------

string-octal-escape:
  type: extra
  output: "\x1b[1;32mhi\x1b[m??"
  input: >
    '\033[1;32mhi\033[m\077\077'

string-octal-two-digits:
  type: extra
  output: "\n\x1c\x2e\x07890\x01"
  input: >
    '\12\34\56\78\90\1'

string-octal-three-digits:
  type: extra
  output: "\n34.78\xff 0"
  input: >
    '\01234\5678\377\400'

string-hex-escape:
  type: extra
  output: "\x01\x23\xab\xcd\xef"
  input: >
    "\x01\x23\xab\xCd\xEF"

# \0 is *not* an octal escape sequence,
# and is allowed even in strict mode
string-zero-point:
  type: basic
  output: "\0"
  input: >
    '\0'

string-escape-double-quotes:
  type: basic
  output: "\"''"
  input: >
    "\"'\'"

string-escape-single-quotes:
  type: basic
  output: "   '\"\"   "
  input: >
    '   \'"\"   '

string-escape-json-chars:
  type: basic
  output: "\\\/\b\f\n\r\t"
  input: >
    "\\\/\b\f\n\r\t"

# this character was left out of
# json spec for whatever reason
string-escape-slash-v:
  type: basic
  output: "\v"
  input: >
    "\v"

string-unicode-escape:
  type: basic
  output: "\u0000\uffffx\ufeff\u1234\u9f6a\u2028\uabcd"
  input: >
    "\u0000\uFFFFx\uFeFf\u1234\u9F6a\u2028\uabcd"

string-arbitrary-escape:
  type: advanced
  output: "X12Uqwe\r\tyiopasd\fghjklzc\u000b\b\nm9 "
  input: >
    '\X12\U\q\w\e\r\t\y\i\o\p\a\s\d\f\g\h\j\k\l\z\c\v\b\n\m\9\ '

string-bad-unicode:
  type: advanced
  output: !error
  input: >
    '\uEFGH'

string-incomplete-unicode:
  type: advanced
  output: !error
  input: >
    '\u$'

string-bad-hex:
  type: advanced
  output: !error
  input: >
    '\xFG'

string-incomplete-hex:
  type: advanced
  output: !error
  input: >
    '\x$'

# Object literals
# ---------------

object-nested:
  type: basic
  output: {q:{'w':{"e":[1]}}}
  input: |
    {q:{'w':{"e":[1]}}}

object-trailing-comma:
  type: basic
  output: {foo: 'bar'}
  input: |
    {foo: 'bar',}

object-leading-comma-style:
  type: basic
  output: {q: 1,w: 2,e: 3}
  input: |
    { q: 1
    , w: 2
    , e: 3
    }

object-incomplete:
  type: basic
  output: !error
  input: |
    {q:1,w:2,{}

object-isnt-array:
  type: basic
  output: !error
  input: |
    {1,2}

object-no-single-comma:
  type: basic
  output: !error
  input: |
    {,}

object-no-elisions:
  type: basic
  output: !error
  input: |
    {q:1,,w:2}

# Objects: keys
# -------------

object-singlequoted:
  type: basic
  output: {q: 1,w: 2,e: 3}
  input: |
    {'q':1,'w':2,'e':3}

object-doublequoted:
  type: basic
  output: {q: 1,w: 2,e: 3}
  input: |
    {"q":1,"w":2,"e":3}

object-unquoted:
  type: basic
  output: {$FOO_bar123: 'baz'}
  input: >
    {$FOO_bar123: 'baz'}

object-no-first-digit:
  type: advanced
  output: !error
  input: >
    {123foo: bar}

object-unquoted-unicode:
  type: advanced
  output: {"\u1f04\u03bb\u03c6\u03b1": baz}
  input: "{\u1f04\u03bb\u03c6\u03b1:'baz'}"

object-unicode-escape-key:
  type: advanced
  output: {foo: 'bar', "\u1f04\u03bb\u03c6\u03b1": baz, "qwe\u1f04rty": quux}
  input: |
    {foo:'bar', \u1f04\u03bb\u03c6\u03b1:'baz', qwe\u1f04rty: "quux"}

object-no-raw-literal:
  type: extra
  output: !error
  input: |
    {foo: bar}

object-bad-literal:
  type: advanced
  output: !error
  input: |
    {foo-bar: 123}

object-no-space-in-key:
  type: advanced
  output: !error
  input: |
    {foo bar: 123}

object-no-comment-in-key:
  type: advanced
  output: !error
  input: |
    {foo/*bar*/baz: 123}

object-float-keys:
  type: advanced
  output: {'1': 'one', '3.1415': 'pi'}
  input: |
    {1:'one', 3.1415:'pi'}

object-no-negative:
  type: advanced
  output: !error
  input: |
    {-5: 123}

object-exponent-keys:
  type: advanced
  output: {'1': 'exp', '1000': 'pos', '0.001': 'neg'}
  input: |
    {1e0: 'exp', 1e+3: 'pos', 1e-3: 'neg'}

object-octal-keys:
  type: extra
  output: {'668': 1}
  input: |
    {01234: 1}

object-hex-keys:
  type: advanced
  output: {'51966': 1}
  input: |
    {0xCAFE: 1}

object-null-keys:
  type: basic
  output: {'null': null}
  input: |
    {null: null}

object-no-array-keys:
  type: extra
  output: !error
  input: |
    {[]: 123}

object-no-empty-keys:
  type: basic
  output: !error
  input: |
    {: 123}

object-empty-string-key:
  type: basic
  output: {s: {'': 1}, m: {'': 2}}
  input: |
    {s: {'': 1}, m: {"": 2}}

object-bad-unicode-space:
  type: advanced
  output: !error
  input: |
    { \u0020foobar: 123 }

object-bad-unicode-dash:
  type: advanced
  output: !error
  input: |
    { foo\u002dbar: 123}

object-incomplete-unicode-sequence:
  type: advanced
  output: !error
  input: |
    { foo\u12f: 123 }

object-double-escape:
  type: advanced
  output: !error
  input: |
    { foo\\u1234bar: 123 }

object-we-arent-es3:
  type: basic
  output: {new: 1, delete: 2, throw: 3}
  input: |
    {new: 1, delete: 2, throw: 3}

object-last-digits:
  type: basic
  output: {$123e2: 1, abc123: 2}
  input: |
    {$123e2: 1, abc123: 2}

object-unicode-in-string:
  type: advanced
  output: {"\uff13qwe": 123}
  input: |
    {"\uff13qwe": 123}

object-unicode-esc-in-string:
  type: advanced
  output: {"\\uff13qwe": 123}
  input: |
    {"\\uff13qwe": 123}

object-unicode-digits-first-esc:
  type: advanced
  output: !error
  input: |
    {\uff13qwe: 123}

object-unicode-digits-first-lit:
  type: advanced
  output: !error
  input: "{\uff13qwe: 123}"

object-unicode-weirdness-esc:
  type: advanced
  output: {"digit\uff13": 1, "comb\u094F": 2, "punct\u2040": 3, "zwnj\u200C": 4}
  input: |
    {digit\uff13: 1, comb\u094F: 2, punct\u2040: 3, zwnj\u200C: 4}

object-unicode-weirdness-lit:
  type: advanced
  output: {"digit\uff13": 1, "comb\u094F": 2, "punct\u2040": 3, "zwnj\u200C": 4}
  input: "{digit\uff13: 1, comb\u094F: 2, punct\u2040: 3, zwnj\u200C: 4}"

# Array literals
# --------------

array-all-types:
  type: basic
  output: [1.2,"3,4",{},[],null,+.inf]
  input: |
    [1.2,"3,4",{},[],null,Infinity]

array-trailing-comma:
  type: basic
  output: [1,2,3,4]
  input: |
    [1,2,3,4,]

array-leading-comma-style:
  type: basic
  output: [quux,foo,bar,baz]
  input: |
    [ 'quux'
    , 'foo'
    , 'bar'
    , 'baz'
    ]

array-incomplete:
  type: basic
  output: !error
  input: |
    [1,2,3,[]

array-nested:
  type: basic
  output: [[[[[[]]]]],[[],[]]]
  input: |
    [[[[[[/*[]*/]]]]],[[],[]]]

array-isnt-object:
  type: extra
  output: !error
  input: |
    [1:2]

array-no-single-comma:
  type: extra
  output: !error
  input: |
    [,]

array-no-elisions:
  type: extra
  output: !error
  input: |
    [1,,2,3]

# Comments
# --------

comment-single:
  type: basic
  output: foobar
  input: |
    // blahblah
    "foobar"
    // another one

comment-multi:
  type: basic
  output: foobar
  input: |
    /*
     * 123
     */
    "foobar"
    /**/

comment-single-newlines:
  type: advanced
  output: [ 123, 456, 789 ]
  input: "[// foo\r123,// bar\u2028456,// baz\u2029789]"

comment-inside:
  type: advanced
  output: [123, '// foo', '/* bar']
  input: >
    [
      /*
      " // */ 123, // ",
      "// foo",
      '/* bar',
    ]

comment-in-token:
  type: advanced
  output: !error
  input:
    123/*comment*/456

comment-java-style:
  type: basic
  output: 123
  input:
    /*****************/
    123
    /****************/

comment-object:
  type: basic
  output: {q: 123}
  input: /**/{/**/q/**/:/**/123/**/,/**/}//

# Whitespace
# ----------

ws-no-whitespace:
  type: basic
  output: {"foo":bar,bar:["qwe",null,[],{}],"baz":123}
  input: '{foo:"bar","bar":["qwe",null,[],{}],"baz":123}'

ws-allow-prefix:
  type: basic
  output: 123
  input: " \t123"

ws-unicode-spaces:
  type: advanced
  output: { foo : 123 }
  input: "
    \u0020\u00A0\uFEFF
    {
    \x09\x0A\x0B\x0C\x0D\u1680\u180E
      foo
    \u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A
      :
    \u2028\u2029\u202F\u205F\u3000
      123
    \uFEFF
    }"

ws-unicode-newlines:
  type: advanced
  output: [ 123, 456 ]
  input: "
    [
      \u000D
      123,
      \u2028
      456,
      \u2029
    ]
    "

# Multiple tokens
# ---------------

multi-string-nospace:
  type: basic
  output: !error
  input: '"foo""bar"'

multi-string:
  type: basic
  output: !error
  input: '"foo" "bar"'

# note: valid javascript
multi-array:
  type: extra
  output: !error
  input: '[0] [0]'

multi-object:
  type: basic
  output: !error
  input: '{} {}'
...
