void test_tangle() { istringstream in("a\n" "b\n" "c\n" ":(before b)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "d" "b" "c"); } void test_tangle_with_linenumber() { istringstream in("a\n" "b\n" "c\n" ":(before b)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "#line 1" "a" "#line 5" "d" "#line 2" "b" "c"); // no other #line directives CHECK_TRACE_DOESNT_CONTAIN("tangle", "#line 3"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "#line 4"); } void test_tangle_linenumbers_with_filename() { istringstream in("a\n" "b\n" "c\n" ":(before b)\n" "d\n"); list dummy; tangle(in, "foo", dummy); CHECK_TRACE_CONTENTS("tangle", "a" "#line 5 \"foo\"" "d" "b" "c"); } void test_tangle_line_numbers_with_multiple_filenames() { istringstream in1("a\n" "b\n" "c"); list dummy; tangle(in1, "foo", dummy); CLEAR_TRACE; istringstream in2(":(before b)\n" "d\n"); tangle(in2, "bar", dummy); CHECK_TRACE_CONTENTS("tangle", "a" "#line 2 \"bar\"" "d" "#line 2 \"foo\"" "b" "c"); } void test_tangle_linenumbers_with_multiple_directives() { istringstream in1("a\n" "b\n" "c"); list dummy; tangle(in1, "foo", dummy); CLEAR_TRACE; istringstream in2(":(before b)\n" "d\n" ":(before c)\n" "e"); tangle(in2, "bar", dummy); CHECK_TRACE_CONTENTS("tangle", "a" "#line 2 \"bar\"" "d" "#line 2 \"foo\"" "b" "#line 4 \"bar\"" "e" "#line 3 \"foo\"" "c"); } void test_tangle_with_multiple_filenames_after() { istringstream in1("a\n" "b\n" "c"); list dummy; tangle(in1, "foo", dummy); CLEAR_TRACE; istringstream in2(":(after b)\n" "d\n"); tangle(in2, "bar", dummy); CHECK_TRACE_CONTENTS("tangle", "a" "b" "#line 2 \"bar\"" "d" "#line 3 \"foo\"" "c"); } void test_tangle_skip_tanglecomments() { istringstream in("a\n" "b\n" "c\n" "//: 1\n" "//: 2\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "b" "c" "" "" "d"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); } void test_tangle_with_tanglecomments_and_directive() { istringstream in("a\n" "//: 1\n" "b\n" "c\n" ":(before b)\n" "d\n" ":(code)\n" "e\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "#line 6" "d" "#line 3" "b" "c" "#line 8" "e"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); } void test_tangle_with_tanglecomments_inside_directive() { istringstream in("a\n" "//: 1\n" "b\n" "c\n" ":(before b)\n" "//: abc\n" "d\n" ":(code)\n" "e\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "#line 7" "d" "#line 3" "b" "c" "#line 9" "e"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "//: 1"); } void test_tangle_with_multiword_directives() { istringstream in("a b\n" "c\n" ":(after \"a b\")\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a b" "d" "c"); } void test_tangle_with_quoted_multiword_directives() { istringstream in("a \"b\"\n" "c\n" ":(after \"a \\\"b\\\"\")\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a \"b\"" "d" "c"); } void test_tangle2() { istringstream in("a\n" "b\n" "c\n" ":(after b)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "b" "d" "c"); } void test_tangle_at_end() { istringstream in("a\n" "b\n" "c\n" ":(after c)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "b" "c" "d"); } void test_tangle_indents_hunks_correctly() { istringstream in("a\n" " b\n" "c\n" ":(after b)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" " b" " d" "c"); } void test_tangle_warns_on_missing_target() { Hide_warnings = true; istringstream in(":(before)\n" "abc def\n"); list lines; tangle(in, lines); CHECK_TRACE_WARNS(); } void test_tangle_warns_on_unknown_target() { Hide_warnings = true; istringstream in(":(before \"foo\")\n" "abc def\n"); list lines; tangle(in, lines); CHECK_TRACE_WARNS(); } void test_tangle_delete_range_of_lines() { istringstream in("a\n" "b {\n" "c\n" "}\n" ":(delete{} \"b\")\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "b"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "c"); } void test_tangle_replace() { istringstream in("a\n" "b\n" "c\n" ":(replace b)\n" "d\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "d" "c"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "b"); } void test_tangle_replace_range_of_lines() { istringstream in("a\n" "b {\n" "c\n" "}\n" ":(replace{} \"b\")\n" "d\n" "e\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "d" "e"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "b {"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "c"); } void test_tangle_replace_tracks_old_lines() { istringstream in("a\n" "b {\n" "c\n" "}\n" ":(replace{} \"b\")\n" "d\n" ":OLD_CONTENTS\n" "e\n"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "d" "c" "e"); CHECK_TRACE_DOESNT_CONTAIN("tangle", "b {"); } void test_tangle_nested_patterns() { istringstream in("a\n" "c\n" "b\n" "c\n" "d\n" ":(after \"b\" then \"c\")\n" "e"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "c" "b" "c" "e" "d"); } void test_tangle_nested_patterns2() { istringstream in("a\n" "c\n" "b\n" "c\n" "d\n" ":(after \"c\" following \"b\")\n" "e"); list dummy; tangle(in, dummy); CHECK_TRACE_CONTENTS("tangle", "a" "c" "b" "c" "e" "d"); } // todo: include line numbers in tangle errors //// scenarios void test_tangle_supports_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" "+layer1: pqr\n" "+layer2: xyz"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_ignores_empty_lines_in_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" "+layer1: pqr\n" " \n" "+layer2: xyz"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_handles_empty_lines_in_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" "\n" "+layer1: pqr\n" "+layer2: xyz"); list lines; tangle(in, lines); // no infinite loop } void test_tangle_supports_configurable_toplevel() { istringstream in(":(scenarios foo)\n" ":(scenario does_bar)\n" "abc def\n" "+layer1: pqr"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " foo("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); istringstream cleanup(":(scenarios run)\n"); tangle(cleanup, lines); } void test_tangle_can_hide_warnings_in_scenarios() { istringstream in(":(scenario does_bar)\n" "% Hide_warnings = true;\n" "abc def\n" "+layer1: pqr\n" "+layer2: xyz"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " Hide_warnings = true;"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_include_c_code_at_end_of_scenario() { istringstream in(":(scenario does_bar)\n" "abc def\n" "+layer1: pqr\n" "+layer2: xyz\n" "% int x = 1;"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " int x = 1;"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_include_c_code_at_end_of_scenario_without_trace_expectations() { istringstream in(":(scenario does_bar)\n" "abc def\n" "% int x = 1;"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " int x = 1;"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_supports_strings_in_scenarios() { istringstream in(":(scenario does_bar)\n" "abc \"def\"\n" "+layer1: pqr\n" "+layer2: \"xyz\""); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc \\\"def\\\"\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: \\\"xyz\\\"\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_supports_strings_in_scenarios2() { istringstream in(":(scenario does_bar)\n" "abc \"\"\n" "+layer1: pqr\n" "+layer2: \"\""); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc \\\"\\\"\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: \\\"\\\"\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_supports_multiline_input_in_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" " efg\n" "+layer1: pqr\n" "+layer2: \"\""); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: \\\"\\\"\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_supports_reset_in_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" "===\n" "efg\n" "+layer1: pqr\n" "+layer2: \"\""); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CLEAR_TRACE;"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: \\\"\\\"\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_check_for_absence_at_end_of_scenarios() { istringstream in(":(scenario does_bar)\n" "abc def\n" " efg\n" "+layer1: pqr\n" "-layer1: xyz"); list lines; tangle(in, lines); //? for (list::iterator p = lines.begin(); p != lines.end(); ++p) //? cerr << p->contents << '\n'; CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_check_for_absence_at_end_of_scenarios2() { istringstream in(":(scenario does_bar)\n" "abc def\n" " efg\n" "-layer1: pqr\n" "-layer1: xyz"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: pqr\");"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: xyz\");"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_check_for_count_in_scenario() { istringstream in(":(scenario does_bar)\n" "abc def\n" " efg\n" "$layer1: 2"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_COUNT(\"layer1\", 2);"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_handle_mu_comments_in_scenario() { istringstream in(":(scenario does_bar)\n" "abc def\n" "# comment1\n" " efg\n" " # indented comment 2\n" "+layer1: pqr\n" "# comment inside expected_trace\n" "+layer1: xyz\n" "# comment after expected trace\n" "-layer1: z\n" "# comment before trace count\n" "$layer1: 2\n" "# comment at end\n" "\n"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"# comment1\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" efg\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \" # indented comment 2\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"layer1: z\");"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_COUNT(\"layer1\", 2);"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } void test_tangle_can_interleave_present_and_absent_lines_to_kludgily_avoid_specifying_order() { istringstream in(":(scenario does_bar)\n" "abc def\n" "+layer1: pqr\n" "-absent\n" "+layer2: xyz"); list lines; tangle(in, lines); CHECK_EQ(lines.front().contents, "void test_does_bar() {"); lines.pop_front(); CHECK_EQ(lines.front().contents, " run("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"abc def\\n\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer1: pqr\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_DOESNT_CONTAIN(\"absent\");"); lines.pop_front(); CHECK_EQ(lines.front().contents, " CHECK_TRACE_CONTENTS("); lines.pop_front(); CHECK_EQ(lines.front().contents, " \"layer2: xyz\""); lines.pop_front(); CHECK_EQ(lines.front().contents, " );"); lines.pop_front(); CHECK_EQ(lines.front().contents, "}"); lines.pop_front(); CHECK(lines.empty()); } //// helpers void test_trim() { CHECK_EQ(trim(""), ""); CHECK_EQ(trim(" "), ""); CHECK_EQ(trim(" "), ""); CHECK_EQ(trim("a"), "a"); CHECK_EQ(trim(" a"), "a"); CHECK_EQ(trim(" a"), "a"); CHECK_EQ(trim(" ab"), "ab"); CHECK_EQ(trim("a "), "a"); CHECK_EQ(trim("a "), "a"); CHECK_EQ(trim("ab "), "ab"); CHECK_EQ(trim(" a "), "a"); CHECK_EQ(trim(" a "), "a"); CHECK_EQ(trim(" ab "), "ab"); } void test_strip_indent() { CHECK_EQ(strip_indent("", 0), ""); CHECK_EQ(strip_indent("", 1), ""); CHECK_EQ(strip_indent("", 3), ""); CHECK_EQ(strip_indent(" ", 0), " "); CHECK_EQ(strip_indent(" a", 0), " a"); CHECK_EQ(strip_indent(" ", 1), ""); CHECK_EQ(strip_indent(" a", 1), "a"); CHECK_EQ(strip_indent(" ", 2), ""); CHECK_EQ(strip_indent(" a", 2), "a"); CHECK_EQ(strip_indent(" ", 0), " "); CHECK_EQ(strip_indent(" a", 0), " a"); CHECK_EQ(strip_indent(" ", 1), " "); CHECK_EQ(strip_indent(" a", 1), " a"); CHECK_EQ(strip_indent(" ", 2), ""); CHECK_EQ(strip_indent(" a", 2), "a"); CHECK_EQ(strip_indent(" ", 3), ""); CHECK_EQ(strip_indent(" a", 3), "a"); }