#include <stic.h> #include <stdlib.h> #include <test-utils.h> #include "../../src/ui/colored_line.h" #include "../../src/utils/macros.h" #include "../../src/macros.h" static void check_hi(const char pattern[], size_t nmacros, custom_macro_t macros[], int with_opt, const char line[], const char attrs[]); TEST(empty_string_ok) { custom_macro_t macros[] = { { .letter = 'y', .value = "xx", .uses_left = 0, .group = -1, }, }; const char *const pattern = ""; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("", expanded); free(expanded); } TEST(no_macros_ok) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "no match in here"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("no match in here", expanded); free(expanded); } TEST(macro_substitution_works) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "a match here %i"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here xyz", expanded); free(expanded); } TEST(use_negative_count_macro_not_added_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = -1, .group = -1, }, }; const char *const pattern = "a match here, %i, just was"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here, xyz, just was", expanded); free(expanded); } TEST(use_count_0_macro_not_added_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "a match here, %i, just was"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here, xyz, just was", expanded); free(expanded); } TEST(use_count_1_macro_added_once_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 1, .group = -1, }, }; const char *const pattern = "a match here:"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here: xyz", expanded); free(expanded); } TEST(use_count_1_macro_not_added_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 1, .group = -1, }, }; const char *const pattern = "a match here, %i, just was"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here, xyz, just was", expanded); free(expanded); } TEST(use_count_2_macro_added_once_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 2, .group = -1, }, }; const char *const pattern = "a match here, %i, just was,"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("a match here, xyz, just was, xyz", expanded); free(expanded); } TEST(use_count_2_macro_added_twice_implicitly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 2, .group = -1, }, }; const char *const pattern = "matches follow"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("matches follow xyz xyz", expanded); free(expanded); } TEST(unknown_macro_removed) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "the macro %b was here"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("the macro was here", expanded); free(expanded); } TEST(double_percent_handled_correctly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "the percent sign is here: %%"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("the percent sign is here: %", expanded); free(expanded); } TEST(ends_with_percent_ok) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *const pattern = "the percent sign is here: %"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("the percent sign is here: %", expanded); free(expanded); } TEST(first_group_member_are_not_added_when_should_not) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 1, .group = 0, }, { .letter = 'j', .value = "abc", .uses_left = 0, .group = 0, }, }; const char *const pattern = "no i expansion is expected: %j"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("no i expansion is expected: abc", expanded); free(expanded); } TEST(second_group_member_are_not_added_when_should_not) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 1, .group = 0, }, { .letter = 'j', .value = "abc", .uses_left = 0, .group = 0, }, }; const char *const pattern = "no j expansion is expected: %i"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("no j expansion is expected: xyz", expanded); free(expanded); } TEST(first_item_of_group_is_repeated_when_needed) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 1, .group = 0, }, { .letter = 'j', .value = "abc", .uses_left = 0, .group = 0, }, }; const char *const pattern = "i expansion is expected:"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("i expansion is expected: xyz", expanded); free(expanded); } TEST(explicit_use_sets_appropriate_flag) { custom_macro_t macros[] = { { .letter = 'u', .value = "", .uses_left = 1, .group = -1 }, { .letter = 'U', .value = "", .uses_left = 1, .group = -1 }, }; const char *const pattern = "something%u"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_NOOPT); assert_string_equal("something", expanded); free(expanded); assert_true(macros[0].explicit_use); assert_false(macros[1].explicit_use); } TEST(optional_empty) { const char *pattern = "%[%]"; char *expanded = ma_expand_custom(pattern, /*nmacros=*/0, /*macros=*/NULL, MA_OPT); assert_string_equal("", expanded); free(expanded); } TEST(optional_unmatched) { check_hi("%[%1*a", /*nmacros=*/0, /*macros=*/NULL, MA_OPT, "%[a", " b"); } TEST(optional_with_empty_value) { custom_macro_t macros[] = { { .letter = 'n', .value = "" }, { .letter = 't', .value = "bla" }, }; const char *pattern = "before%[ in%nhere %]after"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("beforeafter", expanded); free(expanded); } TEST(optional_with_nonempty_value) { custom_macro_t macros[] = { { .letter = 'n', .value = "-" }, }; const char *pattern = "before%[ in%nhere %]after"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("before in-here after", expanded); free(expanded); } TEST(nested_optional_with_empty_value) { custom_macro_t macros[] = { { .letter = 'n', .value = "" }, }; const char *pattern = "before%[ %[ in%nhere %] %]after"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("beforeafter", expanded); free(expanded); } TEST(nested_optional_with_nonempty_value) { custom_macro_t macros[] = { { .letter = 'n', .value = "-" }, }; const char *pattern = "before%[ %[ in%nhere %] %]after"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("before in-here after", expanded); free(expanded); } TEST(mods_are_applied) { custom_macro_t macros[] = { { .letter = 'd', .value = "/a/b/<c>", .parent = "/", .expand_mods = 1 }, }; const char *pattern = "before%d:tafter"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("before<c>after", expanded); free(expanded); } TEST(empty_flag) { custom_macro_t macros[] = { { .letter = 'e', .value = "", .flag = 1 }, }; const char *pattern = "%[(empty)%e%]"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("", expanded); free(expanded); } TEST(non_empty_flag) { custom_macro_t macros[] = { { .letter = 'n', .value = "value", .flag = 1 }, }; const char *pattern = "%[(non-empty)%n%]"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("(non-empty)", expanded); free(expanded); } TEST(empty_flag_after_mod) { custom_macro_t macros[] = { { .letter = 'd', .value = "/a/b/<c>", .parent = "/", .expand_mods = 1, .flag = 1 }, }; const char *pattern = "%[(empty)%d:t:e%]"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("", expanded); free(expanded); } TEST(non_empty_flag_after_mod) { custom_macro_t macros[] = { { .letter = 'd', .value = "/a/b/<c>", .parent = "/", .expand_mods = 1, .flag = 1 }, }; const char *pattern = "%[(non-empty)%d:t%]"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("(non-empty)", expanded); free(expanded); } TEST(highlighting_is_ignored_by_uncolored_version) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; const char *pattern = "prefix %1*%i%2* suffix"; char *expanded = ma_expand_custom(pattern, ARRAY_LEN(macros), macros, MA_OPT); assert_string_equal("prefix xyz suffix", expanded); free(expanded); } TEST(highlighting_is_set_correctly) { custom_macro_t macros[] = { { .letter = 'i', .value = "xyz", .uses_left = 0, .group = -1, }, }; check_hi("prefix%1* %10*%i%* %20*suffix", ARRAY_LEN(macros), macros, MA_NOOPT, "prefix xyz suffix", " bk au "); } TEST(opt_can_alter_highlighting_only) { custom_macro_t macros[] = { { .letter = 'C', .value = "", .flag = 1, }, }; check_hi("%1*%[%2*%C%]!", ARRAY_LEN(macros), macros, MA_OPT, "!", "b"); macros[0].value = "*"; check_hi("%1*%[%2*%C%]!", ARRAY_LEN(macros), macros, MA_OPT, "!", "c"); } TEST(bad_user_group_remains_in_line_partially) { custom_macro_t macros[1]; check_hi("%100*", 0, macros, MA_NOOPT, "00*", " "); } TEST(empty_optional_drops_attrs) { custom_macro_t macros[1]; check_hi("%1*%[%2*%]%3*", 0, macros, MA_OPT, "", ""); } TEST(non_empty_optional_preserves_attrs) { custom_macro_t macros[] = { { .letter = 't', .value = "file", .uses_left = 0, .group = -1, }, }; check_hi("%1*%[%t%2*%t%]%3*", ARRAY_LEN(macros), macros, MA_OPT, "filefile", "b c "); check_hi("%1*%[%2*%t%3*%t%]%4*", ARRAY_LEN(macros), macros, MA_OPT, "filefile", "c d "); check_hi("%1*%[%2*%t%3*%]%4*", ARRAY_LEN(macros), macros, MA_OPT, "file", "c "); } TEST(wide_characters_do_not_break_highlighting, IF(utf8_locale)) { custom_macro_t macros[1]; check_hi("%1*螺丝 %= 螺%2*丝", 0, macros, MA_NOOPT, "螺丝 螺丝", "b c "); } static void check_hi(const char pattern[], size_t nmacros, custom_macro_t macros[], int with_opt, const char line[], const char attrs[]) { cline_t expanded = ma_expand_colored_custom(pattern, nmacros, macros, with_opt); assert_string_equal(line, expanded.line); assert_string_equal(attrs, expanded.attrs); free(expanded.line); free(expanded.attrs); } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set cinoptions+=t0 filetype=c : */