From eb5dda75c40d791687ff67d109c4565762647ca3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 9 Sep 2016 09:20:04 -0700 Subject: [PATCH] Start work on randomized changed-region testing Signed-off-by: Nathan Sobo --- spec/helpers/scope_sequence.cc | 110 +++++++++++++++++++++++++++++++++ spec/helpers/scope_sequence.h | 16 +++++ 2 files changed, 126 insertions(+) create mode 100644 spec/helpers/scope_sequence.cc create mode 100644 spec/helpers/scope_sequence.h diff --git a/spec/helpers/scope_sequence.cc b/spec/helpers/scope_sequence.cc new file mode 100644 index 00000000..32a77bc6 --- /dev/null +++ b/spec/helpers/scope_sequence.cc @@ -0,0 +1,110 @@ +#include "./scope_sequence.h" + +#include "bandit/bandit.h" +#include +#include "helpers/stream_methods.h" +#include "helpers/point_helpers.h" + +using std::string; +using std::cout; + +static void append_text_to_scope_sequence(ScopeSequence *sequence, + ScopeStack *current_scopes, + const std::string &text, + size_t length) { + for (size_t i = 0; i < length; i++) { + string character(1, text[sequence->size()]); + sequence->push_back(*current_scopes); + sequence->back().push_back("'" + character + "'"); + } +} + +static void append_to_scope_sequence(ScopeSequence *sequence, + ScopeStack *current_scopes, + TSNode node, TSDocument *document, + const std::string &text) { + string scope = ts_node_type(node, document); + current_scopes->push_back(scope); + size_t child_count = ts_node_child_count(node); + if (child_count > 0) { + size_t previous_child_end = ts_node_start_char(node); + 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 spacing = child_start - previous_child_end; + append_text_to_scope_sequence(sequence, current_scopes, text, spacing); + append_to_scope_sequence(sequence, current_scopes, child, document, text); + previous_child_end = ts_node_end_char(child); + } + size_t spacing = ts_node_end_char(node) - previous_child_end; + append_text_to_scope_sequence(sequence, current_scopes, text, spacing); + } else { + size_t length = ts_node_end_char(node) - ts_node_start_char(node); + append_text_to_scope_sequence(sequence, current_scopes, text, length); + } + current_scopes->pop_back(); +} + +ScopeSequence build_scope_sequence(TSDocument *document, const std::string &text) { + ScopeSequence sequence; + ScopeStack current_scopes; + TSNode node = ts_document_root_node(document); + append_to_scope_sequence(&sequence, ¤t_scopes, node, document, text); + AssertThat(sequence.size(), Equals(text.size())); + return sequence; +} + +bool operator<=(const TSPoint &left, const TSPoint &right) { + if (left.row < right.row) + return true; + else if (left.row == right.row) + return left.column <= right.column; + else + return false; +} + +void verify_changed_ranges(const ScopeSequence &old_sequence, const ScopeSequence &new_sequence, + const string &text, TSRange *ranges, size_t range_count) { + TSPoint current_position = {0, 0}; + for (size_t i = 0; i < text.size(); i++) { + if (text[i] == '\n') { + current_position.row++; + current_position.column = 0; + continue; + } + + const ScopeStack &old_scopes = old_sequence[i]; + const ScopeStack &new_scopes = new_sequence[i]; + if (old_scopes != new_scopes) { + bool found_containing_range = false; + for (size_t j = 0; j < range_count; j++) { + TSRange range = ranges[j]; + if (range.start <= current_position && current_position <= range.end) { + found_containing_range = true; + break; + } + } + + if (!found_containing_range) { + std::stringstream message_stream; + message_stream << "Found changed scope outside of any invalidated range;\n"; + message_stream << "Position: " << current_position << "\n"; + size_t line_start_index = i - current_position.column; + size_t line_end_index = text.find_first_of('\n', i); + message_stream << "Line: " << text.substr(line_start_index, line_end_index - line_start_index) << "\n"; + for (size_t j = 0; j < current_position.column + string("Line: ").size(); j++) + message_stream << " "; + message_stream << "^\n"; + message_stream << "Old scopes: " << old_scopes << "\n"; + message_stream << "New scopes: " << new_scopes << "\n"; + message_stream << "Invalidated ranges:\n"; + for (size_t j = 0; j < range_count; j++) { + message_stream << " " << ranges[i] << "\n"; + } + Assert::Failure(message_stream.str()); + } + } + + current_position.column++; + } +} diff --git a/spec/helpers/scope_sequence.h b/spec/helpers/scope_sequence.h new file mode 100644 index 00000000..c83ad597 --- /dev/null +++ b/spec/helpers/scope_sequence.h @@ -0,0 +1,16 @@ +#ifndef HELPERS_SCOPE_SEQUENCE_H_ +#define HELPERS_SCOPE_SEQUENCE_H_ + +#include +#include +#include "tree_sitter/runtime.h" + +typedef std::string Scope; +typedef std::vector ScopeStack; +typedef std::vector ScopeSequence; + +ScopeSequence build_scope_sequence(TSDocument *document, const std::string &text); + +void verify_changed_ranges(const ScopeSequence &old, const ScopeSequence &new_sequence, const std::string &text, TSRange *ranges, size_t range_count); + +#endif // HELPERS_SCOPE_SEQUENCE_H_