about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-01-27 15:27:29 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-01-27 15:27:29 -0800
commit95425355a01edf284a86d0873e63d88071221ed8 (patch)
treeac293fa0a23a3e51c17faef4de2ebdf36fced6f0
parent5516dd288d705fed42f2c099471b19a76481b18a (diff)
downloadmu-95425355a01edf284a86d0873e63d88071221ed8.tar.gz
2608 - fix-up tests in sandbox/ app
When I first forked it from the edit/ app, I wasn't sure how to deal
with changing the recipe side when the only way the program accesses it
is with the untestable 'restore' hack. Now we introduce a little hook
into event-loop and pass in any updated recipe side directly.

In the process I've cleaned up several minor stylistic inconsistencies
between edit/ and sandbox/ apps.
-rw-r--r--edit/005-sandbox.mu19
-rw-r--r--edit/006-sandbox-edit.mu8
-rw-r--r--edit/007-sandbox-delete.mu16
-rw-r--r--edit/010-warnings.mu12
-rw-r--r--sandbox/005-sandbox.mu94
-rw-r--r--sandbox/006-sandbox-edit.mu91
-rw-r--r--sandbox/007-sandbox-delete.mu16
-rw-r--r--sandbox/008-sandbox-test.mu81
-rw-r--r--sandbox/010-warnings.mu447
9 files changed, 690 insertions, 94 deletions
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu
index e8f97fce..568c7cb1 100644
--- a/edit/005-sandbox.mu
+++ b/edit/005-sandbox.mu
@@ -721,9 +721,7 @@ scenario scrolling-down-on-recipe-side [
   assume-console [
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   # hit 'down' in recipe editor
   assume-console [
     press down-arrow
@@ -733,8 +731,7 @@ scenario scrolling-down-on-recipe-side [
     4:character/cursor <- copy 9251/␣
     print screen:address:shared:screen, 4:character/cursor
   ]
-  # sandbox editor hidden; first sandbox displayed
-  # cursor moves to first sandbox
+  # cursor moves down on recipe side
   screen-should-contain [
     .                              .
     .               ┊              .
@@ -763,11 +760,9 @@ scenario scrolling-through-multiple-sandboxes [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-    4:character/cursor <- copy 9251/␣
-    print screen:address:shared:screen, 4:character/cursor
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
+  4:character/cursor <- copy 9251/␣
+  print screen:address:shared:screen, 4:character/cursor
   screen-should-contain [
     .                              .
     .               ┊␣             .
@@ -917,9 +912,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊              .
diff --git a/edit/006-sandbox-edit.mu b/edit/006-sandbox-edit.mu
index 33ef2f18..de4be675 100644
--- a/edit/006-sandbox-edit.mu
+++ b/edit/006-sandbox-edit.mu
@@ -190,9 +190,7 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     press down-arrow
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊━━━━━━━━━━━━━━.
@@ -238,9 +236,7 @@ scenario editing-sandbox-updates-sandbox-count [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊              .
diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu
index a478c93f..3d6d2d12 100644
--- a/edit/007-sandbox-delete.mu
+++ b/edit/007-sandbox-delete.mu
@@ -134,9 +134,7 @@ scenario deleting-sandbox-after-scroll [
     press F4
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊━━━━━━━━━━━━━━.
@@ -182,9 +180,7 @@ scenario deleting-top-sandbox-after-scroll [
     press F4
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊━━━━━━━━━━━━━━.
@@ -231,9 +227,7 @@ scenario deleting-final-sandbox-after-scroll [
     press down-arrow
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊━━━━━━━━━━━━━━.
@@ -279,9 +273,7 @@ scenario deleting-updates-sandbox-count [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .               ┊              .
diff --git a/edit/010-warnings.mu b/edit/010-warnings.mu
index ccecc880..c37e31e2 100644
--- a/edit/010-warnings.mu
+++ b/edit/010-warnings.mu
@@ -182,7 +182,7 @@ scenario run-updates-status-with-first-erroneous-sandbox [
   run [
     event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   ]
-  # status shows first sandbox with error
+  # status line shows that error is in first sandbox
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
   ]
@@ -209,7 +209,7 @@ scenario run-updates-status-with-first-erroneous-sandbox-2 [
   run [
     event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   ]
-  # status shows first sandbox with error
+  # status line shows that error is in second sandbox
   screen-should-contain [
     .  errors found (1)                                                               run (F4)           .
   ]
@@ -263,9 +263,7 @@ z <- add x, [a]
   assume-console [
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .  errors found (0)                                                               run (F4)           .
     .recipe foo x:_elem -> z:_elem [                   ┊                                                 .
@@ -489,9 +487,7 @@ recipe foo [
   assume-console [
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
   screen-should-contain [
     .  errors found                                                                   run (F4)           .
     .                                                  ┊foo                                              .
diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu
index 31aa243d..87f688ed 100644
--- a/sandbox/005-sandbox.mu
+++ b/sandbox/005-sandbox.mu
@@ -116,7 +116,9 @@ after <global-keypress> [
     break-unless do-run?
     status:address:shared:array:character <- new [running...       ]
     screen <- update-status screen, status, 245/grey
-    error?:boolean, env, screen <- run-sandboxes env, screen
+    test-recipes:address:shared:array:character, _/optional <- next-ingredient
+    error?:boolean, env, screen <- run-sandboxes env, screen, test-recipes
+#?     test-recipes <- copy 0  # abandon
     # F4 might update warnings and results on both sides
     screen <- render-all screen, env
     {
@@ -130,10 +132,10 @@ after <global-keypress> [
   }
 ]
 
-recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
-  errors-found?:boolean, env, screen <- update-recipes env, screen
+  errors-found?:boolean, env, screen <- update-recipes env, screen, test-recipes
   reply-if errors-found?
   # check contents of editor
   <run-sandboxes-begin>
@@ -175,13 +177,20 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add
   <run-sandboxes-end>
 ]
 
-# load code from recipes.mu
+# load code from recipes.mu, or from test-recipes in tests
 # replaced in a later layer (whereupon errors-found? will actually be set)
-recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
-  in:address:shared:array:character <- restore [recipes.mu]  # newlayer: persistence
-  reload in
+  {
+    break-if test-recipes
+    in:address:shared:array:character <- restore [recipes.mu]  # newlayer: persistence
+    reload in
+  }
+  {
+    break-unless test-recipes
+    reload test-recipes
+  }
   errors-found? <- copy 0/false
 ]
 
@@ -420,6 +429,57 @@ recipe render-screen screen:address:shared:screen, sandbox-screen:address:shared
   }
 ]
 
+scenario run-updates-results [
+  assume-screen 50/width, 12/height
+  # define a recipe (no indent for the 'add' line below so column numbers are more obvious)
+  1:address:shared:array:character <- new [ 
+recipe foo [
+z:number <- add 2, 2
+reply z
+]]
+  # sandbox editor contains an instruction without storing outputs
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  # run the code in the editors
+  assume-console [
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/recipes
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo                                               .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # make a change (incrementing one of the args to 'add'), then rerun
+  4:address:shared:array:character <- new [ 
+recipe foo [
+z:number <- add 2, 3
+reply z
+]]
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 4:address:shared:array:character/recipes
+  ]
+  # check that screen updates the result on the right
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo                                               .
+    .5                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
 scenario run-instruction-manages-screen-per-sandbox [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 20/height
@@ -504,11 +564,9 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [
     type [abc
 ]
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-    3:character/cursor <- copy 9251/␣
-    print screen:address:shared:screen, 3:character/cursor
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
+  3:character/cursor <- copy 9251/␣
+  print screen:address:shared:screen, 3:character/cursor
   screen-should-contain [
     .                               run (F4)           .
     .abc                                               .
@@ -652,11 +710,9 @@ scenario scrolling-through-multiple-sandboxes [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-    3:character/cursor <- copy 9251/␣
-    print screen:address:shared:screen, 3:character/cursor
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
+  3:character/cursor <- copy 9251/␣
+  print screen:address:shared:screen, 3:character/cursor
   screen-should-contain [
     .                               run (F4)           .
     .␣                                                 .
@@ -811,9 +867,7 @@ scenario scrolling-manages-sandbox-index-correctly [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                               run (F4)           .
     .                                                  .
diff --git a/sandbox/006-sandbox-edit.mu b/sandbox/006-sandbox-edit.mu
index 6f3ac272..e974034a 100644
--- a/sandbox/006-sandbox-edit.mu
+++ b/sandbox/006-sandbox-edit.mu
@@ -121,6 +121,9 @@ recipe extract-sandbox env:address:shared:programming-environment-data, click-ro
   # snip sandbox out of its list
   result <- copy *sandbox
   *sandbox <- copy next-sandbox
+  # update sandbox count
+  sandbox-count:address:number <- get-address *env, number-of-sandboxes:offset
+  *sandbox-count <- subtract *sandbox-count, 1
 ]
 
 scenario sandbox-with-print-can-be-edited [
@@ -133,9 +136,7 @@ scenario sandbox-with-print-can-be-edited [
   assume-console [
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                               run (F4)           .
     .                                                  .
@@ -150,13 +151,6 @@ scenario sandbox-with-print-can-be-edited [
     .  .                              .                .
     .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  .
-    .                                                  .
-    .                                                  .
-    .                                                  .
-    .                                                  .
-    .                                                  .
-    .                                                  .
-    .                                                  .
   ]
   # edit the sandbox
   assume-console [
@@ -179,9 +173,8 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
   assume-screen 50/width, 20/height
   # initialize environment
   1:address:shared:array:character <- new []
-  2:address:shared:array:character <- new []
-  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
-  render-all screen, 3:address:shared:programming-environment-data
+  2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
+  render-all screen, 2:address:shared:programming-environment-data
   # create 2 sandboxes and scroll to second
   assume-console [
     press ctrl-n
@@ -192,9 +185,7 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     press down-arrow
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                               run (F4)           .
     .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -209,7 +200,7 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     left-click 2, 20
   ]
   run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
+    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   ]
   # second sandbox shows in editor; scroll resets to display first sandbox
   screen-should-contain [
@@ -223,3 +214,69 @@ scenario editing-sandbox-after-scrolling-resets-scroll [
     .                                                  .
   ]
 ]
+
+scenario editing-sandbox-updates-sandbox-count [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # initialize environment
+  1:address:shared:array:character <- new []
+  2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
+  render-all screen, 2:address:shared:programming-environment-data
+  # create 2 sandboxes and scroll to second
+  assume-console [
+    press ctrl-n
+    type [add 2, 2]
+    press F4
+    type [add 1, 1]
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .add 1, 1                                          .
+    .2                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .1                                                x.
+  ]
+  # edit the second sandbox, then resave
+  assume-console [
+    left-click 3, 20
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
+  ]
+  # no change in contents
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .add 1, 1                                          .
+    .2                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .1                                                x.
+  ]
+  # now try to scroll past end
+  assume-console [
+    press down-arrow
+    press down-arrow
+    press down-arrow
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
+  ]
+  # screen should show just final sandbox
+  screen-should-contain [
+    .                               run (F4)           .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .1                                                x.
+    .add 2, 2                                          .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
diff --git a/sandbox/007-sandbox-delete.mu b/sandbox/007-sandbox-delete.mu
index af9db190..35cf47cb 100644
--- a/sandbox/007-sandbox-delete.mu
+++ b/sandbox/007-sandbox-delete.mu
@@ -132,9 +132,7 @@ scenario deleting-sandbox-after-scroll [
     press F4
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                              .  # menu
     .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -182,9 +180,7 @@ scenario deleting-top-sandbox-after-scroll [
     press F4
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                              .  # menu
     .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -233,9 +229,7 @@ scenario deleting-final-sandbox-after-scroll [
     press down-arrow
     press down-arrow
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -280,9 +274,7 @@ scenario deleting-updates-sandbox-count [
     type [add 1, 1]
     press F4
   ]
-  run [
-    event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
-  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
   screen-should-contain [
     .                              .
     .                              .
diff --git a/sandbox/008-sandbox-test.mu b/sandbox/008-sandbox-test.mu
index 4e6b2896..a7344ba4 100644
--- a/sandbox/008-sandbox-test.mu
+++ b/sandbox/008-sandbox-test.mu
@@ -1,6 +1,85 @@
 ## clicking on sandbox results to 'fix' them and turn sandboxes into tests
 
-# todo: perform test from edit/ by faking file system
+scenario sandbox-click-on-result-toggles-color-to-green [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # basic recipe
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  reply 4
+]]
+  # run it
+  2:address:shared:array:character <- new [foo]
+  assume-console [
+    press F4
+  ]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo                                               .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # click on the '4' in the result
+  assume-console [
+    left-click 5, 21
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  # color toggles to green
+  screen-should-contain-in-color 2/green, [
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .4                                                 .
+    .                                                  .
+  ]
+  # cursor should remain unmoved
+  run [
+    4:character/cursor <- copy 9251/␣
+    print screen:address:shared:screen, 4:character/cursor
+  ]
+  screen-should-contain [
+    .                               run (F4)           .
+    .␣                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo                                               .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # now change the result
+  5:address:shared:array:character <- new [ 
+recipe foo [
+  reply 3
+]]
+  # then rerun
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 5:address:shared:array:character/new-test-recipes
+  ]
+  # result turns red
+  screen-should-contain-in-color 1/red, [
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .3                                                 .
+    .                                                  .
+  ]
+]
 
 # clicks on sandbox responses save it as 'expected'
 after <global-touch> [
diff --git a/sandbox/010-warnings.mu b/sandbox/010-warnings.mu
index f7bf0e5d..7f725097 100644
--- a/sandbox/010-warnings.mu
+++ b/sandbox/010-warnings.mu
@@ -5,12 +5,20 @@ container programming-environment-data [
 ]
 
 # copy code from recipe editor, persist, load into mu, save any warnings
-recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
+# test-recipes is a hook for testing
+recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
   local-scope
   load-ingredients
-  in:address:shared:array:character <- restore [recipes.mu]
   recipe-warnings:address:address:shared:array:character <- get-address *env, recipe-warnings:offset
-  *recipe-warnings <- reload in
+  {
+    break-if test-recipes
+    in:address:shared:array:character <- restore [recipes.mu]
+    *recipe-warnings <- reload in
+  }
+  {
+    break-unless test-recipes
+    *recipe-warnings <- reload test-recipes
+  }
   # if recipe editor has errors, stop
   {
     break-unless *recipe-warnings
@@ -122,6 +130,384 @@ after <render-sandbox-trace-done> [
   }
 ]
 
+scenario run-shows-warnings-in-get [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  get 123:number, foo:offset
+]]
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  screen-should-contain-in-color 1/red, [
+    .  errors found                                    .
+    .                                                  .
+  ]
+]
+
+scenario run-updates-status-with-first-erroneous-sandbox [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new []
+  2:address:shared:array:character <- new []
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    # create invalid sandbox 1
+    type [get foo, x:offset]
+    press F4
+    # create invalid sandbox 0
+    type [get foo, x:offset]
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/empty-test-recipes
+  ]
+  # status line shows that error is in first sandbox
+  screen-should-contain [
+    .  errors found (0)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .get foo, x:offset                                 .
+    .expected a container                              .
+    .missing type for foo in 'get foo, x:offset'       .
+    .first ingredient of 'get' should be a container, ↩.
+    .but got foo                                       .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .1                                                x.
+    .get foo, x:offset                                 .
+    .expected a container                              .
+    .missing type for foo in 'get foo, x:offset'       .
+    .first ingredient of 'get' should be a container, ↩.
+    .but got foo                                       .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-updates-status-with-first-erroneous-sandbox-2 [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new []
+  2:address:shared:array:character <- new []
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    # create invalid sandbox 2
+    type [get foo, x:offset]
+    press F4
+    # create invalid sandbox 1
+    type [get foo, x:offset]
+    press F4
+    # create valid sandbox 0
+    type [add 2, 2]
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/empty-test-recipes
+  ]
+  # status line shows that error is in second sandbox
+  screen-should-contain [
+    .  errors found (1)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .add 2, 2                                          .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .1                                                x.
+    .get foo, x:offset                                 .
+    .expected a container                              .
+    .missing type for foo in 'get foo, x:offset'       .
+    .first ingredient of 'get' should be a container, ↩.
+    .but got foo                                       .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .2                                                x.
+    .get foo, x:offset                                 .
+    .expected a container                              .
+    .missing type for foo in 'get foo, x:offset'       .
+    .first ingredient of 'get' should be a container, ↩.
+    .but got foo                                       .
+  ]
+]
+
+scenario run-hides-warnings-from-past-sandboxes [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new []
+  2:address:shared:array:character <- new [get foo, x:offset]  # invalid
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4  # generate error
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/empty-test-recipes
+  assume-console [
+    left-click 3, 10
+    press ctrl-k
+    type [add 2, 2]  # valid code
+    press F4  # update sandbox
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
+  ]
+  # error should disappear
+  screen-should-contain [
+    .                               run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .add 2, 2                                          .
+    .4                                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-updates-warnings-for-shape-shifting-recipes [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # define a shape-shifting recipe with an error
+  1:address:shared:array:character <- new [recipe foo x:_elem -> z:_elem [
+local-scope
+load-ingredients
+z <- add x, [a]
+]]
+  2:address:shared:array:character <- new [foo 2]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  screen-should-contain [
+    .  errors found (0)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo 2                                             .
+    .foo_2: 'add' requires number ingredients, but got↩.
+    . [a]                                              .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # now rerun everything
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  # error should remain unchanged
+  screen-should-contain [
+    .  errors found (0)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo 2                                             .
+    .foo_2: 'add' requires number ingredients, but got↩.
+    . [a]                                              .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-avoids-spurious-warnings-on-reloading-shape-shifting-recipes [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # overload a well-known shape-shifting recipe
+  1:address:shared:array:character <- new [recipe length l:address:shared:list:_elem -> n:number [
+]]
+  # call code that uses other variants of it, but not it itself
+  2:address:shared:array:character <- new [x:address:shared:list:number <- copy 0
+to-text x]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  # run it once
+  assume-console [
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  # no errors anywhere on screen (can't check anything else, since to-text will return an address)
+  screen-should-contain-in-color 1/red, [
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                             <-                   .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+  ]
+  # rerun everything
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  # still no errors
+  screen-should-contain-in-color 1/red, [
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                             <-                   .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+    .                                                  .
+  ]
+]
+
+scenario run-shows-missing-type-warnings [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  x <- copy 0
+]]
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-shows-unbalanced-bracket-warnings [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # recipe is incomplete (unbalanced '[')
+  1:address:shared:array:character <- new [ 
+recipe foo «
+  x <- copy 0
+]
+  replace 1:address:shared:array:character, 171/«, 91  # '['
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-shows-get-on-non-container-warnings [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  x:address:shared:point <- new point:type
+  get x:address:shared:point, 1:offset
+]]
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-shows-non-literal-get-argument-warnings [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  x:number <- copy 0
+  y:address:shared:point <- new point:type
+  get *y:address:shared:point, x:number
+]]
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
+scenario run-shows-warnings-everytime [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # try to run a file with an error
+  1:address:shared:array:character <- new [ 
+recipe foo [
+  x:number <- copy y:number
+]]
+  2:address:shared:array:character <- new [foo]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  assume-console [
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # rerun the file, check for the same error
+  assume-console [
+    press F4
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  screen-should-contain [
+    # TODO: make this more specific
+    .  errors found                 run (F4)           .
+    .foo                                               .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]
+
 scenario run-instruction-and-print-warnings [
   trace-until 100/app  # trace too long
   assume-screen 50/width, 15/height
@@ -157,7 +543,7 @@ scenario run-instruction-and-print-warnings [
   ]
 ]
 
-# todo: print warnings in file even if you can't run a sandbox
+# TODO: print warnings in file even if you can't run a sandbox
 
 scenario run-instruction-and-print-warnings-only-once [
   trace-until 100/app  # trace too long
@@ -217,4 +603,55 @@ loop
   ]
 ]
 
-# todo: scenario sandbox-with-warnings-shows-trace from edit/
+scenario sandbox-with-warnings-shows-trace [
+  trace-until 100/app  # trace too long
+  assume-screen 50/width, 20/height
+  # generate a stash and a warning
+  1:address:shared:array:character <- new [recipe foo [
+local-scope
+a:number <- next-ingredient
+b:number <- next-ingredient
+stash [dividing by], b
+_, c:number <- divide-with-remainder a, b
+reply b
+]]
+  2:address:shared:array:character <- new [foo 4, 0]
+  3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character
+  # run
+  assume-console [
+    press F4
+  ]
+  event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  # screen prints error message
+  screen-should-contain [
+    .  errors found (0)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo 4, 0                                          .
+    .foo: divide by zero in '_, c:number <- divide-wit↩.
+    .h-remainder a, b'                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+  # click on the call in the sandbox
+  assume-console [
+    left-click 4, 15
+  ]
+  run [
+    event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data, 1:address:shared:array:character/test-recipes
+  ]
+  # screen should expand trace
+  screen-should-contain [
+    .  errors found (0)             run (F4)           .
+    .                                                  .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .0                                                x.
+    .foo 4, 0                                          .
+    .dividing by 0                                     .
+    .foo: divide by zero in '_, c:number <- divide-wit↩.
+    .h-remainder a, b'                                 .
+    .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .                                                  .
+  ]
+]