From 97301e41a24110ba65190befb95202be08e41176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Sage?= Date: Mon, 27 Jun 2016 01:05:00 +0200 Subject: [PATCH 1/5] Use a dictionary to save memory --- enamel.py | 12 ++ templates/enamel.c.jinja | 408 +++++++++++---------------------------- 2 files changed, 127 insertions(+), 293 deletions(-) diff --git a/enamel.py b/enamel.py index 1069e85..8bf6c3e 100644 --- a/enamel.py +++ b/enamel.py @@ -104,6 +104,17 @@ def maxdictsize(item): size = max(size, len(str(option['value'])) + 1) return size +def getFirstMessageKey(settings): + count = 0 + for setting in settings : + if setting['type'] == 'section': + messageKey = getFirstMessageKey(setting['items']) + if messageKey != '' : + return messageKey + elif 'messageKey' in setting : + return getmessagekey(setting) + return '' + def removeComments(string): """From http://stackoverflow.com/questions/2319019/using-regex-to-remove-comments-from-source-files""" string = re.sub(re.compile("/\*.*?\*/",re.DOTALL ) ,"" ,string) # remove all occurance streamed comments (/*COMMENT */) from string @@ -129,6 +140,7 @@ def generate(configFile='src/js/config.json', outputDir='src/generated'): env.filters['settingscount'] = settingscount env.filters['getOptionArray'] = getOptionArray env.filters['hasStringOptions'] = hasStringOptions + env.filters['getFirstMessageKey'] = getFirstMessageKey # load config file config_content=open(configFile) diff --git a/templates/enamel.c.jinja b/templates/enamel.c.jinja index 8420641..b2d8c5f 100644 --- a/templates/enamel.c.jinja +++ b/templates/enamel.c.jinja @@ -7,15 +7,19 @@ #include "enamel.h" #ifndef ENAMEL_MAX_STRING_LENGTH -#define ENAMEL_MAX_STRING_LENGTH 30 +#define ENAMEL_MAX_STRING_LENGTH 100 #endif -#define ENAMEL_PKEY 100000000 -#define ENAMEL_VALUE_PKEY ENAMEL_PKEY + 10 +#define ENAMEL_PKEY 3000000000 +#define ENAMEL_DICT_PKEY (ENAMEL_PKEY+1) static EventHandle s_event_handle; static EnamelSettingsReceivedCallback *s_settings_received_callback; +static DictionaryIterator s_dict; +static uint8_t* s_dict_buffer = NULL; +static uint32_t s_dict_size = 0; + static bool s_config_changed; {% macro item_accessors_code(item) %} @@ -26,77 +30,55 @@ static bool s_config_changed; // ----------------------------------------------------- // Getter for '{{ item|getid }}' {% if item['type'] == 'toggle' %} -static bool s_{{ item|getid|cvarname }}; bool enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}; -} -static void prv_set_{{ item|getid|cvarname }}(bool value){ - s_{{ item|getid|cvarname }} = value; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + return tuple ? tuple->value->int32 == 1 : {{item['defaultValue']|lower}}; } {% elif item['type'] == 'select' or item['type'] == 'radiogroup' %} {% if item|hasStringOptions %} -static uint16_t s_{{ item|getid|cvarname }}; -static const char* s_{{ item|getid|cvarname }}_values[{{ item|getOptionArray|length }}] = { -{%- for option in item|getOptionArray -%} - "{{ option['value'] }}", -{%- endfor -%} -}; const char* enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}_values[s_{{ item|getid|cvarname }}]; -} -static void prv_set_{{ item|getid|cvarname }}(char* value){ - for(uint16_t i=0; i<{{ item|getOptionArray|length }}; i++){ - if(strcmp(value, s_{{ item|getid|cvarname }}_values[i]) == 0){ - s_{{ item|getid|cvarname }} = i; - return; - } - } - s_{{ item|getid|cvarname }} = 0; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + return tuple ? tuple->value->cstring : "{{item['defaultValue']}}"; } {% else %} -{{ item|getid|cvarname|upper }}Value s_{{ item|getid|cvarname }}; {{ item|getid|cvarname|upper }}Value enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}; -} -static void prv_set_{{ item|getid|cvarname }}({{ item|getid|cvarname|upper }}Value value){ - s_{{ item|getid|cvarname }} = value; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + return tuple ? atoi(tuple->value->cstring) : {{item['defaultValue']}}; } {% endif %} {% elif item['type'] == 'input' %} -static char* s_{{ item|getid|cvarname }} = NULL; const char* enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}; -} -static void prv_set_{{ item|getid|cvarname }}(char* value){ - if(s_{{ item|getid|cvarname }}) free( s_{{ item|getid|cvarname }}); - uint32_t size = strlen(value); - s_{{ item|getid|cvarname }} = malloc(size + 1); - s_{{ item|getid|cvarname }}[size] = 0; - strncpy(s_{{ item|getid|cvarname }}, value, size); + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + return tuple ? tuple->value->cstring : "{{item['defaultValue']}}"; } {% elif item['type'] == 'color' %} -static GColor s_{{ item|getid|cvarname }}; GColor enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}; -} -static void prv_set_{{ item|getid|cvarname }}(uint8_t value){ - s_{{ item|getid|cvarname }}.argb = value; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + {% if item['defaultValue'] is string %} + return tuple ? GColorFromHEX(tuple->value->int32) : GColorFromHEX(0x{{item['defaultValue']}}); + {% else %} + return tuple ? GColorFromHEX(tuple->value->int32) : GColorFromHEX({{item['defaultValue']}}); + {% endif %} } {% elif item['type'] == 'slider' %} -static int32_t s_{{ item|getid|cvarname }}; int32_t enamel_get_{{ item|getid|cvarname }}(){ - return s_{{ item|getid|cvarname }}; -} -static void prv_set_{{ item|getid|cvarname }}(int32_t value){ - s_{{ item|getid|cvarname }} = value; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }}); + return tuple ? tuple->value->int32 : {{ (item['defaultValue'] * 10**((item['step'] - item['step']|round(0, 'floor'))|string|length - 2))|int }}; } {% elif item['type'] == 'checkboxgroup' %} -static bool s_{{ item|getid|cvarname }}[{{item['options']|length}}]; bool enamel_get_{{ item|getid|cvarname }}({{ item|getid|cvarname|upper }}Value index_){ - return s_{{ item|getid|cvarname }}[index_]; -} -static void prv_set_{{ item|getid|cvarname }}({{ item|getid|cvarname|upper }}Value index_, bool data_){ - s_{{ item|getid|cvarname }}[index_] = data_; + Tuple* tuple = dict_find(&s_dict, {{ item|hashkey }} + index_); + if(tuple){ + return tuple->value->int32 == 1; + } + else { + switch(index_){ + {% for option in item['options'] %} + case {{ loop.index0 }} : return {{ item['defaultValue'][loop.index0]|lower }}; break; + {% endfor %} + default : return false; + } + } } {% endif %} // ----------------------------------------------------- @@ -123,172 +105,115 @@ static void prv_set_{{ item|getid|cvarname }}({{ item|getid|cvarname|upper }}Val {%- endif %} {% endfor %} -{% macro item_in_received_handler(item) %} -{% if 'messageKey' in item and 'enamel-ignore' not in item %} -{% if 'capabilities' in item %} -#if {{ item['capabilities']|getdefines }} -{% endif %} - {% if item['type'] == 'checkboxgroup' %} - {% for option in item['options'] %} - tuple = dict_find(iter, {{ item|getmessagekey }} + {{ loop.index0 }}); - tuple ? prv_set_{{ item|getid|cvarname }}({{ item|getid|cvarname|upper }}_{{ option|cvarname|upper }}, tuple->value->int32 == 1) : false; - {% endfor %} - {% else %} - tuple = dict_find(iter, {{ item|getmessagekey }}); - {% if item['type'] == 'input' %} - tuple ? prv_set_{{ item|getid|cvarname }}(tuple->value->cstring) : false; - {% elif item['type'] == 'select' or item['type'] == 'radiogroup' %} - {% if item|hasStringOptions %} - tuple ? prv_set_{{ item|getid|cvarname }}(tuple->value->cstring) : false; - {% else %} - tuple ? prv_set_{{ item|getid|cvarname }}(atoi(tuple->value->cstring)) : false; - {% endif %} - {% elif item['type'] == 'color' %} - tuple ? prv_set_{{ item|getid|cvarname }}(GColorFromHEX(tuple->value->int32).argb) : false; - {% elif item['type'] == 'toggle' %} - tuple ? prv_set_{{ item|getid|cvarname }}(tuple->value->int32) : false; - {% elif item['type'] == 'slider' %} - tuple ? prv_set_{{ item|getid|cvarname }}(tuple->value->int32) : false; - {% endif %} - {% endif %} -{% if 'capabilities' in item %} -#endif -{% endif %} -{% endif %} -{% endmacro -%} - -{% macro item_init(item) %} -{% if 'messageKey' in item and 'enamel-ignore' not in item %} -{% if 'capabilities' in item %} -#if {{ item['capabilities']|getdefines }} -{% endif %} - pkey = prv_get_pkey(hashes, key_size, {{item|hashkey}}); - if (pkey && persist_exists(pkey)) { - {% if item['type'] == 'input' %} - char tmp[ENAMEL_MAX_STRING_LENGTH]; - persist_read_string(pkey, tmp, ENAMEL_MAX_STRING_LENGTH); - tmp[ENAMEL_MAX_STRING_LENGTH-1]=0; - prv_set_{{ item|getid|cvarname }}(tmp); - {% elif item['type'] == 'select' or item['type'] == 'radiogroup' %} - {% if item|hasStringOptions %} - s_{{ item|getid|cvarname }} = (uint16_t)persist_read_int(pkey); - {% else %} - prv_set_{{ item|getid|cvarname }}(persist_read_int(pkey)); - {% endif %} - {% elif item['type'] == 'color' %} - prv_set_{{ item|getid|cvarname }}(persist_read_int(pkey)); - {% elif item['type'] == 'slider' %} - prv_set_{{ item|getid|cvarname }}(persist_read_int(pkey)); - {% elif item['type'] == 'toggle' %} - prv_set_{{ item|getid|cvarname }}(persist_read_bool(pkey)); - {% elif item['type'] == 'checkboxgroup' %} - persist_read_data(pkey, s_{{ item|getid|cvarname }}, {{ item['options']|length }}); - {% endif %} - } - {% if 'defaultValue' in item %} - else { - {% if item['type'] == 'input' %} - prv_set_{{ item|getid|cvarname }}("{{item['defaultValue']}}"); - {% elif item['type'] == 'select' or item['type'] == 'radiogroup' %} - {% if item|hasStringOptions %} - prv_set_{{ item|getid|cvarname }}("{{item['defaultValue']}}"); - {% else %} - prv_set_{{ item|getid|cvarname }}({{item['defaultValue']}}); - {% endif %} - {% elif item['type'] == 'color' %} - {% if item['defaultValue'] is string %} - prv_set_{{ item|getid|cvarname }}(GColorFromHEX(0x{{item['defaultValue']}}).argb); - {% else %} - prv_set_{{ item|getid|cvarname }}(GColorFromHEX({{item['defaultValue']}}).argb); - {% endif %} - {% elif item['type'] == 'slider' %} - {% if 'step' in item and '.' in item['step']|string %} - prv_set_{{ item|getid|cvarname }}({{ (item['defaultValue'] * 10**((item['step'] - item['step']|round(0, 'floor'))|string|length - 2))|int }}); - {% else %} - prv_set_{{ item|getid|cvarname }}({{item['defaultValue']|lower}}); - {% endif %} - {% elif item['type'] == 'toggle' %} - prv_set_{{ item|getid|cvarname }}({{item['defaultValue']|lower}}); - {% elif item['type'] == 'checkboxgroup' %} - {% for val in item['defaultValue'] %} - prv_set_{{ item|getid|cvarname }}({{ loop.index0 }}, {{ val|lower }}); - {% endfor %} - {% endif %} - } - {% endif %} -{% if 'capabilities' in item %} -#endif -{% endif %} -{% endif %} -{% endmacro -%} - {% macro item_dict_size(item) %} {% if 'messageKey' in item and 'enamel-ignore' not in item %} {% if item['type'] == 'input' %} -+ 7 + ENAMEL_MAX_STRING_LENGTH + + 7 + ENAMEL_MAX_STRING_LENGTH {% elif item['type'] == 'select' or item['type'] == 'radiogroup' %} -+ 7 + {{ item|maxdictsize }} + + 7 + {{ item|maxdictsize }} {% elif item['type'] == 'checkboxgroup' %} -+ 7 + {{ item['options']|length }} + + ( 7 + 4 ) * {{ item['options']|length }} {% elif item['type'] == 'color' or item['type'] == 'toggle' or item['type'] == 'slider' %} -+ 7 + 4 + + 7 + 4 {% endif %} {% endif %} {% endmacro -%} static uint16_t prv_get_inbound_size() { return 1 - {% for item in config %} - {% if item['type'] == 'section' %} +{% for item in config %} +{% if item['type'] == 'section' %} {%- if 'capabilities' in item %} #if {{ item['capabilities']|getdefines }} {% endif -%} - {% for item in item['items'] %} +{% for item in item['items'] %} {%- if 'capabilities' in item %} #if {{ item['capabilities']|getdefines }} {% endif -%} - {{ item_dict_size(item) }} +{{ item_dict_size(item) }} {%- if 'capabilities' in item %} #endif {% endif -%} - {%- endfor %} +{%- endfor %} {%- if 'capabilities' in item %} #endif {% endif -%} - {% else %} +{% else %} {%- if 'capabilities' in item %} #if {{ item['capabilities']|getdefines }} {% endif -%} - {{ item_dict_size(item) }} +{{ item_dict_size(item) }} {%- if 'capabilities' in item %} #endif {% endif -%} - {%- endif %} - {% endfor %}; +{%- endif %} +{% endfor %}; } -static void inbox_received_handle(DictionaryIterator *iter, void *context) { - Tuple *tuple = NULL; +{% macro map_messagekey(item) %} +{% if 'messageKey' in item and 'enamel-ignore' not in item %} +{%- if 'capabilities' in item %} +#if {{ item['capabilities']|getdefines }} +{% endif -%} +{% if item['type'] == 'checkboxgroup' %} +{% for option in item['options'] %} + if( key == {{ item|getmessagekey }} + {{ loop.index0 }}) return {{ item|hashkey + loop.index0 }}; +{% endfor %} +{% else %} + if( key == {{ item|getmessagekey }}) return {{ item|hashkey }}; +{% endif %} +{% endif -%} +{%- if 'capabilities' in item %} +#endif +{% endif -%} +{% endmacro -%} + +static uint32_t prv_map_messagekey(const uint32_t key){ {% for item in config %} {% if item['type'] == 'section' %} -{% if 'capabilities' in item %} +{%- if 'capabilities' in item %} #if {{ item['capabilities']|getdefines }} -{% endif %} +{% endif -%} {% for item in item['items'] %} -{{ item_in_received_handler(item) }} +{{ map_messagekey(item) }} {%- endfor %} {%- if 'capabilities' in item %} #endif {% endif -%} {% else %} -{{ item_in_received_handler(item) }} +{{ map_messagekey(item) }} {%- endif %} {% endfor %} - if(tuple) { - s_config_changed = true; + return 0; +} + +static void prv_key_update_cb(const uint32_t key, const Tuple *new_tuple, const Tuple *old_tuple, void *context){ +} + +static void prv_inbox_received_handle(DictionaryIterator *iter, void *context) { + if(dict_find(iter, {{ config|getFirstMessageKey}})){ + if(s_dict_buffer){ + free(s_dict_buffer); + s_dict_buffer = NULL; + } + s_dict_size = dict_size(iter); + s_dict_buffer = malloc(s_dict_size); + + Tuple *tuple=dict_read_first(iter); + while(tuple){ + tuple->key = prv_map_messagekey(tuple->key); + tuple=dict_read_next(iter); + } + + dict_write_begin(&s_dict, s_dict_buffer, s_dict_size); + dict_write_end(&s_dict); + dict_merge(&s_dict, &s_dict_size, iter, false, prv_key_update_cb, NULL); + if(s_settings_received_callback){ s_settings_received_callback(); } + + s_config_changed = true; } } @@ -326,139 +251,36 @@ static uint16_t prv_load_generic_data(uint32_t startkey, void *data, uint16_t si return total_r_bytes; } -static uint32_t prv_get_pkey(uint32_t *hashes_, uint16_t size_, uint32_t hash_){ - for(uint16_t i=0; i Date: Sun, 26 Jun 2016 00:34:30 +0200 Subject: [PATCH 2/5] Make tests --- .gitignore | 5 + .travis.yml | 6 + Makefile | 24 ++ tests/config.json | 146 ++++++++++ tests/constants.h | 3 + tests/enamel.c | 141 ++++++++++ tests/include/pebble-events/pebble-events.h | 71 +++++ tests/message_keys.auto.h | 9 + tests/pebble-events_stub.c | 8 + tests/pebble_stub.c | 280 ++++++++++++++++++++ tests/src/resource_ids.auto.h | 0 tests/travis-install.sh | 23 ++ tests/unit.h | 19 ++ 13 files changed, 735 insertions(+) create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 tests/config.json create mode 100644 tests/constants.h create mode 100644 tests/enamel.c create mode 100644 tests/include/pebble-events/pebble-events.h create mode 100644 tests/message_keys.auto.h create mode 100644 tests/pebble-events_stub.c create mode 100644 tests/pebble_stub.c create mode 100644 tests/src/resource_ids.auto.h create mode 100755 tests/travis-install.sh create mode 100644 tests/unit.h diff --git a/.gitignore b/.gitignore index 45d4d16..446e715 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ dist.zip node_modules/ *.pyc + +tests/include/pebble +tests/include/linked-list +tests/generated/ +tests/linked-list.c diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b052c51 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +sudo: false +language: c +install: + - pip install --user -r requirements.txt + - ./tests/travis-install.sh +script: make test \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eaf450c --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +PEBBLE_HEADERS=tests/include/pebble/ + +CC=gcc +ifeq ($(TRAVIS), true) +CC_TEST=$(CC) +CFLAGS=-std=c99 +AR=ar +else +CC_TEST=arm-none-eabi-gcc +CFLAGS=-std=c11 +AR=arm-none-eabi-ar +endif +CINCLUDES=-I $(PEBBLE_HEADERS) -I tests/ -I tests/generated/ -I tests/include/ -I tests/include/linked-list + +TEST_FILES=tests/enamel.c +SRC_FILES=tests/generated/enamel.c tests/linked-list.c +TEST_EXTRAS=tests/pebble_stub.c tests/pebble-events_stub.c + +all: test + +test: + @$(CC) $(CFLAGS) $(CINCLUDES) $(TEST_FILES) $(SRC_FILES) $(TEST_EXTRAS) -o tests/run + @tests/run + @rm tests/run \ No newline at end of file diff --git a/tests/config.json b/tests/config.json new file mode 100644 index 0000000..4bb10af --- /dev/null +++ b/tests/config.json @@ -0,0 +1,146 @@ +[ +{ + "type": "heading", + "defaultValue": "Enamel Demo" +}, +{ + "type": "section", + "items": [ + { "type": "heading", "defaultValue": "Section 1" }, + { + "type": "toggle", + "id": "enable_background", + "messageKey": "enable_background", + "label": "Enable Background", + "defaultValue" : true + }, + { + "type": "color", + "id": "background", + "messageKey": "background", + "defaultValue": "FF0000", + "label": "Background Color", + "sunlight": true + }, + { + "type": "select", + "id": "font_size", + "messageKey": "font_size", + "defaultValue": "1", + "label": "Text Size", + "options": [ + { + "label": "Small", + "value": 0 + }, + { + "label": "Normal", + "value": 1 + }, + { + "label": "Large", + "value": 2 + } + ] + }, + { + "type": "checkboxgroup", + "messageKey": "favoritefood", + "label": "Favorite Food", + "defaultValue": [true, false, true], + "options": ["Sushi", "Pizza", "Burgers"] + }, + { + "type": "radiogroup", + "messageKey": "favorite_drink", + "label": "Favorite Drink", + "defaultValue": "coca", + "options": [ + { + "label": "Water", + "value": "water" + }, + { + "label": "Coca", + "value": "coca" + }, + { + "label": "Wine", + "value": "wine" + } + ] + }, + { + "type": "select", + "messageKey": "flavor", + "defaultValue": "grape", + "label": "Favorite Flavor", + "options": [ + { + "label": "", + "value": "" + }, + { + "label": "Fruits", + "value": [ + { + "label": "Berry", + "value": "berry" + }, + { + "label": "Grape", + "value": "grape" + }, + { + "label": "Banana", + "value": "banana" + } + ] + }, + { + "label": "Candy", + "value": [ + { + "label": "Chocolate", + "value": "chocolate" + }, + { + "label": "Cream", + "value": "cream" + }, + { + "label": "Lollipop", + "value": "lollipop" + } + ] + } + ] + }, + { + "type": "slider", + "messageKey": "slider", + "defaultValue": 15, + "label": "Slider", + "description": "This is the description for the slider", + "min": 0, + "max": 100, + "step": 0.25 + } + ] +}, +{ + "type": "section", + "items": [ + { + "type": "heading", + "defaultValue": "Another section" + }, + { + "type": "input", + "messageKey": "email", + "label": "Email Address" + } + ] +}, +{ "type": "submit", "defaultValue": "Done" } +] \ No newline at end of file diff --git a/tests/constants.h b/tests/constants.h new file mode 100644 index 0000000..2330bdd --- /dev/null +++ b/tests/constants.h @@ -0,0 +1,3 @@ +#pragma once + +#define TUPLE_SIZE (sizeof(Tuple) + 100) \ No newline at end of file diff --git a/tests/enamel.c b/tests/enamel.c new file mode 100644 index 0000000..0103639 --- /dev/null +++ b/tests/enamel.c @@ -0,0 +1,141 @@ +#include +#include "unit.h" +#include "enamel.h" +#include +#include "constants.h" + +// Colour code definitions to make the output all pretty. +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +// Keep track of how many tests have run, and how many have passed. +int tests_run = 0; +int tests_passed = 0; + +static AppMessageInboxReceived s_received_callback; + +EventHandle events_app_message_register_inbox_received(AppMessageInboxReceived received_callback, void *context){ + s_received_callback = received_callback; +} + +static void before_each(void) { + enamel_init(); +} + +static void after_each(void) { + enamel_deinit(); +} + +static char* default_values(void) { + printf("default_values\n"); + mu_assert(enamel_get_enable_background(), "enamel_get_enable_background wrong default value"); + mu_assert(GColorFromHEX(0xFF0000).argb == enamel_get_background().argb, "enamel_get_background wrong default value"); + mu_assert(1 == enamel_get_font_size(), "enamel_get_font_size wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_SUSHI), "enamel_get_favoritefood FAVORITEFOOD_SUSHI wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_PIZZA) == false, "enamel_get_favoritefood FAVORITEFOOD_PIZZA wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_BURGERS), "enamel_get_favoritefood FAVORITEFOOD_BURGERS wrong default value"); + mu_assert(strcmp("coca", enamel_get_favorite_drink()) == 0, "enamel_get_favorite_drink wrong default value"); + mu_assert(strcmp("grape", enamel_get_flavor()) == 0, "enamel_get_flavor wrong default value"); + mu_assert(1500 == enamel_get_slider(), "enamel_get_slider wrong default value"); + mu_assert(strcmp("", enamel_get_email()) == 0, "enamel_get_email wrong default value"); + return 0; +} + +static char* save_load_no_change(void) { + printf("save_load_no_change\n"); + enamel_deinit(); + enamel_init(); + mu_assert(enamel_get_enable_background(), "enamel_get_enable_background wrong default value"); + mu_assert(GColorFromHEX(0xFF0000).argb == enamel_get_background().argb, "enamel_get_background wrong default value"); + mu_assert(1 == enamel_get_font_size(), "enamel_get_font_size wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_SUSHI), "enamel_get_favoritefood FAVORITEFOOD_SUSHI wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_PIZZA) == false, "enamel_get_favoritefood FAVORITEFOOD_PIZZA wrong default value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_BURGERS), "enamel_get_favoritefood FAVORITEFOOD_BURGERS wrong default value"); + mu_assert(strcmp("coca", enamel_get_favorite_drink()) == 0, "enamel_get_favorite_drink wrong default value"); + mu_assert(strcmp("grape", enamel_get_flavor()) == 0, "enamel_get_flavor wrong default value"); + mu_assert(1500 == enamel_get_slider(), "enamel_get_slider wrong default value"); + mu_assert(strcmp("", enamel_get_email()) == 0, "enamel_get_email wrong default value"); + return 0; +} + +static char* changes(void) { + printf("changes\n"); + DictionaryIterator iterator; + iterator.dictionary = 0; + + uint8_t dict_buffer[TUPLE_SIZE * 20]; + dict_write_begin(&iterator, dict_buffer, sizeof(dict_buffer)); + dict_write_int32(&iterator, MESSAGE_KEY_enable_background, 0); + dict_write_int32(&iterator, MESSAGE_KEY_background, 0xFFAA00); + dict_write_int32(&iterator, MESSAGE_KEY_favoritefood, false); + dict_write_int32(&iterator, MESSAGE_KEY_favoritefood+1, true); + dict_write_int32(&iterator, MESSAGE_KEY_favoritefood+2, false); + dict_write_cstring(&iterator, MESSAGE_KEY_favorite_drink, "water"); + dict_write_cstring(&iterator, MESSAGE_KEY_flavor, "banana"); + dict_write_int32(&iterator, MESSAGE_KEY_slider, 2000); + dict_write_cstring(&iterator, MESSAGE_KEY_email, "hello you"); + dict_write_end(&iterator); + + s_received_callback(&iterator, NULL); + + mu_assert(enamel_get_enable_background() == false, "enamel_get_enable_background wrong changed value"); + mu_assert(GColorFromHEX(0xFFAA00).argb == enamel_get_background().argb, "enamel_get_background wrong changed value"); + mu_assert(1 == enamel_get_font_size(), "enamel_get_font_size wrong changed value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_SUSHI) == false, "enamel_get_favoritefood FAVORITEFOOD_SUSHI wrong changed value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_PIZZA), "enamel_get_favoritefood FAVORITEFOOD_PIZZA wrong changed value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_BURGERS) == false, "enamel_get_favoritefood FAVORITEFOOD_BURGERS wrong changed value"); + mu_assert(strcmp("water", enamel_get_favorite_drink()) == 0, "enamel_get_favorite_drink wrong changed value"); + mu_assert(strcmp("banana", enamel_get_flavor()) == 0, "enamel_get_flavor wrong changed value"); + mu_assert(2000 == enamel_get_slider(), "enamel_get_slider wrong changed value"); + mu_assert(strcmp("hello you", enamel_get_email()) == 0, "enamel_get_email wrong changed value"); + + return 0; +} + +static char* load_changes(void) { + printf("load_changes\n"); + + mu_assert(enamel_get_enable_background() == false, "enamel_get_enable_background wrong loaded value"); + mu_assert(GColorFromHEX(0xFFAA00).argb == enamel_get_background().argb, "enamel_get_background wrong loaded value"); + mu_assert(1 == enamel_get_font_size(), "enamel_get_font_size wrong loaded value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_SUSHI) == false, "enamel_get_favoritefood FAVORITEFOOD_SUSHI wrong loaded value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_PIZZA), "enamel_get_favoritefood FAVORITEFOOD_PIZZA wrong loaded value"); + mu_assert(enamel_get_favoritefood(FAVORITEFOOD_BURGERS) == false, "enamel_get_favoritefood FAVORITEFOOD_BURGERS wrong loaded value"); + mu_assert(strcmp("water", enamel_get_favorite_drink()) == 0, "enamel_get_favorite_drink wrong loaded value"); + mu_assert(strcmp("banana", enamel_get_flavor()) == 0, "enamel_get_flavor wrong loaded value"); + mu_assert(2000 == enamel_get_slider(), "enamel_get_slider wrong loaded value"); + mu_assert(strcmp("hello you", enamel_get_email()) == 0, "enamel_get_email wrong loaded value"); + + return 0; +} + +static char* all_tests(void) { + mu_run_test(default_values); + mu_run_test(save_load_no_change); + mu_run_test(changes); + mu_run_test(load_changes); + return 0; +} + +// Test application entry point. +// Executes all the tests and prints the results in pretty colours. +int main(int argc, char **argv) { + printf("%s------------------------\n", KCYN); + printf("| Running Enamel Tests |\n"); + printf("------------------------\n%s", KNRM); + char* result = all_tests(); + if (0 != result) { + printf("%s- Failed Test:%s %s\n", KRED, KNRM, result); + } + printf("- Tests Run: %s%d%s\n", (tests_run == tests_passed) ? KGRN : KRED, tests_run, KNRM); + printf("- Tests Passed: %s%d%s\n", (tests_run == tests_passed) ? KGRN : KRED, tests_passed, KNRM); + + printf("%s------------------------%s\n", KCYN, KNRM); + return result != 0; +} \ No newline at end of file diff --git a/tests/include/pebble-events/pebble-events.h b/tests/include/pebble-events/pebble-events.h new file mode 100644 index 0000000..cb52d33 --- /dev/null +++ b/tests/include/pebble-events/pebble-events.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +typedef void* EventHandle; + +// app focus service + +// typedef void(*EventFocusHandler)(bool in_focus, void *context); +// typedef struct EventFocusHandlers { +// EventFocusHandler will_focus; +// EventFocusHandler did_focus; +// } EventFocusHandlers; + +// EventHandle events_app_focus_service_subscribe_handlers(AppFocusHandlers handlers); +// EventHandle events_app_focus_service_subscribe_handlers_context(EventFocusHandlers handlers, void *context); +// EventHandle events_app_focus_service_subscribe(AppFocusHandler handler); +// EventHandle events_app_focus_service_subscribe_context(EventFocusHandler handler, void *context); +// void events_app_focus_service_unsubscribe(EventHandle handle); + +// // battery state service + +// typedef void(*EventBatteryStateHandler)(BatteryChargeState state, void *context); +// EventHandle events_battery_state_service_subscribe(BatteryStateHandler handler); +// EventHandle events_battery_state_service_subscribe_context(EventBatteryStateHandler handler, void *context); +// void events_battery_state_service_unsubscribe(EventHandle handle); + +// // Connection service + +// typedef void(*EventConnectionHandler)(bool connected, void *context); +// typedef struct EventConnectionHandlers { +// EventConnectionHandler pebble_app_connection_handler; +// EventConnectionHandler pebblekit_connection_handler; +// } EventConnectionHandlers; + +// EventHandle events_connection_service_subscribe(ConnectionHandlers conn_handlers); +// EventHandle events_connection_service_subscribe_context(EventConnectionHandlers conn_handlers, void *context); +// void events_connection_service_unsubscribe(EventHandle handle); + +// // Health service + +// EventHandle events_health_service_events_subscribe(HealthEventHandler handler, void *context); +// bool events_health_service_events_unsubscribe(EventHandle handle); + +// // Tick timer service + +// typedef void(*EventTickHandler)(struct tm *tick_time, TimeUnits units_changed, void *context); +// EventHandle events_tick_timer_service_subscribe(TimeUnits units, TickHandler handler); +// EventHandle events_tick_timer_service_subscribe_context(TimeUnits units, EventTickHandler handler, void *context); +// void events_tick_timer_service_unsubscribe(EventHandle handle); + +// Appmessage service + +typedef struct EventAppMessageHandlers { + AppMessageOutboxSent sent; + AppMessageOutboxFailed failed; + AppMessageInboxReceived received; + AppMessageInboxDropped dropped; +} EventAppMessageHandlers; + +void events_app_message_request_inbox_size(uint32_t size); +void events_app_message_request_outbox_size(uint32_t size); +AppMessageResult events_app_message_open(void); +EventHandle events_app_message_subscribe_handlers(EventAppMessageHandlers handlers, void *context); +void events_app_message_unsubscribe(EventHandle handle); + +// For consistency with the official SDK. +EventHandle events_app_message_register_outbox_sent(AppMessageOutboxSent sent_callback, void *context); +EventHandle events_app_message_register_outbox_failed(AppMessageOutboxFailed failed_callback, void *context); +EventHandle events_app_message_register_inbox_received(AppMessageInboxReceived received_callback, void *context); +EventHandle events_app_message_register_inbox_dropped(AppMessageInboxDropped dropped_callback, void *context); diff --git a/tests/message_keys.auto.h b/tests/message_keys.auto.h new file mode 100644 index 0000000..71ca425 --- /dev/null +++ b/tests/message_keys.auto.h @@ -0,0 +1,9 @@ + +#define MESSAGE_KEY_enable_background 0 +#define MESSAGE_KEY_background 1 +#define MESSAGE_KEY_font_size 2 +#define MESSAGE_KEY_favoritefood 3 +#define MESSAGE_KEY_favorite_drink 6 +#define MESSAGE_KEY_flavor 7 +#define MESSAGE_KEY_slider 8 +#define MESSAGE_KEY_email 9 diff --git a/tests/pebble-events_stub.c b/tests/pebble-events_stub.c new file mode 100644 index 0000000..48914ba --- /dev/null +++ b/tests/pebble-events_stub.c @@ -0,0 +1,8 @@ +#include + +void events_app_message_request_inbox_size(uint32_t size){ +} + +void events_app_message_unsubscribe(EventHandle handle){ +} + diff --git a/tests/pebble_stub.c b/tests/pebble_stub.c new file mode 100644 index 0000000..a409231 --- /dev/null +++ b/tests/pebble_stub.c @@ -0,0 +1,280 @@ +#include +#include +#include "constants.h" + +static LinkedRoot* s_persist_root = NULL; + +typedef struct SimpleTuplet { + uint32_t key; + union { + struct { + uint8_t *data; + uint16_t length; + } bytes; + uint32_t integer; + }; +} SimpleTuplet; + +#define SimpleTupletBytes(_key, _data, _length) \ +((const SimpleTuplet) { .key = _key, .bytes = { .data = _data, .length = _length }}) + +#define SimpleTupletInteger(_key, _integer) \ +((const SimpleTuplet) { .key = _key, .integer = _integer }) + +static bool prv_tuplet_compare(void* object1, void* object2){ + SimpleTuplet* t1 = (SimpleTuplet*)object1; + SimpleTuplet* t2 = (SimpleTuplet*)object2; + return t1->key == t2->key; +} + +bool persist_exists(const uint32_t key){ + if(!s_persist_root){ + s_persist_root = linked_list_create_root(); + } + SimpleTuplet t = { .key = key }; + return linked_list_contains_compare(s_persist_root, &t, prv_tuplet_compare); +} + +int32_t persist_read_int(const uint32_t key){ + if(!s_persist_root){ + s_persist_root = linked_list_create_root(); + } + SimpleTuplet t = { .key = key }; + int16_t index = linked_list_find_compare(s_persist_root, &t, prv_tuplet_compare); + if(index != -1){ + SimpleTuplet* res = (SimpleTuplet*)linked_list_get(s_persist_root, index); + return res->integer; + } + return 0; +} + +int persist_read_data(const uint32_t key, void *buffer, const size_t buffer_size){ + if(!s_persist_root){ + s_persist_root = linked_list_create_root(); + } + SimpleTuplet t = { .key = key }; + int16_t index = linked_list_find_compare(s_persist_root, &t, prv_tuplet_compare); + if(index != -1){ + SimpleTuplet* res = (SimpleTuplet*)linked_list_get(s_persist_root, index); + memcpy(buffer, res->bytes.data, buffer_size); + return res->bytes.length; + } + return 0; +} + +status_t persist_write_int(const uint32_t key, const int32_t value){ + if(!s_persist_root){ + s_persist_root = linked_list_create_root(); + } + SimpleTuplet t = SimpleTupletInteger(key, value); + int16_t index = linked_list_find_compare(s_persist_root, &t, prv_tuplet_compare); + if(index != -1){ + SimpleTuplet* res = (SimpleTuplet*)linked_list_get(s_persist_root, index); + res->integer = value; + } + else { + SimpleTuplet* res = malloc(sizeof(SimpleTuplet)); + memcpy(res, &t, sizeof(SimpleTuplet)); + linked_list_append(s_persist_root, res); + } + return 0; +} + +int persist_write_data(const uint32_t key, const void *data, const size_t size){ + if(!s_persist_root){ + s_persist_root = linked_list_create_root(); + } + SimpleTuplet t = SimpleTupletBytes(key, 0, 0); + int16_t index = linked_list_find_compare(s_persist_root, &t, prv_tuplet_compare); + if(index != -1){ + SimpleTuplet* res = (SimpleTuplet*)linked_list_get(s_persist_root, index); + if(res->bytes.data) + free(res->bytes.data); + res->bytes.data = malloc(size); + res->bytes.length = size; + memcpy(res->bytes.data, data, size); + } + else { + SimpleTuplet* res = malloc(sizeof(SimpleTuplet)); + memcpy(res, &t, sizeof(SimpleTuplet)); + res->bytes.data = malloc(size); + res->bytes.length = size; + memcpy(res->bytes.data, data, size); + linked_list_append(s_persist_root, res); + } + return size; +} + +// struct Dictionary; +typedef struct Dictionary { + LinkedRoot* root; + uint16_t index; + const uint8_t *buffer; + uint16_t size; + uint16_t offset; +} Dictionary; + +static bool prv_tuple_compare(void* object1, void* object2){ + Tuple* t1 = (Tuple*)object1; + Tuple* t2 = (Tuple*)object2; + return t1->key == t2->key; +} + +static void prv_init_dict(DictionaryIterator *iter){ + if(!iter->dictionary){ + iter->dictionary = malloc(sizeof(Dictionary)); + iter->dictionary->root = linked_list_create_root(); + iter->dictionary->index = 0; + } +} + +uint32_t dict_size(DictionaryIterator* iter){ + if(iter){ + prv_init_dict(iter); + } + return TUPLE_SIZE * linked_list_count(iter->dictionary->root); +} + +DictionaryResult dict_write_begin(DictionaryIterator *iter, uint8_t * const buffer, const uint16_t size){ + if(iter){ + prv_init_dict(iter); + } + + linked_list_clear(iter->dictionary->root); + iter->dictionary->index = 0; + iter->dictionary->buffer = buffer; + iter->dictionary->size = size; + iter->dictionary->offset = 0; + + return 0; +} + +uint32_t dict_write_end(DictionaryIterator *iter){ + if(iter){ + prv_init_dict(iter); + return TUPLE_SIZE * linked_list_count(iter->dictionary->root); + } + return 0; +} + +Tuple * dict_read_begin_from_buffer(DictionaryIterator *iter, const uint8_t * const buffer, const uint16_t size){ + if(iter){ + prv_init_dict(iter); + + linked_list_clear(iter->dictionary->root); + iter->dictionary->index = 0; + iter->dictionary->buffer = buffer; + iter->dictionary->size = size; + iter->dictionary->offset = 0; + + uint16_t count = size / TUPLE_SIZE; + for(uint16_t i=0; idictionary->root, t); + } + } + return NULL; +} + +Tuple * dict_read_next(DictionaryIterator *iter){ + if(iter){ + prv_init_dict(iter); + uint16_t count = linked_list_count(iter->dictionary->root); + if(count > 0 && iter->dictionary->index < count){ + return linked_list_get(iter->dictionary->root, iter->dictionary->index++); + } + } + return NULL; +} + +Tuple * dict_read_first(DictionaryIterator *iter){ + if(iter){ + prv_init_dict(iter); + uint16_t count = linked_list_count(iter->dictionary->root); + if(count > 0){ + iter->dictionary->index = 0; + return linked_list_get(iter->dictionary->root, iter->dictionary->index++); + } + } + return NULL; +} + +DictionaryResult dict_merge(DictionaryIterator *dest, uint32_t *dest_max_size_in_out, + DictionaryIterator *source, + const bool update_existing_keys_only, + const DictionaryKeyUpdatedCallback key_callback, void *context){ + uint16_t count = linked_list_count(source->dictionary->root); + for(uint16_t i=0; idictionary->root, i); + int16_t destindex = linked_list_find_compare(dest->dictionary->root, t, prv_tuple_compare); + Tuple* t2=NULL; + if(destindex != -1){ + t2=(Tuple*)linked_list_get(dest->dictionary->root, destindex); + memcpy(t2, t, TUPLE_SIZE); + } + else { + if(dest->dictionary->offset < dest->dictionary->size){ + t2=(Tuple*)(dest->dictionary->buffer + dest->dictionary->offset); + dest->dictionary->offset += TUPLE_SIZE; + memcpy(t2, t, TUPLE_SIZE); + linked_list_append(dest->dictionary->root, t2); + } + } + } + return 0; +} + +Tuple *dict_find(const DictionaryIterator *iter, const uint32_t key){ + if(iter && iter->dictionary && iter->dictionary->root){ + Tuple t; + t.key = key; + int16_t index = linked_list_find_compare(iter->dictionary->root, &t, prv_tuple_compare); + if(index != -1){ + return (Tuple*)linked_list_get(iter->dictionary->root, index); + } + } + return 0; +} + +DictionaryResult dict_write_int32(DictionaryIterator * iter, const uint32_t key, const int32_t value){ + if(iter){ + prv_init_dict(iter); + Tuple t; + t.key = key; + int16_t index = linked_list_find_compare(iter->dictionary->root, &t, prv_tuple_compare); + if(index != -1){ + Tuple* res = (Tuple*)linked_list_get(iter->dictionary->root, index); + res->value->uint32 = value; + } + else if(iter->dictionary->offset < iter->dictionary->size){ + Tuple* res=(Tuple*)(iter->dictionary->buffer + iter->dictionary->offset); + iter->dictionary->offset += TUPLE_SIZE; + res->key = key; + res->value->int32 = value; + linked_list_append(iter->dictionary->root, res); + } + } + return 0; +} + +DictionaryResult dict_write_cstring(DictionaryIterator * iter, const uint32_t key, const char *const cstring){ + if(iter){ + prv_init_dict(iter); + Tuple t; + t.key = key; + int16_t index = linked_list_find_compare(iter->dictionary->root, &t, prv_tuple_compare); + if(index != -1){ + Tuple* res = (Tuple*)linked_list_get(iter->dictionary->root, index); + linked_list_remove(iter->dictionary->root, index); + free(res); + } + else if(iter->dictionary->offset < iter->dictionary->size){ + Tuple* res=(Tuple*)(iter->dictionary->buffer + iter->dictionary->offset); + iter->dictionary->offset += TUPLE_SIZE; + res->key = key; + strcpy(res->value->cstring, cstring); + linked_list_append(iter->dictionary->root, res); + } + } + return 0; +} diff --git a/tests/src/resource_ids.auto.h b/tests/src/resource_ids.auto.h new file mode 100644 index 0000000..e69de29 diff --git a/tests/travis-install.sh b/tests/travis-install.sh new file mode 100755 index 0000000..dd9a713 --- /dev/null +++ b/tests/travis-install.sh @@ -0,0 +1,23 @@ +SDK_VERSION=3.13.1 +SDK_ZIP_NAME=sdk-core-$SDK_VERSION.tar.bz2 + +wget https://s3.amazonaws.com/assets.getpebble.com/sdk3/release/$SDK_ZIP_NAME +tar xjf $SDK_ZIP_NAME +mkdir -p tests/include/pebble +head sdk-core/pebble/basalt/include/pebble.h -n -85 > tests/include/pebble/pebble.h +mv sdk-core/pebble/basalt/include/pebble_fonts.h tests/include/pebble/ +mv sdk-core/pebble/basalt/include/pebble_process_info.h tests/include/pebble/ +mv sdk-core/pebble/basalt/include/pebble_worker.h tests/include/pebble/ +mv sdk-core/pebble/basalt/include/gcolor_definitions.h tests/include/pebble/ +touch tests/include/pebble/pebble_warn_unsupported_functions.h +rm $SDK_ZIP_NAME +rm -r sdk-core + +mkdir -p tests/include/linked-list +wget https://raw.githubusercontent.com/smallstoneapps/linked-list/master/include/linked-list.h +mv linked-list.h tests/include/linked-list/linked-list.h +wget https://raw.githubusercontent.com/smallstoneapps/linked-list/master/src/c/linked-list.c +mv linked-list.c tests/linked-list.c + +mkdir -p tests/generated +python enamel.py --config tests/config.json --folder tests/generated \ No newline at end of file diff --git a/tests/unit.h b/tests/unit.h new file mode 100644 index 0000000..93d4afb --- /dev/null +++ b/tests/unit.h @@ -0,0 +1,19 @@ +#define mu_assert(test, message) do { \ + if (!(test)) { \ + return message; \ + } \ +} while (0) + +#define mu_run_test(test) do { \ + before_each(); \ + char *message = test(); \ + after_each(); \ + tests_run++; \ + if (message) { \ + return message; \ + } \ + tests_passed++; \ +} while (0) + +extern int tests_run; +extern int tests_passed; \ No newline at end of file From 0be5a867adfa6dc8d4f31dc1b7d054bfec0709d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Sage?= Date: Tue, 28 Jun 2016 23:15:09 +0200 Subject: [PATCH 3/5] Add license --- LICENSE | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7551702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2016 Grégoire Sage + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From b2460f9e59e47c03c69c109fba676eda732005fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Sage?= Date: Tue, 28 Jun 2016 23:12:41 +0200 Subject: [PATCH 4/5] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 27e16b9..faed6ec 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Enamel +# Enamel [![Build Status](https://travis-ci.org/gregoiresage/enamel.svg?branch=develop)](https://travis-ci.org/gregoiresage/enamel) [![MIT License](http://img.shields.io/badge/license-MIT-lightgray.svg)](./LICENSE) + Enamel is a python script that generates C helpers from a [Clay](https://github.com/pebble/clay) configuration file to easily get the value of your settings. Enamel will : From ec596027539410639ebd087bc9286d3edef24243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Sage?= Date: Wed, 29 Jun 2016 01:13:50 +0200 Subject: [PATCH 5/5] update version --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index faed6ec..405da36 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Enamel [![Build Status](https://travis-ci.org/gregoiresage/enamel.svg?branch=develop)](https://travis-ci.org/gregoiresage/enamel) [![MIT License](http://img.shields.io/badge/license-MIT-lightgray.svg)](./LICENSE) +# Enamel [![Build Status](https://travis-ci.org/gregoiresage/enamel.svg?branch=master)](https://travis-ci.org/gregoiresage/enamel) [![MIT License](http://img.shields.io/badge/license-MIT-lightgray.svg)](./LICENSE) Enamel is a python script that generates C helpers from a [Clay](https://github.com/pebble/clay) configuration file to easily get the value of your settings. diff --git a/package.json b/package.json index db861e9..efb1a0b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "enamel", "author": "Grégoire Sage", - "version": "0.0.1", + "version": "1.1.0", "license": "MIT", "repository": { "type": "git",