summary refs log blame commit diff stats
path: root/svc/query_test.go
blob: 939592e72d3f2b9900e18063d02ac4fad3a2ecf0 (plain) (tree)


















                                                                    
                                                    






                 
                                           

 





























                                                                         


                                       
                            
                             
 
                                                   








                                                                  
                                                                           










                                                          








                                                                                                          
                            
                             
 
                                                   








                                                                  
                                                                           










                                                  
 
 












































                                                                                    
 


                                              
                      






























                                                                                                          


                                                                                             






                                                   
/*
Copyright (c) 2019 Ben Morrison (gbmor)

This file is part of Getwtxt.

Getwtxt is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Getwtxt is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Getwtxt.  If not, see <https://www.gnu.org/licenses/>.
*/

package svc // import "git.sr.ht/~gbmor/getwtxt/svc"

import (
	"net"
	"reflect"
	"strings"
	"testing"

	"git.sr.ht/~gbmor/getwtxt/registry"
)

func Test_dedupe(t *testing.T) {
	t.Run("Simple Deduplication Test", func(t *testing.T) {
		start := []string{
			"first",
			"second",
			"third",
			"third",
		}
		finish := dedupe(start)
		if reflect.DeepEqual(start, finish) {
			t.Errorf("Deduplication didn't occur\n")
		}
		if len(finish) != 3 {
			t.Errorf("Ending length not what was expected\n")
		}
	})
}

func Benchmark_dedupe(b *testing.B) {
	start := []string{
		"first",
		"second",
		"third",
		"third",
	}
	for i := 0; i < b.N; i++ {
		dedupe(start)
	}
}

func Test_parseQueryOut(t *testing.T) {
	initTestConf()

	urls := testTwtxtURL
	nick := "getwtxttest"

	out, _, err := registry.GetTwtxt(urls, nil)
	if err != nil {
		t.Errorf("Couldn't set up test: %v\n", err)
	}

	statusmap, err := registry.ParseUserTwtxt(out, nick, urls)
	if err != nil {
		t.Errorf("Couldn't set up test: %v\n", err)
	}

	twtxtCache.AddUser(nick, urls, net.ParseIP("127.0.0.1"), statusmap)

	t.Run("Parsing Status Query", func(t *testing.T) {
		data, err := twtxtCache.QueryAllStatuses()
		if err != nil {
			t.Errorf("%v\n", err)
		}

		out := parseQueryOut(data)

		conv := strings.Split(string(out), "\n")

		if !reflect.DeepEqual(data, conv) {
			t.Errorf("Pre- and Post- parseQueryOut data are inequal:\n%#v\n%#v\n", data, conv)
		}
	})
}

func Benchmark_parseQueryOut(b *testing.B) {
	initTestConf()

	urls := testTwtxtURL
	nick := "getwtxttest"

	out, _, err := registry.GetTwtxt(urls, nil)
	if err != nil {
		b.Errorf("Couldn't set up test: %v\n", err)
	}

	statusmap, err := registry.ParseUserTwtxt(out, nick, urls)
	if err != nil {
		b.Errorf("Couldn't set up test: %v\n", err)
	}

	twtxtCache.AddUser(nick, urls, net.ParseIP("127.0.0.1"), statusmap)

	data, err := twtxtCache.QueryAllStatuses()
	if err != nil {
		b.Errorf("%v\n", err)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		parseQueryOut(data)
	}
}

func Test_joinQueryOuts(t *testing.T) {
	first := []string{
		"one",
		"two",
		"three",
	}
	second := []string{
		"three",
		"four",
		"five",
		"six",
	}
	t.Run("Joining two string slices", func(t *testing.T) {
		third := joinQueryOuts(first, second)
		if len(third) != (len(first) + len(second) - 1) {
			t.Errorf("Was not combined or deduplicated properly\n")
		}
		fourth := make([]string, 6)
		for i := 0; i < len(first); i++ {
			fourth[i] = first[i]
		}
		for i := 1; i < len(second); i++ {
			fourth[2+i] = second[i]
		}
		if !reflect.DeepEqual(fourth, third) {
			t.Errorf("Output not deeply equal to manual construction\n")
		}
	})
}

func Benchmark_joinQueryOuts(b *testing.B) {
	first := []string{
		"one",
		"two",
		"three",
	}
	second := []string{
		"three",
		"four",
		"five",
		"six",
	}
	for i := 0; i < b.N; i++ {
		joinQueryOuts(first, second)
	}
}

func Test_compositeStatusQuery(t *testing.T) {
	initTestConf()
	mockRegistry()

	t.Run("Composite Query Test", func(t *testing.T) {
		out1, err := twtxtCache.QueryInStatus("sqlite")
		if err != nil {
			t.Errorf("%v\n", err)
		}
		out2, err := twtxtCache.QueryInStatus("Sqlite")
		if err != nil {
			t.Errorf("%v\n", err)
		}
		out3, err := twtxtCache.QueryInStatus("SQLITE")
		if err != nil {
			t.Errorf("%v\n", err)
		}

		outro := make([]string, 0)
		outro = append(outro, out1...)
		outro = append(outro, out2...)
		outro = append(outro, out3...)
		out := dedupe(outro)

		data := compositeStatusQuery("sqlite", nil)

		if !reflect.DeepEqual(out, data) {
			t.Errorf("Returning different data.\nManual: %v\nCompositeQuery: %v\n", out, data)
		}
	})
}

func Benchmark_compositeStatusQuery(b *testing.B) {
	initTestConf()
	statuses, _, _ := registry.GetTwtxt(testTwtxtURL, nil)
	parsed, _ := registry.ParseUserTwtxt(statuses, "getwtxttest", testTwtxtURL)
	_ = twtxtCache.AddUser("getwtxttest", testTwtxtURL, net.ParseIP("127.0.0.1"), parsed)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		compositeStatusQuery("sqlite", nil)
	}

}
narios are take special 'code' strings so we need to ignore brackets</span> <span class="Comment">// inside comments</span> result<span class="Delimiter">.</span>to_run = slurp_quoted<span class="Delimiter">(</span>in<span class="Delimiter">);</span> <span class="Comment">// delete [] delimiters</span> assert<span class="Delimiter">(</span>starts_with<span class="Delimiter">(</span>result<span class="Delimiter">.</span>to_run<span class="Delimiter">,</span> <span class="Constant">&quot;[&quot;</span><span class="Delimiter">));</span> result<span class="Delimiter">.</span>to_run<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>result<span class="Delimiter">.</span>to_run<span class="Delimiter">.</span>at<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>result<span class="Delimiter">.</span>to_run<span class="Delimiter">)</span>-<span class="Constant">1</span><span class="Delimiter">)</span> == <span class="Constant">']'</span><span class="Delimiter">);</span> result<span class="Delimiter">.</span>to_run<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>result<span class="Delimiter">.</span>to_run<span class="Delimiter">)</span>-<span class="Constant">1</span><span class="Delimiter">);</span> <span class="Identifier">return</span> result<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(scenario read_scenario_with_bracket_in_comment)</span> scenario foo [ <span class="Comment"># ']' in comment</span> <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span> ] <span class="traceContains">+run: {1: &quot;number&quot;} &lt;- copy {0: &quot;literal&quot;}</span> <span class="Delimiter">:(scenario read_scenario_with_bracket_in_comment_in_nested_string)</span> scenario foo [ <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span><span class="Normal">new</span> [<span class="Comment"># not a comment]</span> ] <span class="traceContains">+run: {1: (&quot;address&quot; &quot;array&quot; &quot;character&quot;)} &lt;- new {&quot;# not a comment&quot;: &quot;literal-string&quot;}</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 &quot;End Globals&quot;)</span> <span class="Normal">int</span> Num_core_mu_scenarios = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(after &quot;Check For .mu Files&quot;)</span> Num_core_mu_scenarios = SIZE<span class="Delimiter">(</span>Scenarios<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Tests&quot;)</span> Hide_missing_default_space_errors = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Num_core_mu_scenarios<span class="Delimiter">)</span> <span class="Delimiter">{</span> time<span class="Delimiter">(</span>&amp;t<span class="Delimiter">);</span> cerr &lt;&lt; <span class="Constant">&quot;Mu tests: &quot;</span> &lt;&lt; ctime<span class="Delimiter">(</span>&amp;t<span class="Delimiter">);</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; Num_core_mu_scenarios<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; '\n' &lt;&lt; i &lt;&lt; &quot;: &quot; &lt;&lt; Scenarios.at(i).name;</span> run_mu_scenario<span class="Delimiter">(</span>Scenarios<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Passed<span class="Delimiter">)</span> cerr &lt;&lt; <span class="Constant">&quot;.&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> cerr &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">run_app_scenarios</span>: <span class="Normal">if</span> <span class="Delimiter">(</span>Num_core_mu_scenarios != SIZE<span class="Delimiter">(</span>Scenarios<span class="Delimiter">))</span> <span class="Delimiter">{</span> time<span class="Delimiter">(</span>&amp;t<span class="Delimiter">);</span> cerr &lt;&lt; <span class="Constant">&quot;App tests: &quot;</span> &lt;&lt; ctime<span class="Delimiter">(</span>&amp;t<span class="Delimiter">);</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = Num_core_mu_scenarios<span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>Scenarios<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; '\n' &lt;&lt; i &lt;&lt; &quot;: &quot; &lt;&lt; Scenarios.at(i).name;</span> run_mu_scenario<span class="Delimiter">(</span>Scenarios<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Passed<span class="Delimiter">)</span> cerr &lt;&lt; <span class="Constant">&quot;.&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> cerr &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">//: For faster debugging, support running tests for just the Mu app(s) we are</span> <span class="Comment">//: loading.</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> <span class="Normal">bool</span> Test_only_app = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Commandline Options(*arg)&quot;)</span> <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_equal<span class="Delimiter">(</span>*arg<span class="Delimiter">,</span> <span class="Constant">&quot;--test-only-app&quot;</span><span class="Delimiter">))</span> <span class="Delimiter">{</span> Test_only_app = <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(after &quot;End Test Run Initialization&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Test_only_app &amp;&amp; Num_core_mu_scenarios &lt; SIZE<span class="Delimiter">(</span>Scenarios<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span class="Identifier">goto</span> run_app_scenarios<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">//: Convenience: run a single named scenario.</span> <span class="Delimiter">:(after &quot;Test Runs&quot;)</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>Scenarios<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Scenarios<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>name == argv[argc-<span class="Constant">1</span>]<span class="Delimiter">)</span> <span class="Delimiter">{</span> run_mu_scenario<span class="Delimiter">(</span>Scenarios<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Passed<span class="Delimiter">)</span> cerr &lt;&lt; <span class="Constant">&quot;.</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span> <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> <span class="Comment">// this isn't a constant, just a global of type const*</span> <span class="Normal">const</span> scenario* Current_scenario = <span class="Constant">NULL</span><span class="Delimiter">;</span> <span class="Delimiter">:(code)</span> <span class="Normal">void</span> run_mu_scenario<span class="Delimiter">(</span><span class="Normal">const</span> scenario&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span> Current_scenario = &amp;s<span class="Delimiter">;</span> <span class="Normal">bool</span> not_already_inside_test = !Trace_stream<span class="Delimiter">;</span> <span class="CommentedCode">//? cerr &lt;&lt; s.name &lt;&lt; '\n';</span> <span class="Normal">if</span> <span class="Delimiter">(</span>not_already_inside_test<span class="Delimiter">)</span> <span class="Delimiter">{</span> Trace_stream = <span class="Normal">new</span> trace_stream<span class="Delimiter">;</span> setup<span class="Delimiter">();</span> <span class="Delimiter">}</span> vector&lt;recipe_ordinal&gt; tmp = load<span class="Delimiter">(</span><span class="Constant">&quot;recipe scenario_&quot;</span>+s<span class="Delimiter">.</span>name+<span class="Constant">&quot; [ &quot;</span>+s<span class="Delimiter">.</span>to_run+<span class="Constant">&quot; ]&quot;</span><span class="Delimiter">);</span> mark_autogenerated<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> bind_special_scenario_names<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> transform_all<span class="Delimiter">();</span> run<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>front<span class="Delimiter">());</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Hide_errors &amp;&amp; trace_count<span class="Delimiter">(</span><span class="Constant">&quot;error&quot;</span><span class="Delimiter">)</span> &gt; <span class="Constant">0</span><span class="Delimiter">)</span> Passed = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">// End Mu Test Teardown</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Passed<span class="Delimiter">)</span> ++Num_failures<span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>not_already_inside_test &amp;&amp; Trace_stream<span class="Delimiter">)</span> <span class="Delimiter">{</span> teardown<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Save_trace<span class="Delimiter">)</span> <span class="Delimiter">{</span> ofstream fout<span class="Delimiter">(</span><span class="Constant">&quot;last_trace&quot;</span><span class="Delimiter">);</span> fout &lt;&lt; Trace_stream<span class="Delimiter">-&gt;</span>readable_contents<span class="Delimiter">(</span><span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span> fout<span class="Delimiter">.</span>close<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">delete</span> Trace_stream<span class="Delimiter">;</span> Trace_stream = <span class="Constant">NULL</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="Comment">//: Some variables for fake resources always get special /raw addresses in scenarios.</span> <span class="Comment">// Should contain everything passed by is_special_name but failed by is_disqualified.</span> <span class="Normal">void</span> bind_special_scenario_names<span class="Delimiter">(</span>recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// Special Scenario Variable Names(r)</span> <span class="Comment">// End Special Scenario Variable Names(r)</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;Done Placing Ingredient(ingredient, inst, caller)&quot;)</span> maybe_make_raw<span class="Delimiter">(</span>ingredient<span class="Delimiter">,</span> caller<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;Done Placing Product(product, inst, caller)&quot;)</span> maybe_make_raw<span class="Delimiter">(</span>product<span class="Delimiter">,</span> caller<span class="Delimiter">);</span> <span class="Delimiter">:(code)</span> <span class="Normal">void</span> maybe_make_raw<span class="Delimiter">(</span>reagent&amp; r<span class="Delimiter">,</span> <span class="Normal">const</span> recipe&amp; caller<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_special_name<span class="Delimiter">(</span>r<span class="Delimiter">.</span>name<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>starts_with<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>name<span class="Delimiter">,</span> <span class="Constant">&quot;scenario_&quot;</span><span class="Delimiter">))</span> r<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair&lt;string<span class="Delimiter">,</span> string_tree*&gt;<span class="Delimiter">(</span><span class="Constant">&quot;raw&quot;</span><span class="Delimiter">,</span> <span class="Constant">NULL</span><span class="Delimiter">));</span> <span class="Comment">// End maybe_make_raw</span> <span class="Delimiter">}</span> <span class="Comment">//: Test.</span> <span class="Delimiter">:(before &quot;End is_special_name Cases&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>s == <span class="Constant">&quot;__maybe_make_raw_test__&quot;</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Special Scenario Variable Names(r)&quot;)</span> <span class="Comment">//: ugly: we only need this for this one test, but need to define it for all time</span> Name[r][<span class="Constant">&quot;__maybe_make_raw_test__&quot;</span>] = Reserved_for_tests-<span class="Constant">1</span><span class="Delimiter">;</span> <span class="Delimiter">:(code)</span> <span class="Normal">void</span> test_maybe_make_raw<span class="Delimiter">()</span> <span class="Delimiter">{</span> <span class="Comment">// check that scenarios can use local-scope and special variables together</span> vector&lt;recipe_ordinal&gt; tmp = load<span class="Delimiter">(</span> <span class="Constant">&quot;def scenario_foo [</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> <span class="Constant">&quot; local-scope</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> <span class="Constant">&quot; __maybe_make_raw_test__:number &lt;- copy 34</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> <span class="Constant">&quot;]</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">);</span> mark_autogenerated<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> bind_special_scenario_names<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> transform_all<span class="Delimiter">();</span> run<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> CHECK_EQ<span class="Delimiter">(</span>trace_count<span class="Delimiter">(</span><span class="Constant">&quot;error&quot;</span><span class="Delimiter">),</span> <span class="Constant">0</span><span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Comment">//: Watch out for redefinitions of scenario routines. We should never ever be</span> <span class="Comment">//: doing that, regardless of anything else.</span> <span class="Delimiter">:(scenarios run)</span> <span class="Delimiter">:(scenario forbid_redefining_scenario_even_if_forced)</span> <span class="Special">% Hide_errors = true;</span> <span class="Special">% Disable_redefine_checks = true;</span> def scenario-foo [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span> ] def scenario-foo [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span> ] <span class="traceContains">+error: redefining recipe scenario-foo</span> <span class="Delimiter">:(after &quot;bool should_check_for_redefine(const string&amp; recipe_name)&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>recipe_name<span class="Delimiter">.</span>find<span class="Delimiter">(</span><span class="Constant">&quot;scenario-&quot;</span><span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">true</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">:(scenario run)</span> def main [ run [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">13</span> ] ] <span class="traceContains">+mem: storing 13 in location 1</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> RUN<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">,</span> RUN<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> RUN: <span class="Delimiter">{</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> RUN: <span class="Delimiter">{</span> assert<span class="Delimiter">(</span>Name[Next_recipe_ordinal]<span class="Delimiter">.</span>empty<span class="Delimiter">());</span> ostringstream tmp<span class="Delimiter">;</span> tmp &lt;&lt; <span class="Constant">&quot;recipe run_&quot;</span> &lt;&lt; Next_recipe_ordinal &lt;&lt; <span class="Constant">&quot; [ &quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot; ]&quot;</span><span class="Delimiter">;</span> vector&lt;recipe_ordinal&gt; tmp_recipe = load<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>str<span class="Delimiter">());</span> mark_autogenerated<span class="Delimiter">(</span>tmp_recipe<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> bind_special_scenario_names<span class="Delimiter">(</span>tmp_recipe<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> transform_all<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">)</span> <span class="Delimiter">{</span> ++Trace_stream<span class="Delimiter">-&gt;</span>callstack_depth<span class="Delimiter">;</span> trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;trace&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;run: incrementing callstack depth to &quot;</span> &lt;&lt; Trace_stream<span class="Delimiter">-&gt;</span>callstack_depth &lt;&lt; end<span class="Delimiter">();</span> assert<span class="Delimiter">(</span>Trace_stream<span class="Delimiter">-&gt;</span>callstack_depth &lt; <span class="Constant">9000</span><span class="Delimiter">);</span> <span class="Comment">// 9998-101 plus cushion</span> <span class="Delimiter">}</span> Current_routine<span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>push_front<span class="Delimiter">(</span>call<span class="Delimiter">(</span>tmp_recipe<span class="Delimiter">.</span>at<span class="Delimiter">(</span><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">:(before &quot;End maybe_make_raw&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>starts_with<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>name<span class="Delimiter">,</span> <span class="Constant">&quot;run_&quot;</span><span class="Delimiter">))</span> r<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair&lt;string<span class="Delimiter">,</span> string_tree*&gt;<span class="Delimiter">(</span><span class="Constant">&quot;raw&quot;</span><span class="Delimiter">,</span> <span class="Constant">NULL</span><span class="Delimiter">));</span> <span class="Delimiter">:(scenario run_multiple)</span> def main [ run [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">13</span> ] run [ <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">13</span> ] ] <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 errors if specific locations aren't as expected</span> <span class="Comment">//: Also includes some special support for checking strings.</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> <span class="Normal">bool</span> Scenario_testing_scenario = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Setup&quot;)</span> Scenario_testing_scenario = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(scenario memory_check)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ memory-should-contain [ <span class="Constant">1</span><span class="Special"> &lt;- </span><span class="Constant">13</span> ] ] <span class="traceContains">+run: checking location 1</span> <span class="traceContains">+error: expected location '1' to contain 13 but saw 0</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> MEMORY_SHOULD_CONTAIN<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;memory-should-contain&quot;</span><span class="Delimiter">,</span> MEMORY_SHOULD_CONTAIN<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> MEMORY_SHOULD_CONTAIN: <span class="Delimiter">{</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> MEMORY_SHOULD_CONTAIN: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Passed<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> check_memory<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><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="Normal">void</span> check_memory<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span> istringstream in<span class="Delimiter">(</span>s<span class="Delimiter">);</span> in &gt;&gt; std::noskipws<span class="Delimiter">;</span> set&lt;<span class="Normal">int</span>&gt; locations_checked<span class="Delimiter">;</span> <span class="Normal">while</span> <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> <span class="Normal">if</span> <span class="Delimiter">(</span>!has_data<span class="Delimiter">(</span>in<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> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_integer<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> <span class="Normal">int</span> address = to_integer<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 &gt;&gt; _assign<span class="Delimiter">;</span> assert<span class="Delimiter">(</span>_assign == <span class="Constant">&quot;&lt;-&quot;</span><span class="Delimiter">);</span> skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> string rhs = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_integer<span class="Delimiter">(</span>rhs<span class="Delimiter">)</span> &amp;&amp; !is_noninteger<span class="Delimiter">(</span>rhs<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> <span class="Comment">// genuine test in a mu file</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' can't contain non-number &quot;</span> &lt;&lt; rhs &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">else</span> <span class="Comment">// just testing scenario support</span> raise &lt;&lt; <span class="Constant">&quot;location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' can't contain non-number &quot;</span> &lt;&lt; rhs &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Scenario_testing_scenario<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> <span class="Normal">double</span> value = to_double<span class="Delimiter">(</span>rhs<span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>locations_checked<span class="Delimiter">,</span> address<span class="Delimiter">))</span> raise &lt;&lt; <span class="Constant">&quot;duplicate expectation for location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;checking location &quot;</span> &lt;&lt; address &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">)</span> != value<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// genuine test in a mu file</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: expected location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' to contain &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>value<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">))</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Delimiter">{</span> <span class="Comment">// just testing scenario support</span> raise &lt;&lt; <span class="Constant">&quot;expected location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' to contain &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>value<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">))</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Scenario_testing_scenario<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> <span class="Normal">void</span> check_type<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; lhs<span class="Delimiter">,</span> istream&amp; in<span class="Delimiter">)</span> <span class="Delimiter">{</span> reagent x<span class="Delimiter">(</span>lhs<span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_array<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">)</span> &amp;&amp; is_mu_character<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">))</span> <span class="Delimiter">{</span> x<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>to_integer<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">&quot;&lt;-&quot;</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> <span class="Normal">int</span> 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="Delimiter">.</span>begin<span class="Delimiter">()</span> == <span class="Constant">'['</span><span class="Delimiter">);</span> literal<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>literal<span class="Delimiter">.</span>begin<span class="Delimiter">());</span> assert<span class="Delimiter">(</span>*--literal<span class="Delimiter">.</span>end<span class="Delimiter">()</span> == <span class="Constant">']'</span><span class="Delimiter">);</span> literal<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>--literal<span class="Delimiter">.</span>end<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> <span class="Comment">// End Scenario Type Cases</span> raise &lt;&lt; <span class="Constant">&quot;don't know how to check memory for '&quot;</span> &lt;&lt; lhs &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">void</span> check_string<span class="Delimiter">(</span><span class="Normal">int</span> address<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; literal<span class="Delimiter">)</span> <span class="Delimiter">{</span> trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;checking string length at &quot;</span> &lt;&lt; address &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">)</span> != SIZE<span class="Delimiter">(</span>literal<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: expected location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' to contain length &quot;</span> &lt;&lt; SIZE<span class="Delimiter">(</span>literal<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; of string [&quot;</span> &lt;&lt; literal &lt;&lt; <span class="Constant">&quot;] but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot; (&quot;</span> &lt;&lt; read_mu_string<span class="Delimiter">(</span>address<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;)</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">else</span> raise &lt;&lt; <span class="Constant">&quot;expected location '&quot;</span> &lt;&lt; address &lt;&lt; <span class="Constant">&quot;' to contain length &quot;</span> &lt;&lt; SIZE<span class="Delimiter">(</span>literal<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; of string [&quot;</span> &lt;&lt; literal &lt;&lt; <span class="Constant">&quot;] but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address<span class="Delimiter">))</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Scenario_testing_scenario<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> ++address<span class="Delimiter">;</span> <span class="Comment">// now skip length</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>literal<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;checking location &quot;</span> &lt;&lt; address+i &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address+i<span class="Delimiter">)</span> != literal<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// genuine test in a mu file</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: expected location &quot;</span> &lt;&lt; <span class="Delimiter">(</span>address+i<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; to contain &quot;</span> &lt;&lt; literal<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address+i<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot; ('&quot;</span> &lt;&lt; <span class="Normal">static_cast</span>&lt;<span class="Normal">char</span>&gt;<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address+i<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;')</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Delimiter">{</span> <span class="Comment">// just testing scenario support</span> raise &lt;&lt; <span class="Constant">&quot;expected location &quot;</span> &lt;&lt; <span class="Delimiter">(</span>address+i<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; to contain &quot;</span> &lt;&lt; literal<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; but saw &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address+i<span class="Delimiter">))</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Scenario_testing_scenario<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> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Delimiter">:(scenario memory_check_multiple)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ memory-should-contain [ <span class="Constant">1</span><span class="Special"> &lt;- </span><span class="Constant">0</span> <span class="Constant">1</span><span class="Special"> &lt;- </span><span class="Constant">0</span> ] ] <span class="traceContains">+error: duplicate expectation for location '1'</span> <span class="Delimiter">:(scenario memory_check_string_length)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">3</span> <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">97</span> <span class="Comment"># 'a'</span> <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">98</span> <span class="Comment"># 'b'</span> <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">99</span> <span class="Comment"># 'c'</span> memory-should-contain [ <span class="Constant">1</span>:array:character<span class="Special"> &lt;- </span>[ab] ] ] <span class="traceContains">+error: expected location '1' to contain length 2 of string [ab] but saw 3</span> <span class="Delimiter">:(scenario memory_check_string)</span> def main [ <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">3</span> <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">97</span> <span class="Comment"># 'a'</span> <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">98</span> <span class="Comment"># 'b'</span> <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">99</span> <span class="Comment"># 'c'</span> memory-should-contain [ <span class="Constant">1</span>:array:character<span class="Special"> &lt;- </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">:(scenario memory_invalid_string_check)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ memory-should-contain [ <span class="Constant">1</span><span class="Special"> &lt;- </span>[abc] ] ] <span class="traceContains">+error: location '1' can't contain non-number [abc]</span> <span class="Delimiter">:(scenario memory_check_with_comment)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ memory-should-contain [ <span class="Constant">1</span><span class="Special"> &lt;- </span><span class="Constant">34</span> <span class="Comment"># comment</span> ] ] <span class="traceAbsent">-error: location 1 can't contain non-number 34 # comment</span> <span class="Comment"># but there'll be an error signalled by memory-should-contain</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_fails)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ trace-should-contain [ <span class="Normal">a</span>: b <span class="Normal">a</span>: d ] ] <span class="traceContains">+error: missing [b] in trace with label 'a'</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> TRACE_SHOULD_CONTAIN<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;trace-should-contain&quot;</span><span class="Delimiter">,</span> TRACE_SHOULD_CONTAIN<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> TRACE_SHOULD_CONTAIN: <span class="Delimiter">{</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> TRACE_SHOULD_CONTAIN: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Passed<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> check_trace<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><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 errors rather</span> <span class="Comment">// than just printing to stderr</span> <span class="Normal">void</span> check_trace<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> Trace_stream<span class="Delimiter">-&gt;</span>newline<span class="Delimiter">();</span> vector&lt;trace_line&gt; expected_lines = parse_trace<span class="Delimiter">(</span>expected<span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Normal">int</span> curr_expected_line = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Normal">for</span> <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>label != p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>contents != trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<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> <span class="Normal">if</span> <span class="Delimiter">(</span>curr_expected_line == SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: missing [&quot;</span> &lt;&lt; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>contents &lt;&lt; <span class="Constant">&quot;] &quot;</span> &lt;&lt; <span class="Constant">&quot;in trace with label '&quot;</span> &lt;&lt; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>label &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">else</span> raise &lt;&lt; <span class="Constant">&quot;missing [&quot;</span> &lt;&lt; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>contents &lt;&lt; <span class="Constant">&quot;] &quot;</span> &lt;&lt; <span class="Constant">&quot;in trace with label '&quot;</span> &lt;&lt; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>label &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Hide_errors<span class="Delimiter">)</span> DUMP<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>label<span class="Delimiter">);</span> Passed = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> vector&lt;trace_line&gt; parse_trace<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> vector&lt;string&gt; buf = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">);</span> vector&lt;trace_line&gt; result<span class="Delimiter">;</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>buf<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> = trim<span class="Delimiter">(</span>buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span class="Normal">if</span> <span class="Delimiter">(</span>buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>empty<span class="Delimiter">())</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="Normal">int</span> delim = buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>find<span class="Delimiter">(</span><span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span> result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>trace_line<span class="Delimiter">(</span>trim<span class="Delimiter">(</span>buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>substr<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> delim<span class="Delimiter">)),</span> trim<span class="Delimiter">(</span>buf<span class="Delimiter">.</span>at<span class="Delimiter">(</span>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_fails_in_nonfirst_line)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [b] ] trace-should-contain [ <span class="Normal">a</span>: b <span class="Normal">a</span>: d ] ] <span class="traceContains">+error: missing [d] in trace with label 'a'</span> <span class="Delimiter">:(scenario trace_check_passes_silently)</span> <span class="Special">% Scenario_testing_scenario = true;</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [b] ] trace-should-contain [ <span class="Normal">a</span>: b ] ] <span class="traceAbsent">-error: missing [b] in trace with label 'a'</span> $error: <span class="Constant">0</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 &quot;B should not exist after A.&quot;</span> <span class="Delimiter">:(scenario trace_negative_check_fails)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [b] ] trace-should-<span class="Normal">not</span>-contain [ <span class="Normal">a</span>: b ] ] <span class="traceContains">+error: unexpected [b] in trace with label 'a'</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> TRACE_SHOULD_NOT_CONTAIN<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;trace-should-not-contain&quot;</span><span class="Delimiter">,</span> TRACE_SHOULD_NOT_CONTAIN<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> TRACE_SHOULD_NOT_CONTAIN: <span class="Delimiter">{</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> TRACE_SHOULD_NOT_CONTAIN: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Passed<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> check_trace_missing<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><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 errors rather</span> <span class="Comment">// than just printing to stderr</span> <span class="Normal">bool</span> check_trace_missing<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; in<span class="Delimiter">)</span> <span class="Delimiter">{</span> Trace_stream<span class="Delimiter">-&gt;</span>newline<span class="Delimiter">();</span> vector&lt;trace_line&gt; lines = parse_trace<span class="Delimiter">(</span>in<span class="Delimiter">);</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>lines<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>trace_count<span class="Delimiter">(</span>lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>label<span class="Delimiter">,</span> lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>contents<span class="Delimiter">)</span> != <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> raise &lt;&lt; <span class="Constant">&quot;unexpected [&quot;</span> &lt;&lt; lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>contents &lt;&lt; <span class="Constant">&quot;] in trace with label '&quot;</span> &lt;&lt; lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>label &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<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">% Scenario_testing_scenario = true;</span> def main [ trace-should-<span class="Normal">not</span>-contain [ <span class="Normal">a</span>: b ] ] <span class="traceAbsent">-error: unexpected [b] in trace with label 'a'</span> $error: <span class="Constant">0</span> <span class="Delimiter">:(scenario trace_negative_check_fails_on_any_unexpected_line)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [d] ] trace-should-<span class="Normal">not</span>-contain [ <span class="Normal">a</span>: b <span class="Normal">a</span>: d ] ] <span class="traceContains">+error: unexpected [d] in trace with label 'a'</span> <span class="Delimiter">:(scenario trace_count_check)</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [foo] ] check-trace-count-<span class="Normal">for</span>-label <span class="Constant">1</span><span class="Delimiter">,</span> [a] ] <span class="Comment"># checks are inside scenario</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> CHECK_TRACE_COUNT_FOR_LABEL<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;check-trace-count-for-label&quot;</span><span class="Delimiter">,</span> CHECK_TRACE_COUNT_FOR_LABEL<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> CHECK_TRACE_COUNT_FOR_LABEL: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'check-trace-count-for-label' requires exactly two ingredients, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;first ingredient of 'check-trace-count-for-label' should be a number (count), but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_literal_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;second ingredient of 'check-trace-count-for-label' should be a literal string (label), but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> CHECK_TRACE_COUNT_FOR_LABEL: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Passed<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Normal">int</span> expected_count = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> string label = current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>name<span class="Delimiter">;</span> <span class="Normal">int</span> count = trace_count<span class="Delimiter">(</span>label<span class="Delimiter">);</span> <span class="Normal">if</span> <span class="Delimiter">(</span>count != expected_count<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario &amp;&amp; !Scenario_testing_scenario<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// genuine test in a mu file</span> raise &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; Current_scenario<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;expected &quot;</span> &lt;&lt; expected_count &lt;&lt; <span class="Constant">&quot; lines in trace with label '&quot;</span> &lt;&lt; label &lt;&lt; <span class="Constant">&quot;' in trace: &quot;</span> &lt;&lt; end<span class="Delimiter">();</span> DUMP<span class="Delimiter">(</span>label<span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Delimiter">{</span> <span class="Comment">// just testing scenario support</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;expected &quot;</span> &lt;&lt; expected_count &lt;&lt; <span class="Constant">&quot; lines in trace with label '&quot;</span> &lt;&lt; label &lt;&lt; <span class="Constant">&quot;' in trace</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Scenario_testing_scenario<span class="Delimiter">)</span> Passed = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(scenario trace_count_check_2)</span> <span class="Special">% Scenario_testing_scenario = true;</span> <span class="Special">% Hide_errors = true;</span> def main [ run [ trace <span class="Constant">1</span><span class="Delimiter">,</span> [a]<span class="Delimiter">,</span> [foo] ] check-trace-count-<span class="Normal">for</span>-label <span class="Constant">2</span><span class="Delimiter">,</span> [a] ] <span class="traceContains">+error: main: expected 2 lines in trace with label 'a' in trace</span> <span class="Comment">//: Minor detail: ignore 'system' calls in scenarios, since anything we do</span> <span class="Comment">//: with them is by definition impossible to test through mu.</span> <span class="Delimiter">:(after &quot;case _SYSTEM:&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_scenario<span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="SalientComment">//:: Warn if people use '_' manually in function names. They're reserved for internal use.</span> <span class="Delimiter">:(scenario recipe_name_with_underscore)</span> <span class="Special">% Hide_errors = true;</span> def foo_bar [ ] <span class="traceContains">+error: foo_bar: don't create recipes with '_' in the name</span> <span class="Delimiter">:(before &quot;End recipe Fields&quot;)</span> <span class="Normal">bool</span> is_autogenerated<span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End recipe Constructor&quot;)</span> is_autogenerated = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(code)</span> <span class="Normal">void</span> mark_autogenerated<span class="Delimiter">(</span>recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span> get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>is_autogenerated = <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(after &quot;void transform_all()&quot;)</span> <span class="Normal">for</span> <span class="Delimiter">(</span>map&lt;recipe_ordinal<span class="Delimiter">,</span> recipe&gt;::iterator p = Recipe<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Recipe<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">const</span> recipe&amp; r = p<span class="Delimiter">-&gt;</span>second<span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>r<span class="Delimiter">.</span>name<span class="Delimiter">.</span>find<span class="Delimiter">(</span><span class="Constant">'_'</span><span class="Delimiter">)</span> == string::npos<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="Normal">if</span> <span class="Delimiter">(</span>r<span class="Delimiter">.</span>is_autogenerated<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="Comment">// created by previous call to transform_all()</span> raise &lt;&lt; r<span class="Delimiter">.</span>name &lt;&lt; <span class="Constant">&quot;: don't create recipes with '_' in the name</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="SalientComment">//:: Helpers</span> <span class="Delimiter">:(code)</span> <span class="Comment">// just for the scenarios running scenarios in C++ layers</span> <span class="Normal">void</span> run_mu_scenario<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; form<span class="Delimiter">)</span> <span class="Delimiter">{</span> istringstream in<span class="Delimiter">(</span>form<span class="Delimiter">);</span> in &gt;&gt; std::noskipws<span class="Delimiter">;</span> skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span> string _scenario = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span> assert<span class="Delimiter">(</span>_scenario == <span class="Constant">&quot;scenario&quot;</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> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->