about summary refs log tree commit diff stats
path: root/cpp/040scenario
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-04-17 09:56:04 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-04-17 09:56:04 -0700
commit9da1b126cc017e14035b94c4615d211e5bc4bb21 (patch)
treea69baf5f6b75be08e68003a725d33cd478659b56 /cpp/040scenario
parentc8087de8d99a4c3c4264eb89e4d0b35a4fb2c816 (diff)
downloadmu-9da1b126cc017e14035b94c4615d211e5bc4bb21.tar.gz
1072
Diffstat (limited to 'cpp/040scenario')
-rw-r--r--cpp/040scenario132
1 files changed, 132 insertions, 0 deletions
diff --git a/cpp/040scenario b/cpp/040scenario
new file mode 100644
index 00000000..c595ce82
--- /dev/null
+++ b/cpp/040scenario
@@ -0,0 +1,132 @@
+//: Allow tests to be written in mu files.
+:(before "End Types")
+struct scenario {
+  string name;
+  string to_run;
+  map<int, int> memory_expectations;
+  // End scenario Fields
+};
+
+:(before "End Globals")
+vector<scenario> Scenarios;
+
+:(before "End Tests")
+time_t mu_time; time(&mu_time);
+cerr << "\nMu tests: " << ctime(&mu_time);
+for (size_t i = 0; i < Scenarios.size(); ++i) {
+  setup();
+  Trace_file = Scenarios[i].name;
+  START_TRACING_UNTIL_END_OF_SCOPE
+//?   Trace_stream->dump_layer = "all"; //? 1
+//?   cout << "Before:\n";  dump_memory(); //? 1
+//?   cout << Scenarios[i].to_run; //? 1
+  run(Scenarios[i].to_run);
+//?   cout << "After:\n";  dump_memory(); //? 1
+  for (map<int, int>::iterator p = Scenarios[i].memory_expectations.begin();
+       p != Scenarios[i].memory_expectations.end();
+       ++p) {
+    if (Memory[p->first] != p->second) {
+      cerr << Scenarios[i].name << ": Expected location " << p->first << " to contain " << p->second << " but saw " << Memory[p->first] << '\n';
+      Passed = false;
+    }
+  }
+  // End Scenario Checks
+  if (Passed) cerr << ".";
+}
+
+:(before "End Command Handlers")
+else if (command == "scenario") {
+//?   cout << "AAA scenario\n"; //? 1
+  Scenarios.push_back(parse_scenario(in));
+}
+
+:(code)
+scenario parse_scenario(istream& in) {
+  scenario x;
+  x.name = next_word(in);
+  trace("parse") << "reading scenario " << x.name;
+  skip_bracket(in, "'scenario' must begin with '['");
+  ostringstream buffer;
+  slurp_until_matching_bracket(in, buffer);
+//?   cout << "inner buffer: ^" << buffer.str() << "$\n"; //? 1
+  istringstream inner(buffer.str());
+  inner >> std::noskipws;
+  while (!inner.eof()) {
+    skip_whitespace_and_comments(inner);
+    string scenario_command = next_word(inner);
+    if (scenario_command.empty() && inner.eof()) break;
+    // Scenario Command Handlers
+    if (scenario_command == "run") {
+      handle_scenario_run_directive(inner, x);
+      trace("parse") << "scenario will run: " << x.to_run;
+    }
+    else if (scenario_command == "memory") {
+      handle_scenario_memory_directive(inner, x);
+    }
+    // End Scenario Command Handlers
+    else {
+      raise << "unknown command in scenario: ^" << scenario_command << "$\n";
+    }
+  }
+  return x;
+}
+
+void handle_scenario_run_directive(istream& in, scenario& result) {
+  skip_bracket(in, "'run' inside scenario must begin with '['");
+  ostringstream buffer;
+  slurp_until_matching_bracket(in, buffer);
+  result.to_run = "recipe test-"+result.name+" [" + buffer.str() + "]";
+}
+
+void handle_scenario_memory_directive(istream& in, scenario& out) {
+  if (next_word(in) != "should") {
+    raise << "'memory' directive inside scenario must continue 'memory should'\n";
+  }
+  if (next_word(in) != "contain") {
+    raise << "'memory' directive inside scenario must continue 'memory should contain'\n";
+  }
+  skip_bracket(in, "'memory' directive inside scenario must begin with 'memory should contain ['\n");
+  while (true) {
+    skip_whitespace_and_comments(in);
+    if (in.eof()) break;
+//?     cout << "a: " << in.peek() << '\n'; //? 1
+    if (in.peek() == ']') break;
+    int address = 0;  in >> address;
+//?     cout << "address: " << address << '\n'; //? 2
+//?     cout << "b: " << in.peek() << '\n'; //? 1
+    skip_whitespace_and_comments(in);
+//?     cout << "c: " << in.peek() << '\n'; //? 1
+    string _assign;  in >> _assign;  assert(_assign == "<-");
+    skip_whitespace_and_comments(in);
+    int value = 0;  in >> value;
+    out.memory_expectations[address] = value;
+    trace("parse") << "memory expectation: *" << address << " == " << value;
+  }
+  skip_whitespace(in);
+  assert(in.get() == ']');
+}
+
+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;
+  }
+}
+
+void skip_bracket(istream& in, string message) {
+  skip_whitespace(in);  skip_comments_and_newlines(in);  skip_whitespace(in);
+  if (in.get() != '[')
+    raise << message << '\n';
+}
+
+void skip_whitespace_and_comments(istream& in) {
+  while (true) {
+    if (isspace(in.peek())) in.get();
+    else if (in.peek() == '#') skip_comment(in);
+    else break;
+  }
+}