Assertion

Copyright [c] 2011, Marc Simpson Updated for RETRO 12 by Charles Childers, 2018

Description

This vocabulary provides support for testing code in a clean, predicatable manner.

Assertion predicates first check the stack for underflow; if the stack is deep enough, their embedded predicates are applied; if not, the assertion fails.

The result of each assertion - including the underflow check - is ANDed with the assertionFlag which can then be tested after the containing thread has finished executing; this is handled by the .assertion word class.

For custom behaviour, revector preCond and/or postCond; by default the pre-condition is an effective nop while the post-condition simply prints 'Success' or 'Failure'.

Given that each assertion predicate mutates assertionFlag, use of the word class class:assertion is encouraged; this resets the assertionFlag before execution and push its final value to the stack before calling postCond when the thread exits.

NOTE: For simplicity of implementation, failure within a word of class class:assertion will not result in immediate termination; instead, the false value of assertionFlag is left to propagate.

Code & Commentary

~~~'assertionFlag var   :assert  (f-)   &assertionFlag [ and ] v:update ;   :deep?   (n-f)   n:inc depth lteq? dup assert ;   :assert:eq    #2 deep? [ eq?      assert ] if ; :assert:false #1 deep? [ n:zero?  assert ] if ; :assert:true  #1 deep? [ n:-zero? assert ] if ; :assert:gt    #2 deep? [ gt?      assert ] if ; :assert:gteq  #2 deep? [ gteq?    assert ] if ; :assert:lt    #2 deep? [ lt?      assert ] if ; :assert:lteq  #2 deep? [ lteq?    assert ] if ;   :putAssertion (f-)   nl [ 'Success ] [ reset 'Failure ] choose s:put ; ~~~

These are from Hooks.forth:

~~~:hook (-)  #1793 , here n:inc , ; immediate :set-hook (aa-) n:inc store ; :unhook (a-) n:inc dup n:inc swap store ; ~~~

~~~:preCond  (-)  hook ; :postCond (f-) hook putAssertion ;   {{   :buildUp preCond  &assertionFlag v:on ;   :tearDown @assertionFlag  &assertionFlag v:on  postCond ; ---reveal---   :class:assertion (a-)     &buildUp class:word class:word &tearDown class:word ; }}   :assertion (-) &class:assertion reclass ; ~~~

~~~  :a1 (xyz-) #30 assert:eq #20 assert:eq #10 assert:eq ; assertion   :a2 (xy-) assert:true assert:false ; assertion   :a3 (x-) #5 assert:gt ; assertion     :go     nl '---------- s:put     #10 #20 #30 a1     #30 #20 #10 a1     nl '---------- s:put     #10 a1     nl '---------- s:put     a1     nl '---------- s:put     #-1 #0 a2     #0 #-1 a2     #-1 #-1 a2     #-1 a2     nl '---------- s:put     #3 a3     #4 a3     #5 a3     a3     nl '---------- s:put   ;     go ~~~

Functions

+-----------------+-----+-----------------------+ | Name |Stack| Usage | +=================+=====+=======================+ | assertionFlag | -a | Variable. This holds a| | | | true (-1) or false (0)| | | | value indicating | | | | whether the current | | | | set of assertions have| | | | passed or failed. The | | | | class:assertion | | | | class will set this to| | | | true automatically. | +-----------------+-----+-----------------------+ | assert | f- | Updates the | | | | assertionFlag | | | | using bitwise AND | +-----------------+-----+-----------------------+ | deep? | n-f | Checks to see if there| | | | are at least n items| | | | on the stack. | | | | Returns true if there | | | | are, false otherwise. | +-----------------+-----+-----------------------+ | assert:eq | nn- | Check to see if two | | | | values are equal | +-----------------+-----+-----------------------+ | assert:false | f- | Check to see if flag | | | | is false (0) | +-----------------+-----+-----------------------+ | assert:true | f- | Check to see if flag | | | | is true (non-zero) | +-----------------+-----+-----------------------+ | assert:gt | nn- | Check to see if n1 is | | | | greather than n2 | +-----------------+-----+-----------------------+ | assert:gteq | nn- | Check to see if n1 is | | | | greater than or equal | | | | to n2 | +-----------------+-----+-----------------------+ | assert:lt | nn- | Check to see if n1 is | | | | less than n2 | +-----------------+-----+-----------------------+ | assert:lteq | nn- | Check to see if n1 is | | | | less than or equal to | | | | n2 | +-----------------+-----+-----------------------+ | putAssertion | f- | Display 'Success' or | | | | 'Failure' based on | | | | flag | +-----------------+-----+-----------------------+ | preCond | - | Hook, does nothing by | | | | default | +-----------------+-----+-----------------------+ | postCond | f- | Hook, displays either | | | | 'Success' or 'Failure'| | | | by default | +-----------------+-----+-----------------------+ | class:assertion | a- | Class handler for | | | | assertions | +-----------------+-----+-----------------------+ | assertion | - | Change the class of a | | | | function to | | | | class:asssertion | +-----------------+-----+-----------------------+