From 4bc77fb8e8744975cef6552c81d1eeddf0bdd139 Mon Sep 17 00:00:00 2001 From: lexborisov Date: Wed, 9 Nov 2016 23:39:48 +0300 Subject: [PATCH] Added test command for make; Added tests for declarations: test/mycss/data/declaration --- Makefile | 8 +- test/Makefile | 50 +++ test/mycss/data/declaration/height.html | 2 + test/mycss/data/declaration/width.html | 2 + test/mycss/declaration.c | 399 ++++++++++++++++++++++++ 5 files changed, 459 insertions(+), 2 deletions(-) create mode 100644 test/Makefile create mode 100644 test/mycss/data/declaration/height.html create mode 100644 test/mycss/data/declaration/width.html create mode 100644 test/mycss/declaration.c diff --git a/Makefile b/Makefile index 2226dfa..632970b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ TARGET := source SRCDIR := source +TSTDIR := test CC ?= gcc @@ -40,7 +41,7 @@ endif SRCS := HDRS := -EXTDIRS := examples +EXTDIRS := examples test all: create shared static for f in $(EXTDIRS); do $(MAKE) -C $$f all; done @@ -74,4 +75,7 @@ clone: create clean_include myhtml_clone mycss_clone modest_clone myfont_clone find include -name "*.h" -exec sed -i '.bak' -E 's/^[ \t]*#[ \t]*include[ \t]*"([^"]+)"/#include <\1>/g' {} \; find include -name "*.h.bak" -exec rm -f {} \; -.PHONY: all clean clone \ No newline at end of file +test: + test/mycss/declaration test/mycss/data/declaration + +.PHONY: all clean clone test \ No newline at end of file diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..70e1c40 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,50 @@ +TARGET := test +SRCDIR := test + +CC ?= gcc +LIBS := ../lib/libmodest_static.a +LDLIBS := $(LIBS) + +INCLUDE_TMP := include + +MODEST_OPTIMIZATION_LEVEL ?= -O2 + +CFLAGS ?= -Wall -Werror +CFLAGS += $(MODEST_OPTIMIZATION_LEVEL) -Wno-unused-variable -fPIC --std=c99 -I../include + +MODEST_BUILD_WITHOUT_THREADS ?= NO +ifeq ($(MODEST_BUILD_WITHOUT_THREADS),YES) + $(info Build Examples without POSIX Threads) +else + $(info Build Examples with POSIX Threads) + CFLAGS += -pthread +endif + +ifeq ($(OS),Windows_NT) +else + UNAM := $(shell uname -s) + ifeq ($(UNAM),Darwin) + else + CFLAGS += -D_POSIX_C_SOURCE=199309L + endif +endif + +find_files_h = $(wildcard $(dir)/*.h) +find_files_c = $(wildcard $(dir)/*.c) + +SUBDIRS := mycss +HDRS += $(foreach dir,$(SUBDIRS),$(find_files_h)) +SRCS += $(foreach dir,$(SUBDIRS),$(find_files_c)) +#SRCS_FN += $(foreach dir,$(SUBDIRS),$(notdir $(find_files_c))) + +OBJS := $(patsubst %.c,%,$(SRCS)) +#OBJS_RM := $(patsubst %.c,%,$(SRCS_FN)) + +all: $(TARGET) + +$(TARGET): $(OBJS) + +clean: + rm -f $(OBJS) + +.PHONY: all \ No newline at end of file diff --git a/test/mycss/data/declaration/height.html b/test/mycss/data/declaration/height.html new file mode 100644 index 0000000..b7676d3 --- /dev/null +++ b/test/mycss/data/declaration/height.html @@ -0,0 +1,2 @@ +10% +unset diff --git a/test/mycss/data/declaration/width.html b/test/mycss/data/declaration/width.html new file mode 100644 index 0000000..48cd68f --- /dev/null +++ b/test/mycss/data/declaration/width.html @@ -0,0 +1,2 @@ +10% +unset diff --git a/test/mycss/declaration.c b/test/mycss/declaration.c new file mode 100644 index 0000000..1dad8d1 --- /dev/null +++ b/test/mycss/declaration.c @@ -0,0 +1,399 @@ +/* + Copyright (C) 2015-2016 Alexander Borisov + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Author: lex.borisov@gmail.com (Alexander Borisov) +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define TEST_FAILED(status) ((status) != 0) + +typedef bool (*test_read_dir_callback_f)(const char* filename, size_t filename_length, void* ctx); + +struct test_stat { + size_t good; + size_t total; +} +typedef test_stat_t; + +struct test_data { + myhtml_tree_t* tree; + mycss_entry_t* entry; + + test_stat_t stat; +} +typedef test_data_t; + +struct test_res { + char* data; + size_t size; +} +typedef test_res_t; + +test_res_t test_load_file(const char* filename) +{ + FILE *fh = fopen(filename, "rb"); + if(fh == NULL) { + fprintf(stderr, "Can't open file: %s\n", filename); + exit(EXIT_FAILURE); + } + + fseek(fh, 0L, SEEK_END); + long size = ftell(fh); + fseek(fh, 0L, SEEK_SET); + + char *file_data = (char*)malloc(size + 1); + if(file_data == NULL) { + fprintf(stderr, "Can't allocate mem for file: %s\n", filename); + exit(EXIT_FAILURE); + } + + size_t nread = fread(file_data, 1, size, fh); + if (nread != size) { + fprintf(stderr, "Could not read %ld bytes (%zu bytes done)\n", size, nread); + exit(EXIT_FAILURE); + } + + fclose(fh); + + if(size < 0) { + size = 0; + } + + return (test_res_t){file_data, (size_t)size}; +} + +void test_init_str_raw(myhtml_string_raw_t* str, size_t size) +{ + str->size = size; + str->length = 0; + str->data = (char*)myhtml_malloc(str->size * sizeof(char)); + + if(str->data == NULL) { + fprintf(stderr, "Can't allocation resources for myhtml_string_raw_t object\n"); + exit(EXIT_FAILURE); + } +} + +void test_reallocate_str(myhtml_string_raw_t *str, size_t size) +{ + str->data = (char*)myhtml_realloc(str->data, size * sizeof(char)); + + if(str->data == NULL) { + fprintf(stderr, "Can't reallocation resources for myhtml_string_raw_t object\n"); + exit(EXIT_FAILURE); + } +} + +void test_str_set_term(myhtml_string_raw_t *str) +{ + if((str->length + 1) >= str->size) + test_reallocate_str(str, 64); + + str->data[ str->length ] = '\0'; +} + +myhtml_string_raw_t test_combine_to_style(const char* one, size_t one_len, const char* two, size_t two_len) +{ + size_t new_size = one_len + two_len; + + myhtml_string_raw_t str = {0}; + test_init_str_raw(&str, (new_size + 2)); + + memcpy(str.data, one, sizeof(char) * one_len); + str.length = one_len; + + str.data[str.length] = ':'; + str.length++; + + memcpy(&str.data[str.length], two, sizeof(char) * two_len); + str.length += two_len; + + str.data[ str.length ] = '\0'; + + return str; +} + +/* basic init */ +myhtml_tree_t * test_declaration_create_myhtml(void) +{ + myhtml_t* myhtml = myhtml_create(); + if(myhtml == NULL) + exit(EXIT_FAILURE); + + myhtml_status_t status = myhtml_init(myhtml, MyHTML_OPTIONS_PARSE_MODE_SINGLE, 1, 0); + if(TEST_FAILED(status)) exit(EXIT_FAILURE); + + myhtml_tree_t* tree = myhtml_tree_create(); + if(tree == NULL) + exit(EXIT_FAILURE); + + status = myhtml_tree_init(tree, myhtml); + if(TEST_FAILED(status)) exit(EXIT_FAILURE); + + myhtml_tree_parse_flags_set(tree, MyHTML_TREE_PARSE_FLAGS_SKIP_WHITESPACE_TOKEN|MyHTML_TREE_PARSE_FLAGS_WITHOUT_DOCTYPE_IN_TREE); + + return tree; +} + +void test_declaration_destroy_myhtml(myhtml_tree_t *tree) +{ + myhtml_t* myhtml = tree->myhtml; + + myhtml_tree_destroy(tree); + myhtml_destroy(myhtml); +} + +mycss_entry_t * test_declaration_create_mycss(void) +{ + mycss_t *mycss = mycss_create(); + if(mycss == NULL) + exit(EXIT_FAILURE); + + mycss_status_t status = mycss_init(mycss); + if(TEST_FAILED(status)) exit(EXIT_FAILURE); + + // currenr entry work init + mycss_entry_t *entry = mycss_entry_create(); + if(entry == NULL) + exit(EXIT_FAILURE); + + status = mycss_entry_init(mycss, entry); + if(TEST_FAILED(status)) exit(EXIT_FAILURE); + + return entry; +} + +void test_declaration_destroy_mycss(mycss_entry_t *entry) +{ + mycss_t *mycss = entry->mycss; + + mycss_entry_destroy(entry, true); + mycss_destroy(mycss, true); +} + +test_stat_t test_read_dir(const char* dir_path, test_read_dir_callback_f callback, void* context) +{ + /* ho-ho-ho */ + char path[(4096 * 4)]; + sprintf(path, "%s", dir_path); + + printf("Tests in directory: %s\n", path); + + size_t path_len = strlen(dir_path); + + DIR *dir; + struct dirent *ent; + struct stat path_stat; + + test_stat_t result_stat = {0}; + + if((dir = opendir(dir_path)) != NULL) + { + while((ent = readdir(dir)) != NULL) + { + sprintf(&path[path_len], "/%s", ent->d_name); + + stat(path, &path_stat); + + if(ent->d_name[0] == '.' || S_ISDIR(path_stat.st_mode)) + continue; + + result_stat.total++; + printf("%zu) %s: ", result_stat.total, ent->d_name); + + if(callback(path, (ent->d_namlen + path_len + 1), context)) { + result_stat.good++; + } + } + + closedir (dir); + } + + return result_stat; +} + +/* test */ +bool test_process_elements(test_data_t *test_data, myhtml_collection_t *collection, test_stat_t* result_stat); +myhtml_string_raw_t test_process_result_from_node(test_data_t *test_data, myhtml_tree_node_t *node); +myhtml_string_raw_t test_process_serialize_stype(test_data_t *test_data, const char* style, size_t style_size); +void test_process_serialize_callback(const char* buffer, size_t size, void* ctx); + +bool test_process_callback(const char* filename, size_t filename_len, void* context) +{ + test_data_t *test_data = (test_data_t*)context; + test_res_t html_data = test_load_file(filename); + test_stat_t result_stat = {0}; + + /* parse html */ + myhtml_status_t status = myhtml_parse(test_data->tree, MyHTML_ENCODING_UTF_8, html_data.data, html_data.size); + if(status) { + fprintf(stderr, "Could parse HTML from file %s error code %d\n", filename, status); + exit(EXIT_FAILURE); + } + + /* find test elements */ + myhtml_collection_t *collection = myhtml_get_nodes_by_name_in_scope(test_data->tree, NULL, test_data->tree->node_body, "test", 4, NULL); + + if(collection->length) + test_process_elements(test_data, collection, &result_stat); + + myhtml_collection_destroy(collection); + + if((result_stat.total - result_stat.good)) { + printf("\tResult: "); + } + + printf("count(%zu) good(%zu) bad(%zu)\n", result_stat.total, result_stat.good, (result_stat.total - result_stat.good)); + + test_data->stat.good += result_stat.good; + test_data->stat.total += result_stat.total; + + myhtml_free(html_data.data); + return true; +} + +bool test_process_elements(test_data_t *test_data, myhtml_collection_t *collection, test_stat_t* result_stat) +{ + for(size_t i = 0; i < collection->length; i++) + { + myhtml_tree_node_t *node = collection->list[i]; + myhtml_tree_attr_t* attr_name = myhtml_attribute_by_key(node, "name", 4); + myhtml_tree_attr_t* attr_value = myhtml_attribute_by_key(node, "value", 5); + + size_t name_length; + size_t value_length; + + const char* name = myhtml_attribute_value(attr_name, &name_length); + const char* value = myhtml_attribute_value(attr_value, &value_length); + + myhtml_string_raw_t style = test_combine_to_style(name, name_length, value, value_length); + + myhtml_string_raw_t correct_result = test_process_result_from_node(test_data, node); + myhtml_string_raw_t parse_result = test_process_serialize_stype(test_data, style.data, style.length); + + result_stat->total++; + + if(correct_result.length == parse_result.length && + strcmp(correct_result.data, parse_result.data) == 0) + { + result_stat->good++; + } + else { + if((result_stat->total - result_stat->good) == 1) { + printf("\n"); + } + + printf("\tBad: name=\"%s\" value=\"%s\" need=\"%s\" result=\"%s\"\n", name, value, correct_result.data, parse_result.data); + } + + myhtml_string_raw_destroy(&style, false); + myhtml_string_raw_destroy(&correct_result, false); + myhtml_string_raw_destroy(&parse_result, false); + + mycss_entry_clean_all(test_data->entry); + } + + return true; +} + +myhtml_string_raw_t test_process_result_from_node(test_data_t *test_data, myhtml_tree_node_t *node) +{ + myhtml_string_raw_t str = {0}; + + if(myhtml_serialization_node_buffer(test_data->tree, node->child, &str) == false) { + fprintf(stderr, "Could serialization HTML node\n"); + exit(EXIT_FAILURE); + } + + return str; +} + +myhtml_string_raw_t test_process_serialize_stype(test_data_t *test_data, const char* style, size_t style_size) +{ + myhtml_string_raw_t str; + test_init_str_raw(&str, 4096); + + mycss_status_t status; + mycss_declaration_entry_t *declaration = mycss_declaration_parse(test_data->entry->declaration, MyHTML_ENCODING_UTF_8, style, style_size, &status); + + if(status) { + fprintf(stderr, "Could parse CSS Style (%d): %s\n", status, style); + exit(EXIT_FAILURE); + } + + mycss_declaration_serialization_entry_only_value(test_data->entry, declaration, test_process_serialize_callback, &str); + test_str_set_term(&str); + + return str; +} + +void test_process_serialize_callback(const char* buffer, size_t size, void* ctx) +{ + myhtml_string_raw_t *str = (myhtml_string_raw_t*)ctx; + + if((str->length + size) >= str->size) + test_reallocate_str(str, 4096); + + memcpy(&str->data[ str->length ], buffer, sizeof(char) * size); + str->length += size; +} + +int main(int argc, const char * argv[]) +{ + setbuf(stdout, NULL); + + if (argc < 2) { + printf("Bad ARGV!\nUse: declaration \n"); + exit(EXIT_FAILURE); + } + + test_data_t test_data = { + test_declaration_create_myhtml(), + test_declaration_create_mycss(), + {0} + }; + + //test_read_dir("/new/C-git/Modest/test/mycss/data/declaration", test_process_callback, &test_data); + + test_read_dir(argv[1], test_process_callback, &test_data); + + size_t bad_count = (test_data.stat.total - test_data.stat.good); + printf("\nTotal: %zu; Good: %zu; Bad: %zu\n", test_data.stat.total, test_data.stat.good, bad_count); + + test_declaration_destroy_myhtml(test_data.tree); + test_declaration_destroy_mycss(test_data.entry); + + return (bad_count ? EXIT_FAILURE : EXIT_SUCCESS); +} + + + +