diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-05 21:17:24 -0700 |
commit | b96af395b9af2ff9df94b3e82213171f30827c8d (patch) | |
tree | 17c8c12648ccc25625e2534ec8d74fbe8f1542cc /cpp/050scenario.cc | |
parent | 2e3b597fe85b654e82b891c22d50754fa5a26156 (diff) | |
download | mu-b96af395b9af2ff9df94b3e82213171f30827c8d.tar.gz |
1276 - make C++ version the default
I've tried to update the Readme, but there are at least a couple of issues.
Diffstat (limited to 'cpp/050scenario.cc')
-rw-r--r-- | cpp/050scenario.cc | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/cpp/050scenario.cc b/cpp/050scenario.cc deleted file mode 100644 index 07279d39..00000000 --- a/cpp/050scenario.cc +++ /dev/null @@ -1,477 +0,0 @@ -//: Mu scenarios. This will get long, but these are the tests we want to -//: support in this layer. - -//: You can use variable names in scenarios, but for the most part we'll use -//: raw location numbers, because that lets us make assertions on memory. -//: Tests should avoid abstraction as far as possible. -:(scenarios run_mu_scenario) -:(scenario scenario_block) -scenario foo [ - run [ - 1:integer <- copy 13:literal - ] - memory-should-contain [ - 1 <- 13 - ] -] -# checks are inside scenario - -:(scenario scenario_multiple_blocks) -scenario foo [ - run [ - 1:integer <- copy 13:literal - ] - memory-should-contain [ - 1 <- 13 - ] - run [ - 2:integer <- copy 13:literal - ] - memory-should-contain [ - 1 <- 13 - 2 <- 13 - ] -] - -:(scenario scenario_check_memory_and_trace) -scenario foo [ - run [ - 1:integer <- copy 13:literal - trace [a], [a b c] - ] - memory-should-contain [ - 1 <- 13 - ] - trace-should-contain [ - a: a b c - ] - trace-should-not-contain [ - a: x y z - ] -] - -//:: Core data structure - -:(before "End Types") -struct scenario { - string name; - string to_run; -}; - -:(before "End Globals") -vector<scenario> Scenarios; - -//:: Parse the 'scenario' form. -//: Simply store the text of the scenario. - -:(before "End Command Handlers") -else if (command == "scenario") { - Scenarios.push_back(parse_scenario(in)); -} - -:(code) -scenario parse_scenario(istream& in) { - scenario result; - result.name = next_word(in); - skip_bracket(in, "'scenario' must begin with '['"); - ostringstream buffer; - slurp_until_matching_bracket(in, buffer); - result.to_run = buffer.str(); - return result; -} - -//:: Run scenarios when we run 'mu test'. -//: Treat the text of the scenario as a regular series of instructions. - -:(before "End Tests") -time_t mu_time; time(&mu_time); -cerr << "\nMu tests: " << ctime(&mu_time); -for (index_t i = 0; i < Scenarios.size(); ++i) { -//? cerr << Passed << '\n'; //? 1 - run_mu_scenario(Scenarios[i]); - if (Passed) cerr << "."; -} - -:(before "End Globals") -const scenario* Current_scenario = NULL; -:(code) -void run_mu_scenario(const scenario& s) { - Current_scenario = &s; - bool not_already_inside_test = !Trace_stream; - if (not_already_inside_test) { - Trace_file = s.name; - Trace_stream = new trace_stream; - setup(); - } - run("recipe "+s.name+" [ " + s.to_run + " ]"); - if (not_already_inside_test) { - teardown(); - ofstream fout((Trace_dir+Trace_file).c_str()); - fout << Trace_stream->readable_contents(""); - fout.close(); - delete Trace_stream; - Trace_stream = NULL; - Trace_file = ""; - } - Current_scenario = NULL; -} - -//:: The special instructions we want to support inside scenarios. -//: In a compiler for the mu VM these will require more work. - -//: 'run' interprets a string as a set of instructions - -:(scenarios run) -:(scenario run) -#? % Trace_stream->dump_layer = "all"; -recipe main [ - run [ - 1:integer <- copy 13:literal - ] -] -+mem: storing 13 in location 1 - -:(before "End Primitive Recipe Declarations") -RUN, -:(before "End Primitive Recipe Numbers") -Recipe_number["run"] = RUN; -:(before "End Primitive Recipe Implementations") -case RUN: { -//? cout << "recipe " << current_instruction().ingredients[0].name << '\n'; //? 1 - ostringstream tmp; - tmp << "recipe run" << Next_recipe_number << " [ " << current_instruction().ingredients[0].name << " ]"; -//? Show_rest_of_stream = true; //? 1 - vector<recipe_number> tmp_recipe = load(tmp.str()); - // Predefined Scenario Locals In Run. - // End Predefined Scenario Locals In Run. - transform_all(); -//? cout << tmp_recipe[0] << ' ' << Recipe_number["main"] << '\n'; //? 1 - Current_routine->calls.push(call(tmp_recipe[0])); - continue; // not done with caller; don't increment current_step_index() -} - -:(scenario run_multiple) -recipe main [ - run [ - 1:integer <- copy 13:literal - ] - run [ - 2:integer <- copy 13:literal - ] -] -+mem: storing 13 in location 1 -+mem: storing 13 in location 2 - -//: 'memory-should-contain' raises warnings if specific locations aren't as expected -//: Also includes some special support for checking strings. - -:(scenario memory_check) -% Hide_warnings = true; -recipe main [ - memory-should-contain [ - 1 <- 13 - ] -] -+run: checking location 1 -+warn: expected location 1 to contain 13 but saw 0 - -:(before "End Primitive Recipe Declarations") -MEMORY_SHOULD_CONTAIN, -:(before "End Primitive Recipe Numbers") -Recipe_number["memory-should-contain"] = MEMORY_SHOULD_CONTAIN; -:(before "End Primitive Recipe Implementations") -case MEMORY_SHOULD_CONTAIN: { -//? cout << current_instruction().ingredients[0].name << '\n'; //? 1 - check_memory(current_instruction().ingredients[0].name); - break; -} - -:(code) -void check_memory(const string& s) { - istringstream in(s); - in >> std::noskipws; - set<index_t> locations_checked; - while (true) { - skip_whitespace_and_comments(in); - if (in.eof()) break; - string lhs = next_word(in); - if (!is_number(lhs)) { - check_type(lhs, in); - continue; - } - int address = to_int(lhs); - skip_whitespace_and_comments(in); - string _assign; in >> _assign; assert(_assign == "<-"); - skip_whitespace_and_comments(in); - int value = 0; in >> value; - if (locations_checked.find(address) != locations_checked.end()) - raise << "duplicate expectation for location " << address << '\n'; - trace("run") << "checking location " << address; - if (Memory[address] != value) { - if (Current_scenario) - raise << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n'; - else - raise << "expected location " << address << " to contain " << value << " but saw " << Memory[address] << '\n'; - Passed = false; - return; - } - locations_checked.insert(address); - } -} - -void check_type(const string& lhs, istream& in) { - reagent x(lhs); - if (x.properties[0].second[0] == "string") { - x.set_value(to_int(x.name)); - skip_whitespace_and_comments(in); - string _assign = next_word(in); - assert(_assign == "<-"); - skip_whitespace_and_comments(in); - string literal = next_word(in); - index_t address = x.value; - // exclude quoting brackets - assert(literal[0] == '['); literal.erase(0, 1); - assert(literal[literal.size()-1] == ']'); literal.erase(literal.size()-1); - check_string(address, literal); - return; - } - raise << "don't know how to check memory for " << lhs << '\n'; -} - -void check_string(index_t address, const string& literal) { - trace("run") << "checking string length at " << address; - if (Memory[address] != static_cast<signed>(literal.size())) - raise << "expected location " << address << " to contain length " << literal.size() << " of string [" << literal << "] but saw " << Memory[address] << '\n'; - ++address; // now skip length - for (index_t i = 0; i < literal.size(); ++i) { - trace("run") << "checking location " << address+i; - if (Memory[address+i] != literal[i]) - raise << "expected location " << (address+i) << " to contain " << literal[i] << " but saw " << Memory[address+i] << '\n'; - } -} - -:(scenario memory_check_multiple) -% Hide_warnings = true; -recipe main [ - memory-should-contain [ - 1 <- 0 - 1 <- 0 - ] -] -+warn: duplicate expectation for location 1 - -:(scenario memory_check_string_length) -% Hide_warnings = true; -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 97:literal # 'a' - 3:integer <- copy 98:literal # 'b' - 4:integer <- copy 99:literal # 'c' - memory-should-contain [ - 1:string <- [ab] - ] -] -+warn: expected location 1 to contain length 2 of string [ab] but saw 3 - -:(scenario memory_check_string) -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 97:literal # 'a' - 3:integer <- copy 98:literal # 'b' - 4:integer <- copy 99:literal # 'c' - memory-should-contain [ - 1:string <- [abc] - ] -] -+run: checking string length at 1 -+run: checking location 2 -+run: checking location 3 -+run: checking location 4 - -:(code) -//: 'trace-should-contain' is like the '+' lines in our scenarios so far -// Like runs of contiguous '+' lines, order is important. The trace checks -// that the lines are present *and* in the specified sequence. (There can be -// other lines in between.) - -:(scenario trace_check_warns_on_failure) -% Hide_warnings = true; -recipe main [ - trace-should-contain [ - a: b - a: d - ] -] -+warn: missing [b] in trace layer a - -:(before "End Primitive Recipe Declarations") -TRACE_SHOULD_CONTAIN, -:(before "End Primitive Recipe Numbers") -Recipe_number["trace-should-contain"] = TRACE_SHOULD_CONTAIN; -:(before "End Primitive Recipe Implementations") -case TRACE_SHOULD_CONTAIN: { - check_trace(current_instruction().ingredients[0].name); - break; -} - -:(code) -// simplified version of check_trace_contents() that emits warnings rather -// than just printing to stderr -bool check_trace(const string& expected) { - Trace_stream->newline(); - vector<pair<string, string> > expected_lines = parse_trace(expected); - if (expected_lines.empty()) return true; - index_t curr_expected_line = 0; - for (vector<pair<string, pair<int, string> > >::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { - if (expected_lines[curr_expected_line].first != p->first) continue; - if (expected_lines[curr_expected_line].second != p->second.second) continue; - // match - ++curr_expected_line; - if (curr_expected_line == expected_lines.size()) return true; - } - - raise << "missing [" << expected_lines[curr_expected_line].second << "] " - << "in trace layer " << expected_lines[curr_expected_line].first << '\n'; - Passed = false; - return false; -} - -vector<pair<string, string> > parse_trace(const string& expected) { - vector<string> buf = split(expected, "\n"); - vector<pair<string, string> > result; - for (index_t i = 0; i < buf.size(); ++i) { - buf[i] = trim(buf[i]); - if (buf[i].empty()) continue; - index_t delim = buf[i].find(": "); - result.push_back(pair<string, string>(buf[i].substr(0, delim), buf[i].substr(delim+2))); - } - return result; -} - -:(scenario trace_check_warns_on_failure_in_later_line) -% Hide_warnings = true; -recipe main [ - run [ - trace [a], [b] - ] - trace-should-contain [ - a: b - a: d - ] -] -+warn: missing [d] in trace layer a - -:(scenario trace_check_passes_silently) -% Hide_warnings = true; -recipe main [ - run [ - trace [a], [b] - ] - trace-should-contain [ - a: b - ] -] --warn: missing [b] in trace layer a - -//: 'trace-should-not-contain' is like the '-' lines in our scenarios so far -//: Each trace line is separately checked for absense. Order is *not* -//: important, so you can't say things like "B should not exist after A." - -:(scenario trace_negative_check_warns_on_failure) -% Hide_warnings = true; -recipe main [ - run [ - trace [a], [b] - ] - trace-should-not-contain [ - a: b - ] -] -+warn: unexpected [b] in trace layer a - -:(before "End Primitive Recipe Declarations") -TRACE_SHOULD_NOT_CONTAIN, -:(before "End Primitive Recipe Numbers") -Recipe_number["trace-should-not-contain"] = TRACE_SHOULD_NOT_CONTAIN; -:(before "End Primitive Recipe Implementations") -case TRACE_SHOULD_NOT_CONTAIN: { - check_trace_missing(current_instruction().ingredients[0].name); - break; -} - -:(code) -// simplified version of check_trace_contents() that emits warnings rather -// than just printing to stderr -bool check_trace_missing(const string& in) { - Trace_stream->newline(); - vector<pair<string, string> > lines = parse_trace(in); - for (index_t i = 0; i < lines.size(); ++i) { - if (trace_count(lines[i].first, lines[i].second) != 0) { - raise << "unexpected [" << lines[i].second << "] in trace layer " << lines[i].first << '\n'; - Passed = false; - return false; - } - } - return true; -} - -:(scenario trace_negative_check_passes_silently) -% Hide_warnings = true; -recipe main [ - trace-should-not-contain [ - a: b - ] -] --warn: unexpected [b] in trace layer a - -:(scenario trace_negative_check_warns_on_any_unexpected_line) -% Hide_warnings = true; -recipe main [ - run [ - trace [a], [d] - ] - trace-should-not-contain [ - a: b - a: d - ] -] -+warn: unexpected [d] in trace layer a - -//:: Helpers - -:(code) -// just for the scenarios running scenarios in C++ layers -void run_mu_scenario(const string& form) { - istringstream in(form); - in >> std::noskipws; - string _scenario = next_word(in); -//? cout << _scenario << '\n'; //? 1 - assert(_scenario == "scenario"); - scenario s = parse_scenario(in); - run_mu_scenario(s); -} - -void slurp_until_matching_bracket(istream& in, ostream& out) { - int brace_depth = 1; // just scanned '[' - char c; - while (in >> c) { - if (c == '[') ++brace_depth; - if (c == ']') --brace_depth; - if (brace_depth == 0) break; // drop final ']' - out << c; - } -} - -// see tests for this function in tangle/030tangle.test.cc -string trim(const string& s) { - string::const_iterator first = s.begin(); - while (first != s.end() && isspace(*first)) - ++first; - if (first == s.end()) return ""; - - string::const_iterator last = --s.end(); - while (last != s.begin() && isspace(*last)) - --last; - ++last; - return string(first, last); -} |