diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-06 00:19:03 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-06 00:19:03 -0700 |
commit | 672e3e50c6ed6de161e40aa256c3fc0f2b1f7cf9 (patch) | |
tree | 5fa3d82e40137b15dec2941a3446e838ce43d3e5 /html/050scenario.cc.html | |
parent | 20d1c9057a559ce8db83bbc2787ca91348bcb16f (diff) | |
download | mu-672e3e50c6ed6de161e40aa256c3fc0f2b1f7cf9.tar.gz |
1279 - colorized rendering of the source files
Diffstat (limited to 'html/050scenario.cc.html')
-rw-r--r-- | html/050scenario.cc.html | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/html/050scenario.cc.html b/html/050scenario.cc.html new file mode 100644 index 00000000..89766a6e --- /dev/null +++ b/html/050scenario.cc.html @@ -0,0 +1,517 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title>~/Desktop/s/mu/050scenario.cc.html</title> +<meta name="Generator" content="Vim/7.4"> +<meta name="plugin-version" content="vim7.4_v1"> +<meta name="syntax" content="cpp"> +<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy="> +<meta name="colorscheme" content="minimal"> +<style type="text/css"> +<!-- +pre { white-space: pre-wrap; font-family: monospace; color: #d0d0d0; background-color: #000000; } +body { font-family: monospace; color: #d0d0d0; background-color: #000000; } +* { font-size: 1em; } +.cSpecial { color: #008000; } +.CommentedCode { color: #6c6c6c; } +.Constant { color: #008080; } +.Comment { color: #8080ff; } +.Delimiter { color: #c000c0; } +.Special { color: #ff6060; } +.Identifier { color: #008080; } +.SalientComment { color: #00ffff; } +.traceAbsent { color: #c00000; } +.traceContains { color: #008000; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="Comment">//: Mu scenarios. This will get long, but these are the tests we want to</span> +<span class="Comment">//: support in this layer.</span> + +<span class="Comment">//: You can use variable names in scenarios, but for the most part we'll use</span> +<span class="Comment">//: raw location numbers, because that lets us make assertions on memory.</span> +<span class="Comment">//: Tests should avoid abstraction as far as possible.</span> +<span class="Delimiter">:(scenarios run_mu_scenario)</span> +<span class="Delimiter">:(scenario scenario_block)</span> +scenario foo [ + run [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">13</span> + ] +] +<span class="Comment"># checks are inside scenario</span> + +<span class="Delimiter">:(scenario scenario_multiple_blocks)</span> +scenario foo [ + run [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">13</span> + ] + run [ + <span class="Constant">2</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">13</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">13</span> + ] +] + +<span class="Delimiter">:(scenario scenario_check_memory_and_trace)</span> +scenario foo [ + run [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + trace [a]<span class="Delimiter">,</span> [a b c] + ] + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">13</span> + ] + trace-should-contain [ + a: a b c + ] + trace-should-not-contain [ + a: x y z + ] +] + +<span class="SalientComment">//:: Core data structure</span> + +<span class="Delimiter">:(before "End Types")</span> +struct scenario <span class="Delimiter">{</span> + string name<span class="Delimiter">;</span> + string to_run<span class="Delimiter">;</span> +<span class="Delimiter">};</span> + +<span class="Delimiter">:(before "End Globals")</span> +vector<scenario> Scenarios<span class="Delimiter">;</span> + +<span class="SalientComment">//:: Parse the 'scenario' form.</span> +<span class="Comment">//: Simply store the text of the scenario.</span> + +<span class="Delimiter">:(before "End Command Handlers")</span> +else if <span class="Delimiter">(</span>command == <span class="Constant">"scenario"</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + Scenarios<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>parse_scenario<span class="Delimiter">(</span>in<span class="Delimiter">));</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(code)</span> +scenario parse_scenario<span class="Delimiter">(</span>istream& in<span class="Delimiter">)</span> <span class="Delimiter">{</span> + scenario result<span class="Delimiter">;</span> + result<span class="Delimiter">.</span>name = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + skip_bracket<span class="Delimiter">(</span>in<span class="Delimiter">,</span> <span class="Constant">"'scenario' must begin with '['"</span><span class="Delimiter">);</span> + ostringstream buffer<span class="Delimiter">;</span> + slurp_until_matching_bracket<span class="Delimiter">(</span>in<span class="Delimiter">,</span> buffer<span class="Delimiter">);</span> + result<span class="Delimiter">.</span>to_run = buffer<span class="Delimiter">.</span>str<span class="Delimiter">();</span> + <span class="Identifier">return</span> result<span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="SalientComment">//:: Run scenarios when we run 'mu test'.</span> +<span class="Comment">//: Treat the text of the scenario as a regular series of instructions.</span> + +<span class="Delimiter">:(before "End Tests")</span> +time_t mu_time<span class="Delimiter">;</span> time<span class="Delimiter">(</span>&mu_time<span class="Delimiter">);</span> +cerr << <span class="Constant">"</span><span class="cSpecial">\n</span><span class="Constant">Mu tests: "</span> << ctime<span class="Delimiter">(</span>&mu_time<span class="Delimiter">);</span> +for <span class="Delimiter">(</span>index_t i = <span class="Constant">0</span><span class="Delimiter">;</span> i < Scenarios<span class="Delimiter">.</span>size<span class="Delimiter">();</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> +<span class="CommentedCode">//? cerr << Passed << '\n'; //? 1</span> + run_mu_scenario<span class="Delimiter">(</span>Scenarios[i]<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>Passed<span class="Delimiter">)</span> cerr << <span class="Constant">"."</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(before "End Globals")</span> +const scenario* Current_scenario = <span class="Constant">NULL</span><span class="Delimiter">;</span> +<span class="Delimiter">:(code)</span> +void run_mu_scenario<span class="Delimiter">(</span>const scenario& s<span class="Delimiter">)</span> <span class="Delimiter">{</span> + Current_scenario = &s<span class="Delimiter">;</span> + bool not_already_inside_test = !Trace_stream<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>not_already_inside_test<span class="Delimiter">)</span> <span class="Delimiter">{</span> + Trace_file = s<span class="Delimiter">.</span>name<span class="Delimiter">;</span> + Trace_stream = new trace_stream<span class="Delimiter">;</span> + setup<span class="Delimiter">();</span> + <span class="Delimiter">}</span> + run<span class="Delimiter">(</span><span class="Constant">"recipe "</span>+s<span class="Delimiter">.</span>name+<span class="Constant">" [ "</span> + s<span class="Delimiter">.</span>to_run + <span class="Constant">" ]"</span><span class="Delimiter">);</span> + if <span class="Delimiter">(</span>not_already_inside_test<span class="Delimiter">)</span> <span class="Delimiter">{</span> + teardown<span class="Delimiter">();</span> + ofstream fout<span class="Delimiter">((</span>Trace_dir+Trace_file<span class="Delimiter">).</span>c_str<span class="Delimiter">());</span> + fout << Trace_stream<span class="Delimiter">-></span>readable_contents<span class="Delimiter">(</span><span class="Constant">""</span><span class="Delimiter">);</span> + fout<span class="Delimiter">.</span>close<span class="Delimiter">();</span> + delete Trace_stream<span class="Delimiter">;</span> + Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span> + Trace_file = <span class="Constant">""</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + Current_scenario = <span class="Constant">NULL</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="SalientComment">//:: The special instructions we want to support inside scenarios.</span> +<span class="Comment">//: In a compiler for the mu VM these will require more work.</span> + +<span class="Comment">//: 'run' interprets a string as a set of instructions</span> + +<span class="Delimiter">:(scenarios run)</span> +<span class="Delimiter">:(scenario run)</span> +<span class="CommentedCode">#? % Trace_stream->dump_layer = "all";</span> +recipe main [ + run [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] +] +<span class="traceContains">+mem: storing 13 in location 1</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +RUN<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +Recipe_number[<span class="Constant">"run"</span>] = RUN<span class="Delimiter">;</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +case RUN: <span class="Delimiter">{</span> +<span class="CommentedCode">//? cout << "recipe " << current_instruction().ingredients[0].name << '\n'; //? 1</span> + ostringstream tmp<span class="Delimiter">;</span> + tmp << <span class="Constant">"recipe run"</span> << Next_recipe_number << <span class="Constant">" [ "</span> << current_instruction<span class="Delimiter">().</span>ingredients[<span class="Constant">0</span>]<span class="Delimiter">.</span>name << <span class="Constant">" ]"</span><span class="Delimiter">;</span> +<span class="CommentedCode">//? Show_rest_of_stream = true; //? 1</span> + vector<recipe_number> tmp_recipe = load<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>str<span class="Delimiter">());</span> + <span class="Comment">// Predefined Scenario Locals In Run.</span> + <span class="Comment">// End Predefined Scenario Locals In Run.</span> + transform_all<span class="Delimiter">();</span> +<span class="CommentedCode">//? cout << tmp_recipe[0] << ' ' << Recipe_number["main"] << '\n'; //? 1</span> + Current_routine<span class="Delimiter">-></span>calls<span class="Delimiter">.</span>push<span class="Delimiter">(</span>call<span class="Delimiter">(</span>tmp_recipe[<span class="Constant">0</span>]<span class="Delimiter">));</span> + <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="Comment">// not done with caller; don't increment current_step_index()</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(scenario run_multiple)</span> +recipe main [ + run [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] + run [ + <span class="Constant">2</span>:integer<span class="Special"> <- </span>copy <span class="Constant">13</span>:literal + ] +] +<span class="traceContains">+mem: storing 13 in location 1</span> +<span class="traceContains">+mem: storing 13 in location 2</span> + +<span class="Comment">//: 'memory-should-contain' raises warnings if specific locations aren't as expected</span> +<span class="Comment">//: Also includes some special support for checking strings.</span> + +<span class="Delimiter">:(scenario memory_check)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">13</span> + ] +] +<span class="traceContains">+run: checking location 1</span> +<span class="traceContains">+warn: expected location 1 to contain 13 but saw 0</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +MEMORY_SHOULD_CONTAIN<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +Recipe_number[<span class="Constant">"memory-should-contain"</span>] = MEMORY_SHOULD_CONTAIN<span class="Delimiter">;</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +case MEMORY_SHOULD_CONTAIN: <span class="Delimiter">{</span> +<span class="CommentedCode">//? cout << current_instruction().ingredients[0].name << '\n'; //? 1</span> + check_memory<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients[<span class="Constant">0</span>]<span class="Delimiter">.</span>name<span class="Delimiter">);</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(code)</span> +void check_memory<span class="Delimiter">(</span>const string& s<span class="Delimiter">)</span> <span class="Delimiter">{</span> + istringstream in<span class="Delimiter">(</span>s<span class="Delimiter">);</span> + in >> std::noskipws<span class="Delimiter">;</span> + set<index_t> locations_checked<span class="Delimiter">;</span> + while <span class="Delimiter">(</span><span class="Constant">true</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>in<span class="Delimiter">.</span>eof<span class="Delimiter">())</span> <span class="Identifier">break</span><span class="Delimiter">;</span> + string lhs = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>!is_number<span class="Delimiter">(</span>lhs<span class="Delimiter">))</span> <span class="Delimiter">{</span> + check_type<span class="Delimiter">(</span>lhs<span class="Delimiter">,</span> in<span class="Delimiter">);</span> + <span class="Identifier">continue</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + int address = to_int<span class="Delimiter">(</span>lhs<span class="Delimiter">);</span> + skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + string _assign<span class="Delimiter">;</span> in >> _assign<span class="Delimiter">;</span> assert<span class="Delimiter">(</span>_assign == <span class="Constant">"<-"</span><span class="Delimiter">);</span> + skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + int value = <span class="Constant">0</span><span class="Delimiter">;</span> in >> value<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>locations_checked<span class="Delimiter">.</span>find<span class="Delimiter">(</span>address<span class="Delimiter">)</span> != locations_checked<span class="Delimiter">.</span>end<span class="Delimiter">())</span> + raise << <span class="Constant">"duplicate expectation for location "</span> << address << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + trace<span class="Delimiter">(</span><span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"checking location "</span> << address<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>Memory[address] != value<span class="Delimiter">)</span> <span class="Delimiter">{</span> + if <span class="Delimiter">(</span>Current_scenario<span class="Delimiter">)</span> + raise << <span class="Constant">"</span><span class="cSpecial">\n</span><span class="Constant">F - "</span> << Current_scenario<span class="Delimiter">-></span>name << <span class="Constant">": expected location "</span> << address << <span class="Constant">" to contain "</span> << value << <span class="Constant">" but saw "</span> << Memory[address] << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + else + raise << <span class="Constant">"expected location "</span> << address << <span class="Constant">" to contain "</span> << value << <span class="Constant">" but saw "</span> << Memory[address] << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + Passed = <span class="Constant">false</span><span class="Delimiter">;</span> + <span class="Identifier">return</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + locations_checked<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>address<span class="Delimiter">);</span> + <span class="Delimiter">}</span> +<span class="Delimiter">}</span> + +void check_type<span class="Delimiter">(</span>const string& lhs<span class="Delimiter">,</span> istream& in<span class="Delimiter">)</span> <span class="Delimiter">{</span> + reagent x<span class="Delimiter">(</span>lhs<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>x<span class="Delimiter">.</span>properties[<span class="Constant">0</span>]<span class="Delimiter">.</span>second[<span class="Constant">0</span>] == <span class="Constant">"string"</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + x<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>to_int<span class="Delimiter">(</span>x<span class="Delimiter">.</span>name<span class="Delimiter">));</span> + skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + string _assign = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + assert<span class="Delimiter">(</span>_assign == <span class="Constant">"<-"</span><span class="Delimiter">);</span> + skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + string literal = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + index_t address = x<span class="Delimiter">.</span>value<span class="Delimiter">;</span> + <span class="Comment">// exclude quoting brackets</span> + assert<span class="Delimiter">(</span>literal[<span class="Constant">0</span>] == <span class="Constant">'['</span><span class="Delimiter">);</span> literal<span class="Delimiter">.</span>erase<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span> + assert<span class="Delimiter">(</span>literal[literal<span class="Delimiter">.</span>size<span class="Delimiter">()</span>-<span class="Constant">1</span>] == <span class="Constant">']'</span><span class="Delimiter">);</span> literal<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>literal<span class="Delimiter">.</span>size<span class="Delimiter">()</span>-<span class="Constant">1</span><span class="Delimiter">);</span> + check_string<span class="Delimiter">(</span>address<span class="Delimiter">,</span> literal<span class="Delimiter">);</span> + <span class="Identifier">return</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + raise << <span class="Constant">"don't know how to check memory for "</span> << lhs << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +void check_string<span class="Delimiter">(</span>index_t address<span class="Delimiter">,</span> const string& literal<span class="Delimiter">)</span> <span class="Delimiter">{</span> + trace<span class="Delimiter">(</span><span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"checking string length at "</span> << address<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>Memory[address] != static_cast<signed><span class="Delimiter">(</span>literal<span class="Delimiter">.</span>size<span class="Delimiter">()))</span> + raise << <span class="Constant">"expected location "</span> << address << <span class="Constant">" to contain length "</span> << literal<span class="Delimiter">.</span>size<span class="Delimiter">()</span> << <span class="Constant">" of string ["</span> << literal << <span class="Constant">"] but saw "</span> << Memory[address] << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + ++address<span class="Delimiter">;</span> <span class="Comment">// now skip length</span> + for <span class="Delimiter">(</span>index_t i = <span class="Constant">0</span><span class="Delimiter">;</span> i < literal<span class="Delimiter">.</span>size<span class="Delimiter">();</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> + trace<span class="Delimiter">(</span><span class="Constant">"run"</span><span class="Delimiter">)</span> << <span class="Constant">"checking location "</span> << address+i<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>Memory[address+i] != literal[i]<span class="Delimiter">)</span> + raise << <span class="Constant">"expected location "</span> << <span class="Delimiter">(</span>address+i<span class="Delimiter">)</span> << <span class="Constant">" to contain "</span> << literal[i] << <span class="Constant">" but saw "</span> << Memory[address+i] << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(scenario memory_check_multiple)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + memory-should-contain [ + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">0</span> + ] +] +<span class="traceContains">+warn: duplicate expectation for location 1</span> + +<span class="Delimiter">:(scenario memory_check_string_length)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">3</span>:literal + <span class="Constant">2</span>:integer<span class="Special"> <- </span>copy <span class="Constant">97</span>:literal <span class="Comment"># 'a'</span> + <span class="Constant">3</span>:integer<span class="Special"> <- </span>copy <span class="Constant">98</span>:literal <span class="Comment"># 'b'</span> + <span class="Constant">4</span>:integer<span class="Special"> <- </span>copy <span class="Constant">99</span>:literal <span class="Comment"># 'c'</span> + memory-should-contain [ + <span class="Constant">1</span>:string<span class="Special"> <- </span>[ab] + ] +] +<span class="traceContains">+warn: expected location 1 to contain length 2 of string [ab] but saw 3</span> + +<span class="Delimiter">:(scenario memory_check_string)</span> +recipe main [ + <span class="Constant">1</span>:integer<span class="Special"> <- </span>copy <span class="Constant">3</span>:literal + <span class="Constant">2</span>:integer<span class="Special"> <- </span>copy <span class="Constant">97</span>:literal <span class="Comment"># 'a'</span> + <span class="Constant">3</span>:integer<span class="Special"> <- </span>copy <span class="Constant">98</span>:literal <span class="Comment"># 'b'</span> + <span class="Constant">4</span>:integer<span class="Special"> <- </span>copy <span class="Constant">99</span>:literal <span class="Comment"># 'c'</span> + memory-should-contain [ + <span class="Constant">1</span>:string<span class="Special"> <- </span>[abc] + ] +] +<span class="traceContains">+run: checking string length at 1</span> +<span class="traceContains">+run: checking location 2</span> +<span class="traceContains">+run: checking location 3</span> +<span class="traceContains">+run: checking location 4</span> + +<span class="Delimiter">:(code)</span> +<span class="Comment">//: 'trace-should-contain' is like the '+' lines in our scenarios so far</span> +<span class="Comment">// Like runs of contiguous '+' lines, order is important. The trace checks</span> +<span class="Comment">// that the lines are present *and* in the specified sequence. (There can be</span> +<span class="Comment">// other lines in between.)</span> + +<span class="Delimiter">:(scenario trace_check_warns_on_failure)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + trace-should-contain [ + a: b + a: d + ] +] +<span class="traceContains">+warn: missing [b] in trace layer a</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +TRACE_SHOULD_CONTAIN<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +Recipe_number[<span class="Constant">"trace-should-contain"</span>] = TRACE_SHOULD_CONTAIN<span class="Delimiter">;</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +case TRACE_SHOULD_CONTAIN: <span class="Delimiter">{</span> + check_trace<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients[<span class="Constant">0</span>]<span class="Delimiter">.</span>name<span class="Delimiter">);</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(code)</span> +<span class="Comment">// simplified version of check_trace_contents() that emits warnings rather</span> +<span class="Comment">// than just printing to stderr</span> +bool check_trace<span class="Delimiter">(</span>const string& expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> + Trace_stream<span class="Delimiter">-></span>newline<span class="Delimiter">();</span> + vector<pair<string<span class="Delimiter">,</span> string> > expected_lines = parse_trace<span class="Delimiter">(</span>expected<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> + index_t curr_expected_line = <span class="Constant">0</span><span class="Delimiter">;</span> + for <span class="Delimiter">(</span>vector<pair<string<span class="Delimiter">,</span> pair<int<span class="Delimiter">,</span> string> > >::iterator p = Trace_stream<span class="Delimiter">-></span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-></span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span> + if <span class="Delimiter">(</span>expected_lines[curr_expected_line]<span class="Delimiter">.</span>first != p<span class="Delimiter">-></span>first<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + if <span class="Delimiter">(</span>expected_lines[curr_expected_line]<span class="Delimiter">.</span>second != p<span class="Delimiter">-></span>second<span class="Delimiter">.</span>second<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + <span class="Comment">// match</span> + ++curr_expected_line<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>curr_expected_line == expected_lines<span class="Delimiter">.</span>size<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + + raise << <span class="Constant">"missing ["</span> << expected_lines[curr_expected_line]<span class="Delimiter">.</span>second << <span class="Constant">"] "</span> + << <span class="Constant">"in trace layer "</span> << expected_lines[curr_expected_line]<span class="Delimiter">.</span>first << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + Passed = <span class="Constant">false</span><span class="Delimiter">;</span> + <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +vector<pair<string<span class="Delimiter">,</span> string> > parse_trace<span class="Delimiter">(</span>const string& expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> + vector<string> buf = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">"</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span> + vector<pair<string<span class="Delimiter">,</span> string> > result<span class="Delimiter">;</span> + for <span class="Delimiter">(</span>index_t i = <span class="Constant">0</span><span class="Delimiter">;</span> i < buf<span class="Delimiter">.</span>size<span class="Delimiter">();</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> + buf[i] = trim<span class="Delimiter">(</span>buf[i]<span class="Delimiter">);</span> + if <span class="Delimiter">(</span>buf[i]<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> + index_t delim = buf[i]<span class="Delimiter">.</span>find<span class="Delimiter">(</span><span class="Constant">": "</span><span class="Delimiter">);</span> + result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair<string<span class="Delimiter">,</span> string><span class="Delimiter">(</span>buf[i]<span class="Delimiter">.</span>substr<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> delim<span class="Delimiter">),</span> buf[i]<span class="Delimiter">.</span>substr<span class="Delimiter">(</span>delim+<span class="Constant">2</span><span class="Delimiter">)));</span> + <span class="Delimiter">}</span> + <span class="Identifier">return</span> result<span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(scenario trace_check_warns_on_failure_in_later_line)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + run [ + trace [a]<span class="Delimiter">,</span> [b] + ] + trace-should-contain [ + a: b + a: d + ] +] +<span class="traceContains">+warn: missing [d] in trace layer a</span> + +<span class="Delimiter">:(scenario trace_check_passes_silently)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + run [ + trace [a]<span class="Delimiter">,</span> [b] + ] + trace-should-contain [ + a: b + ] +] +<span class="traceAbsent">-warn: missing [b] in trace layer a</span> + +<span class="Comment">//: 'trace-should-not-contain' is like the '-' lines in our scenarios so far</span> +<span class="Comment">//: Each trace line is separately checked for absense. Order is *not*</span> +<span class="Comment">//: important, so you can't say things like "B should not exist after A."</span> + +<span class="Delimiter">:(scenario trace_negative_check_warns_on_failure)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + run [ + trace [a]<span class="Delimiter">,</span> [b] + ] + trace-should-not-contain [ + a: b + ] +] +<span class="traceContains">+warn: unexpected [b] in trace layer a</span> + +<span class="Delimiter">:(before "End Primitive Recipe Declarations")</span> +TRACE_SHOULD_NOT_CONTAIN<span class="Delimiter">,</span> +<span class="Delimiter">:(before "End Primitive Recipe Numbers")</span> +Recipe_number[<span class="Constant">"trace-should-not-contain"</span>] = TRACE_SHOULD_NOT_CONTAIN<span class="Delimiter">;</span> +<span class="Delimiter">:(before "End Primitive Recipe Implementations")</span> +case TRACE_SHOULD_NOT_CONTAIN: <span class="Delimiter">{</span> + check_trace_missing<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients[<span class="Constant">0</span>]<span class="Delimiter">.</span>name<span class="Delimiter">);</span> + <span class="Identifier">break</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(code)</span> +<span class="Comment">// simplified version of check_trace_contents() that emits warnings rather</span> +<span class="Comment">// than just printing to stderr</span> +bool check_trace_missing<span class="Delimiter">(</span>const string& in<span class="Delimiter">)</span> <span class="Delimiter">{</span> + Trace_stream<span class="Delimiter">-></span>newline<span class="Delimiter">();</span> + vector<pair<string<span class="Delimiter">,</span> string> > lines = parse_trace<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + for <span class="Delimiter">(</span>index_t i = <span class="Constant">0</span><span class="Delimiter">;</span> i < lines<span class="Delimiter">.</span>size<span class="Delimiter">();</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> + if <span class="Delimiter">(</span>trace_count<span class="Delimiter">(</span>lines[i]<span class="Delimiter">.</span>first<span class="Delimiter">,</span> lines[i]<span class="Delimiter">.</span>second<span class="Delimiter">)</span> != <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> + raise << <span class="Constant">"unexpected ["</span> << lines[i]<span class="Delimiter">.</span>second << <span class="Constant">"] in trace layer "</span> << lines[i]<span class="Delimiter">.</span>first << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> + Passed = <span class="Constant">false</span><span class="Delimiter">;</span> + <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> + <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> +<span class="Delimiter">}</span> + +<span class="Delimiter">:(scenario trace_negative_check_passes_silently)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + trace-should-not-contain [ + a: b + ] +] +<span class="traceAbsent">-warn: unexpected [b] in trace layer a</span> + +<span class="Delimiter">:(scenario trace_negative_check_warns_on_any_unexpected_line)</span> +<span class="Special">% Hide_warnings = true;</span> +recipe main [ + run [ + trace [a]<span class="Delimiter">,</span> [d] + ] + trace-should-not-contain [ + a: b + a: d + ] +] +<span class="traceContains">+warn: unexpected [d] in trace layer a</span> + +<span class="SalientComment">//:: Helpers</span> + +<span class="Delimiter">:(code)</span> +<span class="Comment">// just for the scenarios running scenarios in C++ layers</span> +void run_mu_scenario<span class="Delimiter">(</span>const string& form<span class="Delimiter">)</span> <span class="Delimiter">{</span> + istringstream in<span class="Delimiter">(</span>form<span class="Delimiter">);</span> + in >> std::noskipws<span class="Delimiter">;</span> + string _scenario = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> +<span class="CommentedCode">//? cout << _scenario << '\n'; //? 1</span> + assert<span class="Delimiter">(</span>_scenario == <span class="Constant">"scenario"</span><span class="Delimiter">);</span> + scenario s = parse_scenario<span class="Delimiter">(</span>in<span class="Delimiter">);</span> + run_mu_scenario<span class="Delimiter">(</span>s<span class="Delimiter">);</span> +<span class="Delimiter">}</span> + +void slurp_until_matching_bracket<span class="Delimiter">(</span>istream& in<span class="Delimiter">,</span> ostream& out<span class="Delimiter">)</span> <span class="Delimiter">{</span> + int brace_depth = <span class="Constant">1</span><span class="Delimiter">;</span> <span class="Comment">// just scanned '['</span> + char c<span class="Delimiter">;</span> + while <span class="Delimiter">(</span>in >> c<span class="Delimiter">)</span> <span class="Delimiter">{</span> + if <span class="Delimiter">(</span>c == <span class="Constant">'['</span><span class="Delimiter">)</span> ++brace_depth<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>c == <span class="Constant">']'</span><span class="Delimiter">)</span> --brace_depth<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>brace_depth == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Comment">// drop final ']'</span> + out << c<span class="Delimiter">;</span> + <span class="Delimiter">}</span> +<span class="Delimiter">}</span> + +<span class="Comment">// see tests for this function in tangle/030tangle.test.cc</span> +string trim<span class="Delimiter">(</span>const string& s<span class="Delimiter">)</span> <span class="Delimiter">{</span> + string::const_iterator first = s<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> + while <span class="Delimiter">(</span>first != s<span class="Delimiter">.</span>end<span class="Delimiter">()</span> && isspace<span class="Delimiter">(</span>*first<span class="Delimiter">))</span> + ++first<span class="Delimiter">;</span> + if <span class="Delimiter">(</span>first == s<span class="Delimiter">.</span>end<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">""</span><span class="Delimiter">;</span> + + string::const_iterator last = --s<span class="Delimiter">.</span>end<span class="Delimiter">();</span> + while <span class="Delimiter">(</span>last != s<span class="Delimiter">.</span>begin<span class="Delimiter">()</span> && isspace<span class="Delimiter">(</span>*last<span class="Delimiter">))</span> + --last<span class="Delimiter">;</span> + ++last<span class="Delimiter">;</span> + <span class="Identifier">return</span> string<span class="Delimiter">(</span>first<span class="Delimiter">,</span> last<span class="Delimiter">);</span> +<span class="Delimiter">}</span> +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> |