File: JSON_parser_tests.ml

package info (click to toggle)
guestfs-tools 1.54.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 69,464 kB
  • sloc: ml: 15,635; ansic: 15,575; sh: 8,238; xml: 5,478; makefile: 3,547; perl: 1,537; lex: 135; yacc: 128; python: 80
file content (171 lines) | stat: -rw-r--r-- 5,802 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
(* virt-builder
 * Copyright (C) 2015-2025 Red Hat Inc.
 *
 * 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 2 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *)

(* This file tests the JSON_parser module. *)

open Printf

open Std_utils
open JSON_parser

let assert_equal ~printer a b =
  if a <> b then
    failwithf "FAIL: %s <> %s" (printer a) (printer b)
let assert_equal_string = assert_equal ~printer:Fun.id
let assert_equal_int = assert_equal ~printer:(fun x -> string_of_int x)
let assert_equal_int64 = assert_equal ~printer:(fun x -> Int64.to_string x)
let assert_equal_bool = assert_equal ~printer:(fun x -> string_of_bool x)

let assert_bool name b =
  if not b then failwithf "FAIL: %s" name

let assert_raises exn fn =
  try
    fn ();
    failwithf "FAIL: expected function to raise an exception"
  with exn' ->
    if exn <> exn' then (
      eprintf "FAIL: function raised the wrong exception:\n\
               expected %s\n\
               actual %s\n"
        (Printexc.to_string exn) (Printexc.to_string exn');
      exit 1
    )

let string_of_json_t = function
  | JSON.Null -> "null"
  | JSON.String _ -> "string"
  | JSON.Int _ -> "int"
  | JSON.Float _ -> "float"
  | JSON.Dict _ -> "dict"
  | JSON.List _ -> "list"
  | JSON.Bool _ -> "bool"
let type_mismatch_string exp value =
  Printf.sprintf "value is not %s but %s" exp (string_of_json_t value)

let assert_raises_invalid_argument str =
  (* Replace the Invalid_argument string with a fixed one, just to check
   * whether the exception has been raised.
   *)
  let mock = "parse_error" in
  let wrapped_tree_parse str =
    try json_parser_tree_parse str
    with Invalid_argument _ -> raise (Invalid_argument mock) in
  assert_raises (Invalid_argument mock) (fun () -> wrapped_tree_parse str)
let assert_raises_nested str =
  let err = "too many levels of object/array nesting" in
  assert_raises (Invalid_argument err) (fun () -> json_parser_tree_parse str)

let assert_is_object value =
  assert_bool
    (type_mismatch_string "object" value)
    (match value with | JSON.Dict _ -> true | _ -> false)
let assert_is_string exp = function
  | JSON.String s -> assert_equal_string exp s
  | _ as v -> failwith (type_mismatch_string "string" v)
let assert_is_number exp = function
  | JSON.Int i -> assert_equal_int64 exp i
  | JSON.Float f -> assert_equal_int64 exp (Int64.of_float f)
  | _ as v -> failwith (type_mismatch_string "number/double" v)
let assert_is_array value =
  assert_bool
    (type_mismatch_string "list" value)
    (match value with | JSON.List _ -> true | _ -> false)
let assert_is_bool exp = function
  | JSON.Bool b -> assert_equal_bool exp b
  | _ as v -> failwith (type_mismatch_string "bool" v)

let get_dict = function
  | JSON.Dict x -> x
  | _ as v -> failwith (type_mismatch_string "dict" v)
let get_list = function
  | JSON.List x -> x
  | _ as v -> failwith (type_mismatch_string "list" v)


(* tree parse invalid *)
let () =
  assert_raises_invalid_argument "";
  assert_raises_invalid_argument "invalid";
  assert_raises_invalid_argument ":5";

  (* Nested objects/arrays. *)
  let str = "[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]" in
  assert_raises_nested str;
  let str = "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":5}}}}}}}}}}}}}}}}}}}}}" in
  assert_raises_nested str

(* tree parse basic *)
let () =
  let value = json_parser_tree_parse "{}" in
  assert_is_object value;

  let value = json_parser_tree_parse "\"foo\"" in
  assert_is_string "foo" value;

  let value = json_parser_tree_parse "[]" in
  assert_is_array value

(* tree parse inspect *)
let () =
  let value = json_parser_tree_parse "{\"foo\":5}" in
  let l = get_dict value in
  assert_equal_int 1 (List.length l);
  assert_equal_string "foo" (fst (List.hd l));
  assert_is_number 5_L (snd (List.hd l));

  let value = json_parser_tree_parse "[\"foo\", true]" in
  let a = get_list value in
  assert_equal_int 2 (List.length a);
  assert_is_string "foo" (List.hd a);
  assert_is_bool true (List.nth a 1);

  let value = json_parser_tree_parse "{\"foo\":[false, {}, 10], \"second\":2}" in
  let l = get_dict value in
  assert_equal_int 2 (List.length l);
  let a = get_list (List.assoc "foo" l) in
  assert_equal_int 3 (List.length a);
  assert_is_bool false (List.hd a);
  assert_is_object (List.nth a 1);
  assert_is_number 10_L (List.nth a 2);
  assert_is_number 2_L (List.assoc "second" l)

(* tree parse file basic *)
let () =
  begin
    let tmpfile, chan = Filename.open_temp_file "tmp" ".tmp" in
    On_exit.unlink tmpfile;
    output_string chan "{}\n";
    flush chan;
    close_out chan;
    let value = json_parser_tree_parse_file tmpfile in
    assert_is_object value
  end;
  begin
    let tmpfile, chan = Filename.open_temp_file "tmp" ".tmp" in
    On_exit.unlink tmpfile;
    output_string chan "{\"foo\":5}\n";
    flush chan;
    close_out chan;
    let value = json_parser_tree_parse_file tmpfile in
    let l = get_dict value in
    assert_equal_int 1 (List.length l);
    assert_equal_string "foo" (fst (List.hd l));
    assert_is_number 5_L (snd (List.hd l));
  end;
  ()