about summary refs log tree commit diff stats
path: root/cpp
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-04-22 11:49:24 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-04-22 11:49:24 -0700
commitccd792dace1439b60882fafd1d1bd4b06c405d9e (patch)
treee1c5b825eab5a0173bf57d114eeeb2c5fb26a6de /cpp
parent3c6784a87bb362a7a2f32d617c5950fec23460cd (diff)
downloadmu-ccd792dace1439b60882fafd1d1bd4b06c405d9e.tar.gz
1126 - 'mu test x.mu' runs just scenarios in x.mu
Required still more tweaking of Recipe namespaces. Mindlessly inserting
setup() took a couple of hours to debug because the test function and
the function it was testing ended up getting the same recipe number,
with the inevitable infinite loop :/
Diffstat (limited to 'cpp')
-rw-r--r--cpp/.traces/factorial-test210
-rw-r--r--cpp/001test2
-rw-r--r--cpp/010vm3
-rw-r--r--cpp/020run7
-rw-r--r--cpp/050scenario75
-rw-r--r--cpp/factorial.mu33
6 files changed, 303 insertions, 27 deletions
diff --git a/cpp/.traces/factorial-test b/cpp/.traces/factorial-test
new file mode 100644
index 00000000..1729d718
--- /dev/null
+++ b/cpp/.traces/factorial-test
@@ -0,0 +1,210 @@
+parse/0: instruction: 108
+parse/0:   ingredient: {name: "5", value: 0, type: 0, properties: ["5": "literal"]}
+parse/0:   product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]}
+after-brace/0: recipe test-factorial-test
+after-brace/0: factorial ...
+run/0: instruction test-factorial-test/0
+run/0: instruction factorial/0
+mem/0: new alloc: 1000
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 5
+mem/0: storing 5 in location 1002
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1002 is 5
+run/0: ingredient 1 is 0
+run/0: product 0 is 0
+mem/0: storing 0 in location 1003
+run/0: instruction factorial/4
+mem/0: location 1003 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 6
+run/0: instruction factorial/7
+run/0: ingredient 0 is n
+mem/0: location 1002 is 5
+run/0: ingredient 1 is 1
+run/0: product 0 is 4
+mem/0: storing 4 in location 1004
+run/0: instruction factorial/8
+mem/0: location 1004 is 4
+run/0: instruction factorial/0
+mem/0: new alloc: 1030
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 4
+mem/0: storing 4 in location 1032
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1032 is 4
+run/0: ingredient 1 is 0
+run/0: product 0 is 0
+mem/0: storing 0 in location 1033
+run/0: instruction factorial/4
+mem/0: location 1033 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 6
+run/0: instruction factorial/7
+run/0: ingredient 0 is n
+mem/0: location 1032 is 4
+run/0: ingredient 1 is 1
+run/0: product 0 is 3
+mem/0: storing 3 in location 1034
+run/0: instruction factorial/8
+mem/0: location 1034 is 3
+run/0: instruction factorial/0
+mem/0: new alloc: 1060
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 3
+mem/0: storing 3 in location 1062
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1062 is 3
+run/0: ingredient 1 is 0
+run/0: product 0 is 0
+mem/0: storing 0 in location 1063
+run/0: instruction factorial/4
+mem/0: location 1063 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 6
+run/0: instruction factorial/7
+run/0: ingredient 0 is n
+mem/0: location 1062 is 3
+run/0: ingredient 1 is 1
+run/0: product 0 is 2
+mem/0: storing 2 in location 1064
+run/0: instruction factorial/8
+mem/0: location 1064 is 2
+run/0: instruction factorial/0
+mem/0: new alloc: 1090
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 2
+mem/0: storing 2 in location 1092
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1092 is 2
+run/0: ingredient 1 is 0
+run/0: product 0 is 0
+mem/0: storing 0 in location 1093
+run/0: instruction factorial/4
+mem/0: location 1093 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 6
+run/0: instruction factorial/7
+run/0: ingredient 0 is n
+mem/0: location 1092 is 2
+run/0: ingredient 1 is 1
+run/0: product 0 is 1
+mem/0: storing 1 in location 1094
+run/0: instruction factorial/8
+mem/0: location 1094 is 1
+run/0: instruction factorial/0
+mem/0: new alloc: 1120
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 1
+mem/0: storing 1 in location 1122
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1122 is 1
+run/0: ingredient 1 is 0
+run/0: product 0 is 0
+mem/0: storing 0 in location 1123
+run/0: instruction factorial/4
+mem/0: location 1123 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 6
+run/0: instruction factorial/7
+run/0: ingredient 0 is n
+mem/0: location 1122 is 1
+run/0: ingredient 1 is 1
+run/0: product 0 is 0
+mem/0: storing 0 in location 1124
+run/0: instruction factorial/8
+mem/0: location 1124 is 0
+run/0: instruction factorial/0
+mem/0: new alloc: 1150
+mem/0: array size is 30
+run/0: instruction factorial/1
+run/0: product 0 is 0
+mem/0: storing 0 in location 1152
+run/0: instruction factorial/3
+run/0: ingredient 0 is n
+mem/0: location 1152 is 0
+run/0: ingredient 1 is 0
+run/0: product 0 is 1
+mem/0: storing 1 in location 1153
+run/0: instruction factorial/4
+mem/0: location 1153 is 1
+run/0: ingredient 0 is 1
+run/0: jump-unless fell through
+run/0: instruction factorial/5
+run/0: result 0 is 1
+mem/0: storing 1 in location 1125
+run/0: instruction factorial/9
+run/0: ingredient 0 is subresult
+mem/0: location 1125 is 1
+run/0: ingredient 1 is n
+mem/0: location 1122 is 1
+run/0: ingredient 1 is 1
+run/0: product 0 is 1
+mem/0: storing 1 in location 1126
+run/0: instruction factorial/10
+mem/0: location 1126 is 1
+run/0: result 0 is 1
+mem/0: storing 1 in location 1095
+run/0: instruction factorial/9
+run/0: ingredient 0 is subresult
+mem/0: location 1095 is 1
+run/0: ingredient 1 is n
+mem/0: location 1092 is 2
+run/0: ingredient 1 is 2
+run/0: product 0 is 2
+mem/0: storing 2 in location 1096
+run/0: instruction factorial/10
+mem/0: location 1096 is 2
+run/0: result 0 is 2
+mem/0: storing 2 in location 1065
+run/0: instruction factorial/9
+run/0: ingredient 0 is subresult
+mem/0: location 1065 is 2
+run/0: ingredient 1 is n
+mem/0: location 1062 is 3
+run/0: ingredient 1 is 3
+run/0: product 0 is 6
+mem/0: storing 6 in location 1066
+run/0: instruction factorial/10
+mem/0: location 1066 is 6
+run/0: result 0 is 6
+mem/0: storing 6 in location 1035
+run/0: instruction factorial/9
+run/0: ingredient 0 is subresult
+mem/0: location 1035 is 6
+run/0: ingredient 1 is n
+mem/0: location 1032 is 4
+run/0: ingredient 1 is 4
+run/0: product 0 is 24
+mem/0: storing 24 in location 1036
+run/0: instruction factorial/10
+mem/0: location 1036 is 24
+run/0: result 0 is 24
+mem/0: storing 24 in location 1005
+run/0: instruction factorial/9
+run/0: ingredient 0 is subresult
+mem/0: location 1005 is 24
+run/0: ingredient 1 is n
+mem/0: location 1002 is 5
+run/0: ingredient 1 is 5
+run/0: product 0 is 120
+mem/0: storing 120 in location 1006
+run/0: instruction factorial/10
+mem/0: location 1006 is 120
+run/0: result 0 is 120
+mem/0: storing 120 in location 1
diff --git a/cpp/001test b/cpp/001test
index 8c4bc5e3..0db10e4b 100644
--- a/cpp/001test
+++ b/cpp/001test
@@ -60,6 +60,8 @@ if (argc > 2 && is_equal(argv[1], "test") && is_number(argv[2])) {
   return 0;
 }
 
+// End Test Runs
+
 :(code)
 void run_tests() {
   time_t t; time(&t);
diff --git a/cpp/010vm b/cpp/010vm
index a900a56e..0a1ada2c 100644
--- a/cpp/010vm
+++ b/cpp/010vm
@@ -152,9 +152,6 @@ setup_recipes();
 assert(MAX_PRIMITIVE_RECIPES < 100);  // level 0 is primitives; until 99
 Next_recipe_number = 100;
 // End Load Recipes
-// give tests a consistent starting point
-assert(Next_recipe_number < 1000);
-Next_recipe_number = 1000;
 delete Trace_stream;  Trace_stream = new trace_stream;
 :(before "End Setup")
 Next_recipe_number = 1000;  // consistent new numbers for each test
diff --git a/cpp/020run b/cpp/020run
index 164bc5ac..0ce86d7a 100644
--- a/cpp/020run
+++ b/cpp/020run
@@ -104,6 +104,7 @@ if (argc > 1) {
 //?   Trace_stream->dump_layer = "all"; //? 2
   transform_all();
   recipe_number r = Recipe_number[string("main")];
+//?   Trace_stream->dump_layer = "all"; //? 1
   if (r) run(r);
   dump_memory();
 }
@@ -119,14 +120,14 @@ void load(string filename) {
   add_recipes(fin);
   transform_all();
   fin.close();
+  // freeze everything so it doesn't get cleared by tests
+  recently_added_recipes.clear();
+  recently_added_types.clear();
 }
 
 //:: On startup, load everything in core.mu
 :(before "End Load Recipes")
 load("core.mu");
-// freeze everything so it doesn't get cleared by tests
-recently_added_recipes.clear();
-recently_added_types.clear();
 
 :(code)
 // helper for tests
diff --git a/cpp/050scenario b/cpp/050scenario
index 16949048..34edbe71 100644
--- a/cpp/050scenario
+++ b/cpp/050scenario
@@ -12,35 +12,41 @@ struct scenario {
 :(before "End Globals")
 vector<scenario> Scenarios;
 
-//: How we check Scenarios.
+//:: How we check Scenarios.
 
 :(before "End Tests")
 time_t mu_time; time(&mu_time);
 cerr << "\nMu tests: " << ctime(&mu_time);
-for (size_t i = 0; i < Scenarios.size(); ++i) {
-  setup();
-  Trace_file = Scenarios[i].name;
-  START_TRACING_UNTIL_END_OF_SCOPE
-  if (!Scenarios[i].dump_layer.empty())
-    Trace_stream->dump_layer = Scenarios[i].dump_layer;
-//?   cout << Scenarios[i].to_run; //? 2
-  run(Scenarios[i].to_run);
-//?   cout << "after: " << Memory[1] << '\n'; //? 1
-//?   cout << "After:\n";  dump_memory(); //? 1
-  for (map<int, int>::iterator p = Scenarios[i].memory_expectations.begin();
-       p != Scenarios[i].memory_expectations.end();
-       ++p) {
-    if (Memory[p->first] != p->second) {
-      // todo: unit tests for the test parsing infrastructure; use raise?
-      cerr << Scenarios[i].name << ": Expected location " << p->first << " to contain " << p->second << " but saw " << Memory[p->first] << '\n';
-      Passed = false;
+run_mu_tests();
+
+:(code)
+void run_mu_tests() {
+  for (size_t i = 0; i < Scenarios.size(); ++i) {
+    setup();
+    Trace_file = Scenarios[i].name;
+    START_TRACING_UNTIL_END_OF_SCOPE
+    if (!Scenarios[i].dump_layer.empty())
+      Trace_stream->dump_layer = Scenarios[i].dump_layer;
+//?     cerr << "AAA " << Scenarios[i].name << '\n'; //? 1
+//?     cout << Scenarios[i].to_run; //? 2
+    run(Scenarios[i].to_run);
+//?     cout << "after: " << Memory[1] << '\n'; //? 1
+//?     cout << "After:\n";  dump_memory(); //? 1
+    for (map<int, int>::iterator p = Scenarios[i].memory_expectations.begin();
+         p != Scenarios[i].memory_expectations.end();
+         ++p) {
+      if (Memory[p->first] != p->second) {
+        // todo: unit tests for the test parsing infrastructure; use raise?
+        cerr << Scenarios[i].name << ": Expected location " << p->first << " to contain " << p->second << " but saw " << Memory[p->first] << '\n';
+        Passed = false;
+      }
     }
+    // End Scenario Checks
+    if (Passed) cerr << ".";
   }
-  // End Scenario Checks
-  if (Passed) cerr << ".";
 }
 
-//: How we create Scenarios.
+//:: How we create Scenarios.
 
 :(scenarios "parse_scenario")
 :(scenario "parse_scenario_memory_expectation")
@@ -188,6 +194,25 @@ void slurp_until_matching_bracket(istream& in, ostream& out) {
   }
 }
 
+//:: Run tests for loaded mu files (rather than running 'main').
+
+:(before "End Test Runs")
+if (argc > 2 && is_equal(argv[1], "test") && file_exists(argv[2])) {
+  Scenarios.clear();  // ignore core.mu
+  assert(Next_recipe_number < 1000);  // don't load into test space
+  for (int i = 2; i < argc; ++i) {
+    load(argv[i]);
+  }
+  run_mu_tests();
+  cerr << '\n';
+  if (Num_failures > 0)
+    cerr << Num_failures << " failure"
+         << (Num_failures > 1 ? "s" : "")
+         << '\n';
+  return 0;
+}
+
+:(code)
 // for tests
 void parse_scenario(const string& s) {
   istringstream in(s);
@@ -212,3 +237,11 @@ string &rtrim(string &s) {
   s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(isspace))).base(), s.end());
   return s;
 }
+
+:(before "End Includes")
+#include <sys/stat.h>
+:(code)
+bool file_exists(const string& filename) {
+  struct stat buffer;
+  return stat(filename.c_str(), &buffer) == 0;
+}
diff --git a/cpp/factorial.mu b/cpp/factorial.mu
new file mode 100644
index 00000000..08d8afee
--- /dev/null
+++ b/cpp/factorial.mu
@@ -0,0 +1,33 @@
+recipe factorial [
+  default-space:address:array:location <- new location:type, 30:literal
+  n:integer <- next-ingredient
+  {
+    # if n=0 return 1
+    zero?:boolean <- equal n:integer, 0:literal
+    break-unless zero?:boolean
+    reply 1:literal
+  }
+  # return n * factorial(n - 1)
+  x:integer <- subtract n:integer, 1:literal
+  subresult:integer <- factorial x:integer
+  result:integer <- multiply subresult:integer, n:integer
+  reply result:integer
+]
+
+recipe main [
+  default-space:address:space <- new location:type, 30:literal
+  x:integer <- factorial 7:literal
+  $print x:integer
+  $print [
+]
+]
+
+scenario factorial-test [
+#?   dump all #? 1
+  run [
+    1:integer <- factorial 5:literal
+  ]
+  memory should contain [
+    1 <- 120
+  ]
+]