bug#71300: [PATCH v4] doc: Document SRFI 64.
Hi Maxime, Maxime Devos writes: >>> Based on this I believe it describes the specification. >> >>That's correct. It's been slightly modified in places where it said >>things like "left to the implementation" and I was able to verify what >>the current implementation in Guix does. > > I assume Guix->Guile. > > This modification of “left to the implementation” -> “what Guile does” is > problematic, since it misleads readers into thinking this is the standard > behaviour (it is after all named SRFI 64, not GRFI 64). > > “What Guile does” is also important information to have. Yes, I agree. I think this is actually what I did, but my way to wording of this above was not very good, and my memory fails. A diff of a freshly "snarfed" [0] srfi-64.html (from its most recent commit) against the documented submitted, which was hand-tuned: diff -u /tmp/srfi-64-resnarfed.texi /tmp/srfi-64-documented.texi --- /tmp/srfi-64-resnarfed.texi 2024-10-02 15:57:27.562406299 +0900 +++ /tmp/srfi-64-documented.texi2024-10-02 15:58:57.798218571 +0900 @@ -1,71 +1,58 @@ -@node SRFI 64 -@subsection SRFI 64: A Scheme API for test suites -@cindex SRFI 64 - - @node SRFI 64 Abstract @subsubsection SRFI 64 Abstract - -This defines an API for writing @dfn{test suites}, to make it easy -to portably test Scheme APIs, libraries, applications, and implementations. -A test suite is a collection of @dfn{test cases} that execute -in the context of a @dfn{test-runner}. This specification -also supports writing new test-runners, to allow customization -of reporting and processing the result of running test suites. +This defines an API for writing @dfn{test suites}, to make it easy to +portably test Scheme APIs, libraries, applications, and implementations. +A test suite is a collection of @dfn{test cases} that execute in the +context of a @dfn{test-runner}. This specification also supports +writing new test-runners, to allow customization of reporting and +processing the result of running test suites. @node SRFI 64 Rationale @subsubsection SRFI 64 Rationale - -The Scheme community needs a standard for writing test suites. -Every SRFI or other library should come with a test suite. -Such a test suite must be portable, without requiring any -non-standard features, such as modules. The test suite implementation -or "runner" need not be portable, but it is desirable that it be -possible to write a portable basic implementation. +The Scheme community needs a standard for writing test suites. Every +SRFI or other library should come with a test suite. Such a test suite +must be portable, without requiring any non-standard features, such as +modules. The test suite implementation or "runner" need not be +portable, but it is desirable that it be possible to write a portable +basic implementation. There are other testing frameworks written in Scheme, including -@url{https://docs.racket-lang.org/rackunit/, RackUnit}However RackUnit is not portable. -It is also a bit on the verbose side. -It would be useful to have a bridge between this framework and RackUnit -so RackUnit tests could run under this framework and vice versa. -There exists also at least one Scheme wrapper providing a Scheme interface -to the ``standard''@url{https://www.junit.org/, JUnit} API for Java. -It would be useful to have a bridge so that tests written using this -framework can run under a JUnit runner. -Neither of these features are part of this specification. - -This API makes use of implicit dynamic state, including an -implicit ``test runner''. This makes the API convenient -and terse to use, but it may be a little less elegant and ``compositional''than using explicit test objects, such as JUnit-style frameworks. -It is not claimed to follow either object-oriented or functional design -principles, but I hope it is useful and convenient to use and extend. +@url{https://docs.racket-lang.org/rackunit/, RackUnit}. However +RackUnit is not portable. It is also a bit on the verbose side. It +would be useful to have a bridge between this framework and RackUnit so +RackUnit tests could run under this framework and vice versa. There +exists also at least one Scheme wrapper providing a Scheme interface to +the ``standard'' @url{https://www.junit.org/, JUnit} API for Java. It +would be useful to have a bridge so that tests written using this +framework can run under a JUnit runner. Neither of these features are +part of this specification. + +This API makes use of implicit dynamic state, including an implicit +``test runner''. This makes the API convenient and terse to use, but it +may be a little less elegant and ``compositional'' than using explicit +test objects, such as JUnit-style frameworks. It is not claimed to +follow either object-oriented or functional design principles, but I +hope it is useful and convenient to use and extend. This proposal allows converting a Scheme source file to a test suite by just adding a few macros. You don'
bug#72365: srfi-64: test-on-bad-end-name-simple is not allowed to raise an exception
Taylan Kammer writes: Hi, sorry for taking so long to respond to your comments, work has been bit busy lately. I really appreciate you looking at them and validating and/or challenging my conclusions. > On 30.07.2024 21:51, Tomas Volf wrote: >> Hello, >> >> I think I found a bug in (srfi srfi-64) module shipped with GNU Guile. > > Hi Tomas, > > Thanks for stress-testing the SRFI 64 spec & implementation and > reporting all these discrepancies. :-) No problem, it was necessary during implementing my own version of SRFI-64. The full test suite is available as part of my library[2], the runner[3] is quite simple, so using it to test your implementation should be fairly easy. I think there are few more bugs than I reported, I lost the willpower to do the rest somewhere on the way. :/ 2: https://git.wolfsden.cz/guile-wolfsden/tree/tests/srfi-64 3: https://git.wolfsden.cz/guile-wolfsden/tree/build-aux/srfi64test-driver.scm > > Firstly, to reiterate some things I've already mentioned in the thread on bug > 71300, just so it goes on record here as well: > > I have a SRFI 64 implementation of my own. I hope Guile will switch to it > eventually because I find the upstream reference implementation to be somewhat > unpleasant to work with. (It's monolithic, and not the cleanest code.) I plan to attempt to upstream my version as well, so I guess it is a race :) > > Until then, my implementation can be used by following these steps: > > 1. Cloning this repo: > > https://codeberg.org/taylan/scheme-srfis/ > > 2. Running Guile like so: > > GUILE_LOAD_PATH=/path/to/scheme-srfis/guile-srfi-64 guile > > (Replacing /path/to/scheme-srfis with the actual path to wherein the repo was > cloned, of course.) > > Then, loading SRFI-64 the regular way should load my implementation > rather than the one that ships with Guile (which is the reference > implementation from the SRFI author). You can find my version here[0]. If you do not use Guix, building from tarball[1] might be easier. Contrary to your version, mine is available as (wolfsden srfi srfi-64). 0: https://git.wolfsden.cz/guile-wolfsden/ 1: https://wolfsden.cz/project/guile-wolfsden.html > > I'll respond to your reports one by one, treating them like bug reports > towards > my own implementation, since it was originally derived from the reference > implementation and has probably inherited some of the bugs. You are braver than me. After few days of staring at the reference implementation (in Guile), I just said "nope" and wrote a new one from scratch. > Unfortunately, I'm not motivated to work on the implementation that's > in Guile, because I find it too cumbersome to navigate its code and > the unclean coding practices too distracting. While in principle I agree, let us not be too harsh, the implementation is really old. I assume coding practices available at the time to achieve portability were bit different. The implementation even considers SRFI-9 optional, these days I think that would be considered bit absurd. > >> The specification says the following about the simple test runner: >> >>> Creates a new simple test-runner, that prints errors and a summary on the >>> standard output port. >> It does not mention that it can signal errors, so I believe the following >> should >> just print to the terminal: >> >> (use-modules (srfi srfi-64)) >> (test-on-bad-end-name-simple (test-runner-null) "x" "y") >> >> However is signals an error instead: >> >> Backtrace: >> In ice-9/boot-9.scm: >> 1752:10 6 (with-exception-handler _ _ #:unwind? _ #:unwind-for-type _) >> In unknown file: >>5 (apply-smob/0 #) >> In ice-9/boot-9.scm: >> 724:2 4 (call-with-prompt ("prompt") #> ice-9/eval.scm:330:…> …) >> In ice-9/eval.scm: >> 619:8 3 (_ #(#(#))) >> In ice-9/boot-9.scm: >>2836:4 2 (save-module-excursion #> ice-9/boot-9.scm:4393:3 ()>) >> 4388:12 1 (_) >> In srfi/srfi-64/testing.scm: >>375:14 0 (test-on-bad-end-name-simple _ _ _) >> >> srfi/srfi-64/testing.scm:375:14: In procedure >> test-on-bad-end-name-simple: >> test-end x does not match test-begin y > > The spec is very sparse on what the simple test runner does, so I'm > not sure if the intention is to imply that it does nothing other than > what's stated. I am not sure how to read the spec regarding this. But in my reading >>> Creates a new simple test-runner, that prints errors and a summary >>> on the standard output port. is clear enough. Same way I would think (for example) reporting a telemetry (e.g. on number of tests executed) would violate the spec. > > In one case, the reference implementation clearly violates the specification: > The simple test runner uses the `aux` field which the spec claims it doesn't > use. (My implementation fixes this.) However, in this case it's not that > clear-cut. > > In this case, I think raising an error is good default behavior, since the > misma
bug#73605: [PATCH] Replace SRFI-64 with a new implementation.
The bundled (reference) implementation was of somewhat mixed quality and it failed to follow standard in multiple places. This commit replaces it with a new one, written from scratch to follow the standard as close as possible. * module/srfi/srfi-64/testing.scm: Delete file. * module/srfi/srfi-64.scm: Replace with new implementation. * am/bootstrap.am (srfi/srfi-64.go): Remove extra dependencies. (NOCOMP_SOURCES): Remove srfi/srfi-64/testing.scm. * test-suite/tests/srfi-64-test.scm ("8.6.1. Simple (form 1) test-apply") ("8.6.2. Simple (form 2) test-apply"): Adjust tests to follow the specification. --- The current implementation of SRFI-64 is buggy and does not even follow the specification in many places. This blog post[0] lists some of the bugs found. This commit it by a new one written from scratch, that tries to solve both of those problems. The code library was tested with GNU Guix (probably biggest user of SRFI-64?) and it works. There are only 4 tests that used to pass and do not with a new implementation. In all of those cases, the bug in the test itself was masked by non-compliance of the previous SRFI-64 implementation. More details here [1]. Tests in Guile (srfi-64-test.scm) did require two changes, the test code does not (in my opinion) follow the specification. Since spec says > Any skip specifiers introduced by a test-skip are removed by a following > non-nested test-end. The test-ends on lines 729 and 747 are nested, they are not top-level, so the skip specifier should not be cleared. But I am opened to debate on this one. During writing the implementation, I produced many (over 300) test files which are available here[2]. I am not sure whether to have them in this commit as well. Opinions? Last remaining point to note is that there is some additional functionality not covered by the specification included (define-test, ...). I can remove it, by I consider it useful. Documentation is currently lacking, but that is intentional, since #71300 is not accepted yet, and logically it would belong in there. 0: https://wolfsden.cz/blog/post/state-of-srfi-64.html 1: https://emacs.ch/@graywolf/112944743928293340 2: https://git.wolfsden.cz/guile-wolfsden/tree/tests/srfi-64 am/bootstrap.am |2 - module/srfi/srfi-64.scm | 1011 +++- module/srfi/srfi-64/testing.scm | 1044 - test-suite/tests/srfi-64-test.scm |4 +- 4 files changed, 978 insertions(+), 1083 deletions(-) delete mode 100644 module/srfi/srfi-64/testing.scm diff --git a/am/bootstrap.am b/am/bootstrap.am index 9e5fca0db..d4a415e35 100644 --- a/am/bootstrap.am +++ b/am/bootstrap.am @@ -54,7 +54,6 @@ COMPILE = $(AM_V_GUILEC) \ ice-9/boot-9.go: ice-9/boot-9.scm ice-9/quasisyntax.scm ice-9/r6rs-libraries.scm ice-9/r7rs-libraries.scm ice-9/read.scm ice-9/match.go: ice-9/match.scm ice-9/match.upstream.scm -srfi/srfi-64.go: srfi/srfi-64.scm srfi/srfi-64/testing.scm # Keep this rule in sync with that in `am/guilec'. ice-9/psyntax-pp.go: ice-9/psyntax.scm ice-9/psyntax-pp.scm @@ -438,7 +437,6 @@ NOCOMP_SOURCES =\ ice-9/r7rs-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 \ diff --git a/module/srfi/srfi-64.scm b/module/srfi/srfi-64.scm index 925726f5c..1f60a72e5 100644 --- a/module/srfi/srfi-64.scm +++ b/module/srfi/srfi-64.scm @@ -1,6 +1,5 @@ -;;; srfi-64.scm -- SRFI 64 - A Scheme API for test suites. +;;; Copyright (C) 2024 Tomas Volf <~@wolfsden.cz> -;; 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 @@ -16,41 +15,983 @@ ;; License along with this library; if not, write to the Free Software ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;;; Commentary: + +;;; Implementation of the SRFI-64. In contrast to the reference +;;; implementation of @samp{(srfi srfi-64)} it aims to implement the +;;; standard fully and correctly. + +;;; Code: + (define-module (srfi srfi-64) + #:use-module (ice-9 exceptions) + #:use-module (ice-9 format) + #:use-module (ice-9 match) + #:use-module (ice-9 pretty-print) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) #: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
bug#72369: srfi-64: test-end fails to signal an error with null runner
Taylan Kammer writes: Hi, > On 30.07.2024 21:51, Tomas Volf wrote: >> Hello, >> >> I think I found a bug in (srfi srfi-64) module shipped with GNU Guile. >> >> The specification says the following about the test-end: >> >>> An error is reported if the suite-name does not match the current test group >>> name. >> Thus the following should signal an error: >> >> (use-modules (srfi srfi-64)) >> (let ((r (test-runner-null))) >> (test-runner-current r) >> (test-begin "x") >> (test-end "y")) >> >> However it does not. >> >> Have a nice day >> Tomas Volf > > This would be easy to change, but the on-bad-end-name handler would be kind of > useless if test-end was hardcoded to always raise an error. I think the > intended > meaning of the spec is that the default/simple test runner reports an error in > this case (by implementing the on-bad-end-name handler) but not test-end > itself. > > One could argue that "reporting" an error is not the same thing as > signaling/raising one. We could make test-end always print something to > stderr, > but not actually raise an error, so it technically fulfills the spec's promise > that it "reports" an error, but the usefulness of this is unclear to me. > > Opinions welcome. I think I reacted to these concerns in response to #72365, but for completeness pasting the same here: I agree that raising an error is good behavior. However I do not think that on-bad-end-name-function is a place where to do it. In my opinion the name mismatch is a hard error, in my implementation subclass of &programming-error[4]. If I am writing new test runner, the specification does not mention that raising the error is *my* responsibility, just that test-end will signal an error. To rephrase that: test-end is mandated to signal error, but custom test runner has no provision requiring it to do it in on-bad-end-name-function. Hence I believe test-end needs to be the one to signal the error. However! That does not make on-bad-end-name-function useless. The specification does not mandate *how* the error signaled by test-end should look like, hence there is no *portable* way to detect it. Custom runner, if it needs to report name mismatch specially, can just produce specific log line in the callback (or even signal its own exception first before test-end does). Let me know what you think (either here or in #72365 ^_^ ). Tomas -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
bug#72365: srfi-64: test-on-bad-end-name-simple is not allowed to raise an exception
On 02.10.2024 14:28, Tomas Volf wrote: > Taylan Kammer writes: > > Hi, > > sorry for taking so long to respond to your comments, work has been bit > busy lately. I took two months whereas you took two days, so I'm not going to complain. :D >> On 30.07.2024 21:51, Tomas Volf wrote: >>> Hello, >>> >>> I think I found a bug in (srfi srfi-64) module shipped with GNU Guile. >> Hi Tomas, >> >> Thanks for stress-testing the SRFI 64 spec & implementation and >> reporting all these discrepancies. :-) > No problem, it was necessary during implementing my own version of > SRFI-64. The full test suite is available as part of my library[2], the > runner[3] is quite simple, so using it to test your implementation > should be fairly easy. > > I think there are few more bugs than I reported, I lost the willpower to > do the rest somewhere on the way. :/ > > 2: https://git.wolfsden.cz/guile-wolfsden/tree/tests/srfi-64 > 3: https://git.wolfsden.cz/guile-wolfsden/tree/build-aux/srfi64test-driver.scm Do I understand correctly that this is an additional test suite for testing SRFI-64 itself? Like the "meta test suite" shipped with SRFI-64? Is there a brief description somewhere on how to run it with Guile? Would be really neat if I can use it to further test my implementation. >> Firstly, to reiterate some things I've already mentioned in the thread on >> bug 71300, just so it goes on record here as well: >> >> I have a SRFI 64 implementation of my own. I hope Guile will switch to it >> eventually because I find the upstream reference implementation to be >> somewhat >> unpleasant to work with. (It's monolithic, and not the cleanest code.) > I plan to attempt to upstream my version as well, so I guess it is a > race :) > >> Until then, my implementation can be used by following these steps: >> >> 1. Cloning this repo: >> >> https://codeberg.org/taylan/scheme-srfis/ >> >> 2. Running Guile like so: >> >> GUILE_LOAD_PATH=/path/to/scheme-srfis/guile-srfi-64 guile >> >> (Replacing /path/to/scheme-srfis with the actual path to wherein the repo >> was cloned, of course.) >> >> Then, loading SRFI-64 the regular way should load my implementation >> rather than the one that ships with Guile (which is the reference >> implementation from the SRFI author). > You can find my version here[0]. If you do not use Guix, building from > tarball[1] might be easier. Contrary to your version, mine is available > as (wolfsden srfi srfi-64). > > 0: https://git.wolfsden.cz/guile-wolfsden/ > 1: https://wolfsden.cz/project/guile-wolfsden.html Your implementation seems written specifically with Guile in mind, which is a big plus I guess. Mine was written with R7RS in mind, and has compatibility shims for Guile as well as other Scheme implementations like Kawa (shims adopted from the original implementation). This makes it hacky in some parts, like when it comes to how it gathers source code information for file name & line number reporting. It also lacks docstrings, doesn't make use of Guile features like `define*` and so on... If the quality of the implementations is the same or higher, in terms of observable behavior, then it should be preferred for Guile, I think. If I find the time, I'll see if I can use your implementation to run some of my test suites, like the bytestructures test suite, and report if I notice any issues. >> Unfortunately, I'm not motivated to work on the implementation that's >> in Guile, because I find it too cumbersome to navigate its code and >> the unclean coding practices too distracting. > While in principle I agree, let us not be too harsh, the implementation > is really old. I assume coding practices available at the time to > achieve portability were bit different. The implementation even > considers SRFI-9 optional, these days I think that would be considered > bit absurd. That's true. I don't mean to insult the author or anything. It is what it is. >> The spec is very sparse on what the simple test runner does, so I'm >> not sure if the intention is to imply that it does nothing other than >> what's stated. > I am not sure how to read the spec regarding this. But in my reading > Creates a new simple test-runner, that prints errors and a summary on the standard output port. > is clear enough. Same way I would think (for example) reporting a > telemetry (e.g. on number of tests executed) would violate the spec. > >> In one case, the reference implementation clearly violates the specification: >> The simple test runner uses the `aux` field which the spec claims it doesn't >> use. (My implementation fixes this.) However, in this case it's not that >> clear-cut. >> >> In this case, I think raising an error is good default behavior, since the >> mismatched end name indicates a problem with the test suite itself rather >> than >> the code being tested. If it poses a problem to the user, one can override >> that >> callback with the `test-runner-on-bad-end-name!` setter. >
bug#72365: srfi-64: test-on-bad-end-name-simple is not allowed to raise an exception
Taylan Kammer writes: > Do I understand correctly that this is an additional test suite for > testing SRFI-64 itself? Like the "meta test suite" shipped with > SRFI-64? Yes, exactly. Vast majority of the tests are just derived from the specification, with few non-portable written just for my implementation, but those can be turned off. > > Is there a brief description somewhere on how to run it with Guile? > Would be really neat if I can use it to further test my > implementation. It is not hard, but at the same time the test suite is not really stand-alone, so the instructions will be bit hackish. 1. Download https://files.wolfsden.cz/releases/guile-wolfsden/guile-wolfsden-0.0.1.tar.gz 2. Unpack it. 3. Open `build-aux/srfi64test-driver.scm'. 4. On line 35 replace 'wolfsden with 'guile. 5. Open `Makefile.am'. 6. Delete lines 17-19 (assignment to `TESTS' variable). 7. Open `tests/srfi-64/local.mk'. 8. On line 4 change `TESTS +=' to `TESTS ='. 9. Build the project and run the tests: $ autoreconf -fvi $ ./configure --disable-doc-snarf $ make $ make check Due to step 4. only portable (== written based on specification) tests will run, and they will run against (srfi srfi-64). Since you library is available as that module, just make sure it is on the load path. When I follow the steps, I get: # TOTAL: 340 # PASS: 265 # SKIP: 36 # XFAIL: 0 # FAIL: 39 # XPASS: 0 # ERROR: 0 You should get less FAILs I guess (since you have fixed many problems already, and some you did not even have). I am sure you will dispute some of those tests. ^_^ >> You can find my version here[0]. If you do not use Guix, building from >> tarball[1] might be easier. Contrary to your version, mine is available >> as (wolfsden srfi srfi-64). >> >> 0: https://git.wolfsden.cz/guile-wolfsden/ >> 1: https://wolfsden.cz/project/guile-wolfsden.html > > Your implementation seems written specifically with Guile in mind, > which is a big plus I guess. Yes, I decided to write my version in as-readable manner as possible (well, at least I hope the code is readable), at the cost of portability. Since I have seen what portability did to (srfi srfi-64). > If the quality of the implementations is the same or higher, in terms of > observable behavior, then it should be preferred for Guile, I think. If I find > the time, I'll see if I can use your implementation to run some of my test > suites, like the bytestructures test suite, and report if I notice any > issues. Oh, that would be much appreciated. I did test my version against Guix's test suite (and it revealed 4 bugs in Guix's tests) and none in my library, so I hope results for your project would be similar. >>> In one case, the reference implementation clearly violates the >>> specification: >>> The simple test runner uses the `aux` field which the spec claims it doesn't >>> use. (My implementation fixes this.) However, in this case it's not that >>> clear-cut. >>> >>> In this case, I think raising an error is good default behavior, since the >>> mismatched end name indicates a problem with the test suite itself rather >>> than >>> the code being tested. If it poses a problem to the user, one can override >>> that >>> callback with the `test-runner-on-bad-end-name!` setter. >>> >>> What do you think? >> I agree that raising an error is good behavior. However I do not think >> that on-bad-end-name-function is a place where to do it. In my opinion >> the name mismatch is a hard error, in my implementation subclass of >> &programming-error[4]. If I am writing new test runner, the >> specification does not mention that raising the error is *my* >> responsibility, just that test-end will signal an error. >> >> To rephrase that: test-end is mandated to signal error, but custom test >> runner has no provision requiring it to do it in >> on-bad-end-name-function. Hence I believe test-end needs to be the one >> to signal the error. > > Makes sense I guess. I've generally tried to imitate the reference > implementation's behavior as closely as possible in such matters, worrying > that > there might be code out there that relies on its various quirks, but maybe I'm > being too paranoid. I tried to not use reference implementation that much, and instead relied on the specification. It was slow and painful process. > I don't have a strong opinion either way. The number of people, who want to > write a test runner that does something special on bad-end-name (something > other > than raise an error), is probably very small. I definitely agree on this one. > > - Making `test-end` itself raise an error would probably be most convenient, > so test runner authors don't have to take care of it. > > - But if `test-end` doesn't do it, it's not a big deal either IMO, because all > they would need to do is to call `(test-runner-on-bad-end-name! my-runner > test-on-bad-end-name-simple)` to make their custom runner raise an error as > well. (And
bug#72369: srfi-64: test-end fails to signal an error with null runner
On 02.10.2024 21:57, Tomas Volf wrote: > Let me know what you think (either here or in #72365 ^_^ ). > > Tomas Sure thing! Responded in the other thread. - Taylan