about summary refs log blame commit diff stats
path: root/cpp/031scenario
blob: c595ce823963d93a22c8941f2f2073e062c060ef (plain) (tree)
1
2
3
4
5
6
7
                                          




                                    
                        





                           

                                          
                                               
          

                                  


                                                
                           
                                               







                                                                                                                                                
                        












                                          




















                                                               
                                                                             













                                                                       
                                                                                  

                                   
                                                                                          
   
                                                                                                     





















                                                                            

                   

                                







                                                                             
                             






                                                
   
 
//: 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;
  }
}