about summary refs log tree commit diff stats
path: root/cpp/050scenario
blob: c595ce823963d93a22c8941f2f2073e062c060ef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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;
  }
}