source: mainline/uspace/lib/ui/test/checkbox.c@ 7470d97

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7470d97 was 7470d97, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Add GC operation to set clipping rectangle

The number of changed files is due to the proliferation of GC
implementations, mostly these are just dummies in unit tests.
Definitely need to tame those in the future.

  • Property mode set to 100644
File size: 14.5 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <gfx/context.h>
30#include <gfx/coord.h>
31#include <mem.h>
32#include <pcut/pcut.h>
33#include <stdbool.h>
34#include <ui/control.h>
35#include <ui/checkbox.h>
36#include <ui/resource.h>
37#include "../private/checkbox.h"
38
39PCUT_INIT;
40
41PCUT_TEST_SUITE(checkbox);
42
43static errno_t testgc_set_clip_rect(void *, gfx_rect_t *);
44static errno_t testgc_set_color(void *, gfx_color_t *);
45static errno_t testgc_fill_rect(void *, gfx_rect_t *);
46static errno_t testgc_update(void *);
47static errno_t testgc_bitmap_create(void *, gfx_bitmap_params_t *,
48 gfx_bitmap_alloc_t *, void **);
49static errno_t testgc_bitmap_destroy(void *);
50static errno_t testgc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
51static errno_t testgc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
52
53static gfx_context_ops_t ops = {
54 .set_clip_rect = testgc_set_clip_rect,
55 .set_color = testgc_set_color,
56 .fill_rect = testgc_fill_rect,
57 .update = testgc_update,
58 .bitmap_create = testgc_bitmap_create,
59 .bitmap_destroy = testgc_bitmap_destroy,
60 .bitmap_render = testgc_bitmap_render,
61 .bitmap_get_alloc = testgc_bitmap_get_alloc
62};
63
64static void test_checkbox_switched(ui_checkbox_t *, void *, bool);
65
66static ui_checkbox_cb_t test_checkbox_cb = {
67 .switched = test_checkbox_switched
68};
69
70static ui_checkbox_cb_t dummy_checkbox_cb = {
71};
72
73typedef struct {
74 bool bm_created;
75 bool bm_destroyed;
76 gfx_bitmap_params_t bm_params;
77 void *bm_pixels;
78 gfx_rect_t bm_srect;
79 gfx_coord2_t bm_offs;
80 bool bm_rendered;
81 bool bm_got_alloc;
82} test_gc_t;
83
84typedef struct {
85 test_gc_t *tgc;
86 gfx_bitmap_alloc_t alloc;
87 bool myalloc;
88} testgc_bitmap_t;
89
90typedef struct {
91 bool switched;
92} test_cb_resp_t;
93
94/** Create and destroy check box */
95PCUT_TEST(create_destroy)
96{
97 ui_checkbox_t *checkbox = NULL;
98 errno_t rc;
99
100 rc = ui_checkbox_create(NULL, "Hello", &checkbox);
101 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
102 PCUT_ASSERT_NOT_NULL(checkbox);
103
104 ui_checkbox_destroy(checkbox);
105}
106
107/** ui_checkbox_destroy() can take NULL argument (no-op) */
108PCUT_TEST(destroy_null)
109{
110 ui_checkbox_destroy(NULL);
111}
112
113/** ui_checkbox_ctl() returns control that has a working virtual destructor */
114PCUT_TEST(ctl)
115{
116 ui_checkbox_t *checkbox;
117 ui_control_t *control;
118 errno_t rc;
119
120 rc = ui_checkbox_create(NULL, "Hello", &checkbox);
121 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
122
123 control = ui_checkbox_ctl(checkbox);
124 PCUT_ASSERT_NOT_NULL(control);
125
126 ui_control_destroy(control);
127}
128
129/** Set check box rectangle sets internal field */
130PCUT_TEST(set_rect)
131{
132 ui_checkbox_t *checkbox;
133 gfx_rect_t rect;
134 errno_t rc;
135
136 rc = ui_checkbox_create(NULL, "Hello", &checkbox);
137 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
138
139 rect.p0.x = 1;
140 rect.p0.y = 2;
141 rect.p1.x = 3;
142 rect.p1.y = 4;
143
144 ui_checkbox_set_rect(checkbox, &rect);
145 PCUT_ASSERT_INT_EQUALS(rect.p0.x, checkbox->rect.p0.x);
146 PCUT_ASSERT_INT_EQUALS(rect.p0.y, checkbox->rect.p0.y);
147 PCUT_ASSERT_INT_EQUALS(rect.p1.x, checkbox->rect.p1.x);
148 PCUT_ASSERT_INT_EQUALS(rect.p1.y, checkbox->rect.p1.y);
149
150 ui_checkbox_destroy(checkbox);
151}
152
153/** Paint check box */
154PCUT_TEST(paint)
155{
156 errno_t rc;
157 gfx_context_t *gc = NULL;
158 test_gc_t tgc;
159 ui_resource_t *resource = NULL;
160 ui_checkbox_t *checkbox;
161
162 memset(&tgc, 0, sizeof(tgc));
163 rc = gfx_context_new(&ops, &tgc, &gc);
164 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
165
166 rc = ui_resource_create(gc, false, &resource);
167 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
168 PCUT_ASSERT_NOT_NULL(resource);
169
170 rc = ui_checkbox_create(resource, "Hello", &checkbox);
171 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
172
173 rc = ui_checkbox_paint(checkbox);
174 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
175
176 ui_checkbox_destroy(checkbox);
177 ui_resource_destroy(resource);
178
179 rc = gfx_context_delete(gc);
180 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
181}
182
183/** Test ui_checkbox_switched() */
184PCUT_TEST(switched)
185{
186 errno_t rc;
187 ui_checkbox_t *checkbox;
188 test_cb_resp_t resp;
189
190 rc = ui_checkbox_create(NULL, "Hello", &checkbox);
191 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
192
193 /* Switched with no callbacks set */
194 ui_checkbox_switched(checkbox);
195
196 /* Switched with callback not implementing switched */
197 ui_checkbox_set_cb(checkbox, &dummy_checkbox_cb, NULL);
198 ui_checkbox_switched(checkbox);
199
200 /* Switched with real callback set */
201 resp.switched = false;
202 ui_checkbox_set_cb(checkbox, &test_checkbox_cb, &resp);
203 ui_checkbox_switched(checkbox);
204 PCUT_ASSERT_TRUE(resp.switched);
205
206 ui_checkbox_destroy(checkbox);
207}
208
209/** Press and release check box */
210PCUT_TEST(press_release)
211{
212 errno_t rc;
213 gfx_context_t *gc = NULL;
214 test_gc_t tgc;
215 ui_resource_t *resource = NULL;
216 ui_checkbox_t *checkbox;
217 test_cb_resp_t resp;
218
219 memset(&tgc, 0, sizeof(tgc));
220 rc = gfx_context_new(&ops, &tgc, &gc);
221 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
222
223 rc = ui_resource_create(gc, false, &resource);
224 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
225 PCUT_ASSERT_NOT_NULL(resource);
226
227 rc = ui_checkbox_create(resource, "Hello", &checkbox);
228 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
229 PCUT_ASSERT_FALSE(checkbox->checked);
230
231 resp.switched = false;
232 ui_checkbox_set_cb(checkbox, &test_checkbox_cb, &resp);
233
234 PCUT_ASSERT_FALSE(checkbox->held);
235 PCUT_ASSERT_FALSE(checkbox->inside);
236
237 ui_checkbox_press(checkbox);
238 PCUT_ASSERT_TRUE(checkbox->held);
239 PCUT_ASSERT_TRUE(checkbox->inside);
240 PCUT_ASSERT_FALSE(resp.switched);
241 PCUT_ASSERT_FALSE(checkbox->checked);
242
243 ui_checkbox_release(checkbox);
244 PCUT_ASSERT_FALSE(checkbox->held);
245 PCUT_ASSERT_TRUE(checkbox->inside);
246 PCUT_ASSERT_TRUE(resp.switched);
247 PCUT_ASSERT_TRUE(checkbox->checked);
248
249 ui_checkbox_destroy(checkbox);
250 ui_resource_destroy(resource);
251
252 rc = gfx_context_delete(gc);
253 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
254}
255
256/** Press, leave and release check box */
257PCUT_TEST(press_leave_release)
258{
259 errno_t rc;
260 gfx_context_t *gc = NULL;
261 test_gc_t tgc;
262 ui_resource_t *resource = NULL;
263 ui_checkbox_t *checkbox;
264 test_cb_resp_t resp;
265
266 memset(&tgc, 0, sizeof(tgc));
267 rc = gfx_context_new(&ops, &tgc, &gc);
268 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
269
270 rc = ui_resource_create(gc, false, &resource);
271 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
272 PCUT_ASSERT_NOT_NULL(resource);
273
274 rc = ui_checkbox_create(resource, "Hello", &checkbox);
275 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
276
277 resp.switched = false;
278 ui_checkbox_set_cb(checkbox, &test_checkbox_cb, &resp);
279
280 PCUT_ASSERT_FALSE(checkbox->held);
281 PCUT_ASSERT_FALSE(checkbox->inside);
282
283 ui_checkbox_press(checkbox);
284 PCUT_ASSERT_TRUE(checkbox->held);
285 PCUT_ASSERT_TRUE(checkbox->inside);
286 PCUT_ASSERT_FALSE(resp.switched);
287 PCUT_ASSERT_FALSE(checkbox->checked);
288
289 ui_checkbox_leave(checkbox);
290 PCUT_ASSERT_TRUE(checkbox->held);
291 PCUT_ASSERT_FALSE(checkbox->inside);
292 PCUT_ASSERT_FALSE(resp.switched);
293 PCUT_ASSERT_FALSE(checkbox->checked);
294
295 ui_checkbox_release(checkbox);
296 PCUT_ASSERT_FALSE(checkbox->held);
297 PCUT_ASSERT_FALSE(checkbox->inside);
298 PCUT_ASSERT_FALSE(resp.switched);
299 PCUT_ASSERT_FALSE(checkbox->checked);
300
301 ui_checkbox_destroy(checkbox);
302 ui_resource_destroy(resource);
303
304 rc = gfx_context_delete(gc);
305 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
306}
307
308/** Press, leave, enter and release check box */
309PCUT_TEST(press_leave_enter_release)
310{
311 errno_t rc;
312 gfx_context_t *gc = NULL;
313 test_gc_t tgc;
314 ui_resource_t *resource = NULL;
315 ui_checkbox_t *checkbox;
316 test_cb_resp_t resp;
317
318 memset(&tgc, 0, sizeof(tgc));
319 rc = gfx_context_new(&ops, &tgc, &gc);
320 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
321
322 rc = ui_resource_create(gc, false, &resource);
323 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
324 PCUT_ASSERT_NOT_NULL(resource);
325
326 rc = ui_checkbox_create(resource, "Hello", &checkbox);
327 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
328 PCUT_ASSERT_FALSE(checkbox->checked);
329
330 resp.switched = false;
331 ui_checkbox_set_cb(checkbox, &test_checkbox_cb, &resp);
332
333 PCUT_ASSERT_FALSE(checkbox->held);
334 PCUT_ASSERT_FALSE(checkbox->inside);
335
336 ui_checkbox_press(checkbox);
337 PCUT_ASSERT_TRUE(checkbox->held);
338 PCUT_ASSERT_TRUE(checkbox->inside);
339 PCUT_ASSERT_FALSE(resp.switched);
340 PCUT_ASSERT_FALSE(checkbox->checked);
341
342 ui_checkbox_leave(checkbox);
343 PCUT_ASSERT_TRUE(checkbox->held);
344 PCUT_ASSERT_FALSE(checkbox->inside);
345 PCUT_ASSERT_FALSE(resp.switched);
346 PCUT_ASSERT_FALSE(checkbox->checked);
347
348 ui_checkbox_enter(checkbox);
349 PCUT_ASSERT_TRUE(checkbox->held);
350 PCUT_ASSERT_TRUE(checkbox->inside);
351 PCUT_ASSERT_FALSE(resp.switched);
352 PCUT_ASSERT_FALSE(checkbox->checked);
353
354 ui_checkbox_release(checkbox);
355 PCUT_ASSERT_FALSE(checkbox->held);
356 PCUT_ASSERT_TRUE(checkbox->inside);
357 PCUT_ASSERT_TRUE(resp.switched);
358 PCUT_ASSERT_TRUE(checkbox->checked);
359
360 ui_checkbox_destroy(checkbox);
361 ui_resource_destroy(resource);
362
363 rc = gfx_context_delete(gc);
364 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
365}
366
367/** ui_pos_event() correctly translates POS_PRESS/POS_RELEASE */
368PCUT_TEST(pos_event_press_release)
369{
370 errno_t rc;
371 gfx_context_t *gc = NULL;
372 test_gc_t tgc;
373 ui_resource_t *resource = NULL;
374 ui_checkbox_t *checkbox;
375 ui_evclaim_t claim;
376 pos_event_t event;
377 gfx_rect_t rect;
378
379 memset(&tgc, 0, sizeof(tgc));
380 rc = gfx_context_new(&ops, &tgc, &gc);
381 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
382
383 rc = ui_resource_create(gc, false, &resource);
384 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
385 PCUT_ASSERT_NOT_NULL(resource);
386
387 rc = ui_checkbox_create(resource, "Hello", &checkbox);
388 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
389
390 PCUT_ASSERT_FALSE(checkbox->held);
391
392 rect.p0.x = 10;
393 rect.p0.y = 20;
394 rect.p1.x = 30;
395 rect.p1.y = 40;
396 ui_checkbox_set_rect(checkbox, &rect);
397
398 /* Press outside is not claimed and does nothing */
399 event.type = POS_PRESS;
400 event.hpos = 9;
401 event.vpos = 20;
402 claim = ui_checkbox_pos_event(checkbox, &event);
403 PCUT_ASSERT_FALSE(checkbox->held);
404 PCUT_ASSERT_EQUALS(ui_unclaimed, claim);
405
406 /* Press inside is claimed and depresses check box */
407 event.type = POS_PRESS;
408 event.hpos = 10;
409 event.vpos = 20;
410 claim = ui_checkbox_pos_event(checkbox, &event);
411 PCUT_ASSERT_TRUE(checkbox->held);
412 PCUT_ASSERT_EQUALS(ui_claimed, claim);
413
414 /* Release outside (or anywhere) is claimed and relases check box */
415 event.type = POS_RELEASE;
416 event.hpos = 9;
417 event.vpos = 20;
418 claim = ui_checkbox_pos_event(checkbox, &event);
419 PCUT_ASSERT_FALSE(checkbox->held);
420 PCUT_ASSERT_EQUALS(ui_claimed, claim);
421
422 ui_checkbox_destroy(checkbox);
423 ui_resource_destroy(resource);
424
425 rc = gfx_context_delete(gc);
426 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
427}
428
429/** ui_pos_event() correctly translates POS_UPDATE to enter/leave */
430PCUT_TEST(pos_event_enter_leave)
431{
432 errno_t rc;
433 gfx_context_t *gc = NULL;
434 test_gc_t tgc;
435 ui_resource_t *resource = NULL;
436 ui_checkbox_t *checkbox;
437 pos_event_t event;
438 gfx_rect_t rect;
439
440 memset(&tgc, 0, sizeof(tgc));
441 rc = gfx_context_new(&ops, &tgc, &gc);
442 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
443
444 rc = ui_resource_create(gc, false, &resource);
445 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
446 PCUT_ASSERT_NOT_NULL(resource);
447
448 rc = ui_checkbox_create(resource, "Hello", &checkbox);
449 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
450
451 PCUT_ASSERT_FALSE(checkbox->inside);
452
453 rect.p0.x = 10;
454 rect.p0.y = 20;
455 rect.p1.x = 30;
456 rect.p1.y = 40;
457 ui_checkbox_set_rect(checkbox, &rect);
458
459 /* Moving outside does nothing */
460 event.type = POS_UPDATE;
461 event.hpos = 9;
462 event.vpos = 20;
463 ui_checkbox_pos_event(checkbox, &event);
464 PCUT_ASSERT_FALSE(checkbox->inside);
465
466 /* Moving inside sets inside flag */
467 event.type = POS_UPDATE;
468 event.hpos = 10;
469 event.vpos = 20;
470 ui_checkbox_pos_event(checkbox, &event);
471 PCUT_ASSERT_TRUE(checkbox->inside);
472
473 /* Moving outside clears inside flag */
474 event.type = POS_UPDATE;
475 event.hpos = 9;
476 event.vpos = 20;
477 ui_checkbox_pos_event(checkbox, &event);
478 PCUT_ASSERT_FALSE(checkbox->inside);
479
480 ui_checkbox_destroy(checkbox);
481 ui_resource_destroy(resource);
482
483 rc = gfx_context_delete(gc);
484 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
485}
486
487static errno_t testgc_set_clip_rect(void *arg, gfx_rect_t *rect)
488{
489 (void) arg;
490 (void) rect;
491 return EOK;
492}
493
494static errno_t testgc_set_color(void *arg, gfx_color_t *color)
495{
496 (void) arg;
497 (void) color;
498 return EOK;
499}
500
501static errno_t testgc_fill_rect(void *arg, gfx_rect_t *rect)
502{
503 (void) arg;
504 (void) rect;
505 return EOK;
506}
507
508static errno_t testgc_update(void *arg)
509{
510 (void) arg;
511 return EOK;
512}
513
514static errno_t testgc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
515 gfx_bitmap_alloc_t *alloc, void **rbm)
516{
517 test_gc_t *tgc = (test_gc_t *) arg;
518 testgc_bitmap_t *tbm;
519
520 tbm = calloc(1, sizeof(testgc_bitmap_t));
521 if (tbm == NULL)
522 return ENOMEM;
523
524 if (alloc == NULL) {
525 tbm->alloc.pitch = (params->rect.p1.x - params->rect.p0.x) *
526 sizeof(uint32_t);
527 tbm->alloc.off0 = 0;
528 tbm->alloc.pixels = calloc(sizeof(uint32_t),
529 (params->rect.p1.x - params->rect.p0.x) *
530 (params->rect.p1.y - params->rect.p0.y));
531 tbm->myalloc = true;
532 if (tbm->alloc.pixels == NULL) {
533 free(tbm);
534 return ENOMEM;
535 }
536 } else {
537 tbm->alloc = *alloc;
538 }
539
540 tbm->tgc = tgc;
541 tgc->bm_created = true;
542 tgc->bm_params = *params;
543 tgc->bm_pixels = tbm->alloc.pixels;
544 *rbm = (void *)tbm;
545 return EOK;
546}
547
548static errno_t testgc_bitmap_destroy(void *bm)
549{
550 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
551 if (tbm->myalloc)
552 free(tbm->alloc.pixels);
553 tbm->tgc->bm_destroyed = true;
554 free(tbm);
555 return EOK;
556}
557
558static errno_t testgc_bitmap_render(void *bm, gfx_rect_t *srect,
559 gfx_coord2_t *offs)
560{
561 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
562 tbm->tgc->bm_rendered = true;
563 tbm->tgc->bm_srect = *srect;
564 tbm->tgc->bm_offs = *offs;
565 return EOK;
566}
567
568static errno_t testgc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
569{
570 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
571 *alloc = tbm->alloc;
572 tbm->tgc->bm_got_alloc = true;
573 return EOK;
574}
575
576static void test_checkbox_switched(ui_checkbox_t *checkbox, void *arg,
577 bool checked)
578{
579 test_cb_resp_t *resp = (test_cb_resp_t *) arg;
580
581 resp->switched = true;
582}
583
584PCUT_EXPORT(checkbox);
Note: See TracBrowser for help on using the repository browser.