1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Assertion and expectation serialization API. |
4 | * |
5 | * Copyright (C) 2019, Google LLC. |
6 | * Author: Brendan Higgins <brendanhiggins@google.com> |
7 | */ |
8 | #include <kunit/assert.h> |
9 | #include <kunit/test.h> |
10 | |
11 | #include "string-stream.h" |
12 | |
13 | void kunit_assert_prologue(const struct kunit_loc *loc, |
14 | enum kunit_assert_type type, |
15 | struct string_stream *stream) |
16 | { |
17 | const char *expect_or_assert = NULL; |
18 | |
19 | switch (type) { |
20 | case KUNIT_EXPECTATION: |
21 | expect_or_assert = "EXPECTATION" ; |
22 | break; |
23 | case KUNIT_ASSERTION: |
24 | expect_or_assert = "ASSERTION" ; |
25 | break; |
26 | } |
27 | |
28 | string_stream_add(stream, fmt: "%s FAILED at %s:%d\n" , |
29 | expect_or_assert, loc->file, loc->line); |
30 | } |
31 | EXPORT_SYMBOL_GPL(kunit_assert_prologue); |
32 | |
33 | static void kunit_assert_print_msg(const struct va_format *message, |
34 | struct string_stream *stream) |
35 | { |
36 | if (message->fmt) |
37 | string_stream_add(stream, fmt: "\n%pV" , message); |
38 | } |
39 | |
40 | void kunit_fail_assert_format(const struct kunit_assert *assert, |
41 | const struct va_format *message, |
42 | struct string_stream *stream) |
43 | { |
44 | string_stream_add(stream, fmt: "%pV" , message); |
45 | } |
46 | EXPORT_SYMBOL_GPL(kunit_fail_assert_format); |
47 | |
48 | void kunit_unary_assert_format(const struct kunit_assert *assert, |
49 | const struct va_format *message, |
50 | struct string_stream *stream) |
51 | { |
52 | struct kunit_unary_assert *unary_assert; |
53 | |
54 | unary_assert = container_of(assert, struct kunit_unary_assert, assert); |
55 | |
56 | if (unary_assert->expected_true) |
57 | string_stream_add(stream, |
58 | KUNIT_SUBTEST_INDENT "Expected %s to be true, but is false\n" , |
59 | unary_assert->condition); |
60 | else |
61 | string_stream_add(stream, |
62 | KUNIT_SUBTEST_INDENT "Expected %s to be false, but is true\n" , |
63 | unary_assert->condition); |
64 | kunit_assert_print_msg(message, stream); |
65 | } |
66 | EXPORT_SYMBOL_GPL(kunit_unary_assert_format); |
67 | |
68 | void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, |
69 | const struct va_format *message, |
70 | struct string_stream *stream) |
71 | { |
72 | struct kunit_ptr_not_err_assert *ptr_assert; |
73 | |
74 | ptr_assert = container_of(assert, struct kunit_ptr_not_err_assert, |
75 | assert); |
76 | |
77 | if (!ptr_assert->value) { |
78 | string_stream_add(stream, |
79 | KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n" , |
80 | ptr_assert->text); |
81 | } else if (IS_ERR(ptr: ptr_assert->value)) { |
82 | string_stream_add(stream, |
83 | KUNIT_SUBTEST_INDENT "Expected %s is not error, but is: %ld\n" , |
84 | ptr_assert->text, |
85 | PTR_ERR(ptr: ptr_assert->value)); |
86 | } |
87 | kunit_assert_print_msg(message, stream); |
88 | } |
89 | EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format); |
90 | |
91 | /* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */ |
92 | static bool is_literal(const char *text, long long value) |
93 | { |
94 | char *buffer; |
95 | int len; |
96 | bool ret; |
97 | |
98 | len = snprintf(NULL, size: 0, fmt: "%lld" , value); |
99 | if (strlen(text) != len) |
100 | return false; |
101 | |
102 | buffer = kmalloc(size: len+1, GFP_KERNEL); |
103 | if (!buffer) |
104 | return false; |
105 | |
106 | snprintf(buf: buffer, size: len+1, fmt: "%lld" , value); |
107 | ret = strncmp(buffer, text, len) == 0; |
108 | |
109 | kfree(objp: buffer); |
110 | |
111 | return ret; |
112 | } |
113 | |
114 | void kunit_binary_assert_format(const struct kunit_assert *assert, |
115 | const struct va_format *message, |
116 | struct string_stream *stream) |
117 | { |
118 | struct kunit_binary_assert *binary_assert; |
119 | |
120 | binary_assert = container_of(assert, struct kunit_binary_assert, |
121 | assert); |
122 | |
123 | string_stream_add(stream, |
124 | KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n" , |
125 | binary_assert->text->left_text, |
126 | binary_assert->text->operation, |
127 | binary_assert->text->right_text); |
128 | if (!is_literal(text: binary_assert->text->left_text, value: binary_assert->left_value)) |
129 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n" , |
130 | binary_assert->text->left_text, |
131 | binary_assert->left_value, |
132 | binary_assert->left_value); |
133 | if (!is_literal(text: binary_assert->text->right_text, value: binary_assert->right_value)) |
134 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)" , |
135 | binary_assert->text->right_text, |
136 | binary_assert->right_value, |
137 | binary_assert->right_value); |
138 | kunit_assert_print_msg(message, stream); |
139 | } |
140 | EXPORT_SYMBOL_GPL(kunit_binary_assert_format); |
141 | |
142 | void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, |
143 | const struct va_format *message, |
144 | struct string_stream *stream) |
145 | { |
146 | struct kunit_binary_ptr_assert *binary_assert; |
147 | |
148 | binary_assert = container_of(assert, struct kunit_binary_ptr_assert, |
149 | assert); |
150 | |
151 | string_stream_add(stream, |
152 | KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n" , |
153 | binary_assert->text->left_text, |
154 | binary_assert->text->operation, |
155 | binary_assert->text->right_text); |
156 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px\n" , |
157 | binary_assert->text->left_text, |
158 | binary_assert->left_value); |
159 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px" , |
160 | binary_assert->text->right_text, |
161 | binary_assert->right_value); |
162 | kunit_assert_print_msg(message, stream); |
163 | } |
164 | EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format); |
165 | |
166 | /* Checks if KUNIT_EXPECT_STREQ() args were string literals. |
167 | * Note: `text` will have ""s where as `value` will not. |
168 | */ |
169 | static bool is_str_literal(const char *text, const char *value) |
170 | { |
171 | int len; |
172 | |
173 | len = strlen(text); |
174 | if (len < 2) |
175 | return false; |
176 | if (text[0] != '\"' || text[len - 1] != '\"') |
177 | return false; |
178 | |
179 | return strncmp(text + 1, value, len - 2) == 0; |
180 | } |
181 | |
182 | void kunit_binary_str_assert_format(const struct kunit_assert *assert, |
183 | const struct va_format *message, |
184 | struct string_stream *stream) |
185 | { |
186 | struct kunit_binary_str_assert *binary_assert; |
187 | |
188 | binary_assert = container_of(assert, struct kunit_binary_str_assert, |
189 | assert); |
190 | |
191 | string_stream_add(stream, |
192 | KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n" , |
193 | binary_assert->text->left_text, |
194 | binary_assert->text->operation, |
195 | binary_assert->text->right_text); |
196 | if (!is_str_literal(text: binary_assert->text->left_text, value: binary_assert->left_value)) |
197 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"\n" , |
198 | binary_assert->text->left_text, |
199 | binary_assert->left_value); |
200 | if (!is_str_literal(text: binary_assert->text->right_text, value: binary_assert->right_value)) |
201 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"" , |
202 | binary_assert->text->right_text, |
203 | binary_assert->right_value); |
204 | kunit_assert_print_msg(message, stream); |
205 | } |
206 | EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format); |
207 | |
208 | /* Adds a hexdump of a buffer to a string_stream comparing it with |
209 | * a second buffer. The different bytes are marked with <>. |
210 | */ |
211 | static void kunit_assert_hexdump(struct string_stream *stream, |
212 | const void *buf, |
213 | const void *compared_buf, |
214 | const size_t len) |
215 | { |
216 | size_t i; |
217 | const u8 *buf1 = buf; |
218 | const u8 *buf2 = compared_buf; |
219 | |
220 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT); |
221 | |
222 | for (i = 0; i < len; ++i) { |
223 | if (!(i % 16) && i) |
224 | string_stream_add(stream, fmt: "\n" KUNIT_SUBSUBTEST_INDENT); |
225 | |
226 | if (buf1[i] != buf2[i]) |
227 | string_stream_add(stream, fmt: "<%02x>" , buf1[i]); |
228 | else |
229 | string_stream_add(stream, fmt: " %02x " , buf1[i]); |
230 | } |
231 | } |
232 | |
233 | void kunit_mem_assert_format(const struct kunit_assert *assert, |
234 | const struct va_format *message, |
235 | struct string_stream *stream) |
236 | { |
237 | struct kunit_mem_assert *mem_assert; |
238 | |
239 | mem_assert = container_of(assert, struct kunit_mem_assert, |
240 | assert); |
241 | |
242 | if (!mem_assert->left_value) { |
243 | string_stream_add(stream, |
244 | KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n" , |
245 | mem_assert->text->left_text); |
246 | } else if (!mem_assert->right_value) { |
247 | string_stream_add(stream, |
248 | KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n" , |
249 | mem_assert->text->right_text); |
250 | } else { |
251 | string_stream_add(stream, |
252 | KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n" , |
253 | mem_assert->text->left_text, |
254 | mem_assert->text->operation, |
255 | mem_assert->text->right_text); |
256 | |
257 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n" , |
258 | mem_assert->text->left_text); |
259 | kunit_assert_hexdump(stream, buf: mem_assert->left_value, |
260 | compared_buf: mem_assert->right_value, len: mem_assert->size); |
261 | |
262 | string_stream_add(stream, fmt: "\n" ); |
263 | |
264 | string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n" , |
265 | mem_assert->text->right_text); |
266 | kunit_assert_hexdump(stream, buf: mem_assert->right_value, |
267 | compared_buf: mem_assert->left_value, len: mem_assert->size); |
268 | |
269 | kunit_assert_print_msg(message, stream); |
270 | } |
271 | } |
272 | EXPORT_SYMBOL_GPL(kunit_mem_assert_format); |
273 | |