about summary refs log blame commit diff stats
path: root/html/003trace.cc.html
blob: 2a6669488cc029992e65211d138f8243f39b5d2f (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                                          
                               

                                                
                                  
                                        

                       
                                                                          

                                                                                            
                             
                               
                             
                                                      
                              
                            

        

       
     















































                                                                                                            

































                                                                                                                                                                                                                   
                                                              

                                                                                                                                                        


                                                                                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                                            

                                 
                                                                


                                                                                                                                                                                                                          
                                                                
                                                                                                                  

                                                                                 
 
                                                                
                                                                                
                                                                     

                                                              
                                                   


                                                                                 
                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                            
 

                                                                                                                                                                 

                                  


                                                                                                                                                                                                              
                                                      
                                                      


                                                                                       
                                                                                                    

                                                                                                                                                                                      
                                                                                                               
                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                       
                                                                                  
                                                                                    

                                                                                     

                                  

                                                                                                                                                                                                      
                                                        
                                                                                      

                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                                      

                                                                                                                      





                                                                                               
                                                                       
                                                                                                                                                                                                                                                                                                                                                                          

                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    


                                                                                                          
                                                                                                                                                                                                                                                                                                                                         


                                                                              
 
                                                              
                                                                         
                                                                

                                                                                                                                                                                                                    
                                                                           

                                
                                                                                                                                                                                                                                                                                                                    
 
                                                                                                                                                                                                                                                                                
 

                                                                                                       
                                                                                                                                        


                                                                                                

                                                                                                                                                                                                             
                                                                                 

                                                                                                                                                                                                                                                         



                                                                                                                                                                                                
                                                                                                                                                                                                                                                             


                                  


                                                                                                                                 
 
                                                                 
                                                                                                                                                                                                                                                                                                                                                                                                                                               
 
                                                                

                                                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                   

                                                                                                                                                                                                                                                                                                                                                                    
                                                        
                                                                                                                                                                                                                                                                                    

                                                                                                                                                                                                                                                                                   

                                                                                                                                                                                                                                                                                                                                                                                                                                                    

                                                                              
                                                                                                                                                                                                 


                                                                              
                                                                                                                                                                                                                                                                                                                                                                      
                                                          
                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                     


                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                            



                                                                                                            



                                                                                                                                                                                                                                                                                                    
                                                                                       
                                                                                      
                                  
                                                                   
                                                                                                                                                                                                                             
                                                                                                                                                                                                           




                                  
                                                                                                                                                        
                                                                                                                                                                                                     

                                





                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                
                                    



                                                                               

                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                        
                                                                                                              

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 


                                                                                                                                            

                                                                                                                                  
                                                                                                                                                                                          






                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
 
                                                                                                                                                                                                              
                                                                                                                                                                                                                                 

                                
                                                                                                                                                                     
                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                         

                                



                                                                                                                                                                          

                                                                                                                                                                                


                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                 


                                                                                                                                                                                                                                            
                                                                                          




                                                                                                                                                           

                                                                                                                                                                                      
                                                                                                                                                    
                                                                                                                                                                                                                                                              
                                                                                                                    



                                                                                                                                                                                                                                                                                        
                                                                                                                                                           
                                                                                                         
                                                                                                                                                                                                                                            
                                           
                                                                                                                                                                                                                                                                  

                                                                                                        
                                                                                                                                                                                                                                            


                                                                                                                                                          



                                                                                 
                                                                             
                                                                               
                                                                           
                                                                              
                                                                          
                                                                              
                                                                          

                                                                                    
                                                                                  

                                                                                    

                                                                                  

                                                                               
 

                                                                                                
                                                                    



                                                                                       
                                                        
                                                                                                 
                                                                          

                                                                                                                                                             
                                                                                                                                     


                                                                                                      


       
<!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>Mu - 003trace.cc</title>
<meta name="Generator" content="Vim/7.3">
<meta name="plugin-version" content="vim7.3_v6">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css">
<style type="text/css">
<!--
pre { font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
.PreProc { color: #800080; }
.cSpecial { color: #008000; }
.Identifier { color: #fcb165; }
.Constant { color: #00a0a0; }
.Normal { color: #eeeeee; background-color: #080808; }
.Delimiter { color: #800080; }
.Comment { color: #9090ff; }
-->
</style>
</head>
<body>
<pre>
<span class="Comment">//: The goal of this skeleton is to make programs more easy to understand and</span>
<span class="Comment">//: more malleable, easy to rewrite in radical ways without accidentally</span>
<span class="Comment">//: breaking some corner case. Tests further both goals. They help</span>
<span class="Comment">//: understandability by letting one make small changes and get feedback. What</span>
<span class="Comment">//: if I wrote this line like so? What if I removed this function call, is it</span>
<span class="Comment">//: really necessary? Just try it, see if the tests pass. Want to explore</span>
<span class="Comment">//: rewriting this bit in this way? Tests put many refactorings on a firmer</span>
<span class="Comment">//: footing.</span>
<span class="Comment">//:</span>
<span class="Comment">//: But the usual way we write tests seems incomplete. Refactorings tend to</span>
<span class="Comment">//: work in the small, but don't help with changes to function boundaries. If</span>
<span class="Comment">//: you want to extract a new function you have to manually test-drive it to</span>
<span class="Comment">//: create tests for it. If you want to inline a function its tests are no</span>
<span class="Comment">//: longer valid. In both cases you end up having to reorganize code as well as</span>
<span class="Comment">//: tests, an error-prone activity.</span>
<span class="Comment">//:</span>
<span class="Comment">//: This file tries to fix this problem by supporting domain-driven testing</span>
<span class="Comment">//: We try to focus on the domain of inputs the program should work on. All</span>
<span class="Comment">//: tests invoke the program in a single way: by calling run() with different</span>
<span class="Comment">//: inputs. The program operates on the input and logs _facts_ it deduces to a</span>
<span class="Comment">//: trace:</span>
<span class="Comment">//:   trace(&quot;label&quot;) &lt;&lt; &quot;fact 1: &quot; &lt;&lt; val;</span>
<span class="Comment">//:</span>
<span class="Comment">//: The tests check for facts:</span>
<span class="Comment">//:   :(scenario foo)</span>
<span class="Comment">//:   34  # call run() with this input</span>
<span class="Comment">//:   +label: fact 1: 34  # trace should have logged this at the end</span>
<span class="Comment">//:   -label: fact 1: 35  # trace should never contain such a line</span>
<span class="Comment">//:</span>
<span class="Comment">//: Since we never call anything but the run() function directly, we never have</span>
<span class="Comment">//: to rewrite the tests when we reorganize the internals of the program. We</span>
<span class="Comment">//: just have to make sure our rewrite deduces the same facts about the domain,</span>
<span class="Comment">//: and that's something we're going to have to do anyway.</span>
<span class="Comment">//:</span>
<span class="Comment">//: To avoid the combinatorial explosion of integration tests, we organize the</span>
<span class="Comment">//: program into different layers, and each fact is logged to the trace with a</span>
<span class="Comment">//: specific label. Individual tests can focus on specific labels. In essence,</span>
<span class="Comment">//: validating the facts logged with a specific label is identical to calling</span>
<span class="Comment">//: some internal subsystem.</span>
<span class="Comment">//:</span>
<span class="Comment">//: Traces interact salubriously with layers. Thanks to our ordering</span>
<span class="Comment">//: directives, each layer can contain its own tests. They may rely on other</span>
<span class="Comment">//: layers, but when a test fails its usually due to breakage in the same</span>
<span class="Comment">//: layer. When multiple tests fail, it's usually useful to debug the very</span>
<span class="Comment">//: first test to fail. This is in contrast with the traditional approach,</span>
<span class="Comment">//: where changes can cause breakages in faraway subsystems, and picking the</span>
<span class="Comment">//: right test to debug can be an important skill to pick up.</span>
<span class="Comment">//:</span>
<span class="Comment">//: To build robust tests, trace facts about your domain rather than details of</span>
<span class="Comment">//: how you computed them.</span>
<span class="Comment">//:</span>
<span class="Comment">//: More details: <a href="http://akkartik.name/blog/tracing-tests">http://akkartik.name/blog/tracing-tests</a></span>
<span class="Comment">//:</span>
<span class="Comment">//: ---</span>
<span class="Comment">//:</span>
<span class="Comment">//: Between layers and domain-driven testing, programming starts to look like a</span>
<span class="Comment">//: fundamentally different activity. Instead of a) superficial, b) local rules</span>
<span class="Comment">//: on c) code [like <a href="http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],">http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],</a></span>
<span class="Comment">//: we allow programmers to engage with the a) deep, b) global structure of the</span>
<span class="Comment">//: c) domain. If you can systematically track discontinuities in the domain</span>
<span class="Comment">//: you don't care if the code used gotos as long as it passed the tests. If</span>
<span class="Comment">//: tests become more robust to run it becomes easier to try out radically</span>
<span class="Comment">//: different implementations for the same program. If code is super-easy to</span>
<span class="Comment">//: rewrite, it becomes less important what indentation style it uses, or that</span>
<span class="Comment">//: the objects are appropriately encapsulated, or that the functions are</span>
<span class="Comment">//: referentially transparent.</span>
<span class="Comment">//:</span>
<span class="Comment">//: Instead of plumbing, programming becomes building and gradually refining a</span>
<span class="Comment">//: map of the environment the program must operate under. Whether a program is</span>
<span class="Comment">//: 'correct' at a given point in time is a red herring; what matters is</span>
<span class="Comment">//: avoiding regression by monotonically nailing down the more 'eventful' parts</span>
<span class="Comment">//: of the terrain. It helps readers new and old and rewards curiosity to</span>
<span class="Comment">//: organize large programs in self-similar hiearchies of example scenarios</span>
<span class="Comment">//: colocated with the code that makes them work.</span>
<span class="Comment">//:</span>
<span class="Comment">//:   &quot;Programming properly should be regarded as an activity by which</span>
<span class="Comment">//:   programmers form a mental model, rather than as production of a program.&quot;</span>
<span class="Comment">//:   -- Peter Naur (<a href="http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)">http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)</a></span>

<span class="Delimiter">:(before &quot;int main&quot;)</span>
<span class="Comment">// End Tracing  // hack to ensure most code in this layer comes before anything else</span>

<span class="Delimiter">:(before &quot;End Types&quot;)</span>
<span class="Normal">struct</span> trace_line <span class="Delimiter">{</span>
  <span class="Normal">int</span> depth<span class="Delimiter">;</span>  <span class="Comment">// optional field just to help browse traces later</span>
  string label<span class="Delimiter">;</span>
  string contents<span class="Delimiter">;</span>
  trace_line<span class="Delimiter">(</span>string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
  trace_line<span class="Delimiter">(</span><span class="Normal">int</span> d<span class="Delimiter">,</span> string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span>d<span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
<span class="Delimiter">};</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
<span class="Normal">const</span> <span class="Normal">int</span> Max_depth = <span class="Constant">9999</span><span class="Delimiter">;</span>
<span class="Normal">const</span> <span class="Normal">int</span> Error_depth = <span class="Constant">0</span><span class="Delimiter">;</span>  <span class="Comment">// definitely always print errors</span>
<span class="Normal">const</span> <span class="Normal">int</span> App_depth = <span class="Constant">2</span><span class="Delimiter">;</span>  <span class="Comment">// temporarily where all mu code will trace to</span>
<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
<span class="Normal">bool</span> Hide_errors = <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Setup&quot;)</span>
Hide_errors = <span class="Constant">false</span><span class="Delimiter">;</span>

<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
<span class="Normal">struct</span> trace_stream <span class="Delimiter">{</span>
  vector&lt;trace_line&gt; past_lines<span class="Delimiter">;</span>
  <span class="Comment">// accumulator for current line</span>
  ostringstream* curr_stream<span class="Delimiter">;</span>
  string curr_label<span class="Delimiter">;</span>
  <span class="Normal">int</span> curr_depth<span class="Delimiter">;</span>
  <span class="Normal">int</span> callstack_depth<span class="Delimiter">;</span>
  <span class="Normal">int</span> collect_depth<span class="Delimiter">;</span>
  ofstream null_stream<span class="Delimiter">;</span>  <span class="Comment">// never opens a file, so writes silently fail</span>
  trace_stream<span class="Delimiter">()</span> :curr_stream<span class="Delimiter">(</span><span class="Constant">NULL</span><span class="Delimiter">),</span> curr_depth<span class="Delimiter">(</span>Max_depth<span class="Delimiter">),</span> callstack_depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> collect_depth<span class="Delimiter">(</span>Max_depth<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
  ~trace_stream<span class="Delimiter">()</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>curr_stream<span class="Delimiter">)</span> <span class="Normal">delete</span> curr_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span>

  ostream&amp; stream<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Identifier">return</span> stream<span class="Delimiter">(</span>Max_depth<span class="Delimiter">,</span> label<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>

  ostream&amp; stream<span class="Delimiter">(</span><span class="Normal">int</span> depth<span class="Delimiter">,</span> string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>depth &gt; collect_depth<span class="Delimiter">)</span> <span class="Identifier">return</span> null_stream<span class="Delimiter">;</span>
    curr_stream = <span class="Normal">new</span> ostringstream<span class="Delimiter">;</span>
    curr_label = label<span class="Delimiter">;</span>
    curr_depth = depth<span class="Delimiter">;</span>
    <span class="Identifier">return</span> *curr_stream<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>

  <span class="Comment">// be sure to call this before messing with curr_stream or curr_label</span>
  <span class="Normal">void</span> newline<span class="Delimiter">()</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!curr_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
    string curr_contents = curr_stream<span class="Delimiter">-&gt;</span>str<span class="Delimiter">();</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>curr_contents<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
    past_lines<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>trace_line<span class="Delimiter">(</span>curr_depth<span class="Delimiter">,</span> trim<span class="Delimiter">(</span>curr_label<span class="Delimiter">),</span> curr_contents<span class="Delimiter">));</span>  <span class="Comment">// preserve indent in contents</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!Hide_errors &amp;&amp; curr_label == <span class="Constant">&quot;error&quot;</span><span class="Delimiter">)</span>
      cerr &lt;&lt; curr_label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; curr_contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
    <span class="Normal">delete</span> curr_stream<span class="Delimiter">;</span>
    curr_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span>
    curr_label<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
    curr_depth = Max_depth<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>

  <span class="Comment">// useful for debugging</span>
  string readable_contents<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>  <span class="Comment">// empty label = show everything</span>
    ostringstream output<span class="Delimiter">;</span>
    label = trim<span class="Delimiter">(</span>label<span class="Delimiter">);</span>
    <span class="Normal">for</span> <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>label<span class="Delimiter">.</span>empty<span class="Delimiter">()</span> || label == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        output &lt;&lt; std::setw<span class="Delimiter">(</span><span class="Constant">4</span><span class="Delimiter">)</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>depth &lt;&lt; <span class="Constant">' '</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
    <span class="Identifier">return</span> output<span class="Delimiter">.</span>str<span class="Delimiter">();</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">};</span>

^L

trace_stream* Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span>

<span class="Comment">// Top-level helper. IMPORTANT: can't nest</span>
<span class="PreProc">#define trace(</span><span class="Delimiter">...</span><span class="PreProc">)  !Trace_stream ? cerr </span><span class="Comment">/*</span><span class="Comment">print nothing</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(__VA_ARGS__)</span>

<span class="Comment">// Errors are a special layer.</span>
<span class="PreProc">#define raise  (!Trace_stream ? </span><span class="Delimiter">(</span><span class="PreProc">tb_shutdown</span><span class="Delimiter">(),</span><span class="PreProc">cerr</span><span class="Delimiter">)</span><span class="PreProc"> </span><span class="Comment">/*</span><span class="Comment">do print</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(Error_depth</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">&quot;error&quot;</span><span class="PreProc">))</span>
<span class="Comment">// Inside tests, fail any tests that displayed (unexpected) errors.</span>
<span class="Comment">// Expected errors in tests should always be hidden and silently checked for.</span>
<span class="Delimiter">:(before &quot;End Test Teardown&quot;)</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>Passed &amp;&amp; !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> <span class="Delimiter">{</span>
  Passed = <span class="Constant">false</span><span class="Delimiter">;</span>
  ++Num_failures<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(before &quot;End Types&quot;)</span>
<span class="Normal">struct</span> end <span class="Delimiter">{};</span>
<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
ostream&amp; <span class="Normal">operator</span>&lt;&lt;<span class="Delimiter">(</span>ostream&amp; os<span class="Delimiter">,</span> unused end<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">)</span> Trace_stream<span class="Delimiter">-&gt;</span>newline<span class="Delimiter">();</span>
  <span class="Identifier">return</span> os<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="PreProc">#define CLEAR_TRACE  </span><span class="Normal">delete</span><span class="PreProc"> Trace_stream</span><span class="Delimiter">,</span><span class="PreProc"> Trace_stream = </span><span class="Normal">new</span><span class="PreProc"> trace_stream</span><span class="Delimiter">;</span>

<span class="PreProc">#define DUMP(label)  </span><span class="Normal">if</span><span class="PreProc"> (Trace_stream) cerr &lt;&lt; Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">readable_contents(label)</span><span class="Delimiter">;</span>

<span class="Comment">// All scenarios save their traces in the repo, just like code. This gives</span>
<span class="Comment">// future readers more meat when they try to make sense of a new project.</span>
<span class="Normal">static</span> string Trace_dir = <span class="Constant">&quot;.traces/&quot;</span><span class="Delimiter">;</span>
string Trace_file<span class="Delimiter">;</span>

<span class="Comment">// Trace_stream is a resource, lease_tracer uses RAII to manage it.</span>
<span class="Normal">struct</span> lease_tracer <span class="Delimiter">{</span>
  lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span> Trace_stream = <span class="Normal">new</span> trace_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span>
  ~lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>  <span class="Comment">// in case tests close Trace_stream</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!Trace_file<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <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 &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> Trace_file = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">};</span>

<span class="PreProc">#define START_TRACING_UNTIL_END_OF_SCOPE  lease_tracer leased_tracer</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Test Setup&quot;)</span>
START_TRACING_UNTIL_END_OF_SCOPE

<span class="Delimiter">:(before &quot;End Includes&quot;)</span>
<span class="PreProc">#define CHECK_TRACE_CONTENTS(</span><span class="Delimiter">...</span><span class="PreProc">)  check_trace_contents(__FUNCTION__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__FILE__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__LINE__</span><span class="Delimiter">,</span><span class="PreProc"> __VA_ARGS__)</span>

<span class="Delimiter">:(before &quot;End Tracing&quot;)</span>
<span class="Normal">bool</span> check_trace_contents<span class="Delimiter">(</span>string FUNCTION<span class="Delimiter">,</span> string <span class="Normal">FILE</span><span class="Delimiter">,</span> <span class="Normal">int</span> LINE<span class="Delimiter">,</span> string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
  vector&lt;string&gt; expected_lines = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;^D&quot;</span><span class="Delimiter">);</span>
  <span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span> curr_expected_line = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</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="Constant">true</span><span class="Delimiter">;</span>
  string label<span class="Delimiter">,</span> contents<span class="Delimiter">;</span>
  split_label_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;label<span class="Delimiter">,</span> &amp;contents<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>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>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>

    ++curr_expected_line<span class="Delimiter">;</span>
    <span class="Normal">while</span> <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</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="Constant">true</span><span class="Delimiter">;</span>
    split_label_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;label<span class="Delimiter">,</span> &amp;contents<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>

  ++Num_failures<span class="Delimiter">;</span>
  cerr &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; FUNCTION &lt;&lt; <span class="Constant">&quot;(&quot;</span> &lt;&lt; <span class="Normal">FILE</span> &lt;&lt; <span class="Constant">&quot;:&quot;</span> &lt;&lt; LINE &lt;&lt; <span class="Constant">&quot;): missing [&quot;</span> &lt;&lt; contents &lt;&lt; <span class="Constant">&quot;] in trace:</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span>
  DUMP<span class="Delimiter">(</span>label<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="Normal">void</span> split_label_contents<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; s<span class="Delimiter">,</span> string* label<span class="Delimiter">,</span> string* contents<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">static</span> <span class="Normal">const</span> string delim<span class="Delimiter">(</span><span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span>
  <span class="Normal">size_t</span> pos = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>pos == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    *label = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>
    *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Normal">else</span> <span class="Delimiter">{</span>
    *label = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> pos<span class="Delimiter">));</span>
    *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span>pos+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">)));</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

^L

<span class="Normal">int</span> trace_count<span class="Delimiter">(</span>string label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>label<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Normal">int</span> trace_count<span class="Delimiter">(</span>string label<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!Trace_stream<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">long</span> result = <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>label == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>line == <span class="Constant">&quot;&quot;</span> || trim<span class="Delimiter">(</span>line<span class="Delimiter">)</span> == trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<span class="Delimiter">))</span>
        ++result<span class="Delimiter">;</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="PreProc">#define CHECK_TRACE_CONTAINS_ERROR()  CHECK(trace_count(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">)</span>
<span class="PreProc">#define CHECK_TRACE_DOESNT_CONTAIN_ERROR() \</span>
<span class="PreProc">  </span><span class="Normal">if</span><span class="PreProc"> (trace_count(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">) </span><span class="Delimiter">{</span><span class="PreProc"> \</span>
<span class="PreProc">    ++Num_failures</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span><span class="PreProc"> &lt;&lt; __FUNCTION__ &lt;&lt; </span><span class="Constant">&quot;(&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__FILE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;:&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__LINE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;): unexpected errors</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    DUMP(</span><span class="Constant">&quot;error&quot;</span><span class="PreProc">)</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    Passed = </span><span class="Constant">false</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    </span><span class="Identifier">return</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">  </span><span class="Delimiter">}</span>

<span class="PreProc">#define CHECK_TRACE_COUNT(label</span><span class="Delimiter">,</span><span class="PreProc"> count) \</span>
<span class="PreProc">  </span><span class="Normal">if</span><span class="PreProc"> (trace_count(label) != (count)) </span><span class="Delimiter">{</span><span class="PreProc"> \</span>
<span class="PreProc">    ++Num_failures</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span><span class="PreProc"> &lt;&lt; __FUNCTION__ &lt;&lt; </span><span class="Constant">&quot;(&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__FILE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;:&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__LINE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;): trace_count of &quot;</span><span class="PreProc"> &lt;&lt; label &lt;&lt; </span><span class="Constant">&quot; should be &quot;</span><span class="PreProc"> &lt;&lt; count &lt;&lt; </span><span class="cSpecial">'\n'</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    cerr &lt;&lt; </span><span class="Constant">&quot;  got &quot;</span><span class="PreProc"> &lt;&lt; trace_count(label) &lt;&lt; </span><span class="cSpecial">'\n'</span><span class="Delimiter">;</span><span class="PreProc">  </span><span class="Comment">/*</span><span class="Comment"> multiple eval </span><span class="Comment">*/</span><span class="PreProc"> \</span>
<span class="PreProc">    DUMP(label)</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    Passed = </span><span class="Constant">false</span><span class="Delimiter">;</span><span class="PreProc"> \</span>
<span class="PreProc">    </span><span class="Identifier">return</span><span class="Delimiter">;</span><span class="PreProc">  </span><span class="Comment">/*</span><span class="Comment"> Currently we stop at the very first failure. </span><span class="Comment">*/</span><span class="PreProc"> \</span>
<span class="PreProc">  </span><span class="Delimiter">}</span>

<span class="Normal">bool</span> trace_doesnt_contain<span class="Delimiter">(</span>string label<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>label<span class="Delimiter">,</span> line<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Normal">bool</span> trace_doesnt_contain<span class="Delimiter">(</span>string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; tmp = split_first<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span>
  <span class="Identifier">return</span> trace_doesnt_contain<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">));</span>
<span class="Delimiter">}</span>

<span class="PreProc">#define CHECK_TRACE_DOESNT_CONTAIN(</span><span class="Delimiter">...</span><span class="PreProc">)  CHECK(trace_doesnt_contain(__VA_ARGS__))</span>

^L

vector&lt;string&gt; split<span class="Delimiter">(</span>string s<span class="Delimiter">,</span> string delim<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; result<span class="Delimiter">;</span>
  <span class="Normal">size_t</span> begin=<span class="Constant">0</span><span class="Delimiter">,</span> end=s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<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>
    <span class="Normal">if</span> <span class="Delimiter">(</span>end == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> string::npos<span class="Delimiter">));</span>
      <span class="Identifier">break</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> end-begin<span class="Delimiter">));</span>
    begin = end+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
    end = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">,</span> begin<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

vector&lt;string&gt; split_first<span class="Delimiter">(</span>string s<span class="Delimiter">,</span> string delim<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  vector&lt;string&gt; result<span class="Delimiter">;</span>
  <span class="Normal">size_t</span> end=s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span>
  result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">,</span> end<span class="Delimiter">));</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>end != string::npos<span class="Delimiter">)</span>
    result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> end+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">),</span> string::npos<span class="Delimiter">));</span>
  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

string trim<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  string::const_iterator first = s<span class="Delimiter">.</span>begin<span class="Delimiter">();</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span>first != s<span class="Delimiter">.</span>end<span class="Delimiter">()</span> &amp;&amp; isspace<span class="Delimiter">(</span>*first<span class="Delimiter">))</span>
    ++first<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>first == s<span class="Delimiter">.</span>end<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span>

  string::const_iterator last = --s<span class="Delimiter">.</span>end<span class="Delimiter">();</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span>last != s<span class="Delimiter">.</span>begin<span class="Delimiter">()</span> &amp;&amp; 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>

<span class="Delimiter">:(before &quot;End Includes&quot;)</span>
<span class="PreProc">#include</span><span class="Constant">&lt;vector&gt;</span>
<span class="Normal">using</span> std::vector<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;list&gt;</span>
<span class="Normal">using</span> std::list<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;map&gt;</span>
<span class="Normal">using</span> std::map<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;set&gt;</span>
<span class="Normal">using</span> std::set<span class="Delimiter">;</span>
<span class="PreProc">#include</span><span class="Constant">&lt;algorithm&gt;</span>

<span class="PreProc">#include</span><span class="Constant">&lt;sstream&gt;</span>
<span class="Normal">using</span> std::istringstream<span class="Delimiter">;</span>
<span class="Normal">using</span> std::ostringstream<span class="Delimiter">;</span>

<span class="PreProc">#include</span><span class="Constant">&lt;fstream&gt;</span>
<span class="Normal">using</span> std::ifstream<span class="Delimiter">;</span>
<span class="Normal">using</span> std::ofstream<span class="Delimiter">;</span>

<span class="PreProc">#include</span><span class="Constant">&quot;termbox/termbox.h&quot;</span>

<span class="PreProc">#define unused  __attribute__((unused))</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
<span class="Comment">//: In future layers we'll use the depth field as follows:</span>
<span class="Comment">//:</span>
<span class="Comment">//: Errors will be depth 0.</span>
<span class="Comment">//: Mu 'applications' will be able to use depths 1-100 as they like.</span>
<span class="Comment">//: Primitive statements will occupy 101-9989</span>
<span class="Normal">const</span> <span class="Normal">int</span> Initial_callstack_depth = <span class="Constant">101</span><span class="Delimiter">;</span>
<span class="Normal">const</span> <span class="Normal">int</span> Max_callstack_depth = <span class="Constant">9989</span><span class="Delimiter">;</span>
<span class="Comment">//: Finally, details of primitive mu statements will occupy depth 9990-9999 (more on that later as well)</span>
<span class="Comment">//:</span>
<span class="Comment">//: This framework should help us hide some details at each level, mixing</span>
<span class="Comment">//: static ideas like layers with the dynamic notion of call-stack depth.</span>
</pre>
</body>
</html>