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