From 082cc6eb92827c447942f6688b97bb0e7dd162c5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 20 Aug 2018 18:32:10 +0200 Subject: [PATCH] tests: fix unit tests --- tests/unit/io.c | 325 +++++++++++++++++++++++++------------------ tests/unit/mapping.c | 19 +-- 2 files changed, 203 insertions(+), 141 deletions(-) diff --git a/tests/unit/io.c b/tests/unit/io.c index c4140d5a1..d7185b28a 100644 --- a/tests/unit/io.c +++ b/tests/unit/io.c @@ -30,195 +30,235 @@ #include #include #include +#include #include #include #include #include -#define NUM_SAMPLES 10 +extern void init_memory(); + #define NUM_VALUES 10 -static char formats[][32] = { -#ifdef LIBHDF5_FOUND - "hdf5", -#endif -#ifdef LIBPROTOBUF_FOUND - "protobuf", -#endif - "raw.int8", - "raw.int16.be", - "raw.int16.le", - "raw.int32.be", - "raw.int32.le", - "raw.int64.be", - "raw.int64.le", - "raw.flt32", - "raw.flt64", - "villas.human", - "villas.binary", - "csv", - "json", - "gtnet", - "gtnet.fake" +struct param { + const char *fmt; + int cnt; + int bits; }; -void generate_samples(struct pool *p, struct sample *smps[], struct sample *smpt[], unsigned cnt, unsigned values) +static struct param params[] = { + { "gtnet", 1, 32 }, + { "gtnet.fake", 1, 32 }, + { "raw.8", 1, 8 }, + { "raw.16.be", 1, 16 }, + { "raw.16.le", 1, 16 }, + { "raw.32.be", 1, 32 }, + { "raw.32.le", 1, 32 }, + { "raw.64.be", 1, 64 }, + { "raw.64.le", 1, 64 }, + { "villas.human", 10, 0 }, + { "villas.binary", 10, 0 }, + { "csv", 10, 0 }, + { "json", 10, 0 }, +#ifdef LIBPROTOBUF_FOUND + { "protobuf", 10, 0 } +#endif +}; + +void fill_sample_data(struct list *signals, struct sample *smps[], unsigned cnt) { - int ret; struct timespec delta, now; - /* Prepare a sample with arbitrary data */ - ret = sample_alloc_many(p, smps, cnt); - cr_assert_eq(ret, NUM_SAMPLES); - - ret = sample_alloc_many(p, smpt, cnt); - cr_assert_eq(ret, cnt); - now = time_now(); delta = time_from_double(50e-6); for (int i = 0; i < cnt; i++) { - smpt[i]->capacity = values; - - smps[i]->flags = SAMPLE_HAS_SEQUENCE | SAMPLE_HAS_VALUES | SAMPLE_HAS_ORIGIN | SAMPLE_HAS_FORMAT; - smps[i]->length = values; + smps[i]->flags = SAMPLE_HAS_SEQUENCE | SAMPLE_HAS_DATA | SAMPLE_HAS_TS_ORIGIN; + smps[i]->length = list_length(signals); smps[i]->sequence = 235 + i; - smps[i]->format = 0; /* all float */ smps[i]->ts.origin = now; + smps[i]->signals = signals; - for (int j = 0; j < smps[i]->length; j++) { - smps[i]->data[j].f = j * 0.1 + i * 100; - //smps[i]->data[j].i = -500 + j*100; + for (int j = 0; j < list_length(signals); j++) { + struct signal *sig = (struct signal *) list_at(signals, j); + + switch (sig->type) { + case SIGNAL_TYPE_BOOLEAN: + smps[i]->data[j].b = j * 0.1 + i * 100; + break; + + case SIGNAL_TYPE_COMPLEX: + smps[i]->data[j].z = CMPLXF(j * 0.1, i * 100); + break; + + case SIGNAL_TYPE_FLOAT: + smps[i]->data[j].f = j * 0.1 + i * 100; + break; + + case SIGNAL_TYPE_INTEGER: + smps[i]->data[j].i = j + i * 1000; + break; + + default: { } + } } now = time_add(&now, &delta); } } -void cr_assert_eq_sample(struct sample *a, struct sample *b) +void cr_assert_eq_sample(struct sample *a, struct sample *b, int flags) { cr_assert_eq(a->length, b->length); - cr_assert_eq(a->sequence, b->sequence); - cr_assert_eq(a->ts.origin.tv_sec, b->ts.origin.tv_sec); - cr_assert_eq(a->ts.origin.tv_nsec, b->ts.origin.tv_nsec); + if (flags & SAMPLE_HAS_SEQUENCE) + cr_assert_eq(a->sequence, b->sequence); - for (int j = 0; j < MIN(a->length, b->length); j++) { - cr_assert_eq(sample_get_data_format(a, j), sample_get_data_format(b, j)); + if (flags & SAMPLE_HAS_TS_ORIGIN) { + cr_assert_eq(a->ts.origin.tv_sec, b->ts.origin.tv_sec); + cr_assert_eq(a->ts.origin.tv_nsec, b->ts.origin.tv_nsec); + } - switch (sample_get_data_format(b, j)) { - case SAMPLE_DATA_FORMAT_FLOAT: - cr_assert_float_eq(a->data[j].f, b->data[j].f, 1e-3, "Sample data mismatch at index %d: %f != %f", j, a->data[j].f, b->data[j].f); - break; - case SAMPLE_DATA_FORMAT_INT: - cr_assert_eq(a->data[j].i, b->data[j].i, "Sample data mismatch at index %d: %lld != %lld", j, a->data[j].i, b->data[j].i); - break; + if (flags & SAMPLE_HAS_DATA) { + for (int j = 0; j < MIN(a->length, b->length); j++) { + cr_assert_eq(sample_format(a, j), sample_format(b, j)); + + switch (sample_format(b, j)) { + case SIGNAL_TYPE_FLOAT: + cr_assert_float_eq(a->data[j].f, b->data[j].f, 1e-3, "Sample data mismatch at index %d: %f != %f", j, a->data[j].f, b->data[j].f); + break; + + case SIGNAL_TYPE_INTEGER: + cr_assert_eq(a->data[j].i, b->data[j].i, "Sample data mismatch at index %d: %lld != %lld", j, a->data[j].i, b->data[j].i); + break; + + case SIGNAL_TYPE_BOOLEAN: + cr_assert_eq(a->data[j].b, b->data[j].b, "Sample data mismatch at index %d: %s != %s", j, a->data[j].b ? "true" : "false", b->data[j].b ? "true" : "false"); + break; + + case SIGNAL_TYPE_COMPLEX: + cr_assert_float_eq(cabs(a->data[j].z - b->data[j].z), 0, 1e-6, "Sample data mismatch at index %d: %f+%fi != %f+%fi", j, creal(a->data[j].z), cimag(a->data[j].z), creal(b->data[j].z), cimag(b->data[j].z)); + break; + + default: { } + } } } } -void cr_assert_eq_samples(struct format_type *f, struct sample *smps[], struct sample *smpt[], unsigned cnt) +void cr_assert_eq_sample_raw(struct sample *a, struct sample *b, int flags, int bits) { - /* The RAW format has certain limitations: - * - limited accuracy if smaller datatypes are used - * - no support for vectors / framing - * - * We need to take these limitations into account before comparing. - */ - if (f->sscan == raw_sscan) { - cr_assert_eq(cnt, 1); - cr_assert_eq(smpt[0]->length, smpt[0]->capacity, "Expected values: %d, Received values: %d", smpt[0]->capacity, smpt[0]->length); + cr_assert_eq(a->length, b->length); - if (f->flags & RAW_FAKE) { + if (flags & SAMPLE_HAS_SEQUENCE) + cr_assert_eq(a->sequence, b->sequence); - } - else { - smpt[0]->sequence = smps[0]->sequence; - smpt[0]->ts.origin = smps[0]->ts.origin; - } + if (flags & SAMPLE_HAS_TS_ORIGIN) { + cr_assert_eq(a->ts.origin.tv_sec, b->ts.origin.tv_sec); + cr_assert_eq(a->ts.origin.tv_nsec, b->ts.origin.tv_nsec); + } - int bits = 1 << (f->flags >> 24); - for (int j = 0; j < smpt[0]->length; j++) { - if (f->flags & RAW_FLT) { - switch (bits) { - case 32: smps[0]->data[j].f = (float) smps[0]->data[j].f; break; - case 64: smps[0]->data[j].f = (double) smps[0]->data[j].f; break; - } - } - else { - switch (bits) { - case 8: smps[0]->data[j].f = ( int8_t) smps[0]->data[j].f; break; - case 16: smps[0]->data[j].f = ( int16_t) smps[0]->data[j].f; break; - case 32: smps[0]->data[j].f = ( int32_t) smps[0]->data[j].f; break; - case 64: smps[0]->data[j].f = ( int64_t) smps[0]->data[j].f; break; - } + if (flags & SAMPLE_HAS_DATA) { + for (int j = 0; j < MIN(a->length, b->length); j++) { + cr_assert_eq(sample_format(a, j), sample_format(b, j)); - /* The RAW format stores raw integer samples in integer format. - However, the test expects floating point data */ - smpt[0]->data[j].f = smpt[0]->data[j].i; - sample_set_data_format(smpt[0], j, SAMPLE_DATA_FORMAT_FLOAT); + switch (sample_format(b, j)) { + case SIGNAL_TYPE_FLOAT: + if (bits != 8 && bits != 16) + cr_assert_float_eq(a->data[j].f, b->data[j].f, 1e-3, "Sample data mismatch at index %d: %f != %f", j, a->data[j].f, b->data[j].f); + break; + + case SIGNAL_TYPE_INTEGER: + cr_assert_eq(a->data[j].i, b->data[j].i, "Sample data mismatch at index %d: %lld != %lld", j, a->data[j].i, b->data[j].i); + break; + + case SIGNAL_TYPE_BOOLEAN: + cr_assert_eq(a->data[j].b, b->data[j].b, "Sample data mismatch at index %d: %s != %s", j, a->data[j].b ? "true" : "false", b->data[j].b ? "true" : "false"); + break; + + case SIGNAL_TYPE_COMPLEX: + if (bits != 8 && bits != 16) + cr_assert_float_eq(cabs(a->data[j].z - b->data[j].z), 0, 1e-6, "Sample data mismatch at index %d: %f+%fi != %f+%fi", j, creal(a->data[j].z), cimag(a->data[j].z), creal(b->data[j].z), cimag(b->data[j].z)); + break; + + default: { } } } } - else - cr_assert_eq(cnt, NUM_SAMPLES, "Read only %d of %d samples back", cnt, NUM_SAMPLES); - - for (int i = 0; i < cnt; i++) - cr_assert_eq_sample(smps[i], smpt[i]); } ParameterizedTestParameters(io, lowlevel) { - return cr_make_param_array(char[32], formats, ARRAY_LEN(formats)); + return cr_make_param_array(struct param, params, ARRAY_LEN(params)); } -ParameterizedTest(char *fmt, io, lowlevel) +ParameterizedTest(struct param *p, io, lowlevel, .init = init_memory) { - int ret; + int ret, cnt; char buf[8192]; size_t wbytes, rbytes; struct format_type *f; - struct pool p = { .state = STATE_DESTROYED }; + struct pool pool = { .state = STATE_DESTROYED }; struct io io = { .state = STATE_DESTROYED }; - struct sample *smps[NUM_SAMPLES]; - struct sample *smpt[NUM_SAMPLES]; + struct list signals = { .state = STATE_DESTROYED }; + struct sample *smps[p->cnt]; + struct sample *smpt[p->cnt]; - ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LENGTH(NUM_VALUES), &memory_hugepage); + ret = pool_init(&pool, 2 * p->cnt, SAMPLE_LENGTH(NUM_VALUES), &memory_hugepage); cr_assert_eq(ret, 0); - info("Running test for format = %s", fmt); + info("Running test for format=%s, cnt=%u", p->fmt, p->cnt); - generate_samples(&p, smps, smpt, NUM_SAMPLES, NUM_VALUES); + list_init(&signals); + signal_list_generate(&signals, NUM_VALUES, SIGNAL_TYPE_FLOAT); - f = format_type_lookup(fmt); - cr_assert_not_null(f, "Format '%s' does not exist", fmt); + ret = sample_alloc_many(&pool, smps, p->cnt); + cr_assert_eq(ret, p->cnt); - ret = io_init(&io, f, NULL, SAMPLE_HAS_ALL); + ret = sample_alloc_many(&pool, smpt, p->cnt); + cr_assert_eq(ret, p->cnt); + + fill_sample_data(&signals, smps, p->cnt); + + f = format_type_lookup(p->fmt); + cr_assert_not_null(f, "Format '%s' does not exist", p->fmt); + + ret = io_init(&io, f, &signals, SAMPLE_HAS_ALL); cr_assert_eq(ret, 0); - ret = io_sprint(&io, buf, sizeof(buf), &wbytes, smps, NUM_SAMPLES); - cr_assert_eq(ret, NUM_SAMPLES); + ret = io_check(&io); + cr_assert_eq(ret, 0); - ret = io_sscan(&io, buf, wbytes, &rbytes, smpt, NUM_SAMPLES); - cr_assert_eq(rbytes, wbytes); + cnt = io_sprint(&io, buf, sizeof(buf), &wbytes, smps, p->cnt); + cr_assert_eq(cnt, p->cnt, "Written only %d of %d samples for format %s", cnt, p->cnt, format_type_name(f)); - cr_assert_eq_samples(f, smps, smpt, ret); + cnt = io_sscan(&io, buf, wbytes, &rbytes, smpt, p->cnt); + cr_assert_eq(cnt, p->cnt, "Read only %d of %d samples back for format %s", cnt, p->cnt, format_type_name(f)); - sample_free_many(smps, NUM_SAMPLES); - sample_free_many(smpt, NUM_SAMPLES); + cr_assert_eq(rbytes, wbytes, "rbytes != wbytes: %#zx != %#zx", rbytes, wbytes); - ret = pool_destroy(&p); + for (int i = 0; i < cnt; i++) { + if (p->bits) + cr_assert_eq_sample_raw(smps[i], smpt[i], f->flags, p->bits); + else + cr_assert_eq_sample(smps[i], smpt[i], f->flags); + } + + sample_free_many(smps, p->cnt); + sample_free_many(smpt, p->cnt); + + ret = pool_destroy(&pool); cr_assert_eq(ret, 0); } ParameterizedTestParameters(io, highlevel) { - return cr_make_param_array(char[32], formats, ARRAY_LEN(formats)); + return cr_make_param_array(struct param, params, ARRAY_LEN(params)); } -ParameterizedTest(char *fmt, io, highlevel) +ParameterizedTest(struct param *p, io, highlevel, .init = init_memory) { int ret, cnt; char *retp; @@ -226,16 +266,27 @@ ParameterizedTest(char *fmt, io, highlevel) struct format_type *f; struct io io = { .state = STATE_DESTROYED }; - struct pool p = { .state = STATE_DESTROYED }; - struct sample *smps[NUM_SAMPLES]; - struct sample *smpt[NUM_SAMPLES]; + struct pool pool = { .state = STATE_DESTROYED }; + struct list signals = { .state = STATE_DESTROYED }; - info("Running test for format = %s", fmt); + struct sample *smps[p->cnt]; + struct sample *smpt[p->cnt]; - ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LENGTH(NUM_VALUES), &memory_hugepage); + info("Running test for format=%s, cnt=%u", p->fmt, p->cnt); + + ret = pool_init(&pool, 2 * p->cnt, SAMPLE_LENGTH(NUM_VALUES), &memory_hugepage); cr_assert_eq(ret, 0); - generate_samples(&p, smps, smpt, NUM_SAMPLES, NUM_VALUES); + ret = sample_alloc_many(&pool, smps, p->cnt); + cr_assert_eq(ret, p->cnt); + + ret = sample_alloc_many(&pool, smpt, p->cnt); + cr_assert_eq(ret, p->cnt); + + list_init(&signals); + signal_list_generate(&signals, NUM_VALUES, SIGNAL_TYPE_FLOAT); + + fill_sample_data(&signals, smps, p->cnt); /* Open a file for IO */ char *fn, dir[64]; @@ -248,24 +299,27 @@ ParameterizedTest(char *fmt, io, highlevel) ret = asprintf(&fn, "%s/file", dir); cr_assert_gt(ret, 0); - f = format_type_lookup(fmt); - cr_assert_not_null(f, "Format '%s' does not exist", fmt); + f = format_type_lookup(p->fmt); + cr_assert_not_null(f, "Format '%s' does not exist", p->fmt); - ret = io_init(&io, f, NULL, SAMPLE_HAS_ALL); + ret = io_init(&io, f, &signals, SAMPLE_HAS_ALL); + cr_assert_eq(ret, 0); + + ret = io_check(&io); cr_assert_eq(ret, 0); ret = io_open(&io, fn); cr_assert_eq(ret, 0); - ret = io_print(&io, smps, NUM_SAMPLES); - cr_assert_eq(ret, NUM_SAMPLES); + cnt = io_print(&io, smps, p->cnt); + cr_assert_eq(cnt, p->cnt, "Written only %d of %d samples for format %s", cnt, p->cnt, format_type_name(f)); ret = io_flush(&io); cr_assert_eq(ret, 0); #if 0 /* Show the file contents */ char cmd[128]; - if (!strcmp(fmt, "csv") || !strcmp(fmt, "json") || !strcmp(fmt, "villas.human")) + if (!strcmp(p->fmt, "csv") || !strcmp(p->fmt, "json") || !strcmp(p->fmt, "villas.human")) snprintf(cmd, sizeof(cmd), "cat %s", fn); else snprintf(cmd, sizeof(cmd), "hexdump -C %s", fn); @@ -277,10 +331,17 @@ ParameterizedTest(char *fmt, io, highlevel) if (io.mode == IO_MODE_ADVIO) adownload(io.in.stream.adv, 0); - cnt = io_scan(&io, smpt, NUM_SAMPLES); + cnt = io_scan(&io, smpt, p->cnt); cr_assert_gt(cnt, 0, "Failed to read samples back: cnt=%d", cnt); - cr_assert_eq_samples(f, smps, smpt, cnt); + cr_assert_eq(cnt, p->cnt, "Read only %d of %d samples back", cnt, p->cnt); + + for (int i = 0; i < cnt; i++) { + if (p->bits) + cr_assert_eq_sample_raw(smps[i], smpt[i], f->flags, p->bits); + else + cr_assert_eq_sample(smps[i], smpt[i], f->flags); + } ret = io_close(&io); cr_assert_eq(ret, 0); @@ -296,9 +357,9 @@ ParameterizedTest(char *fmt, io, highlevel) free(fn); - sample_free_many(smps, NUM_SAMPLES); - sample_free_many(smpt, NUM_SAMPLES); + sample_free_many(smps, p->cnt); + sample_free_many(smpt, p->cnt); - ret = pool_destroy(&p); + ret = pool_destroy(&pool); cr_assert_eq(ret, 0); } diff --git a/tests/unit/mapping.c b/tests/unit/mapping.c index 5bede510b..302e6e454 100644 --- a/tests/unit/mapping.c +++ b/tests/unit/mapping.c @@ -47,16 +47,17 @@ Test(mapping, parse_nodes) struct node *n = alloc(sizeof(struct node)); n->name = node_names[i]; - n->in.signals.state = STATE_DESTROYED; + n->signals.state = STATE_DESTROYED; - list_init(&n->in.signals); + list_init(&n->signals); for (int j = 0; j < ARRAY_LEN(signal_names[i]); j++) { - struct signal *s = alloc(sizeof(struct signal *)); + struct signal *sig; - s->name = signal_names[i][j]; + sig = signal_create(signal_names[i][j], NULL, SIGNAL_TYPE_AUTO); + cr_assert_not_null(sig); - list_push(&n->in.signals, s); + list_push(&n->signals, sig); } list_push(&nodes, n); @@ -66,7 +67,7 @@ Test(mapping, parse_nodes) cr_assert_eq(ret, 0); cr_assert_eq(m.node, list_lookup(&nodes, "apple")); cr_assert_eq(m.type, MAPPING_TYPE_TIMESTAMP); - cr_assert_eq(m.ts.id, MAPPING_TS_ORIGIN); + cr_assert_eq(m.timestamp.type, MAPPING_TIMESTAMP_TYPE_ORIGIN); ret = mapping_parse_str(&m, "cherry.stats.owd.mean", &nodes); cr_assert_eq(ret, 0); @@ -87,7 +88,7 @@ Test(mapping, parse_nodes) cr_assert_eq(m.node, list_lookup(&nodes, "carrot")); cr_assert_eq(m.type, MAPPING_TYPE_DATA); cr_assert_eq(m.data.offset, 0); - cr_assert_eq(m.length, 0); + cr_assert_eq(m.length, list_length(&m.node->signals)); ret = mapping_parse_str(&m, "carrot.data[sole]", &nodes); cr_assert_eq(ret, 0); @@ -115,12 +116,12 @@ Test(mapping, parse) ret = mapping_parse_str(&m, "ts.origin", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_TIMESTAMP); - cr_assert_eq(m.ts.id, MAPPING_TS_ORIGIN); + cr_assert_eq(m.timestamp.type, MAPPING_TIMESTAMP_TYPE_ORIGIN); ret = mapping_parse_str(&m, "hdr.sequence", NULL); cr_assert_eq(ret, 0); cr_assert_eq(m.type, MAPPING_TYPE_HEADER); - cr_assert_eq(m.hdr.id, MAPPING_HDR_SEQUENCE); + cr_assert_eq(m.header.type, MAPPING_HEADER_TYPE_SEQUENCE); ret = mapping_parse_str(&m, "stats.owd.mean", NULL); cr_assert_eq(ret, 0);