From 3e2e9d4e5bb2551f67eee1605b1f904ee91b363c Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Sun, 26 Nov 2017 14:18:43 +0100 Subject: [PATCH] Add screen.[ch] and unit tests --- include/screen.h | 28 ++++++++ include/widget.h | 13 ++++ src/screen.c | 121 ++++++++++++++++++++++++++++++++++ src/widget.c | 101 +++++++++++++++++++--------- unittest/Makefile | 2 +- unittest/data/TestScreen.json | 5 ++ unittest/main.c | 10 ++- unittest/mgos_mock.c | 2 +- unittest/test.h | 14 ++++ unittest/test_screen.c | 73 ++++++++++++++++++++ unittest/test_widget.c | 21 +++--- 11 files changed, 344 insertions(+), 46 deletions(-) create mode 100644 include/screen.h create mode 100644 src/screen.c diff --git a/include/screen.h b/include/screen.h new file mode 100644 index 0000000..8e2f9a7 --- /dev/null +++ b/include/screen.h @@ -0,0 +1,28 @@ +#ifndef __SCREEN_H +#define __SCREEN_H + +#include "mgos.h" +#include "frozen/frozen.h" +#include "common/queue.h" +#include "widget.h" + +struct screen_t { + char *name; + uint16_t x, y, w, h; + + // Private + SLIST_HEAD(widget_entries, widget_list_t) widget_entries; +}; + +struct screen_t *screen_create(char *name, uint16_t x, uint16_t y, uint16_t w, uint16_t h); +struct screen_t *screen_create_from_file(char *fn); +void screen_destroy(struct screen_t **s); + +bool screen_widget_add(struct screen_t *s, struct widget_t *w); +struct widget_t *screen_widget_add_from_file(struct screen_t *s, char *fn); + +bool screen_widget_destroy(struct screen_t *s, struct widget_t **w); + +uint16_t screen_get_num_widgets(struct screen_t *s); + +#endif //__SCREEN_H diff --git a/include/widget.h b/include/widget.h index 9352e01..fe7e3f7 100644 --- a/include/widget.h +++ b/include/widget.h @@ -1,6 +1,8 @@ #ifndef __WIDGET_H #define __WIDGET_H +#include "common/queue.h" + struct widget_t; #define EV_WIDGET_NONE 0 @@ -25,9 +27,20 @@ struct widget_t { mgos_timer_id _timer_id; }; +struct widget_list_t { + struct widget_t *widget; + SLIST_ENTRY(widget_list_t) entries; +}; + struct widget_t *widget_add(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data); struct widget_t *widget_add_from_file(const char *fn, uint32_t timer_msec, widget_event_fn handler, void *user_data); struct widget_t *widget_find(uint16_t x, uint16_t y); void widget_remove(struct widget_t *widget); +struct widget_t *widget_create(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data); +struct widget_t *widget_create_from_file(const char *fn); +struct widget_t *widget_create_from_json(const char *json); +void widget_destroy(struct widget_t **widget); + + #endif // __WIDGET_H diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..593718a --- /dev/null +++ b/src/screen.c @@ -0,0 +1,121 @@ +#include "screen.h" + +struct screen_t *screen_create(char *name, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + struct screen_t *screen = NULL; + + screen = (struct screen_t *) calloc(1, sizeof(*screen)); + if (!screen) + return NULL; + screen->x=x; + screen->y=y; + screen->w=w; + screen->h=h; + if (name) + screen->name=strdup(name); + SLIST_INIT(&screen->widget_entries); + + return screen; +} + +struct screen_t *screen_create_from_file(char *fn) { + char *json; + void *h = NULL; +// struct json_token key; + struct json_token val; + int idx; + struct screen_t *screen = NULL; + struct widget_t *widget = NULL; + int screen_x, screen_y, screen_w, screen_h; + char *screen_name = NULL; + + + json = json_fread(fn); + if (!json) { + LOG(LL_ERROR, ("Could not read file %s", fn)); + goto exit; + } + + if (json_scanf(json, strlen(json), "{x:%d,y:%d,w:%d,h:%d,name:%Q}", &screen_x, &screen_y, &screen_w, &screen_h, &screen_name) != 5) { + LOG(LL_ERROR, ("%s: Incomplete JSON: require 'x', 'y', 'w', 'h' and 'name' fields", fn)); + screen=NULL; goto exit; + } + screen = screen_create(screen_name, screen_x, screen_y, screen_w, screen_h); + +/* + // Traverse Object + while ((h = json_next_key(json, strlen(json), h, ".", &key, &val)) != NULL) { + printf("[%.*s] -> [%.*s]\n", key.len, key.ptr, val.len, val.ptr); + } + +*/ + + // Traverse Array + while ((h = json_next_elem(json, strlen(json), h, ".widgets", &idx, &val)) != NULL) { +// printf("[%d]: [%.*s]\n", idx, val.len, val.ptr); + if (val.len>0 && val.ptr) { + widget = widget_create_from_json(val.ptr); + if (!screen_widget_add(screen, widget)) { + LOG(LL_ERROR, ("Could not add widget to screen")); + } + } + } + +exit: + if (json) free(json); + if (screen_name) free(screen_name); + return screen; +} + +void screen_destroy(struct screen_t **s) { + free(*s); + if ((*s)->name) free ((*s)->name); + *s = NULL; +} + +bool screen_widget_add(struct screen_t *s, struct widget_t *w) { + struct widget_list_t *wl; + + wl = (struct widget_list_t *) calloc(1, sizeof(*wl)); + if (!wl) { + return false; + } + wl->widget = w; + SLIST_INSERT_HEAD(&s->widget_entries, wl, entries); + return true; +} + +struct widget_t *screen_widget_add_from_file(struct screen_t *s, char *fn) { + struct widget_t *w; + + w = widget_create_from_file(fn); + if (!w) + return NULL; + screen_widget_add(s, w); + return w; +} + +bool screen_widget_destroy(struct screen_t *s, struct widget_t **w) { + struct widget_list_t *wl; + + if (!s) + return false; + SLIST_FOREACH(wl, &s->widget_entries, entries) { + if (wl->widget == *w) { + SLIST_REMOVE(&s->widget_entries, wl, widget_list_t, entries); + widget_destroy(w); + } + } + return true; +} + +uint16_t screen_get_num_widgets(struct screen_t *s) { + struct widget_list_t *wl; + uint16_t num = 0; + + if (!s) + return 0; + SLIST_FOREACH(wl, &s->widget_entries, entries) + num++; + + return num; +} diff --git a/src/widget.c b/src/widget.c index 28d93b8..7dd0569 100644 --- a/src/widget.c +++ b/src/widget.c @@ -3,11 +3,6 @@ #include "frozen/frozen.h" #include "common/queue.h" -struct widget_list_t { - struct widget_t *widget; - SLIST_ENTRY(widget_list_t) entries; -}; - SLIST_HEAD(widget_list, widget_list_t) s_widgets; static void widget_event_timer(void *arg) { @@ -18,46 +13,38 @@ static void widget_event_timer(void *arg) { widget->handler(EV_WIDGET_TIMER, widget, NULL); } -static void widget_destroy(struct widget_t *widget) { - if (!widget) +void widget_destroy(struct widget_t **widget) { + if (!*widget) return; - if (widget->handler) - widget->handler(EV_WIDGET_DESTROY, widget, NULL); + if ((*widget)->handler) + (*widget)->handler(EV_WIDGET_DESTROY, *widget, NULL); - if (widget->timer_msec) - mgos_clear_timer(widget->_timer_id); - if (widget->user_data) - free(widget->user_data); - free(widget); + if ((*widget)->timer_msec) + mgos_clear_timer((*widget)->_timer_id); + if ((*widget)->user_data) + free((*widget)->user_data); + free(*widget); + *widget=NULL; } struct widget_t *widget_add(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data) { struct widget_t *widget; struct widget_list_t *wl; - widget = (struct widget_t *) calloc(1, sizeof(*widget)); - if (!widget) - return NULL; - widget->x=x; - widget->y=y; - widget->w=w; - widget->h=h; - widget->timer_msec=timer_msec; - widget->handler=handler; - widget->user_data=user_data; - if (timer_msec > 0) - widget->_timer_id = mgos_set_timer(timer_msec, MGOS_TIMER_REPEAT, widget_event_timer, widget); - wl = (struct widget_list_t *) calloc(1, sizeof(*wl)); if (!wl) { - widget_destroy(widget); return NULL; } + + widget = widget_create(x, y, w, h, timer_msec, handler, user_data); + if (!widget) { + free(wl); + return NULL; + } + wl->widget = widget; SLIST_INSERT_HEAD(&s_widgets, wl, entries); - if (handler) - handler(EV_WIDGET_CREATE, widget, NULL); return widget; } @@ -82,7 +69,7 @@ void widget_remove(struct widget_t *widget) { SLIST_FOREACH(wl, &s_widgets, entries) { if (wl->widget == widget) { SLIST_REMOVE(&s_widgets, wl, widget_list_t, entries); - widget_destroy(widget); + widget_destroy(&widget); } } } @@ -119,3 +106,55 @@ exit: (void) handler; (void) user_data; } + +struct widget_t *widget_create(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data) { + struct widget_t *widget; + + widget = (struct widget_t *) calloc(1, sizeof(*widget)); + if (!widget) + return NULL; + widget->x=x; + widget->y=y; + widget->w=w; + widget->h=h; + widget->timer_msec=timer_msec; + widget->handler=handler; + widget->user_data=user_data; + if (timer_msec > 0) + widget->_timer_id = mgos_set_timer(timer_msec, MGOS_TIMER_REPEAT, widget_event_timer, widget); + + if (handler) + handler(EV_WIDGET_CREATE, widget, NULL); + + return widget; +} + +struct widget_t *widget_create_from_json(const char *json) { + struct widget_t *widget=NULL; + int x, y, w, h; + int type = 0; + char *label = NULL; + char *icon = NULL; + + if (json_scanf(json, strlen(json), "{x:%d,y:%d,w:%d,h:%d}", &x, &y, &w, &h) != 4) { + LOG(LL_ERROR, ("Incomplete JSON: require 'x', 'y', 'w', 'h' fields")); + return NULL; + } + json_scanf(json, strlen(json), "{type:%d,label:%Q,icon:%Q}", &type, &label, &icon); + widget = widget_create(x, y, w, h, 0, NULL, NULL); + return widget; +} + +struct widget_t *widget_create_from_file(const char *fn) { + char *json; + struct widget_t *widget=NULL; + + if (!(json = json_fread(fn))) { + LOG(LL_ERROR, ("%s: Could not json_fread()", fn)); + return NULL; + } + + widget = widget_create_from_json(json); + free(json); + return widget; +} diff --git a/unittest/Makefile b/unittest/Makefile index f05a356..dba770d 100644 --- a/unittest/Makefile +++ b/unittest/Makefile @@ -9,7 +9,7 @@ default: $(TARGET) all: default OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) -SRCS = frozen/frozen.c ../src/widget.c +SRCS = frozen/frozen.c ../src/widget.c ../src/screen.c HEADERS = $(wildcard *.h) %.o: %.c $(HEADERS) diff --git a/unittest/data/TestScreen.json b/unittest/data/TestScreen.json index ce00bf2..c6cbbc6 100644 --- a/unittest/data/TestScreen.json +++ b/unittest/data/TestScreen.json @@ -1,5 +1,10 @@ { "name": "TestScreen", + "x": 0, + "y": 0, + "w": 320, + "h": 240, + "widgets": [ { "x": 16, diff --git a/unittest/main.c b/unittest/main.c index 642fcd3..2b5dbce 100644 --- a/unittest/main.c +++ b/unittest/main.c @@ -1,8 +1,16 @@ #include "test.h" +int test_failures=0; +int assert_count=0; + int main() { - LOG(LL_INFO, ("test_widget")); test_widget(); test_screen(); + + if (test_failures) { + LOG(LL_ERROR, ("%d test failures", test_failures)); + return -1; + } + LOG(LL_INFO, ("All tests passed, %d assertions OK", assert_count)); return 0; } diff --git a/unittest/mgos_mock.c b/unittest/mgos_mock.c index 692da96..fa0c812 100644 --- a/unittest/mgos_mock.c +++ b/unittest/mgos_mock.c @@ -25,7 +25,7 @@ int log_print_prefix(enum cs_log_level l, const char *func, const char *file) { default: // LL_NONE return 0; } - printf ("%-5s %-10s %-15s| ", ll_str, file, func); + printf ("%-5s %-15s %-15s| ", ll_str, file, func); return 1; } diff --git a/unittest/test.h b/unittest/test.h index 6e7fc7a..3f211b2 100644 --- a/unittest/test.h +++ b/unittest/test.h @@ -6,6 +6,20 @@ #include "frozen/frozen.h" #include "mgos_mock.h" +extern int test_failures; +extern int assert_count; + +#define ASSERT(expr, errstr) \ + do { \ + if (!(expr)) { \ + LOG(LL_ERROR, ("ASSERT FAIL: "errstr)); \ + test_failures++; \ + } \ + assert_count++; \ + } while (0) + + + int test_widget(void); int test_screen(void); diff --git a/unittest/test_screen.c b/unittest/test_screen.c index 2129e6c..b33489f 100644 --- a/unittest/test_screen.c +++ b/unittest/test_screen.c @@ -1,5 +1,78 @@ #include "test.h" +#include "screen.h" +#include "widget.h" + + +static void test_widget_add_and_remove(struct screen_t *s, const char *fn) { + struct widget_t *w1; + int num_widgets_before, num_widgets; + bool ret; + + w1 = widget_create_from_file(fn); + ASSERT(w1, "widget_create_from_file() failed"); + + num_widgets_before = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets_before)); + + ret = screen_widget_add(s, w1); + ASSERT(true == ret, "screen_widget_add() failed for widget1"); + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == num_widgets_before+1, "Did not see widget in screen"); + + ret = screen_widget_destroy(s, &w1); + ASSERT(true == ret, "screen_widget_destroy() failed for widget1"); + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == num_widgets_before, "Too many widgets in screen"); + + return; + + (void) s; + (void) fn; +} + int test_screen() { + struct screen_t *s = NULL; + struct widget_t *w = NULL; + uint16_t num_widgets; + + LOG(LL_INFO, ("screen_create_from_file(data/TestScreen.json)")); + s = screen_create_from_file("data/TestScreen.json"); + ASSERT(s, "Could not create screen"); + + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == 2, "Expecting 2 widgets in screen"); + + LOG(LL_INFO, ("test_widget_add_and_remove(data/TestWidget.json)")); + test_widget_add_and_remove(s, "data/TestWidget.json"); + + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == 2, "Expecting 2 widgets in screen"); + + LOG(LL_INFO, ("test_widget_add_from_file(data/TestWidget.json)")); + w = screen_widget_add_from_file(s, "data/TestWidget.json"); + ASSERT(w, "screen_widget_add_from_file() failed for data/TestWidget.json"); + + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == 3, "Expecting 3 widgets in screen"); + + LOG(LL_INFO, ("screen_widget_destroy()")); + screen_widget_destroy(s, &w); + ASSERT(!w, "screen_widget_destroy() failed for data/TestWidget.json"); + + num_widgets = screen_get_num_widgets(s); + LOG(LL_INFO, ("Screen has %d widget(s)", num_widgets)); + ASSERT(num_widgets == 2, "Expecting 2 widgets in screen"); + + + LOG(LL_INFO, ("screen_destroy()")); + screen_destroy(&s); + ASSERT(!s, "Could not destroy screen"); + return 0; } diff --git a/unittest/test_widget.c b/unittest/test_widget.c index 3e344da..368bbc7 100644 --- a/unittest/test_widget.c +++ b/unittest/test_widget.c @@ -28,24 +28,21 @@ exit: return 0; */ -static int test_widget_add_from_file(void) { +static int test_widget_create_from_file(char *fn) { struct widget_t *w; - const char *fn = "data/TestWidget.json"; - w = widget_add_from_file(fn, 0, NULL, NULL); - if (!w) { - LOG(LL_ERROR, ("Could not add %s", fn)); - return -1; - } - if (16 != w->x || 48 != w->w || 16 != w->y || 48 != w->h) { - LOG(LL_ERROR, ("widget x, y, w, h incorrect")); - return -1; - } + LOG(LL_INFO, ("Adding widget from %s", fn)); + w = widget_create_from_file(fn); + ASSERT(w, "widget_create_from_file()"); + ASSERT(w->x == 16, "'x' field is invalid"); + ASSERT(w->y == 16, "'x' field is invalid"); + ASSERT(w->w == 48, "'x' field is invalid"); + ASSERT(w->h == 48, "'x' field is invalid"); return 0; } int test_widget() { - test_widget_add_from_file(); + test_widget_create_from_file("data/TestWidget.json"); return 0; }