@@ -75,12 +75,14 @@ module.exports = function(path, options) {
7575 console . log ( source . replace ( / \n $ / , '' ) ) ;
7676 return Promise . resolve ( [ ] ) ;
7777 } else if ( options . silent ) {
78- return Promise . resolve ( evaluate ( options . module , source , path ) ) ;
78+ return evaluate ( options . module , source , path ) ;
7979 } else {
8080 console . log ( 'running doctests in ' + path + '...' ) ;
81- var results = evaluate ( options . module , source , path ) ;
82- log ( results ) ;
83- return Promise . resolve ( results ) ;
81+ return ( evaluate ( options . module , source , path ) )
82+ . then ( function ( results ) {
83+ log ( results ) ;
84+ return results ;
85+ } ) ;
8486 }
8587} ;
8688
@@ -164,6 +166,9 @@ var CLOSED = 'closed';
164166var OPEN = 'open' ;
165167var INPUT = 'input' ;
166168var OUTPUT = 'output' ;
169+ var LOG = 'log' ;
170+
171+ var MATCH_LOG = / ^ \[ ( [ a - z A - Z ] + ) \] : / ;
167172
168173// normalizeTest :: { output :: { value :: String } } -> Undefined
169174function normalizeTest ( $test ) {
@@ -201,16 +206,36 @@ function processLine(
201206 accum . tests . push ( $test = { } ) ;
202207 $test [ accum . state = INPUT ] = { value : value } ;
203208 input ( $test ) ;
204- } else if ( trimmedLine . charAt ( 0 ) === '.' ) {
209+ } else if ( accum . state === INPUT && trimmedLine . charAt ( 0 ) === '.' ) {
210+ value = stripLeading ( 1 , ' ' , stripLeading ( Infinity , '.' , trimmedLine ) ) ;
211+ $test = accum . tests [ accum . tests . length - 1 ] ;
212+ $test [ INPUT ] . value += '\n' + value ;
213+ appendToInput ( $test ) ;
214+ } else if ( accum . state === OUTPUT && trimmedLine . charAt ( 0 ) === '.' ) {
205215 value = stripLeading ( 1 , ' ' , stripLeading ( Infinity , '.' , trimmedLine ) ) ;
206216 $test = accum . tests [ accum . tests . length - 1 ] ;
207- $test [ accum . state ] . value += '\n' + value ;
208- ( accum . state === INPUT ? appendToInput : appendToOutput ) ( $test ) ;
209- } else if ( accum . state === INPUT ) {
217+ $test [ OUTPUT ] [ $test [ OUTPUT ] . length - 1 ] . value += '\n' + value ;
218+ appendToOutput ( $test ) ;
219+ } else if ( MATCH_LOG . test ( trimmedLine ) ) {
220+ value = stripLeading ( 1 , ' ' , trimmedLine . replace ( MATCH_LOG , '' ) ) ;
221+ $test = accum . tests [ accum . tests . length - 1 ] ;
222+ ( $test [ accum . state = OUTPUT ] = $test [ accum . state ] || [ ] ) . push ( {
223+ channel : MATCH_LOG . exec ( trimmedLine ) [ 1 ] ,
224+ value : value
225+ } ) ;
226+ if ( $test [ OUTPUT ] . length === 1 ) {
227+ output ( $test ) ;
228+ }
229+ } else {
210230 value = trimmedLine ;
211231 $test = accum . tests [ accum . tests . length - 1 ] ;
212- $test [ accum . state = OUTPUT ] = { value : value } ;
213- output ( $test ) ;
232+ ( $test [ accum . state = OUTPUT ] = $test [ accum . state ] || [ ] ) . push ( {
233+ channel : null ,
234+ value : value
235+ } ) ;
236+ if ( $test [ OUTPUT ] . length === 1 ) {
237+ output ( $test ) ;
238+ }
214239 }
215240 }
216241}
@@ -335,7 +360,9 @@ function wrap$js(test, sourceType) {
335360 ' ":": ' + test [ OUTPUT ] . loc . start . line + ',' ,
336361 ' "!": ' + test [ '!' ] + ',' ,
337362 ' thunk: function() {' ,
338- ' return ' + test [ OUTPUT ] . value + ';' ,
363+ ' return ' + test [ OUTPUT ] . map ( function ( out ) {
364+ return '{channel: "' + out . channel + '", value: ' + out . value + '}' ;
365+ } ) + ';' ,
339366 ' }' ,
340367 '});'
341368 ] ) . join ( '\n' ) ;
@@ -526,47 +553,59 @@ function commonjsEval(source, path) {
526553 return run ( queue ) ;
527554}
528555
529- function run ( queue ) {
530- return queue . reduce ( function ( accum , io ) {
531- var thunk = accum . thunk ;
532- if ( io . type === INPUT ) {
533- if ( thunk != null ) thunk ( ) ;
534- accum . thunk = io . thunk ;
535- } else if ( io . type === OUTPUT ) {
536- var either ;
537- try {
538- either = { tag : 'Right' , value : thunk ( ) } ;
539- } catch ( err ) {
540- either = { tag : 'Left' , value : err } ;
541- }
542- accum . thunk = null ;
543- var expected = io . thunk ( ) ;
544-
545- var pass , repr ;
546- if ( either . tag === 'Left' ) {
547- var name = either . value . name ;
548- var message = either . value . message ;
549- pass = io [ '!' ] &&
550- name === expected . name &&
551- message === expected . message . replace ( / ^ $ / , message ) ;
552- repr = '! ' + name +
553- ( expected . message && message . replace ( / ^ (? ! $ ) / , ': ' ) ) ;
554- } else {
555- pass = ! io [ '!' ] && Z . equals ( either . value , expected ) ;
556- repr = show ( either . value ) ;
557- }
556+ function run ( queue , logMediator ) {
557+ return queue . reduce ( function ( p , io ) {
558+ return p . then ( function ( accum ) {
559+ var thunk = accum . thunk ;
560+ if ( io . type === INPUT ) {
561+ if ( thunk != null ) thunk ( ) ;
562+ accum . thunk = io . thunk ;
563+ } else if ( io . type === OUTPUT ) {
564+ var either ;
565+ var expected = io . thunk ( ) ;
566+
567+ accum . thunk = null ;
568+
569+ // Instead of calling the io thunk straight away, we register
570+ // the appropriate listener on logMediator beforehand, to catch any
571+ // synchronous log calls the thunk might make.
572+ try {
573+ either = { tag : 'Right' , value : thunk ( ) } ;
574+ } catch ( err ) {
575+ either = { tag : 'Left' , value : err } ;
576+ }
558577
559- accum . results . push ( [
560- pass ,
561- repr ,
562- io [ '!' ] ?
563- '! ' + expected . name + expected . message . replace ( / ^ (? ! $ ) / , ': ' ) :
564- show ( expected ) ,
565- io [ ':' ]
566- ] ) ;
567- }
568- return accum ;
569- } , { results : [ ] , thunk : null } ) . results ;
578+ // Instead of just analyzing a single output on a single channel,
579+ // we compare output on al channels, in the order indicated by the
580+ // user.
581+ var pass , repr ;
582+ if ( either . tag === 'Left' ) {
583+ var name = either . value . name ;
584+ var message = either . value . message ;
585+ pass = io [ '!' ] &&
586+ name === expected . name &&
587+ message === expected . message . replace ( / ^ $ / , message ) ;
588+ repr = '! ' + name +
589+ ( expected . message && message . replace ( / ^ (? ! $ ) / , ': ' ) ) ;
590+ } else {
591+ pass = ! io [ '!' ] && Z . equals ( either . value , expected ) ;
592+ repr = show ( either . value ) ;
593+ }
594+
595+ accum . results . push ( [
596+ pass ,
597+ repr ,
598+ io [ '!' ] ?
599+ '! ' + expected . name + expected . message . replace ( / ^ (? ! $ ) / , ': ' ) :
600+ show ( expected ) ,
601+ io [ ':' ]
602+ ] ) ;
603+ }
604+ return accum ;
605+ } ) ;
606+ } , Promise . resolve ( { results : [ ] , thunk : null } ) ) . then ( function ( reduced ) {
607+ return reduced . results ;
608+ } ) ;
570609}
571610
572611module . exports . run = run ;
0 commit comments