%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Unit tests for fromjSON() %% %% Code in libinterp/corefcn/fromjSON.cc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Note: This script is intended to also run under Matlab to verify %% compatibility. Preserve Matlab-formatting when making changes. %%% Test 1: decode null values %% null, in non-numeric arrays -> Empty double [] %! json = '["str", 5, null, true]'; %! exp = {'str'; 5; []; true}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% null, in numeric arrays to NaN (extracted from JSONio) %! json = '[1, 2, null, 3]'; %! exp = [1; 2; NaN; 3]; %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %% corner case: array of null values %! json = '[null, null, null]'; %! exp = [NaN; NaN; NaN]; %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %%% Test 2: Decode scalar Boolean, Number, and String values %! assert (isequal (fromjSON ('true'), logical (1))); %! assert (isa (fromjSON ('true'), 'logical')); %! assert (isequal (fromjSON ('false'), logical (0))); %! assert (isa (fromjSON ('false'), 'logical')); %! assert (isequal (fromjSON ('123.45'), 123.45)); %! assert (isequal (fromjSON ('"hello there"'), 'hello there')); %%% Test 3: Decode Array of Booleans, Numbers, and Strings values %% vectors are always rendered as column vectors %! json = '[true, true, false, true]'; %! exp = logical ([1; 1; 0; 1]); %! obs = fromjSON (json); %! assert (isa (obs, 'logical')); %! assert (isequal (obs, exp)); %!testif HAVE_RAPIDJSON <59135> %! json = '[[true, true], [false, true]]'; %! exp = logical ([1, 1; 0, 1]); %! obs = fromjSON (json); %! assert (isa (obs, 'logical')); %! assert (isequal (obs, exp)); %! json = '["true", "true", "false", "true"]'; %! exp = {'true'; 'true'; 'false'; 'true'}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %! json = '["foo", "bar", ["foo", "bar"]]'; %! exp = {'foo'; 'bar'; {'foo'; 'bar'}}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% vectors are always rendered as column vectors %! json = '[15000, 5, 12.25, 1502302.3012]'; %! exp = [15000; 5; 12.25; 1502302.3012]; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% row vectors are preserved by adding one level of hierarchy %% extracted from JSONio %! json = '[[1,2]]'; %! exp = [1, 2]; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% If same dimensions -> transform to an array (extracted from JSONio) %! json = '[[1, 2], [3, 4]]'; %! exp = [1, 2; 3, 4]; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% extracted from JSONio %! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]'; %! exp = cat (3, [1, 3; 5, 7], [2, 4; 6, 8]); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% try different dimensions for the array %! json = '[[[1, 2, -1], [3, 4, null]], [[5, 6, Inf], [7, 8, -Inf]]]'; %! exp = cat (3, [1, 3; 5, 7], [2, 4; 6, 8], [-1, NaN; Inf, -Inf]); %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %% try different dimensions for the array %! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]'; %! exp = cat (3, [1, 3; 5, 7; 9, 11], [2, 4; 6, 8; 10, 12]); %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %% try higher dimensions for the array %! json = ['[[[[1,-1], [2,-2]],[[3,-3],[4,-4]]],[[[5,-5],[6,-6]],[[7,-7],', ... %! '[8,-8]]],[[[9,-9], [10,-10]],[[11,-11],[12,-12]]],', ... %! '[[[13,-13],[14,-14]],[[15,-15],[16,-16]]]]']; %! var1 = cat (3, [1, 3; 5, 7; 9, 11; 13, 15], [2, 4; 6, 8; 10, 12; 14, 16]); %! var2 = cat (3, [-1, -3; -5, -7; -9, -11; -13, -15], ... %! [-2, -4; -6, -8; -10, -12; -14, -16]); %! exp = cat (4, var1, var2); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %! json = '[[true, false], [true, false], [true, false]]'; %! exp = logical ([1 0; 1 0; 1 0]); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% If different dimensions -> transform to a cell array (extracted from JSONio) %! json = '[[1, 2], [3, 4, 5]]'; %! exp = {[1; 2]; [3; 4; 5]}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% extracted from JSONio % %! json = '[1, 2, [3, 4]]'; %! exp = {1; 2; [3; 4]}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %! json = '[true, false, [true, false, false]]'; %! exp = {true; false; logical([1; 0; 0])}; %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %! assert (isa (obs{1}, 'logical')); %! assert (isa (obs{2}, 'logical')); %! assert (isa (obs{3}, 'logical')); %%% Test 4: decode JSON Objects %% Check decoding of Boolean, Number, and String values inside an Object %! json = '{"number": 3.14, "string": "foobar", "boolean": false}'; %! exp = struct ('number', 3.14, 'string', 'foobar', 'boolean', false); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %! assert (isa (obs.boolean, 'logical')); %% Check decoding of null values and arrays inside an object & makeValidName %! json = [ '{"nonnumeric array": ["str", 5, null],' ... %! '"numeric array": [1, 2, null]}' ]; %! exp = struct ('nonnumericArray', {{'str'; 5; []}}, ... %! 'numericArray', {[1; 2; NaN]}); %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %% Check decoding of objects inside an object & makeValidName (from JSONio) %! json = '{"object": {" field 1 ": 1, "field- 2": 2, "3field": 3, "": 1}}'; %! exp = struct ('object', ... %! struct ('field1', 1, 'field_2', 2, 'x3field', 3, 'x', 1)); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Check decoding of empty objects, empty arrays, and Inf inside an object %! json = '{"a": Inf, "b": [], "c": {}}'; %! exp = struct ('a', Inf, 'b', [], 'c', struct ()); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Check decoding of string arrays inside an object & makeValidName %% extracted from JSONio %! json = '{"%string.array": ["Statistical","Parametric","Mapping"]}'; %! exp = struct ('x_string_array', ... %! {{'Statistical'; 'Parametric'; 'Mapping'}}); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% extracted from jsonlab %! json = ['{' , ... %! '"glossary": { ', ... %! '"title": "example glossary",', ... %! '"GlossDiv": {', ... %! '"title": "S",', ... %! '"GlossList": {', ... %! '"GlossEntry": {', ... %! '"ID": "SGML",', ... %! '"SortAs": "SGML",', ... %! '"GlossTerm": "Standard Generalized Markup Language",', ... %! '"Acronym": "SGML",', ... %! '"Abbrev": "ISO 8879:1986",', ... %! '"GlossDef": {', ... %! '"para": "A meta-markup language, ', ... %! 'used to create markup languages such as DocBook.",', ... %! '"GlossSeeAlso": ["GML", "XML"]', ... %! '},', ... %! '"GlossSee": "markup"', ... %! '}', ... %! '}', ... %! '}', ... %! '}', ... %! '}']; %! var1 = struct ('para', ['A meta-markup language, used to create ' ... %! 'markup languages such as DocBook.'], ... %! 'GlossSeeAlso', {{'GML'; 'XML'}}); %! var2 = struct ('ID', 'SGML', 'SortAs', 'SGML', ... %! 'GlossTerm', 'Standard Generalized Markup Language', ... %! 'Acronym', 'SGML', 'Abbrev', 'ISO 8879:1986', ... %! 'GlossDef', var1, 'GlossSee', 'markup'); %! exp = struct ('glossary', ... %! struct ('title', 'example glossary', ... %! 'GlossDiv', struct ('title', 'S', ... %! 'GlossList', ... %! struct ('GlossEntry', var2)))); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %%% Test 5: decode Array of JSON objects %% Arrays with the same field names in the same order (extracted from JSONio) %! json = '{"structarray": [{"a":1,"b":2},{"a":3,"b":4}]}'; %! exp = struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4})); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Different field names before calling makeValidName, BUT the same after %% calling it, resulting in structarray. %! json = [ '[', ... %! '{', ... %! '"i*d": 0,', ... %! '"12name": "Osborn"', ... %! '},', ... %! '{', ... %! '"i/d": 1,', ... %! '"12name": "Mcdowell"', ... %! '},', ... %! '{', ... %! '"i+d": 2,', ... %! '"12name": "Jewel"', ... %! '}', ... %! ']']; %! exp = struct ('i_d', {0; 1; 2}, ... %! 'x12name', {'Osborn'; 'Mcdowell'; 'Jewel'}); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Arrays with the same field names in the same order. %% JSON text is generated from json-generator.com %! json = ['[', ... %! '{', ... %! '"x_id": "5ee28980fc9ab3",', ... %! '"index": 0,', ... %! '"guid": "b229d1de-f94a",', ... %! '"latitude": -17.124067,', ... %! '"longitude": -61.161831,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Collins"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Hays"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Griffin"', ... %! '}', ... %! ']', ... %! '},', ... %! '{', ... %! '"x_id": "5ee28980dd7250",', ... %! '"index": 1,', ... %! '"guid": "39cee338-01fb",', ... %! '"latitude": 13.205994,', ... %! '"longitude": -37.276231,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Osborn"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Mcdowell"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Jewel"', ... %! '}', ... %! ']', ... %! '},', ... %! '{', ... %! '"x_id": "5ee289802422ac",', ... %! '"index": 2,', ... %! '"guid": "3db8d55a-663e",', ... %! '"latitude": -35.453456,', ... %! '"longitude": 14.080287,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Socorro"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Darla"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Leanne"', ... %! '}', ... %! ']', ... %! '}', ... %! ']']; %! var1 = struct ('id', {0; 1; 2}, 'name', {'Collins'; 'Hays'; 'Griffin'}); %! var2 = struct ('id', {0; 1; 2}, 'name', {'Osborn'; 'Mcdowell'; 'Jewel'}); %! var3 = struct ('id', {0; 1; 2}, 'name', {'Socorro'; 'Darla'; 'Leanne'}); %! exp = struct (... %! 'x_id', {'5ee28980fc9ab3'; '5ee28980dd7250'; '5ee289802422ac'}, ... %! 'index', {0; 1; 2}, ... %! 'guid', {'b229d1de-f94a'; '39cee338-01fb'; '3db8d55a-663e'}, ... %! 'latitude', {-17.124067; 13.205994; -35.453456}, ... %! 'longitude', {-61.161831; -37.276231; 14.080287}, ... %! 'friends', {var1; var2; var3}); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Arrays with the same field names in different order (extracted from JSONio) %% Results in cell array, rather than struct array %! json = '{"cellarray": [{"a":1,"b":2},{"b":3,"a":4}]}'; %! exp = struct ('cellarray', {{struct('a', 1, 'b', 2); ... %! struct('b', 3, 'a', 4)}}); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Arrays with different field names (extracted from JSONio) %! json = '{"cellarray": [{"a":1,"b":2},{"a":3,"c":4}]}'; %! exp = struct ('cellarray', {{struct('a', 1, 'b', 2); ... %! struct('a', 3, 'c', 4)}}); %! obs = fromjSON (json); %! assert (isequal (obs, exp)); %% Arrays with different field names and a big test %! json = ['[', ... %! '{', ... %! '"x_id": "5ee28980fc9ab3",', ... %! '"index": 0,', ... %! '"guid": "b229d1de-f94a",', ... %! '"latitude": -17.124067,', ... %! '"longitude": -61.161831,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Collins"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Hays"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Griffin"', ... %! '}', ... %! ']', ... %! '},', ... %! '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ... %! '{', ... %! '"firstName": "John",', ... %! '"lastName": "Smith",', ... %! '"age": 25,', ... %! '"address":', ... %! '{', ... %! '"streetAddress": "21 2nd Street",', ... %! '"city": "New York",', ... %! '"state": "NY"', ... %! '},', ... %! '"phoneNumber":', ... %! '{', ... %! '"type": "home",', ... %! '"number": "212 555-1234"', ... %! '}', ... %! '}]']; %! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ... %! 'guid', 'b229d1de-f94a', 'latitude', -17.124067, ... %! 'longitude', -61.161831, ... %! 'friends', ... %! struct ('id', {0; 1; 2}, ... %! 'name', {'Collins'; 'Hays'; 'Griffin'})); %! var2 = struct ('numericArray', {{'str'; 5; []}}, ... %! 'nonnumericArray', {[1; 2; NaN]}); %! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ... %! 'address', ... %! struct ('streetAddress', '21 2nd Street', ... %! 'city', 'New York', 'state', 'NY'), ... %! 'phoneNumber', ... %! struct ('type', 'home', 'number', '212 555-1234')); %! exp = {var1; var2; var3}; %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %%% Test 6: decode Array of different JSON data types %! json = ['[null, true, Inf, 2531.023, "hello there", ', ... %! '{', ... %! '"x_id": "5ee28980dd7250",', ... %! '"index": 1,', ... %! '"guid": "39cee338-01fb",', ... %! '"latitude": 13.205994,', ... %! '"longitude": -37.276231,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Osborn"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Mcdowell"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Jewel"', ... %! '}', ... %! ']', ... %! '}]']; %! var = struct ('x_id', '5ee28980dd7250', 'index', 1, ... %! 'guid', '39cee338-01fb', 'latitude', 13.205994, ... %! 'longitude', -37.276231, %! 'friends', struct ('id', {0; 1; 2}, ... %! 'name', {'Osborn'; 'Mcdowell'; 'Jewel'})); %! exp = {[]; 1; Inf; 2531.023; 'hello there'; var}; %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %% Array of arrays %! json = ['[["str", Inf, null], [1, 2, null], ["foo", "bar", ["foo", "bar"]],', ... %! '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]],' , ... %! '[', ... %! '{', ... %! '"x_id": "5ee28980fc9ab3",', ... %! '"index": 0,', ... %! '"guid": "b229d1de-f94a",', ... %! '"latitude": -17.124067,', ... %! '"longitude": -61.161831,', ... %! '"friends": [', ... %! '{', ... %! '"id": 0,', ... %! '"name": "Collins"', ... %! '},', ... %! '{', ... %! '"id": 1,', ... %! '"name": "Hays"', ... %! '},', ... %! '{', ... %! '"id": 2,', ... %! '"name": "Griffin"', ... %! '}', ... %! ']', ... %! '},', ... %! '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ... %! '{', ... %! '"firstName": "John",', ... %! '"lastName": "Smith",', ... %! '"age": 25,', ... %! '"address":', ... %! '{', ... %! '"streetAddress": "21 2nd Street",', ... %! '"city": "New York",', ... %! '"state": "NY"', ... %! '},', ... %! '"phoneNumber":', ... %! '{', ... %! '"type": "home",', ... %! '"number": "212 555-1234"', ... %! '}', ... %! '}]]']; %! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ... %! 'guid', 'b229d1de-f94a', 'latitude', -17.124067, ... %! 'longitude', -61.161831, ... %! 'friends', struct ('id', {0; 1; 2}, ... %! 'name', {'Collins'; 'Hays'; 'Griffin'})); %! var2 = struct ('numericArray', {{'str'; 5; []}}, ... %! 'nonnumericArray', {[1; 2; NaN]}); %! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ... %! 'address', ... %! struct ('streetAddress', '21 2nd Street', ... %! 'city', 'New York', 'state', 'NY'), ... %! 'phoneNumber', ... %! struct ('type', 'home', 'number', '212 555-1234')); %! exp = {{'str'; Inf; []}; [1; 2; NaN]; {'foo'; 'bar'; {'foo'; 'bar'}}; %! cat(3, [1, 3; 5, 7], [2, 4; 6, 8]); {var1; var2 ;var3}}; %! obs = fromjSON (json); %! assert (isequaln (obs, exp)); %%% Test 7: Check "ReplacementStyle" and "Prefix" options %! json = '{"1a": {"1*a": {"1+*/-a": {"1#a": {}}}}}'; %! exp = struct ('n1a', ... %! struct ('n1a', struct ('n1a', struct ('n1a', struct ())))); %! obs = fromjSON (json, "ReplacementStyle", "delete", ... %! "Prefix", "_", "Prefix", "n"); %! assert (isequal (obs, exp)); %% Check forwarding of "ReplacementStyle" and "Prefix" options inside arrays %! json = [ '[', ... %! '{', ... %! '"i*d": 0,', ... %! '"12name": "Osborn"', ... %! '},', ... %! '{', ... %! '"i*d": 1,', ... %! '"12name": "Mcdowell"', ... %! '},', ... %! '{', ... %! '"i*d": 2,', ... %! '"12name": "Jewel"', ... %! '}', ... %! ']']; %! exp = struct ('i0x2Ad', {0; 1; 2}, ... %! 'm_12name', {'Osborn'; 'Mcdowell'; 'Jewel'}); %! obs = fromjSON (json, "ReplacementStyle", "hex", "Prefix", "m_"); %! assert (isequal (obs, exp)); %! json = '{"cell*array": [{"1a":1,"b*1":2},{"1a":3,"b/2":4}]}'; %! exp = struct ('cell_array', {{struct('x_1a', 1, 'b_1', 2); ... %! struct('x_1a', 3, 'b_2', 4)}}); %! obs = fromjSON (json, "ReplacementStyle", "underscore", "Prefix", "x_"); %! assert (isequal (obs, exp));