libadc-cxx 1.0.0
Structured logging for scientific computing
Loading...
Searching...
No Matches
testBuilder.cpp
Go to the documentation of this file.
1/* Copyright 2025 NTESS. See the top-level LICENSE.txt file for details.
2 *
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "adc/factory.hpp"
6#if ADC_BOOST_JSON_PUBLIC
7#include "boost/json/src.hpp"
8#endif
9#include <cerrno>
10#include <cstring>
11#include <limits>
12
13std::map<std::string, std::string> adc_plugin_file_config =
14 {{ "ADC_FILE_PLUGIN_DIRECTORY", "./test.outputs"},
15 { "ADC_FILE_PLUGIN_FILE", "out.file.log" },
16 { "ADC_FILE_PLUGIN_APPEND", "true" }
17 };
18
19std::map<std::string, std::string> file_config =
20 {{ "DIRECTORY", "./test.outputs"},
21 { "FILE", "out.file.log" },
22 { "APPEND", "true" }
23 };
24
25// config w/file_config and call initialize.
26int test_publisher(std::shared_ptr<adc::publisher_api> pi, std::shared_ptr<adc::builder_api> b ) {
27 int err = 0;
28 int e = 0;
29 err = pi->config(file_config);
30 if (err) {
31 std::cout << "config failed " <<
32 std::strerror(err) << std::endl;
33 e += 1;
34 err = 0;
35 }
36 err = pi->initialize();
37 if (err) {
38 std::cout << "initialize failed " <<
39 std::strerror(err) << std::endl;
40 e += 1;
41 err = 0;
42 }
43 err = pi->publish(b); // there should be 1 b in the output
44 if (err) {
45 std::cout << "publish 1 failed " <<
46 std::strerror(err) << std::endl;
47 e += 1;
48 err = 0;
49 }
50 return e;
51}
52
53// check in builder named b for a field named NAME with value VAL and types as CPTYPE and CTYPE
54#define ROUNDTRIP(NAME, VAL, CPTYPE, CTYPE) \
55 ck = b->get_value(NAME); \
56 std::cerr << NAME << " roundtrip " << std::flush ; \
57 if (ck.kt != adc::k_value || ck.count != 1 || ck.st != adc::CPTYPE || \
58 *((CTYPE *)ck.vp) != VAL || !( std::get<CTYPE>(ck.data) == VAL) ) { \
59 std::cerr << "BAD" << std::endl; \
60 std::cerr << "\tkt: " << ck.kt <<std::endl; \
61 std::cerr << "\tst: " << to_string(ck.st) <<std::endl; \
62 std::cerr << "\tcount: " << ck.count <<std::endl; \
63 std::cerr << "\tvp: " << (CTYPE *)ck.vp <<std::endl; \
64 std::cerr << "\tdata: " << std::visit(adc::var_string(), ck.data) <<std::endl; \
65 } else \
66 std::cerr << "ok " << std::visit(adc::var_string(), ck.data) << std::endl
67
68template<typename STYPE>
69static int cmp_argv(std::string *argv, STYPE *val, size_t count)
70{
71 for (size_t i = 0; i < count; i++) {
72 if (argv[i] != std::string(val[i])) {
73 return 1;
74 }
75 }
76 return 0;
77}
78
79#define ROUNDTRIP_ARRAY_STRING(NAME, VAL, COUNT, CTYPE_VAL) roundtrip_array_string<CTYPE_VAL>(NAME, VAL, COUNT, b)
80template <typename STYPE>
81static void roundtrip_array_string(const char *name, STYPE* val, size_t count, std::shared_ptr< adc::builder_api > b)
82{
83 auto ck = b->get_value(name);
84 std::cerr << name << " roundtrip " << std::flush;
85
86 if (ck.kt != adc::k_value) {
87 std::cerr << "\n WRONG kt" << std::endl;
88 } else if ( ck.st != adc::cp_cstr ) {
89 std::cerr << "\n WRONG st" << std::endl;
90 } else if (ck.count != count) {
91 std::cerr << "\n WRONG: NOT len " << count <<
92 " (" << ck.count << " instead)" << std::endl;
93 } else if ( cmp_argv<STYPE>((std::string *)ck.vp, val, count) ) {
94 std::cerr << "\n WRONG data" << std::endl;
95 for (size_t i = 0; i < count; i++) {
96 std::cerr << "[" << i << "]:" <<
97 ((std::string *)ck.vp)[i] << " vs " << val[i] << std::endl;
98 }
99 } else {
100 std::cerr << " ok " << ck.container << std::endl;
101 return;
102 }
103 std::cerr << "BAD" << std::endl;
104 std::cerr << "\tkt: " << ck.kt <<std::endl;
105 std::cerr << "\tst: " << to_string(ck.st) <<std::endl;
106 std::cerr << "\tcount: " << ck.count <<std::endl;
107 std::cerr << "\tvp: " << std::endl;
108 std::string *argv = (std::string *)ck.vp;
109 for (size_t i = 0; i < count; i++) {
110 std::cerr << "\t\t" << argv[i] << std::endl;
111 }
112 std::cerr << "\tdata: " << std::visit(adc::var_string(ck.count), ck.data) <<std::endl; \
113 std::cerr << "\tcontainer: " << ck.container << std::endl; \
114}
115
116
117#define ROUNDTRIP_ARRAY(NAME, VAL, COUNT, CTYPE, CPTYPE) roundtrip_array<CTYPE>(NAME, VAL, adc:: CPTYPE, COUNT, b)
118template<typename CTYPE >
119void roundtrip_array(const char *name, CTYPE* val, adc::scalar_type cptype, size_t count, std::shared_ptr< adc::builder_api > b)
120{
121 auto ck = b->get_value(name);
122 std::cerr << name << " roundtrip " << std::flush;
123
124 if (ck.kt != adc::k_value) {
125 std::cerr << "\n WRONG kt" << std::endl;
126 } else if ( ck.st != cptype ) {
127 std::cerr << "\n WRONG st" << std::endl;
128 } else if (ck.count != count) {
129 std::cerr << "\n WRONG: NOT len " << count <<
130 " (" << ck.count << " instead)" << std::endl;
131 } else if ( memcmp(ck.vp, val, sizeof(CTYPE)*count) ) {
132 std::cerr << "\n WRONG data" << std::endl;
133 for (size_t i = 0; i < count; i++) {
134 std::cerr << "[" << i << "]:" <<
135 ((CTYPE *)ck.vp)[i] << " vs " << val[i] << std::endl;
136 }
137 } else {
138 std::cerr << " ok" << std::endl;
139 return;
140 }
141 std::cerr << "BAD" << std::endl;
142 std::cerr << "\tkt: " << ck.kt <<std::endl;
143 std::cerr << "\tst: " << to_string(ck.st) <<std::endl;
144 std::cerr << "\tcount: " << ck.count <<std::endl;
145 std::cerr << "\tvp: " << (CTYPE *)ck.vp <<std::endl;
146 std::cerr << "\tdata: " << std::visit(adc::var_string(ck.count), ck.data) <<std::endl; \
147}
148
149void roundtrip_string(const char *name, const char *val, adc::scalar_type cptype, std::shared_ptr< adc::builder_api > b)
150{
151 auto ck = b->get_value(name);
152 std::cerr << name << " roundtrip " << std::flush;
153 if (ck.kt != adc::k_value) {
154 std::cerr << "\n WRONG kt" << std::endl;
155 } else if ( ck.count != strlen(val) ) {
156 std::cerr << "\n WRONG count" << std::endl;
157 } else if ( ck.st != cptype ) {
158 std::cerr << "\n WRONG st" << std::endl;
159 } else if ( strcmp(((const char *)ck.vp), val) != 0 ) {
160 std::cerr << "\n WRONG vp" << std::endl;
161 } else {
162 std::cerr << " ok" << std::endl;
163 return;
164 }
165 std::cerr << val << " vs vp " << (const char *)ck.vp << std::endl;
166 std::cerr << "\tkt: " << ck.kt <<std::endl;
167 std::cerr << "\tst: " << adc::to_string(ck.st) << std::endl;
168 std::cerr << "\tcount: " << ck.count << std::endl;
169 std::cerr << "\tdata: " << std::visit(adc::var_string(), ck.data) << std::endl;
170}
171
172#if 0
173// check in builder named b for a string named NAME with char * value VAL and type as CPTYPE.
174// Unclear why this macro generates useafterdelete for some cases while the function version
175// does not. Some string apparently goes out of scope unexpectedly.
176#define ROUNDTRIP_STRING(NAME, VAL, CPTYPE) \
177 ck = b->get_value(NAME); \
178 std::cerr << NAME << " roundtrip " << std::flush; \
179 if (ck.kt != adc::k_value || ck.count != strlen(VAL) || \
180 ck.st != adc::CPTYPE || strcmp(((const char *)ck.vp), VAL) != 0 ) { \
181 std::cerr << " BAD " << VAL << " vs " << (const char *)ck.vp << std::endl; \
182 std::cerr << "\tkt: " << ck.kt <<std::endl; \
183 std::cerr << "\tst: " << to_string(ck.st) <<std::endl; \
184 std::cerr << "\tcount: " << ck.count << std::endl; \
185 std::cerr << "\tdata: " << std::visit(adc::var_string(), ck.data) <<std::endl; \
186 } else \
187 std::cerr << " ok" << std::endl
188#else
189#define ROUNDTRIP_STRING(NAME, VAL, CPTYPE) roundtrip_string(NAME, VAL, adc:: CPTYPE, b)
190#endif
191
192
193void populate_builder(std::shared_ptr< adc::builder_api > b, adc::factory & f) {
194#if ADC_BOOST_JSON_PUBLIC
195 boost::json::object jo = {{"a","b"},{"C","d"},{"n",1}};
196#endif
197 adc::field ck;
198 b->add("bool0", false);
199#if 1
200 ROUNDTRIP("bool0", false, cp_bool, bool);
201#else
202 ck = b->get_value("bool0"); \
203 if (ck.kt != adc::k_value || ck.count != 1 || ck.st != adc::cp_bool ||
204 *((bool *)ck.vp) != false || std::get<bool>(ck.data) != false)
205 std::cerr << "bool0" << " not returned correctly" << std::endl;
206#endif
207
208 b->add("bool1", true);
209 ROUNDTRIP("bool1", true, cp_bool, bool);
210
211 b->add("char1", 'A');
212 ROUNDTRIP("char1", 'A', cp_char, char);
213 char16_t c16 = u'¢';
214 b->add("c16", c16);
215 ROUNDTRIP("c16", c16, cp_char16, char16_t);
216 char32_t c32 = U'猫';
217 b->add("c32", c32);
218 ROUNDTRIP("c32", c32, cp_char32, char32_t);
219
220 uint8_t u8 = std::numeric_limits<uint8_t>::max() / 2;
221 uint16_t u16 = std::numeric_limits<uint16_t>::max() / 2;
222 uint32_t u32 = std::numeric_limits<uint32_t>::max() / 2;
223 uint64_t u64 = std::numeric_limits<uint64_t>::max() / 2;
224 b->add("u8", u8);
225 ROUNDTRIP("u8", u8, cp_uint8, uint8_t);
226 b->add("u16", u16);
227 ROUNDTRIP("u16", u16, cp_uint16, uint16_t);
228 b->add("u32", u32);
229 ROUNDTRIP("u32", u32, cp_uint32, uint32_t);
230 b->add("u64", u64);
231 ROUNDTRIP("u64", u64, cp_uint64, uint64_t);
232 int8_t i8 = std::numeric_limits<int8_t>::max() / 2;
233 int16_t i16 = std::numeric_limits<int16_t>::max() / 2;
234 int32_t i32 = std::numeric_limits<int32_t>::max() / 2;
235 int64_t i64 = std::numeric_limits<int64_t>::max() / 2;
236 float flt = std::numeric_limits<float>::max() / 2;
237 double dbl = std::numeric_limits<double>::max() / 2 ;
238 b->add("i8", i8);
239 ROUNDTRIP("i8", i8, cp_int8, int8_t);
240 b->add("i16", i16);
241 ROUNDTRIP("i16", i16, cp_int16, int16_t);
242 b->add("i32", i32);
243 ROUNDTRIP("i32", i32, cp_int32, int32_t);
244 b->add("i64", i64);
245 ROUNDTRIP("i64", i64, cp_int64, int64_t);
246 b->add("flt", flt);
247 ROUNDTRIP("flt", flt, cp_f32, float);
248 b->add("dbl", dbl);
249 ROUNDTRIP("dbl", dbl, cp_f64, double);
250
251 std::complex<float> fcplx(flt, flt);
252 std::complex<double> dcplx(dbl,dbl);
253
254 b->add("fcplx", fcplx);
255 ROUNDTRIP("fcplx", fcplx, cp_c_f32, std::complex<float>);
256
257 b->add("dcplx", dcplx);
258 ROUNDTRIP("dcplx", dcplx, cp_c_f64, std::complex<double>);
259
260 const std::string ccppstr("ccppstr");
261 b->add("ccppstr", ccppstr);
262 ROUNDTRIP_STRING("ccppstr", ccppstr.c_str(), cp_cstr);
263
264 std::string cppstr("cppstr");
265 b->add("cppstr", cppstr);
266 ROUNDTRIP_STRING("cppstr", cppstr.c_str(), cp_cstr);
267
268 const char *cstr = "cstr_nul";
269 b->add("cstr1", cstr);
270 ROUNDTRIP_STRING("cstr1", cstr, cp_cstr);
271
272 const char *jstr = "{\"a\":\"b\", \"c\":[1,2, 3]}";
273 b->add_json_string("jstr1", std::string(jstr));
274 ROUNDTRIP_STRING("jstr1", jstr, cp_json_str);
275
276 const char *ystr = "---\na: b\nc: [1,2, 3]\nd:\n e: 1\n f: 2";
277 b->add_yaml_string("ystr1", ystr);
278 ROUNDTRIP_STRING("ystr1", ystr, cp_yaml_str);
279
280 const char *xstr = "<note> <to>Tove</to> <from>Jani</from> </note>";
281 b->add_xml_string("xstr1", std::string (xstr));
282 ROUNDTRIP_STRING("xstr1", xstr, cp_xml_str);
283
284 const char *nstr = "1234567890123456789012345678901234567890.123";
285 b->add_number_string("number1", std::string (nstr));
286 ROUNDTRIP_STRING("number1", nstr, cp_number_str);
287#if ADC_BOOST_JSON_PUBLIC
288 b->add("jsonobj", jo);
289#endif
290 // fixme roundtrip complex
291 const char *cstrings[] = {"a", "B", "c2"};
292 char *vcstrings[4];
293 int32_t ia[4];
294 float fa[4];
295 double da[4];
296 uint64_t ua[4];
297 for (int i = 0; i < 4; i++) {
298 vcstrings[i] = new char[2];
299 snprintf(vcstrings[i], 2, "%d", i);
300 ua[i] = i;
301 ia[i] = -i;
302 da[i] = 3.14*i;
303 fa[i] = 3.14*i *2;
304 }
305 b->add_array("ia", ia, 4);
306 b->add_array("ua", ua, 4);
307 b->add_array("fa", fa, 4);
308 b->add_array("da", da, 4);
309 ROUNDTRIP_ARRAY("ia", ia, 4, int32_t, cp_int32);
310 ROUNDTRIP_ARRAY("ua", ua, 4, uint64_t, cp_uint64);
311 ROUNDTRIP_ARRAY("fa", fa, 4, float, cp_f32);
312 ROUNDTRIP_ARRAY("da", da, 4, double, cp_f64);
313
314 b->add_array("nulembed", "a\0b", 3);
315 ROUNDTRIP_ARRAY("nulembed", "a\0b", 3, const char, cp_char);
316
317 std::string cppstrings[] = {"ap", "Bp", "c2p"};
318 b->add_array("cstrs", cstrings, 3);
319 ROUNDTRIP_ARRAY_STRING("cstrs", cstrings, 3, const char *);
320 b->add_array("cppstrs", cppstrings, 3);
321 ROUNDTRIP_ARRAY_STRING("cppstrs", cppstrings, 3, std::string);
322 b->add_array("vcstrs", vcstrings, 4);
323 ROUNDTRIP_ARRAY_STRING("vcstrs", vcstrings, 4, char *);
324 for (int i = 0; i < 4; i++) {
325 delete [] vcstrings[i];
326 }
327 const char *e1="a1", *e2="a2", *e3="a3",* eb="b",* ec="c_";
328 std::vector<std::string> tcsv = { e1, eb, ec };
329 std::list<std::string> tcsl = { e2, eb, ec };
330 std::set<std::string> tcss = { e3, eb, ec };
331 const char * tcsv_a[] = { e1, eb, ec };
332 const char * tcsl_a[] = { e2, eb, ec };
333 const char * tcss_a[] = { e3, eb, ec };
334
335 b->add_array("sv", tcsv);
336 b->add_array("sl", tcsl);
337 b->add_array("ss", tcss);
338 ROUNDTRIP_ARRAY_STRING("sv", tcsv_a, 3, const char *);
339 ROUNDTRIP_ARRAY_STRING("sl", tcsl_a, 3, const char *);
340 // the ss test depends on strcmp order of tcss to match sortedness of tcss_a
341 ROUNDTRIP_ARRAY_STRING("ss", tcss_a, 3, const char *);
342
343 std::vector<std::string> children = { "uuid1", "uuid2", "uuid3"};
344 b->add_workflow_section();
345 b->add_workflow_children(children);
346
347
348 // section test with host-like data treated as app data
349 std::shared_ptr<adc::builder_api> host = f.get_builder();
350 std::shared_ptr<adc::builder_api> arch = f.get_builder();
351 std::shared_ptr<adc::builder_api> cpu = f.get_builder();
352 std::shared_ptr<adc::builder_api> mem = f.get_builder();
353
354 host->add("name","myhost");
355 host->add("cluster","mycluster");
356 cpu->add("processor","pentium II");
357 mem->add("size", "256G");
358
359 arch->add_section("cpu", cpu);
360 arch->add_section("memory", mem);
361 host->add_section("architecture",arch);
362 b->add_section("host", host);
363
364#if ADC_BOOST_JSON_PUBLIC
365 // section test with host-like data treated as standard schema data (json fields of default types), not app fields)
366 boost::json::object host2;
367 boost::json::object arch2;
368 boost::json::object cpu2;
369 boost::json::object mem2;
370 // fix [ below
371 host2["name"] = "myhost";
372 host2["cluster"]="mycluster";
373 cpu2["processor"]="pentium II";
374 mem2["size"]="256G";
375 arch2["cpu"]= cpu2;
376 arch2["memory"]= mem2;
377 host2["architecture"]=arch2;
378
379 b->add("host2", host2);
380#endif
381
382 //std::vector<short> vs = { 1, 2, 3};
383 //adc::builder_add_vector1(b, "v1", vs);
384 //adc::builder_add_vector2(b, "v2", vs);
385
386
387 std::string ss = b->serialize();
388 std::cout << "-------------------------------" << std::endl;
389 std::cout << ss << std::endl;
390 std::cout << "-------------------------------" << std::endl;
391}
392
393int main(int /* argc */ , char ** /* argv */)
394{
395 std::cout << "adc pub version: " << adc::publisher_api_version.name << std::endl;
396 std::cout << "adc builder version: " << adc::builder_api_version.name << std::endl;
397 std::cout << "adc enum version: " << adc::enum_version.name << std::endl;
398
399 adc::factory f;
400
401 std::shared_ptr< adc::builder_api > b = f.get_builder();
402
403 populate_builder(b, f);
404
405#if 1 // switch to 0 when developing new fields and testing them
406 std::shared_ptr< adc::publisher_api > p0 = f.get_publisher("none");
407 std::cout << test_publisher(p0, b) << std::endl;
408
409 std::shared_ptr< adc::publisher_api > p1 = f.get_publisher("file");
410 std::cout << test_publisher(p1, b) << std::endl;
411
412 std::shared_ptr< adc::publisher_api > p2 = f.get_publisher("stdout");
413 std::cout << test_publisher(p2, b) << std::endl;
414
415 std::shared_ptr< adc::publisher_api > p3 = f.get_publisher("syslog");
416 std::cout << test_publisher(p3, b) << std::endl;
417
418 std::shared_ptr<adc::multi_publisher_api> mp = f.get_multi_publisher();
419 mp->add(p0);
420 mp->add(p1);
421 mp->add(p2);
422 mp->add(p3);
423 mp->publish(b);
424 mp->pause();
425 mp->publish(b);
426 mp->resume();
427 mp->publish(b);
428 mp->terminate();
429#endif
430 int n;
431 if ((n = adc::test_enum_strings()))
432 std::cout << "scalar_type and to_string(st) are inconsistent: " << n << std::endl;
433 return 0;
434}
provides publishers and builders of application metadata.
Definition factory.hpp:34
std::shared_ptr< publisher_api > get_publisher(const std::string &name)
Definition factory.ipp:178
std::shared_ptr< multi_publisher_api > get_multi_publisher()
Definition factory.ipp:115
std::shared_ptr< builder_api > get_builder()
Definition factory.ipp:300
return string for printing from variant v.
Definition types.hpp:201
int test_enum_strings()
return non-zero if to_string and enum scalar_type are inconsisent.
Definition enums.ipp:364
version enum_version("1.0.0", {"none"})
the version number of enum scalar_type and object_type
const std::string to_string(float f)
get string of float using to_chars.
Definition enums.ipp:132
version publisher_api_version("1.0.0", {"none"})
version builder_api_version("1.0.0", {"none"})
scalar_type
field types for scientific data encode/decode with json.
Definition types.hpp:62
@ k_value
Definition types.hpp:115
@ cp_bool
bool (true/false,1/0)
Definition types.hpp:64
@ cp_cstr
c null-terminated string
Definition types.hpp:69
scalar_type st
scalar type of the data as published,
Definition types.hpp:165
size_t count
number of elements in vp.
Definition types.hpp:167
variant data
Definition types.hpp:169
key_type kt
kind of data associated with the name queried
Definition types.hpp:164
const void * vp
address of data to be cast according to st for use with c/fortran
Definition types.hpp:166
const std::string name
Definition types.hpp:29
void roundtrip_string(const char *name, const char *val, adc::scalar_type cptype, std::shared_ptr< adc::builder_api > b)
int main(int, char **)
void roundtrip_array(const char *name, CTYPE *val, adc::scalar_type cptype, size_t count, std::shared_ptr< adc::builder_api > b)
#define ROUNDTRIP_ARRAY_STRING(NAME, VAL, COUNT, CTYPE_VAL)
#define ROUNDTRIP_ARRAY(NAME, VAL, COUNT, CTYPE, CPTYPE)
void populate_builder(std::shared_ptr< adc::builder_api > b, adc::factory &f)
#define ROUNDTRIP(NAME, VAL, CPTYPE, CTYPE)
int test_publisher(std::shared_ptr< adc::publisher_api > pi, std::shared_ptr< adc::builder_api > b)
std::map< std::string, std::string > file_config
#define ROUNDTRIP_STRING(NAME, VAL, CPTYPE)
std::map< std::string, std::string > adc_plugin_file_config