/* * Copyright (C) 2024 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import { JsonValue } from 'cockpit'; import { import_json_object, get, get_optional, import_string, import_number, import_boolean, import_array, import_record, validate } from 'import-json'; import QUnit from 'qunit-tests'; // Hook into console.error let console_errors: string[] = []; const console_error = console.error; console.error = function (msg) { console_errors.push(msg); console_error(msg); }; QUnit.hooks.beforeEach(() => { console_errors = []; }); QUnit.test("import_string", function(assert) { assert.equal(import_string("foo"), "foo", "string"); assert.equal(import_string(""), "", "empty string"); assert.throws(() => import_string(12), /JSON validation error for : Not a string: 12/, "not a string"); }); QUnit.test("import_number", function(assert) { assert.equal(import_number(12), 12, "number"); assert.throws( () => import_number("foo"), /JSON validation error for : Not a number: "foo"/, "not a number"); }); QUnit.test("import_boolean", function(assert) { assert.equal(import_boolean(true), true, "boolean"); assert.throws( () => import_boolean("foo"), /JSON validation error for : Not a boolean: "foo"/, "not a boolean"); }); QUnit.test("import_array", function(assert) { assert.deepEqual(import_array(["a", "b", "c"], import_string), ["a", "b", "c"], "array of strings"); assert.deepEqual(import_array([1, 2, 3], import_number), [1, 2, 3], "array of numbers"); assert.deepEqual(import_array([], import_number), [], "empty array"); assert.throws( () => import_array([1, 2, "c"], import_number), /JSON validation error for \[2\]: Not a number: "c"/, "array of numbers with a string"); assert.throws( () => import_array("foo", import_string), /JSON validation error for : Not an array: "foo"/, "not an array"); }); QUnit.test("import_record", function(assert) { assert.deepEqual( import_record({ a: "a", b: "b", c: "c" }, import_string), { a: "a", b: "b", c: "c" }, "record of strings"); assert.deepEqual( import_record({ a: 1, b: 2, c: 3 }, import_number), { a: 1, b: 2, c: 3 }, "record of numbers"); assert.throws( () => import_record({ a: 1, b: 2, c: "c" }, import_number), /JSON validation error for \.c: Not a number: "c"/, "record of numbers with a string"); assert.throws( () => import_record("foo", import_string), /JSON validation error for : Not an object: "foo"/, "not a record"); }); QUnit.test("validate", function(assert) { assert.equal(validate("test input", "foo", import_string, "default"), "foo", "string"); assert.equal(validate("test input", 12, import_string, "default"), "default", "not a string"); assert.deepEqual( console_errors, [ 'JSON validation error for test input: Not a string: 12' ], "console errors" ); }); interface Player { name: string; age: number | undefined; position: string; } function import_Player(val: JsonValue): Player { const obj = import_json_object(val); return { name: get(obj, "name", import_string), age: get_optional(obj, "age", import_number), position: get(obj, "position", import_string, "unknown"), }; } interface Team { name: string; players: Player[]; } function import_Team(val: JsonValue): Team { const obj = import_json_object(val); return { name: get(obj, "name", import_string), players: get(obj, "players", v => import_array(v, import_Player)), }; } interface Teams { [name: string]: Team; } function import_Teams(val: JsonValue): Teams { return import_record(val, import_Team); } QUnit.test("objects", function(assert) { const valid_checks: [JsonValue, Teams][] = [ // "stadium" should be omitted [ { MAC: { name: "ManCity", players: [ { name: "Haaland", age: 24, position: "striker" }, { name: "De Bruyne", age: 33, position: "midfield" } ], stadium: "City of Manchester Stadium" }, }, { MAC: { name: "ManCity", players: [ { name: "Haaland", age: 24, position: "striker" }, { name: "De Bruyne", age: 33, position: "midfield" } ], }, } ], // optional fields [ { MAC: { name: "ManCity", players: [ { name: "Haaland", }, { name: "De Bruyne", age: 33 } ], }, }, { MAC: { name: "ManCity", players: [ { name: "Haaland", age: undefined, position: "unknown" }, { name: "De Bruyne", age: 33, position: "unknown" } ], }, } ], ]; const invalid_checks: [JsonValue, string][] = [ // invalid optional field [ { MAC: { name: "ManCity", players: [ { name: "Haaland", age: "unknown" }, { name: "De Bruyne", age: 33 } ], }, }, 'JSON validation error for test input.MAC.players[0].age: Not a number: "unknown"', ], // invalid mandatory field [ { MAC: { name: "ManCity", players: [ { name: ["Erling", "Braut", "Haaland"] }, { name: "De Bruyne", age: 33 } ], }, }, 'JSON validation error for test input.MAC.players[0].name: Not a string: ["Erling","Braut","Haaland"]', ], // invalid mandatory array [ { MAC: { name: "ManCity", players: "TBD", }, }, 'JSON validation error for test input.MAC.players: Not an array: "TBD"', ], // invalid object [ "...", 'JSON validation error for test input: Not an object: "..."' ] ]; for (let i = 0; i < valid_checks.length; i++) { assert.deepEqual(validate("test input", valid_checks[i][0], import_Teams, {}), valid_checks[i][1]); } for (let i = 0; i < invalid_checks.length; i++) { console_errors = []; assert.deepEqual(validate("test input", invalid_checks[i][0], import_Teams, {}), {}); assert.deepEqual(console_errors, [invalid_checks[i][1]]); } }); QUnit.start();