view tests/test_cbor_pack.c @ 661:6ba753927d3f

tests: replace test-file.c with test.c The previous commit duplicated test-file.c's functionality within test.c. As an added bonus, this change adds support for expected-panic-strings to file based test cases. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Sun, 10 Feb 2019 21:45:35 -0500
parents bc0841b964fb
children f2cc03ad4b1f
line wrap: on
line source

/*
 * Copyright (c) 2017-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <jeffpc/hexdump.h>
#include <jeffpc/sexpr.h>
#include <jeffpc/cbor.h>
#include <jeffpc/io.h>
#include <jeffpc/mem.h>

#include "test.c"

static inline void dumpbuf(struct buffer *buf)
{
	const size_t len = buffer_used(buf);
	char tmp[len * 2 + 1];

	hexdumpz(tmp, buffer_data(buf), len, false);
	fprintf(stderr, "%s", tmp);
}

static void cmp_buffers(struct buffer *exp, struct buffer *got)
{
	fprintf(stderr, "  expected: ");
	dumpbuf(exp);
	fprintf(stderr, "\n");
	fprintf(stderr, "  got:      ");
	dumpbuf(got);
	fprintf(stderr, "\n");

	if (buffer_used(got) != buffer_used(exp))
		fail("cbor packing failed: length mismatch "
		     "(got %zu, expected %zu)", buffer_used(got),
		     buffer_used(exp));

	if (memcmp(buffer_data(got), buffer_data(exp), buffer_used(got)))
		fail("cbor packing failed: content mismatch");
}

#define TEST_ONE(pack, got, exp, input)					\
	do {								\
		int ret;						\
									\
		buffer_truncate((got), 0);				\
									\
		fprintf(stderr, "pack via: %s\n", #pack);		\
		ret = pack;						\
		if (ret)						\
			fail("failed to pack value directly: %s",	\
			     xstrerror(ret));				\
									\
		cmp_buffers((exp), (got));				\
									\
		buffer_truncate((got), 0);				\
									\
		fprintf(stderr, "pack via: %s\n",			\
		        "cbor_pack_val(got, input)");			\
		ret = cbor_pack_val((got), (input));			\
		if (ret)						\
			fail("failed to pack value indirectly: %s",	\
			     xstrerror(ret));				\
									\
		cmp_buffers((exp), (got));				\
	} while (0)

static struct val *convert_input(struct val *input)
{
	struct val **arr;
	size_t len;
	size_t i;
	int ret;

	if (input->type != VT_CONS)
		return input;

	/*
	 * We are dealing with either a list or an assoc, we need to figure
	 * out which it is...
	 * FIXME
	 */

	if (0) {
		/* it is an assoc; turn it into a VT_NVL */
		fail("not yet implemented");
	} else {
		/* it is a list; turn it into a VT_ARRAY */
		len = sexpr_length(val_getref(input));
		if (len < 0)
			fail("failed to get length of array");

		arr = mem_reallocarray(NULL, len, sizeof(struct val *));
		if (!arr)
			fail("failed to allocate val array");

		ret = sexpr_list_to_array(input, arr, len);
		if (ret < 0)
			fail("failed to construct an array");

		for (i = 0; i < len; i++)
			arr[i] = convert_input(arr[i]);

		val_putref(input);

		return VAL_ALLOC_ARRAY(arr, len);
	}
}

static void onefile(struct val *input, struct buffer *expected)
{
	struct buffer *got;

	fprintf(stderr, "input: ");
	val_dump_file(stderr, input, 0);

	got = buffer_alloc(1000);
	if (IS_ERR(got))
		fail("failed to allocate output buffer");

	/* possibly an VT_ARRAY or VT_NVL in sexpr list form */
	if (input->type == VT_CONS)
		input = convert_input(input);

	fprintf(stderr, "modified input: ");
	val_dump_file(stderr, input, 0);

	switch (input->type) {
		case VT_NULL:
			TEST_ONE(cbor_pack_null(got), got, expected, input);
			break;
		case VT_INT:
			TEST_ONE(cbor_pack_uint(got, input->i), got, expected,
				 input);
			break;
		case VT_BOOL:
			TEST_ONE(cbor_pack_bool(got, input->b), got, expected,
				 input);
			break;
		case VT_STR:
			TEST_ONE(cbor_pack_str(got, val_cast_to_str(input)),
				 got, expected, input);
			break;
		case VT_ARRAY:
			TEST_ONE(cbor_pack_array_vals(got, input->array.vals,
						      input->array.nelem),
				 got, expected, input);
			break;
		case VT_NVL:
			TEST_ONE(cbor_pack_map_val(got, input), got,
				 expected, input);
			break;
		case VT_SYM:
		case VT_CONS:
		case VT_CHAR:
		case VT_BLOB:
			fail("Unsupported val type");
			break;
	}

	val_putref(input);
}

static void get_expected_output(const char *fname, struct buffer *buf)
{
	char expfname[FILENAME_MAX];
	size_t len;
	char *tmp;

	VERIFY3U(strlen("cbor"), <=, strlen("lisp"));

	/* replace .lisp with .ext */
	strcpy(expfname, fname);
	strcpy(expfname + strlen(expfname) - 4, "cbor");

	tmp = read_file_len(expfname, &len);
	ASSERT(!IS_ERR(tmp));

	buffer_init_static(buf, tmp, len, false);
}

static void test(const char *fname)
{
	struct buffer expected;
	struct val *lv;
	char *in;

	in = read_file(fname);
	if (IS_ERR(in))
		fail("failed to read input (%s)", xstrerror(PTR_ERR(in)));

	lv = sexpr_parse(in, strlen(in));
	if (IS_ERR(lv))
		fail("failed to parse input: %s", xstrerror(PTR_ERR(lv)));

	free(in);

	get_expected_output(fname, &expected);

	onefile(lv, &expected);

	free((void *) buffer_data(&expected));
}