/** * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #include "Layout-test-utils.h" #include #ifdef _MSC_VER #include #define isnan _isnan /* define fmaxf & fminf if < VC12 */ #if _MSC_VER < 1800 __forceinline const float fmaxf(const float a, const float b) { return (a > b) ? a : b; } __forceinline const float fminf(const float a, const float b) { return (a < b) ? a : b; } #endif #endif /** START_GENERATED **/ #define SMALL_WIDTH 35 #define SMALL_HEIGHT 18 #define BIG_WIDTH 172 #define BIG_HEIGHT 36 #define BIG_MIN_WIDTH 100 #define SMALL_TEXT "small" #define LONG_TEXT "loooooooooong with space" #define MEASURE_WITH_RATIO_2 "measureWithRatio2" #define MEASURE_WITH_MATCH_PARENT "measureWithMatchParent" /** END_GENERATED **/ typedef struct failed_test_t { struct failed_test_t *next; const char *name; css_node_t *style; css_node_t *expected; } failed_test_t; static failed_test_t *failed_test_head = NULL; static failed_test_t *failed_test_tail = NULL; static void add_failed_test(const char *name, css_node_t *style, css_node_t *expected) { failed_test_t *failed_test = (failed_test_t *)malloc(sizeof(failed_test_t)); failed_test->next = NULL; failed_test->name = name; failed_test->style = style; failed_test->expected = expected; if (!failed_test_head) { failed_test_head = failed_test; failed_test_tail = failed_test; } else { failed_test_tail->next = failed_test; failed_test_tail = failed_test; } } static bool eq(float a, float b) { return fabs(a - b) < 0.0001; } static bool are_layout_equal(css_node_t *a, css_node_t *b) { if (!eq(a->layout.dimensions[CSS_WIDTH], b->layout.dimensions[CSS_WIDTH]) || !eq(a->layout.dimensions[CSS_HEIGHT], b->layout.dimensions[CSS_HEIGHT]) || !eq(a->layout.position[CSS_TOP], b->layout.position[CSS_TOP]) || !eq(a->layout.position[CSS_LEFT], b->layout.position[CSS_LEFT]) || !eq(a->children_count, b->children_count)) { return false; } for (int i = 0; i < a->children_count; ++i) { if (!are_layout_equal(a->get_child(a->context, i), b->get_child(b->context, i))) { return false; } } return true; } css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode) { const char *text = (const char *)context; css_dim_t dim; if (strcmp(text, SMALL_TEXT) == 0) { if (widthMode == CSS_MEASURE_MODE_UNDEFINED) { width = 1000000; } dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width); dim.dimensions[CSS_HEIGHT] = SMALL_HEIGHT; return dim; } if (strcmp(text, LONG_TEXT) == 0) { if (widthMode == CSS_MEASURE_MODE_UNDEFINED) { width = 1000000; } dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width); dim.dimensions[CSS_HEIGHT] = width >= BIG_WIDTH ? SMALL_HEIGHT : BIG_HEIGHT; return dim; } if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) { if (widthMode != CSS_MEASURE_MODE_UNDEFINED) { dim.dimensions[CSS_WIDTH] = width; dim.dimensions[CSS_HEIGHT] = width * 2; } else if (heightMode != CSS_MEASURE_MODE_UNDEFINED) { dim.dimensions[CSS_WIDTH] = height * 2; dim.dimensions[CSS_HEIGHT] = height; } else { dim.dimensions[CSS_WIDTH] = 99999; dim.dimensions[CSS_HEIGHT] = 99999; } return dim; } if (strcmp(text, MEASURE_WITH_MATCH_PARENT) == 0) { if (widthMode == CSS_MEASURE_MODE_UNDEFINED) { width = 99999; } if (heightMode == CSS_MEASURE_MODE_UNDEFINED) { height = 99999; } dim.dimensions[CSS_WIDTH] = width; dim.dimensions[CSS_HEIGHT] = height; return dim; } // Should not go here dim.dimensions[CSS_WIDTH] = CSS_UNDEFINED; dim.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; return dim; } static int test_ran_count = 0; void test(const char *name, css_node_t *style, css_node_t *expected_layout) { ++test_ran_count; layoutNode(style, CSS_UNDEFINED, CSS_UNDEFINED, (css_direction_t)-1); if (!are_layout_equal(style, expected_layout)) { printf("%sF%s", "\x1B[31m", "\x1B[0m"); add_failed_test(name, style, expected_layout); } else { printf("%s.%s", "\x1B[32m", "\x1B[0m"); free_css_node(style); free_css_node(expected_layout); } } int tests_finished() { failed_test_t *failed_test = failed_test_head; printf("\n"); int tests_failed = 0; while (failed_test) { printf("%sFAIL%s %s\n", "\x1B[31m", "\x1B[0m", failed_test->name); printf("Input: "); print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_STYLE | CSS_PRINT_CHILDREN)); printf("Output: "); print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN)); printf("Expected: "); print_css_node(failed_test->expected, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN)); free_css_node(failed_test->style); free_css_node(failed_test->expected); failed_test_t *next_failed_test = failed_test->next; free(failed_test); failed_test = next_failed_test; tests_failed++; } printf("\n\n"); if (tests_failed > 0) { printf("TESTS FAILED: %d\n", tests_failed); return 1; } else { printf("ALL TESTS PASSED: %d tests ran.\n", test_ran_count); return 0; } } static css_node_t* get_child(void *context, int i) { css_node_t* children = (css_node_t*)context; return &children[i]; } static bool is_dirty(void *context) { (void)context; // remove unused warning return true; } static void init_test_css_node(css_node_t *node) { node->get_child = get_child; node->is_dirty = is_dirty; } css_node_t *new_test_css_node(void) { css_node_t *node = new_css_node(); init_test_css_node(node); return node; } void init_css_node_children(css_node_t *node, int children_count) { node->context = calloc((size_t)children_count, sizeof(css_node_t)); for (int i = 0; i < children_count; ++i) { init_css_node(node->get_child(node->context, i)); init_test_css_node(node->get_child(node->context, i)); } node->children_count = children_count; }