#!/bin/bash

# json_spec.sh - Test cases for the toolbox json module
# Copyright (C) 2021-2023 Matthias Kruk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

if ! . toolbox.sh; then
	exit 1
fi

if ! include "json"; then
	exit 1
fi

Describe "json_object()"
  It "creates an empty JSON object"
    When call json_object
    The stdout should equal "{}"
    The status should equal 0
  End

  It "fails if there are more keys than values"
    When call json_object "data"
    The stderr should match pattern "*Invalid number of arguments"
    The status should equal 1
  End

  It "inserts a string into a JSON object (type specified)"
    When call json_object "data" "s:hello world"
    The stdout should equal '{"data": "hello world"}'
    The status should equal 0
  End

  It "inserts a string into a JSON object (type inferred)"
    When call json_object "data" "hello world"
    The stdout should equal '{"data": "hello world"}'
    The status should equal 0
  End

  It "inserts an integer into a JSON object (type specified)"
    When call json_object "data" "i:123"
    The stdout should equal '{"data": 123}'
    The status should equal 0
  End

  It "inserts an integer into a JSON object (type inferred)"
    When call json_object "data" 123
    The stdout should equal '{"data": 123}'
    The status should equal 0
  End

  It "inserts a boolean (true) into a JSON object (type specified)"
    When call json_object "data" "b:true"
    The stdout should equal '{"data": true}'
    The status should equal 0
  End

  It "inserts a boolean (true) into a JSON object (type inferred)"
    When call json_object "data" "true"
    The stdout should equal '{"data": true}'
    The status should equal 0
  End

  It "inserts a boolean (false) into a JSON object (type specified)"
    When call json_object "data" "b:false"
    The stdout should equal '{"data": false}'
    The status should equal 0
  End

  It "inserts a boolean (false) into a JSON object (type inferred)"
    When call json_object "data" "false"
    The stdout should equal '{"data": false}'
    The status should equal 0
  End

  It "inserts a float into a JSON object (type specified)"
    When call json_object "data" "3.14"
    The stdout should equal '{"data": 3.140000}'
    The status should equal 0
  End

  It "inserts a float into a JSON object (type inferred)"
    When call json_object "data" "3.14"
    The stdout should equal '{"data": 3.140000}'
    The status should equal 0
  End

  It "inserts an object into a JSON object (type specified)"
    When call json_object "data" "o:{}"
    The stdout should equal '{"data": {}}'
    The status should equal 0
  End

  It "inserts an object into a JSON object (type inferred)"
    When call json_object "data" "{}"
    The stdout should equal '{"data": {}}'
    The status should equal 0
  End

  It "inserts an array into a JSON object (type specified)"
    When call json_object "data" "a:[]"
    The stdout should equal '{"data": []}'
    The status should equal 0
  End

  It "inserts an array into a JSON object (type inferred)"
    When call json_object "data" "[]"
    The stdout should equal '{"data": []}'
    The status should equal 0
  End
End

Describe "json_object_get()"
  It "retrieves a string from an object"
    When call json_object_get '{"data": "hello world"}' "data"
    The stdout should equal "hello world"
    The status should equal 0
  End

  It "retrieves an integer from an object"
    When call json_object_get '{"data": 123}' "data"
    The stdout should equal "123"
    The status should equal 0
  End

  It "retrieves a boolean (true) from an object"
    When call json_object_get '{"data": true}' "data"
    The stdout should equal "true"
    The status should equal 0
  End

  It "retrieves a boolean (false) from an object"
    When call json_object_get '{"data": false}' "data"
    The stdout should equal "false"
    The status should equal 0
  End

  It "retrieves a float from an object"
    When call json_object_get '{"data": 1.23}' "data"
    The stdout should equal "1.23"
    The status should equal 0
  End

  It "retrieves an array from an object"
    When call json_object_get '{"data": []}' "data"
    The stdout should equal "[]"
    The status should equal 0
  End

  It "retrieves an object from an object"
    When call json_object_get '{"data": {}}' "data"
    The stdout should equal "{}"
    The status should equal 0
  End
End

Describe "json_array()"
  It "creates an empty array"
    When call json_array
    The stdout should equal "[]"
    The status should equal 0
  End

  It "creates a string array (type specified)"
    When call json_array "s:hello" "s:world"
    The stdout should equal '["hello", "world"]'
    The status should equal 0
  End

  It "creates a string array (type inferred)"
    When call json_array "hello" "world"
    The stdout should equal '["hello", "world"]'
    The status should equal 0
  End

  It "creates an integer array (type specified)"
    When call json_array "i:1" "i:2" "i:3"
    The stdout should equal '[1, 2, 3]'
    The status should equal 0
  End

  It "creates an integer array (type inferred)"
    When call json_array 1 2 3
    The stdout should equal '[1, 2, 3]'
    The status should equal 0
  End

  It "creates a boolean array (type specified)"
    When call json_array "b:true" "b:false"
    The stdout should equal '[true, false]'
    The status should equal 0
  End

  It "creates a boolean array (type inferred)"
    When call json_array "true" "false"
    The stdout should equal '[true, false]'
    The status should equal 0
  End

  It "creates a float array (type specified)"
    When call json_array "f:1.23" "f:2.34" "f:3.45"
    The stdout should equal "[1.230000, 2.340000, 3.450000]"
    The status should equal 0
  End

  It "creates a float array (type inferred)"
    When call json_array "1.23" "2.34" "3.45"
    The stdout should equal "[1.230000, 2.340000, 3.450000]"
    The status should equal 0
  End

  It "creates an array array (type specified)"
    When call json_array "a:[]" "a:[]"
    The stdout should equal "[[], []]"
    The status should equal 0
  End

  It "creates an array array (type inferred)"
    When call json_array "[]" "[]"
    The stdout should equal "[[], []]"
    The status should equal 0
  End

  It "creates an object array (type specified)"
    When call json_array "o:{}" "o:{}"
    The stdout should equal "[{}, {}]"
    The status should equal 0
  End

  It "creates an object array (type inferred)"
    When call json_array "{}" "{}"
    The stdout should equal "[{}, {}]"
    The status should equal 0
  End
End

Describe "json_array_head()"
  It "fails if the array is empty"
    When call json_array_head "[]"
    The status should equal 1
  End

  It "retrieves a string from the head of the array"
    When call json_array_head '["hello", "world"]'
    The stdout should equal "hello"
    The status should equal 0
  End

  It "retrieves an integer from the head of the array"
    When call json_array_head "[1, 2, 3]"
    The stdout should equal "1"
    The status should equal 0
  End

  It "retrieves a boolean (true) from the head of the array"
    When call json_array_head "[true, false]"
    The stdout should equal "true"
    The status should equal 0
  End

  It "retrieves a boolean (false) from the head of the array"
    When call json_array_head "[false, true]"
    The stdout should equal "false"
    The status should equal 0
  End

  It "retrieves a float from the head of the array"
    When call json_array_head "[1.23, 2.34, 3.45]"
    The stdout should equal "1.23"
    The status should equal 0
  End

  It "retrieves an array from the head of the array"
    When call json_array_head "[[], [1]]"
    The stdout should equal "[]"
    The status should equal 0
  End

  It "retrieves an object from the head of the array"
    When call json_array_head '[{}, {"hello": "world"}]'
    The stdout should equal "{}"
    The status should equal 0
  End
End

Describe "json_array_tail()"
  It "returns an empty array if the array is empty"
    When call json_array_tail "[]"
    The stdout should equal "[]"
    The status should equal 0
  End

  It "removes a string from the head of the array"
    When call json_array_tail '["hello", "world", "foobar"]'
    The stdout should equal '["world", "foobar"]'
    The status should equal 0
  End

  It "removes an integer from the head of the array"
    When call json_array_tail "[1, 2, 3]"
    The stdout should equal "[2, 3]"
    The status should equal 0
  End

  It "removes a boolean (true) from the head of the array"
    When call json_array_tail "[true, false, false]"
    The stdout should equal "[false, false]"
    The status should equal 0
  End

  It "removes a boolean (false) from the head of the array"
    When call json_array_tail "[false, true, true]"
    The stdout should equal "[true, true]"
    The status should equal 0
  End

  It "removes a float from the head of the array"
    When call json_array_tail "[1.23, 2.34, 3.45]"
    The stdout should equal "[2.340000, 3.450000]"
    The status should equal 0
  End

  It "removes an array from the head of the array"
    When call json_array_tail "[[], [1]]"
    The stdout should equal "[[1]]"
    The status should equal 0
  End

  It "removes an object from the head of the array"
    When call json_array_tail '[{}, {"hello":"world"}]'
    The stdout should equal '[{"hello":"world"}]'
    The status should equal 0
  End
End

Describe "json_array_to_lines()"
  It "does not output any lines if the array is empty"
    When call json_array_to_lines "[]"
    The status should equal 0
  End

  It "splits a string array to lines"
    When call json_array_to_lines '["hello","world"]'
    The first line of stdout should equal "hello"
    The second line of stdout should equal "world"
    The status should equal 0
  End

  It "splits an integer array to lines"
    When call json_array_to_lines "[1, 2, 3]"
    The first line of stdout should equal "1"
    The second line of stdout should equal "2"
    The third line of stdout should equal "3"
    The status should equal 0
  End

  It "splits a boolean array to lines"
    When call json_array_to_lines "[true, false]"
    The first line of stdout should equal "true"
    The second line of stdout should equal "false"
    The status should equal 0
  End

  It "splits a float array to lines"
    When call json_array_to_lines "[1.23, 2.34, 3.45]"
    The first line of stdout should equal "1.23"
    The second line of stdout should equal "2.34"
    The third line of stdout should equal "3.45"
    The status should equal 0
  End

  It "splits an array array to lines"
    When call json_array_to_lines "[[1], [2], [3]]"
    The first line of stdout should equal "[1]"
    The second line of stdout should equal "[2]"
    The third line of stdout should equal "[3]"
    The status should equal 0
  End

  It "splits an object array to lines"
    When call json_array_to_lines '[{"data":1}, {"data":2}]'
    The first line of stdout should equal '{"data":1}'
    The second line of stdout should equal '{"data":2}'
    The status should equal 0
  End
End
