1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 11:50:28 +02:00
Conflicts:
	module/Makefile.am
This commit is contained in:
Andy Wingo 2014-02-07 15:13:22 +01:00
commit cd36c69619
9 changed files with 4957 additions and 2 deletions

View file

@ -47,12 +47,14 @@ get the relevant SRFI documents from the SRFI home page
* SRFI-39:: Parameter objects
* SRFI-41:: Streams.
* SRFI-42:: Eager comprehensions
* SRFI-43:: Vector Library.
* SRFI-45:: Primitives for expressing iterative lazy algorithms
* SRFI-46:: Basic syntax-rules Extensions.
* SRFI-55:: Requiring Features.
* SRFI-60:: Integers as bits.
* SRFI-61:: A more general `cond' clause
* SRFI-62:: S-expression comments.
* SRFI-64:: A Scheme API for test suites.
* SRFI-67:: Compare procedures
* SRFI-69:: Basic hash tables.
* SRFI-87:: => in case clauses.
@ -4504,6 +4506,417 @@ the input @var{stream}s is finite, or is infinite if all the input
See @uref{http://srfi.schemers.org/srfi-42/srfi-42.html, the
specification of SRFI-42}.
@node SRFI-43
@subsection SRFI-43 - Vector Library
@cindex SRFI-43
This subsection is based on the
@uref{http://srfi.schemers.org/srfi-43/srfi-43.html, specification of
SRFI-43} by Taylor Campbell.
@c The copyright notice and license text of the SRFI-43 specification is
@c reproduced below:
@c Copyright (C) Taylor Campbell (2003). All Rights Reserved.
@c Permission is hereby granted, free of charge, to any person obtaining a
@c copy of this software and associated documentation files (the
@c "Software"), to deal in the Software without restriction, including
@c without limitation the rights to use, copy, modify, merge, publish,
@c distribute, sublicense, and/or sell copies of the Software, and to
@c permit persons to whom the Software is furnished to do so, subject to
@c the following conditions:
@c The above copyright notice and this permission notice shall be included
@c in all copies or substantial portions of the Software.
@c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
@c OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
@c MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@c NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
@c LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
@c OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
@c WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@noindent
SRFI-43 implements a comprehensive library of vector operations. It can
be made available with:
@example
(use-modules (srfi srfi-43))
@end example
@menu
* SRFI-43 Constructors::
* SRFI-43 Predicates::
* SRFI-43 Selectors::
* SRFI-43 Iteration::
* SRFI-43 Searching::
* SRFI-43 Mutators::
* SRFI-43 Conversion::
@end menu
@node SRFI-43 Constructors
@subsubsection SRFI-43 Constructors
@deffn {Scheme Procedure} make-vector size [fill]
Create and return a vector of size @var{size}, optionally filling it
with @var{fill}. The default value of @var{fill} is unspecified.
@example
(make-vector 5 3) @result{} #(3 3 3 3 3)
@end example
@end deffn
@deffn {Scheme Procedure} vector x @dots{}
Create and return a vector whose elements are @var{x} @enddots{}.
@example
(vector 0 1 2 3 4) @result{} #(0 1 2 3 4)
@end example
@end deffn
@deffn {Scheme Procedure} vector-unfold f length initial-seed @dots{}
The fundamental vector constructor. Create a vector whose length is
@var{length} and iterates across each index k from 0 up to
@var{length} - 1, applying @var{f} at each iteration to the current index
and current seeds, in that order, to receive n + 1 values: first, the
element to put in the kth slot of the new vector and n new seeds for
the next iteration. It is an error for the number of seeds to vary
between iterations.
@example
(vector-unfold (lambda (i x) (values x (- x 1)))
10 0)
@result{} #(0 -1 -2 -3 -4 -5 -6 -7 -8 -9)
(vector-unfold values 10)
@result{} #(0 1 2 3 4 5 6 7 8 9)
@end example
@end deffn
@deffn {Scheme Procedure} vector-unfold-right f length initial-seed @dots{}
Like @code{vector-unfold}, but it uses @var{f} to generate elements from
right-to-left, rather than left-to-right.
@example
(vector-unfold-right (lambda (i x) (values x (+ x 1)))
10 0)
@result{} #(9 8 7 6 5 4 3 2 1 0)
@end example
@end deffn
@deffn {Scheme Procedure} vector-copy vec [start [end [fill]]]
Allocate a new vector whose length is @var{end} - @var{start} and fills
it with elements from @var{vec}, taking elements from @var{vec} starting
at index @var{start} and stopping at index @var{end}. @var{start}
defaults to 0 and @var{end} defaults to the value of
@code{(vector-length vec)}. If @var{end} extends beyond the length of
@var{vec}, the slots in the new vector that obviously cannot be filled
by elements from @var{vec} are filled with @var{fill}, whose default
value is unspecified.
@example
(vector-copy '#(a b c d e f g h i))
@result{} #(a b c d e f g h i)
(vector-copy '#(a b c d e f g h i) 6)
@result{} #(g h i)
(vector-copy '#(a b c d e f g h i) 3 6)
@result{} #(d e f)
(vector-copy '#(a b c d e f g h i) 6 12 'x)
@result{} #(g h i x x x)
@end example
@end deffn
@deffn {Scheme Procedure} vector-reverse-copy vec [start [end]]
Like @code{vector-copy}, but it copies the elements in the reverse order
from @var{vec}.
@example
(vector-reverse-copy '#(5 4 3 2 1 0) 1 5)
@result{} #(1 2 3 4)
@end example
@end deffn
@deffn {Scheme Procedure} vector-append vec @dots{}
Return a newly allocated vector that contains all elements in order from
the subsequent locations in @var{vec} @enddots{}.
@example
(vector-append '#(a) '#(b c d))
@result{} #(a b c d)
@end example
@end deffn
@deffn {Scheme Procedure} vector-concatenate list-of-vectors
Append each vector in @var{list-of-vectors}. Equivalent to
@code{(apply vector-append list-of-vectors)}.
@example
(vector-concatenate '(#(a b) #(c d)))
@result{} #(a b c d)
@end example
@end deffn
@node SRFI-43 Predicates
@subsubsection SRFI-43 Predicates
@deffn {Scheme Procedure} vector? obj
Return true if @var{obj} is a vector, else return false.
@end deffn
@deffn {Scheme Procedure} vector-empty? vec
Return true if @var{vec} is empty, i.e. its length is 0, else return
false.
@end deffn
@deffn {Scheme Procedure} vector= elt=? vec @dots{}
Return true if the vectors @var{vec} @dots{} have equal lengths and
equal elements according to @var{elt=?}. @var{elt=?} is always applied
to two arguments. Element comparison must be consistent with @code{eq?}
in the following sense: if @code{(eq? a b)} returns true, then
@code{(elt=? a b)} must also return true. The order in which
comparisons are performed is unspecified.
@end deffn
@node SRFI-43 Selectors
@subsubsection SRFI-43 Selectors
@deffn {Scheme Procedure} vector-ref vec i
Return the value that the location in @var{vec} at @var{i} is mapped to
in the store. Indexing is based on zero.
@end deffn
@deffn {Scheme Procedure} vector-length vec
Return the length of @var{vec}.
@end deffn
@node SRFI-43 Iteration
@subsubsection SRFI-43 Iteration
@deffn {Scheme Procedure} vector-fold kons knil vec1 vec2 @dots{}
The fundamental vector iterator. @var{kons} is iterated over each index
in all of the vectors, stopping at the end of the shortest; @var{kons}
is applied as
@smalllisp
(kons i state (vector-ref vec1 i) (vector-ref vec2 i) ...)
@end smalllisp
where @var{state} is the current state value, and @var{i} is the current
index. The current state value begins with @var{knil}, and becomes
whatever @var{kons} returned at the respective iteration. The iteration
is strictly left-to-right.
@end deffn
@deffn {Scheme Procedure} vector-fold-right kons knil vec1 vec2 @dots{}
Similar to @code{vector-fold}, but it iterates right-to-left instead of
left-to-right.
@end deffn
@deffn {Scheme Procedure} vector-map f vec1 vec2 @dots{}
Return a new vector of the shortest size of the vector arguments. Each
element at index i of the new vector is mapped from the old vectors by
@smalllisp
(f i (vector-ref vec1 i) (vector-ref vec2 i) ...)
@end smalllisp
The dynamic order of application of @var{f} is unspecified.
@end deffn
@deffn {Scheme Procedure} vector-map! f vec1 vec2 @dots{}
Similar to @code{vector-map}, but rather than mapping the new elements
into a new vector, the new mapped elements are destructively inserted
into @var{vec1}. The dynamic order of application of @var{f} is
unspecified.
@end deffn
@deffn {Scheme Procedure} vector-for-each f vec1 vec2 @dots{}
Call @code{(f i (vector-ref vec1 i) (vector-ref vec2 i) ...)} for each
index i less than the length of the shortest vector passed. The
iteration is strictly left-to-right.
@end deffn
@deffn {Scheme Procedure} vector-count pred? vec1 vec2 @dots{}
Count the number of parallel elements in the vectors that satisfy
@var{pred?}, which is applied, for each index i less than the length of
the smallest vector, to i and each parallel element in the vectors at
that index, in order.
@example
(vector-count (lambda (i elt) (even? elt))
'#(3 1 4 1 5 9 2 5 6))
@result{} 3
(vector-count (lambda (i x y) (< x y))
'#(1 3 6 9) '#(2 4 6 8 10 12))
@result{} 2
@end example
@end deffn
@node SRFI-43 Searching
@subsubsection SRFI-43 Searching
@deffn {Scheme Procedure} vector-index pred? vec1 vec2 @dots{}
Find and return the index of the first elements in @var{vec1} @var{vec2}
@dots{} that satisfy @var{pred?}. If no matching element is found by
the end of the shortest vector, return @code{#f}.
@example
(vector-index even? '#(3 1 4 1 5 9))
@result{} 2
(vector-index < '#(3 1 4 1 5 9 2 5 6) '#(2 7 1 8 2))
@result{} 1
(vector-index = '#(3 1 4 1 5 9 2 5 6) '#(2 7 1 8 2))
@result{} #f
@end example
@end deffn
@deffn {Scheme Procedure} vector-index-right pred? vec1 vec2 @dots{}
Like @code{vector-index}, but it searches right-to-left, rather than
left-to-right. Note that the SRFI 43 specification requires that all
the vectors must have the same length, but both the SRFI 43 reference
implementation and Guile's implementation allow vectors with unequal
lengths, and start searching from the last index of the shortest vector.
@end deffn
@deffn {Scheme Procedure} vector-skip pred? vec1 vec2 @dots{}
Find and return the index of the first elements in @var{vec1} @var{vec2}
@dots{} that do not satisfy @var{pred?}. If no matching element is
found by the end of the shortest vector, return @code{#f}. Equivalent
to @code{vector-index} but with the predicate inverted.
@example
(vector-skip number? '#(1 2 a b 3 4 c d)) @result{} 2
@end example
@end deffn
@deffn {Scheme Procedure} vector-skip-right pred? vec1 vec2 @dots{}
Like @code{vector-skip}, but it searches for a non-matching element
right-to-left, rather than left-to-right. Note that the SRFI 43
specification requires that all the vectors must have the same length,
but both the SRFI 43 reference implementation and Guile's implementation
allow vectors with unequal lengths, and start searching from the last
index of the shortest vector.
@end deffn
@deffn {Scheme Procedure} vector-binary-search vec value cmp [start [end]]
Find and return an index of @var{vec} between @var{start} and @var{end}
whose value is @var{value} using a binary search. If no matching
element is found, return @code{#f}. The default @var{start} is 0 and
the default @var{end} is the length of @var{vec}.
@var{cmp} must be a procedure of two arguments such that @code{(cmp a
b)} returns a negative integer if @math{a < b}, a positive integer if
@math{a > b}, or zero if @math{a = b}. The elements of @var{vec} must
be sorted in non-decreasing order according to @var{cmp}.
Note that SRFI 43 does not document the @var{start} and @var{end}
arguments, but both its reference implementation and Guile's
implementation support them.
@example
(define (char-cmp c1 c2)
(cond ((char<? c1 c2) -1)
((char>? c1 c2) 1)
(else 0)))
(vector-binary-search '#(#\a #\b #\c #\d #\e #\f #\g #\h)
#\g
char-cmp)
@result{} 6
@end example
@end deffn
@deffn {Scheme Procedure} vector-any pred? vec1 vec2 @dots{}
Find the first parallel set of elements from @var{vec1} @var{vec2}
@dots{} for which @var{pred?} returns a true value. If such a parallel
set of elements exists, @code{vector-any} returns the value that
@var{pred?} returned for that set of elements. The iteration is
strictly left-to-right.
@end deffn
@deffn {Scheme Procedure} vector-every pred? vec1 vec2 @dots{}
If, for every index i between 0 and the length of the shortest vector
argument, the set of elements @code{(vector-ref vec1 i)}
@code{(vector-ref vec2 i)} @dots{} satisfies @var{pred?},
@code{vector-every} returns the value that @var{pred?} returned for the
last set of elements, at the last index of the shortest vector.
Otherwise it returns @code{#f}. The iteration is strictly
left-to-right.
@end deffn
@node SRFI-43 Mutators
@subsubsection SRFI-43 Mutators
@deffn {Scheme Procedure} vector-set! vec i value
Assign the contents of the location at @var{i} in @var{vec} to
@var{value}.
@end deffn
@deffn {Scheme Procedure} vector-swap! vec i j
Swap the values of the locations in @var{vec} at @var{i} and @var{j}.
@end deffn
@deffn {Scheme Procedure} vector-fill! vec fill [start [end]]
Assign the value of every location in @var{vec} between @var{start} and
@var{end} to @var{fill}. @var{start} defaults to 0 and @var{end}
defaults to the length of @var{vec}.
@end deffn
@deffn {Scheme Procedure} vector-reverse! vec [start [end]]
Destructively reverse the contents of @var{vec} between @var{start} and
@var{end}. @var{start} defaults to 0 and @var{end} defaults to the
length of @var{vec}.
@end deffn
@deffn {Scheme Procedure} vector-copy! target tstart source [sstart [send]]
Copy a block of elements from @var{source} to @var{target}, both of
which must be vectors, starting in @var{target} at @var{tstart} and
starting in @var{source} at @var{sstart}, ending when (@var{send} -
@var{sstart}) elements have been copied. It is an error for
@var{target} to have a length less than (@var{tstart} + @var{send} -
@var{sstart}). @var{sstart} defaults to 0 and @var{send} defaults to
the length of @var{source}.
@end deffn
@deffn {Scheme Procedure} vector-reverse-copy! target tstart source [sstart [send]]
Like @code{vector-copy!}, but this copies the elements in the reverse
order. It is an error if @var{target} and @var{source} are identical
vectors and the @var{target} and @var{source} ranges overlap; however,
if @var{tstart} = @var{sstart}, @code{vector-reverse-copy!} behaves as
@code{(vector-reverse! target tstart send)} would.
@end deffn
@node SRFI-43 Conversion
@subsubsection SRFI-43 Conversion
@deffn {Scheme Procedure} vector->list vec [start [end]]
Return a newly allocated list containing the elements in @var{vec}
between @var{start} and @var{end}. @var{start} defaults to 0 and
@var{end} defaults to the length of @var{vec}.
@end deffn
@deffn {Scheme Procedure} reverse-vector->list vec [start [end]]
Like @code{vector->list}, but the resulting list contains the specified
range of elements of @var{vec} in reverse order.
@end deffn
@deffn {Scheme Procedure} list->vector proper-list [start [end]]
Return a newly allocated vector of the elements from @var{proper-list}
with indices between @var{start} and @var{end}. @var{start} defaults to
0 and @var{end} defaults to the length of @var{proper-list}. Note that
SRFI 43 does not document the @var{start} and @var{end} arguments, but
both its reference implementation and Guile's implementation support
them.
@end deffn
@deffn {Scheme Procedure} reverse-list->vector proper-list [start [end]]
Like @code{list->vector}, but the resulting vector contains the specified
range of elements of @var{proper-list} in reverse order. Note that SRFI
43 does not document the @var{start} and @var{end} arguments, but both
its reference implementation and Guile's implementation support them.
@end deffn
@node SRFI-45
@subsection SRFI-45 - Primitives for Expressing Iterative Lazy Algorithms
@cindex SRFI-45
@ -4852,6 +5265,13 @@ needed to get SRFI-61 itself. Extended @code{cond} is documented in
Starting from version 2.0, Guile's @code{read} supports SRFI-62/R7RS
S-expression comments by default.
@node SRFI-64
@subsection SRFI-64 - A Scheme API for test suites.
@cindex SRFI-64
See @uref{http://srfi.schemers.org/srfi-64/srfi-64.html, the
specification of SRFI-64}.
@node SRFI-67
@subsection SRFI-67 - Compare procedures
@cindex SRFI-67

View file

@ -1,6 +1,7 @@
## Process this file with automake to produce Makefile.in.
##
## Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
## Copyright (C) 2009, 2010, 2011, 2012, 2013,
## 2014 Free Software Foundation, Inc.
##
## This file is part of GUILE.
##
@ -279,6 +280,8 @@ SCRIPTS_SOURCES += \
endif BUILD_ICE_9_POPEN
srfi/srfi-64.go: srfi/srfi-64.scm srfi/srfi-64/testing.scm
SRFI_SOURCES = \
srfi/srfi-2.scm \
srfi/srfi-4.scm \
@ -304,9 +307,11 @@ SRFI_SOURCES = \
srfi/srfi-38.scm \
srfi/srfi-41.scm \
srfi/srfi-42.scm \
srfi/srfi-43.scm \
srfi/srfi-39.scm \
srfi/srfi-45.scm \
srfi/srfi-60.scm \
srfi/srfi-64.scm \
srfi/srfi-67.scm \
srfi/srfi-69.scm \
srfi/srfi-88.scm \
@ -418,6 +423,7 @@ NOCOMP_SOURCES = \
ice-9/r6rs-libraries.scm \
ice-9/quasisyntax.scm \
srfi/srfi-42/ec.scm \
srfi/srfi-64/testing.scm \
srfi/srfi-67/compare.scm \
system/base/lalr.upstream.scm \
system/repl/describe.scm \

1077
module/srfi/srfi-43.scm Normal file

File diff suppressed because it is too large Load diff

55
module/srfi/srfi-64.scm Normal file
View file

@ -0,0 +1,55 @@
;;; srfi-64.scm -- SRFI 64 - A Scheme API for test suites.
;; Copyright (C) 2014 Free Software Foundation, Inc.
;;
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
;; License as published by the Free Software Foundation; either
;; version 3 of the License, or (at your option) any later version.
;;
;; This library is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public
;; License along with this library; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (srfi srfi-64)
#:export
(test-begin
test-end test-assert test-eqv test-eq test-equal
test-approximate test-assert test-error test-apply test-with-runner
test-match-nth test-match-all test-match-any test-match-name
test-skip test-expect-fail test-read-eval-string
test-runner-group-path test-group test-group-with-cleanup
test-result-ref test-result-set! test-result-clear test-result-remove
test-result-kind test-passed?
test-log-to-file
test-runner? test-runner-reset test-runner-null
test-runner-simple test-runner-current test-runner-factory test-runner-get
test-runner-create test-runner-test-name
test-runner-pass-count test-runner-pass-count!
test-runner-fail-count test-runner-fail-count!
test-runner-xpass-count test-runner-xpass-count!
test-runner-xfail-count test-runner-xfail-count!
test-runner-skip-count test-runner-skip-count!
test-runner-group-stack test-runner-group-stack!
test-runner-on-test-begin test-runner-on-test-begin!
test-runner-on-test-end test-runner-on-test-end!
test-runner-on-group-begin test-runner-on-group-begin!
test-runner-on-group-end test-runner-on-group-end!
test-runner-on-final test-runner-on-final!
test-runner-on-bad-count test-runner-on-bad-count!
test-runner-on-bad-end-name test-runner-on-bad-end-name!
test-result-alist test-result-alist!
test-runner-aux-value test-runner-aux-value!
test-on-group-begin-simple test-on-group-end-simple
test-on-bad-count-simple test-on-bad-end-name-simple
test-on-final-simple test-on-test-end-simple
test-on-final-simple))
(cond-expand-provide (current-module) '(srfi-64))
(include-from-path "srfi/srfi-64/testing.scm")

File diff suppressed because it is too large Load diff

View file

@ -137,8 +137,10 @@ SCM_TESTS = tests/00-initial-env.test \
tests/srfi-39.test \
tests/srfi-41.test \
tests/srfi-42.test \
tests/srfi-43.test \
tests/srfi-45.test \
tests/srfi-60.test \
tests/srfi-64.test \
tests/srfi-67.test \
tests/srfi-69.test \
tests/srfi-88.test \
@ -177,7 +179,8 @@ EXTRA_DIST = \
guile-test \
test-suite/lib.scm \
$(SCM_TESTS) \
tests/rnrs-test-a.scm
tests/rnrs-test-a.scm \
tests/srfi-64-test.scm \
ChangeLog-2008

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,934 @@
;;;
;;; This is a test suite written in the notation of
;;; SRFI-64, A Scheme API for test suites
;;;
(test-begin "SRFI 64 - Meta-Test Suite")
;;;
;;; Ironically, in order to set up the meta-test environment,
;;; we have to invoke one of the most sophisticated features:
;;; custom test runners
;;;
;;; The `prop-runner' invokes `thunk' in the context of a new
;;; test runner, and returns the indicated properties of the
;;; last-executed test result.
(define (prop-runner props thunk)
(let ((r (test-runner-null))
(plist '()))
;;
(test-runner-on-test-end!
r
(lambda (runner)
(set! plist (test-result-alist runner))))
;;
(test-with-runner r (thunk))
;; reorder the properties so they are in the order
;; given by `props'. Note that any property listed in `props'
;; that is not in the property alist will occur as #f
(map (lambda (k)
(assq k plist))
props)))
;;; `on-test-runner' creates a null test runner and then
;;; arranged for `visit' to be called with the runner
;;; whenever a test is run. The results of the calls to
;;; `visit' are returned in a list
(define (on-test-runner thunk visit)
(let ((r (test-runner-null))
(results '()))
;;
(test-runner-on-test-end!
r
(lambda (runner)
(set! results (cons (visit r) results))))
;;
(test-with-runner r (thunk))
(reverse results)))
;;;
;;; The `triv-runner' invokes `thunk'
;;; and returns a list of 6 lists, the first 5 of which
;;; are a list of the names of the tests that, respectively,
;;; PASS, FAIL, XFAIL, XPASS, and SKIP.
;;; The last item is a list of counts.
;;;
(define (triv-runner thunk)
(let ((r (test-runner-null))
(accum-pass '())
(accum-fail '())
(accum-xfail '())
(accum-xpass '())
(accum-skip '()))
;;
(test-runner-on-bad-count!
r
(lambda (runner count expected-count)
(error (string-append "bad count " (number->string count)
" but expected "
(number->string expected-count)))))
(test-runner-on-bad-end-name!
r
(lambda (runner begin end)
(error (string-append "bad end group name " end
" but expected " begin))))
(test-runner-on-test-end!
r
(lambda (runner)
(let ((n (test-runner-test-name runner)))
(case (test-result-kind runner)
((pass) (set! accum-pass (cons n accum-pass)))
((fail) (set! accum-fail (cons n accum-fail)))
((xpass) (set! accum-xpass (cons n accum-xpass)))
((xfail) (set! accum-xfail (cons n accum-xfail)))
((skip) (set! accum-skip (cons n accum-skip)))))))
;;
(test-with-runner r (thunk))
(list (reverse accum-pass) ; passed as expected
(reverse accum-fail) ; failed, but was expected to pass
(reverse accum-xfail) ; failed as expected
(reverse accum-xpass) ; passed, but was expected to fail
(reverse accum-skip) ; was not executed
(list (test-runner-pass-count r)
(test-runner-fail-count r)
(test-runner-xfail-count r)
(test-runner-xpass-count r)
(test-runner-skip-count r)))))
(define (path-revealing-runner thunk)
(let ((r (test-runner-null))
(seq '()))
;;
(test-runner-on-test-end!
r
(lambda (runner)
(set! seq (cons (list (test-runner-group-path runner)
(test-runner-test-name runner))
seq))))
(test-with-runner r (thunk))
(reverse seq)))
;;;
;;; Now we can start testing compliance with SRFI-64
;;;
(test-begin "1. Simple test-cases")
(test-begin "1.1. test-assert")
(define (t)
(triv-runner
(lambda ()
(test-assert "a" #t)
(test-assert "b" #f))))
(test-equal
"1.1.1. Very simple"
'(("a") ("b") () () () (1 1 0 0 0))
(t))
(test-equal
"1.1.2. A test with no name"
'(("a") ("") () () () (1 1 0 0 0))
(triv-runner (lambda () (test-assert "a" #t) (test-assert #f))))
(test-equal
"1.1.3. Tests can have the same name"
'(("a" "a") () () () () (2 0 0 0 0))
(triv-runner (lambda () (test-assert "a" #t) (test-assert "a" #t))))
(define (choke)
(vector-ref '#(1 2) 3))
(test-equal
"1.1.4. One way to FAIL is to throw an error"
'(() ("a") () () () (0 1 0 0 0))
(triv-runner (lambda () (test-assert "a" (choke)))))
(test-end);1.1
(test-begin "1.2. test-eqv")
(define (mean x y)
(/ (+ x y) 2.0))
(test-equal
"1.2.1. Simple numerical equivalence"
'(("c") ("a" "b") () () () (1 2 0 0 0))
(triv-runner
(lambda ()
(test-eqv "a" (mean 3 5) 4)
(test-eqv "b" (mean 3 5) 4.5)
(test-eqv "c" (mean 3 5) 4.0))))
(test-end);1.2
(test-end "1. Simple test-cases")
;;;
;;;
;;;
(test-begin "2. Tests for catching errors")
(test-begin "2.1. test-error")
(test-equal
"2.1.1. Baseline test; PASS with no optional args"
'(("") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
;; PASS
(test-error (vector-ref '#(1 2) 9)))))
(test-equal
"2.1.2. Baseline test; FAIL with no optional args"
'(() ("") () () () (0 1 0 0 0))
(triv-runner
(lambda ()
;; FAIL: the expr does not raise an error and `test-error' is
;; claiming that it will, so this test should FAIL
(test-error (vector-ref '#(1 2) 0)))))
(test-equal
"2.1.3. PASS with a test name and error type"
'(("a") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
;; PASS
(test-error "a" #t (vector-ref '#(1 2) 9)))))
(test-end "2.1. test-error")
(test-end "2. Tests for catching errors")
;;;
;;;
;;;
(test-begin "3. Test groups and paths")
(test-equal
"3.1. test-begin with unspecific test-end"
'(("b") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "b" #t)
(test-end))))
(test-equal
"3.2. test-begin with name-matching test-end"
'(("b") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "b" #t)
(test-end "a"))))
;;; since the error raised by `test-end' on a mismatch is not a test
;;; error, we actually expect the triv-runner itself to fail
(test-error
"3.3. test-begin with mismatched test-end"
#t
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "b" #t)
(test-end "x"))))
(test-equal
"3.4. test-begin with name and count"
'(("b" "c") () () () () (2 0 0 0 0))
(triv-runner
(lambda ()
(test-begin "a" 2)
(test-assert "b" #t)
(test-assert "c" #t)
(test-end "a"))))
;; similarly here, a mismatched count is a lexical error
;; and not a test failure...
(test-error
"3.5. test-begin with mismatched count"
#t
(triv-runner
(lambda ()
(test-begin "a" 99)
(test-assert "b" #t)
(test-end "a"))))
(test-equal
"3.6. introspecting on the group path"
'((() "w")
(("a" "b") "x")
(("a" "b") "y")
(("a") "z"))
;;
;; `path-revealing-runner' is designed to return a list
;; of the tests executed, in order. Each entry is a list
;; (GROUP-PATH TEST-NAME), and each GROUP-PATH is a list
;; of test groups starting from the topmost
;;
(path-revealing-runner
(lambda ()
(test-assert "w" #t)
(test-begin "a")
(test-begin "b")
(test-assert "x" #t)
(test-assert "y" #t)
(test-end)
(test-assert "z" #t))))
(test-end "3. Test groups and paths")
;;;
;;;
;;;
(test-begin "4. Handling set-up and cleanup")
(test-equal "4.1. Normal exit path"
'(in 1 2 out)
(let ((ex '()))
(define (do s)
(set! ex (cons s ex)))
;;
(triv-runner
(lambda ()
(test-group-with-cleanup
"foo"
(do 'in)
(do 1)
(do 2)
(do 'out))))
(reverse ex)))
(test-equal "4.2. Exception exit path"
'(in 1 out)
(let ((ex '()))
(define (do s)
(set! ex (cons s ex)))
;;
;; the outer runner is to run the `test-error' in, to
;; catch the exception raised in the inner runner,
;; since we don't want to depend on any other
;; exception-catching support
;;
(triv-runner
(lambda ()
(test-error
(triv-runner
(lambda ()
(test-group-with-cleanup
"foo"
(do 'in) (test-assert #t)
(do 1) (test-assert #t)
(choke) (test-assert #t)
(do 2) (test-assert #t)
(do 'out)))))))
(reverse ex)))
(test-end "4. Handling set-up and cleanup")
;;;
;;;
;;;
(test-begin "5. Test specifiers")
(test-begin "5.1. test-match-named")
(test-equal "5.1.1. match test names"
'(("y") () () () ("x") (1 0 0 0 1))
(triv-runner
(lambda ()
(test-skip (test-match-name "x"))
(test-assert "x" #t)
(test-assert "y" #t))))
(test-equal "5.1.2. but not group names"
'(("z") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
(test-skip (test-match-name "x"))
(test-begin "x")
(test-assert "z" #t)
(test-end))))
(test-end)
(test-begin "5.2. test-match-nth")
;; See also: [6.4. Short-circuit evaluation]
(test-equal "5.2.1. skip the nth one after"
'(("v" "w" "y" "z") () () () ("x") (4 0 0 0 1))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-nth 2))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP
(test-assert "y" #t) ; 3
(test-assert "z" #t)))) ; 4
(test-equal "5.2.2. skip m, starting at n"
'(("v" "w" "z") () () () ("x" "y") (3 0 0 0 2))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-nth 2 2))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP
(test-assert "y" #t) ; 3 SKIP
(test-assert "z" #t)))) ; 4
(test-end)
(test-begin "5.3. test-match-any")
(test-equal "5.3.1. basic disjunction"
'(("v" "w" "z") () () () ("x" "y") (3 0 0 0 2))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-any (test-match-nth 3)
(test-match-name "x")))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP(NAME)
(test-assert "y" #t) ; 3 SKIP(COUNT)
(test-assert "z" #t)))) ; 4
(test-equal "5.3.2. disjunction is commutative"
'(("v" "w" "z") () () () ("x" "y") (3 0 0 0 2))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-any (test-match-name "x")
(test-match-nth 3)))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP(NAME)
(test-assert "y" #t) ; 3 SKIP(COUNT)
(test-assert "z" #t)))) ; 4
(test-end)
(test-begin "5.4. test-match-all")
(test-equal "5.4.1. basic conjunction"
'(("v" "w" "y" "z") () () () ("x") (4 0 0 0 1))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-all (test-match-nth 2 2)
(test-match-name "x")))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP(NAME) & SKIP(COUNT)
(test-assert "y" #t) ; 3 SKIP(COUNT)
(test-assert "z" #t)))) ; 4
(test-equal "5.4.2. conjunction is commutative"
'(("v" "w" "y" "z") () () () ("x") (4 0 0 0 1))
(triv-runner
(lambda ()
(test-assert "v" #t)
(test-skip (test-match-all (test-match-name "x")
(test-match-nth 2 2)))
(test-assert "w" #t) ; 1
(test-assert "x" #t) ; 2 SKIP(NAME) & SKIP(COUNT)
(test-assert "y" #t) ; 3 SKIP(COUNT)
(test-assert "z" #t)))) ; 4
(test-end)
(test-end "5. Test specifiers")
;;;
;;;
;;;
(test-begin "6. Skipping selected tests")
(test-equal
"6.1. Skip by specifier - match-name"
'(("x") () () () ("y") (1 0 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip (test-match-name "y"))
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; SKIP
(test-end))))
(test-equal
"6.2. Shorthand specifiers"
'(("x") () () () ("y") (1 0 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "y")
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; SKIP
(test-end))))
(test-begin "6.3. Specifier Stack")
(test-equal
"6.3.1. Clearing the Specifier Stack"
'(("x" "x") ("y") () () ("y") (2 1 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "y")
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; SKIP
(test-end)
(test-begin "b")
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; FAIL
(test-end))))
(test-equal
"6.3.2. Inheriting the Specifier Stack"
'(("x" "x") () () () ("y" "y") (2 0 0 0 2))
(triv-runner
(lambda ()
(test-skip "y")
(test-begin "a")
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; SKIP
(test-end)
(test-begin "b")
(test-assert "x" #t) ; PASS
(test-assert "y" #f) ; SKIP
(test-end))))
(test-end);6.3
(test-begin "6.4. Short-circuit evaluation")
(test-equal
"6.4.1. In test-match-all"
'(("x") ("y" "x" "z") () () ("y") (1 3 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip (test-match-all "y" (test-match-nth 2)))
;; let's label the substructure forms so we can
;; see which one `test-match-nth' is going to skip
;; ; # "y" 2 result
(test-assert "x" #t) ; 1 - #f #f PASS
(test-assert "y" #f) ; 2 - #t #t SKIP
(test-assert "y" #f) ; 3 - #t #f FAIL
(test-assert "x" #f) ; 4 - #f #f FAIL
(test-assert "z" #f) ; 5 - #f #f FAIL
(test-end))))
(test-equal
"6.4.2. In separate skip-list entries"
'(("x") ("x" "z") () () ("y" "y") (1 2 0 0 2))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "y")
(test-skip (test-match-nth 2))
;; let's label the substructure forms so we can
;; see which one `test-match-nth' is going to skip
;; ; # "y" 2 result
(test-assert "x" #t) ; 1 - #f #f PASS
(test-assert "y" #f) ; 2 - #t #t SKIP
(test-assert "y" #f) ; 3 - #t #f SKIP
(test-assert "x" #f) ; 4 - #f #f FAIL
(test-assert "z" #f) ; 5 - #f #f FAIL
(test-end))))
(test-begin "6.4.3. Skipping test suites")
(test-equal
"6.4.3.1. Introduced using 'test-begin'"
'(("x") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "b")
(test-begin "b") ; not skipped
(test-assert "x" #t)
(test-end "b")
(test-end "a"))))
(test-expect-fail 1) ;; ???
(test-equal
"6.4.3.2. Introduced using 'test-group'"
'(() () () () () (0 0 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "b")
(test-group
"b" ; skipped
(test-assert "x" #t))
(test-end "a"))))
(test-equal
"6.4.3.3. Non-skipped 'test-group'"
'(("x") () () () () (1 0 0 0 0))
(triv-runner
(lambda ()
(test-begin "a")
(test-skip "c")
(test-group "b" (test-assert "x" #t))
(test-end "a"))))
(test-end) ; 6.4.3
(test-end);6.4
(test-end "6. Skipping selected tests")
;;;
;;;
;;;
(test-begin "7. Expected failures")
(test-equal "7.1. Simple example"
'(() ("x") ("z") () () (0 1 1 0 0))
(triv-runner
(lambda ()
(test-assert "x" #f)
(test-expect-fail "z")
(test-assert "z" #f))))
(test-equal "7.2. Expected exception"
'(() ("x") ("z") () () (0 1 1 0 0))
(triv-runner
(lambda ()
(test-assert "x" #f)
(test-expect-fail "z")
(test-assert "z" (choke)))))
(test-equal "7.3. Unexpectedly PASS"
'(() () ("y") ("x") () (0 0 1 1 0))
(triv-runner
(lambda ()
(test-expect-fail "x")
(test-expect-fail "y")
(test-assert "x" #t)
(test-assert "y" #f))))
(test-end "7. Expected failures")
;;;
;;;
;;;
(test-begin "8. Test-runner")
;;;
;;; Because we want this test suite to be accurate even
;;; when the underlying implementation chooses to use, e.g.,
;;; a global variable to implement what could be thread variables
;;; or SRFI-39 parameter objects, we really need to save and restore
;;; their state ourselves
;;;
(define (with-factory-saved thunk)
(let* ((saved (test-runner-factory))
(result (thunk)))
(test-runner-factory saved)
result))
(test-begin "8.1. test-runner-current")
(test-assert "8.1.1. automatically restored"
(let ((a 0)
(b 1)
(c 2))
;
(triv-runner
(lambda ()
(set! a (test-runner-current))
;;
(triv-runner
(lambda ()
(set! b (test-runner-current))))
;;
(set! c (test-runner-current))))
;;
(and (eq? a c)
(not (eq? a b)))))
(test-end)
(test-begin "8.2. test-runner-simple")
(test-assert "8.2.1. default on-test hook"
(eq? (test-runner-on-test-end (test-runner-simple))
test-on-test-end-simple))
(test-assert "8.2.2. default on-final hook"
(eq? (test-runner-on-final (test-runner-simple))
test-on-final-simple))
(test-end)
(test-begin "8.3. test-runner-factory")
(test-assert "8.3.1. default factory"
(eq? (test-runner-factory) test-runner-simple))
(test-assert "8.3.2. settable factory"
(with-factory-saved
(lambda ()
(test-runner-factory test-runner-null)
;; we have no way, without bringing in other SRFIs,
;; to make sure the following doesn't print anything,
;; but it shouldn't:
(test-with-runner
(test-runner-create)
(lambda ()
(test-begin "a")
(test-assert #t) ; pass
(test-assert #f) ; fail
(test-assert (vector-ref '#(3) 10)) ; fail with error
(test-end "a")))
(eq? (test-runner-factory) test-runner-null))))
(test-end)
;;; This got tested about as well as it could in 8.3.2
(test-begin "8.4. test-runner-create")
(test-end)
;;; This got tested about as well as it could in 8.3.2
(test-begin "8.5. test-runner-factory")
(test-end)
(test-begin "8.6. test-apply")
(test-equal "8.6.1. Simple (form 1) test-apply"
'(("w" "p" "v") () () () ("x") (3 0 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "w" #t)
(test-apply
(test-match-name "p")
(lambda ()
(test-begin "p")
(test-assert "x" #t)
(test-end)
(test-begin "z")
(test-assert "p" #t) ; only this one should execute in here
(test-end)))
(test-assert "v" #t))))
(test-equal "8.6.2. Simple (form 2) test-apply"
'(("w" "p" "v") () () () ("x") (3 0 0 0 1))
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "w" #t)
(test-apply
(test-runner-current)
(test-match-name "p")
(lambda ()
(test-begin "p")
(test-assert "x" #t)
(test-end)
(test-begin "z")
(test-assert "p" #t) ; only this one should execute in here
(test-end)))
(test-assert "v" #t))))
(test-expect-fail 1) ;; depends on all test-match-nth being called.
(test-equal "8.6.3. test-apply with skips"
'(("w" "q" "v") () () () ("x" "p" "x") (3 0 0 0 3))
(triv-runner
(lambda ()
(test-begin "a")
(test-assert "w" #t)
(test-skip (test-match-nth 2))
(test-skip (test-match-nth 4))
(test-apply
(test-runner-current)
(test-match-name "p")
(test-match-name "q")
(lambda ()
; only execute if SKIP=no and APPLY=yes
(test-assert "x" #t) ; # 1 SKIP=no APPLY=no
(test-assert "p" #t) ; # 2 SKIP=yes APPLY=yes
(test-assert "q" #t) ; # 3 SKIP=no APPLY=yes
(test-assert "x" #f) ; # 4 SKIP=yes APPLY=no
0))
(test-assert "v" #t))))
;;; Unfortunately, since there is no way to UNBIND the current test runner,
;;; there is no way to test the behavior of `test-apply' in the absence
;;; of a current runner within our little meta-test framework.
;;;
;;; To test the behavior manually, you should be able to invoke:
;;;
;;; (test-apply "a" (lambda () (test-assert "a" #t)))
;;;
;;; from the top level (with SRFI 64 available) and it should create a
;;; new, default (simple) test runner.
(test-end)
;;; This entire suite depends heavily on 'test-with-runner'. If it didn't
;;; work, this suite would probably go down in flames
(test-begin "8.7. test-with-runner")
(test-end)
;;; Again, this suite depends heavily on many of the test-runner
;;; components. We'll just test those that aren't being exercised
;;; by the meta-test framework
(test-begin "8.8. test-runner components")
(define (auxtrack-runner thunk)
(let ((r (test-runner-null)))
(test-runner-aux-value! r '())
(test-runner-on-test-end! r (lambda (r)
(test-runner-aux-value!
r
(cons (test-runner-test-name r)
(test-runner-aux-value r)))))
(test-with-runner r (thunk))
(reverse (test-runner-aux-value r))))
(test-equal "8.8.1. test-runner-aux-value"
'("x" "" "y")
(auxtrack-runner
(lambda ()
(test-assert "x" #t)
(test-begin "a")
(test-assert #t)
(test-end)
(test-assert "y" #f))))
(test-end) ; 8.8
(test-end "8. Test-runner")
(test-begin "9. Test Result Properties")
(test-begin "9.1. test-result-alist")
(define (symbol-alist? l)
(if (null? l)
#t
(and (pair? l)
(pair? (car l))
(symbol? (caar l))
(symbol-alist? (cdr l)))))
;;; check the various syntactic forms
(test-assert (symbol-alist?
(car (on-test-runner
(lambda ()
(test-assert #t))
(lambda (r)
(test-result-alist r))))))
(test-assert (symbol-alist?
(car (on-test-runner
(lambda ()
(test-assert #t))
(lambda (r)
(test-result-alist r))))))
;;; check to make sure the required properties are returned
(test-equal '((result-kind . pass))
(prop-runner
'(result-kind)
(lambda ()
(test-assert #t)))
)
(test-equal
'((result-kind . fail)
(expected-value . 2)
(actual-value . 3))
(prop-runner
'(result-kind expected-value actual-value)
(lambda ()
(test-equal 2 (+ 1 2)))))
(test-end "9.1. test-result-alist")
(test-begin "9.2. test-result-ref")
(test-equal '(pass)
(on-test-runner
(lambda ()
(test-assert #t))
(lambda (r)
(test-result-ref r 'result-kind))))
(test-equal '(pass)
(on-test-runner
(lambda ()
(test-assert #t))
(lambda (r)
(test-result-ref r 'result-kind))))
(test-equal '(fail pass)
(on-test-runner
(lambda ()
(test-assert (= 1 2))
(test-assert (= 1 1)))
(lambda (r)
(test-result-ref r 'result-kind))))
(test-end "9.2. test-result-ref")
(test-begin "9.3. test-result-set!")
(test-equal '(100 100)
(on-test-runner
(lambda ()
(test-assert (= 1 2))
(test-assert (= 1 1)))
(lambda (r)
(test-result-set! r 'foo 100)
(test-result-ref r 'foo))))
(test-end "9.3. test-result-set!")
(test-end "9. Test Result Properties")
;;;
;;;
;;;
#| Time to stop having fun...
(test-begin "9. For fun, some meta-test errors")
(test-equal
"9.1. Really PASSes, but test like it should FAIL"
'(() ("b") () () ())
(triv-runner
(lambda ()
(test-assert "b" #t))))
(test-expect-fail "9.2. Expect to FAIL and do so")
(test-expect-fail "9.3. Expect to FAIL but PASS")
(test-skip "9.4. SKIP this one")
(test-assert "9.2. Expect to FAIL and do so" #f)
(test-assert "9.3. Expect to FAIL but PASS" #t)
(test-assert "9.4. SKIP this one" #t)
(test-end)
|#
(test-end "SRFI 64 - Meta-Test Suite")
;;;

View file

@ -0,0 +1,45 @@
;;;; srfi-64.test --- Test suite for SRFI-64. -*- scheme -*-
;;;;
;;;; Copyright (C) 2014 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (test-srfi-64)
#:use-module ((test-suite lib) #:select (report))
#:use-module (srfi srfi-64))
(define (guile-test-runner)
(let ((runner (test-runner-null)))
(test-runner-on-test-end! runner
(lambda (runner)
(let* ((result-alist (test-result-alist runner))
(result-kind (assq-ref result-alist 'result-kind))
(test-name (list (assq-ref result-alist 'test-name))))
(case result-kind
((pass) (report 'pass test-name))
((xpass) (report 'upass test-name))
((skip) (report 'untested test-name))
((fail xfail)
(apply report result-kind test-name result-alist))
(else #t)))))
runner))
(test-with-runner
(guile-test-runner)
(primitive-load-path "tests/srfi-64-test.scm"))
;;; Local Variables:
;;; eval: (put 'test-runner-on-test-end! 'scheme-indent-function 1)
;;; End: