From c5ffb6e1cc9c5ff880d037c53b8ebc8562be0008 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 25 May 2015 22:27:19 -0700 Subject: 1459 --- html/072scenario_screen.cc.html | 169 +++++++++++++++++++++++++++++----------- 1 file changed, 122 insertions(+), 47 deletions(-) (limited to 'html/072scenario_screen.cc.html') diff --git a/html/072scenario_screen.cc.html b/html/072scenario_screen.cc.html index 79cc6044..18b70868 100644 --- a/html/072scenario_screen.cc.html +++ b/html/072scenario_screen.cc.html @@ -2,7 +2,7 @@ -~/Desktop/s/mu/072scenario_screen.cc +072scenario_screen.cc @@ -54,6 +54,22 @@ scenario screen-in-scenario [ #? $exit ] +:(scenario screen_in_scenario_unicode) +# screen-should-contain can check unicode characters in the fake screen +scenario screen-in-scenario [ + assume-screen 5:literal/width, 3:literal/height + run [ + screen:address <- print-character screen:address, 955:literal # 'λ' + ] + screen-should-contain [ + # 01234 + .λ . + . . + . . + ] +#? $exit +] + :(scenario screen_in_scenario_error) #? % cerr << "AAA\n"; % Hide_warnings = true; @@ -69,14 +85,18 @@ scenario screen-in-scenario-error [ . . ] ] -+warn: expected screen location (0, 0) to contain 'b' instead of 'a' ++warn: expected screen location (0, 0) to contain 98 ('b') instead of 97 ('a') + +//: allow naming just for 'screen' +:(before "End is_special_name Cases") +if (s == "screen") return true; :(before "End Globals") // Scenarios may not define default-space, so they should fit within the // initial area of memory reserved for tests. We'll put the predefined // variables available to them at the end of that region. -const size_t Max_variables_in_scenarios = Reserved_for_tests-100; -size_t Next_predefined_global_for_scenarios = Max_variables_in_scenarios; +const long long int Max_variables_in_scenarios = Reserved_for_tests-100; +long long int Next_predefined_global_for_scenarios = Max_variables_in_scenarios; :(before "End Setup") assert(Next_predefined_global_for_scenarios < Reserved_for_tests); :(after "transform_all()" following "case RUN:") @@ -87,7 +107,7 @@ assert(Name[tmp_recipe.:(before "End Globals") // Scenario Globals. -const size_t SCREEN = Next_predefined_global_for_scenarios++; +const long long int SCREEN = Next_predefined_global_for_scenarios++; // End Scenario Globals. :(before "End Predefined Scenario Locals In Run") Name[tmp_recipe.at(0)]["screen"] = SCREEN; @@ -117,53 +137,65 @@ case SCREEN_SHOULD_CONTAIN: { break; } +:(before "End Types") +// scan an array of characters in a unicode-aware, bounds-checked manner +struct raw_string_stream { + long long int index; + const long long int max; + const char* buf; + + raw_string_stream(const string&); + uint32_t get(); // unicode codepoint + uint32_t peek(); // unicode codepoint + bool at_end() const; + void skip_whitespace_and_comments(); +}; + :(code) -void check_screen(const string& contents) { +void check_screen(const string& expected_contents) { //? cerr << "Checking screen\n"; //? 1 assert(!Current_routine->calls.front().default_space); // not supported - index_t screen_location = Memory[SCREEN]; + long long int screen_location = Memory[SCREEN]; int data_offset = find_element_name(Type_number["screen"], "data"); assert(data_offset >= 0); - index_t screen_data_location = screen_location+data_offset; // type: address:array:character - index_t screen_data_start = Memory[screen_data_location]; // type: array:character + long long int screen_data_location = screen_location+data_offset; // type: address:array:character + long long int screen_data_start = Memory[screen_data_location]; // type: array:character int width_offset = find_element_name(Type_number["screen"], "num-columns"); - size_t screen_width = Memory[screen_location+width_offset]; + long long int screen_width = Memory[screen_location+width_offset]; int height_offset = find_element_name(Type_number["screen"], "num-rows"); - size_t screen_height = Memory[screen_location+height_offset]; - string expected_contents; - istringstream in(contents); - in >> std::noskipws; - for (index_t row = 0; row < screen_height; ++row) { - skip_whitespace_and_comments(in); - assert(!in.eof()); - assert(in.get() == '.'); - for (index_t column = 0; column < screen_width; ++column) { - assert(!in.eof()); - expected_contents += in.get(); - } - assert(in.get() == '.'); - } - skip_whitespace_and_comments(in); -//? assert(in.get() == ']'); - trace("run") << "checking screen size at " << screen_data_start; -//? cout << expected_contents.size() << '\n'; //? 1 - if (Memory[screen_data_start] > static_cast<signed>(expected_contents.size())) - raise << "expected contents are larger than screen size " << Memory[screen_data_start] << '\n'; - ++screen_data_start; // now skip length - for (index_t i = 0; i < expected_contents.size(); ++i) { - trace("run") << "checking location " << screen_data_start+i; -//? cerr << "comparing " << i/screen_width << ", " << i%screen_width << ": " << Memory[screen_data_start+i] << " vs " << (int)expected_contents.at(i) << '\n'; //? 1 - if ((!Memory[screen_data_start+i] && !isspace(expected_contents.at(i))) // uninitialized memory => spaces - || (Memory[screen_data_start+i] && Memory[screen_data_start+i] != expected_contents.at(i))) { -//? cerr << "CCC " << Trace_stream << " " << Hide_warnings << '\n'; //? 1 + long long int screen_height = Memory[screen_location+height_offset]; + raw_string_stream cursor(expected_contents); + // todo: too-long expected_contents should fail + long long int addr = screen_data_start+1; // skip length + for (long long int row = 0; row < screen_height; ++row) { + cursor.skip_whitespace_and_comments(); + if (cursor.at_end()) break; + assert(cursor.get() == '.'); + for (long long int column = 0; column < screen_width; ++column, ++addr) { + uint32_t curr = cursor.get(); + if (Memory[addr] == 0 && isspace(curr)) continue; + if (Memory[addr] != 0 && Memory[addr] == curr) continue; + // mismatch + // can't print multi-byte unicode characters in warnings just yet. not very useful for debugging anyway. + char expected_pretty[10] = {0}; + if (curr < 256) { + // " ('<curr>')" + expected_pretty[0] = ' ', expected_pretty[1] = '(', expected_pretty[2] = '\'', expected_pretty[3] = static_cast<unsigned char>(curr), expected_pretty[4] = '\'', expected_pretty[5] = ')', expected_pretty[6] = '\0'; + } + char actual_pretty[10] = {0}; + if (Memory[addr] < 256) { + // " ('<curr>')" + actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(Memory[addr]), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0'; + } + if (Current_scenario && !Hide_warnings) { // genuine test in a mu file - raise << "\nF - " << Current_scenario->name << ": expected screen location (" << i/screen_width << ", " << i%screen_width << ") to contain '" << expected_contents.at(i) << "' instead of '" << static_cast<char>(Memory[screen_data_start+i]) << "'\n"; + raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << Memory[addr] << actual_pretty << "'\n"; dump_screen(); } else { // just testing check_screen - raise << "expected screen location (" << i/screen_width << ", " << i%screen_width << ") to contain '" << expected_contents.at(i) << "' instead of '" << static_cast<char>(Memory[screen_data_start+i]) << "'\n"; + raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << Memory[addr] << actual_pretty << '\n'; } if (!Hide_warnings) { Passed = false; @@ -171,6 +203,49 @@ void check_screen(const string& contents} return; } + assert(cursor.get() == '.'); + } + cursor.skip_whitespace_and_comments(); + assert(cursor.at_end()); +} + +raw_string_stream::raw_string_stream(const string& backing) :index(0), max(backing.size()), buf(backing.c_str()) {} + +bool raw_string_stream::at_end() const { + if (index >= max) return true; + if (tb_utf8_char_length(buf[index]) > max-index) { + raise << "unicode string seems corrupted at index "<< index << " character " << static_cast<int>(buf[index]) << '\n'; + return true; + } + return false; +} + +uint32_t raw_string_stream::get() { + assert(index < max); // caller must check bounds before calling 'get' + uint32_t result = 0; + int length = tb_utf8_char_to_unicode(&result, &buf[index]); + assert(length != TB_EOF); + index += length; + return result; +} + +uint32_t raw_string_stream::peek() { + assert(index < max); // caller must check bounds before calling 'get' + uint32_t result = 0; + int length = tb_utf8_char_to_unicode(&result, &buf[index]); + assert(length != TB_EOF); + return result; +} + +void raw_string_stream::skip_whitespace_and_comments() { + while (!at_end()) { + if (isspace(peek())) get(); + else if (peek() == '#') { + // skip comment + get(); + while (peek() != '\n') get(); // implicitly also handles CRLF + } + else break; } } @@ -187,21 +262,21 @@ case _DUMP_SCREEN: { :(code) void dump_screen() { assert(!Current_routine->calls.front().default_space); // not supported - index_t screen_location = Memory[SCREEN]; + long long int screen_location = Memory[SCREEN]; int width_offset = find_element_name(Type_number["screen"], "num-columns"); - size_t screen_width = Memory[screen_location+width_offset]; + long long int screen_width = Memory[screen_location+width_offset]; int height_offset = find_element_name(Type_number["screen"], "num-rows"); - size_t screen_height = Memory[screen_location+height_offset]; + long long int screen_height = Memory[screen_location+height_offset]; int data_offset = find_element_name(Type_number["screen"], "data"); assert(data_offset >= 0); - index_t screen_data_location = screen_location+data_offset; // type: address:array:character - index_t screen_data_start = Memory[screen_data_location]; // type: array:character + long long int screen_data_location = screen_location+data_offset; // type: address:array:character + long long int screen_data_start = Memory[screen_data_location]; // type: array:character //? cerr << "data start: " << screen_data_start << '\n'; //? 1 assert(Memory[screen_data_start] == screen_width*screen_height); - index_t curr = screen_data_start+1; // skip length - for (index_t row = 0; row < screen_height; ++row) { + long long int curr = screen_data_start+1; // skip length + for (long long int row = 0; row < screen_height; ++row) { //? cerr << curr << ":\n"; //? 1 - for (index_t col = 0; col < screen_width; ++col) { + for (long long int col = 0; col < screen_width; ++col) { cerr << static_cast<char>(Memory[curr]); ++curr; } -- cgit 1.4.1-2-gfad0