aboutsummaryrefslogtreecommitdiff
path: root/subprojects/d2tk/test
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2019-03-16 16:55:40 +0100
committerHanspeter Portner <dev@open-music-kontrollers.ch>2019-03-16 16:55:40 +0100
commitf4d902d6a016f9d25f45cca7bb9b1c876a0864e9 (patch)
tree2b92dd1f9d2ba19af99b3c8bab1f71a9cb5c2d5e /subprojects/d2tk/test
parentc37cce9d075cb1eb6691244cf25121ddea438f3b (diff)
parent2462d1c890de3a577f278795029a40399d72db8e (diff)
downloadtracker.lv2-f4d902d6a016f9d25f45cca7bb9b1c876a0864e9.tar.xz
Merge commit '2462d1c890de3a577f278795029a40399d72db8e' as 'subprojects/d2tk'
Diffstat (limited to 'subprojects/d2tk/test')
-rw-r--r--subprojects/d2tk/test/base.c107
-rw-r--r--subprojects/d2tk/test/core.c1291
-rw-r--r--subprojects/d2tk/test/mock.c236
-rw-r--r--subprojects/d2tk/test/mock.h45
4 files changed, 1679 insertions, 0 deletions
diff --git a/subprojects/d2tk/test/base.c b/subprojects/d2tk/test/base.c
new file mode 100644
index 0000000..c711528
--- /dev/null
+++ b/subprojects/d2tk/test/base.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018-2019 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <d2tk/base.h>
+#include <d2tk/hash.h>
+#include "mock.h"
+
+static void
+_expose_hot(d2tk_base_t *base, const d2tk_rect_t *rect, unsigned n, unsigned p)
+{
+ D2TK_BASE_TABLE(rect, n, 1, tab)
+ {
+ const d2tk_rect_t *bnd = d2tk_table_get_rect(tab);
+ const unsigned k = d2tk_table_get_index(tab);
+ const d2tk_id_t id = D2TK_ID_IDX(k);
+
+ const d2tk_state_t state = d2tk_base_button(base, id, bnd);
+
+ if(k == p) // this element must be of state OVER and HOT
+ {
+ if(p == 0) // first element additionally has FOCUS
+ {
+ assert(state == (D2TK_STATE_OVER | D2TK_STATE_FOCUS | D2TK_STATE_HOT) );
+ }
+ else
+ {
+ assert(state == (D2TK_STATE_OVER | D2TK_STATE_HOT) );
+ }
+ }
+ else if(k == 0) // first element always has FOCUS
+ {
+ assert(state == D2TK_STATE_FOCUS);
+ }
+ else // all other elements have no state
+ {
+ assert(state == D2TK_STATE_NONE);
+ }
+ }
+}
+
+static void
+_test_hot()
+{
+#define N 4
+ d2tk_mock_ctx_t ctx = {
+ .check = NULL
+ };
+
+ d2tk_base_t *base = d2tk_base_new(&d2tk_mock_driver_lazy, &ctx);
+ assert(base);
+
+ d2tk_base_set_dimensions(base, DIM_W, DIM_H);
+ const d2tk_rect_t rect = D2TK_RECT(0, 0, DIM_W, DIM_H);
+
+ for(unsigned p = 0; p < N; p++)
+ {
+ const float p5 = p + 0.5f;
+ const d2tk_coord_t mx = DIM_W / N * p5;
+ const d2tk_coord_t my = DIM_H / 2;
+
+ d2tk_base_set_mouse_pos(base, mx, my);
+
+ d2tk_base_pre(base);
+
+ _expose_hot(base, &rect, N, p);
+
+ d2tk_base_post(base);
+ }
+
+ // trigger garbage collector
+ for(unsigned i = 0; i < 0x400; i++)
+ {
+ d2tk_base_pre(base);
+ d2tk_base_post(base);
+ }
+
+ d2tk_base_free(base);
+#undef N
+}
+
+int
+main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+ _test_hot();
+
+ return EXIT_SUCCESS;
+}
diff --git a/subprojects/d2tk/test/core.c b/subprojects/d2tk/test/core.c
new file mode 100644
index 0000000..f2b0b17
--- /dev/null
+++ b/subprojects/d2tk/test/core.c
@@ -0,0 +1,1291 @@
+/*
+ * Copyright (c) 2018-2019 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <d2tk/core.h>
+#include <d2tk/hash.h>
+#include "mock.h"
+
+static void
+_test_hash()
+{
+ const char *foo = "barbarbarbar";
+
+ const uint64_t hash1 = d2tk_hash(foo, -1);
+ const uint64_t hash2 = d2tk_hash(foo, strlen(foo));
+
+ assert(hash1 == hash2);
+}
+
+static void
+_test_hash_foreach()
+{
+ const char *foo = "barbarbarbar";
+ const char *bar = "foofoofoofoo";
+
+ const uint64_t hash1 = d2tk_hash_foreach(foo, -1,
+ bar, -1,
+ NULL);
+ const uint64_t hash2 = d2tk_hash_foreach(foo, strlen(foo),
+ bar, strlen(bar),
+ NULL);
+
+ assert(hash1 == hash2);
+}
+
+static void
+_test_rect_shrink()
+{
+ d2tk_rect_t dst;
+
+ // initialization
+ const d2tk_rect_t src = D2TK_RECT(1, 2, 3, 4);
+ assert(src.x == 1);
+ assert(src.y == 2);
+ assert(src.w == 3);
+ assert(src.h == 4);
+
+ // shrink on x-axis
+ memset(&dst, 0x0, sizeof(dst));
+ d2tk_rect_shrink_x(&dst, &src, 1);
+ assert(dst.x == 1 + 1);
+ assert(dst.y == 2);
+ assert(dst.w == 3 - 2*1);
+ assert(dst.h == 4);
+
+ // shrink on y-axis
+ memset(&dst, 0x0, sizeof(dst));
+ d2tk_rect_shrink_y(&dst, &src, 1);
+ assert(dst.x == 1);
+ assert(dst.y == 2 + 1);
+ assert(dst.w == 3);
+ assert(dst.h == 4 - 2*1);
+
+ // shrink on x/y-axes
+ memset(&dst, 0x0, sizeof(dst));
+ d2tk_rect_shrink(&dst, &src, 1);
+ assert(dst.x == 1 + 1);
+ assert(dst.y == 2 + 1);
+ assert(dst.w == 3 - 2*1);
+ assert(dst.h == 4 - 2*1);
+}
+
+static void
+_test_point()
+{
+ // initialization
+ const d2tk_point_t src = D2TK_POINT(11, 22);
+ assert(src.x == 11);
+ assert(src.y == 22);
+}
+
+static void
+_test_dimensions()
+{
+ d2tk_coord_t w;
+ d2tk_coord_t h;
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, NULL);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ w = 0;
+ h = 0;
+ d2tk_core_get_dimensions(core, &w, &h);
+ assert(w == DIM_W);
+ assert(h == DIM_H);
+
+ w = 0;
+ h = 0;
+ d2tk_core_get_dimensions(core, NULL, NULL);
+ assert(w == 0);
+ assert(h == 0);
+
+ d2tk_core_free(core);
+}
+
+#define BG_COLOR 0x222222ff
+
+static void
+_test_bg_color()
+{
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, NULL);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_set_bg_color(core, BG_COLOR);
+ assert(BG_COLOR == d2tk_core_get_bg_color(core));
+
+ d2tk_core_free(core);
+}
+
+#undef BG_COLOR
+
+#define MOVE_TO_X 10
+#define MOVE_TO_Y 20
+
+static void
+_check_move_to(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_move_to_t));
+ assert(com->instr == D2TK_INSTR_MOVE_TO);
+ assert(com->body->move_to.x == MOVE_TO_X - CLIP_X);
+ assert(com->body->move_to.y == MOVE_TO_Y - CLIP_Y);
+}
+
+static void
+_test_move_to()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_move_to
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_move_to(core, MOVE_TO_X, MOVE_TO_Y);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+
+ // trigger garbage collector
+ for(unsigned i = 0; i < 0x400; i++)
+ {
+ d2tk_core_pre(core);
+ d2tk_core_post(core);
+ }
+
+ d2tk_core_free(core);
+}
+
+#undef MOVE_TO_X
+#undef MOVE_TO_Y
+
+#define LINE_TO_X 10
+#define LINE_TO_Y 20
+
+static void
+_check_line_to(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_line_to_t));
+ assert(com->instr == D2TK_INSTR_LINE_TO);
+ assert(com->body->line_to.x == LINE_TO_X - CLIP_X);
+ assert(com->body->line_to.y == LINE_TO_Y - CLIP_Y);
+}
+
+static void
+_test_line_to()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_line_to
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_line_to(core, LINE_TO_X, LINE_TO_Y);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef LINE_TO_X
+#undef LINE_TO_Y
+
+#define RECT_X 10
+#define RECT_Y 20
+#define RECT_W 30
+#define RECT_H 40
+
+static void
+_check_rect(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_rect_t));
+ assert(com->instr == D2TK_INSTR_RECT);
+ assert(com->body->rect.x == RECT_X - CLIP_X);
+ assert(com->body->rect.y == RECT_Y - CLIP_Y);
+ assert(com->body->rect.w == RECT_W);
+ assert(com->body->rect.h == RECT_H);
+}
+
+static void
+_test_rect()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_rect
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rect(core, &D2TK_RECT(RECT_X, RECT_Y, RECT_W, RECT_H));
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef RECT_X
+#undef RECT_Y
+#undef RECT_W
+#undef RECT_H
+
+#define ROUNDED_RECT_X 10
+#define ROUNDED_RECT_Y 20
+#define ROUNDED_RECT_W 30
+#define ROUNDED_RECT_H 40
+#define ROUNDED_RECT_R 5
+
+static void
+_check_rounded_rect(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_rounded_rect_t));
+ assert(com->instr == D2TK_INSTR_ROUNDED_RECT);
+ assert(com->body->rounded_rect.x == ROUNDED_RECT_X - CLIP_X);
+ assert(com->body->rounded_rect.y == ROUNDED_RECT_Y - CLIP_Y);
+ assert(com->body->rounded_rect.w == ROUNDED_RECT_W);
+ assert(com->body->rounded_rect.h == ROUNDED_RECT_H);
+ assert(com->body->rounded_rect.r == ROUNDED_RECT_R);
+}
+
+static void
+_test_rounded_rect()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_rounded_rect
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rounded_rect(core,
+ &D2TK_RECT(ROUNDED_RECT_X, ROUNDED_RECT_Y, ROUNDED_RECT_W, ROUNDED_RECT_H),
+ ROUNDED_RECT_R);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef ROUNDED_RECT_X
+#undef ROUNDED_RECT_Y
+#undef ROUNDED_RECT_W
+#undef ROUNDED_RECT_H
+#undef ROUNDED_RECT_R
+
+#define ARC_X 10
+#define ARC_Y 20
+#define ARC_R 5
+#define ARC_A 30
+#define ARC_B 60
+#define ARC_CW true
+
+static void
+_check_arc(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_arc_t));
+ assert(com->instr == D2TK_INSTR_ARC);
+ assert(com->body->arc.x == ARC_X - CLIP_X);
+ assert(com->body->arc.y == ARC_Y - CLIP_Y);
+ assert(com->body->arc.r == ARC_R);
+ assert(com->body->arc.a == ARC_A);
+ assert(com->body->arc.b == ARC_B);
+ assert(com->body->arc.cw == ARC_CW);
+}
+
+static void
+_test_arc()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_arc
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_arc(core, ARC_X, ARC_Y, ARC_R, ARC_A, ARC_B, ARC_CW);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef ARC_X
+#undef ARC_Y
+#undef ARC_R
+#undef ARC_A
+#undef ARC_B
+#undef ARC_CW
+
+#define CURVE_TO_X1 10
+#define CURVE_TO_Y1 10
+#define CURVE_TO_X2 20
+#define CURVE_TO_Y2 20
+#define CURVE_TO_X3 30
+#define CURVE_TO_Y3 30
+
+static void
+_check_curve_to(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_curve_to_t));
+ assert(com->instr == D2TK_INSTR_CURVE_TO);
+ assert(com->body->curve_to.x1 == CURVE_TO_X1 - CLIP_X);
+ assert(com->body->curve_to.y1 == CURVE_TO_Y1 - CLIP_Y);
+ assert(com->body->curve_to.x2 == CURVE_TO_X2 - CLIP_X);
+ assert(com->body->curve_to.y2 == CURVE_TO_Y2 - CLIP_Y);
+ assert(com->body->curve_to.x3 == CURVE_TO_X3 - CLIP_X);
+ assert(com->body->curve_to.y3 == CURVE_TO_Y3 - CLIP_Y);
+}
+
+static void
+_test_curve_to()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_curve_to
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_curve_to(core, CURVE_TO_X1, CURVE_TO_Y1, CURVE_TO_X2, CURVE_TO_Y2,
+ CURVE_TO_X3, CURVE_TO_Y3);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef CURVE_TO_X1
+#undef CURVE_TO_Y1
+#undef CURVE_TO_X2
+#undef CURVE_TO_Y2
+#undef CURVE_TO_X3
+#undef CURVE_TO_Y3
+
+#define COLOR_RGBA 0xff00ff00
+
+static void
+_check_color(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_color_t));
+ assert(com->instr == D2TK_INSTR_COLOR);
+ assert(com->body->color.rgba == COLOR_RGBA);
+}
+
+static void
+_test_color()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_color
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_color(core, COLOR_RGBA);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef COLOR_RGBA
+
+#define LINEAR_GRADIENT_X_0 10
+#define LINEAR_GRADIENT_Y_0 20
+#define LINEAR_GRADIENT_X_1 30
+#define LINEAR_GRADIENT_Y_1 40
+#define LINEAR_GRADIENT_RGBA_0 0xff00ff00
+#define LINEAR_GRADIENT_RGBA_1 0xffff00ff
+
+static void
+_check_linear_gradient(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_linear_gradient_t));
+ assert(com->instr == D2TK_INSTR_LINEAR_GRADIENT);
+ assert(com->body->linear_gradient.p[0].x == LINEAR_GRADIENT_X_0 - CLIP_X);
+ assert(com->body->linear_gradient.p[0].y == LINEAR_GRADIENT_Y_0 - CLIP_Y);
+ assert(com->body->linear_gradient.p[1].x == LINEAR_GRADIENT_X_1 - CLIP_X);
+ assert(com->body->linear_gradient.p[1].y == LINEAR_GRADIENT_Y_1 - CLIP_Y);
+ assert(com->body->linear_gradient.rgba[0] == LINEAR_GRADIENT_RGBA_0);
+ assert(com->body->linear_gradient.rgba[1] == LINEAR_GRADIENT_RGBA_1);
+}
+
+static void
+_test_linear_gradient()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_linear_gradient
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ const d2tk_point_t p [2] = {
+ D2TK_POINT(LINEAR_GRADIENT_X_0, LINEAR_GRADIENT_Y_0),
+ D2TK_POINT(LINEAR_GRADIENT_X_1, LINEAR_GRADIENT_Y_1)
+ };
+ const uint32_t rgba [2] = {
+ LINEAR_GRADIENT_RGBA_0,
+ LINEAR_GRADIENT_RGBA_1
+ };
+ d2tk_core_linear_gradient(core, p, rgba);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef LINEAR_GRADIENT_X_0
+#undef LINEAR_GRADIENT_Y_0
+#undef LINEAR_GRADIENT_X_1
+#undef LINEAR_GRADIENT_Y_1
+#undef LINEAR_GRADIENT_RGBA_0
+#undef LINEAR_GRADIENT_RGBA_1
+
+static void
+_check_stroke(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_STROKE);
+}
+
+static void
+_test_stroke()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_stroke
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_stroke(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+static void
+_check_fill(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_FILL);
+}
+
+static void
+_test_fill()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_fill
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_fill(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+static void
+_check_save(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_SAVE);
+}
+
+static void
+_test_save()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_save
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_save(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+static void
+_check_restore(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_RESTORE);
+}
+
+static void
+_test_restore()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_restore
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_restore(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#define ROTATE_DEG 45
+
+static void
+_check_rotate(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_rotate_t));
+ assert(com->instr == D2TK_INSTR_ROTATE);
+ assert(com->body->rotate.deg == ROTATE_DEG);
+}
+
+static void
+_test_rotate()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_rotate
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rotate(core, ROTATE_DEG);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef ROTATE_DEG
+
+static void
+_check_begin_path(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_BEGIN_PATH);
+}
+
+static void
+_test_begin_path()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_begin_path
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_begin_path(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+static void
+_check_close_path(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_CLOSE_PATH);
+}
+
+static void
+_test_close_path()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_close_path
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_close_path(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#define SCISSOR_X 10
+#define SCISSOR_Y 20
+#define SCISSOR_W 30
+#define SCISSOR_H 40
+
+static void
+_check_scissor(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_scissor_t));
+ assert(com->instr == D2TK_INSTR_SCISSOR);
+ assert(com->body->scissor.x == SCISSOR_X - CLIP_X);
+ assert(com->body->scissor.y == SCISSOR_Y - CLIP_Y);
+ assert(com->body->scissor.w == SCISSOR_W);
+ assert(com->body->scissor.h == SCISSOR_H);
+}
+
+static void
+_test_scissor()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_scissor
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_scissor(core, &D2TK_RECT(SCISSOR_X, SCISSOR_Y, SCISSOR_W, SCISSOR_H));
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef SCISSOR_X
+#undef SCISSOR_Y
+#undef SCISSOR_W
+#undef SCISSOR_H
+
+static void
+_check_reset_scissor(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == 0);
+ assert(com->instr == D2TK_INSTR_RESET_SCISSOR);
+}
+
+static void
+_test_reset_scissor()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_reset_scissor
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_reset_scissor(core);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#define FONT_SIZE 11
+
+static void
+_check_font_size(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_font_size_t));
+ assert(com->instr == D2TK_INSTR_FONT_SIZE);
+ assert(com->body->font_size.size == FONT_SIZE);
+}
+
+static void
+_test_font_size()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_font_size
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_font_size(core, FONT_SIZE);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef FONT_SIZE
+
+#define FONT_FACE "Monospace"
+
+static void
+_check_font_face(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_font_face_t) + strlen(FONT_FACE));
+ assert(com->instr == D2TK_INSTR_FONT_FACE);
+ assert(strcmp(com->body->font_face.face, FONT_FACE) == 0);
+}
+
+static void
+_test_font_face()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_font_face
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_font_face(core, strlen(FONT_FACE), FONT_FACE);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef FONT_FACE
+
+#define TEXT_X 10
+#define TEXT_Y 20
+#define TEXT_W 30
+#define TEXT_H 40
+#define TEXT_TEXT "Text"
+#define TEXT_ALIGN D2TK_ALIGN_LEFT
+
+static void
+_check_text(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_text_t) + strlen(TEXT_TEXT));
+ assert(com->instr == D2TK_INSTR_TEXT);
+ assert(com->body->text.x == TEXT_X - CLIP_X);
+ assert(com->body->text.y == TEXT_Y - CLIP_Y);
+ assert(com->body->text.w == TEXT_W);
+ assert(com->body->text.h == TEXT_H);
+ assert(strcmp(com->body->text.text, TEXT_TEXT) == 0);
+ assert(com->body->text.align == TEXT_ALIGN);
+}
+
+static void
+_test_text()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_text
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_text(core, &D2TK_RECT(TEXT_X, TEXT_Y, TEXT_W, TEXT_H),
+ strlen(TEXT_TEXT), TEXT_TEXT, TEXT_ALIGN);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef TEXT_X
+#undef TEXT_Y
+#undef TEXT_W
+#undef TEXT_H
+#undef TEXT_TEXT
+#undef TEXT_ALIGN
+
+#define IMAGE_X 10
+#define IMAGE_Y 20
+#define IMAGE_W 30
+#define IMAGE_H 40
+#define IMAGE_PATH "./libre-sugar-skull.png"
+#define IMAGE_ALIGN D2TK_ALIGN_LEFT
+
+static void
+_check_image(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_image_t) + strlen(IMAGE_PATH));
+ assert(com->instr == D2TK_INSTR_IMAGE);
+ assert(com->body->image.x == IMAGE_X - CLIP_X);
+ assert(com->body->image.y == IMAGE_Y - CLIP_Y);
+ assert(com->body->image.w == IMAGE_W);
+ assert(com->body->image.h == IMAGE_H);
+ assert(strcmp(com->body->image.path , IMAGE_PATH) == 0);
+ assert(com->body->image.align == IMAGE_ALIGN);
+}
+
+static void
+_test_image()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_image
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_image(core, &D2TK_RECT(IMAGE_X, IMAGE_Y, IMAGE_W, IMAGE_H),
+ strlen(IMAGE_PATH), IMAGE_PATH, IMAGE_ALIGN);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef IMAGE_X
+#undef IMAGE_Y
+#undef IMAGE_W
+#undef IMAGE_H
+#undef IMAGE_PATH
+#undef IMAGE_ALIGN
+
+#define STROKE_WIDTH 2
+
+static void
+_check_stroke_width(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_stroke_width_t));
+ assert(com->instr == D2TK_INSTR_STROKE_WIDTH);
+ assert(com->body->stroke_width.width == STROKE_WIDTH);
+}
+
+static void
+_test_stroke_width()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_stroke_width
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_stroke_width(core, STROKE_WIDTH);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef STROKE_WIDTH
+
+static void
+_check_triple(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ (void)com; //FIXME
+}
+
+static void
+_test_triple()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_triple
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver_triple, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ for(unsigned i = 0; i < 3; i++)
+ {
+ d2tk_core_pre(core);
+
+ if(i != 0)
+ {
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rect(core, &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+
+ d2tk_core_bbox_pop(core, ref);
+ }
+
+ if(i != 1)
+ {
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rect(core, &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W/2, CLIP_H));
+
+ d2tk_core_bbox_pop(core, ref);
+ }
+
+ if(i != 2)
+ {
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ d2tk_core_rect(core, &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H/2));
+
+ d2tk_core_bbox_pop(core, ref);
+ }
+
+ d2tk_core_post(core);
+ }
+
+ d2tk_core_free(core);
+}
+
+int
+main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+ _test_hash();
+ _test_hash_foreach();
+ _test_rect_shrink();
+ _test_point();
+ _test_dimensions();
+ _test_bg_color();
+
+ _test_move_to();
+ _test_line_to();
+ _test_rect();
+ _test_rounded_rect();
+ _test_arc();
+ _test_curve_to();
+ _test_color();
+ _test_linear_gradient();
+ _test_stroke();
+ _test_fill();
+ _test_save();
+ _test_restore();
+ _test_rotate();
+ _test_begin_path();
+ _test_close_path();
+ _test_scissor();
+ _test_reset_scissor();
+ _test_font_size();
+ _test_font_face();
+ _test_text();
+ _test_image();
+ _test_stroke_width();
+
+ _test_triple();
+
+ return EXIT_SUCCESS;
+}
diff --git a/subprojects/d2tk/test/mock.c b/subprojects/d2tk/test/mock.c
new file mode 100644
index 0000000..95ef666
--- /dev/null
+++ b/subprojects/d2tk/test/mock.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2019 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "mock.h"
+
+static inline void
+_d2tk_mock_pre(void *data, d2tk_core_t *core, d2tk_coord_t w, d2tk_coord_t h,
+ unsigned pass)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(core);
+ assert(w == DIM_W);
+ assert(h == DIM_H);
+ assert(pass == 0);
+}
+
+static inline bool
+_d2tk_mock_post(void *data, d2tk_core_t *core, d2tk_coord_t w, d2tk_coord_t h,
+ unsigned pass)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(core);
+ assert(w == DIM_W);
+ assert(h == DIM_H);
+ assert(pass == 0);
+
+ assert(d2tk_core_get_pixels(core));
+
+ return false; // do NOT enter 3rd pass
+}
+
+static inline void
+_d2tk_mock_sprite_free(void *data, uint8_t type, uintptr_t body)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(type == 1);
+
+ uint32_t *dummy = (uint32_t *)body;
+ assert(*dummy == 1234);
+ free(dummy);
+}
+
+static inline void
+_d2tk_mock_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
+ d2tk_coord_t xo, d2tk_coord_t yo,
+ const d2tk_clip_t *clip __attribute__((unused)), unsigned pass)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(core);
+ assert(com);
+ assert(xo == CLIP_X);
+ assert(yo == CLIP_Y);
+ assert(pass == 0);
+
+ assert(com->instr == D2TK_INSTR_BBOX);
+
+ const d2tk_body_bbox_t *body = &com->body->bbox;
+ assert(body->dirty == false);
+ assert(body->cached == true);
+ assert(body->hash != 0x0); //FIXME
+
+ uintptr_t *sprite = d2tk_core_get_sprite(core, body->hash, 1);
+ assert(sprite);
+ assert(*sprite == 0);
+
+ uint32_t *dummy = calloc(1, sizeof(uint32_t));
+ assert(dummy);
+ *dummy = 1234;
+
+ *sprite = (uintptr_t)dummy;
+
+ assert(sprite == d2tk_core_get_sprite(core, body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, body->hash, 0));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 0));
+
+ unsigned num = 0;
+ D2TK_COM_FOREACH_CONST(com, bbox)
+ {
+ if(ctx->check)
+ {
+ ctx->check(bbox, &body->clip);
+ }
+ num += 1;
+ }
+ assert(num == 1);
+}
+
+static inline void
+_d2tk_mock_process_triple(void *data, d2tk_core_t *core, const d2tk_com_t *com,
+ d2tk_coord_t xo, d2tk_coord_t yo,
+ const d2tk_clip_t *clip __attribute__((unused)), unsigned pass)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(core);
+ assert(com);
+ assert(xo == CLIP_X);
+ assert(yo == CLIP_Y);
+ assert(pass == 0);
+
+ assert(com->instr == D2TK_INSTR_BBOX);
+
+ const d2tk_body_bbox_t *body = &com->body->bbox;
+ //assert(body->dirty == false);
+ assert(body->cached == true);
+ assert(body->hash != 0x0); //FIXME
+
+ uintptr_t *sprite = d2tk_core_get_sprite(core, body->hash, 1);
+ assert(sprite);
+
+ if(*sprite == 0)
+ {
+ uint32_t *dummy = calloc(1, sizeof(uint32_t));
+ assert(dummy);
+ *dummy = 1234;
+
+ *sprite = (uintptr_t)dummy;
+ }
+
+ assert(sprite == d2tk_core_get_sprite(core, body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, body->hash, 0));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 0));
+
+ unsigned num = 0;
+ D2TK_COM_FOREACH_CONST(com, bbox)
+ {
+ if(ctx->check)
+ {
+ ctx->check(bbox, &body->clip);
+ }
+ num += 1;
+ }
+ assert(num == 1);
+}
+
+static inline void
+_d2tk_mock_process_lazy(void *data, d2tk_core_t *core, const d2tk_com_t *com,
+ d2tk_coord_t xo __attribute__((unused)), d2tk_coord_t yo __attribute__((unused)),
+ const d2tk_clip_t *clip __attribute__((unused)), unsigned pass)
+{
+ d2tk_mock_ctx_t *ctx = data;
+ assert(ctx);
+
+ assert(core);
+ assert(com);
+ assert(pass == 0);
+
+ assert(com->instr == D2TK_INSTR_BBOX);
+
+ const d2tk_body_bbox_t *body = &com->body->bbox;
+ assert(body->cached == true);
+ assert(body->hash != 0x0); //FIXME
+
+ uintptr_t *sprite = d2tk_core_get_sprite(core, body->hash, 1);
+ assert(sprite);
+
+ if(*sprite == 0)
+ {
+ uint32_t *dummy = calloc(1, sizeof(uint32_t));
+ assert(dummy);
+ *dummy = 1234;
+
+ *sprite = (uintptr_t)dummy;
+ }
+
+ assert(sprite == d2tk_core_get_sprite(core, body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, body->hash, 0));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 1));
+ assert(sprite != d2tk_core_get_sprite(core, ~body->hash, 0));
+
+ unsigned num = 0;
+ D2TK_COM_FOREACH_CONST(com, bbox)
+ {
+ if(ctx->check)
+ {
+ ctx->check(bbox, &body->clip);
+ }
+ num += 1;
+ }
+ assert(num > 0);
+}
+
+const d2tk_core_driver_t d2tk_mock_driver = {
+ .new = NULL,
+ .free = NULL,
+ .pre = _d2tk_mock_pre,
+ .process = _d2tk_mock_process,
+ .post = _d2tk_mock_post,
+ .sprite_free = _d2tk_mock_sprite_free
+};
+
+const d2tk_core_driver_t d2tk_mock_driver_triple = {
+ .new = NULL,
+ .free = NULL,
+ .pre = _d2tk_mock_pre,
+ .process = _d2tk_mock_process_triple,
+ .post = _d2tk_mock_post,
+ .sprite_free = _d2tk_mock_sprite_free
+};
+
+const d2tk_core_driver_t d2tk_mock_driver_lazy = {
+ .new = NULL,
+ .free = NULL,
+ .pre = _d2tk_mock_pre,
+ .process = _d2tk_mock_process_lazy,
+ .post = _d2tk_mock_post,
+ .sprite_free = _d2tk_mock_sprite_free
+};
diff --git a/subprojects/d2tk/test/mock.h b/subprojects/d2tk/test/mock.h
new file mode 100644
index 0000000..8b18ddb
--- /dev/null
+++ b/subprojects/d2tk/test/mock.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2019 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#ifndef _D2TK_MOCK_H
+#define _D2TK_MOCK_H
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include "src/core_internal.h"
+
+#define DIM_W 640
+#define DIM_H 480
+
+#define CLIP_X 10
+#define CLIP_Y 10
+#define CLIP_W 100
+#define CLIP_H 100
+
+typedef void (*d2tk_check_t)(const d2tk_com_t *com, const d2tk_clip_t *clip);
+typedef struct _d2tk_mock_ctx_t d2tk_mock_ctx_t;
+
+struct _d2tk_mock_ctx_t {
+ d2tk_check_t check;
+};
+
+extern const d2tk_core_driver_t d2tk_mock_driver;
+extern const d2tk_core_driver_t d2tk_mock_driver_triple;
+extern const d2tk_core_driver_t d2tk_mock_driver_lazy;
+
+#endif // _D2TK_MOCK_H