From 2c2c567a2945aba2ba2f6509925748be01bf698e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 9 Dec 2015 12:35:11 -0800 Subject: [PATCH] Improve randomized edits in corpus specs --- spec/runtime/language_specs.cc | 206 ++++++++++++++++++++------------- 1 file changed, 128 insertions(+), 78 deletions(-) diff --git a/spec/runtime/language_specs.cc b/spec/runtime/language_specs.cc index 105ff540..169f7c19 100644 --- a/spec/runtime/language_specs.cc +++ b/spec/runtime/language_specs.cc @@ -1,5 +1,7 @@ #include "runtime/runtime_spec_helper.h" #include +#include +#include #include "runtime/length.h" #include "runtime/helpers/read_test_entries.h" #include "runtime/helpers/spy_input.h" @@ -13,44 +15,6 @@ extern "C" const TSLanguage *ts_language_golang(); extern "C" const TSLanguage *ts_language_c(); extern "C" const TSLanguage *ts_language_cpp(); -void expect_the_correct_tree(TSNode node, TSDocument *doc, string tree_string) { - const char *node_string = ts_node_string(node, doc); - AssertThat(node_string, Equals(tree_string)); - free((void *)node_string); -} - -void expect_a_consistent_tree(TSNode node, TSDocument *doc) { - size_t child_count = ts_node_child_count(node); - size_t start = ts_node_start_char(node); - size_t end = ts_node_end_char(node); - TSPoint start_point = ts_node_start_point(node); - TSPoint end_point = ts_node_end_point(node); - - bool has_changes = ts_node_has_changes(node); - bool some_child_has_changes = false; - - for (size_t i = 0; i < child_count; i++) { - TSNode child = ts_node_child(node, i); - size_t child_start = ts_node_start_char(child); - size_t child_end = ts_node_end_char(child); - TSPoint child_start_point = ts_node_start_point(child); - TSPoint child_end_point = ts_node_end_point(child); - - AssertThat(child_start, IsGreaterThan(start) || Equals(start)); - AssertThat(child_end, IsLessThan(end) || Equals(end)); - AssertThat(child_start_point, IsGreaterThan(start_point) || Equals(start_point)); - AssertThat(child_end_point, IsLessThan(end_point) || Equals(end_point)); - - if (ts_node_has_changes(child)) - some_child_has_changes = true; - } - - if (child_count > 0) - AssertThat(has_changes, Equals(some_child_has_changes)); -} - -START_TEST - map languages({ {"json", ts_language_json()}, {"arithmetic", ts_language_arithmetic()}, @@ -60,22 +24,100 @@ map languages({ {"cpp", ts_language_cpp()}, }); +void expect_the_correct_tree(TSNode node, TSDocument *doc, string tree_string) { + const char *node_string = ts_node_string(node, doc); + AssertThat(node_string, Equals(tree_string)); + free((void *)node_string); +} + +void expect_a_consistent_tree(TSNode node, TSDocument *doc) { + size_t child_count = ts_node_child_count(node); + size_t start_char = ts_node_start_char(node); + size_t end_char = ts_node_end_char(node); + TSPoint start_point = ts_node_start_point(node); + TSPoint end_point = ts_node_end_point(node); + bool has_changes = ts_node_has_changes(node); + bool some_child_has_changes = false; + + AssertThat(start_char, !IsGreaterThan(end_char)); + AssertThat(start_point, !IsGreaterThan(end_point)); + + size_t last_child_end_char = 0; + TSPoint last_child_end_point = {0, 0}; + + for (size_t i = 0; i < child_count; i++) { + TSNode child = ts_node_child(node, i); + size_t child_start_char = ts_node_start_char(child); + size_t child_end_char = ts_node_end_char(child); + TSPoint child_start_point = ts_node_start_point(child); + TSPoint child_end_point = ts_node_end_point(child); + + if (i > 0) { + AssertThat(child_start_char, !IsLessThan(last_child_end_char)); + AssertThat(child_start_point, !IsLessThan(last_child_end_point)); + last_child_end_char = child_end_char; + last_child_end_point = child_end_point; + } + + AssertThat(child_start_char, !IsLessThan(start_char)); + AssertThat(child_end_char, !IsGreaterThan(end_char)); + AssertThat(child_start_point, !IsLessThan(start_point)); + AssertThat(child_end_point, !IsGreaterThan(end_point)); + + expect_a_consistent_tree(child, doc); + + if (ts_node_has_changes(child)) + some_child_has_changes = true; + } + + if (child_count > 0) + AssertThat(has_changes, Equals(some_child_has_changes)); +} + +string random_string(char min, char max) { + string result; + size_t length = rand() % 12; + for (size_t i = 0; i < length; i++) { + char inserted_char = min + (rand() % (max - min)); + result += inserted_char; + } + return result; +} + +string random_char(string characters) { + size_t index = rand() % characters.size(); + return string() + characters[index]; +} + +string random_words(size_t count) { + string result; + for (size_t i = 0; i < count; i++) { + if (!result.empty() && rand() % 2 > 0) + result += " "; + if (rand() % 10 < 5) + result += random_char("!(){}[]<>+-="); + else + result += random_string('a', 'z'); + } + return result; +} + +START_TEST + describe("Languages", [&]() { - TSDocument *doc; - - before_each([&]() { - doc = ts_document_make(); - }); - - after_each([&]() { - ts_document_free(doc); - }); + srand(0); for (const auto &pair : languages) { describe(("The " + pair.first + " parser").c_str(), [&]() { + TSDocument *doc; + before_each([&]() { + doc = ts_document_make(); ts_document_set_language(doc, pair.second); - // ts_document_set_debugger(doc, log_debugger_make(false)); + }); + + after_each([&]() { + ts_document_free(doc); }); for (auto &entry : test_entries_for_language(pair.first)) { @@ -97,49 +139,57 @@ describe("Languages", [&]() { ts_document_parse(doc); }); - srand(2); + std::set> deletions; + std::set> insertions; - for (int i = 0; i < 5; i++) { + for (size_t i = 0; i < 50; i++) { size_t edit_position = rand() % entry.input.size(); - size_t deletion_amount = rand() % (entry.input.size() - edit_position); - string pos_string = to_string(edit_position); + size_t deletion_size = rand() % (entry.input.size() - edit_position); + string inserted_text = random_words(rand() % 4 + 1); - it_handles_edit_sequence("repairing an inserted error at " + pos_string, [&]() { - ts_document_edit(doc, input->replace(edit_position, 0, "%^&*")); - ts_document_parse(doc); + if (insertions.insert({edit_position, inserted_text}).second) { + string description = "'" + inserted_text + "' at " + to_string(edit_position); - ts_document_edit(doc, input->undo()); - ts_document_parse(doc); - }); + it_handles_edit_sequence("repairing an insertion of " + description, [&]() { + ts_document_edit(doc, input->replace(edit_position, 0, inserted_text)); + ts_document_parse(doc); - it_handles_edit_sequence("creating and repairing an inserted error at " + pos_string, [&]() { - ts_document_parse(doc); + ts_document_edit(doc, input->undo()); + ts_document_parse(doc); + }); - ts_document_edit(doc, input->replace(edit_position, 0, "%^&*")); + it_handles_edit_sequence("performing and repairing an insertion of " + description, [&]() { + ts_document_parse(doc); - ts_document_parse(doc); + ts_document_edit(doc, input->replace(edit_position, 0, inserted_text)); + ts_document_parse(doc); - ts_document_edit(doc, input->undo()); - ts_document_parse(doc); - }); + ts_document_edit(doc, input->undo()); + ts_document_parse(doc); + }); + } - it_handles_edit_sequence("repairing an errant deletion at " + pos_string, [&]() { - ts_document_parse(doc); + if (deletions.insert({edit_position, deletion_size}).second) { + string desription = to_string(edit_position) + "-" + to_string(edit_position + deletion_size); - ts_document_edit(doc, input->replace(edit_position, deletion_amount, "")); - ts_document_parse(doc); + it_handles_edit_sequence("repairing a deletion of " + desription, [&]() { + ts_document_edit(doc, input->replace(edit_position, deletion_size, "")); + ts_document_parse(doc); - ts_document_edit(doc, input->undo()); - ts_document_parse(doc); - }); + ts_document_edit(doc, input->undo()); + ts_document_parse(doc); + }); - it_handles_edit_sequence("creating and repairing an errant deletion at " + pos_string, [&]() { - ts_document_edit(doc, input->replace(edit_position, deletion_amount, "")); - ts_document_parse(doc); + it_handles_edit_sequence("performing and repairing a deletion of " + desription, [&]() { + ts_document_parse(doc); - ts_document_edit(doc, input->undo()); - ts_document_parse(doc); - }); + ts_document_edit(doc, input->replace(edit_position, deletion_size, "")); + ts_document_parse(doc); + + ts_document_edit(doc, input->undo()); + ts_document_parse(doc); + }); + } } } });