factor/basis/tools/test/test.factor

145 lines
3.8 KiB
Factor

! Copyright (C) 2003, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators compiler.units
continuations debugger effects fry generalizations io io.files
io.styles kernel lexer locals macros math.parser namespaces parser
vocabs.parser prettyprint quotations sequences source-files splitting
stack-checker summary unicode.case vectors vocabs vocabs.loader
vocabs.files words tools.errors source-files.errors io.streams.string
make compiler.errors ;
IN: tools.test
TUPLE: test-failure < source-file-error continuation ;
SYMBOL: +test-failure+
M: test-failure error-type drop +test-failure+ ;
SYMBOL: test-failures
test-failures [ V{ } clone ] initialize
T{ error-type
{ type +test-failure+ }
{ word ":test-failures" }
{ plural "unit test failures" }
{ icon "vocab:ui/tools/error-list/icons/unit-test-error.tiff" }
{ quot [ test-failures get ] }
} define-error-type
<PRIVATE
: <test-failure> ( error experiment file line# -- triple )
test-failure new
swap >>line#
swap >>file
swap >>asset
swap >>error
error-continuation get >>continuation ;
: failure ( error experiment file line# -- )
"--> test failed!" print
<test-failure> test-failures get push
notify-error-observers ;
SYMBOL: file
: file-failure ( error -- )
f file get f failure ;
:: (unit-test) ( output input -- error ? )
[ { } input with-datastack output assert-sequence= f f ] [ t ] recover ;
: short-effect ( effect -- pair )
[ in>> length ] [ out>> length ] bi 2array ;
:: (must-infer-as) ( effect quot -- error ? )
[ quot infer short-effect effect assert= f f ] [ t ] recover ;
:: (must-infer) ( quot -- error ? )
[ quot infer drop f f ] [ t ] recover ;
TUPLE: did-not-fail ;
CONSTANT: did-not-fail T{ did-not-fail }
M: did-not-fail summary drop "Did not fail" ;
:: (must-fail-with) ( quot pred -- error ? )
[ { } quot with-datastack drop did-not-fail t ]
[ dup pred call( error -- ? ) [ drop f f ] [ t ] if ] recover ;
:: (must-fail) ( quot -- error ? )
[ { } quot with-datastack drop did-not-fail t ] [ drop f f ] recover ;
: experiment-title ( word -- string )
"(" ?head drop ")" ?tail drop { { CHAR: - CHAR: \s } } substitute >title ;
MACRO: <experiment> ( word -- )
[ stack-effect in>> length dup ]
[ name>> experiment-title ] bi
'[ _ ndup _ narray _ prefix ] ;
: experiment. ( seq -- )
[ first write ": " write ] [ rest . flush ] bi ;
:: experiment ( word: ( -- error ? ) line# -- )
word <experiment> :> e
e experiment.
word execute [
file get [
e file get line# failure
] [ rethrow ] if
] [ drop ] if ; inline
: parse-test ( accum word -- accum )
literalize parsed
lexer get line>> parsed
\ experiment parsed ; inline
<<
SYNTAX: TEST:
scan
[ create-in ]
[ "(" ")" surround search '[ _ parse-test ] ] bi
define-syntax ;
>>
: run-test-file ( path -- )
dup file [
test-failures get file get +test-failure+ delete-file-errors
'[ _ run-file ] [ file-failure ] recover
] with-variable ;
: run-vocab-tests ( vocab -- )
dup vocab source-loaded?>> [
vocab-tests [ run-test-file ] each
] [ drop ] if ;
: traceback-button. ( failure -- )
"[" write [ "Traceback" ] dip continuation>> write-object "]" print ;
PRIVATE>
TEST: unit-test
TEST: must-infer-as
TEST: must-infer
TEST: must-fail-with
TEST: must-fail
M: test-failure error. ( error -- )
{
[ error-location print nl ]
[ asset>> [ experiment. nl ] when* ]
[ error>> error. ]
[ traceback-button. ]
} cleave ;
: :test-failures ( -- ) test-failures get errors. ;
: test ( prefix -- )
child-vocabs [ run-vocab-tests ] each ;
: test-all ( -- ) "" test ;