diff options
Diffstat (limited to 'src/style-test.cpp')
| -rw-r--r-- | src/style-test.cpp | 770 |
1 files changed, 770 insertions, 0 deletions
diff --git a/src/style-test.cpp b/src/style-test.cpp new file mode 100644 index 000000000..86382b174 --- /dev/null +++ b/src/style-test.cpp @@ -0,0 +1,770 @@ +#include <cassert> +#include <cmath> +#include "utest/utest.h" +#include "streq.h" +#include "strneq.h" +#include "style.h" + +/// Dummy functions to keep linker happy +int sp_main_gui (int, char const**) { return 0; } +int sp_main_console (int, char const**) { return 0; } + +/* Extracted mechanically from http://www.w3.org/TR/SVG11/types.html#ColorKeywords: + * + * tidy -wrap 999 < types.html 2> /dev/null | + * egrep '(prop|color-keyword)-value' | + * sed 's,<td><span class="prop-value">, {",;s/<td><span class="color-keyword-value">rgb(/", {/;s%).*%}},@%;s%</span></td>%%' | + * tr -d \\n | + * tr @ \\n + */ +static struct { + char const *color_keyword; + struct {unsigned r; unsigned g; unsigned b; } rgb; +} const color_keywords[] = { + {"aliceblue", {240, 248, 255}}, + {"antiquewhite", {250, 235, 215}}, + {"aqua", { 0, 255, 255}}, + {"aquamarine", {127, 255, 212}}, + {"azure", {240, 255, 255}}, + {"beige", {245, 245, 220}}, + {"bisque", {255, 228, 196}}, + {"black", { 0, 0, 0}}, + {"blanchedalmond", {255, 235, 205}}, + {"blue", { 0, 0, 255}}, + {"blueviolet", {138, 43, 226}}, + {"brown", {165, 42, 42}}, + {"burlywood", {222, 184, 135}}, + {"cadetblue", { 95, 158, 160}}, + {"chartreuse", {127, 255, 0}}, + {"chocolate", {210, 105, 30}}, + {"coral", {255, 127, 80}}, + {"cornflowerblue", {100, 149, 237}}, + {"cornsilk", {255, 248, 220}}, + {"crimson", {220, 20, 60}}, + {"cyan", { 0, 255, 255}}, + {"darkblue", { 0, 0, 139}}, + {"darkcyan", { 0, 139, 139}}, + {"darkgoldenrod", {184, 134, 11}}, + {"darkgray", {169, 169, 169}}, + {"darkgreen", { 0, 100, 0}}, + {"darkgrey", {169, 169, 169}}, + {"darkkhaki", {189, 183, 107}}, + {"darkmagenta", {139, 0, 139}}, + {"darkolivegreen", { 85, 107, 47}}, + {"darkorange", {255, 140, 0}}, + {"darkorchid", {153, 50, 204}}, + {"darkred", {139, 0, 0}}, + {"darksalmon", {233, 150, 122}}, + {"darkseagreen", {143, 188, 143}}, + {"darkslateblue", { 72, 61, 139}}, + {"darkslategray", { 47, 79, 79}}, + {"darkslategrey", { 47, 79, 79}}, + {"darkturquoise", { 0, 206, 209}}, + {"darkviolet", {148, 0, 211}}, + {"deeppink", {255, 20, 147}}, + {"deepskyblue", { 0, 191, 255}}, + {"dimgray", {105, 105, 105}}, + {"dimgrey", {105, 105, 105}}, + {"dodgerblue", { 30, 144, 255}}, + {"firebrick", {178, 34, 34}}, + {"floralwhite", {255, 250, 240}}, + {"forestgreen", { 34, 139, 34}}, + {"fuchsia", {255, 0, 255}}, + {"gainsboro", {220, 220, 220}}, + {"ghostwhite", {248, 248, 255}}, + {"gold", {255, 215, 0}}, + {"goldenrod", {218, 165, 32}}, + {"gray", {128, 128, 128}}, + {"grey", {128, 128, 128}}, + {"green", { 0, 128, 0}}, + {"greenyellow", {173, 255, 47}}, + {"honeydew", {240, 255, 240}}, + {"hotpink", {255, 105, 180}}, + {"indianred", {205, 92, 92}}, + {"indigo", { 75, 0, 130}}, + {"ivory", {255, 255, 240}}, + {"khaki", {240, 230, 140}}, + {"lavender", {230, 230, 250}}, + {"lavenderblush", {255, 240, 245}}, + {"lawngreen", {124, 252, 0}}, + {"lemonchiffon", {255, 250, 205}}, + {"lightblue", {173, 216, 230}}, + {"lightcoral", {240, 128, 128}}, + {"lightcyan", {224, 255, 255}}, + {"lightgoldenrodyellow", {250, 250, 210}}, + {"lightgray", {211, 211, 211}}, + {"lightgreen", {144, 238, 144}}, + {"lightgrey", {211, 211, 211}}, + {"lightpink", {255, 182, 193}}, + {"lightsalmon", {255, 160, 122}}, + {"lightseagreen", { 32, 178, 170}}, + {"lightskyblue", {135, 206, 250}}, + {"lightslategray", {119, 136, 153}}, + {"lightslategrey", {119, 136, 153}}, + {"lightsteelblue", {176, 196, 222}}, + {"lightyellow", {255, 255, 224}}, + {"lime", { 0, 255, 0}}, + {"limegreen", { 50, 205, 50}}, + {"linen", {250, 240, 230}}, + {"magenta", {255, 0, 255}}, + {"maroon", {128, 0, 0}}, + {"mediumaquamarine", {102, 205, 170}}, + {"mediumblue", { 0, 0, 205}}, + {"mediumorchid", {186, 85, 211}}, + {"mediumpurple", {147, 112, 219}}, + {"mediumseagreen", { 60, 179, 113}}, + {"mediumslateblue", {123, 104, 238}}, + {"mediumspringgreen", { 0, 250, 154}}, + {"mediumturquoise", { 72, 209, 204}}, + {"mediumvioletred", {199, 21, 133}}, + {"midnightblue", { 25, 25, 112}}, + {"mintcream", {245, 255, 250}}, + {"mistyrose", {255, 228, 225}}, + {"moccasin", {255, 228, 181}}, + {"navajowhite", {255, 222, 173}}, + {"navy", { 0, 0, 128}}, + {"oldlace", {253, 245, 230}}, + {"olive", {128, 128, 0}}, + {"olivedrab", {107, 142, 35}}, + {"orange", {255, 165, 0}}, + {"orangered", {255, 69, 0}}, + {"orchid", {218, 112, 214}}, + {"palegoldenrod", {238, 232, 170}}, + {"palegreen", {152, 251, 152}}, + {"paleturquoise", {175, 238, 238}}, + {"palevioletred", {219, 112, 147}}, + {"papayawhip", {255, 239, 213}}, + {"peachpuff", {255, 218, 185}}, + {"peru", {205, 133, 63}}, + {"pink", {255, 192, 203}}, + {"plum", {221, 160, 221}}, + {"powderblue", {176, 224, 230}}, + {"purple", {128, 0, 128}}, + {"red", {255, 0, 0}}, + {"rosybrown", {188, 143, 143}}, + {"royalblue", { 65, 105, 225}}, + {"saddlebrown", {139, 69, 19}}, + {"salmon", {250, 128, 114}}, + {"sandybrown", {244, 164, 96}}, + {"seagreen", { 46, 139, 87}}, + {"seashell", {255, 245, 238}}, + {"sienna", {160, 82, 45}}, + {"silver", {192, 192, 192}}, + {"skyblue", {135, 206, 235}}, + {"slateblue", {106, 90, 205}}, + {"slategray", {112, 128, 144}}, + {"slategrey", {112, 128, 144}}, + {"snow", {255, 250, 250}}, + {"springgreen", { 0, 255, 127}}, + {"steelblue", { 70, 130, 180}}, + {"tan", {210, 180, 140}}, + {"teal", { 0, 128, 128}}, + {"thistle", {216, 191, 216}}, + {"tomato", {255, 99, 71}}, + {"turquoise", { 64, 224, 208}}, + {"violet", {238, 130, 238}}, + {"wheat", {245, 222, 179}}, + {"white", {255, 255, 255}}, + {"whitesmoke", {245, 245, 245}}, + {"yellow", {255, 255, 0}}, + {"yellowgreen", {154, 205, 50}}, + {NULL, {0, 0, 0}} +}; + +static char const *const display_vals[] = { + "inline", "block", "list-item", "run-in", "compact", "marker", "table", "inline-table", + "table-row-group", "table-header-group", "table-footer-group", "table-row", + "table-column-group", "table-column", "table-cell", "table-caption", "none", NULL +}; + +static char const *const font_stretch_vals[] = { + "normal", + "wider", + "narrower", + "ultra-condensed", + "extra-condensed", + "condensed", + "semi-condensed", + "semi-expanded", + "expanded", + "extra-expanded", + "ultra-expanded", + NULL +}; + +static char const *const font_style_vals[] = {"normal", "italic", "oblique", NULL}; + +static char const *const font_variant_vals[] = {"normal", "small-caps", NULL}; + +static char const *const font_weight_vals[] = {"normal", "bold", "bolder", "lighter", + "100", "200", "300", "400", "500", + "600", "700", "800", "900", NULL}; + +static char const *const normal_val[] = {"normal", NULL}; + +static char const *const none_val[] = {"none", NULL}; + +static char const *const linecap_vals[] = {"butt", "round", "square", NULL}; + +static char const *const linejoin_vals[] = {"miter", "round", "bevel", NULL}; + +static char const *const text_anchor_vals[] = {"start", "middle", "end", NULL}; + +static char const *const visibility_vals[] = {"visible", "hidden", "collapse", NULL}; + +static char const *const writing_mode_vals[] = {"lr-tb", "rl-tb", "tb-rl", /*"lr", "rl", "tb",*/ NULL}; +/* TODO: Inkscape correctly accepts lr,rl,tb, but reports them as lr-tb etc. + Either change inkscape or write custom test. */ + +static char const *const fill_rule_vals[] = {"nonzero", "evenodd", NULL}; + +static char const *const paint_enum_vals[] = {"none", "currentColor", NULL}; + +static gchar * +merge_then_write_string(gchar const *const str, guint const flags) +{ + SPStyle *const style = sp_style_new(); + sp_style_merge_from_style_string(style, str); + gchar *const ret = sp_style_write_string(style, flags); + sp_style_unref(style); + return ret; +} + +static void +enum_val(char const prop[], char const *const vals[]) +{ + assert(vals); + assert(vals[0]); + + for (unsigned i = 0; vals[i]; ++i) { + char *prop_eq_val = g_strdup_printf("%s:%s", prop, vals[i]); + gchar *ifset_str = merge_then_write_string(prop_eq_val, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(streq(ifset_str, prop_eq_val)); + g_free(ifset_str); + g_free(prop_eq_val); + } +} + +static void +color_val(char const prop[], char const *const dummy_vals[]) +{ + assert(dummy_vals == NULL); + char const *const extra_vals[] = {"#0000ff", NULL}; + enum_val(prop, extra_vals); +#if 0 + char const *color_vals[G_N_ELEMENTS(color_keywords) + G_N_ELEMENTS(extra_vals)]; + for (unsigned i = 0; i < G_N_ELEMENTS(extra_vals); ++i) { + color_vals[i] = extra_vals[i]; + } + for (unsigned i = 0; i < G_N_ELEMENTS(color_keywords); ++i) { + color_vals[G_N_ELEMENTS(extra_vals) + i] = color_keywords[i].color_keyword; + } + enum_val(prop, color_vals); + /* todo: other color stuff (rgb(), #123) */ +#endif +} + +static void +paint_val(char const prop[], char const *const dummy_vals[]) +{ + /* Ref: http://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint */ + assert(dummy_vals == NULL); + color_val(prop, NULL); + enum_val(prop, paint_enum_vals); + /* todo: uri, `<uri> none' etc. */ +} + +static void +number_val(char const prop[], double const min, double const max, double const eps) +{ + assert(min <= max); + /* TODO */ + double const propns[] = {0., .5, .25, .125, + (1.0 / (1 << 7)), + (1.0 / (1 << 8)), + (1.0 / (1 << 15)), + (1.0 / (1 << 23)), + (1.0 / (1 << 24)), + (1.0 / (1 << 25)), + (1.0 / (1 << 26)), + 1e-5, 0.13, 1/7., 2/3., 10/11., 1.0}; + size_t const prop_len = std::strlen(prop); + for (unsigned i = 0; i < G_N_ELEMENTS(propns); ++i) { + double const propn = propns[i]; + double const val = ( propn == 0 + ? min + : ( propn == 1 + ? max + : min + (propns[i] * (max - min)) ) ); + char val_str[35]; + g_ascii_formatd(val_str, sizeof(val_str), "%.17f", val); + char *prop_eq_val = g_strdup_printf("%s:%s", prop, val_str); + gchar *ifset_str = merge_then_write_string(prop_eq_val, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(strneq(ifset_str, prop_eq_val, prop_len + 1)); + char *endptr; + double const found_val = g_strtod(ifset_str + prop_len + 1, &endptr); + UTEST_ASSERT(*endptr == '\0'); + if (fabs(val) < 1.) { + UTEST_ASSERT(std::fabs(found_val - val) < eps); + } else { + UTEST_ASSERT(std::fabs(found_val / val - 1.) < eps); + } + g_free(ifset_str); + g_free(prop_eq_val); + } +} + +static void +miterlimit_val(char const prop[], char const *const dummy_vals[]) +{ + // Ref: http://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty + assert(dummy_vals == NULL); + number_val(prop, 1., 20., 2e-7); +#if 0 + static char const *const miterlimit_vals[] = { + "1", "1.0", "1.5", "2", "4", "8", "1e1", NULL + }; + // bad values: <1, percentages, strings (none etc.). +#endif +} + +static void +font_family_val(char const prop[], char const *const dummy_vals[]) +{ + assert(dummy_vals == NULL); + static char const *const generic_font_family_vals[] = {"serif", "sans-serif", "cursive", "fantasy", "monospace", NULL}; + enum_val(prop, generic_font_family_vals); + /* todo: unrecognized fonts, comma-separated lists. */ +} + +/** + * "unitful length" is used for font-size, which we always write with an explicit unit (typically + * `px') for better CSS interoperability. + */ +static void +unitful_length_val(char const prop[], char const *const dummy_vals[]) +{ + /* todo */ + assert(dummy_vals == NULL); +} + +static void +length_val(char const prop[], char const *const dummy_vals[]) +{ + assert(dummy_vals == NULL); + number_val(prop, 0., 6., 1e-7); + unitful_length_val(prop, dummy_vals); + /* todo: exponential notation. See http://www.w3.org/TR/SVG11/types.html#DataTypeNumber for + where exponential notation is/isn't allowed. */ +} + +static void +length_or_enum_val(char const prop[], char const *const vals[]) +{ + length_val(prop, NULL); + enum_val(prop, vals); +} + +static void +opacity_val(char const prop[], char const *const dummy_vals[]) +{ + assert(dummy_vals == NULL); + number_val(prop, 0., 1., 1.0 / (1 << 24)); + /* todo: exponential notation */ +} + +static void +uri_or_enum_val(char const prop[], char const *const vals[]) +{ + enum_val(prop, vals); + /* todo: uri's */ +} + +static void +suppress_warning_log_handler(gchar const *log_domain, GLogLevelFlags /*log_level*/, + gchar const *message, + gpointer /*user_data*/) +{ + /* todo: We could strncpy message to a static buffer for later testing with + * UTEST_ASSERT(streq(prev_message, exp_message)). */ +} + +static void +test_mul24(unsigned const a24, unsigned const b24) +{ + assert(a24 <= SP_SCALE24_MAX); + assert(b24 <= SP_SCALE24_MAX); + unsigned const manual_prod24 = SP_SCALE24_FROM_FLOAT(SP_SCALE24_TO_FLOAT(a24) * + SP_SCALE24_TO_FLOAT(b24) ); + unsigned const prod24 = SP_SCALE24_MUL(a24, b24); + UTEST_ASSERT_SHOW(prod24 == manual_prod24, + ("MUL gives 0x%06x=%g, whereas explicit conversions give 0x%06x=%g;\n" + "multiplicands: 0x%06x * 0x%06x (i.e. %g * %g)", + prod24, SP_SCALE24_TO_FLOAT(prod24), + manual_prod24, SP_SCALE24_TO_FLOAT(manual_prod24), + a24, b24, SP_SCALE24_TO_FLOAT(a24), SP_SCALE24_TO_FLOAT(b24))); +} + +static void +test_scale24_mul() +{ + UTEST_TEST("SP_SCALE24_MUL") { + UTEST_ASSERT(0x1000 < SP_SCALE24_MAX); + UTEST_ASSERT(SP_SCALE24_MAX < SP_SCALE24_MAX + 1); // i.e. no overflow. + + for (unsigned i = 0; i <= 10; ++i) { + unsigned const i24 = SP_SCALE24_MAX * i / 10; + UTEST_ASSERT(i24 == SP_SCALE24_FROM_FLOAT(i / 10.0)); + for (unsigned j = 0; j <= 10; ++j) { + unsigned const j24 = SP_SCALE24_MAX * j / 10; + test_mul24(i24, j24); + } + } + + for (unsigned i = 0; i < 10000; ++i) { + unsigned const a24 = rand() % (SP_SCALE24_MAX + 1); + unsigned const b24 = rand() % (SP_SCALE24_MAX + 1); + test_mul24(a24, b24); + } + } +} + +static void +test_merge_opacity() +{ + SPStyle &parent = *sp_style_new(); + SPStyle &child = *sp_style_new(); + + unsigned const either = 2; + struct { + bool parent_set; + bool parent_inherit; + float parent_float_val; + bool child_set; + bool child_inherit; + float child_float_val; + unsigned exp_set; + unsigned exp_inherit; + double exp_float_val; + } const cases[] = { + {false, false, 1.0, false, false, 1.0, false, false, 1.0}, + {false, false, 1.0, true, true, 1.0, false, false, 1.0}, + {false, false, 1.0, true, false, 1.0, false, false, 1.0}, + {false, false, 1.0, true, false, 0.5, true, false, 0.5}, + {false, false, 1.0, true, false, 0.0, true, false, 0.0}, + + {true, true, 1.0, false, false, 1.0, true, true, 1.0}, + {true, true, 0.7, false, false, 1.0, true, true, 0.7}, + {true, true, 0.0, false, false, 1.0, true, true, 0.0}, + {true, true, 1.0, true, true, 1.0, true, true, 1.0}, + /* child computed value isn't required to be up-to-date, so test what happens when it + * isn't up-to-date. */ + {true, true, 1.0, true, true, 0.7, true, true, 1.0}, + {true, true, 0.6, true, true, 0.3, true, false, 0.36}, + {true, true, 0.0, true, true, 0.0, true, true, 0.0}, + {true, true, 0.0, true, true, 0.9, true, true, 0.0}, + + /* parent inherit, child set to number */ + {true, true, 1.0, true, false, 1.0, true, true, 1.0}, + {true, true, 1.0, true, false, 0.8, true, false, 0.8}, + {true, true, 1.0, true, false, 0.0, true, false, 0.0}, + {true, true, 0.9, true, false, 1.0, true, true, 0.9}, + {true, true, 0.9, true, false, 0.8, true, false, 0.72}, + {true, true, 0.9, true, false, 0.0, true, false, 0.0}, + {true, true, 0.0, true, false, 1.0, true, true, 0.0}, + {true, true, 0.0, true, false, 0.6, true, either, 0.0}, + {true, true, 0.0, true, false, 0.0, true, false, 0.0}, + + /* parent set to number. */ + {true, false, 1.0, false, false, 1.0, either, false, 1.0}, + {true, false, 0.3, false, false, 1.0, true, false, 0.3}, + {true, false, 0.3, false, false, 1.0, true, false, 0.3}, + {true, false, 0.0, false, false, 1.0, true, false, 0.0}, + + {true, false, 1.0, true, true, 1.0, either, false, 1.0}, + {true, false, 1.0, true, true, 0.8, either, false, 1.0}, + {true, false, 0.8, true, true, 0.8, true, false, 0.64}, + {true, false, 0.8, true, true, 0.5, true, false, 0.64}, + {true, false, 0.0, true, true, 0.0, true, false, 0.0}, + {true, false, 0.0, true, true, 0.4, true, false, 0.0}, + + {true, false, 1.0, true, false, 1.0, either, false, 1.0}, + {true, false, 1.0, true, false, 0.4, true, false, 0.4}, + {true, false, 1.0, true, false, 0.0, true, false, 0.0}, + {true, false, 0.7, true, false, 1.0, true, false, 0.7}, + {true, false, 0.7, true, false, 0.4, true, false, 0.28}, + {true, false, 0.7, true, false, 0.0, true, false, 0.0}, + {true, false, 0.0, true, false, 1.0, true, false, 0.0}, + {true, false, 0.0, true, false, 0.6, true, false, 0.0}, + {true, false, 0.0, true, false, 0.0, true, false, 0.0} + }; + UTEST_TEST("sp_style_merge_from_dying_parent: opacity") { + for (unsigned i = 0; i < G_N_ELEMENTS(cases); ++i) { + parent.opacity.set = cases[i].parent_set; + parent.opacity.inherit = cases[i].parent_inherit; + parent.opacity.value = SP_SCALE24_FROM_FLOAT(cases[i].parent_float_val); + unsigned const parent24 = parent.opacity.value; + + child.opacity.set = cases[i].child_set; + child.opacity.inherit = cases[i].child_inherit; + child.opacity.value = SP_SCALE24_FROM_FLOAT(cases[i].child_float_val); + unsigned const child24 = child.opacity.value; + + sp_style_merge_from_dying_parent(&child, &parent); + if (cases[i].exp_set != either) { + UTEST_ASSERT(child.opacity.set == cases[i].exp_set); + } + if (cases[i].exp_inherit != either) { + UTEST_ASSERT(child.opacity.inherit == cases[i].exp_inherit); + } + unsigned const exp24 = SP_SCALE24_FROM_FLOAT(cases[i].exp_float_val); + UTEST_ASSERT_SHOW(child.opacity.value == exp24, + ("i=%u, expected 0x%06x=%g but found 0x%06x=%g; " + "parent 0x%06x=%g, child 0x%06x=%g", + i, exp24, cases[i].exp_float_val, + child.opacity.value, SP_SCALE24_TO_FLOAT(child.opacity.value), + parent24, SP_SCALE24_TO_FLOAT(parent24), + child24, SP_SCALE24_TO_FLOAT(child24))); + } + } +} + +static bool +test_style() +{ + struct { + char const *property; + char const *ink_dfl; + char const *spec_dfl; + void (*tst_fn)(char const[], char const *const[]); + char const *const *tst_fn_arg; + bool can_explicitly_inherit; + } const props[] = { + {"color", "#000000", "#000000", color_val, NULL, true}, + // initial value "depends on user agent" + {"display", "inline", "inline", enum_val, display_vals, true}, + {"fill", "#000000", "black", paint_val, NULL, true}, + {"fill-opacity", "1", "1", opacity_val, NULL, true}, + {"fill-rule", "nonzero", "nonzero", enum_val, fill_rule_vals, true}, + {"font-family", "Bitstream Vera Sans", "Bitstream Vera Sans", font_family_val, NULL, true}, + // initial value depends on user agent + {"font-size", "medium", "medium", unitful_length_val, NULL, true}, + // TODO: abs, rel, pcnt. + {"font-stretch", "normal", "normal", enum_val, font_stretch_vals, true}, + {"font-style", "normal", "normal", enum_val, font_style_vals, true}, + {"font-variant", "normal", "normal", enum_val, font_variant_vals, true}, + {"font-weight", "normal", "normal", enum_val, font_weight_vals, true}, + {"letter-spacing", "normal", "normal", length_or_enum_val, normal_val, true}, + {"marker", "none", "none", uri_or_enum_val, none_val, true}, + {"marker-end", "none", "none", uri_or_enum_val, none_val, true}, + {"marker-mid", "none", "none", uri_or_enum_val, none_val, true}, + {"marker-start", "none", "none", uri_or_enum_val, none_val, true}, + {"opacity", "1", "1", opacity_val, NULL, true}, + {"stroke", "none", "none", paint_val, NULL, true}, + {"stroke-dasharray", "none", "none", enum_val, none_val, true}, + // TODO: http://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty + //{"stroke-dashoffset", "0", "0", length_val, NULL, true}, + // fixme: dashoffset currently fails a number of tests, but the relevant code + // is being worked on for something else at the time of writing, so I'm + // delaying fixing it. It should be changed to SPILength. + {"stroke-linecap", "butt", "butt", enum_val, linecap_vals, true}, + {"stroke-linejoin", "miter", "miter", enum_val, linejoin_vals, true}, + {"stroke-miterlimit", "4", "4", miterlimit_val, NULL, true}, + {"stroke-opacity", "1", "1", opacity_val, NULL, true}, + {"stroke-width", "1", "1", length_val, NULL, true}, + {"text-anchor", "start", "start", enum_val, text_anchor_vals, true}, + {"visibility", "visible", "visible", enum_val, visibility_vals, true}, + {"writing-mode", "lr-tb", "lr-tb", enum_val, writing_mode_vals, true} + }; + + char const str0_all_exp[] = + "font-size:medium;" + "font-style:normal;" + "font-variant:normal;" + "font-weight:normal;" + "font-stretch:normal;" + "text-indent:0;" + "text-align:start;" + "text-decoration:none;" + "line-height:normal;" + "letter-spacing:normal;" + "word-spacing:normal;" + "text-transform:none;" + "direction:ltr;" + "block-progression:tb;" + "writing-mode:lr-tb;" + "text-anchor:start;" + "opacity:1;" + "color:#000000;" + "fill:#000000;" + "fill-opacity:1;" + "fill-rule:nonzero;" + "stroke:none;" + "stroke-width:1;" + "stroke-linecap:butt;" + "stroke-linejoin:miter;" + "marker:none;" + "marker-start:none;" + "marker-mid:none;" + "marker-end:none;" + "stroke-miterlimit:4;" + "stroke-dasharray:none;" + "stroke-dashoffset:0;" + "stroke-opacity:1;" + "visibility:visible;" + "display:inline;" + "overflow:visible;" + "font-family:Bitstream Vera Sans"; + + utest_start("style"); + UTEST_TEST("sp_style_new, sp_style_write_string") { + SPStyle *style = sp_style_new(); + gchar *str0_all = sp_style_write_string(style, SP_STYLE_FLAG_ALWAYS); + gchar *str0_set = sp_style_write_string(style, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(*str0_set == '\0'); + UTEST_ASSERT(streq(str0_all, str0_all_exp)); + printf(str0_all); + g_free(str0_all); + g_free(str0_set); + sp_style_unref(style); + } + + UTEST_TEST("sp_style_merge_from_style_string(whitespace, ifset") { + gchar *str0_set = merge_then_write_string(" \t \t\t", SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(*str0_set == '\0'); + g_free(str0_set); + } + + UTEST_TEST("sp_style_merge_from_style_string(whitespace, always") { + gchar *str0_all = merge_then_write_string(" \t \t\t", SP_STYLE_FLAG_ALWAYS); + UTEST_ASSERT(streq(str0_all, str0_all_exp)); + g_free(str0_all); + } + + /* Some tests for invalid style strings. We temporarily suppress all g_warning's. (The + current code uses g_warning instead of proper SVG error handling.) */ + guint const log_handler_id = g_log_set_handler(NULL, G_LOG_LEVEL_WARNING, + suppress_warning_log_handler, NULL); + UTEST_TEST("sp_style_merge_from_style_string(\"fill:\", ifset)") { + gchar *str0_set = merge_then_write_string("fill:", SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(*str0_set == '\0'); + g_free(str0_set); + } + + UTEST_TEST("sp_style_merge_from_style_string(\"font-family:\", always)") { + gchar *str0_all = merge_then_write_string("font-family:", SP_STYLE_FLAG_ALWAYS); + UTEST_ASSERT(streq(str0_all, str0_all_exp)); + g_free(str0_all); + } + + UTEST_TEST("sp_style_merge_from_style_string(\"fill: \", ifset)") { + gchar *str0_set = merge_then_write_string("fill: ", SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(*str0_set == '\0'); + g_free(str0_set); + } + + UTEST_TEST("sp_style_merge_from_style_string(\"font-family: \", always)") { + gchar *str0_all = merge_then_write_string("font-family: ", SP_STYLE_FLAG_ALWAYS); + UTEST_ASSERT(streq(str0_all, str0_all_exp)); + g_free(str0_all); + } + + UTEST_TEST("sp_style_merge_from_style_string(\":none\", ifset)") { + gchar *str0_set = merge_then_write_string(":none", SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(*str0_set == '\0'); + g_free(str0_set); + } + g_log_remove_handler(NULL, log_handler_id); + + /* The following tests involve invalid style, but aren't expected to trigger + g_log calls. */ + /* invalid color setting */ + { + char const *bad[] = {"#4321", "currentColor", "#87654321", "#42", "aquam"}; + for (unsigned i = 0; i < G_N_ELEMENTS(bad); ++i) { + gchar *tst_name = g_strdup_printf("invalid color setting: %s", bad[i]); + gchar *style_str = g_strdup_printf("color:%s;color:#123;color:%s", + bad[i], bad[i]); + UTEST_TEST(tst_name) { + gchar *str0_set = merge_then_write_string(style_str, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(streq(str0_set, "color:#112233")); + g_free(str0_set); + } + g_free(style_str); + g_free(tst_name); + } + } + + /* End of invalid style string examples. */ + + +#if 1 /* previously failed because of dashoffset:0 vs dashoffset:0.00000000 */ + UTEST_TEST("sp_style_merge_from_style_string(default): ifset") { + gchar *ifset_str = merge_then_write_string(str0_all_exp, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(streq(ifset_str, str0_all_exp)); + g_free(ifset_str); + } + + UTEST_TEST("sp_style_merge_from_style_string(default): always") { + gchar *ifset_str = merge_then_write_string(str0_all_exp, SP_STYLE_FLAG_ALWAYS); + UTEST_ASSERT(streq(ifset_str, str0_all_exp)); + g_free(ifset_str); + } +#endif + + UTEST_TEST("sp_style_merge_from_style_string") { + /* Try setting default values, check that the all string is unaffected + but that the ifset string is affected. */ + for (unsigned i = 0; i < G_N_ELEMENTS(props); ++i) { + char *prop_eq_val = g_strdup_printf("%s:%s", props[i].property, props[i].spec_dfl); + char *exp_set_str = g_strdup_printf("%s:%s", props[i].property, props[i].ink_dfl); + gchar *str0_all = merge_then_write_string(prop_eq_val, SP_STYLE_FLAG_ALWAYS); + gchar *str0_set = merge_then_write_string(prop_eq_val, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(streq(str0_all, str0_all_exp)); + UTEST_ASSERT(streq(str0_set, exp_set_str)); + g_free(str0_set); + g_free(str0_all); + g_free(exp_set_str); + g_free(prop_eq_val); + } + + /* Check that explicit `inherit' is correctly preserved by write(ifset). */ + for (unsigned i = 0; i < G_N_ELEMENTS(props); ++i) { + if (!props[i].can_explicitly_inherit) { + continue; + } + char *prop_eq_val = g_strdup_printf("%s:inherit", props[i].property); + gchar *ifset_str = merge_then_write_string(prop_eq_val, SP_STYLE_FLAG_IFSET); + UTEST_ASSERT(streq(ifset_str, prop_eq_val)); + g_free(ifset_str); + g_free(prop_eq_val); + } + + for (unsigned i = 0; i < G_N_ELEMENTS(props); ++i) { + props[i].tst_fn(props[i].property, props[i].tst_fn_arg); + } + } + + test_scale24_mul(); + test_merge_opacity(); + + return utest_end(); +} + +int main() +{ + return ( test_style() + ? EXIT_SUCCESS + : EXIT_FAILURE ); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
