1 // vim: ts=4 sw=4 noet :
3 ==================================================================================
4 Copyright (c) 2020 Nokia
5 Copyright (c) 2020 AT&T Intellectual Property.
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 ==================================================================================
22 Mnemonic: json_test.cpp
23 Abstract: Unit test for the json module. This expects that a static json
24 file exist in the current directory with a known set of fields,
25 arrays and objects that can be sussed out after parsing. The
26 expected file is test.json.
29 Author: E. Scott Daniels
44 Very simple file reader. Reads up to 8k into a single buffer and
45 returns the buffer as char*. Easier to put json test things in
48 static char* read_jstring( char* fname ) {
53 rbuf = (char *) malloc( sizeof( char ) * 8192 );
54 fd = open( fname, O_RDONLY, 0 );
56 fprintf( stderr, "<ABORT> can't open test file: %s: %s\n", fname, strerror( errno ) );
60 len = read( fd, rbuf, 8190 );
63 fprintf( stderr, "<ABORT> read from file failed: %s: %s\n", fname, strerror( errno ) );
73 // this also tests jwrapper.c but that is built as a special object to link in
74 // rather than including here.
76 #include "../src/json/jhash.hpp"
77 #include "../src/json/jhash.cpp"
79 #include "ut_support.cpp"
81 int main( int argc, char** argv ) {
92 set_test_name( "jhash_test" );
93 jstr = read_jstring( (char *) "test.json" ); // read and parse the json
95 fprintf( stderr, "read: (%s)\n", jstr );
97 jh = new xapp::Jhash( jstr );
101 fprintf( stderr, "<FAIL> could not parse json string from: test.json\n" );
106 sval = jh->String( (char *) "meeting_day" );
107 fprintf( stderr, "<INFO> sval=(%s)\n", sval.c_str() );
108 errors += fail_if( sval.compare( "" ) == 0, "did not get meeting day string" );
109 errors += fail_if( sval.compare( "Tuesday" ) != 0, "meeting day was not expected string" );
111 sval = jh->String( (char *) "meeting_place" );
112 fprintf( stderr, "<INFO> sval=(%s)\n", sval.c_str() );
113 errors += fail_if( sval.compare( "" ) == 0, "did not get meeting place" );
114 errors += fail_if( sval.compare( "16801 East Green Drive" ) != 0, "meeting place stirng was not correct" );
116 state = jh->Exists( (char *) "meeting_place" );
117 errors += fail_if( !state, "test for meeting place exists did not return true" );
119 state = jh->Exists( (char *) "no-name" );
120 errors += fail_if( state, "test for non-existant thing returned true" );
122 state = jh->Is_missing( (char *) "no-name" );
123 errors += fail_if( !state, "missing test for non-existant thing returned false" );
125 state = jh->Is_missing( (char *) "meeting_place" );
126 errors += fail_if( state, "missing test for existing thing returned true" );
128 val = jh->Value( (char *) "lodge_number" );
129 errors += fail_if( val != 41.0, "lodge number value was not correct" );
131 val = jh->Value( (char *) "monthly_dues" );
132 fprintf( stderr, "<INFO> got dues: %.2f\n", val );
133 errors += fail_if( val != (double) 43.5, "lodge dues value was not correct" );
135 len = jh->Array_len( (char *) "members" );
136 fprintf( stderr, "<INFO> got %d members\n", len );
137 errors += fail_if( len != 4, "array length was not correct" );
139 for( i = 0; i < len; i++ ) {
140 if( ! jh->Set_blob_ele( (char *) "members", i ) ) {
142 fprintf( stderr, (char *) "couldn't set blob for element %d\n", i );
144 fprintf( stderr, (char *) "<INFO> testing element %d of %d\n", i, len );
146 state = jh->Is_value( (char *) "age" );
147 errors += fail_if( !state, "is value test for age returned false" );
148 state = jh->Is_value( (char *) "married" );
149 errors += fail_if( state, "is value test for married returned true" );
151 state = jh->Is_string( (char *) "occupation" );
152 errors += fail_if( !state, "is string test for spouse returned false" );
153 state = jh->Is_string( (char *) "married" );
154 errors += fail_if( state, "is string test for married returned true" );
156 state = jh->Is_bool( (char *) "married" );
157 errors += fail_if( !state, "is bool test for married returned false" );
158 state = jh->Is_bool( (char *) "occupation" );
159 errors += fail_if( state, "is bool test for spouse returned true" );
161 val = jh->Value( (char *) "age" );
162 fprintf( stderr, "<INFO> got age: %.2f\n", (double) val );
163 errors += fail_if( val < 0, "age value wasn't positive" );
165 sval = jh->String( (char *) "name" );
166 fprintf( stderr, "<INFO> sval=(%s)\n", sval.c_str() );
167 errors += fail_if( sval.compare( "" ) == 0, "no name found in element" );
169 if( jh->Bool( (char *) "married" ) ) {
174 jh->Unset_blob(); // must return to root
177 fprintf( stderr, "<INFO> true count = %d\n", true_count );
178 errors += fail_if( true_count != 3, "married == true count was not right" );
181 state = jh->Set_blob( (char *) "no-such-thing" );
182 errors += fail_if( state, "setting blob to non-existant blob returned true" );
184 state = jh->Set_blob( (char *) "grand_poobah" );
185 errors += fail_if( !state, "setting blob to existing blob failed" );
187 sval = jh->String( (char *) "elected" );
188 fprintf( stderr, "<INFO> sval=(%s)\n", sval.c_str() );
189 errors += fail_if( sval != "February 2019", "blob 'elected' didn't return the expected string" );
191 state = jh->Exists( (char *) "monthly_dues" );
192 errors += fail_if( state, "blob that shouldn't have a field reports it does" );
194 jh->Unset_blob( ); // ensure that this is found once we unset to root
195 state = jh->Exists( (char *) "monthly_dues" );
196 errors += fail_if( !state, "after rest, root blob, that should have a field, reports it does not" );
200 // ---- test array element value type checks -------------------------------------------------
201 state = jh->Is_string_ele( (char *) "sponser", 1 );
202 errors += fail_if( !state, "string element check on sponser failed" );
203 state = jh->Is_string_ele( (char *) "current_on_dues", 1 );
204 errors += fail_if( state, "string element check on non-stirng element returned true" );
206 state = jh->Is_value_ele( (char *) "dues_assistance", 1 );
207 errors += fail_if( !state, "value element type check on value element reported false" );
208 state = jh->Is_value_ele( (char *) "current_on_dues", 1 );
209 errors += fail_if( state, "value element type check on non-value element returned true" );
211 state = jh->Is_bool_ele( (char *) "current_on_dues", 1 );
212 errors += fail_if( !state, "string element check on sponser failed" );
213 state = jh->Is_bool_ele( (char *) "sponser", 1 );
214 errors += fail_if( state, "string element check on non-stirng element returned true" );
216 state = jh->Is_null( (char *) "nvt" );
217 errors += fail_if( !state, "test for nil value returned false" );
218 state = jh->Is_null( (char *) "lodge_number" );
219 errors += fail_if( state, "nil test for non-nil value returned true" );
221 state = jh->Is_null_ele( (char *) "nvat", 0 );
222 errors += fail_if( !state, "test for nil array element value returned false" );
225 // ---- test sussing of elements from arrays -------------------------------------------------
226 sval = jh->String_ele( (char *) "sponser", 1 );
227 errors += fail_if( sval.compare( "" ) == 0, "get string element failed for sponser (empty string)" );
228 errors += fail_if( sval.compare( "slate" ) != 0, "get string element failed for sponser (wrong value for[1])" );
230 sval = jh->String_ele( (char *) "sponser", 0 );
231 errors += fail_if( sval.compare( "slate" ) != 0, "get string element failed for sponser (wrong value for [0])" );
233 sval = jh->String_ele( (char *) "sponser", 3 );
234 errors += fail_if( sval.compare( "brick" ) != 0, "get string element failed for sponser (wrong value for [3])" );
236 val = jh->Value_ele( (char *) "dues_assistance", 1 );
237 errors += fail_if( val == 0.0, "get value element for dues_assistance was zero" );
239 state = jh->Bool_ele( (char *) "current_on_dues", 1 );
240 errors += fail_if( state, "bool ele test returned true for a false value" );
241 state = jh->Bool_ele( (char *) "current_on_dues", 0 );
242 errors += fail_if( !state, "bool ele test returned false for a true value" );
245 val = jh->Value( (char *) "timestamp" );
246 fprintf( stderr, "<INFO> timestamp: %.10f\n", val );
248 jh->Dump(); // for coverage of debug things
251 // ----- jhashes can be moved, drive that logic for coverage
252 xapp::Jhash j2( "{}" );
254 xapp::Jhash j1 = std::move( *jh ); // drives move constructor function
255 j2 = std::move( j1 ); // drives move operator function
261 fprintf( stderr, "<INFO> testing for failures; jwrapper error and warning messages expected\n" );
262 // ---- these shouild all fail to parse, generate warnings to stderr, and drive error handling coverage ----
263 jh = new xapp::Jhash( (char *) "{ \"bad\": [ [ 1, 2, 3 ], [ 3, 4, 5]] }" ); // drive the exception process for bad json
266 jh = new xapp::Jhash( (char *) " \"bad\": 5 }" ); // no opening brace
267 state = jh->Parse_errors();
268 errors += fail_if( !state, "parse errors check returned false when known errors exist" );
271 jh = new xapp::Jhash( (char *) "{ \"bad\": fred }" ); // no quotes
274 jh = new xapp::Jhash( (char *) "{ \"bad: 456, \"good\": 100 }" ); // missing quote; impossible to detect error
275 jh->Dump(); // but dump should provide details
276 fprintf( stderr, "<INFO> good value=%d\n", (int) val );
280 // ---------------------------- end housekeeping ---------------------------
281 announce_results( errors );