Add API allowing xAPPs to send alarm messages
[ric-plt/xapp-frame-cpp.git] / test / jhash_test.cpp
1 // vim: ts=4 sw=4 noet :
2 /*
3 ==================================================================================
4        Copyright (c) 2020 Nokia
5        Copyright (c) 2020 AT&T Intellectual Property.
6
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
10
11        http://www.apache.org/licenses/LICENSE-2.0
12
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 ==================================================================================
19 */
20
21 /*
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.
27
28         Date:           26 June 2020
29         Author:         E. Scott Daniels
30 */
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <string.h>
38
39 #include <string>
40 #include <memory>
41
42
43 /*
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
46         a file than strings.
47 */
48 static char* read_jstring( char* fname ) {
49         char*   rbuf;
50         int     fd;
51         int len;
52
53         rbuf = (char *) malloc( sizeof( char ) * 8192 );
54         fd = open( fname, O_RDONLY, 0 );
55         if( fd < 0  ) {
56                 fprintf( stderr, "<ABORT> can't open test file: %s: %s\n", fname, strerror( errno ) );
57                 exit( 1 );
58         }
59
60         len = read( fd, rbuf, 8190 );
61         if( len < 0  ) {
62                 close( fd );
63                 fprintf( stderr, "<ABORT> read from file failed: %s: %s\n", fname, strerror( errno ) );
64                 exit( 1 );
65         }
66
67         rbuf[len] = 0;
68         close( fd );
69
70         return rbuf;
71 }
72
73 // this also tests jwrapper.c but that is built as a special object to link in
74 // rather than including here.
75 //
76 #include "../src/json/jhash.hpp"
77 #include "../src/json/jhash.cpp"
78
79 #include "ut_support.cpp"
80
81 int main( int argc, char** argv ) {
82         int             errors = 0;
83         xapp::Jhash*    jh;
84         char*   jstr;
85         std::string     sval;
86         double  val;
87         bool    state;
88         int             i;
89         int             len;
90         int             true_count = 0;
91
92         set_test_name( "jhash_test" );
93         jstr = read_jstring( (char *) "test.json" );                    // read and parse the json
94
95         fprintf( stderr, "read: (%s)\n", jstr );
96
97         jh = new xapp::Jhash( jstr );
98         free( jstr );
99
100         if( jh == NULL ) {
101                 fprintf( stderr, "<FAIL> could not parse json string from: test.json\n" );
102                 exit( 1 );
103         }
104
105
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" );
110
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" );
115
116         state = jh->Exists( (char *) "meeting_place" );
117         errors += fail_if( !state, "test for meeting place exists did not return true" );
118
119         state = jh->Exists( (char *) "no-name" );
120         errors += fail_if( state, "test for non-existant thing returned true" );
121
122         state = jh->Is_missing( (char *) "no-name" );
123         errors += fail_if( !state, "missing test for non-existant thing returned false" );
124
125         state = jh->Is_missing( (char *) "meeting_place" );
126         errors += fail_if( state, "missing test for existing thing returned true" );
127
128         val = jh->Value( (char *) "lodge_number" );
129         errors += fail_if( val != 41.0, "lodge number value was not correct" );
130
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" );
134
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" );
138         if( len > 0 ) {
139                 for( i = 0; i < len; i++ ) {
140                         if( ! jh->Set_blob_ele( (char *) "members", i ) ) {
141                                 errors++;
142                                 fprintf( stderr, (char *) "couldn't set blob for element %d\n", i );
143                         } else {
144                                 fprintf( stderr, (char *) "<INFO> testing element %d of %d\n", i, len );
145
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" );
150
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" );
155
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" );
160
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" );
164
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" );
168
169                                 if( jh->Bool( (char *) "married" ) ) {
170                                         true_count++;
171                                 }
172                         }
173
174                         jh->Unset_blob();               // must return to root
175                 }
176
177                 fprintf( stderr, "<INFO> true count = %d\n", true_count );
178                 errors += fail_if( true_count != 3, "married == true count was not right" );
179         }
180
181         state = jh->Set_blob( (char *) "no-such-thing" );
182         errors += fail_if( state, "setting blob to non-existant blob returned true" );
183
184         state = jh->Set_blob( (char *) "grand_poobah" );
185         errors += fail_if( !state, "setting blob to existing blob failed" );
186         if( state ) {
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" );
190
191                 state = jh->Exists( (char *) "monthly_dues" );
192                 errors += fail_if( state, "blob that shouldn't have a field reports it does" );
193
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" );
197         }
198
199
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" );
205
206         state = jh->Is_value_ele( (char *) "dues_assistance", 1 );
207         errors += fail_if( !state, "string element check on sponser failed" );
208         state = jh->Is_value_ele( (char *) "current_on_dues", 1 );
209         errors += fail_if( state, "string element check on non-stirng element returned true" );
210
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" );
215
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" );
220
221         state = jh->Is_null_ele( (char *) "nvat", 0 );
222         errors += fail_if( !state, "test for nil array element value returned false" );
223
224
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" );
228
229         val = jh->Value_ele( (char *) "dues_assistance", 1 );
230         errors += fail_if( val == 0.0, "get value element for dues_assistance was zero" );
231
232         state = jh->Bool_ele( (char *) "current_on_dues", 1 );
233         errors += fail_if( state, "bool ele test returned true for a false value" );
234         state = jh->Bool_ele( (char *) "current_on_dues", 0 );
235         errors += fail_if( !state, "bool ele test returned false for a true value" );
236
237
238         val = jh->Value( (char *) "timestamp" );
239         fprintf( stderr, "<INFO> timestamp: %.10f\n", val );
240
241
242         //  ----- jhashes can be moved, drive that logic for coverage
243         xapp::Jhash  j2( "{}" );
244
245         xapp::Jhash j1 = std::move( *jh );                              // drives move constructor function
246         j2 = std::move( j1 );                                           // drives move operator function
247
248
249
250         delete jh;
251
252         fprintf( stderr, "<INFO> testing for failures; jwrapper error and warning messages expected\n" );
253         // ---- these shouild all fail to parse, generate warnings to stderr, and drive error handling coverage ----
254     jh = new xapp::Jhash( (char *) "{ \"bad\": [ [ 1, 2, 3 ], [ 3, 4, 5]] }" );         // drive the exception process for bad json
255         delete jh;
256
257     jh = new xapp::Jhash( (char *) " \"bad\":  5 }" );                  // no opening brace
258         state = jh->Parse_errors();
259         errors += fail_if( !state, "parse errors check returned false when known errors exist" );
260         delete jh;
261
262     jh = new xapp::Jhash( (char *) "{ \"bad\":  fred }" );              // no quotes
263         delete jh;
264
265     jh = new xapp::Jhash( (char *) "{ \"bad:  456, \"good\": 100 }" );                  // missing quote; impossible to detect error
266         jh->Dump();                                                                                                                             // but dump should provide details
267         fprintf( stderr, "<INFO> good value=%d\n", (int) val );
268         delete jh;
269
270
271         // ---------------------------- end housekeeping ---------------------------
272         announce_results( errors );
273         return !!errors;
274 }