1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4
5 #include <json.h>
6
7 #include "igt.h"
8 #include "resultgen.h"
9
10 static char testdatadir[] = JSON_TESTS_DIRECTORY;
11
read_json(int fd)12 static struct json_object *read_json(int fd)
13 {
14 struct json_object *obj;
15 struct json_tokener *tok = json_tokener_new();
16 enum json_tokener_error err;
17 char buf[512];
18 ssize_t s;
19
20 do {
21 s = read(fd, buf, sizeof(buf));
22 obj = json_tokener_parse_ex(tok, buf, s);
23 } while ((err = json_tokener_get_error(tok)) == json_tokener_continue);
24
25 igt_assert_eq(err, json_tokener_success);
26
27 json_tokener_free(tok);
28 return obj;
29 }
30
31 static void compare(struct json_object *one,
32 struct json_object *two);
33
compare_objects(struct json_object * one,struct json_object * two)34 static void compare_objects(struct json_object *one,
35 struct json_object *two)
36 {
37 json_object_iter iter;
38 struct json_object *subobj;
39
40 json_object_object_foreachC(one, iter) {
41 igt_debug("Key %s\n", iter.key);
42
43 igt_assert(json_object_object_get_ex(two, iter.key, &subobj));
44
45 compare(iter.val, subobj);
46 }
47 }
48
compare_arrays(struct json_object * one,struct json_object * two)49 static void compare_arrays(struct json_object *one,
50 struct json_object *two)
51 {
52 size_t i;
53
54 for (i = 0; i < json_object_array_length(one); i++) {
55 igt_debug("Array index %zd\n", i);
56 compare(json_object_array_get_idx(one, i),
57 json_object_array_get_idx(two, i));
58 }
59 }
60
compatible_types(struct json_object * one,struct json_object * two)61 static bool compatible_types(struct json_object *one,
62 struct json_object *two)
63 {
64 /*
65 * A double of value 0.0 gets written as "0", which gets read
66 * as an int.
67 */
68 json_type onetype = json_object_get_type(one);
69 json_type twotype = json_object_get_type(two);
70
71 switch (onetype) {
72 case json_type_boolean:
73 case json_type_string:
74 case json_type_object:
75 case json_type_array:
76 case json_type_null:
77 return onetype == twotype;
78 break;
79 case json_type_double:
80 case json_type_int:
81 return twotype == json_type_double || twotype == json_type_int;
82 break;
83 }
84
85 igt_assert(!"Cannot be reached");
86 return false;
87 }
88
compare(struct json_object * one,struct json_object * two)89 static void compare(struct json_object *one,
90 struct json_object *two)
91 {
92 igt_assert(compatible_types(one, two));
93
94 switch (json_object_get_type(one)) {
95 case json_type_boolean:
96 igt_assert_eq(json_object_get_boolean(one), json_object_get_boolean(two));
97 break;
98 case json_type_double:
99 case json_type_int:
100 /*
101 * A double of value 0.0 gets written as "0", which
102 * gets read as an int. Both yield 0.0 with
103 * json_object_get_double(). Comparing doubles with ==
104 * considered crazy but it's good enough.
105 */
106 igt_assert(json_object_get_double(one) == json_object_get_double(two));
107 break;
108 case json_type_string:
109 igt_assert(!strcmp(json_object_get_string(one), json_object_get_string(two)));
110 break;
111 case json_type_object:
112 igt_assert_eq(json_object_object_length(one), json_object_object_length(two));
113 compare_objects(one, two);
114 break;
115 case json_type_array:
116 igt_assert_eq(json_object_array_length(one), json_object_array_length(two));
117 compare_arrays(one, two);
118 break;
119 case json_type_null:
120 break;
121 default:
122 igt_assert(!"Cannot be reached");
123 }
124 }
125
run_results_and_compare(int dirfd,const char * dirname)126 static void run_results_and_compare(int dirfd, const char *dirname)
127 {
128 int testdirfd = openat(dirfd, dirname, O_RDONLY | O_DIRECTORY);
129 int reference;
130 struct json_object *resultsobj, *referenceobj;
131
132 igt_assert_fd(testdirfd);
133
134 igt_assert((resultsobj = generate_results_json(testdirfd)) != NULL);
135
136 reference = openat(testdirfd, "reference.json", O_RDONLY);
137 close(testdirfd);
138
139 igt_assert_fd(reference);
140 referenceobj = read_json(reference);
141 close(reference);
142 igt_assert(referenceobj != NULL);
143
144 igt_debug("Root object\n");
145 compare(resultsobj, referenceobj);
146 igt_assert_eq(json_object_put(resultsobj), 1);
147 igt_assert_eq(json_object_put(referenceobj), 1);
148 }
149
150 static const char *dirnames[] = {
151 "normal-run",
152 "warnings",
153 "warnings-with-dmesg-warns",
154 "piglit-style-dmesg",
155 "incomplete-before-any-subtests",
156 "dmesg-results",
157 "aborted-on-boot",
158 "aborted-after-a-test",
159 "dmesg-escapes",
160 "notrun-results",
161 "notrun-results-multiple-mode",
162 "dmesg-warn-level",
163 "dmesg-warn-level-piglit-style",
164 "dmesg-warn-level-one-piglit-style"
165 };
166
167 igt_main
168 {
169 int dirfd = open(testdatadir, O_RDONLY | O_DIRECTORY);
170 size_t i;
171
172 igt_assert_fd(dirfd);
173
174 for (i = 0; i < ARRAY_SIZE(dirnames); i++) {
igt_subtest(dirnames[i])175 igt_subtest(dirnames[i]) {
176 run_results_and_compare(dirfd, dirnames[i]);
177 }
178 }
179 }
180