Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / lib / kunit / test-test.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit test for core test infrastructure.
4  *
5  * Copyright (C) 2019, Google LLC.
6  * Author: Brendan Higgins <brendanhiggins@google.com>
7  */
8 #include <kunit/test.h>
9
10 struct kunit_try_catch_test_context {
11         struct kunit_try_catch *try_catch;
12         bool function_called;
13 };
14
15 static void kunit_test_successful_try(void *data)
16 {
17         struct kunit *test = data;
18         struct kunit_try_catch_test_context *ctx = test->priv;
19
20         ctx->function_called = true;
21 }
22
23 static void kunit_test_no_catch(void *data)
24 {
25         struct kunit *test = data;
26
27         KUNIT_FAIL(test, "Catch should not be called\n");
28 }
29
30 static void kunit_test_try_catch_successful_try_no_catch(struct kunit *test)
31 {
32         struct kunit_try_catch_test_context *ctx = test->priv;
33         struct kunit_try_catch *try_catch = ctx->try_catch;
34
35         kunit_try_catch_init(try_catch,
36                              test,
37                              kunit_test_successful_try,
38                              kunit_test_no_catch);
39         kunit_try_catch_run(try_catch, test);
40
41         KUNIT_EXPECT_TRUE(test, ctx->function_called);
42 }
43
44 static void kunit_test_unsuccessful_try(void *data)
45 {
46         struct kunit *test = data;
47         struct kunit_try_catch_test_context *ctx = test->priv;
48         struct kunit_try_catch *try_catch = ctx->try_catch;
49
50         kunit_try_catch_throw(try_catch);
51         KUNIT_FAIL(test, "This line should never be reached\n");
52 }
53
54 static void kunit_test_catch(void *data)
55 {
56         struct kunit *test = data;
57         struct kunit_try_catch_test_context *ctx = test->priv;
58
59         ctx->function_called = true;
60 }
61
62 static void kunit_test_try_catch_unsuccessful_try_does_catch(struct kunit *test)
63 {
64         struct kunit_try_catch_test_context *ctx = test->priv;
65         struct kunit_try_catch *try_catch = ctx->try_catch;
66
67         kunit_try_catch_init(try_catch,
68                              test,
69                              kunit_test_unsuccessful_try,
70                              kunit_test_catch);
71         kunit_try_catch_run(try_catch, test);
72
73         KUNIT_EXPECT_TRUE(test, ctx->function_called);
74 }
75
76 static int kunit_try_catch_test_init(struct kunit *test)
77 {
78         struct kunit_try_catch_test_context *ctx;
79
80         ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
81         KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
82         test->priv = ctx;
83
84         ctx->try_catch = kunit_kmalloc(test,
85                                        sizeof(*ctx->try_catch),
86                                        GFP_KERNEL);
87         KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->try_catch);
88
89         return 0;
90 }
91
92 static struct kunit_case kunit_try_catch_test_cases[] = {
93         KUNIT_CASE(kunit_test_try_catch_successful_try_no_catch),
94         KUNIT_CASE(kunit_test_try_catch_unsuccessful_try_does_catch),
95         {}
96 };
97
98 static struct kunit_suite kunit_try_catch_test_suite = {
99         .name = "kunit-try-catch-test",
100         .init = kunit_try_catch_test_init,
101         .test_cases = kunit_try_catch_test_cases,
102 };
103 kunit_test_suite(kunit_try_catch_test_suite);
104
105 /*
106  * Context for testing test managed resources
107  * is_resource_initialized is used to test arbitrary resources
108  */
109 struct kunit_test_resource_context {
110         struct kunit test;
111         bool is_resource_initialized;
112         int allocate_order[2];
113         int free_order[2];
114 };
115
116 static int fake_resource_init(struct kunit_resource *res, void *context)
117 {
118         struct kunit_test_resource_context *ctx = context;
119
120         res->allocation = &ctx->is_resource_initialized;
121         ctx->is_resource_initialized = true;
122         return 0;
123 }
124
125 static void fake_resource_free(struct kunit_resource *res)
126 {
127         bool *is_resource_initialized = res->allocation;
128
129         *is_resource_initialized = false;
130 }
131
132 static void kunit_resource_test_init_resources(struct kunit *test)
133 {
134         struct kunit_test_resource_context *ctx = test->priv;
135
136         kunit_init_test(&ctx->test, "testing_test_init_test");
137
138         KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
139 }
140
141 static void kunit_resource_test_alloc_resource(struct kunit *test)
142 {
143         struct kunit_test_resource_context *ctx = test->priv;
144         struct kunit_resource *res;
145         kunit_resource_free_t free = fake_resource_free;
146
147         res = kunit_alloc_and_get_resource(&ctx->test,
148                                            fake_resource_init,
149                                            fake_resource_free,
150                                            GFP_KERNEL,
151                                            ctx);
152
153         KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
154         KUNIT_EXPECT_PTR_EQ(test,
155                             &ctx->is_resource_initialized,
156                             (bool *) res->allocation);
157         KUNIT_EXPECT_TRUE(test, list_is_last(&res->node, &ctx->test.resources));
158         KUNIT_EXPECT_PTR_EQ(test, free, res->free);
159 }
160
161 static void kunit_resource_test_destroy_resource(struct kunit *test)
162 {
163         struct kunit_test_resource_context *ctx = test->priv;
164         struct kunit_resource *res = kunit_alloc_and_get_resource(
165                         &ctx->test,
166                         fake_resource_init,
167                         fake_resource_free,
168                         GFP_KERNEL,
169                         ctx);
170
171         KUNIT_ASSERT_FALSE(test,
172                            kunit_resource_destroy(&ctx->test,
173                                                   kunit_resource_instance_match,
174                                                   res->free,
175                                                   res->allocation));
176
177         KUNIT_EXPECT_FALSE(test, ctx->is_resource_initialized);
178         KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
179 }
180
181 static void kunit_resource_test_cleanup_resources(struct kunit *test)
182 {
183         int i;
184         struct kunit_test_resource_context *ctx = test->priv;
185         struct kunit_resource *resources[5];
186
187         for (i = 0; i < ARRAY_SIZE(resources); i++) {
188                 resources[i] = kunit_alloc_and_get_resource(&ctx->test,
189                                                             fake_resource_init,
190                                                             fake_resource_free,
191                                                             GFP_KERNEL,
192                                                             ctx);
193         }
194
195         kunit_cleanup(&ctx->test);
196
197         KUNIT_EXPECT_TRUE(test, list_empty(&ctx->test.resources));
198 }
199
200 static void kunit_resource_test_mark_order(int order_array[],
201                                            size_t order_size,
202                                            int key)
203 {
204         int i;
205
206         for (i = 0; i < order_size && order_array[i]; i++)
207                 ;
208
209         order_array[i] = key;
210 }
211
212 #define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key)                  \
213                 kunit_resource_test_mark_order(ctx->order_field,               \
214                                                ARRAY_SIZE(ctx->order_field),   \
215                                                key)
216
217 static int fake_resource_2_init(struct kunit_resource *res, void *context)
218 {
219         struct kunit_test_resource_context *ctx = context;
220
221         KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 2);
222
223         res->allocation = ctx;
224
225         return 0;
226 }
227
228 static void fake_resource_2_free(struct kunit_resource *res)
229 {
230         struct kunit_test_resource_context *ctx = res->allocation;
231
232         KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 2);
233 }
234
235 static int fake_resource_1_init(struct kunit_resource *res, void *context)
236 {
237         struct kunit_test_resource_context *ctx = context;
238
239         kunit_alloc_and_get_resource(&ctx->test,
240                                      fake_resource_2_init,
241                                      fake_resource_2_free,
242                                      GFP_KERNEL,
243                                      ctx);
244
245         KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, allocate_order, 1);
246
247         res->allocation = ctx;
248
249         return 0;
250 }
251
252 static void fake_resource_1_free(struct kunit_resource *res)
253 {
254         struct kunit_test_resource_context *ctx = res->allocation;
255
256         KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, free_order, 1);
257 }
258
259 /*
260  * TODO(brendanhiggins@google.com): replace the arrays that keep track of the
261  * order of allocation and freeing with strict mocks using the IN_SEQUENCE macro
262  * to assert allocation and freeing order when the feature becomes available.
263  */
264 static void kunit_resource_test_proper_free_ordering(struct kunit *test)
265 {
266         struct kunit_test_resource_context *ctx = test->priv;
267
268         /* fake_resource_1 allocates a fake_resource_2 in its init. */
269         kunit_alloc_and_get_resource(&ctx->test,
270                                      fake_resource_1_init,
271                                      fake_resource_1_free,
272                                      GFP_KERNEL,
273                                      ctx);
274
275         /*
276          * Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
277          * before returning to fake_resource_1_init, it should be the first to
278          * put its key in the allocate_order array.
279          */
280         KUNIT_EXPECT_EQ(test, ctx->allocate_order[0], 2);
281         KUNIT_EXPECT_EQ(test, ctx->allocate_order[1], 1);
282
283         kunit_cleanup(&ctx->test);
284
285         /*
286          * Because fake_resource_2 finishes allocation before fake_resource_1,
287          * fake_resource_1 should be freed first since it could depend on
288          * fake_resource_2.
289          */
290         KUNIT_EXPECT_EQ(test, ctx->free_order[0], 1);
291         KUNIT_EXPECT_EQ(test, ctx->free_order[1], 2);
292 }
293
294 static int kunit_resource_test_init(struct kunit *test)
295 {
296         struct kunit_test_resource_context *ctx =
297                         kzalloc(sizeof(*ctx), GFP_KERNEL);
298
299         KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
300
301         test->priv = ctx;
302
303         kunit_init_test(&ctx->test, "test_test_context");
304
305         return 0;
306 }
307
308 static void kunit_resource_test_exit(struct kunit *test)
309 {
310         struct kunit_test_resource_context *ctx = test->priv;
311
312         kunit_cleanup(&ctx->test);
313         kfree(ctx);
314 }
315
316 static struct kunit_case kunit_resource_test_cases[] = {
317         KUNIT_CASE(kunit_resource_test_init_resources),
318         KUNIT_CASE(kunit_resource_test_alloc_resource),
319         KUNIT_CASE(kunit_resource_test_destroy_resource),
320         KUNIT_CASE(kunit_resource_test_cleanup_resources),
321         KUNIT_CASE(kunit_resource_test_proper_free_ordering),
322         {}
323 };
324
325 static struct kunit_suite kunit_resource_test_suite = {
326         .name = "kunit-resource-test",
327         .init = kunit_resource_test_init,
328         .exit = kunit_resource_test_exit,
329         .test_cases = kunit_resource_test_cases,
330 };
331 kunit_test_suite(kunit_resource_test_suite);