# file      : tests/type/json/testscript
# license   : MIT; see accompanying LICENSE file

# See also tests in function/json/.

.include ../../common.testscript

: basics
:
{{
  : empty-null
  :
  $* <<EOI >>EOO
  print ([json, null] ) # Note: "our" NULL.
  print ([json] null)
  print ([json] )
  print ([json] "")
  print ([json_array] )
  print ([json_object] )
  print ([json] one@null)
  print ([json_object] one) # Absent pair value (null).
  print ([json] one@1 two)  # Ditto.
  print ([json] one@)       # Empty pair value (empty string).
  print ([json] one@"")     # Empty pair value (empty string).
  EOI
  [null]
  null
  null
  ""
  []
  {}
  {"one":null}
  {"one":null}
  {"one":1,"two":null}
  {"one":""}
  {"one":""}
  EOO

  : reverse
  :
  $* <<EOI >>EOO
  print ([json] null)
  print [string] ([json] null)
  print ([json] true)
  print ([json] 123)
  print ([json] -123)
  print ([json] 0xdecaf)
  print ([json] -0xdecaf)
  print ([json] abc)
  print ([json] '"abc"')
  print ([json] "'abc'")
  print ([string] ([json] abc)) # Strip JSON syntax (unquoted).
  print ([json] dir/{file1 file2})
  print ([json] '  ["dir/file1", "dir/file2"]  ')
  print ([json] zero@null one@1 two@abc three@([json] x@123 y@-123) four@([json] null true))
  print ([json] '{"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]}')
  EOI
  null

  true
  123
  -123
  0xdecaf
  -0xdecaf
  "abc"
  "abc"
  "abc"
  abc
  ["dir/file1","dir/file2"]
  ["dir/file1","dir/file2"]
  {"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]}
  {"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]}
  EOO


  : hex
  :
  $* <<EOI >>EOO
  print ([json] 0xffffFFFF)

  print ([json] 0x0 0x01 0xff 0xFFFF)
  print ([json] ff@0xff FFFF@0xFFFF)
  print ([json] '{ff: 0xff, FFFF: -0xFFFF}')

  # Note: we have to explicitly "cast back" to JSON since subscript by
  # default returns simple JSON value converted to the corresponding
  # simple types.
  #
  j = [json] ff@0xff
  print $value_type([json] $j[ff], true)
  j = [json] '{ff: -0xff}'
  print $value_type([json] $j[ff], true)

  j = [json] '[0xff]'
  for i [json]: $j
    print $value_type($i, true)

  j = [json] '{x:"null"}'
  print [json] $member_value($j)
  EOI
  0xffffffff
  [0x0,0x1,0xff,0xffff]
  {"ff":0xff,"FFFF":0xffff}
  {"ff":0xff,"FFFF":-0xffff}
  hexadecimal unsigned number
  hexadecimal signed number
  hexadecimal unsigned number
  "null"
  EOO

  : json5
  :
  $* <<EOI >>EOO
  print ([json] "
  {
    'single-quoted': 'abc',
    'multi-line': 'a\\
  b\\
  c',
    unquoted: 0xff, // Trailing comma, and this is a comment.
  }
  ")

  n = 123
  s = abc
  print ([json] "{number:$n, string:'$s'}")
  EOI
  {"single-quoted":"abc","multi-line":"abc","unquoted":0xff}
  {"number":123,"string":"abc"}
  EOO

  : json5e
  :
  $* <<EOI >>EOO
  print ([json] "
  {
    un-quoted: 0xff
    newline.separated: 123
  }
  ")
  EOI
  {"un-quoted":0xff,"newline.separated":123}
  EOO

  : diagnostics-reverse-invalid
  :
  $* <<EOI 2>>EOE != 0
  o = [json] '{"one":1, "two":}'
  EOI
  error: invalid json value in variable o: invalid json input: unexpected '}' in value
    <stdin>:1:5: info: variable o value is assigned here
  EOE

  : diagnostics-duplicate-member
  :
  $* <<EOI 2>>EOE != 0
  o = [json] one@1 one@2
  EOI
  error: invalid json value in variable o: duplicate json object member 'one'
    <stdin>:1:5: info: variable o value is assigned here
  EOE
}}

: compare
:
{{
  : type
  :
  $* <<EOI >>EOO
  print (([json] null) < ([json] true))
  print (([json] true) < ([json] 0))
  print (([json] 123)  < ([json] '"0"'))
  print (([json] abc)  < ([json] xxx yyy))
  print (([json] xxx yyy)  < ([json] xxx@null yyy@null))
  EOI
  true
  true
  true
  true
  true
  EOO

  : simple
  :
  $* <<EOI >>EOO
  print (([json] false) == ([json] false))
  print (([json] false) <  ([json] true))

  print (([json] 123)  == ([json] 123))
  print (([json] -123) == ([json] -123))
  print (([json] 0xff) == ([json] 255))
  print (([json] 0)    == ([json] -0))
  print (([json] -1)   <  ([json] 0))
  print (([json] 123)  <  ([json] 234))
  print (([json] -234) <  ([json] -123))

  print (([json] abc) == ([json] abc))
  print (([json] abc) <  ([json] abz))
  print (([json] abc) <  ([json] abcd))
  EOI
  true
  true
  true
  true
  true
  true
  true
  true
  true
  true
  true
  true
  EOO

  : array
  :
  $* <<EOI >>EOO
  print (([json] 1 2 3) == ([json] 1 2 3))
  print (([json] 1 2 3) <  ([json] 1 2 4))
  print (([json] 1 2 3) <  ([json] 1 2 3 4))
  EOI
  true
  true
  true
  EOO

  : object
  :
  $* <<EOI >>EOO
  print (([json] one@1 two@2 three@3) == ([json] three@3 one@1 two@2))
  print (([json] one@1 two@2 three@3) <  ([json] three@3 one@1 two@4))
  print (([json] one@1       three@3) <  ([json] three@3 one@1 two@2))
  EOI
  true
  true
  true
  EOO
}}

: append-prepend
:
{{
  : array
  :
  $* <<EOI >'[0,1,2,3,4,5,6,7,8]'
  a = [json] 2 3
  a += 4
  a += 5 6
  a += [json] 7 8
  a =+ [json] 0 1
  print $a
  EOI

  : array-type
  :
  $* <<EOI >'[1,2,3,4,5]'
  [json_array] a =
  a += 1
  a += 2 3
  a += [json_array] 4 5 # @@ Should be possible to use json.
  print $a
  EOI

  : object
  :
  $* <<EOI >'{"zero":0,"one":6,"two":8,"three":3,"four":4,"five":5,"seven":7}'
  o = [json] one@1 two@2 three@3
  o += four@4
  o += five@5 one@6
  o += [json] seven@7 two@8
  o =+ [json] zero@0 three@9
  print $o
  EOI

  : object-type
  :
  $* <<EOI >'{"one":1,"two":2,"three":3,"four":4,"five":5}'
  [json_object] o =
  o += one@1
  o += two@2 three@3
  o += [json_object] four@4 five@5 # @@ Should be possible to use json.
  print $o
  EOI

  : boolean
  :
  $* <<EOI >>EOO
  b = [json] false
  b += [json] true
  print $b
  EOI
  true
  EOO

  : number
  :
  $* <<EOI >>EOO
  n = [json] -2
  print $value_type($n, true) $n
  n += 1
  print $value_type($n, true) $n
  n += 1
  print $value_type($n, true) $n
  n += 1
  print $value_type($n, true) $n
  n += [json] -1
  print $value_type($n, true) $n
  n += [json] -1
  print $value_type($n, true) $n
  EOI
  signed number -2
  signed number -1
  unsigned number 0
  unsigned number 1
  unsigned number 0
  signed number -1
  EOO

  : string
  :
  $* <<EOI >>EOO
  s = [json] yyy
  s += [json] zzz
  s =+ [json] xxx
  print $s
  EOI
  "xxxyyyzzz"
  EOO

  : invalid
  :
  $* <<EOI 2>>EOE != 0
  a = [json] 1 2 3
  s = [json] str
  s += $a
  print $s
  EOI
  error: invalid json value in variable s: unable to append array to string
    <stdin>:3:6: info: variable s value is assigned here
  EOE
}}

: subscript
:
{{
  : null
  :
  $* <<EOI >>EOO
  j = [json] null
  print ($j[0])
  print ($j[one])
  EOI
  [null]
  [null]
  EOO

  : array
  :
  $* <<EOI >>EOO
  j = [json] 1 2 3 null
  print ($j[1])
  print ($j[3])
  print ($j[4])
  EOI
  2
  [null]
  [null]
  EOO

  : object-name
  :
  $* <<EOI >>EOO
  j = [json] one@1 two@2 three@3 four@null
  print ($j[two])
  print ($j[four])
  print ($j[five])
  EOI
  2
  [null]
  [null]
  EOO

  : object-index
  :
  $* <<EOI >>EOO
  j = [json] one@1 two@2 three@3
  print ($j[([uint64] 1)])
  EOI
  {"two":2}
  EOO

  : nested
  :
  $* <<EOI >>EOO
  o = [json] one@([json] 1 2 ([json] a@3 b@4) null) two@([json] x@x y@([json] 5 6))
  print ($o[one][1])
  print ($o[one][2][b])
  print ($o[two][y][1])
  print ($o[two][bogus][junk])
  print ($o[two][bogus][junk][garbage])
  print ($o[one][3][junk]) # JSON null
  print ($o[one][3][junk][garbage])

  a = [json] ([json] one@1 two@([json] 2 3)) ([json] 4 5) null
  print ($a[0][one])
  print ($a[0][two][1])
  print ($a[1][1])
  print ($a[1][123][junk])
  print ($a[1][123][junk][garbage])
  print ($a[2][junk]) # JSON null
  print ($a[2][junk][garbage])
  EOI
  2
  4
  6
  [null]
  [null]
  [null]
  [null]
  1
  3
  5
  [null]
  [null]
  [null]
  [null]
  EOO

  : reverse
  :
  $* <<EOI >>EOO
  print (([json] one@null)[one])
  print (([json] one@true)[one])
  print (([json] one@123)[one])
  print (([json] one@-123)[one])
  print (([json] one@0xdecaf)[one])
  print (([json] one@abc)[one])
  EOI
  [null]
  true
  123
  -123
  912559
  abc
  EOO

  : diagnostics-not-object
  :
  $* <<EOI 2>>EOE != 0
  j = [json] 1 2 3
  print ($j[one])
  EOI
  <stdin>:2:11: error: invalid json value subscript: invalid uint64 value 'one'
    info: json value type is array
    <stdin>:2:9: info: use the '\[' escape sequence if this is a wildcard pattern
  EOE
}}

: iteration
:
{{
  : null
  :
  $* <<EOI
  for v: ([json] null)
    print $v
  EOI

  : simple
  :
  $* <<EOI >>EOO
  for v: ([json] 123)
    print $v
  EOI
  123
  EOO

  : array
  :
  $* <<EOI >>EOO
  for v: ([json] 1 2 3)
    print $v
  EOI
  1
  2
  3
  EOO

  : object
  :
  $* <<EOI >>EOO
  for v: ([json] one@1 two@2 three@3)
    print $v
  EOI
  {"one":1}
  {"two":2}
  {"three":3}
  EOO

  : reverse
  :
  $* <<EOI >>EOO
  for v: ([json] null true 123 -123 0xdecaf abc)
    print $v
  EOI
  [null]
  true
  123
  -123
  912559
  abc
  EOO
}}

: cast
:
{{
  : basics
  :
  $* <<EOI >>EOO
  #a1 = [json_array] 1 2 3
  a1 = [json] '[1, 2, 3]'
  a2 = [json] '["a", "b", "c"]'
  oa = [json] '{a: [4, 5, 6]}'
  s1 = [strings] $a1
  s2 = [strings] $a1 $a2 $member_value($oa)
  s3 = [strings] $a1
  s3 += $a2
  s4 = [strings]
  s4 += $a1 $a2
  [strings] test.s5 = $a1 $a2

  print [strings] $a1
  print [strings] $a1 $a2
  print $s1
  print $s2
  print $s3
  print $s4
  print $test.s5
  print $regex.merge([strings] $a1, '.+', '$&', ', ')
  print $regex.merge([strings] $a1 $a2 $member_value($oa), '.+', '$&', ', ')
  print ([strings] $a1)
  print ([strings] $a1 $a2)
  print (true ? [strings] $a1 $a2 : [strings] $a2)
  print [strings] ($a1)
  print [strings] ($a1 $a2)
  print ([strings] (true ? $a1 $a2 : $a2))
  print [strings] $a2 (true ? $a1 $a2 : $a2)
  print ([strings] $a1 (true ? $a2 : $a1))
  EOI
  1 2 3
  1 2 3 a b c
  1 2 3
  1 2 3 a b c 4 5 6
  1 2 3 a b c
  1 2 3 a b c
  1 2 3 a b c
  1, 2, 3
  1, 2, 3, a, b, c, 4, 5, 6
  1 2 3
  1 2 3 a b c
  1 2 3 a b c
  1 2 3
  1 2 3 a b c
  1 2 3 a b c
  a b c 1 2 3 a b c
  1 2 3 a b c
  EOO
}}

: json-map
:
{{
  : basics
  :
  $* <<EOI >>EOO
  m = [json_map] 2@([json] a@1 b@2) 1@([json] 1 2) 0@([json] null) -1@null
  print $m
  for p: $m
    print $first($p) $second($p)
  print ($m[1])
  print $type($m[1])
  print ($m[2][b])
  print ($m[0])
  print ($m[-1])
  EOI
  -1@null 0@null 1@[1,2] 2@{"a":1,"b":2}
  -1 null
  0 null
  1 [1,2]
  2 {"a":1,"b":2}
  [1,2]
  json
  2
  null
  null
  EOO
}}

: json-set
:
{{
  : basics
  :
  $* <<EOI >>EOO
  s = [json_set] ([json] x@1 y@2) ([json] a@1 b@2)
  print $s
  for v: $s
    print $type($v) $v
  print ($s[([json] y@2 x@1)])
  EOI
  {"a":1,"b":2} {"x":1,"y":2}
  json {"a":1,"b":2}
  json {"x":1,"y":2}
  true
  EOO
}}
