1268896Sbapt/* Copyright (c) 2014, Vsevolod Stakhov
2268896Sbapt * All rights reserved.
3268896Sbapt *
4268896Sbapt * Redistribution and use in source and binary forms, with or without
5268896Sbapt * modification, are permitted provided that the following conditions are met:
6268896Sbapt *       * Redistributions of source code must retain the above copyright
7268896Sbapt *         notice, this list of conditions and the following disclaimer.
8268896Sbapt *       * Redistributions in binary form must reproduce the above copyright
9268896Sbapt *         notice, this list of conditions and the following disclaimer in the
10268896Sbapt *         documentation and/or other materials provided with the distribution.
11268896Sbapt *
12268896Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13268896Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14268896Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15268896Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16268896Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17268896Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18268896Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19268896Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20268896Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21268896Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22268896Sbapt */
23268896Sbapt
24268896Sbapt#include <stdio.h>
25268896Sbapt#include <errno.h>
26268896Sbapt#include <unistd.h>
27268896Sbapt#include "ucl.h"
28268896Sbapt
29268896Sbaptstatic int
30268896Sbaptread_stdin (char **buf)
31268896Sbapt{
32268896Sbapt	int size = BUFSIZ, remain, ret;
33268896Sbapt	char *p;
34268896Sbapt
35268896Sbapt	*buf = malloc (size);
36268896Sbapt	if (*buf == NULL) {
37268896Sbapt		return -1;
38268896Sbapt	}
39268896Sbapt
40268896Sbapt	p = *buf;
41268896Sbapt	remain = size;
42268896Sbapt
43268896Sbapt	while ((ret = read (STDIN_FILENO, p, remain)) > 0) {
44268896Sbapt		remain -= ret;
45268896Sbapt		p += ret;
46268896Sbapt		if (remain == 0) {
47268896Sbapt			*buf = realloc (*buf, size * 2);
48268896Sbapt			if (*buf == NULL) {
49268896Sbapt				return -1;
50268896Sbapt			}
51268896Sbapt			p = *buf + size;
52268896Sbapt			remain = size;
53268896Sbapt			size *= 2;
54268896Sbapt		}
55268896Sbapt	}
56268896Sbapt
57268896Sbapt	return ret;
58268896Sbapt}
59268896Sbapt
60268896Sbaptstatic bool
61268896Sbaptperform_test (const ucl_object_t *schema, const ucl_object_t *obj,
62268896Sbapt		struct ucl_schema_error *err)
63268896Sbapt{
64268896Sbapt	const const ucl_object_t *valid, *data, *description;
65268896Sbapt	bool match;
66268896Sbapt
67268896Sbapt	data = ucl_object_find_key (obj, "data");
68268896Sbapt	description = ucl_object_find_key (obj, "description");
69268896Sbapt	valid = ucl_object_find_key (obj, "valid");
70268896Sbapt
71268896Sbapt	if (data == NULL || description == NULL || valid == NULL) {
72268896Sbapt		fprintf (stdout, "Bad test case\n");
73268896Sbapt		return false;
74268896Sbapt	}
75268896Sbapt
76268896Sbapt	match = ucl_object_validate (schema, data, err);
77268896Sbapt	if (match != ucl_object_toboolean (valid)) {
78268896Sbapt		fprintf (stdout, "Test case '%s' failed (expected %s): '%s'\n",
79268896Sbapt				ucl_object_tostring (description),
80268896Sbapt				ucl_object_toboolean (valid) ? "valid" : "invalid",
81268896Sbapt						err->msg);
82268896Sbapt		return false;
83268896Sbapt	}
84268896Sbapt
85268896Sbapt	return true;
86268896Sbapt}
87268896Sbapt
88268896Sbaptstatic int
89268896Sbaptperform_tests (const ucl_object_t *obj)
90268896Sbapt{
91268896Sbapt	struct ucl_schema_error err;
92268896Sbapt	ucl_object_iter_t iter = NULL;
93268896Sbapt	const ucl_object_t *schema, *tests, *description, *test;
94268896Sbapt
95268896Sbapt	if (obj->type != UCL_OBJECT) {
96268896Sbapt		fprintf (stdout, "Bad test case\n");
97268896Sbapt		return EXIT_FAILURE;
98268896Sbapt	}
99268896Sbapt
100268896Sbapt	schema = ucl_object_find_key (obj, "schema");
101268896Sbapt	tests = ucl_object_find_key (obj, "tests");
102268896Sbapt	description = ucl_object_find_key (obj, "description");
103268896Sbapt
104268896Sbapt	if (schema == NULL || tests == NULL || description == NULL) {
105268896Sbapt		fprintf (stdout, "Bad test case\n");
106268896Sbapt		return EXIT_FAILURE;
107268896Sbapt	}
108268896Sbapt
109268896Sbapt	memset (&err, 0, sizeof (err));
110268896Sbapt
111268896Sbapt	while ((test = ucl_iterate_object (tests, &iter, true)) != NULL) {
112268896Sbapt		if (!perform_test (schema, test, &err)) {
113268896Sbapt			fprintf (stdout, "Test suite '%s' failed\n",
114268896Sbapt							ucl_object_tostring (description));
115268896Sbapt			return EXIT_FAILURE;
116268896Sbapt		}
117268896Sbapt	}
118268896Sbapt
119268896Sbapt	return 0;
120268896Sbapt}
121268896Sbapt
122268896Sbaptint
123268896Sbaptmain (int argc, char **argv)
124268896Sbapt{
125268896Sbapt	char *buf = NULL;
126268896Sbapt	struct ucl_parser *parser;
127268896Sbapt	ucl_object_t *obj = NULL;
128268896Sbapt	const ucl_object_t *elt;
129268896Sbapt	ucl_object_iter_t iter = NULL;
130268896Sbapt	int ret = 0;
131268896Sbapt
132268896Sbapt	if (read_stdin (&buf) == -1) {
133268896Sbapt		exit (EXIT_FAILURE);
134268896Sbapt	}
135268896Sbapt
136268896Sbapt	parser = ucl_parser_new (0);
137268896Sbapt
138268896Sbapt	ucl_parser_add_string (parser, buf, 0);
139268896Sbapt
140268896Sbapt	if (ucl_parser_get_error (parser) != NULL) {
141268896Sbapt		fprintf (stdout, "Error occurred: %s\n", ucl_parser_get_error (parser));
142268896Sbapt		ret = 1;
143268896Sbapt		return EXIT_FAILURE;
144268896Sbapt	}
145268896Sbapt	obj = ucl_parser_get_object (parser);
146268896Sbapt	ucl_parser_free (parser);
147268896Sbapt
148268896Sbapt	while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
149268896Sbapt		ret = perform_tests (elt);
150268896Sbapt		if (ret != 0) {
151268896Sbapt			break;
152268896Sbapt		}
153268896Sbapt	}
154268896Sbapt
155268896Sbapt	ucl_object_unref (obj);
156268896Sbapt
157268896Sbapt	return ret;
158268896Sbapt}
159