From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v3] doc: Document SRFI 64. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Sat, 01 Jun 2024 02:19:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: 71300@debbugs.gnu.org Cc: Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxime Devos , Maxim Cournoyer X-Debbugs-Original-To: bug-guile@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.1717208294817 (code B ref -1); Sat, 01 Jun 2024 02:19:01 +0000 Received: (at submit) by debbugs.gnu.org; 1 Jun 2024 02:18:14 +0000 Received: from localhost ([127.0.0.1]:55562 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sDEJv-0000D5-R2 for submit@debbugs.gnu.org; Fri, 31 May 2024 22:18:13 -0400 Received: from lists.gnu.org ([209.51.188.17]:47398) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sDEJr-0000Cw-RJ for submit@debbugs.gnu.org; Fri, 31 May 2024 22:18:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sDEJg-00068W-1d for bug-guile@gnu.org; Fri, 31 May 2024 22:17:56 -0400 Received: from mail-yb1-xb2f.google.com ([2607:f8b0:4864:20::b2f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sDEJb-00041r-4H for bug-guile@gnu.org; Fri, 31 May 2024 22:17:55 -0400 Received: by mail-yb1-xb2f.google.com with SMTP id 3f1490d57ef6-dfa65af5367so2285134276.1 for ; Fri, 31 May 2024 19:17:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717208269; x=1717813069; darn=gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=yD9H3oOn2NRTimz2CTfPltsRFY3CRqyMAQ8Nn9XVlTE=; b=dVGbUOoTtGDNoWyxhLrW7G0iulgyEANtAuHrhLhBkIeXqxchshwcJ8BtZEpBEbB327 DVYDYIMlPbXBJIfT8sEQbWrMMP5mKlBdN5NlZyVIlwIGWfw/yun0GJcsvu4Vt5IuOAu5 etEa+SvMeAn9LW5FdpLonfL4GWe1h7/VqBB8XHOJY4PJG+dhJp7KKbEsdpwdxskSuH56 Mfz7udpSXI21EdkUV2rvPTo8XK1gVU8c8GdCvm3owr+Htzc8Bm0BXVBz1DUILJ/xmmWc 4QKLDFzc18vmD4n+8EqzWqf0mr1IDMYSM0+w5SSWC4pilYAqcME9I5kAhsndivgciQUN HjoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717208269; x=1717813069; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=yD9H3oOn2NRTimz2CTfPltsRFY3CRqyMAQ8Nn9XVlTE=; b=FS/kWLAcXuoHVv6Vws3Oh4Ec+QKMlVTJOYkG9pcLlUK7lQUDH2iWMeZlGrxiwonG6k kMaLE9oS6gY6Vt73v6hgDVBVnBMDVNOB32uLdpfKV9GeHmsOh/CV5LEC4qijiBLOJRt2 q+gpV+NfREc29eulr50cMH1YceKTxk5Yq+8Y1Wy7S72bUzvQNYL/KQWYrhpp1i53Uoz5 EeRn20tvjGKhc5itutSdfjAObVAJciTtUST2zHkkgwnc0DjFqWeFWcviO2ERoXYBvFil qd6hpK1FR4Lwucr3irDhmhDdwOjCPFk45/dl/hjrBiYmFVVtY0FTT5BKN01oTzyYjUnT BqUQ== X-Gm-Message-State: AOJu0Yxtq2iMTktQV+m59V9gjXVAJbP81cidWIt4vPeP/nrQBm6GagAx lFsfxiJJUiNUBKuwmt7zZlqYN/GYgMRENBmFf0XZWfLZVlU1/vrL50jgYw== X-Google-Smtp-Source: AGHT+IGglc1mK4xRUKj4UIk8o1yfrjzaGyjta+CTn3ohXwPhcZhV+gKujhbPlGN0Vf2c41IInI3SkQ== X-Received: by 2002:a25:df93:0:b0:de4:738b:c2ea with SMTP id 3f1490d57ef6-dfa73bec3d6mr3661537276.24.1717208268623; Fri, 31 May 2024 19:17:48 -0700 (PDT) Received: from localhost.localdomain (dsl-205-233-124-92.b2b2c.ca. [205.233.124.92]) by smtp.gmail.com with ESMTPSA id af79cd13be357-794f3061456sm102183085a.78.2024.05.31.19.17.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 May 2024 19:17:48 -0700 (PDT) From: Maxim Cournoyer Date: Fri, 31 May 2024 22:17:28 -0400 Message-ID: <20240601021743.808-1-maxim.cournoyer@gmail.com> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2607:f8b0:4864:20::b2f; envelope-from=maxim.cournoyer@gmail.com; helo=mail-yb1-xb2f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.3 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) This is an import of the 'Abstract', 'Rationale', and 'Specification' sections from the upstream specification text, with some manual adjustment. * doc/ref/srfi-modules.texi (SRFI 64): New subsection. --- Changes in v3: - Add copyright / license information - Replace SchemeUnit mentions with RackUnit Changes in v2: - Fix the category of many definitions doc/ref/guile.texi | 25 +- doc/ref/srfi-modules.texi | 830 +++++++++++++++++++++++++++++++++++++- 2 files changed, 847 insertions(+), 8 deletions(-) diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index bde9f6f75..988d30155 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -24,8 +24,31 @@ any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' -@end copying +Additionally, the documentation of the SRFI 64 module is adapted from +its specification text, which is made available under the following +Expat license: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@end copying @c Notes @c diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index efb9ccca4..0c2ddec81 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -1,7 +1,8 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018, 2019, 2020 +@c Copyright (C) 1996-1997, 2000-2004, 2006-2014, 2017-2020, 2023 @c Free Software Foundation, Inc. +@c Copyright (C) 2005-2006 Per Bothner @c See the file guile.texi for copying conditions. @node SRFI Support @@ -55,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page * 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 64:: A Scheme API for test suites. * SRFI-67:: Compare procedures * SRFI-69:: Basic hash tables. * SRFI-71:: Extended let-syntax for multiple values. @@ -5289,12 +5290,827 @@ 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 +@c This SRFI 64 documentation was "snarfed" from upstream specification +@c HTML document using the 'snarfi' script. +@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}. +@menu +* SRFI 64 Abstract:: +* SRFI 64 Rationale:: +* SRFI 64 Writing basic test suites:: +* SRFI 64 Conditonal test-suites and other advanced features:: +* SRFI 64 Test-runner:: +* SRFI 64 Test results:: +* SRFI 64 Writing a new test-runner:: +@end menu + +@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. + +@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. + +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. + +This proposal allows converting a Scheme source file to a +test suite by just adding a few macros. You don't have to +write the entire file in a new form, thus you don't have to +re-indent it. + +All names defined by the API start with the prefix @samp{test-}. All +function-like forms are defined as syntax. They may be implemented as +functions or macros or built-ins. The reason for specifying them as +syntax is to allow specific tests to be skipped without evaluating +sub-expressions, or for implementations to add features such as printing +line numbers or catching exceptions. + +@node SRFI 64 Writing basic test suites +@subsubsection SRFI 64 Writing basic test suites + +Let's start with a simple example. This is a complete self-contained +test-suite. + +@lisp +;; Initialize and give a name to a simple testsuite. +(test-begin "vec-test") +(define v (make-vector 5 99)) +;; Require that an expression evaluate to true. +(test-assert (vector? v)) +;; Test that an expression is eqv? to some other expression. +(test-eqv 99 (vector-ref v 2)) +(vector-set! v 2 7) +(test-eqv 7 (vector-ref v 2)) +;; Finish the testsuite, and report results. +(test-end "vec-test") +@end lisp + +This testsuite could be saved in its own source file. Nothing else is +needed: We do not require any top-level forms, so it is easy to wrap an +existing program or test to this form, without adding indentation. It +is also easy to add new tests, without having to name individual tests +(though that is optional). + +Test cases are executed in the context of a @dfn{test runner}, which is +a object that accumulates and reports test results. This specification +defines how to create and use custom test runners, but implementations +should also provide a default test runner. It is suggested (but not +required) that loading the above file in a top-level environment will +cause the tests to be executed using an implementation-specified default +test runner, and @code{test-end} will cause a summary to be displayed in +an implementation-specified manner. + +@subsubheading Simple test-cases + +Primitive test cases test that a given condition is true. They may have +a name. The core test case form is @code{test-assert}: + +@deffn {Scheme Syntax} test-assert [test-name] expression + +This evaluates the @var{expression}. The test passes if the result is +true; if the result is false, a test failure is reported. The test also +fails if an exception is raised, assuming the implementation has a way +to catch exceptions. How the failure is reported depends on the test +runner environment. The @var{test-name} is a string that names the test +case. (Though the @var{test-name} is a string literal in the examples, +it is an expression. It is evaluated only once.) It is used when +reporting errors, and also when skipping tests, as described below. It +is an error to invoke @code{test-assert}if there is no current test +runner. +@end deffn + +The following forms may be more convenient than using @code{test-assert} +directly: + +@deffn {Scheme Syntax} test-eqv [test-name] expected test-expr + +This is equivalent to: + +@lisp +(test-assert [@var{test-name}] (eqv? @var{expected} @var{test-expr})) +@end lisp + +@end deffn + +Similarly @code{test-equal} and @code{test-eq} are shorthand for +@code{test-assert} combined with @code{equal?} or @code{eq?}, +respectively: + +@deffn {Scheme Syntax} test-equal [test-name] expected test-expr +@deffnx {Scheme Syntax} test-eq [test-name] expected test-expr + +Here is a simple example: + +@lisp +(define (mean x y) (/ (+ x y) 2.0)) +(test-eqv 4 (mean 3 5)) +@end lisp +@end deffn + +For testing approximate equality of inexact reals +we can use @code{test-approximate}: + +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr error + +This is equivalent to (except that each argument is only evaluated +once): + +@lisp +(test-assert [test-name] + (and (>= test-expr (- expected error)) + (<= test-expr (+ expected error)))) +@end lisp +@end deffn + +@subsubheading Tests for catching errors + +We need a way to specify that evaluation @emph{should} fail. This +verifies that errors are detected when required. + +@deffn {Scheme Syntax} test-error [[test-name] error-type] test-expr + +Evaluating @var{test-expr} is expected to signal an error. The kind of +error is indicated by @var{error-type}. + +If the @var{error-type} is left out, or it is @code{#t}, it means "some +kind of unspecified error should be signaled". For example: + +@lisp +(test-error #t (vector-ref '#(1 2) 9)) +@end lisp + +This specification leaves it implementation-defined (or for a future +specification) what form @var{test-error} may take, though all +implementations must allow @code{#t}. Some implementations may support +@url{https://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35's +conditions}, but these are only standardized for +@url{https://srfi.schemers.org/srfi-36/srfi-36.html, SRFI-36's I/O +conditions}, which are seldom useful in test suites. An implementation +may also allow implementation-specific ``exception types''. For example +Java-based implementations may allow the names of Java exception +classes: + +@lisp +;; Kawa-specific example +(test-error (vector-ref '#(1 2) 9)) +@end lisp + +An implementation that cannot catch exceptions should skip +@code{test-error} forms. +@end deffn + +@subsubheading Testing syntax + +Testing syntax is tricky, especially if we want to check that invalid +syntax is causing an error. The following utility function can help: + +@deffn {Scheme Procedure} test-read-eval-string string + +This function parses @var{string} (using @code{read}) and evaluates the +result. The result of evaluation is returned from +@code{test-read-eval-string}. An error is signalled if there are unread +characters after the @code{read} is done. For example: +@code{(test-read-eval-string "(+ 3 4)")} @i{evaluates to} @code{7}. +@code{(test-read-eval-string "(+ 3 4")} @i{signals an error}. +@code{(test-read-eval-string "(+ 3 4) ")} @i{signals an error}, because +there is extra ``junk'' (@i{i.e.} a space) after the list is read. + +The @code{test-read-eval-string} used in tests: + +@lisp +(test-equal 7 (test-read-eval-string "(+ 3 4)")) +(test-error (test-read-eval-string "(+ 3")) +(test-equal #\newline (test-read-eval-string "#\\newline")) +(test-error (test-read-eval-string "#\\newlin")) +;; Skip the next 2 tests unless srfi-62 is available. +(test-skip (cond-expand (srfi-62 0) (else 2))) +(test-equal 5 (test-read-eval-string "(+ 1 #;(* 2 3) 4)")) +(test-equal '(x z) (test-read-string "(list 'x #;'y 'z)")) +@end lisp +@end deffn + +@subsubheading Test groups and paths + +A @dfn{test group} is a named sequence of forms containing testcases, +expressions, and definitions. Entering a group sets the @dfn{test group +name}; leaving a group restores the previous group name. These are +dynamic (run-time) operations, and a group has no other effect or +identity. Test groups are informal groupings: they are neither Scheme +values, nor are they syntactic forms. +@c (More formal test suite values are introduced below.) +A test group may contain nested inner test groups. +The @dfn{test group path} is a list of the currently-active +(entered) test group names, oldest (outermost) first. + +@deffn {Scheme Syntax} test-begin suite-name [count] + +A @code{test-begin} enters a new test group. The @var{suite-name} +becomes the current test group name, and is added to the end of the test +group path. Portable test suites should use a string literal for +@var{suite-name}; the effect of expressions or other kinds of literals +is unspecified. + +@emph{Rationale:} In some ways using symbols would be preferable. +However, we want human-readable names, and standard Scheme does not +provide a way to include spaces or mixed-case text in literal symbols. + +The optional @var{count} must match the number of test-cases executed by +this group. (Nested test groups count as a single test case for this +count.) This extra test may be useful to catch cases where a test +doesn't get executed because of some unexpected error. + +Additionally, if there is no currently executing test runner, +one is installed in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-end [suite-name] + +A @code{test-end} leaves the current test group. +An error is reported if the @var{suite-name} does not +match the current test group name. +@c If it does match an earlier name in the test group path, intervening +@c groups are left. + +Additionally, if the matching @code{test-begin}installed a new +test-runner, then the @code{test-end} will uninstall it, after reporting +the accumulated test results in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-group suite-name decl-or-expr @dots{} + +Equivalent to: + +@lisp +(if (not (test-to-skip% (var suite-name))) + (dynamic-wind + (lambda () (test-begin (var suite-name))) + (lambda () (var decl-or-expr) ...) + (lambda () (test-end (var suite-name))))) +@end lisp + +This is usually equivalent to executing the @var{decl-or-expr}s +within the named test group. However, the entire group is skipped +if it matched an active @code{test-skip} (see later). +Also, the @code{test-end} is executed in case of an exception. +@end deffn + +@subsubheading Handling set-up and cleanup + +@deffn {Scheme Syntax} test-group-with-cleanup suite-name decl-or-expr @dots{} cleanup-form + +Execute each of the @var{decl-or-expr} forms in order (as in a +@var{}), and then execute the @var{cleanup-form}. The latter +should be executed even if one of a @var{decl-or-expr} forms raises an +exception (assuming the implementation has a way to catch exceptions). + +For example: + +@lisp +(let ((f (open-output-file "log"))) + (test-group-with-cleanup "test-file" + (do-a-bunch-of-tests f) + (close-output-port f))) +@end lisp +@end deffn + +@node SRFI 64 Conditonal test-suites and other advanced features +@subsubsection SRFI 64 Conditonal test-suites and other advanced features + +The following describes features for controlling which tests to execute, +or specifying that some tests are @emph{expected} to fail. + +@subsubheading Test specifiers + +Sometimes we want to only run certain tests, or we know that certain +tests are expected to fail. A @dfn{test specifier} is one-argument +function that takes a test-runner and returns a boolean. The specifier +may be run before a test is performed, and the result may control +whether the test is executed. For convenience, a specifier may also be +a non-procedure value, which is coerced to a specifier procedure, as +described below for @var{count} and @var{name}. + +A simple example is: + +@lisp +(if (var some-condition) (test-skip 2)) ;; skip next 2 tests +@end lisp + +@deffn {Scheme Procedure} test-match-name name + +The resulting specifier matches if the current test name (as returned by +@code{test-runner-test-name}) is @code{equal?} to @var{name}. +@end deffn + +@deffn {Scheme Syntax} test-match-nth n [count] + +This evaluates to a @emph{stateful} predicate: A counter keeps track of +how many times it has been called. The predicate matches the @var{n}'th +time it is called (where @code{1} is the first time), and the next +@samp{(- @var{count} 1)} times, where @var{count} defaults to @code{1}. +@end deffn + +@deffn {Scheme Syntax} test-match-any specifier @dots{} + +The resulting specifier matches if any @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is true. +@end deffn + +@deffn {Scheme Syntax} test-match-all specifier @dots{} + +The resulting specifier matches if each @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is false. +@end deffn + +@var{count} @i{(i.e. an integer)} +Convenience short-hand for: @samp{(test-match-nth 1 @var{count})}. + +@var{name} @i{(i.e. a string)} +Convenience short-hand for @samp{(test-match-name @var{name})}. + +@subsubheading Skipping selected tests + +In some cases you may want to skip a test. + +@deffn {Scheme Syntax} test-skip specifier + +Evaluating @code{test-skip} adds the resulting @var{specifier} to the +set of currently active skip-specifiers. Before each test (or +@code{test-group}) the set of active skip-specifiers are applied to the +active test-runner. If any specifier matches, then the test is skipped. + +For convenience, if the @var{specifier} is a string that is syntactic +sugar for @code{(test-match-name @var{specifier})}. For example: + +@lisp +(test-skip "test-b") +(test-assert "test-a") ;; executed +(test-assert "test-b") ;; skipped +@end lisp + +Any skip specifiers introduced by a @code{test-skip} are removed by a +following non-nested @code{test-end}. + +@lisp +(test-begin "group1") +(test-skip "test-a") +(test-assert "test-a") ;; skipped +(test-end "group1") ;; Undoes the prior test-skip +(test-assert "test-a") ;; executed +@end lisp +@end deffn + +@subsubheading Expected failures + +Sometimes you know a test case will fail, but you don't have time to or +can't fix it. Maybe a certain feature only works on certain platforms. +However, you want the test-case to be there to remind you to fix it. +You want to note that such tests are expected to fail. + +@deffn {Scheme Syntax} test-expect-fail specifier + +Matching tests (where matching is defined as in @code{test-skip}) +are expected to fail. This only affects test reporting, +not test execution. For example: + +@lisp +(test-expect-fail 2) +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to pass +@end lisp +@end deffn + +@node SRFI 64 Test-runner +@subsubsection SRFI 64 Test-runner + +A @dfn{test-runner} is an object that runs a test-suite, and manages the +state. The test group path, and the sets skip and expected-fail +specifiers are part of the test-runner. A test-runner will also +typically accumulate statistics about executed tests, + +@deffn {Scheme Procedure} test-runner? value + +True if and only if @var{value} is a test-runner object. +@end deffn + +@deffn {Scheme Parameter} test-runner-current +@deffnx {Scheme Parameter} test-runner-current runner + +Get or set the current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-get + +Same as @code{(test-runner-current)}, but throws an exception if there +is no current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-simple + +Creates a new simple test-runner, that prints errors and a summary on +the standard output port. +@end deffn + +@deffn {Scheme Procedure} test-runner-null + +Creates a new test-runner, that does nothing with the test results. +This is mainly meant for extending when writing a custom runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-create + +Create a new test-runner. Equivalent to @samp{((test-runner-factory))}. +@end deffn + +@deffn {Scheme Parameter} test-runner-factory +@deffnx {Scheme Parameter} test-runner-factory factory + +Get or set the current test-runner factory. A factory is a +zero-argument function that creates a new test-runner. The default +value is @code{test-runner-simple}. +@end deffn + +@subsubheading Running specific tests with a specified runner + +@deffn {Scheme Procedure} test-apply [runner] specifier @dots{} procedure + +Calls @var{procedure} with no arguments using the specified @var{runner} +as the current test-runner. If @var{runner} is omitted, then +@code{(test-runner-current)} is used. (If there is no current runner, +one is created as in @code{test-begin}.) If one or more +@var{specifier}s are listed then only tests matching the +@var{specifier}s are executed. A @var{specifier} has the same form as +one used for @code{test-skip}. A test is executed if it matches any of +the @var{specifier}s in the @code{test-apply} @emph{and} does not match +any active @code{test-skip} specifiers. +@end deffn + +@deffn {Scheme Syntax} test-with-runner runner decl-or-expr @dots{} + +Executes each @var{decl-or-expr} in order in a context where the current +test-runner is @var{runner}. +@end deffn + +@node SRFI 64 Test results +@subsubsection SRFI 64 Test results + +Running a test sets various status properties in the current test-runner. +This can be examined by a custom test-runner, +or (more rarely) in a test-suite. + +@subsubheading Result kind + +Running a test may yield one of the following +status symbols: + +@table @asis +@item @code{'pass} +The test passed, as expected. + +@item @code{'fail} +The test failed (and was not expected to). + +@item @code{'xfail} +The test failed and was expected to. + +@item @code{'xpass} +The test passed, but was expected to fail. + +@item @code{'skip} +The test was skipped. +@end table + +@deffn {Scheme Procedure} test-result-kind [runner] + +Returns one of the above result codes from the most recent tests. +Returns @code{#f} if no tests have been run yet. If we've started on a +new test, but don't have a result yet, then the result kind is +@code{'xfail} if the test is expected to fail, @code{'skip} if the test +is supposed to be skipped, or @code{#f} otherwise. +@end deffn + +@deffn {Scheme Procedure} test-passed? [runner] + +True if the value of @samp{(test-result-kind [@var{runner}])} is one of +@code{'pass} or @code{'xpass}. This is a convenient shorthand that +might be useful in a test suite to only run certain tests if the +previous test passed. +@end deffn + +@subsubheading Test result properties + +A test runner also maintains a set of more detailed +``result@tie{}properties'' associated with the current or most recent +test. (I.e. the properties of the most recent test are available as +long as a new test hasn't started.) Each property has a name (a symbol) +and a value (any value). Some properties are standard or set by the +implementation; implementations can add more. + +@deffn {Scheme Procedure} test-result-ref runner pname [default] + +Returns the property value associated with the @var{pname} property name +(a symbol). If there is no value associated with @var{pname} return +@var{default}, or @code{#f} if @var{default} isn't specified. +@end deffn + +@deffn {Scheme Syntax} test-result-set! runner pname value + +Sets the property value associated with the @var{pname} property name to +@var{value}. Usually implementation code should call this function, but +it may be useful for a custom test-runner to add extra properties. +@end deffn + +@deffn {Scheme Procedure} test-result-remove runner pname + +Remove the property with the name @var{pname}. +@end deffn + +@deffn {Scheme Procedure} test-result-clear runner + +Remove all result properties. The implementation automatically calls +@code{test-result-clear} at the start of a @code{test-assert} and +similar procedures. +@end deffn + +@deffn {Scheme Procedure} test-result-alist runner + +Returns an association list of the current result properties. It is +unspecified if the result shares state with the test-runner. The result +should not be modified; on the other hand, the result may be implicitly +modified by future @code{test-result-set!} or @code{test-result-remove} +calls. However, a @code{test-result-clear} does not modify the returned +alist. Thus you can ``archive'' result objects from previous runs. +@end deffn + +@subsubheading Standard result properties + +The set of available result properties is implementation-specific. +However, it is suggested that the following might be provided: +@table @asis + +@item @code{'result-kind} +The result kind, as defined previously. +This is the only mandatory result property. +@code{(test-result-kind @var{runner})} is equivalent to: +@code{(test-result-ref @var{runner} 'result-kind)} + +@item @code{'source-file} +@itemx @code{'source-line} +If known, the location of test statements (such as @code{test-assert}) +in test suite source code. + +@item @code{'source-form} +The source form, if meaningful and known. + +@item @code{'expected-value} +The expected non-error result, if meaningful and known. + +@item @code{'expected-error} +The @var{error-type}specified in a @code{test-error}, if it meaningful and known. + +@item @code{'actual-value} +The actual non-error result value, if meaningful and known. + +@item @code{'actual-error} +The error value, if an error was signalled and it is known. +The actual error value is implementation-defined. +@end table + +@node SRFI 64 Writing a new test-runner +@subsubsection SRFI 64 Writing a new test-runner + +This section specifies how to write a test-runner. It can be ignored if +you just want to write test-cases. + +@subsubheading Call-back functions + +These call-back functions are ``methods'' (in the object-oriented sense) +of a test-runner. A method @code{test-runner-on-@var{event}} is called +by the implementation when @var{event} happens. + +To define (set) the callback function for @var{event} use the following +expression. (This is normally done when initializing a test-runner.) + +@code{(test-runner-on-@var{event}! @var{runner} @var{event-function})} + +An @var{event-function} takes a test-runner argument, and possibly other +arguments, depending on the @var{event}. + +To extract (get) the callback function for @var{event} do this: +@code{(test-runner-on-@var{event} @var{runner})} + +To extract call the callback function for @var{event} use the following +expression. (This is normally done by the implementation core.) +@samp{((test-runner-on-@var{event} @var{runner}) @var{runner} +@var{other-args} @dots{})}. + +The following call-back hooks are available. + +@deffn {Scheme Procedure} test-runner-on-test-begin runner +@deffnx {Scheme Procedure} test-runner-on-test-begin! runner on-test-begin-function +@deffnx {Scheme Procedure} on-test-begin-function runner + +The @var{on-test-begin-function} is called at the start of an +individual testcase, before the test expression (and expected value) are +evaluated. + +@end deffn + +@deffn {Scheme Procedure} test-runner-on-test-end runner +@deffnx {Scheme Procedure} test-runner-on-test-end! runner on-test-end-function +@deffnx {Scheme Procedure} on-test-end-function runner + +The @var{on-test-end-function} is called at the end of an +individual testcase, when the result of the test is available. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-begin runner +@deffnx {Scheme Procedure} test-runner-on-group-begin! runner on-group-begin-function +@deffnx {Scheme Procedure} on-group-begin-function runner suite-name count + +The @var{on-group-begin-function} is called by a @code{test-begin}, +including at the start of a @code{test-group}. The @var{suite-name} is +a Scheme string, and @var{count} is an integer or @code{#f}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-end runner +@deffnx {Scheme Procedure} test-runner-on-group-end! runner on-group-end-function +@deffnx {Scheme Procedure} on-group-end-function runner + +The @var{on-group-end-function} is called by a @code{test-end}, +including at the end of a @code{test-group}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-count runner +@deffnx {Scheme Procedure} test-runner-on-bad-count! runner on-bad-count-function +@deffnx {Scheme Procedure} on-bad-count-function runner actual-count expected-count + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if an @var{expected-count} was specified by the matching +@code{test-begin} and the @var{expected-count} does not match the +@var{actual-count} of tests actually executed or skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-end-name runner +@deffnx {Scheme Procedure} test-runner-on-bad-end-name! runner on-bad-end-name-function +@deffnx {Scheme Procedure} on-bad-end-name-function runner begin-name end-name + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if a @var{suite-name} was specified, and it did not that the +name in the matching @code{test-begin}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-final runner +@deffnx {Scheme Procedure} test-runner-on-final! runner on-final-function +@deffnx {Scheme Procedure} on-final-function runner + +The @var{on-final-function} takes one parameter (a test-runner) and +typically displays a summary (count) of the tests. The +@var{on-final-function} is called after called the +@var{on-group-end-function} correspondiong to the outermost +@code{test-end}. The default value is @code{test-on-final-simple} which +writes to the standard output port the number of tests of the various +kinds. +@end deffn + +The default test-runner returned by @code{test-runner-simple} uses the +following call-back functions: + +@deffn {Scheme Procedure} test-on-test-begin-simple runner +@deffnx {Scheme Procedure} test-on-test-end-simple runner +@deffnx {Scheme Procedure} test-on-group-begin-simple runner suite-name count +@deffnx {Scheme Procedure} test-on-group-end-simple runner +@deffnx {Scheme Procedure} test-on-bad-count-simple runner actual-count expected-count +@deffnx {Scheme Procedure} test-on-bad-end-name-simple runner begin-name end-name + +You can call those if you want to write your own test-runner. +@end deffn + +@subsubheading Test-runner components + +The following functions are for accessing the other components of a +test-runner. They would normally only be used to write a new +test-runner or a match-predicate. + +@deffn {Scheme Procedure} test-runner-pass-count runner + +Returns the number of tests that passed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-fail-count runner + +Returns the number of tests that failed, but were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-xpass-count runner + +Returns the number of tests that passed, but were expected to fail. +@end deffn + +@deffn {Scheme Procedure} test-runner-xfail-count runner + +Returns the number of tests that failed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-skip-count runner + +Returns the number of tests or test groups that were skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-test-name runner + +Returns the name of the current test or test group, as a string. During +execution of @code{test-begin} this is the name of the test group; +during the execution of an actual test, this is the name of the +test-case. If no name was specified, the name is the empty string. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-path runner + +A list of names of groups we're nested in, with the outermost group +first. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-stack runner + +A list of names of groups we're nested in, with the outermost group +last. (This is more efficient than @code{test-runner-group-path}, since +it doesn't require any copying.) +@end deffn + +@deffn {Scheme Procedure} test-runner-aux-value runner +@deffnx {Scheme Procedure} test-runner-aux-value! runner on-test + +Get or set the @code{aux-value} field of a test-runner. This field is +not used by this API or the @code{test-runner-simple} test-runner, but +may be used by custom test-runners to store extra state. +@end deffn + +@deffn {Scheme Procedure} test-runner-reset runner + +Resets the state of the @var{runner} to its initial state. +@end deffn + +@subsubheading Example + +This is an example of a simple custom test-runner. +Loading this program before running a test-suite will install +it as the default test runner. + +@lisp +(define (my-simple-runner filename) + (let ((runner (test-runner-null)) + (port (open-output-file filename)) + (num-passed 0) + (num-failed 0)) + (test-runner-on-test-end! runner + (lambda (runner) + (case (test-result-kind runner) + ((pass xpass) (set! num-passed (+ num-passed 1))) + ((fail xfail) (set! num-failed (+ num-failed 1))) + (else #t)))) + (test-runner-on-final! runner + (lambda (runner) + (format port "Passing tests: ~d.~%Failing tests: ~d.~%" + num-passed num-failed) + (close-output-port port))) + runner)) +(test-runner-factory + (lambda () (my-simple-runner "/tmp/my-test.log"))) +@end lisp @node SRFI-67 @subsection SRFI-67 - Compare procedures base-commit: 779a83d9c682345802f9a605cb8e2b4892129316 -- 2.41.0 From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. References: <20240601021743.808-1-maxim.cournoyer@gmail.com> In-Reply-To: <20240601021743.808-1-maxim.cournoyer@gmail.com> Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Sun, 15 Sep 2024 04:28:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: 71300@debbugs.gnu.org Cc: Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxime Devos , Maxim Cournoyer Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.172637445627368 (code B ref 71300); Sun, 15 Sep 2024 04:28:02 +0000 Received: (at 71300) by debbugs.gnu.org; 15 Sep 2024 04:27:36 +0000 Received: from localhost ([127.0.0.1]:48126 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1spgrG-00077K-2y for submit@debbugs.gnu.org; Sun, 15 Sep 2024 00:27:36 -0400 Received: from mail-pf1-f173.google.com ([209.85.210.173]:55786) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1spgrB-000771-MT for 71300@debbugs.gnu.org; Sun, 15 Sep 2024 00:27:32 -0400 Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-71957eb256bso69165b3a.3 for <71300@debbugs.gnu.org>; Sat, 14 Sep 2024 21:27:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1726374371; x=1726979171; darn=debbugs.gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=OMOuo7FTOI5OGE8YxzNIT4EjxjborTcYFAPIda/GsAo=; b=eYb1VGWq3e5uwIGF+MO58SEV7R1/i2mn5hetTu2fL+OlcRPs4UUdJ+V3uGafMWduiu SuaIjOpI5NXM+FkRG0/Pzz+CSfMEzXszdW1uM2AcoQb1uQicpjNk8lKoHoAjISHwDcmG 03+WQ7ap0X1wlvOxWj6rVsvU8pycnX2egwIRAJzpaMIMwW3XdGVF5YAVBd1dtv3Bq7R+ pEzD6ua08cY6rdZ44ksVIvIAq7TmiFzjTXdETG7kF5a26EWk7vILFOkK8uWEqNi3tiyd 0TriuWJzv4V307ux6aALTek1nk5WL77G4wtGZvvGiAlGjRpa+9TT0sO9gUanxpbXB+Sy mjkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726374371; x=1726979171; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=OMOuo7FTOI5OGE8YxzNIT4EjxjborTcYFAPIda/GsAo=; b=ejntgfHIp6le7BGmWddqYQA4I47dQnUqdNgAEe3vJC4VeeH1RI6+UULOljhmc6AcW2 gQt9RQJhexZh8xKZ6grgmpIGDOXn9FkLzXvycSFDoWvgebCZRSBy4bi52HqtwhH7JuW7 VqVA6GaSTZZfVt787Nb06SfEzf6BV9mETtt4WxCqrT7XO9Aelu04czq0nkJhj1UrM54I kxAbjgPVRvi0fBltODoUBk0QGKkccO2cCEejD3wzsGPgIX2SY9KTCFEzV3fSAtsKMiMk qpHoNyM3vIDoZrOPp+9+2bluCr5GFcQ1DtcJcu/GZa+JzoEsL4DzURRMROZqFrSW5w74 v1FA== X-Gm-Message-State: AOJu0Yz8N6taG7QA7hpR0tWn8cS16gq8TJFM3ZnwMVgp8QyMTx6C/nBZ YGAYDFXaoMnGtz1w64Duovu6Ty1FfCnSSov7kasjNZWsgr9nGxpcQn+9C/E5 X-Google-Smtp-Source: AGHT+IEESZi69dkM9dFIqBh0W6Rj4lEtsaM0OTkv44olHF+9Z6w55HTKerRGjy5qKXUCtE+XD1BXUw== X-Received: by 2002:a05:6a00:3ccf:b0:717:849a:d668 with SMTP id d2e1a72fcca58-71936a4bef6mr12642441b3a.10.1726374370391; Sat, 14 Sep 2024 21:26:10 -0700 (PDT) Received: from hurd.lan ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-71944abaa98sm1650285b3a.68.2024.09.14.21.26.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 14 Sep 2024 21:26:09 -0700 (PDT) From: Maxim Cournoyer Date: Sun, 15 Sep 2024 13:25:46 +0900 Message-ID: <20240915042603.8529-1-maxim.cournoyer@gmail.com> X-Mailer: git-send-email 2.46.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) This is an import of the 'Abstract', 'Rationale', and 'Specification' sections from the upstream specification text, with some manual adjustment. * doc/ref/srfi-modules.texi (SRFI 64): New subsection. --- Changes in v4: - Rebased Changes in v3: - Add copyright / license information - Replace SchemeUnit mentions with RackUnit Changes in v2: - Fix the category of many definitions doc/ref/guile.texi | 25 +- doc/ref/srfi-modules.texi | 830 +++++++++++++++++++++++++++++++++++++- 2 files changed, 847 insertions(+), 8 deletions(-) diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index bde9f6f75..988d30155 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -24,8 +24,31 @@ any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' -@end copying +Additionally, the documentation of the SRFI 64 module is adapted from +its specification text, which is made available under the following +Expat license: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@end copying @c Notes @c diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index 02da3e2f2..4d408d6cb 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -1,7 +1,8 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018, 2019, 2020 +@c Copyright (C) 1996-1997, 2000-2004, 2006-2014, 2017-2020, 2023 @c Free Software Foundation, Inc. +@c Copyright (C) 2005-2006 Per Bothner @c See the file guile.texi for copying conditions. @node SRFI Support @@ -55,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page * 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 64:: A Scheme API for test suites. * SRFI-67:: Compare procedures * SRFI-69:: Basic hash tables. * SRFI-71:: Extended let-syntax for multiple values. @@ -5290,12 +5291,827 @@ 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 +@c This SRFI 64 documentation was "snarfed" from upstream specification +@c HTML document using the 'snarfi' script. +@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}. +@menu +* SRFI 64 Abstract:: +* SRFI 64 Rationale:: +* SRFI 64 Writing basic test suites:: +* SRFI 64 Conditonal test-suites and other advanced features:: +* SRFI 64 Test-runner:: +* SRFI 64 Test results:: +* SRFI 64 Writing a new test-runner:: +@end menu + +@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. + +@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. + +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. + +This proposal allows converting a Scheme source file to a +test suite by just adding a few macros. You don't have to +write the entire file in a new form, thus you don't have to +re-indent it. + +All names defined by the API start with the prefix @samp{test-}. All +function-like forms are defined as syntax. They may be implemented as +functions or macros or built-ins. The reason for specifying them as +syntax is to allow specific tests to be skipped without evaluating +sub-expressions, or for implementations to add features such as printing +line numbers or catching exceptions. + +@node SRFI 64 Writing basic test suites +@subsubsection SRFI 64 Writing basic test suites + +Let's start with a simple example. This is a complete self-contained +test-suite. + +@lisp +;; Initialize and give a name to a simple testsuite. +(test-begin "vec-test") +(define v (make-vector 5 99)) +;; Require that an expression evaluate to true. +(test-assert (vector? v)) +;; Test that an expression is eqv? to some other expression. +(test-eqv 99 (vector-ref v 2)) +(vector-set! v 2 7) +(test-eqv 7 (vector-ref v 2)) +;; Finish the testsuite, and report results. +(test-end "vec-test") +@end lisp + +This testsuite could be saved in its own source file. Nothing else is +needed: We do not require any top-level forms, so it is easy to wrap an +existing program or test to this form, without adding indentation. It +is also easy to add new tests, without having to name individual tests +(though that is optional). + +Test cases are executed in the context of a @dfn{test runner}, which is +a object that accumulates and reports test results. This specification +defines how to create and use custom test runners, but implementations +should also provide a default test runner. It is suggested (but not +required) that loading the above file in a top-level environment will +cause the tests to be executed using an implementation-specified default +test runner, and @code{test-end} will cause a summary to be displayed in +an implementation-specified manner. + +@subsubheading Simple test-cases + +Primitive test cases test that a given condition is true. They may have +a name. The core test case form is @code{test-assert}: + +@deffn {Scheme Syntax} test-assert [test-name] expression + +This evaluates the @var{expression}. The test passes if the result is +true; if the result is false, a test failure is reported. The test also +fails if an exception is raised, assuming the implementation has a way +to catch exceptions. How the failure is reported depends on the test +runner environment. The @var{test-name} is a string that names the test +case. (Though the @var{test-name} is a string literal in the examples, +it is an expression. It is evaluated only once.) It is used when +reporting errors, and also when skipping tests, as described below. It +is an error to invoke @code{test-assert}if there is no current test +runner. +@end deffn + +The following forms may be more convenient than using @code{test-assert} +directly: + +@deffn {Scheme Syntax} test-eqv [test-name] expected test-expr + +This is equivalent to: + +@lisp +(test-assert [@var{test-name}] (eqv? @var{expected} @var{test-expr})) +@end lisp + +@end deffn + +Similarly @code{test-equal} and @code{test-eq} are shorthand for +@code{test-assert} combined with @code{equal?} or @code{eq?}, +respectively: + +@deffn {Scheme Syntax} test-equal [test-name] expected test-expr +@deffnx {Scheme Syntax} test-eq [test-name] expected test-expr + +Here is a simple example: + +@lisp +(define (mean x y) (/ (+ x y) 2.0)) +(test-eqv 4 (mean 3 5)) +@end lisp +@end deffn + +For testing approximate equality of inexact reals +we can use @code{test-approximate}: + +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr error + +This is equivalent to (except that each argument is only evaluated +once): + +@lisp +(test-assert [test-name] + (and (>= test-expr (- expected error)) + (<= test-expr (+ expected error)))) +@end lisp +@end deffn + +@subsubheading Tests for catching errors + +We need a way to specify that evaluation @emph{should} fail. This +verifies that errors are detected when required. + +@deffn {Scheme Syntax} test-error [[test-name] error-type] test-expr + +Evaluating @var{test-expr} is expected to signal an error. The kind of +error is indicated by @var{error-type}. + +If the @var{error-type} is left out, or it is @code{#t}, it means "some +kind of unspecified error should be signaled". For example: + +@lisp +(test-error #t (vector-ref '#(1 2) 9)) +@end lisp + +This specification leaves it implementation-defined (or for a future +specification) what form @var{test-error} may take, though all +implementations must allow @code{#t}. Some implementations may support +@url{https://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35's +conditions}, but these are only standardized for +@url{https://srfi.schemers.org/srfi-36/srfi-36.html, SRFI-36's I/O +conditions}, which are seldom useful in test suites. An implementation +may also allow implementation-specific ``exception types''. For example +Java-based implementations may allow the names of Java exception +classes: + +@lisp +;; Kawa-specific example +(test-error (vector-ref '#(1 2) 9)) +@end lisp + +An implementation that cannot catch exceptions should skip +@code{test-error} forms. +@end deffn + +@subsubheading Testing syntax + +Testing syntax is tricky, especially if we want to check that invalid +syntax is causing an error. The following utility function can help: + +@deffn {Scheme Procedure} test-read-eval-string string + +This function parses @var{string} (using @code{read}) and evaluates the +result. The result of evaluation is returned from +@code{test-read-eval-string}. An error is signalled if there are unread +characters after the @code{read} is done. For example: +@code{(test-read-eval-string "(+ 3 4)")} @i{evaluates to} @code{7}. +@code{(test-read-eval-string "(+ 3 4")} @i{signals an error}. +@code{(test-read-eval-string "(+ 3 4) ")} @i{signals an error}, because +there is extra ``junk'' (@i{i.e.} a space) after the list is read. + +The @code{test-read-eval-string} used in tests: + +@lisp +(test-equal 7 (test-read-eval-string "(+ 3 4)")) +(test-error (test-read-eval-string "(+ 3")) +(test-equal #\newline (test-read-eval-string "#\\newline")) +(test-error (test-read-eval-string "#\\newlin")) +;; Skip the next 2 tests unless srfi-62 is available. +(test-skip (cond-expand (srfi-62 0) (else 2))) +(test-equal 5 (test-read-eval-string "(+ 1 #;(* 2 3) 4)")) +(test-equal '(x z) (test-read-string "(list 'x #;'y 'z)")) +@end lisp +@end deffn + +@subsubheading Test groups and paths + +A @dfn{test group} is a named sequence of forms containing testcases, +expressions, and definitions. Entering a group sets the @dfn{test group +name}; leaving a group restores the previous group name. These are +dynamic (run-time) operations, and a group has no other effect or +identity. Test groups are informal groupings: they are neither Scheme +values, nor are they syntactic forms. +@c (More formal test suite values are introduced below.) +A test group may contain nested inner test groups. +The @dfn{test group path} is a list of the currently-active +(entered) test group names, oldest (outermost) first. + +@deffn {Scheme Syntax} test-begin suite-name [count] + +A @code{test-begin} enters a new test group. The @var{suite-name} +becomes the current test group name, and is added to the end of the test +group path. Portable test suites should use a string literal for +@var{suite-name}; the effect of expressions or other kinds of literals +is unspecified. + +@emph{Rationale:} In some ways using symbols would be preferable. +However, we want human-readable names, and standard Scheme does not +provide a way to include spaces or mixed-case text in literal symbols. + +The optional @var{count} must match the number of test-cases executed by +this group. (Nested test groups count as a single test case for this +count.) This extra test may be useful to catch cases where a test +doesn't get executed because of some unexpected error. + +Additionally, if there is no currently executing test runner, +one is installed in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-end [suite-name] + +A @code{test-end} leaves the current test group. +An error is reported if the @var{suite-name} does not +match the current test group name. +@c If it does match an earlier name in the test group path, intervening +@c groups are left. + +Additionally, if the matching @code{test-begin}installed a new +test-runner, then the @code{test-end} will uninstall it, after reporting +the accumulated test results in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-group suite-name decl-or-expr @dots{} + +Equivalent to: + +@lisp +(if (not (test-to-skip% (var suite-name))) + (dynamic-wind + (lambda () (test-begin (var suite-name))) + (lambda () (var decl-or-expr) ...) + (lambda () (test-end (var suite-name))))) +@end lisp + +This is usually equivalent to executing the @var{decl-or-expr}s +within the named test group. However, the entire group is skipped +if it matched an active @code{test-skip} (see later). +Also, the @code{test-end} is executed in case of an exception. +@end deffn + +@subsubheading Handling set-up and cleanup + +@deffn {Scheme Syntax} test-group-with-cleanup suite-name decl-or-expr @dots{} cleanup-form + +Execute each of the @var{decl-or-expr} forms in order (as in a +@var{}), and then execute the @var{cleanup-form}. The latter +should be executed even if one of a @var{decl-or-expr} forms raises an +exception (assuming the implementation has a way to catch exceptions). + +For example: + +@lisp +(let ((f (open-output-file "log"))) + (test-group-with-cleanup "test-file" + (do-a-bunch-of-tests f) + (close-output-port f))) +@end lisp +@end deffn + +@node SRFI 64 Conditonal test-suites and other advanced features +@subsubsection SRFI 64 Conditonal test-suites and other advanced features + +The following describes features for controlling which tests to execute, +or specifying that some tests are @emph{expected} to fail. + +@subsubheading Test specifiers + +Sometimes we want to only run certain tests, or we know that certain +tests are expected to fail. A @dfn{test specifier} is one-argument +function that takes a test-runner and returns a boolean. The specifier +may be run before a test is performed, and the result may control +whether the test is executed. For convenience, a specifier may also be +a non-procedure value, which is coerced to a specifier procedure, as +described below for @var{count} and @var{name}. + +A simple example is: + +@lisp +(if (var some-condition) (test-skip 2)) ;; skip next 2 tests +@end lisp + +@deffn {Scheme Procedure} test-match-name name + +The resulting specifier matches if the current test name (as returned by +@code{test-runner-test-name}) is @code{equal?} to @var{name}. +@end deffn + +@deffn {Scheme Syntax} test-match-nth n [count] + +This evaluates to a @emph{stateful} predicate: A counter keeps track of +how many times it has been called. The predicate matches the @var{n}'th +time it is called (where @code{1} is the first time), and the next +@samp{(- @var{count} 1)} times, where @var{count} defaults to @code{1}. +@end deffn + +@deffn {Scheme Syntax} test-match-any specifier @dots{} + +The resulting specifier matches if any @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is true. +@end deffn + +@deffn {Scheme Syntax} test-match-all specifier @dots{} + +The resulting specifier matches if each @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is false. +@end deffn + +@var{count} @i{(i.e. an integer)} +Convenience short-hand for: @samp{(test-match-nth 1 @var{count})}. + +@var{name} @i{(i.e. a string)} +Convenience short-hand for @samp{(test-match-name @var{name})}. + +@subsubheading Skipping selected tests + +In some cases you may want to skip a test. + +@deffn {Scheme Syntax} test-skip specifier + +Evaluating @code{test-skip} adds the resulting @var{specifier} to the +set of currently active skip-specifiers. Before each test (or +@code{test-group}) the set of active skip-specifiers are applied to the +active test-runner. If any specifier matches, then the test is skipped. + +For convenience, if the @var{specifier} is a string that is syntactic +sugar for @code{(test-match-name @var{specifier})}. For example: + +@lisp +(test-skip "test-b") +(test-assert "test-a") ;; executed +(test-assert "test-b") ;; skipped +@end lisp + +Any skip specifiers introduced by a @code{test-skip} are removed by a +following non-nested @code{test-end}. + +@lisp +(test-begin "group1") +(test-skip "test-a") +(test-assert "test-a") ;; skipped +(test-end "group1") ;; Undoes the prior test-skip +(test-assert "test-a") ;; executed +@end lisp +@end deffn + +@subsubheading Expected failures + +Sometimes you know a test case will fail, but you don't have time to or +can't fix it. Maybe a certain feature only works on certain platforms. +However, you want the test-case to be there to remind you to fix it. +You want to note that such tests are expected to fail. + +@deffn {Scheme Syntax} test-expect-fail specifier + +Matching tests (where matching is defined as in @code{test-skip}) +are expected to fail. This only affects test reporting, +not test execution. For example: + +@lisp +(test-expect-fail 2) +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to pass +@end lisp +@end deffn + +@node SRFI 64 Test-runner +@subsubsection SRFI 64 Test-runner + +A @dfn{test-runner} is an object that runs a test-suite, and manages the +state. The test group path, and the sets skip and expected-fail +specifiers are part of the test-runner. A test-runner will also +typically accumulate statistics about executed tests, + +@deffn {Scheme Procedure} test-runner? value + +True if and only if @var{value} is a test-runner object. +@end deffn + +@deffn {Scheme Parameter} test-runner-current +@deffnx {Scheme Parameter} test-runner-current runner + +Get or set the current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-get + +Same as @code{(test-runner-current)}, but throws an exception if there +is no current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-simple + +Creates a new simple test-runner, that prints errors and a summary on +the standard output port. +@end deffn + +@deffn {Scheme Procedure} test-runner-null + +Creates a new test-runner, that does nothing with the test results. +This is mainly meant for extending when writing a custom runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-create + +Create a new test-runner. Equivalent to @samp{((test-runner-factory))}. +@end deffn + +@deffn {Scheme Parameter} test-runner-factory +@deffnx {Scheme Parameter} test-runner-factory factory + +Get or set the current test-runner factory. A factory is a +zero-argument function that creates a new test-runner. The default +value is @code{test-runner-simple}. +@end deffn + +@subsubheading Running specific tests with a specified runner + +@deffn {Scheme Procedure} test-apply [runner] specifier @dots{} procedure + +Calls @var{procedure} with no arguments using the specified @var{runner} +as the current test-runner. If @var{runner} is omitted, then +@code{(test-runner-current)} is used. (If there is no current runner, +one is created as in @code{test-begin}.) If one or more +@var{specifier}s are listed then only tests matching the +@var{specifier}s are executed. A @var{specifier} has the same form as +one used for @code{test-skip}. A test is executed if it matches any of +the @var{specifier}s in the @code{test-apply} @emph{and} does not match +any active @code{test-skip} specifiers. +@end deffn + +@deffn {Scheme Syntax} test-with-runner runner decl-or-expr @dots{} + +Executes each @var{decl-or-expr} in order in a context where the current +test-runner is @var{runner}. +@end deffn + +@node SRFI 64 Test results +@subsubsection SRFI 64 Test results + +Running a test sets various status properties in the current test-runner. +This can be examined by a custom test-runner, +or (more rarely) in a test-suite. + +@subsubheading Result kind + +Running a test may yield one of the following +status symbols: + +@table @asis +@item @code{'pass} +The test passed, as expected. + +@item @code{'fail} +The test failed (and was not expected to). + +@item @code{'xfail} +The test failed and was expected to. + +@item @code{'xpass} +The test passed, but was expected to fail. + +@item @code{'skip} +The test was skipped. +@end table + +@deffn {Scheme Procedure} test-result-kind [runner] + +Returns one of the above result codes from the most recent tests. +Returns @code{#f} if no tests have been run yet. If we've started on a +new test, but don't have a result yet, then the result kind is +@code{'xfail} if the test is expected to fail, @code{'skip} if the test +is supposed to be skipped, or @code{#f} otherwise. +@end deffn + +@deffn {Scheme Procedure} test-passed? [runner] + +True if the value of @samp{(test-result-kind [@var{runner}])} is one of +@code{'pass} or @code{'xpass}. This is a convenient shorthand that +might be useful in a test suite to only run certain tests if the +previous test passed. +@end deffn + +@subsubheading Test result properties + +A test runner also maintains a set of more detailed +``result@tie{}properties'' associated with the current or most recent +test. (I.e. the properties of the most recent test are available as +long as a new test hasn't started.) Each property has a name (a symbol) +and a value (any value). Some properties are standard or set by the +implementation; implementations can add more. + +@deffn {Scheme Procedure} test-result-ref runner pname [default] + +Returns the property value associated with the @var{pname} property name +(a symbol). If there is no value associated with @var{pname} return +@var{default}, or @code{#f} if @var{default} isn't specified. +@end deffn + +@deffn {Scheme Syntax} test-result-set! runner pname value + +Sets the property value associated with the @var{pname} property name to +@var{value}. Usually implementation code should call this function, but +it may be useful for a custom test-runner to add extra properties. +@end deffn + +@deffn {Scheme Procedure} test-result-remove runner pname + +Remove the property with the name @var{pname}. +@end deffn + +@deffn {Scheme Procedure} test-result-clear runner + +Remove all result properties. The implementation automatically calls +@code{test-result-clear} at the start of a @code{test-assert} and +similar procedures. +@end deffn + +@deffn {Scheme Procedure} test-result-alist runner + +Returns an association list of the current result properties. It is +unspecified if the result shares state with the test-runner. The result +should not be modified; on the other hand, the result may be implicitly +modified by future @code{test-result-set!} or @code{test-result-remove} +calls. However, a @code{test-result-clear} does not modify the returned +alist. Thus you can ``archive'' result objects from previous runs. +@end deffn + +@subsubheading Standard result properties + +The set of available result properties is implementation-specific. +However, it is suggested that the following might be provided: +@table @asis + +@item @code{'result-kind} +The result kind, as defined previously. +This is the only mandatory result property. +@code{(test-result-kind @var{runner})} is equivalent to: +@code{(test-result-ref @var{runner} 'result-kind)} + +@item @code{'source-file} +@itemx @code{'source-line} +If known, the location of test statements (such as @code{test-assert}) +in test suite source code. + +@item @code{'source-form} +The source form, if meaningful and known. + +@item @code{'expected-value} +The expected non-error result, if meaningful and known. + +@item @code{'expected-error} +The @var{error-type}specified in a @code{test-error}, if it meaningful and known. + +@item @code{'actual-value} +The actual non-error result value, if meaningful and known. + +@item @code{'actual-error} +The error value, if an error was signalled and it is known. +The actual error value is implementation-defined. +@end table + +@node SRFI 64 Writing a new test-runner +@subsubsection SRFI 64 Writing a new test-runner + +This section specifies how to write a test-runner. It can be ignored if +you just want to write test-cases. + +@subsubheading Call-back functions + +These call-back functions are ``methods'' (in the object-oriented sense) +of a test-runner. A method @code{test-runner-on-@var{event}} is called +by the implementation when @var{event} happens. + +To define (set) the callback function for @var{event} use the following +expression. (This is normally done when initializing a test-runner.) + +@code{(test-runner-on-@var{event}! @var{runner} @var{event-function})} + +An @var{event-function} takes a test-runner argument, and possibly other +arguments, depending on the @var{event}. + +To extract (get) the callback function for @var{event} do this: +@code{(test-runner-on-@var{event} @var{runner})} + +To extract call the callback function for @var{event} use the following +expression. (This is normally done by the implementation core.) +@samp{((test-runner-on-@var{event} @var{runner}) @var{runner} +@var{other-args} @dots{})}. + +The following call-back hooks are available. + +@deffn {Scheme Procedure} test-runner-on-test-begin runner +@deffnx {Scheme Procedure} test-runner-on-test-begin! runner on-test-begin-function +@deffnx {Scheme Procedure} on-test-begin-function runner + +The @var{on-test-begin-function} is called at the start of an +individual testcase, before the test expression (and expected value) are +evaluated. + +@end deffn + +@deffn {Scheme Procedure} test-runner-on-test-end runner +@deffnx {Scheme Procedure} test-runner-on-test-end! runner on-test-end-function +@deffnx {Scheme Procedure} on-test-end-function runner + +The @var{on-test-end-function} is called at the end of an +individual testcase, when the result of the test is available. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-begin runner +@deffnx {Scheme Procedure} test-runner-on-group-begin! runner on-group-begin-function +@deffnx {Scheme Procedure} on-group-begin-function runner suite-name count + +The @var{on-group-begin-function} is called by a @code{test-begin}, +including at the start of a @code{test-group}. The @var{suite-name} is +a Scheme string, and @var{count} is an integer or @code{#f}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-end runner +@deffnx {Scheme Procedure} test-runner-on-group-end! runner on-group-end-function +@deffnx {Scheme Procedure} on-group-end-function runner + +The @var{on-group-end-function} is called by a @code{test-end}, +including at the end of a @code{test-group}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-count runner +@deffnx {Scheme Procedure} test-runner-on-bad-count! runner on-bad-count-function +@deffnx {Scheme Procedure} on-bad-count-function runner actual-count expected-count + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if an @var{expected-count} was specified by the matching +@code{test-begin} and the @var{expected-count} does not match the +@var{actual-count} of tests actually executed or skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-end-name runner +@deffnx {Scheme Procedure} test-runner-on-bad-end-name! runner on-bad-end-name-function +@deffnx {Scheme Procedure} on-bad-end-name-function runner begin-name end-name + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if a @var{suite-name} was specified, and it did not that the +name in the matching @code{test-begin}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-final runner +@deffnx {Scheme Procedure} test-runner-on-final! runner on-final-function +@deffnx {Scheme Procedure} on-final-function runner + +The @var{on-final-function} takes one parameter (a test-runner) and +typically displays a summary (count) of the tests. The +@var{on-final-function} is called after called the +@var{on-group-end-function} correspondiong to the outermost +@code{test-end}. The default value is @code{test-on-final-simple} which +writes to the standard output port the number of tests of the various +kinds. +@end deffn + +The default test-runner returned by @code{test-runner-simple} uses the +following call-back functions: + +@deffn {Scheme Procedure} test-on-test-begin-simple runner +@deffnx {Scheme Procedure} test-on-test-end-simple runner +@deffnx {Scheme Procedure} test-on-group-begin-simple runner suite-name count +@deffnx {Scheme Procedure} test-on-group-end-simple runner +@deffnx {Scheme Procedure} test-on-bad-count-simple runner actual-count expected-count +@deffnx {Scheme Procedure} test-on-bad-end-name-simple runner begin-name end-name + +You can call those if you want to write your own test-runner. +@end deffn + +@subsubheading Test-runner components + +The following functions are for accessing the other components of a +test-runner. They would normally only be used to write a new +test-runner or a match-predicate. + +@deffn {Scheme Procedure} test-runner-pass-count runner + +Returns the number of tests that passed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-fail-count runner + +Returns the number of tests that failed, but were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-xpass-count runner + +Returns the number of tests that passed, but were expected to fail. +@end deffn + +@deffn {Scheme Procedure} test-runner-xfail-count runner + +Returns the number of tests that failed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-skip-count runner + +Returns the number of tests or test groups that were skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-test-name runner + +Returns the name of the current test or test group, as a string. During +execution of @code{test-begin} this is the name of the test group; +during the execution of an actual test, this is the name of the +test-case. If no name was specified, the name is the empty string. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-path runner + +A list of names of groups we're nested in, with the outermost group +first. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-stack runner + +A list of names of groups we're nested in, with the outermost group +last. (This is more efficient than @code{test-runner-group-path}, since +it doesn't require any copying.) +@end deffn + +@deffn {Scheme Procedure} test-runner-aux-value runner +@deffnx {Scheme Procedure} test-runner-aux-value! runner on-test + +Get or set the @code{aux-value} field of a test-runner. This field is +not used by this API or the @code{test-runner-simple} test-runner, but +may be used by custom test-runners to store extra state. +@end deffn + +@deffn {Scheme Procedure} test-runner-reset runner + +Resets the state of the @var{runner} to its initial state. +@end deffn + +@subsubheading Example + +This is an example of a simple custom test-runner. +Loading this program before running a test-suite will install +it as the default test runner. + +@lisp +(define (my-simple-runner filename) + (let ((runner (test-runner-null)) + (port (open-output-file filename)) + (num-passed 0) + (num-failed 0)) + (test-runner-on-test-end! runner + (lambda (runner) + (case (test-result-kind runner) + ((pass xpass) (set! num-passed (+ num-passed 1))) + ((fail xfail) (set! num-failed (+ num-failed 1))) + (else #t)))) + (test-runner-on-final! runner + (lambda (runner) + (format port "Passing tests: ~d.~%Failing tests: ~d.~%" + num-passed num-failed) + (close-output-port port))) + runner)) +(test-runner-factory + (lambda () (my-simple-runner "/tmp/my-test.log"))) +@end lisp @node SRFI-67 @subsection SRFI-67 - Compare procedures base-commit: d0790d766bedf08fb65231eff53f6c8044eb94f1 -- 2.46.0 From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v3] doc: Document SRFI 64. Resent-From: "Dr. Arne Babenhauserheide" Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Sun, 22 Sep 2024 10:16:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxim Cournoyer , 71300@debbugs.gnu.org Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.17270001051360 (code B ref 71300); Sun, 22 Sep 2024 10:16:01 +0000 Received: (at 71300) by debbugs.gnu.org; 22 Sep 2024 10:15:05 +0000 Received: from localhost ([127.0.0.1]:40899 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ssJcO-0000Lr-I3 for submit@debbugs.gnu.org; Sun, 22 Sep 2024 06:15:05 -0400 Received: from mout.web.de ([212.227.17.11]:34489) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ssJcL-0000L5-Mj for 71300@debbugs.gnu.org; Sun, 22 Sep 2024 06:15:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=web.de; s=s29768273; t=1727000072; x=1727604872; i=arne_bab@web.de; bh=oGlHEDeydstRa8GN1c9om32oPdQCGOs7zQ181sTR0oI=; h=X-UI-Sender-Class:From:To:Subject:In-Reply-To:References:Date: Message-ID:MIME-Version:Content-Type:cc:content-transfer-encoding: content-type:date:from:message-id:mime-version:reply-to:subject: to; b=oya/yRvEIz+nKF/ZkInlg2fp9cE3vqO0n7xNWbVWS3V7KBadqsA4lX/3MiwXvuZm fbQhv1gHhcbQ120Q1QMzgra24rlOQRJMP/XB37a+0LLrrmCTGViKxd2Z2fs6RzFQh Hy6IQNvHAtElwYwX/NqvPLFk//nD7WYGst2lEHQgTe2kqqxdl+UxQF6ZkqspoKqRr fUi7i1FR3bZdruxrAb0Yuw+9LbaQKGher2k3I57C2h8AC9PjU2cwlE4Z9EdOcj16o nieDGdS1Bt3wDPxuKN1dLlgogTmww6DCsjELa+MCipWPb9OsTMHiwU+nx38I5Zm5c PpFE5I9BA+hbPwuRFA== X-UI-Sender-Class: 814a7b36-bfc1-4dae-8640-3722d8ec6cd6 Received: from fluss ([84.165.28.123]) by smtp.web.de (mrweb105 [213.165.67.124]) with ESMTPSA (Nemesis) id 1MrwwJ-1sDBa11wFp-00nGfl; Sun, 22 Sep 2024 12:14:32 +0200 From: "Dr. Arne Babenhauserheide" In-Reply-To: <20240915042603.8529-1-maxim.cournoyer@gmail.com> (Maxim Cournoyer's message of "Sun, 15 Sep 2024 13:25:46 +0900") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> Date: Sun, 22 Sep 2024 12:14:28 +0200 Message-ID: <87frps2dx7.fsf_-_@web.de> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" X-Provags-ID: V03:K1:+1wp9Z8ctJ7IRsp98J8CEd4/jVeNTEh1+rmoUoO0vgMOCS0+zCJ n5fbMXv6I4xaaNL0UgWamJaiObPK51lz1NvutpwY77u+4XzkPsOlQ0+38udd5JcT4Wrn3vK Y6EJ9Qv/npcaDVrvV+kbkdydqdAj7JtIjEdqFkbNjDYuyNxtQi00egh9ELjCPfeOPbPY9xt KgIxxCzNdvLFg5l0Qv3cQ== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:YVwxEmC4h9k=;Wwr0MErsfnecFD36HKIt+14vrvT ziQjtnpnYNZQwilDpZWITH1GHQ1N51BhRdU2wW8Au5ypGP1h6YqJX7mDrw99C8xQcuaGxm73n R0eKQjqQ/4HkATiYfawvnabqCPWr+gk4pXuxo7fDAyUteXzsxjJSG9XFNaYCivkaDc7pZGoxe 7iwTj+wY4A+bPMvb+BoVVrJ6vkFM94PicAFIG0fQ3Eg/ppjOMlb3ntaNE4u9zu3pjLh0jSKlS IhM6Hzep9MGAg2tMxgCH1R702WAlry1NPmDgjrStT5WQu+IA7r3Sg2hYaayziDw8//zSRvU5x xG44QsAtVk+RcfvYitBh6mG/paeiZrcz0SbMJ4ZluXmMdcs03S8ichkYzuWLNp+YOUnI9FWyq towgoMFfmhiiAjAjurI69Cg9KLlVl2nQEBiPFi0dHOk2WvwTZbneuitoqqYWhjW60cWkwfaVf ZpfDxj6fur2TlEDumnRaTAis890ZzKkLbN9sZRWTAzibcPVbBbwpPjbMsozNpKRnppDhVcBbh gBsYRRdiikstW+XhMCkf208LkxCCmYCvp+ya8fIaW2ZIYlx8iysFHsmrFnYLz3mIeHBW93spQ TD+H57XY3q+pjuuGIgJ/OjHP6kj8SJmRfU9o1cXu4nfbHXuI+KcmCaCgSe2jnUccFsMSkJh5e d3sXPW0Zahe4QlNvu1PQliVPsDZU42Xet4qGQ+RuaQesANMpCbWAiVoNQxvXW0JRFtjAHFSmT Sck4rd0B8jPPK8K7p6nsNgNY0Itza6F+crT14ZqowE4cM31jRF2OJL5LRPpsFP3zmOSLTm5wV IRVJLJreabEB6JmKHee+/8qw== X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Maxim Cournoyer writes: > diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi > index 02da3e2f2..4d408d6cb 100644 > --- a/doc/ref/srfi-modules.texi > +++ b/doc/ref/srfi-modules.texi > @@ -55,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page > * 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 64:: A Scheme API for test suites. If you change this for one, please harmonize the others (with or without =2D). Consistency wins here. > @@ -5290,12 +5291,827 @@ needed to get SRFI-61 itself. Extended @code{co= nd} is documented in =E2=80=A6 > +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. Is this relevant for Guile? If not, I=E2=80=99d take the racket specific part out. > +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 sub-sentence ("but I hope...") isn=E2=80=99t needed here, I think. > +Test cases are executed in the context of a @dfn{test runner}, which is > +a object that accumulates and reports test results. This > specification Typo: a object -> an object (this might also be a good change/PR for srfi 64 itself =E2=87=92 upstream) > +defines how to create and use custom test runners, but implementations > +should also provide a default test runner. It is suggested (but not Does Guile provide a default test runner? =E2=87=92 that may be good to note instead of "should also". > +required) that loading the above file in a top-level environment will > +cause the tests to be executed using an implementation-specified default > +test runner, and @code{test-end} will cause a summary to be displayed in > +an implementation-specified manner. =E2=80=A6 > +For testing approximate equality of inexact reals > +we can use @code{test-approximate}: > + > +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr e= rror > + > +This is equivalent to (except that each argument is only evaluated > +once): > + > +@lisp > +(test-assert [test-name] > + (and (>=3D test-expr (- expected error)) > + (<=3D test-expr (+ expected error)))) > +@end lisp > +@end deffn It would be nice to have an explicit example here. > +@lisp > +(test-error #t (vector-ref '#(1 2) 9)) > +@end lisp > + > +This specification leaves it implementation-defined (or for a future > +specification) what form @var{test-error} may take, though all > +implementations must allow @code{#t}. It would be good to show what Guile accepts instead. =E2=80=A6 > +@lisp > +;; Kawa-specific example > +(test-error (vector-ref '#(1 2) 9)) > +@end lisp An example with Guile would be good. > +@subsubheading Test specifiers > + > +Sometimes we want to only run certain tests, or we know that certain > +tests are expected to fail. A @dfn{test specifier} is one-argument > +function that takes a test-runner and returns a boolean. The > specifier is *a* one-argument function (also for upstream) Aside from these, this patch looks good to me.=20 Thank you! Can you send one more iteration of the patch? Best wishes, Arne =2D-=20 Unpolitisch sein hei=C3=9Ft politisch sein, ohne es zu merken. draketo.de --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJEBAEBCAAuFiEE801qEjXQSQPNItXAE++NRSQDw+sFAmbv7gUQHGFybmVfYmFi QHdlYi5kZQAKCRAT741FJAPD6zs8EADP750p+nHmfdt+r7EPu2ZsX2LMm5BJm65b 3Coqe29M92Ke73pzl8P7xgbG9eBryxNf4Wd7/r3hSmb5vPwWI1HnpRpnzm0626al rlVzOKd7++XS6GUa9klIWDwvaUa5EdwQoc3xFEyRIgAlyU/9uCZ04oHzQoSC+a0e 3GMlvLLz5Ic+3m97kTpI/Atb0ITha0KVUHySWkBhT1LnUeKq29ZK5rX1W299joFh jBZG4yvtKgceXtnB4ZMIxHA3R+PYVG1VE9KVU93CpAJzCtbd2+lmzf00ixTXMJ/g fTxw42j+yHMRszeN+DvpS/9rmHDkBOdRFjYlLO72vGw1SgLobPhZlUCSKNerXlry IPZy4BBer3fIFT/e7+i16TIVIgEAPwvXCHjp/pXxLelxAaNiZUEkr6yEZmtzO6UD caCYVSlGwTOK54gKw7O7CBB7zK5TUTPEtNDIZJlgygt3rDYc3UfeqFP7je9B9MLS K2K8mbx02+mstmnnhG1XP6oO7VxSOc5O6JBifhEvvnpYVUCAZma4Lr14nCJsOdSi geJRf+5cHU4QBeS9LF9Ib0/kdr+24hYWT4TgsYFMahd6jTVlW1OyulX9K0nPFVtN RV9yWk6vNXKAT6E4c2MMLr1A/eSFB7x5sj06vZgxxQdlJ/Abez9vB486loTEPaxU Jic5NbxwtIjEBAEBCAAuFiEE3Si95tmHXKvOSosd3M8NswvBBUgFAmbv7gcQHGFy bmVfYmFiQHdlYi5kZQAKCRDczw2zC8EFSBQBBACdQL19msAHsYh/HNcHW2jFW9Mo aINWYZsw7mdir5n8CKrxLoyM9OlA4mhRi8WqrE/L3HIPq4gGcc7ITiKZ1V7woMYy KIZWwVq65r0fsIhHhgV06Zjef4v7kMQBH9Up4xY35bNWX1SIZFbeUMSRFak2HSa9 7PntX7FvVXHe5qNwjQ== =IZBN -----END PGP SIGNATURE----- --=-=-=-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Tomas Volf <~@wolfsden.cz> Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Sun, 22 Sep 2024 12:31:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxim Cournoyer Cc: 71300@debbugs.gnu.org, Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxime Devos Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.172700824530272 (code B ref 71300); Sun, 22 Sep 2024 12:31:02 +0000 Received: (at 71300) by debbugs.gnu.org; 22 Sep 2024 12:30:45 +0000 Received: from localhost ([127.0.0.1]:41059 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ssLjg-0007sC-NQ for submit@debbugs.gnu.org; Sun, 22 Sep 2024 08:30:44 -0400 Received: from wolfsden.cz ([37.205.8.62]:33710) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1ssLjd-0007s1-N6 for 71300@debbugs.gnu.org; Sun, 22 Sep 2024 08:30:43 -0400 Received: by wolfsden.cz (Postfix, from userid 104) id 7703332705F; Sun, 22 Sep 2024 12:30:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1727008218; bh=1KS/oMzL6bRdtdQNNnAXMIA1jD6wfDt96TwcwtWlpnc=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=eJ8/B9zaT1VXuIuKfYlw/gIx28ym5aEVKgc2U4TWFd0+pUAaa4CC/gqG/KO1zbYyr NxSMvo1rdC/u2AsNb3ySTD8/RnPjHAX1nrsyLk2unKrp83UePPlLOLBnf7WefnvVM9 Pcvx/uZ0QZf2YOUDZ9fY8WWE7Bev4aHonAtWYT/oxoZ8QtDw+agi4rZhRiFvErFsCd ST4BXcl6qgkCcC8tfJVpBZriNqb2bIcKbOrN73Q3DrKz/gsy7uTUnUNwWWpdnLwssd xbIES4sA+UGUVXJ+5HTQKrNFTFit3PC7G7Vr5tlXAyqiC42KEor3Gxeu1AFlAxcGgs vV4cH4laUfb4igqchmhj+Ex83Ir32yuxuFcXR2S4yTOHWie04tYA/l9CVgVDIDjt0Y A6K6J5JTylpY2bBRd0xwTitwgi+KLcfcitPoRqD7eTLDeQcB3m7De4qXDHefAWr6sM 2W0ky0dTDUVM+NXfhLx96xZ7ur7ib0yxaBEpB9guUTHMEvy5Fcib2lAoLwTQy5p+Jw CVpphs9zrUPiXZYmys9d1zcVszG7HRYgUuXcW4q5nkcoM8gPlZw2O9RrwuW10UQRJ7 KOnOS9+Wh5xDQjAUiiJleDZBpJBBR3gYybDnwThR5MApW6xGj2v175ZhKVFHznupG0 5fBO7usgqqYG0Ffr28JSCr/U= X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on wolfsden X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from localhost (unknown [128.0.188.242]) by wolfsden.cz (Postfix) with ESMTPSA id 3536B3269D5; Sun, 22 Sep 2024 12:30:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1727008218; bh=1KS/oMzL6bRdtdQNNnAXMIA1jD6wfDt96TwcwtWlpnc=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=eJ8/B9zaT1VXuIuKfYlw/gIx28ym5aEVKgc2U4TWFd0+pUAaa4CC/gqG/KO1zbYyr NxSMvo1rdC/u2AsNb3ySTD8/RnPjHAX1nrsyLk2unKrp83UePPlLOLBnf7WefnvVM9 Pcvx/uZ0QZf2YOUDZ9fY8WWE7Bev4aHonAtWYT/oxoZ8QtDw+agi4rZhRiFvErFsCd ST4BXcl6qgkCcC8tfJVpBZriNqb2bIcKbOrN73Q3DrKz/gsy7uTUnUNwWWpdnLwssd xbIES4sA+UGUVXJ+5HTQKrNFTFit3PC7G7Vr5tlXAyqiC42KEor3Gxeu1AFlAxcGgs vV4cH4laUfb4igqchmhj+Ex83Ir32yuxuFcXR2S4yTOHWie04tYA/l9CVgVDIDjt0Y A6K6J5JTylpY2bBRd0xwTitwgi+KLcfcitPoRqD7eTLDeQcB3m7De4qXDHefAWr6sM 2W0ky0dTDUVM+NXfhLx96xZ7ur7ib0yxaBEpB9guUTHMEvy5Fcib2lAoLwTQy5p+Jw CVpphs9zrUPiXZYmys9d1zcVszG7HRYgUuXcW4q5nkcoM8gPlZw2O9RrwuW10UQRJ7 KOnOS9+Wh5xDQjAUiiJleDZBpJBBR3gYybDnwThR5MApW6xGj2v175ZhKVFHznupG0 5fBO7usgqqYG0Ffr28JSCr/U= From: Tomas Volf <~@wolfsden.cz> In-Reply-To: <20240915042603.8529-1-maxim.cournoyer@gmail.com> (Maxim Cournoyer's message of "Sun, 15 Sep 2024 13:25:46 +0900") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> Date: Sun, 22 Sep 2024 14:30:16 +0200 Message-ID: <877cb3hnvr.fsf@wolfsden.cz> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Maxim Cournoyer writes: > This is an import of the 'Abstract', 'Rationale', and 'Specification' > sections from the upstream specification text, with some manual > adjustment. > > * doc/ref/srfi-modules.texi (SRFI 64): New subsection. I think important question to ask here is whether this manual section documents SRFI-64 or what Guile ships as SRFI-64. Current implementation shipped by Guile has many quirks that do not conform to the specification. > +@c This SRFI 64 documentation was "snarfed" from upstream specification > +@c HTML document using the 'snarfi' script. Based on this I believe it describes the specification. I think either of those is fine (albeit describing the Guile's flavor would be preferred), but is should be stated (that the behavior described by the manual does not match the implementation shipped). Have a nice day, Tomas =2D-=20 There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors. --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJCBAEBCgAsFiEEt4NJs4wUfTYpiGikL7/ufbZ/wakFAmbwDdgOHH5Ad29sZnNk ZW4uY3oACgkQL7/ufbZ/wakEiA/+ObTsNxHZ1tSqFvkrthq1b00NwLo/DvGSyAXP YUxqocrJhmSLlWUW7UqvXbqe8bb4naC8AjtP1ZT/HUKRU7heUEafFVDDx/1WQGzB pMBbLbyfaEEm5GSG31w2E1pDugrKlwPfLsiAgjCF28QOb0VaMcdIfg98xZYTq2sL sJPVG12Km7RrMjiMUxqozWhZ+AHh5brpK7w9xM6klOGCmJyJc/69sORfbIK0DTkV citwxI9DvmNAuSOCG14Qqf8ok6dq0CC0Q/7BG1k61AJpmyoVDxW1kV9n8gwfqJ/a pT0XPjNDC4ABhdzR1RX7hOIryhlA65bFeleIeDy7gXssMiNhSkzzsKjAeMJP7ruo y9sdg3eyGWc4cSkTxOvInnPQVWN2z5udwX55NCJeMBaprTUWcEqOiyZ1ZwizzLFU bCQ/YZmH/8MJluMxaGpaGxWCLOBNvXA6aJ3WSG0I8RPm9CPMqugD+Wbi5QLHElqZ 7tqJtwN+LKzJmPJlcLDWVm78xoKn2LQD/do79lNBio6rPq8iW2Q43ctmNJiGXYO2 4tSgMESQ4RMZGhatiLMycpPjSP99ReZd4cDqCbMInk/lhi2Md3ujtBxWpxzwRMu/ pDh4fHTSINcWF3WCkCkJHAhGX4aXm0RLkvLH4pAmeMybddbFUYbfIjw243Hpekgw HlxBxnc= =kWWR -----END PGP SIGNATURE----- --=-=-=-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Thu, 26 Sep 2024 13:38:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Tomas Volf <~@wolfsden.cz> Cc: 71300@debbugs.gnu.org, Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxime Devos Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.1727357844668 (code B ref 71300); Thu, 26 Sep 2024 13:38:02 +0000 Received: (at 71300) by debbugs.gnu.org; 26 Sep 2024 13:37:24 +0000 Received: from localhost ([127.0.0.1]:33639 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1stogN-0000Af-0D for submit@debbugs.gnu.org; Thu, 26 Sep 2024 09:37:24 -0400 Received: from mail-pg1-f182.google.com ([209.85.215.182]:58675) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1stogK-0000A9-92 for 71300@debbugs.gnu.org; Thu, 26 Sep 2024 09:37:20 -0400 Received: by mail-pg1-f182.google.com with SMTP id 41be03b00d2f7-7db1f13b14aso752160a12.1 for <71300@debbugs.gnu.org>; Thu, 26 Sep 2024 06:36:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1727357747; x=1727962547; darn=debbugs.gnu.org; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=+hE77JjINT8eKl092axTt3hazn5sT5OwP+D8HGLP3Ao=; b=CmC/OmIiPLTs8adUCBS4k6H+teq+HAywK7sgrZht3oVMNdJcrFkc9ovPfxlAD6I5Jr 5DIRuf/wzZYBobRn6ZVZ4YIe+o84WYDDlslGSkBQb3n1iUqvl06zeJuGg3zqjWJrZ9MB YhJ/eJZhkVXzVN72OEYYiAZoA5UWbE3O0ijELN31stpWvWaDXsP4tnREMv3w0+eaCPIl edvaILrU0dp52R1oItSLtuAnk314ZBT5t8zD3ZD8PYMD3yO/dFLUzkbanaVjHhaHMm70 lFMUR9o9jlrmQda/vlncSiDzocH6FLpN1coAfVbIBedyt1kRkMZeTWEhu8C833UdRliZ oZ/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727357747; x=1727962547; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=+hE77JjINT8eKl092axTt3hazn5sT5OwP+D8HGLP3Ao=; b=A9Pp7KUquMJP5Zbod9RwZYr3obvDB0sZkOED5XByZ7PRtYQrsxV/DCnVFubVNuJyeK ++S17v4w5L3nXrT3DBwFmheQsKcNdBGy93YPop/M/absdipZSeVOfOnlVZwu4SwxgYKf RS7FRuFZHVBZKUreIbcz1gJZyx7PfGpaXEtLuK7AtMocXjb2KbUsDchhHAM3c1u4JVxX o1/tKG+bZY6eV5k/JbE+f+d4AlzXfEn0Lryq1YVBgZUMBntUlKpglU9bhHbG2PUc4Uf8 8amDuVYB/lxAnA94K0dN92/264qguVNXnP7+/O+PTvQT21zTa8ukWhZB5ZymqlqAiKpt IL3w== X-Gm-Message-State: AOJu0Ywa8bVsazzDSxCRQ3EDGX1rmijSQnZILZAhqM/sCKfbvGkMDQMm XTrlSi+2sFWqYhy+kw8i7Y9UjVwQ0V8QQSYdoTTg9juXheg+G/91 X-Google-Smtp-Source: AGHT+IFWrdY3RQFur0pdp3Y5dDNE7TOyV/u8ARirCX0GQYBEuAqyeaDB8gIYD7ttfOQg/n2E5LigLA== X-Received: by 2002:a05:6a20:bf22:b0:1d4:e5fd:a98c with SMTP id adf61e73a8af0-1d4e5fda9d7mr5544969637.0.1727357747241; Thu, 26 Sep 2024 06:35:47 -0700 (PDT) Received: from hurd ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-71afc9c79a5sm4341411b3a.220.2024.09.26.06.35.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Sep 2024 06:35:46 -0700 (PDT) From: Maxim Cournoyer In-Reply-To: <877cb3hnvr.fsf@wolfsden.cz> (Tomas Volf's message of "Sun, 22 Sep 2024 14:30:16 +0200") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> Date: Thu, 26 Sep 2024 22:35:44 +0900 Message-ID: <87r096edvz.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Tomas, Tomas Volf <~@wolfsden.cz> writes: > Maxim Cournoyer writes: > >> This is an import of the 'Abstract', 'Rationale', and 'Specification' >> sections from the upstream specification text, with some manual >> adjustment. >> >> * doc/ref/srfi-modules.texi (SRFI 64): New subsection. > > I think important question to ask here is whether this manual section > documents SRFI-64 or what Guile ships as SRFI-64. Current > implementation shipped by Guile has many quirks that do not conform to > the specification. > >> +@c This SRFI 64 documentation was "snarfed" from upstream specification >> +@c HTML document using the 'snarfi' script. > > 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 think either of those is fine (albeit describing the Guile's flavor > would be preferred), but is should be stated (that the behavior There's not really a Guile flavor; it's more like the reference implementation flavor ;-). The one in Guile is pretty stock. > described by the manual does not match the implementation shipped). I'd consider different behavior in the implementation compared to the specification bugs. -- Thanks, Maxim From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Taylan Kammer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Thu, 26 Sep 2024 19:16:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: 71300@debbugs.gnu.org X-Debbugs-Original-To: bug-guile@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.172737814328583 (code B ref -1); Thu, 26 Sep 2024 19:16:02 +0000 Received: (at submit) by debbugs.gnu.org; 26 Sep 2024 19:15:43 +0000 Received: from localhost ([127.0.0.1]:50951 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sttxn-0007Qw-3R for submit@debbugs.gnu.org; Thu, 26 Sep 2024 15:15:43 -0400 Received: from lists.gnu.org ([209.51.188.17]:37688) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sttxk-0007Qj-Sw for submit@debbugs.gnu.org; Thu, 26 Sep 2024 15:15:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sttxJ-0000jH-2h for bug-guile@gnu.org; Thu, 26 Sep 2024 15:15:13 -0400 Received: from mail-wr1-x42e.google.com ([2a00:1450:4864:20::42e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sttxG-0003Yp-RY for bug-guile@gnu.org; Thu, 26 Sep 2024 15:15:12 -0400 Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-37cd26c874bso85852f8f.3 for ; Thu, 26 Sep 2024 12:15:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1727378108; x=1727982908; darn=gnu.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id:from :to:cc:subject:date:message-id:reply-to; bh=KEMc3ezf64bpfwjd7y6EaUplJ/Mzwwzp5TLuNYra0Gs=; b=SlTb9kLBgKaOYrNwug2qKnY71Axd41T6TYdvIhNpM63Uxq/Z2ADegmyAi4etXdSS5J M4S3AbFp1+p/4fSfoWUBAxTUzyncweonprwSJYt1DaNMW0r1h9mPN5eGdlHRt0+M8Ixc pU3nkJZ+70Ji2QifiC4wA6mpXkpD2sdjsmV81zgp4nd7g+xTtBoweS5yAA1xu0AysjCZ UVJIpqNnggyUbE/nkCnZsMg95F7XsDwJV83sPotZG+1g+LO4J9yUS+w4b9H3B5KSd36b MEa4R4kD55RkExwAXGig1PWZbBlKC5gDBVS8YfqXmknFkNs/fZ9NFt04D92RqRC4w6n1 Df9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727378108; x=1727982908; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KEMc3ezf64bpfwjd7y6EaUplJ/Mzwwzp5TLuNYra0Gs=; b=RD+yXCJXSg2cJ9P5NTvImz9PYJC8TeROUPo7AixUs+RvJ5Y7pXb3VCIW2Myh/q5STq r71V4NA+bWzJdmwCcOiRzr8VtVIg9saq4/Ow+O5GhFjivAn6RigtEBD+lCZehmWCAbyZ IFFu4+8KEp1poIAeE43rD038JknsxAo5ePErV6VSHIVn5jdulGUxgJ3UR3iTQVjZj8iW aPtSrHOknxtuLxEZtoJYwR9mH+ylAYnMTZ+ORQmPcf4C0Et91wxUmDaWJsT73qvu7nZe +Kkb1sgY0HKNIM9VBu9p+NCN7YbRzksfzMf0ZeURJWgNMb/XRhzZxH9q7EUvqgHKgwW+ M6Eg== X-Gm-Message-State: AOJu0YyAN/AsFFkA8HSLX9b7mqPoqZgAug7g7i8I+0qKDQvGVFDw6Wzn KFgbbERcRXIrKR63KMyP91Ye32tsYbBThDuTpTLtqhQIlnFRQrbOH4v8qpU+ X-Google-Smtp-Source: AGHT+IHPSgVE1dCXB3FxMJ508jSWDN2rWZmcfo/jK7yElJpDjk9TC99q+9k+1BuwwLDEadSNYP53FA== X-Received: by 2002:a05:600c:4686:b0:42c:aeee:e605 with SMTP id 5b1f17b1804b1-42f584aefdfmr1938385e9.9.1727378107826; Thu, 26 Sep 2024 12:15:07 -0700 (PDT) Received: from ?IPV6:2003:106:8f04:c300:b11c:c085:7361:37dc? (p200301068f04c300b11cc085736137dc.dip0.t-ipconnect.de. [2003:106:8f04:c300:b11c:c085:7361:37dc]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42f57e2fe89sm6914165e9.40.2024.09.26.12.15.06 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 26 Sep 2024 12:15:07 -0700 (PDT) Message-ID: <84f71af5-41eb-44b0-86b1-a73be14f6543@gmail.com> Date: Thu, 26 Sep 2024 21:15:06 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> <87r096edvz.fsf@gmail.com> Content-Language: en-US From: Taylan Kammer In-Reply-To: <87r096edvz.fsf@gmail.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a00:1450:4864:20::42e; envelope-from=taylan.kammer@gmail.com; helo=mail-wr1-x42e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.3 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) On 26.09.2024 15:35, Maxim Cournoyer wrote: > Hi Tomas, > > Tomas Volf <~@wolfsden.cz> writes: > >> Maxim Cournoyer writes: >> >>> This is an import of the 'Abstract', 'Rationale', and 'Specification' >>> sections from the upstream specification text, with some manual >>> adjustment. >>> >>> * doc/ref/srfi-modules.texi (SRFI 64): New subsection. >> I think important question to ask here is whether this manual section >> documents SRFI-64 or what Guile ships as SRFI-64. Current >> implementation shipped by Guile has many quirks that do not conform to >> the specification. >> >>> +@c This SRFI 64 documentation was "snarfed" from upstream specification >>> +@c HTML document using the 'snarfi' script. >> 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 think either of those is fine (albeit describing the Guile's flavor >> would be preferred), but is should be stated (that the behavior > There's not really a Guile flavor; it's more like the reference > implementation flavor ;-). The one in Guile is pretty stock. > >> described by the manual does not match the implementation shipped). > I'd consider different behavior in the implementation compared to the > specification bugs. > Let me once again advertise my implementation of SRFI 64, found here:     https://codeberg.org/taylan/scheme-srfis/ The code is more readable and better structured, has fewer bugs (obeys the specification), and adds a small number of useful extensions, as explained here:     https://codeberg.org/taylan/scheme-srfis/#srfi-64 The output of the default test runner is also a lot more informative, and handles nested test groups. (Prints the entire "path" hierarchy of the current test.) It's also more verbose though, which may be a matter of taste: It prints something for every test executed, whereas the reference implementation (the one used by Guile) only prints something for failed tests. Sadly, the patch I previously sent to Guile for switching to this implementation was ignored, and Guile's R7RS support is still insufficient to use the R7RS SRFI libraries "out of the box." However, for the convenience of Guile users, the latest commit contains the directory "guile-srfi-64" in the repo's root, which contains a copy of the implementation with file naming and module boilerplate that should work with all recent Guile versions. So, you can use it by adding the following to your GUILE_LOAD_PATH:     $scheme_srfis_repo_root/guile-srfi-64 E.g. I can start guile like this, to use it in lieu of the implementation that ships with Guile:     GUILE_LOAD_PATH=/home/taylan/src/scheme-srfis/guile-srfi-64 guile Maybe someone will want to try it out, and push for its inclusion in Guile if they agree that it's a superior implementation. All the best, Taylan From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Maxime Devos Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Sun, 29 Sep 2024 19:46:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxim Cournoyer , Tomas Volf <~@wolfsden.cz> Cc: "71300@debbugs.gnu.org" <71300@debbugs.gnu.org>, Filip =?UTF-8?Q?=C5=81ajszczak?= Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.172763911828566 (code B ref 71300); Sun, 29 Sep 2024 19:46:02 +0000 Received: (at 71300) by debbugs.gnu.org; 29 Sep 2024 19:45:18 +0000 Received: from localhost ([127.0.0.1]:41955 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1suzr4-0007Qg-E0 for submit@debbugs.gnu.org; Sun, 29 Sep 2024 15:45:18 -0400 Received: from gauss.telenet-ops.be ([195.130.132.49]:60828) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1suzr1-0007QO-S3 for 71300@debbugs.gnu.org; Sun, 29 Sep 2024 15:45:16 -0400 Received: from andre.telenet-ops.be (andre.telenet-ops.be [IPv6:2a02:1800:120:4::f00:15]) by gauss.telenet-ops.be (Postfix) with ESMTPS id 4XGvmW06D7z4x40M for <71300@debbugs.gnu.org>; Sun, 29 Sep 2024 21:44:43 +0200 (CEST) Received: from [IPv6:2a02:1811:8c0e:ef00:2165:444c:61e5:2a1] ([IPv6:2a02:1811:8c0e:ef00:2165:444c:61e5:2a1]) by andre.telenet-ops.be with cmsmtp id JKjf2D00f5Amo2z01KjgPd; Sun, 29 Sep 2024 21:43:40 +0200 Message-ID: <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> MIME-Version: 1.0 From: Maxime Devos Date: Sun, 29 Sep 2024 21:43:37 +0200 Importance: normal X-Priority: 3 In-Reply-To: <87r096edvz.fsf@gmail.com> References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> <87r096edvz.fsf@gmail.com> Content-Type: multipart/alternative; boundary="_FB76AF55-E55C-4F8D-94EE-097A52256FCE_" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=telenet.be; s=r24; t=1727639020; bh=pJTz/i2eYhLlzKKdwAiP5RlzgoE6cKoO3tuLXyvEEhI=; h=Message-ID:MIME-Version:To:Cc:From:Subject:Date:In-Reply-To: References:Content-Type:From; b=Dhmd0YbRLlpMlAha0MS6SnBvaduZ0ZEw66dPvZcECXiv6AEtSB5oEavjT7JF5J7Mx /+cH6J1gpS7SSWrKO1q2nrsm0OgLD8JhJT91ZIvyX8l5uELcEZ1ts7u54huWWkyHsg hobzA0PLYT/OXzTnei3jzzvmH5bqkYbgw4GMjfe6Pd09qAiLditbndXy9krAouk/f9 soKD3M5PWn/H/eU70obNa2VlJxjWp67EAOPzyy1ssfgMT2m4fXZswu7L4ZIJBEcLJM o0Fp9I5+hYzfmNSZ+lIhMHWhbb0OJE1/W+KqnG/VMi3RCSdWWxiOhDKo2TkJPr7Okq 8AUn3KJIotudw== X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --_FB76AF55-E55C-4F8D-94EE-097A52256FCE_ Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" >> 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 =E2=80=9Cleft to the implementation=E2=80=9D -> =E2=80= =9Cwhat Guile does=E2=80=9D is problematic, since it misleads readers into = thinking this is the standard behaviour (it is after all named SRFI 64, not= GRFI 64). =E2=80=9CWhat Guile does=E2=80=9D is also important information to have. To avoid this problem, when it documents a choice made by Guile, it should = indicate in some way that this is Guile behaviour. (E.g.: =E2=80=9CIt is left to the implementation what happens when A. Guile= chooses to B.=E2=80=9D, or =E2=80=9CIt is left to the implementation what = happens when A. Guile currently chooses to B, but may choose differently in= future versions.=E2=80=9D) >> I think either of those is fine (albeit describing the Guile's flavor >> would be preferred), but is should be stated (that the behavior >There's not really a Guile flavor; it's more like the reference implementation flavor ;-). The one in Guile is pretty stock. Then Guile flavour is stock flavour, and stock flavour isn=E2=80=99t specif= ication vanilla. From what I=E2=80=99ve heard, it=E2=80=99s not just sprink= les added to vanilla, it also has bugs (not the crunchy food kind). >> described by the manual does not match the implementation shipped). >I'd consider different behavior in the implementation compared to the specification bugs. See response by Taylan Kammer. Best regards, Maxime Devos --_FB76AF55-E55C-4F8D-94EE-097A52256FCE_ Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset="utf-8"

=  

>> Based on this I believe it de= scribes the specification.

> 

>That's correct. It's been slightly modified in pl= aces where it said

>things like "left to th= e implementation" and I was able to verify what

>the current implementation in Guix does.

 

I assume Guix->Guile.

 

This modification of= =E2=80=9Cleft to the implementation=E2=80=9D -> =E2=80=9Cwhat Guile doe= s=E2=80=9D is problematic, since it misleads readers into thinking this is = the standard behaviour (it is after all named SRFI 64, not GRFI 64).

 

=E2=80=9CWhat G= uile does=E2=80=9D is also important information to have.

 

To avoid this problem, whe= n it documents a choice made by Guile, it should indicate in some way that = this is Guile behaviour.

(E.g.: =E2=80=9CIt is left= to the implementation what happens when A. Guile chooses to B.=E2=80=9D, o= r =E2=80=9CIt is left to the implementation what happens when A. Guile curr= ently chooses to B, but may choose differently in future versions.=E2=80=9D= )

 

>>= ; I think either of those is fine (albeit describing the Guile's flavor

=

>> would be preferred), but is should be stated = (that the behavior

>There's not really a Guile f= lavor; it's more like the reference

implementation = flavor ;-).=C2=A0 The one in Guile is pretty stock.

 

Then Guile flavour is stock flav= our, and stock flavour isn=E2=80=99t specification vanilla. From what I=E2= =80=99ve heard, it=E2=80=99s not just sprinkles added to vanilla, it also h= as bugs (not the crunchy food kind).

 

>> described by the manual does not match= the implementation shipped).

>I'd consider diff= erent behavior in the implementation compared to the

specification bugs.

 

See response by Taylan Kammer.

&n= bsp;

Best regards,

Ma= xime Devos

= --_FB76AF55-E55C-4F8D-94EE-097A52256FCE_-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Taylan Kammer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Mon, 30 Sep 2024 11:44:29 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxime Devos , Maxim Cournoyer , Tomas Volf <~@wolfsden.cz> Cc: "71300@debbugs.gnu.org" <71300@debbugs.gnu.org>, Filip =?UTF-8?Q?=C5=81ajszczak?= Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.172769664620581 (code B ref 71300); Mon, 30 Sep 2024 11:44:29 +0000 Received: (at 71300) by debbugs.gnu.org; 30 Sep 2024 11:44:06 +0000 Received: from localhost ([127.0.0.1]:44860 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1svEnz-00051c-Pw for submit@debbugs.gnu.org; Mon, 30 Sep 2024 07:43:58 -0400 Received: from mail-wm1-f54.google.com ([209.85.128.54]:39872) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1svEmd-0004Yf-IR for 71300@debbugs.gnu.org; Mon, 30 Sep 2024 07:42:43 -0400 Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-42cacd90ee4so6044755e9.3 for <71300@debbugs.gnu.org>; Mon, 30 Sep 2024 04:41:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1727696405; x=1728301205; darn=debbugs.gnu.org; h=in-reply-to:from:content-language:references:cc:to:subject :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=m69lt2UUbyjovwS34GAZCZkJhIlW2xcfCwDrH3Oiyfw=; b=c1CrgzU0ymOSC/lT1gEkrRnI1ZsVBvHibHrt2cPp2iDAdrGCJ3H3VRx7y44fF24o0h tVtTwSWLGP1T9iLYWIOrR8XvIXuF0CtWsx1/Iul2TyvfTTZE1q9b5scc3F/V+UBe7Bsu 1zKPsbERhnbbGNS4V8hIPZzV/jPs8gKHgQWll19RBw3RfwpNNVljo5hy1gzlelryuCgq rs20Y1137VGNHs+h86AWN3yXBM5CDAWZYYaHUHACS905lHhjOIaMqIhL6c9gZVS9sCm7 QvPSkp9mNvfCTGhYx3d4Uw9cqTdOjZ+JlSl+w7IETGQXLAcegyTiL9i9lS9xxauUFpoa 0Kqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727696405; x=1728301205; h=in-reply-to:from:content-language:references:cc:to:subject :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=m69lt2UUbyjovwS34GAZCZkJhIlW2xcfCwDrH3Oiyfw=; b=FRyaVOLaQ8eXRCE4ndHbY/pImXE1CSUZ1igBlzTavsddeecNQEnjYavDPa6peNWT6k E39nM0Dn4vJ+LocTtkDVnaFv1E4yUqD9elcagk4budKYyP/Fdkc4rqU0EaLpLm0FA5a4 4ixlu+BAbqD76B2USvguUP1kDGjXdTwF5/gQTreTBk1LHrl1ZHgEihBBA+Lcmbboc4dp XR55848aBAFAKwThRkmUC6iSjZl84DfpyuZVGoyG6xtaJZYaEFl0RLOVCUZ+tqB1trvK GLCl4fLj74zRSAa51pEAe7IIeHR/fSDMh89K+LiWbxub5lxfxZJt5wzIBNn8X8y61o7G xIMw== X-Gm-Message-State: AOJu0Yx63NA7b/6woGMvUwXzE1+nnDKypLrgtoh57Nzrr/blHdhC2fif x0CSejIwJei16PtHfb57wgIybzs6GEaPj671apnpH7HTIPGxNzOB X-Google-Smtp-Source: AGHT+IHyggL6K86Dh8kyTcDmPX5X1aJtMvRK6SZDP/u/zKmS0P8EecEMBv359HiWwM6TmYCZKI8r5A== X-Received: by 2002:a05:600c:3c9d:b0:42c:b9c8:2ba9 with SMTP id 5b1f17b1804b1-42f6daeca73mr4955445e9.6.1727696404394; Mon, 30 Sep 2024 04:40:04 -0700 (PDT) Received: from ?IPV6:2003:106:8f04:c300:192e:476d:8ae3:22f2? (p200301068f04c300192e476d8ae322f2.dip0.t-ipconnect.de. [2003:106:8f04:c300:192e:476d:8ae3:22f2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42e969ffb11sm148747485e9.21.2024.09.30.04.40.03 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 30 Sep 2024 04:40:03 -0700 (PDT) Content-Type: multipart/alternative; boundary="------------H1A4S0j2nCirs0bWOenKnxpG" Message-ID: <45010bfa-8ef4-4046-9dde-540d534a1611@gmail.com> Date: Mon, 30 Sep 2024 13:39:59 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> <87r096edvz.fsf@gmail.com> <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> Content-Language: en-US From: Taylan Kammer In-Reply-To: <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> X-Spam-Score: -0.9 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.9 (-) This is a multi-part message in MIME format. --------------H1A4S0j2nCirs0bWOenKnxpG Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 29.09.2024 21:43, Maxime Devos via Bug reports for GUILE, GNU's Ubiquitous Extension Language wrote: > >   > > >> 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. > >   > > To avoid this problem, when it documents a choice made by Guile, it should indicate in some way that this is Guile behaviour. > > (E.g.: “It is left to the implementation what happens when A. Guile chooses to B.”, or “It is left to the implementation what happens when A. Guile currently chooses to B, but may choose differently in future versions.”) > >   > To be fair to Guile, this is a problem caused by the reference implementation coming directly from SRFI 64. It doesn't properly follow its own specification. I believe most Scheme implementations that support SRFI-64 just use the reference implementation, just like Guile does, so one could even say: There's the "on paper" standard of SRFI 64 (the spec), and then there's the de facto standard of SRFI 64 that basically all implementations use (the reference implementation provided by the SRFI 64 author), and Guile uses the latter like every other Scheme implementation. I think the spec as written is more useful though, so I've made my implementation actually conform to it. Mainly, there's one significant difference: The test runner returned by `test-runner-simple` shouldn't use its `aux` field (and the spec explicitly claims that it doesn't), so users can use the simple test runner as a basis to extend upon, using the `aux` field to store any state that their custom extension to the runner may need to store. The `test-runner-simple` returned by the reference implementation actually *does* use the `aux` field for something internal already (name of a log file), in direct contradiction to what the spec states. > >> I think either of those is fine (albeit describing the Guile's flavor > > >> would be preferred), but is should be stated (that the behavior > > >There's not really a Guile flavor; it's more like the reference > > implementation flavor ;-).  The one in Guile is pretty stock. > >   > > Then Guile flavour is stock flavour, and stock flavour isn’t specification vanilla. From what I’ve heard, it’s not just sprinkles added to vanilla, it also has bugs (not the crunchy food kind). > One or two bugs in the upstream reference implementation were actually fixed after I had pointed them out. From a quick glance, it doesn't seem Guile ever bothered to update, though, so I guess Guile still has them. Further, on July 30, Tomas Volf sent a large number of SRFI-64 bug reports to the bug-guile mailing list. I didn't have time then, but will be responding to them now... I can see at least one clear bug he seems to have found, which my implementation doesn't seem to suffer from (simply thanks to clean coding practices). Maybe I'll find a couple more to fix, because my implementation was originally derived from the reference implementation so may still be sharing bugs with it. Some of them seem like issues with the spec instead... Anyway, I'll respond to them one by one. Thanks for raising these issues, Taylan P.S.: I've been sending HTML email using Thunderbird lately. If it messes up the formatting too much, please do complain. Some of my contacts use HTML, and I haven't yet found a way to switch back and forth quickly in Thunderbird. --------------H1A4S0j2nCirs0bWOenKnxpG Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit
On 29.09.2024 21:43, Maxime Devos via Bug reports for GUILE, GNU's Ubiquitous Extension Language wrote:

 

>> 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.

 

To avoid this problem, when it documents a choice made by Guile, it should indicate in some way that this is Guile behaviour.

(E.g.: “It is left to the implementation what happens when A. Guile chooses to B.”, or “It is left to the implementation what happens when A. Guile currently chooses to B, but may choose differently in future versions.”)

 

To be fair to Guile, this is a problem caused by the reference implementation coming directly from SRFI 64. It doesn't properly follow its own specification.

I believe most Scheme implementations that support SRFI-64 just use the reference implementation, just like Guile does, so one could even say: There's the "on paper" standard of SRFI 64 (the spec), and then there's the de facto standard of SRFI 64 that basically all implementations use (the reference implementation provided by the SRFI 64 author), and Guile uses the latter like every other Scheme implementation.

I think the spec as written is more useful though, so I've made my implementation actually conform to it. Mainly, there's one significant difference: The test runner returned by `test-runner-simple` shouldn't use its `aux` field (and the spec explicitly claims that it doesn't), so users can use the simple test runner as a basis to extend upon, using the `aux` field to store any state that their custom extension to the runner may need to store. The `test-runner-simple` returned by the reference implementation actually *does* use the `aux` field for something internal already (name of a log file), in direct contradiction to what the spec states.

>> I think either of those is fine (albeit describing the Guile's flavor

>> would be preferred), but is should be stated (that the behavior

>There's not really a Guile flavor; it's more like the reference

implementation flavor ;-).  The one in Guile is pretty stock.

 

Then Guile flavour is stock flavour, and stock flavour isn’t specification vanilla. From what I’ve heard, it’s not just sprinkles added to vanilla, it also has bugs (not the crunchy food kind).

One or two bugs in the upstream reference implementation were actually fixed after I had pointed them out. From a quick glance, it doesn't seem Guile ever bothered to update, though, so I guess Guile still has them.

Further, on July 30, Tomas Volf sent a large number of SRFI-64 bug reports to the bug-guile mailing list. I didn't have time then, but will be responding to them now... I can see at least one clear bug he seems to have found, which my implementation doesn't seem to suffer from (simply thanks to clean coding practices). Maybe I'll find a couple more to fix, because my implementation was originally derived from the reference implementation so may still be sharing bugs with it. Some of them seem like issues with the spec instead... Anyway, I'll respond to them one by one.


Thanks for raising these issues,

Taylan


P.S.: I've been sending HTML email using Thunderbird lately. If it messes up the formatting too much, please do complain. Some of my contacts use HTML, and I haven't yet found a way to switch back and forth quickly in Thunderbird.

--------------H1A4S0j2nCirs0bWOenKnxpG-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v4] doc: Document SRFI 64. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Wed, 02 Oct 2024 07:13:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxime Devos Cc: "71300@debbugs.gnu.org" <71300@debbugs.gnu.org>, "Dr. Arne Babenhauserheide" , Filip =?UTF-8?Q?=C5=81ajszczak?= , Tomas Volf <~@wolfsden.cz> Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.172785314319732 (code B ref 71300); Wed, 02 Oct 2024 07:13:01 +0000 Received: (at 71300) by debbugs.gnu.org; 2 Oct 2024 07:12:23 +0000 Received: from localhost ([127.0.0.1]:56438 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1svtX5-00058C-KX for submit@debbugs.gnu.org; Wed, 02 Oct 2024 03:12:23 -0400 Received: from mail-pj1-f49.google.com ([209.85.216.49]:53632) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1svtX3-00057y-6o for 71300@debbugs.gnu.org; Wed, 02 Oct 2024 03:12:21 -0400 Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-2e192a2fe6cso224926a91.3 for <71300@debbugs.gnu.org>; Wed, 02 Oct 2024 00:12:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1727853075; x=1728457875; darn=debbugs.gnu.org; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=qQrMaV171fWsDXmBXLEjeZfN4a3FFRMkIzDRM+zk9tM=; b=MRcd6HrS4agHd9+Qhih30pbwnaFS6v8isy2zbAf3mE/bWQFu3fgysoBjRKiE99ghKb ikkf5nv/EWYiMx/o5CZm2TMBxiME7W7bJMjlAenSPmzGeFGQM3e9A+kP6rLtkUCCiNzk WD9ElncxLP6agW65ST3vXS0lv+rucrOSDI0oUmJDNyXJRjCGitdJahjoJWGWcfcsSYRM c93zZOPJ3wk2hUVXRiFBXwZePkZceTTI/Pw3p2abFy6LZwvJ7ZS9rFL0TKcBrpSWPz6N +TuIoV+qHZad0x69qUx6EkNpjszD1kVXvmDvJEkLjriLXKKQtRVlpWrn3+9j/9H5M1Vw g4+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727853075; x=1728457875; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=qQrMaV171fWsDXmBXLEjeZfN4a3FFRMkIzDRM+zk9tM=; b=lFEiGQozKL926TpaD5crZmKgUbKkEdBFlt8jsEIghCqknWsUQ02lbhjOYHVDrij1u6 2qQk6GE9xZ4p0QKkmDcj+8A15g9TPN+eyJTkcTuyMYUw274zISV9At3/2DlengSyFeiX 3QV0SK8eZpDBHDW1mfKGgUgmP4RSL9EdM9WsoW+TV1Rh+x4Ov8bC1xqIiAWrPE8L0x41 OAZy3l2BWz9P8Q+f0N1unwo12j8EZ0l27V55fIYUpTu7NJ9bAw8FzaRgJfD9U/2gglVj /7Zl6b0BlI6T5koPYo52kzuvhmgY//HV84gJ7ZQOgB+RKmX8WSKuGPLqQ42FaSS+ds6t wa6A== X-Forwarded-Encrypted: i=1; AJvYcCV6KzOS8PQbiLO80BUX7gwaPvFiaXUIQz9bsm/LHY1KD0dZKgkzFN7xIGH9qi93nfJnGGfuVw==@debbugs.gnu.org X-Gm-Message-State: AOJu0YyE5C84DtBwU37HHrpjzaeeKKn5IwzgOEa8lHSylT9S5iQBJYfe a1LINwvscH8COK1ZppU67E8dmWrLoH/61M7JrKHBWJHmSDLb4Z7+hcYbYQ== X-Google-Smtp-Source: AGHT+IETVe3GmN0H0bbXXpu6QQShv9UR18tazr6ULfWSq7pGygUcpr/TyjgEtfqzymE/L5qg8RizWA== X-Received: by 2002:a17:90a:7402:b0:2d8:77cc:85e with SMTP id 98e67ed59e1d1-2e18496b9e2mr2951841a91.37.1727853074350; Wed, 02 Oct 2024 00:11:14 -0700 (PDT) Received: from hurd ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20b37da0213sm79610205ad.94.2024.10.02.00.11.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Oct 2024 00:11:13 -0700 (PDT) From: Maxim Cournoyer In-Reply-To: <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> (Maxime Devos's message of "Sun, 29 Sep 2024 21:43:37 +0200") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> <87r096edvz.fsf@gmail.com> <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> Date: Wed, 02 Oct 2024 16:11:09 +0900 Message-ID: <87zfnnrnci.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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 =E2=80=9Cleft to the implementation=E2=80=9D -> =E2= =80=9Cwhat Guile does=E2=80=9D is problematic, since it misleads readers in= to thinking this is the standard behaviour (it is after all named SRFI 64, = not GRFI 64). > > =E2=80=9CWhat Guile does=E2=80=9D 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: --=-=-= Content-Type: text/plain Content-Disposition: inline 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.texi 2024-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't have to write the entire file in a new form, thus you don't have to re-indent it. -All names defined by the API start with the prefix @code{test-}All function-like forms are defined as syntax. They may be implemented -as functions or macros or built-ins. The reason for specifying them as -syntax is to allow specific tests to be skipped without evaluating sub-expressions, or for implementations -to add features such as printing line numbers or catching exceptions. -@c TODO: Review (delete/relocate) the following text (if any) -@c orphaned by splicing the `(h1 Specification)' node. - - -While this is a moderately complex specification, -you should be able to write simple test suites after just reading the -first few sections below. More advanced functionality, such -as writing a custom test-runner, is at the end of the specification. +All names defined by the API start with the prefix @samp{test-}. All +function-like forms are defined as syntax. They may be implemented as +functions or macros or built-ins. The reason for specifying them as +syntax is to allow specific tests to be skipped without evaluating +sub-expressions, or for implementations to add features such as printing +line numbers or catching exceptions. @node SRFI 64 Writing basic test suites @subsubsection SRFI 64 Writing basic test suites - -Let's start with a simple example. -This is a complete self-contained test-suite. +Let's start with a simple example. This is a complete self-contained +test-suite. @lisp ;; Initialize and give a name to a simple testsuite. @@ -81,73 +68,59 @@ (test-end "vec-test") @end lisp -This testsuite could be saved in its own source file. -Nothing else is needed: -We do not require any top-level forms, so it is easy -to wrap an existing program or test to this form, without adding indentation. -It is also easy to add new tests, without having to name individual -tests (though that is optional). - -Test cases are executed in the context of a @dfn{test runner}, -which is a object that accumulates and reports test results. -This specification defines how to create and use custom test runners, -but implementations should also provide a default test runner. -It is suggested (but not required) that loading the above -file in a top-level environment will cause the -tests to be executed using an implementation-specified default test runner, -and @code{test-end} will cause a summary to be displayed -in an implementation-specified manner. +This testsuite could be saved in its own source file. Nothing else is +needed: We do not require any top-level forms, so it is easy to wrap an +existing program or test to this form, without adding indentation. It +is also easy to add new tests, without having to name individual tests +(though that is optional). + +Test cases are executed in the context of a @dfn{test runner}, which is +a object that accumulates and reports test results. This specification +defines how to create and use custom test runners, but implementations +should also provide a default test runner. It is suggested (but not +required) that loading the above file in a top-level environment will +cause the tests to be executed using an implementation-specified default +test runner, and @code{test-end} will cause a summary to be displayed in +an implementation-specified manner. @subsubheading Simple test-cases +Primitive test cases test that a given condition is true. They may have +a name. The core test case form is @code{test-assert}: -Primitive test cases test that a given condition is true. -They may have a name. -The core test case form is @code{test-assert}: - +@deffn {Scheme Syntax} test-assert [test-name] expression -@deffn {Scheme Procedure} test-assert [test-name] expression -@c FIXME: Check deffn category and adjust '@end deffn' location +This evaluates the @var{expression}. The test passes if the result is +true; if the result is false, a test failure is reported. The test also +fails if an exception is raised, assuming the implementation has a way +to catch exceptions. How the failure is reported depends on the test +runner environment. The @var{test-name} is a string that names the test +case. (Though the @var{test-name} is a string literal in the examples, +it is an expression. It is evaluated only once.) It is used when +reporting errors, and also when skipping tests, as described below. It +is an error to invoke @code{test-assert}if there is no current test +runner. @end deffn +The following forms may be more convenient than using @code{test-assert} +directly: -This evaluates the @var{expression}The test passes if the result -is true; if the result is false, a test failure is reported. -The test also fails if an exception is raised, assuming the implementation -has a way to catch exceptions. -How the failure is reported depends on the test runner environment. -The @var{test-name} is a string that names the test case. -(Though the @var{test-name} is a string literal in the examples, -it is an expression. It is evaluated only once.) -It is used when reporting errors, and also when skipping tests, -as described below. -It is an error to invoke @code{test-assert}if there is no current test runner. - -The following forms may be more convenient than -using @code{test-assert} directly: - - -@deffn {Scheme Procedure} test-eqv [test-name] expected test-expr -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - +@deffn {Scheme Syntax} test-eqv [test-name] expected test-expr This is equivalent to: @lisp -(test-assert [@var{test-name}] (eqv? @var{expected}@var{test-expr})) +(test-assert [@var{test-name}] (eqv? @var{expected} @var{test-expr})) @end lisp -Similarly @code{test-equal} and @code{test-eq}are shorthand for @code{test-assert} combined with -@code{equal?} or @code{eq?}, respectively: - - -@deffn {Scheme Procedure} test-equal [test-name] expected test-expr - -@deffnx {Scheme Procedure} test-eq [test-name] expected test-expr -@c FIXME: Check deffn category and adjust '@end deffn' location @end deffn +Similarly @code{test-equal} and @code{test-eq} are shorthand for +@code{test-assert} combined with @code{equal?} or @code{eq?}, +respectively: + +@deffn {Scheme Syntax} test-equal [test-name] expected test-expr +@deffnx {Scheme Syntax} test-eq [test-name] expected test-expr Here is a simple example: @@ -155,56 +128,50 @@ (define (mean x y) (/ (+ x y) 2.0)) (test-eqv 4 (mean 3 5)) @end lisp +@end deffn For testing approximate equality of inexact reals we can use @code{test-approximate}: +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr error -@deffn {Scheme Procedure} test-approximate [test-name] expected test-expr error -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - - -This is equivalent to (except that each argument is only evaluated once): +This is equivalent to (except that each argument is only evaluated +once): @lisp (test-assert [test-name] (and (>= test-expr (- expected error)) (<= test-expr (+ expected error)))) @end lisp +@end deffn @subsubheading Tests for catching errors +We need a way to specify that evaluation @emph{should} fail. This +verifies that errors are detected when required. -We need a way to specify that evaluation @emph{should} fail. -This verifies that errors are detected when required. +@deffn {Scheme Syntax} test-error [[test-name] error-type] test-expr +Evaluating @var{test-expr} is expected to signal an error. The kind of +error is indicated by @var{error-type}. -@deffn {Scheme Procedure} test-error [[test-name] error-type] test-expr -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - - -Evaluating @var{test-expr} is expected to signal an error. -The kind of error is indicated by @var{error-type}. - -If the @var{error-type} is left out, or it is -@code{#t}, it means "some kind of unspecified error should be signaled". -For example: +If the @var{error-type} is left out, or it is @code{#t}, it means "some +kind of unspecified error should be signaled". For example: @lisp (test-error #t (vector-ref '#(1 2) 9)) @end lisp This specification leaves it implementation-defined (or for a future -specification) what form @var{test-error} may take, -though all implementations must allow @code{#t}Some implementations may support -@url{https://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35's conditions}, -but these are only standardized for -@url{https://srfi.schemers.org/srfi-36/srfi-36.html, SRFI-36's I/O conditions}, which are seldom useful in test suites. -An implementation may also allow implementation-specific -``exception types''For example Java-based implementations may allow -the names of Java exception classes: +specification) what form @var{test-error} may take, though all +implementations must allow @code{#t}. Some implementations may support +@url{https://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35's +conditions}, but these are only standardized for +@url{https://srfi.schemers.org/srfi-36/srfi-36.html, SRFI-36's I/O +conditions}, which are seldom useful in test suites. An implementation +may also allow implementation-specific ``exception types''. For example +Java-based implementations may allow the names of Java exception +classes: @lisp ;; Kawa-specific example @@ -213,31 +180,23 @@ An implementation that cannot catch exceptions should skip @code{test-error} forms. +@end deffn @subsubheading Testing syntax - -Testing syntax is tricky, especially if we want to -check that invalid syntax is causing an error. -The following utility function can help: - +Testing syntax is tricky, especially if we want to check that invalid +syntax is causing an error. The following utility function can help: @deffn {Scheme Procedure} test-read-eval-string string -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - - -This function parses @var{string} (using @code{read}) -and evaluates the result. -The result of evaluation is returned from @code{test-read-eval-string}An error is signalled if there are unread characters after the -@code{read} is done. -For example: -@code{(test-read-eval-string "(+ 3 4)")}@i{evaluates to}@code{7}. -@code{(test-read-eval-string "(+ 3 4")}@i{signals an error}. -@code{(test-read-eval-string "(+ 3 4) ")}@i{signals an error}, -because there is extra ``junk'' (@i{i.e.} a space) after the -list is read. +This function parses @var{string} (using @code{read}) and evaluates the +result. The result of evaluation is returned from +@code{test-read-eval-string}. An error is signalled if there are unread +characters after the @code{read} is done. For example: +@code{(test-read-eval-string "(+ 3 4)")} @i{evaluates to} @code{7}. +@code{(test-read-eval-string "(+ 3 4")} @i{signals an error}. +@code{(test-read-eval-string "(+ 3 4) ")} @i{signals an error}, because +there is extra ``junk'' (@i{i.e.} a space) after the list is read. The @code{test-read-eval-string} used in tests: @@ -251,101 +210,81 @@ (test-equal 5 (test-read-eval-string "(+ 1 #;(* 2 3) 4)")) (test-equal '(x z) (test-read-string "(list 'x #;'y 'z)")) @end lisp +@end deffn @subsubheading Test groups and paths - A @dfn{test group} is a named sequence of forms containing testcases, -expressions, and definitions. -Entering a group sets the @dfn{test group name}; leaving a -group restores the previous group name. -These are dynamic (run-time) operations, and a group has no -other effect or identity. -Test groups are informal groupings: they are neither -Scheme values, nor are they syntactic forms. +expressions, and definitions. Entering a group sets the @dfn{test group +name}; leaving a group restores the previous group name. These are +dynamic (run-time) operations, and a group has no other effect or +identity. Test groups are informal groupings: they are neither Scheme +values, nor are they syntactic forms. @c (More formal test suite values are introduced below.) - - A test group may contain nested inner test groups. The @dfn{test group path} is a list of the currently-active (entered) test group names, oldest (outermost) first. +@deffn {Scheme Syntax} test-begin suite-name [count] -@deffn {Scheme Procedure} test-begin suite-name [count] -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - +A @code{test-begin} enters a new test group. The @var{suite-name} +becomes the current test group name, and is added to the end of the test +group path. Portable test suites should use a string literal for +@var{suite-name}; the effect of expressions or other kinds of literals +is unspecified. -A @code{test-begin} enters a new test group. -The @var{suite-name} becomes the current test group name, -and is added to the end of the test group path. -Portable test suites should use a string literal for @var{suite-name}; -the effect of expressions or other kinds of literals is unspecified. - -@b{Rationale:} In some ways using symbols would be preferable. +@emph{Rationale:} In some ways using symbols would be preferable. However, we want human-readable names, and standard Scheme does not -provide a way to include spaces or mixed-case text in -literal symbols. +provide a way to include spaces or mixed-case text in literal symbols. -The optional @var{count} must match the number of -test-cases executed by this group. -(Nested test groups count as a single test case for this count.) -This extra test may be useful to catch cases where a test doesn't -get executed because of some unexpected error. +The optional @var{count} must match the number of test-cases executed by +this group. (Nested test groups count as a single test case for this +count.) This extra test may be useful to catch cases where a test +doesn't get executed because of some unexpected error. Additionally, if there is no currently executing test runner, one is installed in an implementation-defined manner. - - -@deffn {Scheme Procedure} test-end [suite-name] -@c FIXME: Check deffn category and adjust '@end deffn' location @end deffn +@deffn {Scheme Syntax} test-end [suite-name] A @code{test-end} leaves the current test group. An error is reported if the @var{suite-name} does not match the current test group name. -@c If it does match an earlier -@c name in the test group path, intervening groups are left. - +@c If it does match an earlier name in the test group path, intervening +@c groups are left. +Additionally, if the matching @code{test-begin}installed a new +test-runner, then the @code{test-end} will uninstall it, after reporting +the accumulated test results in an implementation-defined manner. +@end deffn -Additionally, if the matching @code{test-begin}installed a new test-runner, then the @code{test-end}will uninstall it, after reporting the accumulated test -results in an implementation-defined manner. - -@lisp -(@b{test-group}@var{suite-name}@var{decl-or-expr} @dots{}) -@end lisp +@deffn {Scheme Syntax} test-group suite-name decl-or-expr @dots{} Equivalent to: @lisp -(if (not (test-to-skip% @var{suite-name})) +(if (not (test-to-skip% (var suite-name))) (dynamic-wind - (lambda () (test-begin @var{suite-name})) - (lambda () @var{decl-or-expr} @dots{}) - (lambda () (test-end @var{suite-name})))) + (lambda () (test-begin (var suite-name))) + (lambda () (var decl-or-expr) ...) + (lambda () (test-end (var suite-name))))) @end lisp This is usually equivalent to executing the @var{decl-or-expr}s within the named test group. However, the entire group is skipped if it matched an active @code{test-skip} (see later). Also, the @code{test-end} is executed in case of an exception. +@end deffn @subsubheading Handling set-up and cleanup +@deffn {Scheme Syntax} test-group-with-cleanup suite-name decl-or-expr @dots{} cleanup-form - -@deffn {Scheme Procedure} test-group-with-cleanup suite-name decl-or-expr @dots{} cleanup-form -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - - -Execute each of the @var{decl-or-expr} forms in order -(as in a @var{}), -and then execute the @var{cleanup-form}The latter should be executed even if -one of a @var{decl-or-expr} forms raises an exception -(assuming the implementation has a way to catch exceptions). +Execute each of the @var{decl-or-expr} forms in order (as in a +@var{}), and then execute the @var{cleanup-form}. The latter +should be executed even if one of a @var{decl-or-expr} forms raises an +exception (assuming the implementation has a way to catch exceptions). For example: @@ -355,103 +294,77 @@ (do-a-bunch-of-tests f) (close-output-port f))) @end lisp - -@b{Erratum note:}@url{https://github.com/scheme-requests-for-implementation/srfi-64/blob/4470ffdec71b1cf61633b664958a3ce5e6997710/srfi-64.html, Earlier versions} had a non-working example. - -@c

Test suites

-@c

-@c (Not sure how useful this is, given test-group). -@c

A test suite is a test group that can (and must) be -@c executed explicitly. -@c

-@c (test-suite suite-name decl-or-expr @dots{})
-@c 
-@c

-@c The test suite path is the list of names of currently -@c running testsuites, from outermost (oldest) to innermost (newest). -@c

A test-suite form is equivalent to: -@c

-@c (test-suite-register suite-name
-@c   (test-group suite-name decl-or-expr @dots{}))
-@c 
-@c You can run previously registered test suite: -@c
-@c (test-suite-run suite-name)
-@c 
- +@end deffn @node SRFI 64 Conditonal test-suites and other advanced features @subsubsection SRFI 64 Conditonal test-suites and other advanced features - The following describes features for controlling which tests to execute, or specifying that some tests are @emph{expected} to fail. @subsubheading Test specifiers - -Sometimes we want to only run certain tests, or we know that -certain tests are expected to fail. -A @dfn{test specifier} is one-argument function that takes a test-runner -and returns a boolean. The specifier may be run before a test is performed, -and the result may control whether the test is executed. -For convenience, a specifier may also be a non-procedure value, -which is coerced to a specifier procedure, as described below for -@var{count} and @var{name}. +Sometimes we want to only run certain tests, or we know that certain +tests are expected to fail. A @dfn{test specifier} is one-argument +function that takes a test-runner and returns a boolean. The specifier +may be run before a test is performed, and the result may control +whether the test is executed. For convenience, a specifier may also be +a non-procedure value, which is coerced to a specifier procedure, as +described below for @var{count} and @var{name}. A simple example is: @lisp -(if @var{some-condition} (test-skip 2)) ;; skip next 2 tests +(if (var some-condition) (test-skip 2)) ;; skip next 2 tests @end lisp - @deffn {Scheme Procedure} test-match-name name -The resulting specifier matches if the current test name (asreturned by@code{test-runner-test-name}) is@code{equal?}toname. +The resulting specifier matches if the current test name (as returned by +@code{test-runner-test-name}) is @code{equal?} to @var{name}. @end deffn +@deffn {Scheme Syntax} test-match-nth n [count] -@deffn {Scheme Procedure} test-match-nth n [count] - -This evaluates to a@emph{stateful}predicate: A counter keeps track ofhow many times it has been called.The predicate matches then'th time it is called(where@code{1}is the first time), andthe next -@c FIXME: Check deffn category and adjust '@end deffn' location +This evaluates to a @emph{stateful} predicate: A counter keeps track of +how many times it has been called. The predicate matches the @var{n}'th +time it is called (where @code{1} is the first time), and the next +@samp{(- @var{count} 1)} times, where @var{count} defaults to @code{1}. @end deffn +@deffn {Scheme Syntax} test-match-any specifier @dots{} -@c FIXME: Check deffn category and adjust '@end deffn' location +The resulting specifier matches if any @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is true. @end deffn +@deffn {Scheme Syntax} test-match-all specifier @dots{} -@c FIXME: Check deffn category and adjust '@end deffn' location +The resulting specifier matches if each @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is false. @end deffn +@var{count} @i{(i.e. an integer)} +Convenience short-hand for: @samp{(test-match-nth 1 @var{count})}. -@var{count}@i{(i.e. an integer)} -Convenience short-hand for: @code{(test-match-nth 1 @var{count})}. - -@var{name}@i{(i.e. a string)} -Convenience short-hand for @code{(test-match-name @var{name})}. +@var{name} @i{(i.e. a string)} +Convenience short-hand for @samp{(test-match-name @var{name})}. @subsubheading Skipping selected tests - In some cases you may want to skip a test. +@deffn {Scheme Syntax} test-skip specifier -@deffn {Scheme Procedure} test-skip specifier -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - - -Evaluating @code{test-skip} adds the -resulting @var{specifier}to the set of currently active skip-specifiers. -Before each test (or @code{test-group}) -the set of active skip-specifiers are applied to the active test-runner. -If any specifier matches, then the test is skipped. +Evaluating @code{test-skip} adds the resulting @var{specifier} to the +set of currently active skip-specifiers. Before each test (or +@code{test-group}) the set of active skip-specifiers are applied to the +active test-runner. If any specifier matches, then the test is skipped. -For convenience, if the @var{specifier} is a string that -is syntactic sugar for @code{(test-match-name @var{specifier})}For example: +For convenience, if the @var{specifier} is a string that is syntactic +sugar for @code{(test-match-name @var{specifier})}. For example: @lisp (test-skip "test-b") @@ -459,7 +372,8 @@ (test-assert "test-b") ;; skipped @end lisp -Any skip specifiers introduced by a @code{test-skip}are removed by a following non-nested @code{test-end}. +Any skip specifiers introduced by a @code{test-skip} are removed by a +following non-nested @code{test-end}. @lisp (test-begin "group1") @@ -468,21 +382,16 @@ (test-end "group1") ;; Undoes the prior test-skip (test-assert "test-a") ;; executed @end lisp +@end deffn @subsubheading Expected failures +Sometimes you know a test case will fail, but you don't have time to or +can't fix it. Maybe a certain feature only works on certain platforms. +However, you want the test-case to be there to remind you to fix it. +You want to note that such tests are expected to fail. -Sometimes you know a test case will fail, but you don't have time -to or can't fix it. Maybe a certain feature only works on certain platforms. -However, you want the test-case to be there -to remind you to fix it. You want to note that -such tests are expected to fail. - - -@deffn {Scheme Procedure} test-expect-fail specifier -@c FIXME: Check deffn category and adjust '@end deffn' location -@end deffn - +@deffn {Scheme Syntax} test-expect-fail specifier Matching tests (where matching is defined as in @code{test-skip}) are expected to fail. This only affects test reporting, @@ -490,102 +399,95 @@ @lisp (test-expect-fail 2) -(test-eqv @dots{}) ;; expected to fail -(test-eqv @dots{}) ;; expected to fail -(test-eqv @dots{}) ;; expected to pass +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to pass @end lisp +@end deffn @node SRFI 64 Test-runner @subsubsection SRFI 64 Test-runner - -A @dfn{test-runner} is an object that runs a test-suite, -and manages the state. The test group path, and the sets skip and -expected-fail specifiers are part of the test-runner. -A test-runner will also typically accumulate statistics about executed tests. - - +A @dfn{test-runner} is an object that runs a test-suite, and manages the +state. The test group path, and the sets skip and expected-fail +specifiers are part of the test-runner. A test-runner will also +typically accumulate statistics about executed tests, @deffn {Scheme Procedure} test-runner? value -True iff@code{value}is a test-runner object. +True if and only if @var{value} is a test-runner object. @end deffn +@deffn {Scheme Parameter} test-runner-current +@deffnx {Scheme Parameter} test-runner-current runner -@deffn {Scheme Procedure} test-runner-current - -@deffnx {Scheme Procedure} test-runner-current runner - -Get or set the current test-runner.If an implementation supports parameter objects(as in@url{https://srfi.schemers.org/srfi-39/srfi-39.html, SRFI-39}),then@code{test-runner-current}can be a parameter object.Alternatively,@code{test-runner-current}may be implementedas a macro or functionthat uses a fluid or thread-local variable, or a plain global variable. +Get or set the current test-runner. @end deffn - @deffn {Scheme Procedure} test-runner-get -Same as -@c FIXME: Check deffn category and adjust '@end deffn' location +Same as @code{(test-runner-current)}, but throws an exception if there +is no current test-runner. @end deffn - - @deffn {Scheme Procedure} test-runner-simple -Creates a new simple test-runner, that prints errors and a summaryon the standard output port. +Creates a new simple test-runner, that prints errors and a summary on +the standard output port. @end deffn - @deffn {Scheme Procedure} test-runner-null -Creates a new test-runner, that does nothing with the test results.This is mainly meant for extending when writing a custom runner. +Creates a new test-runner, that does nothing with the test results. +This is mainly meant for extending when writing a custom runner. @end deffn -Implementations @emph{may} provide other test-runners, perhaps -a @code{(test-runner-gui)}. - - @deffn {Scheme Procedure} test-runner-create -Create a new test-runner. Equivalent to -@c FIXME: Check deffn category and adjust '@end deffn' location +Create a new test-runner. Equivalent to @samp{((test-runner-factory))}. @end deffn +@deffn {Scheme Parameter} test-runner-factory +@deffnx {Scheme Parameter} test-runner-factory factory - -@deffn {Scheme Procedure} test-runner-factory - -@deffnx {Scheme Procedure} test-runner-factory factory - -Get or set the current test-runner factory.A factory is a zero-argument function that creates a new test-runner.The default value is@code{test-runner-simple},but implementations may provide a way to override the default.As with@code{test-runner-current}, this may be a parameter object,or use a per-thread, fluid, or global variable. +Get or set the current test-runner factory. A factory is a +zero-argument function that creates a new test-runner. The default +value is @code{test-runner-simple}. @end deffn @subsubheading Running specific tests with a specified runner - - @deffn {Scheme Procedure} test-apply [runner] specifier @dots{} procedure -Callsprocedurewith no arguments using the specifiedrunneras the current test-runner.Ifrunneris omitted,then -@c FIXME: Check deffn category and adjust '@end deffn' location +Calls @var{procedure} with no arguments using the specified @var{runner} +as the current test-runner. If @var{runner} is omitted, then +@code{(test-runner-current)} is used. (If there is no current runner, +one is created as in @code{test-begin}.) If one or more +@var{specifier}s are listed then only tests matching the +@var{specifier}s are executed. A @var{specifier} has the same form as +one used for @code{test-skip}. A test is executed if it matches any of +the @var{specifier}s in the @code{test-apply} @emph{and} does not match +any active @code{test-skip} specifiers. @end deffn +@deffn {Scheme Syntax} test-with-runner runner decl-or-expr @dots{} -@c FIXME: Check deffn category and adjust '@end deffn' location +Executes each @var{decl-or-expr} in order in a context where the current +test-runner is @var{runner}. @end deffn - @node SRFI 64 Test results @subsubsection SRFI 64 Test results - Running a test sets various status properties in the current test-runner. This can be examined by a custom test-runner, or (more rarely) in a test-suite. @subsubheading Result kind - Running a test may yield one of the following status symbols: + @table @asis @item @code{'pass} The test passed, as expected. @@ -601,70 +503,76 @@ @item @code{'skip} The test was skipped. - @end table - @deffn {Scheme Procedure} test-result-kind [runner] -Returns one of the above result codes from the most recent tests.Returns@code{#f}if no tests have been run yet.If we've started on a new test, but don't have a result yet,then the result kind is@code{'xfail}if the test is expected to fail,@code{'skip}if the test is supposed to be skipped,or@code{#f}otherwise. +Returns one of the above result codes from the most recent tests. +Returns @code{#f} if no tests have been run yet. If we've started on a +new test, but don't have a result yet, then the result kind is +@code{'xfail} if the test is expected to fail, @code{'skip} if the test +is supposed to be skipped, or @code{#f} otherwise. @end deffn - @deffn {Scheme Procedure} test-passed? [runner] -True if the value of - -@deffnx {Scheme Procedure} test-result-kind [runner] - -is one of@code{'pass}or@code{'xpass}This is a convenient shorthand that might be usefulin a test suite to only run certain tests if the previous test passed. +True if the value of @samp{(test-result-kind [@var{runner}])} is one of +@code{'pass} or @code{'xpass}. This is a convenient shorthand that +might be useful in a test suite to only run certain tests if the +previous test passed. @end deffn @subsubheading Test result properties +A test runner also maintains a set of more detailed +``result@tie{}properties'' associated with the current or most recent +test. (I.e. the properties of the most recent test are available as +long as a new test hasn't started.) Each property has a name (a symbol) +and a value (any value). Some properties are standard or set by the +implementation; implementations can add more. -A test runner also maintains a set of more detailed ``result properties''associated with the current or most recent test. (I.e. the properties of the -most recent test are available as long as a new test hasn't started.) -Each property has a name (a symbol) and a value (any value). -Some properties are standard or set by the implementation; -implementations can add more. - +@deffn {Scheme Procedure} test-result-ref runner pname [default] -@deffn {Scheme Procedure} test-result-ref runner ' pname [default] - -Returns the property value associated with thepnameproperty name.If there is no value associated with@code{'pname}returndefault,or@code{#f}ifdefaultisn't specified. +Returns the property value associated with the @var{pname} property name +(a symbol). If there is no value associated with @var{pname} return +@var{default}, or @code{#f} if @var{default} isn't specified. @end deffn +@deffn {Scheme Syntax} test-result-set! runner pname value -@deffn {Scheme Procedure} test-result-set! runner ' pname value - -Sets the property value associated with thepnameproperty name tovalueUsually implementation code should call this function, but it may beuseful for a custom test-runner to add extra properties. +Sets the property value associated with the @var{pname} property name to +@var{value}. Usually implementation code should call this function, but +it may be useful for a custom test-runner to add extra properties. @end deffn +@deffn {Scheme Procedure} test-result-remove runner pname -@deffn {Scheme Procedure} test-result-remove runner ' pname - -Remove the property with the name@code{'pname}. +Remove the property with the name @var{pname}. @end deffn - @deffn {Scheme Procedure} test-result-clear runner -Remove all result properties.The implementation automatically calls@code{test-result-clear}at the start of a@code{test-assert}and similar procedures. +Remove all result properties. The implementation automatically calls +@code{test-result-clear} at the start of a @code{test-assert} and +similar procedures. @end deffn - @deffn {Scheme Procedure} test-result-alist runner -Returns an association list of the current result properties.It is unspecified if the result shares state with the test-runner.The result should not be modified; on the other hand, the resultmay be implicitly modified by future@code{test-result-set!}or@code{test-result-remove}calls.However, a@code{test-result-clear}does not modify the returnedalist. Thus you can``archive''result objects from previous runs. +Returns an association list of the current result properties. It is +unspecified if the result shares state with the test-runner. The result +should not be modified; on the other hand, the result may be implicitly +modified by future @code{test-result-set!} or @code{test-result-remove} +calls. However, a @code{test-result-clear} does not modify the returned +alist. Thus you can ``archive'' result objects from previous runs. @end deffn @subsubheading Standard result properties - The set of available result properties is implementation-specific. However, it is suggested that the following might be provided: @table @asis + @item @code{'result-kind} The result kind, as defined previously. This is the only mandatory result property. @@ -691,121 +599,113 @@ @item @code{'actual-error} The error value, if an error was signalled and it is known. The actual error value is implementation-defined. - @end table @node SRFI 64 Writing a new test-runner @subsubsection SRFI 64 Writing a new test-runner - -This section specifies how to write a test-runner. -It can be ignored if you just want to write test-cases. +This section specifies how to write a test-runner. It can be ignored if +you just want to write test-cases. @subsubheading Call-back functions - These call-back functions are ``methods'' (in the object-oriented sense) -of a test-runner. A method @code{test-runner-on-@var{event}}is called by the implementation when @var{event} happens. +of a test-runner. A method @code{test-runner-on-@var{event}} is called +by the implementation when @var{event} happens. -To define (set) the callback function for @var{event} use the following expression. -(This is normally done when initializing a test-runner.) +To define (set) the callback function for @var{event} use the following +expression. (This is normally done when initializing a test-runner.) -@code{(test-runner-on-@var{event}! @var{runner}@var{event-function})} +@code{(test-runner-on-@var{event}! @var{runner} @var{event-function})} -An @var{event-function} takes a test-runner argument, and possibly other arguments, depending on the @var{event}. +An @var{event-function} takes a test-runner argument, and possibly other +arguments, depending on the @var{event}. To extract (get) the callback function for @var{event} do this: -@code{(test-runner-on-@var{event}@var{runner})} +@code{(test-runner-on-@var{event} @var{runner})} -To extract call the callback function for @var{event} use the following expression. -(This is normally done by the implementation core.) -@code{((test-runner-on-@var{event}@var{runner}) @var{runner}@var{other-args} @dots{})} +To extract call the callback function for @var{event} use the following +expression. (This is normally done by the implementation core.) +@samp{((test-runner-on-@var{event} @var{runner}) @var{runner} +@var{other-args} @dots{})}. The following call-back hooks are available. - @deffn {Scheme Procedure} test-runner-on-test-begin runner - @deffnx {Scheme Procedure} test-runner-on-test-begin! runner on-test-begin-function +@deffnx {Scheme Procedure} on-test-begin-function runner -@deffnx {Scheme Procedure} on-test-begin-function runner +The @var{on-test-begin-function} is called at the start of an +individual testcase, before the test expression (and expected value) are +evaluated. -Theon-test-begin-functionis called at the start of anindividual testcase, before the test expression (and expected value) areevaluated. @end deffn - @deffn {Scheme Procedure} test-runner-on-test-end runner - @deffnx {Scheme Procedure} test-runner-on-test-end! runner on-test-end-function +@deffnx {Scheme Procedure} on-test-end-function runner -@deffnx {Scheme Procedure} on-test-end-function runner - -Theon-test-end-functionis called at the end of anindividual testcase, when the result of the test is available. +The @var{on-test-end-function} is called at the end of an +individual testcase, when the result of the test is available. @end deffn - @deffn {Scheme Procedure} test-runner-on-group-begin runner - @deffnx {Scheme Procedure} test-runner-on-group-begin! runner on-group-begin-function +@deffnx {Scheme Procedure} on-group-begin-function runner suite-name count -@deffnx {Scheme Procedure} on-group-begin-function runner suite-name count - -Theon-group-begin-functionis called by a@code{test-begin},including at the start of a@code{test-group}Thesuite-nameis a Scheme string,andcountis an integer or@code{#f}. +The @var{on-group-begin-function} is called by a @code{test-begin}, +including at the start of a @code{test-group}. The @var{suite-name} is +a Scheme string, and @var{count} is an integer or @code{#f}. @end deffn - @deffn {Scheme Procedure} test-runner-on-group-end runner - @deffnx {Scheme Procedure} test-runner-on-group-end! runner on-group-end-function +@deffnx {Scheme Procedure} on-group-end-function runner -@deffnx {Scheme Procedure} on-group-end-function runner - -Theon-group-end-functionis called by a@code{test-end},including at the end of a@code{test-group}. +The @var{on-group-end-function} is called by a @code{test-end}, +including at the end of a @code{test-group}. @end deffn - @deffn {Scheme Procedure} test-runner-on-bad-count runner - @deffnx {Scheme Procedure} test-runner-on-bad-count! runner on-bad-count-function +@deffnx {Scheme Procedure} on-bad-count-function runner actual-count expected-count -@deffnx {Scheme Procedure} on-bad-count-function runner actual-count expected-count - -Called from@code{test-end}(before theon-group-end-functionis called) if anexpected-countwas specified by the matching@code{test-begin}and theexpected-countdoes not matchtheactual-countof tests actually executed or skipped. +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if an @var{expected-count} was specified by the matching +@code{test-begin} and the @var{expected-count} does not match the +@var{actual-count} of tests actually executed or skipped. @end deffn - @deffn {Scheme Procedure} test-runner-on-bad-end-name runner - @deffnx {Scheme Procedure} test-runner-on-bad-end-name! runner on-bad-end-name-function +@deffnx {Scheme Procedure} on-bad-end-name-function runner begin-name end-name -@deffnx {Scheme Procedure} on-bad-end-name-function runner begin-name end-name - -Called from@code{test-end}(before theon-group-end-functionis called) if asuite-namewas specified, and it did not that thename in the matching@code{test-begin}. +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if a @var{suite-name} was specified, and it did not that the +name in the matching @code{test-begin}. @end deffn - @deffn {Scheme Procedure} test-runner-on-final runner - @deffnx {Scheme Procedure} test-runner-on-final! runner on-final-function +@deffnx {Scheme Procedure} on-final-function runner -@deffnx {Scheme Procedure} on-final-function runner - -Theon-final-functiontakes one parameter (a test-runner)and typically displays a summary (count) of the tests.Theon-final-functionis called after called theon-group-end-functioncorrespondiong to the outermost@code{test-end}The default value is@code{test-on-final-simple}which writesto the standard output port the number of tests of the various kinds. +The @var{on-final-function} takes one parameter (a test-runner) and +typically displays a summary (count) of the tests. The +@var{on-final-function} is called after called the +@var{on-group-end-function} correspondiong to the outermost +@code{test-end}. The default value is @code{test-on-final-simple} which +writes to the standard output port the number of tests of the various +kinds. @end deffn - -The default test-runner returned by@code{test-runner-simple}uses the following call-back functions: +The default test-runner returned by @code{test-runner-simple} uses the +following call-back functions: @deffn {Scheme Procedure} test-on-test-begin-simple runner - @deffnx {Scheme Procedure} test-on-test-end-simple runner - @deffnx {Scheme Procedure} test-on-group-begin-simple runner suite-name count - @deffnx {Scheme Procedure} test-on-group-end-simple runner - @deffnx {Scheme Procedure} test-on-bad-count-simple runner actual-count expected-count - @deffnx {Scheme Procedure} test-on-bad-end-name-simple runner begin-name end-name You can call those if you want to write your own test-runner. @@ -813,76 +713,71 @@ @subsubheading Test-runner components - -The following functions are for accessing the other components of a test-runner. -They would normally only be used to write a new test-runner or -a match-predicate. - +The following functions are for accessing the other components of a +test-runner. They would normally only be used to write a new +test-runner or a match-predicate. @deffn {Scheme Procedure} test-runner-pass-count runner Returns the number of tests that passed, and were expected to pass. @end deffn - @deffn {Scheme Procedure} test-runner-fail-count runner Returns the number of tests that failed, but were expected to pass. @end deffn - @deffn {Scheme Procedure} test-runner-xpass-count runner Returns the number of tests that passed, but were expected to fail. @end deffn - @deffn {Scheme Procedure} test-runner-xfail-count runner Returns the number of tests that failed, and were expected to pass. @end deffn - @deffn {Scheme Procedure} test-runner-skip-count runner Returns the number of tests or test groups that were skipped. @end deffn - @deffn {Scheme Procedure} test-runner-test-name runner -Returns the name of the current test or test group, as a string.During execution of@code{test-begin}this is the name of thetest group; during the execution of an actual test, this is the nameof the test-case.If no name was specified, the name is the empty string. +Returns the name of the current test or test group, as a string. During +execution of @code{test-begin} this is the name of the test group; +during the execution of an actual test, this is the name of the +test-case. If no name was specified, the name is the empty string. @end deffn - @deffn {Scheme Procedure} test-runner-group-path runner -A list of names of groups we're nested in, with the outermost group first. +A list of names of groups we're nested in, with the outermost group +first. @end deffn - @deffn {Scheme Procedure} test-runner-group-stack runner -A list of names of groups we're nested in, with the outermost group last.(This is more efficient than@code{test-runner-group-path},since it doesn't require any copying.) +A list of names of groups we're nested in, with the outermost group +last. (This is more efficient than @code{test-runner-group-path}, since +it doesn't require any copying.) @end deffn - @deffn {Scheme Procedure} test-runner-aux-value runner - @deffnx {Scheme Procedure} test-runner-aux-value! runner on-test -Get or set the@code{aux-value}field of a test-runner.This field is not used by this API or the@code{test-runner-simple}test-runner, but may be used by custom test-runners to store extra state. +Get or set the @code{aux-value} field of a test-runner. This field is +not used by this API or the @code{test-runner-simple} test-runner, but +may be used by custom test-runners to store extra state. @end deffn - @deffn {Scheme Procedure} test-runner-reset runner -Resets the state of therunnerto its initial state. +Resets the state of the @var{runner} to its initial state. @end deffn @subsubheading Example - This is an example of a simple custom test-runner. Loading this program before running a test-suite will install it as the default test runner. Diff finished. Wed Oct 2 15:59:15 2024 --=-=-= Content-Type: text/plain Looking at it more closely, it looks pretty much left alone. It's only been re-flowed and some typos or extraneous comments fixed (I had submitted a bunch of typo fixes to upstream but it seems I had missed to send some). I'm also attaching the two versions (original snarfed vs submitted) for reference. [0] To snarf it on your own, you can use the tool I had shared here: https://lists.gnu.org/r/guile-devel/2023-12/msg00067.html --=-=-= Content-Type: application/texinfo Content-Disposition: attachment; filename=srfi-64-resnarfed.texi Content-Transfer-Encoding: base64 Content-Description: original QG5vZGUgU1JGSSA2NApAc3Vic2VjdGlvbiBTUkZJIDY0OiBBIFNjaGVtZSBBUEkgZm9yIHRlc3Qg c3VpdGVzCkBjaW5kZXggU1JGSSA2NAoKCkBub2RlIFNSRkkgNjQgQWJzdHJhY3QKQHN1YnN1YnNl Y3Rpb24gU1JGSSA2NCBBYnN0cmFjdAoKClRoaXMgZGVmaW5lcyBhbiBBUEkgZm9yIHdyaXRpbmcg QGRmbnt0ZXN0IHN1aXRlc30sIHRvIG1ha2UgaXQgZWFzeQp0byBwb3J0YWJseSB0ZXN0IFNjaGVt ZSBBUElzLCBsaWJyYXJpZXMsIGFwcGxpY2F0aW9ucywgYW5kIGltcGxlbWVudGF0aW9ucy4KQSB0 ZXN0IHN1aXRlIGlzIGEgY29sbGVjdGlvbiBvZiBAZGZue3Rlc3QgY2FzZXN9IHRoYXQgZXhlY3V0 ZQppbiB0aGUgY29udGV4dCBvZiBhIEBkZm57dGVzdC1ydW5uZXJ9LiAgVGhpcyBzcGVjaWZpY2F0 aW9uCmFsc28gc3VwcG9ydHMgd3JpdGluZyBuZXcgdGVzdC1ydW5uZXJzLCB0byBhbGxvdyBjdXN0 b21pemF0aW9uCm9mIHJlcG9ydGluZyBhbmQgcHJvY2Vzc2luZyB0aGUgcmVzdWx0IG9mIHJ1bm5p bmcgdGVzdCBzdWl0ZXMuCgpAbm9kZSBTUkZJIDY0IFJhdGlvbmFsZQpAc3Vic3Vic2VjdGlvbiBT UkZJIDY0IFJhdGlvbmFsZQoKClRoZSBTY2hlbWUgY29tbXVuaXR5IG5lZWRzIGEgc3RhbmRhcmQg Zm9yIHdyaXRpbmcgdGVzdCBzdWl0ZXMuCkV2ZXJ5IFNSRkkgb3Igb3RoZXIgbGlicmFyeSBzaG91 bGQgY29tZSB3aXRoIGEgdGVzdCBzdWl0ZS4KU3VjaCBhIHRlc3Qgc3VpdGUgbXVzdCBiZSBwb3J0 YWJsZSwgd2l0aG91dCByZXF1aXJpbmcgYW55Cm5vbi1zdGFuZGFyZCBmZWF0dXJlcywgc3VjaCBh cyBtb2R1bGVzLiAgVGhlIHRlc3Qgc3VpdGUgaW1wbGVtZW50YXRpb24Kb3IgInJ1bm5lciIgbmVl ZCBub3QgYmUgcG9ydGFibGUsIGJ1dCBpdCBpcyBkZXNpcmFibGUgdGhhdCBpdCBiZQpwb3NzaWJs ZSB0byB3cml0ZSBhIHBvcnRhYmxlIGJhc2ljIGltcGxlbWVudGF0aW9uLgoKVGhlcmUgYXJlIG90 aGVyIHRlc3RpbmcgZnJhbWV3b3JrcyB3cml0dGVuIGluIFNjaGVtZSwgaW5jbHVkaW5nCkB1cmx7 aHR0cHM6Ly9kb2NzLnJhY2tldC1sYW5nLm9yZy9yYWNrdW5pdC8sIFJhY2tVbml0fUhvd2V2ZXIg UmFja1VuaXQgaXMgbm90IHBvcnRhYmxlLgpJdCBpcyBhbHNvIGEgYml0IG9uIHRoZSB2ZXJib3Nl IHNpZGUuCkl0IHdvdWxkIGJlIHVzZWZ1bCB0byBoYXZlIGEgYnJpZGdlIGJldHdlZW4gdGhpcyBm cmFtZXdvcmsgYW5kIFJhY2tVbml0CnNvIFJhY2tVbml0IHRlc3RzIGNvdWxkIHJ1biB1bmRlciB0 aGlzIGZyYW1ld29yayBhbmQgdmljZSB2ZXJzYS4KVGhlcmUgZXhpc3RzIGFsc28gYXQgbGVhc3Qg b25lIFNjaGVtZSB3cmFwcGVyIHByb3ZpZGluZyBhIFNjaGVtZSBpbnRlcmZhY2UKdG8gdGhlIGBg c3RhbmRhcmQnJ0B1cmx7aHR0cHM6Ly93d3cuanVuaXQub3JnLywgSlVuaXR9IEFQSSBmb3IgSmF2 YS4KSXQgd291bGQgYmUgdXNlZnVsIHRvIGhhdmUgYSBicmlkZ2Ugc28gdGhhdCB0ZXN0cyB3cml0 dGVuIHVzaW5nIHRoaXMKZnJhbWV3b3JrIGNhbiBydW4gdW5kZXIgYSBKVW5pdCBydW5uZXIuCk5l aXRoZXIgb2YgdGhlc2UgZmVhdHVyZXMgYXJlIHBhcnQgb2YgdGhpcyBzcGVjaWZpY2F0aW9uLgoK VGhpcyBBUEkgbWFrZXMgdXNlIG9mIGltcGxpY2l0IGR5bmFtaWMgc3RhdGUsIGluY2x1ZGluZyBh bgppbXBsaWNpdCBgYHRlc3QgcnVubmVyJycuICBUaGlzIG1ha2VzIHRoZSBBUEkgY29udmVuaWVu dAphbmQgdGVyc2UgdG8gdXNlLCBidXQgaXQgbWF5IGJlIGEgbGl0dGxlIGxlc3MgZWxlZ2FudCBh bmQgYGBjb21wb3NpdGlvbmFsJyd0aGFuIHVzaW5nIGV4cGxpY2l0IHRlc3Qgb2JqZWN0cywgc3Vj aCBhcyBKVW5pdC1zdHlsZSBmcmFtZXdvcmtzLgpJdCBpcyBub3QgY2xhaW1lZCB0byBmb2xsb3cg ZWl0aGVyIG9iamVjdC1vcmllbnRlZCBvciBmdW5jdGlvbmFsIGRlc2lnbgpwcmluY2lwbGVzLCBi dXQgSSBob3BlIGl0IGlzIHVzZWZ1bCBhbmQgY29udmVuaWVudCB0byB1c2UgYW5kIGV4dGVuZC4K ClRoaXMgcHJvcG9zYWwgYWxsb3dzIGNvbnZlcnRpbmcgYSBTY2hlbWUgc291cmNlIGZpbGUgdG8g YQp0ZXN0IHN1aXRlIGJ5IGp1c3QgYWRkaW5nIGEgZmV3IG1hY3Jvcy4gIFlvdSBkb24ndCBoYXZl IHRvCndyaXRlIHRoZSBlbnRpcmUgZmlsZSBpbiBhIG5ldyBmb3JtLCB0aHVzIHlvdSBkb24ndCBo YXZlIHRvCnJlLWluZGVudCBpdC4KCkFsbCBuYW1lcyBkZWZpbmVkIGJ5IHRoZSBBUEkgc3RhcnQg d2l0aCB0aGUgcHJlZml4IEBjb2Rle3Rlc3QtfUFsbCBmdW5jdGlvbi1saWtlIGZvcm1zIGFyZSBk ZWZpbmVkIGFzIHN5bnRheC4gIFRoZXkgbWF5IGJlIGltcGxlbWVudGVkCmFzIGZ1bmN0aW9ucyBv ciBtYWNyb3Mgb3IgYnVpbHQtaW5zLiAgVGhlIHJlYXNvbiBmb3Igc3BlY2lmeWluZyB0aGVtIGFz CnN5bnRheCBpcyB0byBhbGxvdyBzcGVjaWZpYyB0ZXN0cyB0byBiZSBza2lwcGVkIHdpdGhvdXQg ZXZhbHVhdGluZyBzdWItZXhwcmVzc2lvbnMsIG9yIGZvciBpbXBsZW1lbnRhdGlvbnMKdG8gYWRk IGZlYXR1cmVzIHN1Y2ggYXMgcHJpbnRpbmcgbGluZSBudW1iZXJzIG9yIGNhdGNoaW5nIGV4Y2Vw dGlvbnMuCkBjIFRPRE86IFJldmlldyAoZGVsZXRlL3JlbG9jYXRlKSB0aGUgZm9sbG93aW5nIHRl eHQgKGlmIGFueSkKQGMgb3JwaGFuZWQgYnkgc3BsaWNpbmcgdGhlIGAoaDEgU3BlY2lmaWNhdGlv biknIG5vZGUuCgoKV2hpbGUgdGhpcyBpcyBhIG1vZGVyYXRlbHkgY29tcGxleCBzcGVjaWZpY2F0 aW9uLAp5b3Ugc2hvdWxkIGJlIGFibGUgdG8gd3JpdGUgc2ltcGxlIHRlc3Qgc3VpdGVzIGFmdGVy IGp1c3QgcmVhZGluZyB0aGUKZmlyc3QgZmV3IHNlY3Rpb25zIGJlbG93LiAgTW9yZSBhZHZhbmNl ZCBmdW5jdGlvbmFsaXR5LCBzdWNoCmFzIHdyaXRpbmcgYSBjdXN0b20gdGVzdC1ydW5uZXIsIGlz IGF0IHRoZSBlbmQgb2YgdGhlIHNwZWNpZmljYXRpb24uCgpAbm9kZSBTUkZJIDY0IFdyaXRpbmcg YmFzaWMgdGVzdCBzdWl0ZXMKQHN1YnN1YnNlY3Rpb24gU1JGSSA2NCBXcml0aW5nIGJhc2ljIHRl c3Qgc3VpdGVzCgoKTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBleGFtcGxlLgpUaGlzIGlzIGEg Y29tcGxldGUgc2VsZi1jb250YWluZWQgdGVzdC1zdWl0ZS4KCkBsaXNwCjs7IEluaXRpYWxpemUg YW5kIGdpdmUgYSBuYW1lIHRvIGEgc2ltcGxlIHRlc3RzdWl0ZS4KKHRlc3QtYmVnaW4gInZlYy10 ZXN0IikKKGRlZmluZSB2IChtYWtlLXZlY3RvciA1IDk5KSkKOzsgUmVxdWlyZSB0aGF0IGFuIGV4 cHJlc3Npb24gZXZhbHVhdGUgdG8gdHJ1ZS4KKHRlc3QtYXNzZXJ0ICh2ZWN0b3I/IHYpKQo7OyBU ZXN0IHRoYXQgYW4gZXhwcmVzc2lvbiBpcyBlcXY/IHRvIHNvbWUgb3RoZXIgZXhwcmVzc2lvbi4K KHRlc3QtZXF2IDk5ICh2ZWN0b3ItcmVmIHYgMikpCih2ZWN0b3Itc2V0ISB2IDIgNykKKHRlc3Qt ZXF2IDcgKHZlY3Rvci1yZWYgdiAyKSkKOzsgRmluaXNoIHRoZSB0ZXN0c3VpdGUsIGFuZCByZXBv cnQgcmVzdWx0cy4KKHRlc3QtZW5kICJ2ZWMtdGVzdCIpCkBlbmQgbGlzcAoKVGhpcyB0ZXN0c3Vp dGUgY291bGQgYmUgc2F2ZWQgaW4gaXRzIG93biBzb3VyY2UgZmlsZS4KTm90aGluZyBlbHNlIGlz IG5lZWRlZDoKV2UgZG8gbm90IHJlcXVpcmUgYW55IHRvcC1sZXZlbCBmb3Jtcywgc28gaXQgaXMg ZWFzeQp0byB3cmFwIGFuIGV4aXN0aW5nIHByb2dyYW0gb3IgdGVzdCB0byB0aGlzIGZvcm0sIHdp dGhvdXQgYWRkaW5nIGluZGVudGF0aW9uLgpJdCBpcyBhbHNvIGVhc3kgdG8gYWRkIG5ldyB0ZXN0 cywgd2l0aG91dCBoYXZpbmcgdG8gbmFtZSBpbmRpdmlkdWFsCnRlc3RzICh0aG91Z2ggdGhhdCBp cyBvcHRpb25hbCkuCgpUZXN0IGNhc2VzIGFyZSBleGVjdXRlZCBpbiB0aGUgY29udGV4dCBvZiBh IEBkZm57dGVzdCBydW5uZXJ9LAp3aGljaCBpcyBhIG9iamVjdCB0aGF0IGFjY3VtdWxhdGVzIGFu ZCByZXBvcnRzIHRlc3QgcmVzdWx0cy4KVGhpcyBzcGVjaWZpY2F0aW9uIGRlZmluZXMgaG93IHRv IGNyZWF0ZSBhbmQgdXNlIGN1c3RvbSB0ZXN0IHJ1bm5lcnMsCmJ1dCBpbXBsZW1lbnRhdGlvbnMg c2hvdWxkIGFsc28gcHJvdmlkZSBhIGRlZmF1bHQgdGVzdCBydW5uZXIuCkl0IGlzIHN1Z2dlc3Rl ZCAoYnV0IG5vdCByZXF1aXJlZCkgdGhhdCBsb2FkaW5nIHRoZSBhYm92ZQpmaWxlIGluIGEgdG9w LWxldmVsIGVudmlyb25tZW50IHdpbGwgY2F1c2UgdGhlCnRlc3RzIHRvIGJlIGV4ZWN1dGVkIHVz aW5nIGFuIGltcGxlbWVudGF0aW9uLXNwZWNpZmllZCBkZWZhdWx0IHRlc3QgcnVubmVyLAphbmQg QGNvZGV7dGVzdC1lbmR9IHdpbGwgY2F1c2UgYSBzdW1tYXJ5IHRvIGJlIGRpc3BsYXllZAppbiBh biBpbXBsZW1lbnRhdGlvbi1zcGVjaWZpZWQgbWFubmVyLgoKQHN1YnN1YmhlYWRpbmcgU2ltcGxl IHRlc3QtY2FzZXMKCgpQcmltaXRpdmUgdGVzdCBjYXNlcyB0ZXN0IHRoYXQgYSBnaXZlbiBjb25k aXRpb24gaXMgdHJ1ZS4KVGhleSBtYXkgaGF2ZSBhIG5hbWUuClRoZSBjb3JlIHRlc3QgY2FzZSBm b3JtIGlzIEBjb2Rle3Rlc3QtYXNzZXJ0fToKCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRl c3QtYXNzZXJ0IFt0ZXN0LW5hbWVdIGV4cHJlc3Npb24KQGMgRklYTUU6IENoZWNrIGRlZmZuIGNh dGVnb3J5IGFuZCBhZGp1c3QgJ0BlbmQgZGVmZm4nIGxvY2F0aW9uCkBlbmQgZGVmZm4KCgpUaGlz IGV2YWx1YXRlcyB0aGUgQHZhcntleHByZXNzaW9ufVRoZSB0ZXN0IHBhc3NlcyBpZiB0aGUgcmVz dWx0CmlzIHRydWU7IGlmIHRoZSByZXN1bHQgaXMgZmFsc2UsIGEgdGVzdCBmYWlsdXJlIGlzIHJl cG9ydGVkLgpUaGUgdGVzdCBhbHNvIGZhaWxzIGlmIGFuIGV4Y2VwdGlvbiBpcyByYWlzZWQsIGFz c3VtaW5nIHRoZSBpbXBsZW1lbnRhdGlvbgpoYXMgYSB3YXkgdG8gY2F0Y2ggZXhjZXB0aW9ucy4K SG93IHRoZSBmYWlsdXJlIGlzIHJlcG9ydGVkIGRlcGVuZHMgb24gdGhlIHRlc3QgcnVubmVyIGVu dmlyb25tZW50LgpUaGUgQHZhcnt0ZXN0LW5hbWV9IGlzIGEgc3RyaW5nIHRoYXQgbmFtZXMgdGhl IHRlc3QgY2FzZS4KKFRob3VnaCB0aGUgQHZhcnt0ZXN0LW5hbWV9IGlzIGEgc3RyaW5nIGxpdGVy YWwgaW4gdGhlIGV4YW1wbGVzLAppdCBpcyBhbiBleHByZXNzaW9uLiAgSXQgaXMgZXZhbHVhdGVk IG9ubHkgb25jZS4pCkl0IGlzIHVzZWQgd2hlbiByZXBvcnRpbmcgZXJyb3JzLCBhbmQgYWxzbyB3 aGVuIHNraXBwaW5nIHRlc3RzLAphcyBkZXNjcmliZWQgYmVsb3cuCkl0IGlzIGFuIGVycm9yIHRv IGludm9rZSBAY29kZXt0ZXN0LWFzc2VydH1pZiB0aGVyZSBpcyBubyBjdXJyZW50IHRlc3QgcnVu bmVyLgoKVGhlIGZvbGxvd2luZyBmb3JtcyBtYXkgYmUgbW9yZSBjb252ZW5pZW50IHRoYW4KdXNp bmcgQGNvZGV7dGVzdC1hc3NlcnR9IGRpcmVjdGx5OgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVy ZX0gdGVzdC1lcXYgW3Rlc3QtbmFtZV0gZXhwZWN0ZWQgdGVzdC1leHByCkBjIEZJWE1FOiBDaGVj ayBkZWZmbiBjYXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBsb2NhdGlvbgpAZW5kIGRl ZmZuCgoKVGhpcyBpcyBlcXVpdmFsZW50IHRvOgoKQGxpc3AKKHRlc3QtYXNzZXJ0IFtAdmFye3Rl c3QtbmFtZX1dIChlcXY/IEB2YXJ7ZXhwZWN0ZWR9QHZhcnt0ZXN0LWV4cHJ9KSkKQGVuZCBsaXNw CgpTaW1pbGFybHkgQGNvZGV7dGVzdC1lcXVhbH0gYW5kIEBjb2Rle3Rlc3QtZXF9YXJlIHNob3J0 aGFuZCBmb3IgQGNvZGV7dGVzdC1hc3NlcnR9IGNvbWJpbmVkIHdpdGgKQGNvZGV7ZXF1YWw/fSBv ciBAY29kZXtlcT99LCByZXNwZWN0aXZlbHk6CgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0 ZXN0LWVxdWFsIFt0ZXN0LW5hbWVdIGV4cGVjdGVkIHRlc3QtZXhwcgoKQGRlZmZueCB7U2NoZW1l IFByb2NlZHVyZX0gdGVzdC1lcSBbdGVzdC1uYW1lXSBleHBlY3RlZCB0ZXN0LWV4cHIKQGMgRklY TUU6IENoZWNrIGRlZmZuIGNhdGVnb3J5IGFuZCBhZGp1c3QgJ0BlbmQgZGVmZm4nIGxvY2F0aW9u CkBlbmQgZGVmZm4KCgpIZXJlIGlzIGEgc2ltcGxlIGV4YW1wbGU6CgpAbGlzcAooZGVmaW5lICht ZWFuIHggeSkgKC8gKCsgeCB5KSAyLjApKQoodGVzdC1lcXYgNCAobWVhbiAzIDUpKQpAZW5kIGxp c3AKCkZvciB0ZXN0aW5nIGFwcHJveGltYXRlIGVxdWFsaXR5IG9mIGluZXhhY3QgcmVhbHMKd2Ug Y2FuIHVzZSBAY29kZXt0ZXN0LWFwcHJveGltYXRlfToKCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1 cmV9IHRlc3QtYXBwcm94aW1hdGUgW3Rlc3QtbmFtZV0gZXhwZWN0ZWQgdGVzdC1leHByIGVycm9y CkBjIEZJWE1FOiBDaGVjayBkZWZmbiBjYXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBs b2NhdGlvbgpAZW5kIGRlZmZuCgoKVGhpcyBpcyBlcXVpdmFsZW50IHRvIChleGNlcHQgdGhhdCBl YWNoIGFyZ3VtZW50IGlzIG9ubHkgZXZhbHVhdGVkIG9uY2UpOgoKQGxpc3AKKHRlc3QtYXNzZXJ0 IFt0ZXN0LW5hbWVdCiAgKGFuZCAoPj0gdGVzdC1leHByICgtIGV4cGVjdGVkIGVycm9yKSkKICAg ICAgICg8PSB0ZXN0LWV4cHIgKCsgZXhwZWN0ZWQgZXJyb3IpKSkpCkBlbmQgbGlzcAoKQHN1YnN1 YmhlYWRpbmcgVGVzdHMgZm9yIGNhdGNoaW5nIGVycm9ycwoKCldlIG5lZWQgYSB3YXkgdG8gc3Bl Y2lmeSB0aGF0IGV2YWx1YXRpb24gQGVtcGh7c2hvdWxkfSBmYWlsLgpUaGlzIHZlcmlmaWVzIHRo YXQgZXJyb3JzIGFyZSBkZXRlY3RlZCB3aGVuIHJlcXVpcmVkLgoKCkBkZWZmbiB7U2NoZW1lIFBy b2NlZHVyZX0gdGVzdC1lcnJvciBbW3Rlc3QtbmFtZV0gZXJyb3ItdHlwZV0gdGVzdC1leHByCkBj IEZJWE1FOiBDaGVjayBkZWZmbiBjYXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBsb2Nh dGlvbgpAZW5kIGRlZmZuCgoKRXZhbHVhdGluZyBAdmFye3Rlc3QtZXhwcn0gaXMgZXhwZWN0ZWQg dG8gc2lnbmFsIGFuIGVycm9yLgpUaGUga2luZCBvZiBlcnJvciBpcyBpbmRpY2F0ZWQgYnkgIEB2 YXJ7ZXJyb3ItdHlwZX0uCgpJZiB0aGUgQHZhcntlcnJvci10eXBlfSBpcyBsZWZ0IG91dCwgb3Ig aXQgaXMKQGNvZGV7I3R9LCBpdCBtZWFucyAic29tZSBraW5kIG9mIHVuc3BlY2lmaWVkIGVycm9y IHNob3VsZCBiZSBzaWduYWxlZCIuCkZvciBleGFtcGxlOgoKQGxpc3AKKHRlc3QtZXJyb3IgI3Qg KHZlY3Rvci1yZWYgJyMoMSAyKSA5KSkKQGVuZCBsaXNwCgpUaGlzIHNwZWNpZmljYXRpb24gbGVh dmVzIGl0IGltcGxlbWVudGF0aW9uLWRlZmluZWQgKG9yIGZvciBhIGZ1dHVyZQpzcGVjaWZpY2F0 aW9uKSB3aGF0IGZvcm0gQHZhcnt0ZXN0LWVycm9yfSBtYXkgdGFrZSwKdGhvdWdoIGFsbCBpbXBs ZW1lbnRhdGlvbnMgbXVzdCBhbGxvdyBAY29kZXsjdH1Tb21lIGltcGxlbWVudGF0aW9ucyBtYXkg c3VwcG9ydApAdXJse2h0dHBzOi8vc3JmaS5zY2hlbWVycy5vcmcvc3JmaS0zNS9zcmZpLTM1Lmh0 bWwsIFNSRkktMzUncyBjb25kaXRpb25zfSwKYnV0IHRoZXNlIGFyZSBvbmx5IHN0YW5kYXJkaXpl ZCBmb3IKQHVybHtodHRwczovL3NyZmkuc2NoZW1lcnMub3JnL3NyZmktMzYvc3JmaS0zNi5odG1s LCBTUkZJLTM2J3MgSS9PIGNvbmRpdGlvbnN9LCB3aGljaCBhcmUgc2VsZG9tIHVzZWZ1bCBpbiB0 ZXN0IHN1aXRlcy4KQW4gaW1wbGVtZW50YXRpb24gbWF5IGFsc28gYWxsb3cgaW1wbGVtZW50YXRp b24tc3BlY2lmaWMKYGBleGNlcHRpb24gdHlwZXMnJ0ZvciBleGFtcGxlIEphdmEtYmFzZWQgaW1w bGVtZW50YXRpb25zIG1heSBhbGxvdwp0aGUgbmFtZXMgb2YgSmF2YSBleGNlcHRpb24gY2xhc3Nl czoKCkBsaXNwCjs7IEthd2Etc3BlY2lmaWMgZXhhbXBsZQoodGVzdC1lcnJvciA8amF2YS5sYW5n LkluZGV4T3V0T2ZCb3VuZHNFeGNlcHRpb24+ICh2ZWN0b3ItcmVmICcjKDEgMikgOSkpCkBlbmQg bGlzcAoKQW4gaW1wbGVtZW50YXRpb24gdGhhdCBjYW5ub3QgY2F0Y2ggZXhjZXB0aW9ucyBzaG91 bGQgc2tpcApAY29kZXt0ZXN0LWVycm9yfSBmb3Jtcy4KCkBzdWJzdWJoZWFkaW5nIFRlc3Rpbmcg c3ludGF4CgoKVGVzdGluZyBzeW50YXggaXMgdHJpY2t5LCBlc3BlY2lhbGx5IGlmIHdlIHdhbnQg dG8KY2hlY2sgdGhhdCBpbnZhbGlkIHN5bnRheCBpcyBjYXVzaW5nIGFuIGVycm9yLgpUaGUgZm9s bG93aW5nIHV0aWxpdHkgZnVuY3Rpb24gY2FuIGhlbHA6CgoKQGRlZmZuIHtTY2hlbWUgUHJvY2Vk dXJlfSB0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgc3RyaW5nCkBjIEZJWE1FOiBDaGVjayBkZWZmbiBj YXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBsb2NhdGlvbgpAZW5kIGRlZmZuCgoKVGhp cyBmdW5jdGlvbiBwYXJzZXMgQHZhcntzdHJpbmd9ICh1c2luZyBAY29kZXtyZWFkfSkKYW5kIGV2 YWx1YXRlcyB0aGUgcmVzdWx0LgpUaGUgcmVzdWx0IG9mIGV2YWx1YXRpb24gaXMgcmV0dXJuZWQg ZnJvbSBAY29kZXt0ZXN0LXJlYWQtZXZhbC1zdHJpbmd9QW4gZXJyb3IgaXMgc2lnbmFsbGVkIGlm IHRoZXJlIGFyZSB1bnJlYWQgY2hhcmFjdGVycyBhZnRlciB0aGUKQGNvZGV7cmVhZH0gaXMgZG9u ZS4KRm9yIGV4YW1wbGU6CkBjb2Rleyh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigrIDMgNCkiKX1A aXtldmFsdWF0ZXMgdG99QGNvZGV7N30uCkBjb2Rleyh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigr IDMgNCIpfUBpe3NpZ25hbHMgYW4gZXJyb3J9LgpAY29kZXsodGVzdC1yZWFkLWV2YWwtc3RyaW5n ICIoKyAzIDQpICIpfUBpe3NpZ25hbHMgYW4gZXJyb3J9LApiZWNhdXNlIHRoZXJlIGlzIGV4dHJh IGBganVuaycnIChAaXtpLmUufSBhIHNwYWNlKSBhZnRlciB0aGUKbGlzdCBpcyByZWFkLgoKClRo ZSBAY29kZXt0ZXN0LXJlYWQtZXZhbC1zdHJpbmd9IHVzZWQgaW4gdGVzdHM6CgpAbGlzcAoodGVz dC1lcXVhbCA3ICh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigrIDMgNCkiKSkKKHRlc3QtZXJyb3Ig KHRlc3QtcmVhZC1ldmFsLXN0cmluZyAiKCsgMyIpKQoodGVzdC1lcXVhbCAjXG5ld2xpbmUgKHRl c3QtcmVhZC1ldmFsLXN0cmluZyAiI1xcbmV3bGluZSIpKQoodGVzdC1lcnJvciAodGVzdC1yZWFk LWV2YWwtc3RyaW5nICIjXFxuZXdsaW4iKSkKOzsgU2tpcCB0aGUgbmV4dCAyIHRlc3RzIHVubGVz cyBzcmZpLTYyIGlzIGF2YWlsYWJsZS4KKHRlc3Qtc2tpcCAoY29uZC1leHBhbmQgKHNyZmktNjIg MCkgKGVsc2UgMikpKQoodGVzdC1lcXVhbCA1ICh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigrIDEg IzsoKiAyIDMpIDQpIikpCih0ZXN0LWVxdWFsICcoeCB6KSAodGVzdC1yZWFkLXN0cmluZyAiKGxp c3QgJ3ggIzsneSAneikiKSkKQGVuZCBsaXNwCgpAc3Vic3ViaGVhZGluZyBUZXN0IGdyb3VwcyBh bmQgcGF0aHMKCgpBIEBkZm57dGVzdCBncm91cH0gaXMgYSBuYW1lZCBzZXF1ZW5jZSBvZiBmb3Jt cyBjb250YWluaW5nIHRlc3RjYXNlcywKZXhwcmVzc2lvbnMsIGFuZCBkZWZpbml0aW9ucy4KRW50 ZXJpbmcgYSBncm91cCBzZXRzIHRoZSBAZGZue3Rlc3QgZ3JvdXAgbmFtZX07IGxlYXZpbmcgYQpn cm91cCByZXN0b3JlcyB0aGUgcHJldmlvdXMgZ3JvdXAgbmFtZS4KVGhlc2UgYXJlIGR5bmFtaWMg KHJ1bi10aW1lKSBvcGVyYXRpb25zLCBhbmQgYSBncm91cCBoYXMgbm8Kb3RoZXIgZWZmZWN0IG9y IGlkZW50aXR5LgpUZXN0IGdyb3VwcyBhcmUgaW5mb3JtYWwgZ3JvdXBpbmdzOiB0aGV5IGFyZSBu ZWl0aGVyClNjaGVtZSB2YWx1ZXMsIG5vciBhcmUgdGhleSBzeW50YWN0aWMgZm9ybXMuCkBjIChN b3JlIGZvcm1hbCA8cT50ZXN0IHN1aXRlPC9xPiB2YWx1ZXMgYXJlIGludHJvZHVjZWQgYmVsb3cu KQoKCkEgdGVzdCBncm91cCBtYXkgY29udGFpbiBuZXN0ZWQgaW5uZXIgdGVzdCBncm91cHMuClRo ZSBAZGZue3Rlc3QgZ3JvdXAgcGF0aH0gaXMgYSBsaXN0IG9mIHRoZSBjdXJyZW50bHktYWN0aXZl CihlbnRlcmVkKSB0ZXN0IGdyb3VwIG5hbWVzLCBvbGRlc3QgKG91dGVybW9zdCkgZmlyc3QuCgoK QGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LWJlZ2luIHN1aXRlLW5hbWUgW2NvdW50XQpA YyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9j YXRpb24KQGVuZCBkZWZmbgoKCkEgQGNvZGV7dGVzdC1iZWdpbn0gZW50ZXJzIGEgbmV3IHRlc3Qg Z3JvdXAuClRoZSBAdmFye3N1aXRlLW5hbWV9IGJlY29tZXMgdGhlIGN1cnJlbnQgdGVzdCBncm91 cCBuYW1lLAphbmQgaXMgYWRkZWQgdG8gdGhlIGVuZCBvZiB0aGUgdGVzdCBncm91cCBwYXRoLgpQ b3J0YWJsZSB0ZXN0IHN1aXRlcyBzaG91bGQgdXNlIGEgc3RyaW5nIGxpdGVyYWwgZm9yIEB2YXJ7 c3VpdGUtbmFtZX07CnRoZSBlZmZlY3Qgb2YgZXhwcmVzc2lvbnMgb3Igb3RoZXIga2luZHMgb2Yg bGl0ZXJhbHMgaXMgdW5zcGVjaWZpZWQuCgpAYntSYXRpb25hbGU6fSBJbiBzb21lIHdheXMgdXNp bmcgc3ltYm9scyB3b3VsZCBiZSBwcmVmZXJhYmxlLgpIb3dldmVyLCB3ZSB3YW50IGh1bWFuLXJl YWRhYmxlIG5hbWVzLCBhbmQgc3RhbmRhcmQgU2NoZW1lIGRvZXMgbm90CnByb3ZpZGUgYSB3YXkg dG8gaW5jbHVkZSBzcGFjZXMgb3IgbWl4ZWQtY2FzZSB0ZXh0IGluCmxpdGVyYWwgc3ltYm9scy4K ClRoZSBvcHRpb25hbCBAdmFye2NvdW50fSBtdXN0IG1hdGNoIHRoZSBudW1iZXIgb2YKdGVzdC1j YXNlcyBleGVjdXRlZCBieSB0aGlzIGdyb3VwLgooTmVzdGVkIHRlc3QgZ3JvdXBzIGNvdW50IGFz IGEgc2luZ2xlIHRlc3QgY2FzZSBmb3IgdGhpcyBjb3VudC4pClRoaXMgZXh0cmEgdGVzdCBtYXkg YmUgdXNlZnVsIHRvIGNhdGNoIGNhc2VzIHdoZXJlIGEgdGVzdCBkb2Vzbid0CmdldCBleGVjdXRl ZCBiZWNhdXNlIG9mIHNvbWUgdW5leHBlY3RlZCBlcnJvci4KCkFkZGl0aW9uYWxseSwgaWYgdGhl cmUgaXMgbm8gY3VycmVudGx5IGV4ZWN1dGluZyB0ZXN0IHJ1bm5lciwKb25lIGlzIGluc3RhbGxl ZCBpbiBhbiBpbXBsZW1lbnRhdGlvbi1kZWZpbmVkIG1hbm5lci4KCgpAZGVmZm4ge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtZW5kIFtzdWl0ZS1uYW1lXQpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0 ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCkEgQGNv ZGV7dGVzdC1lbmR9IGxlYXZlcyB0aGUgY3VycmVudCB0ZXN0IGdyb3VwLgpBbiBlcnJvciBpcyBy ZXBvcnRlZCBpZiB0aGUgQHZhcntzdWl0ZS1uYW1lfSBkb2VzIG5vdAptYXRjaCB0aGUgY3VycmVu dCB0ZXN0IGdyb3VwIG5hbWUuCkBjIElmIGl0IGRvZXMgbWF0Y2ggYW4gZWFybGllcgpAYyBuYW1l IGluIHRoZSB0ZXN0IGdyb3VwIHBhdGgsIGludGVydmVuaW5nIGdyb3VwcyBhcmUgbGVmdC4KCgoK QWRkaXRpb25hbGx5LCBpZiB0aGUgbWF0Y2hpbmcgQGNvZGV7dGVzdC1iZWdpbn1pbnN0YWxsZWQg YSBuZXcgdGVzdC1ydW5uZXIsIHRoZW4gdGhlIEBjb2Rle3Rlc3QtZW5kfXdpbGwgdW5pbnN0YWxs IGl0LCBhZnRlciByZXBvcnRpbmcgdGhlIGFjY3VtdWxhdGVkIHRlc3QKcmVzdWx0cyBpbiBhbiBp bXBsZW1lbnRhdGlvbi1kZWZpbmVkIG1hbm5lci4KCkBsaXNwCihAYnt0ZXN0LWdyb3VwfUB2YXJ7 c3VpdGUtbmFtZX1AdmFye2RlY2wtb3ItZXhwcn0gQGRvdHN7fSkKQGVuZCBsaXNwCgpFcXVpdmFs ZW50IHRvOgoKQGxpc3AKKGlmIChub3QgKHRlc3QtdG8tc2tpcCUgQHZhcntzdWl0ZS1uYW1lfSkp CiAgKGR5bmFtaWMtd2luZAogICAgKGxhbWJkYSAoKSAodGVzdC1iZWdpbiBAdmFye3N1aXRlLW5h bWV9KSkKICAgIChsYW1iZGEgKCkgQHZhcntkZWNsLW9yLWV4cHJ9IEBkb3Rze30pCiAgICAobGFt YmRhICgpICh0ZXN0LWVuZCBAdmFye3N1aXRlLW5hbWV9KSkpKQpAZW5kIGxpc3AKClRoaXMgaXMg dXN1YWxseSBlcXVpdmFsZW50IHRvIGV4ZWN1dGluZyB0aGUgQHZhcntkZWNsLW9yLWV4cHJ9cwp3 aXRoaW4gdGhlIG5hbWVkIHRlc3QgZ3JvdXAuICBIb3dldmVyLCB0aGUgZW50aXJlIGdyb3VwIGlz IHNraXBwZWQKaWYgaXQgbWF0Y2hlZCBhbiBhY3RpdmUgQGNvZGV7dGVzdC1za2lwfSAoc2VlIGxh dGVyKS4KQWxzbywgdGhlIEBjb2Rle3Rlc3QtZW5kfSBpcyBleGVjdXRlZCBpbiBjYXNlIG9mIGFu IGV4Y2VwdGlvbi4KCkBzdWJzdWJoZWFkaW5nIEhhbmRsaW5nIHNldC11cCBhbmQgY2xlYW51cAoK CgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtZ3JvdXAtd2l0aC1jbGVhbnVwIHN1aXRl LW5hbWUgZGVjbC1vci1leHByIEBkb3Rze30gY2xlYW51cC1mb3JtCkBjIEZJWE1FOiBDaGVjayBk ZWZmbiBjYXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBsb2NhdGlvbgpAZW5kIGRlZmZu CgoKRXhlY3V0ZSBlYWNoIG9mIHRoZSBAdmFye2RlY2wtb3ItZXhwcn0gZm9ybXMgaW4gb3JkZXIK KGFzIGluIGEgQHZhcns8Ym9keT59KSwKYW5kIHRoZW4gZXhlY3V0ZSB0aGUgQHZhcntjbGVhbnVw LWZvcm19VGhlIGxhdHRlciBzaG91bGQgYmUgZXhlY3V0ZWQgZXZlbiBpZgpvbmUgb2YgYSBAdmFy e2RlY2wtb3ItZXhwcn0gZm9ybXMgcmFpc2VzIGFuIGV4Y2VwdGlvbgooYXNzdW1pbmcgdGhlIGlt cGxlbWVudGF0aW9uIGhhcyBhIHdheSB0byBjYXRjaCBleGNlcHRpb25zKS4KCkZvciBleGFtcGxl OgoKQGxpc3AKKGxldCAoKGYgKG9wZW4tb3V0cHV0LWZpbGUgImxvZyIpKSkKICAodGVzdC1ncm91 cC13aXRoLWNsZWFudXAgInRlc3QtZmlsZSIKICAgIChkby1hLWJ1bmNoLW9mLXRlc3RzIGYpCiAg ICAoY2xvc2Utb3V0cHV0LXBvcnQgZikpKQpAZW5kIGxpc3AKCkBie0VycmF0dW0gbm90ZTp9QHVy bHtodHRwczovL2dpdGh1Yi5jb20vc2NoZW1lLXJlcXVlc3RzLWZvci1pbXBsZW1lbnRhdGlvbi9z cmZpLTY0L2Jsb2IvNDQ3MGZmZGVjNzFiMWNmNjE2MzNiNjY0OTU4YTNjZTVlNjk5NzcxMC9zcmZp LTY0Lmh0bWwsIEVhcmxpZXIgdmVyc2lvbnN9IGhhZCBhIG5vbi13b3JraW5nIGV4YW1wbGUuCgpA YyA8aDM+VGVzdCBzdWl0ZXM8L2gzPgpAYyA8cD4KQGMgPGk+KE5vdCBzdXJlIGhvdyB1c2VmdWwg dGhpcyBpcywgZ2l2ZW4gPGNvZGU+dGVzdC1ncm91cDwvY29kZT4pLjwvaT4KQGMgPHA+QSA8ZGZu PnRlc3Qgc3VpdGU8L2Rmbj4gaXMgYSB0ZXN0IGdyb3VwIHRoYXQgY2FuIChhbmQgbXVzdCkgYmUK QGMgZXhlY3V0ZWQgZXhwbGljaXRseS4KQGMgPHByZT4KQGMgKHRlc3Qtc3VpdGUgPHZhcj5zdWl0 ZS1uYW1lPC92YXI+IDx2YXI+ZGVjbC1vci1leHByPC92YXI+IEBkb3Rze30pCkBjIDwvcHJlPgpA YyA8cD4KQGMgVGhlIDxkZj50ZXN0IHN1aXRlIHBhdGg8L2Rmbj4gaXMgdGhlIGxpc3Qgb2YgbmFt ZXMgb2YgY3VycmVudGx5CkBjIHJ1bm5pbmcgdGVzdHN1aXRlcywgZnJvbSBvdXRlcm1vc3QgKG9s ZGVzdCkgdG8gaW5uZXJtb3N0IChuZXdlc3QpLgpAYyA8cD5BIDxjb2RlPnRlc3Qtc3VpdGU8L2Nv ZGU+IGZvcm0gaXMgZXF1aXZhbGVudCB0bzoKQGMgPHByZT4KQGMgKHRlc3Qtc3VpdGUtcmVnaXN0 ZXIgPHZhcj5zdWl0ZS1uYW1lPC92YXI+CkBjICAgKHRlc3QtZ3JvdXAgPHZhcj5zdWl0ZS1uYW1l PC92YXI+IDx2YXI+ZGVjbC1vci1leHByPC92YXI+IEBkb3Rze30pKQpAYyA8L3ByZT4KQGMgWW91 IGNhbiBydW4gcHJldmlvdXNseSByZWdpc3RlcmVkIHRlc3Qgc3VpdGU6CkBjIDxwcmU+CkBjICh0 ZXN0LXN1aXRlLXJ1biA8dmFyPnN1aXRlLW5hbWU8L3Zhcj4pCkBjIDwvcHJlPgoKCkBub2RlIFNS RkkgNjQgQ29uZGl0b25hbCB0ZXN0LXN1aXRlcyBhbmQgb3RoZXIgYWR2YW5jZWQgZmVhdHVyZXMK QHN1YnN1YnNlY3Rpb24gU1JGSSA2NCBDb25kaXRvbmFsIHRlc3Qtc3VpdGVzIGFuZCBvdGhlciBh ZHZhbmNlZCBmZWF0dXJlcwoKClRoZSBmb2xsb3dpbmcgZGVzY3JpYmVzIGZlYXR1cmVzIGZvciBj b250cm9sbGluZyB3aGljaCB0ZXN0cyB0byBleGVjdXRlLApvciBzcGVjaWZ5aW5nIHRoYXQgc29t ZSB0ZXN0cyBhcmUgQGVtcGh7ZXhwZWN0ZWR9IHRvIGZhaWwuCgpAc3Vic3ViaGVhZGluZyBUZXN0 IHNwZWNpZmllcnMKCgpTb21ldGltZXMgd2Ugd2FudCB0byBvbmx5IHJ1biBjZXJ0YWluIHRlc3Rz LCBvciB3ZSBrbm93IHRoYXQKY2VydGFpbiB0ZXN0cyBhcmUgZXhwZWN0ZWQgdG8gZmFpbC4KQSBA ZGZue3Rlc3Qgc3BlY2lmaWVyfSBpcyBvbmUtYXJndW1lbnQgZnVuY3Rpb24gdGhhdCB0YWtlcyBh IHRlc3QtcnVubmVyCmFuZCByZXR1cm5zIGEgYm9vbGVhbi4gIFRoZSBzcGVjaWZpZXIgbWF5IGJl IHJ1biBiZWZvcmUgYSB0ZXN0IGlzIHBlcmZvcm1lZCwKYW5kIHRoZSByZXN1bHQgbWF5IGNvbnRy b2wgd2hldGhlciB0aGUgdGVzdCBpcyBleGVjdXRlZC4KRm9yIGNvbnZlbmllbmNlLCBhIHNwZWNp ZmllciBtYXkgYWxzbyBiZSBhIG5vbi1wcm9jZWR1cmUgdmFsdWUsCndoaWNoIGlzIGNvZXJjZWQg dG8gYSBzcGVjaWZpZXIgcHJvY2VkdXJlLCBhcyBkZXNjcmliZWQgYmVsb3cgZm9yCkB2YXJ7Y291 bnR9IGFuZCBAdmFye25hbWV9LgoKQSBzaW1wbGUgZXhhbXBsZSBpczoKCkBsaXNwCihpZiBAdmFy e3NvbWUtY29uZGl0aW9ufSAgKHRlc3Qtc2tpcCAyKSkgOzsgc2tpcCBuZXh0IDIgdGVzdHMKQGVu ZCBsaXNwCgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LW1hdGNoLW5hbWUgbmFtZQoK VGhlIHJlc3VsdGluZyBzcGVjaWZpZXIgbWF0Y2hlcyBpZiB0aGUgY3VycmVudCB0ZXN0IG5hbWUg KGFzcmV0dXJuZWQgYnlAY29kZXt0ZXN0LXJ1bm5lci10ZXN0LW5hbWV9KSBpc0Bjb2Rle2VxdWFs P310b25hbWUuCkBlbmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtbWF0 Y2gtbnRoIG4gW2NvdW50XQoKVGhpcyBldmFsdWF0ZXMgdG8gYUBlbXBoe3N0YXRlZnVsfXByZWRp Y2F0ZTogQSBjb3VudGVyIGtlZXBzIHRyYWNrIG9maG93IG1hbnkgdGltZXMgaXQgaGFzIGJlZW4g Y2FsbGVkLlRoZSBwcmVkaWNhdGUgbWF0Y2hlcyB0aGVuJ3RoIHRpbWUgaXQgaXMgY2FsbGVkKHdo ZXJlQGNvZGV7MX1pcyB0aGUgZmlyc3QgdGltZSksIGFuZHRoZSBuZXh0CkBjIEZJWE1FOiBDaGVj ayBkZWZmbiBjYXRlZ29yeSBhbmQgYWRqdXN0ICdAZW5kIGRlZmZuJyBsb2NhdGlvbgpAZW5kIGRl ZmZuCgoKQGMgRklYTUU6IENoZWNrIGRlZmZuIGNhdGVnb3J5IGFuZCBhZGp1c3QgJ0BlbmQgZGVm Zm4nIGxvY2F0aW9uCkBlbmQgZGVmZm4KCgpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0ZWdvcnkg YW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCkB2YXJ7Y291bnR9 QGl7KGkuZS4gYW4gaW50ZWdlcil9CkNvbnZlbmllbmNlIHNob3J0LWhhbmQgZm9yOiBAY29kZXso dGVzdC1tYXRjaC1udGggMSBAdmFye2NvdW50fSl9LgoKQHZhcntuYW1lfUBpeyhpLmUuIGEgc3Ry aW5nKX0KQ29udmVuaWVuY2Ugc2hvcnQtaGFuZCBmb3IgQGNvZGV7KHRlc3QtbWF0Y2gtbmFtZSBA dmFye25hbWV9KX0uCgpAc3Vic3ViaGVhZGluZyBTa2lwcGluZyBzZWxlY3RlZCB0ZXN0cwoKCklu IHNvbWUgY2FzZXMgeW91IG1heSB3YW50IHRvIHNraXAgYSB0ZXN0LgoKCkBkZWZmbiB7U2NoZW1l IFByb2NlZHVyZX0gdGVzdC1za2lwIHNwZWNpZmllcgpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0 ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCkV2YWx1 YXRpbmcgQGNvZGV7dGVzdC1za2lwfSBhZGRzIHRoZQpyZXN1bHRpbmcgQHZhcntzcGVjaWZpZXJ9 dG8gdGhlIHNldCBvZiBjdXJyZW50bHkgYWN0aXZlIHNraXAtc3BlY2lmaWVycy4KQmVmb3JlIGVh Y2ggdGVzdCAob3IgQGNvZGV7dGVzdC1ncm91cH0pCnRoZSBzZXQgb2YgYWN0aXZlIHNraXAtc3Bl Y2lmaWVycyBhcmUgYXBwbGllZCB0byB0aGUgYWN0aXZlIHRlc3QtcnVubmVyLgpJZiBhbnkgc3Bl Y2lmaWVyIG1hdGNoZXMsIHRoZW4gdGhlIHRlc3QgaXMgc2tpcHBlZC4KCkZvciBjb252ZW5pZW5j ZSwgaWYgdGhlIEB2YXJ7c3BlY2lmaWVyfSBpcyBhIHN0cmluZyB0aGF0CmlzIHN5bnRhY3RpYyBz dWdhciBmb3IgQGNvZGV7KHRlc3QtbWF0Y2gtbmFtZSBAdmFye3NwZWNpZmllcn0pfUZvciBleGFt cGxlOgoKQGxpc3AKKHRlc3Qtc2tpcCAidGVzdC1iIikKKHRlc3QtYXNzZXJ0ICJ0ZXN0LWEiKSAg IDs7IGV4ZWN1dGVkCih0ZXN0LWFzc2VydCAidGVzdC1iIikgICA7OyBza2lwcGVkCkBlbmQgbGlz cAoKQW55IHNraXAgc3BlY2lmaWVycyBpbnRyb2R1Y2VkIGJ5IGEgQGNvZGV7dGVzdC1za2lwfWFy ZSByZW1vdmVkIGJ5IGEgZm9sbG93aW5nIG5vbi1uZXN0ZWQgQGNvZGV7dGVzdC1lbmR9LgoKQGxp c3AKKHRlc3QtYmVnaW4gImdyb3VwMSIpCih0ZXN0LXNraXAgInRlc3QtYSIpCih0ZXN0LWFzc2Vy dCAidGVzdC1hIikgICA7OyBza2lwcGVkCih0ZXN0LWVuZCAiZ3JvdXAxIikgICAgICA7OyBVbmRv ZXMgdGhlIHByaW9yIHRlc3Qtc2tpcAoodGVzdC1hc3NlcnQgInRlc3QtYSIpICAgOzsgZXhlY3V0 ZWQKQGVuZCBsaXNwCgpAc3Vic3ViaGVhZGluZyBFeHBlY3RlZCBmYWlsdXJlcwoKClNvbWV0aW1l cyB5b3Uga25vdyBhIHRlc3QgY2FzZSB3aWxsIGZhaWwsIGJ1dCB5b3UgZG9uJ3QgaGF2ZSB0aW1l CnRvIG9yIGNhbid0IGZpeCBpdC4gICBNYXliZSBhIGNlcnRhaW4gZmVhdHVyZSBvbmx5IHdvcmtz IG9uIGNlcnRhaW4gcGxhdGZvcm1zLgpIb3dldmVyLCB5b3Ugd2FudCB0aGUgdGVzdC1jYXNlIHRv IGJlIHRoZXJlCnRvIHJlbWluZCB5b3UgdG8gZml4IGl0LiAgWW91IHdhbnQgdG8gbm90ZSB0aGF0 CnN1Y2ggdGVzdHMgYXJlIGV4cGVjdGVkIHRvIGZhaWwuCgoKQGRlZmZuIHtTY2hlbWUgUHJvY2Vk dXJlfSB0ZXN0LWV4cGVjdC1mYWlsIHNwZWNpZmllcgpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0 ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCk1hdGNo aW5nIHRlc3RzICh3aGVyZSBtYXRjaGluZyBpcyBkZWZpbmVkIGFzIGluIEBjb2Rle3Rlc3Qtc2tp cH0pCmFyZSBleHBlY3RlZCB0byBmYWlsLiAgVGhpcyBvbmx5IGFmZmVjdHMgdGVzdCByZXBvcnRp bmcsCm5vdCB0ZXN0IGV4ZWN1dGlvbi4gIEZvciBleGFtcGxlOgoKQGxpc3AKKHRlc3QtZXhwZWN0 LWZhaWwgMikKKHRlc3QtZXF2IEBkb3Rze30pIDs7IGV4cGVjdGVkIHRvIGZhaWwKKHRlc3QtZXF2 IEBkb3Rze30pIDs7IGV4cGVjdGVkIHRvIGZhaWwKKHRlc3QtZXF2IEBkb3Rze30pIDs7IGV4cGVj dGVkIHRvIHBhc3MKQGVuZCBsaXNwCgpAbm9kZSBTUkZJIDY0IFRlc3QtcnVubmVyCkBzdWJzdWJz ZWN0aW9uIFNSRkkgNjQgVGVzdC1ydW5uZXIKCgpBIEBkZm57dGVzdC1ydW5uZXJ9IGlzIGFuIG9i amVjdCB0aGF0IHJ1bnMgYSB0ZXN0LXN1aXRlLAphbmQgbWFuYWdlcyB0aGUgc3RhdGUuICBUaGUg dGVzdCBncm91cCBwYXRoLCBhbmQgdGhlIHNldHMgc2tpcCBhbmQKZXhwZWN0ZWQtZmFpbCBzcGVj aWZpZXJzIGFyZSBwYXJ0IG9mIHRoZSB0ZXN0LXJ1bm5lci4KQSB0ZXN0LXJ1bm5lciB3aWxsIGFs c28gdHlwaWNhbGx5IGFjY3VtdWxhdGUgc3RhdGlzdGljcyBhYm91dCBleGVjdXRlZCB0ZXN0cy4K CgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lcj8gdmFsdWUKClRydWUgaWZm QGNvZGV7dmFsdWV9aXMgYSB0ZXN0LXJ1bm5lciBvYmplY3QuCkBlbmQgZGVmZm4KCgpAZGVmZm4g e1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWN1cnJlbnQKCkBkZWZmbngge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtcnVubmVyLWN1cnJlbnQgcnVubmVyCgpHZXQgb3Igc2V0IHRoZSBjdXJy ZW50IHRlc3QtcnVubmVyLklmIGFuIGltcGxlbWVudGF0aW9uIHN1cHBvcnRzIHBhcmFtZXRlciBv YmplY3RzKGFzIGluQHVybHtodHRwczovL3NyZmkuc2NoZW1lcnMub3JnL3NyZmktMzkvc3JmaS0z OS5odG1sLCBTUkZJLTM5fSksdGhlbkBjb2Rle3Rlc3QtcnVubmVyLWN1cnJlbnR9Y2FuIGJlIGEg cGFyYW1ldGVyIG9iamVjdC5BbHRlcm5hdGl2ZWx5LEBjb2Rle3Rlc3QtcnVubmVyLWN1cnJlbnR9 bWF5IGJlIGltcGxlbWVudGVkYXMgYSBtYWNybyBvciBmdW5jdGlvbnRoYXQgdXNlcyBhIGZsdWlk IG9yIHRocmVhZC1sb2NhbCB2YXJpYWJsZSwgb3IgYSBwbGFpbiBnbG9iYWwgdmFyaWFibGUuCkBl bmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWdldAoKU2Ft ZSBhcwpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZm bicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3Qt cnVubmVyLXNpbXBsZQoKQ3JlYXRlcyBhIG5ldyBzaW1wbGUgdGVzdC1ydW5uZXIsIHRoYXQgcHJp bnRzIGVycm9ycyBhbmQgYSBzdW1tYXJ5b24gdGhlIHN0YW5kYXJkIG91dHB1dCBwb3J0LgpAZW5k IGRlZmZuCgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1udWxsCgpDcmVh dGVzIGEgbmV3IHRlc3QtcnVubmVyLCB0aGF0IGRvZXMgbm90aGluZyB3aXRoIHRoZSB0ZXN0IHJl c3VsdHMuVGhpcyBpcyBtYWlubHkgbWVhbnQgZm9yIGV4dGVuZGluZyB3aGVuIHdyaXRpbmcgYSBj dXN0b20gcnVubmVyLgpAZW5kIGRlZmZuCgpJbXBsZW1lbnRhdGlvbnMgQGVtcGh7bWF5fSBwcm92 aWRlIG90aGVyIHRlc3QtcnVubmVycywgcGVyaGFwcwphIEBjb2Rleyh0ZXN0LXJ1bm5lci1ndWkp fS4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWNyZWF0ZQoKQ3JlYXRl IGEgbmV3IHRlc3QtcnVubmVyLiAgRXF1aXZhbGVudCB0bwpAYyBGSVhNRTogQ2hlY2sgZGVmZm4g Y2F0ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCgpA ZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWZhY3RvcnkKCkBkZWZmbngge1Nj aGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWZhY3RvcnkgZmFjdG9yeQoKR2V0IG9yIHNldCB0 aGUgY3VycmVudCB0ZXN0LXJ1bm5lciBmYWN0b3J5LkEgZmFjdG9yeSBpcyBhIHplcm8tYXJndW1l bnQgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGEgbmV3IHRlc3QtcnVubmVyLlRoZSBkZWZhdWx0IHZh bHVlIGlzQGNvZGV7dGVzdC1ydW5uZXItc2ltcGxlfSxidXQgaW1wbGVtZW50YXRpb25zIG1heSBw cm92aWRlIGEgd2F5IHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0LkFzIHdpdGhAY29kZXt0ZXN0LXJ1 bm5lci1jdXJyZW50fSwgdGhpcyBtYXkgYmUgYSBwYXJhbWV0ZXIgb2JqZWN0LG9yIHVzZSBhIHBl ci10aHJlYWQsIGZsdWlkLCBvciBnbG9iYWwgdmFyaWFibGUuCkBlbmQgZGVmZm4KCkBzdWJzdWJo ZWFkaW5nIFJ1bm5pbmcgc3BlY2lmaWMgdGVzdHMgd2l0aCBhIHNwZWNpZmllZCBydW5uZXIKCgoK QGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LWFwcGx5IFtydW5uZXJdIHNwZWNpZmllciBA ZG90c3t9IHByb2NlZHVyZQoKQ2FsbHNwcm9jZWR1cmV3aXRoIG5vIGFyZ3VtZW50cyB1c2luZyB0 aGUgc3BlY2lmaWVkcnVubmVyYXMgdGhlIGN1cnJlbnQgdGVzdC1ydW5uZXIuSWZydW5uZXJpcyBv bWl0dGVkLHRoZW4KQGMgRklYTUU6IENoZWNrIGRlZmZuIGNhdGVnb3J5IGFuZCBhZGp1c3QgJ0Bl bmQgZGVmZm4nIGxvY2F0aW9uCkBlbmQgZGVmZm4KCgpAYyBGSVhNRTogQ2hlY2sgZGVmZm4gY2F0 ZWdvcnkgYW5kIGFkanVzdCAnQGVuZCBkZWZmbicgbG9jYXRpb24KQGVuZCBkZWZmbgoKCkBub2Rl IFNSRkkgNjQgVGVzdCByZXN1bHRzCkBzdWJzdWJzZWN0aW9uIFNSRkkgNjQgVGVzdCByZXN1bHRz CgoKUnVubmluZyBhIHRlc3Qgc2V0cyB2YXJpb3VzIHN0YXR1cyBwcm9wZXJ0aWVzIGluIHRoZSBj dXJyZW50IHRlc3QtcnVubmVyLgpUaGlzIGNhbiBiZSBleGFtaW5lZCBieSBhIGN1c3RvbSB0ZXN0 LXJ1bm5lciwKb3IgKG1vcmUgcmFyZWx5KSBpbiBhIHRlc3Qtc3VpdGUuCgpAc3Vic3ViaGVhZGlu ZyBSZXN1bHQga2luZAoKClJ1bm5pbmcgYSB0ZXN0IG1heSB5aWVsZCBvbmUgb2YgdGhlIGZvbGxv d2luZwpzdGF0dXMgc3ltYm9sczoKQHRhYmxlIEBhc2lzCkBpdGVtIEBjb2RleydwYXNzfQpUaGUg dGVzdCBwYXNzZWQsIGFzIGV4cGVjdGVkLgoKQGl0ZW0gQGNvZGV7J2ZhaWx9ClRoZSB0ZXN0IGZh aWxlZCAoYW5kIHdhcyBub3QgZXhwZWN0ZWQgdG8pLgoKQGl0ZW0gQGNvZGV7J3hmYWlsfQpUaGUg dGVzdCBmYWlsZWQgYW5kIHdhcyBleHBlY3RlZCB0by4KCkBpdGVtIEBjb2Rleyd4cGFzc30KVGhl IHRlc3QgcGFzc2VkLCBidXQgd2FzIGV4cGVjdGVkIHRvIGZhaWwuCgpAaXRlbSBAY29kZXsnc2tp cH0KVGhlIHRlc3Qgd2FzIHNraXBwZWQuCgpAZW5kIHRhYmxlCgoKQGRlZmZuIHtTY2hlbWUgUHJv Y2VkdXJlfSB0ZXN0LXJlc3VsdC1raW5kIFtydW5uZXJdCgpSZXR1cm5zIG9uZSBvZiB0aGUgYWJv dmUgcmVzdWx0IGNvZGVzIGZyb20gdGhlIG1vc3QgcmVjZW50IHRlc3RzLlJldHVybnNAY29kZXsj Zn1pZiBubyB0ZXN0cyBoYXZlIGJlZW4gcnVuIHlldC5JZiB3ZSd2ZSBzdGFydGVkIG9uIGEgbmV3 IHRlc3QsIGJ1dCBkb24ndCBoYXZlIGEgcmVzdWx0IHlldCx0aGVuIHRoZSByZXN1bHQga2luZCBp c0Bjb2Rleyd4ZmFpbH1pZiB0aGUgdGVzdCBpcyBleHBlY3RlZCB0byBmYWlsLEBjb2Rleydza2lw fWlmIHRoZSB0ZXN0IGlzIHN1cHBvc2VkIHRvIGJlIHNraXBwZWQsb3JAY29kZXsjZn1vdGhlcndp c2UuCkBlbmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcGFzc2VkPyBb cnVubmVyXQoKVHJ1ZSBpZiB0aGUgdmFsdWUgb2YKCkBkZWZmbngge1NjaGVtZSBQcm9jZWR1cmV9 IHRlc3QtcmVzdWx0LWtpbmQgW3J1bm5lcl0KCmlzIG9uZSBvZkBjb2RleydwYXNzfW9yQGNvZGV7 J3hwYXNzfVRoaXMgaXMgYSBjb252ZW5pZW50IHNob3J0aGFuZCB0aGF0IG1pZ2h0IGJlIHVzZWZ1 bGluIGEgdGVzdCBzdWl0ZSB0byBvbmx5IHJ1biBjZXJ0YWluIHRlc3RzIGlmIHRoZSBwcmV2aW91 cyB0ZXN0IHBhc3NlZC4KQGVuZCBkZWZmbgoKQHN1YnN1YmhlYWRpbmcgVGVzdCByZXN1bHQgcHJv cGVydGllcwoKCkEgdGVzdCBydW5uZXIgYWxzbyBtYWludGFpbnMgYSBzZXQgb2YgbW9yZSBkZXRh aWxlZCBgYHJlc3VsdCBwcm9wZXJ0aWVzJydhc3NvY2lhdGVkIHdpdGggdGhlIGN1cnJlbnQgb3Ig bW9zdCByZWNlbnQgdGVzdC4gIChJLmUuIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZQptb3N0IHJlY2Vu dCB0ZXN0IGFyZSBhdmFpbGFibGUgYXMgbG9uZyBhcyBhIG5ldyB0ZXN0IGhhc24ndCBzdGFydGVk LikKRWFjaCBwcm9wZXJ0eSBoYXMgYSBuYW1lIChhIHN5bWJvbCkgYW5kIGEgdmFsdWUgKGFueSB2 YWx1ZSkuClNvbWUgcHJvcGVydGllcyBhcmUgc3RhbmRhcmQgb3Igc2V0IGJ5IHRoZSBpbXBsZW1l bnRhdGlvbjsKaW1wbGVtZW50YXRpb25zIGNhbiBhZGQgbW9yZS4KCgpAZGVmZm4ge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtcmVzdWx0LXJlZiBydW5uZXIgJyBwbmFtZSBbZGVmYXVsdF0KClJldHVy bnMgdGhlIHByb3BlcnR5IHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGVwbmFtZXByb3BlcnR5IG5h bWUuSWYgdGhlcmUgaXMgbm8gdmFsdWUgYXNzb2NpYXRlZCB3aXRoQGNvZGV7J3BuYW1lfXJldHVy bmRlZmF1bHQsb3JAY29kZXsjZn1pZmRlZmF1bHRpc24ndCBzcGVjaWZpZWQuCkBlbmQgZGVmZm4K CgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcmVzdWx0LXNldCEgcnVubmVyICcgcG5h bWUgdmFsdWUKClNldHMgdGhlIHByb3BlcnR5IHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGVwbmFt ZXByb3BlcnR5IG5hbWUgdG92YWx1ZVVzdWFsbHkgaW1wbGVtZW50YXRpb24gY29kZSBzaG91bGQg Y2FsbCB0aGlzIGZ1bmN0aW9uLCBidXQgaXQgbWF5IGJldXNlZnVsIGZvciBhIGN1c3RvbSB0ZXN0 LXJ1bm5lciB0byBhZGQgZXh0cmEgcHJvcGVydGllcy4KQGVuZCBkZWZmbgoKCkBkZWZmbiB7U2No ZW1lIFByb2NlZHVyZX0gdGVzdC1yZXN1bHQtcmVtb3ZlIHJ1bm5lciAnIHBuYW1lCgpSZW1vdmUg dGhlIHByb3BlcnR5IHdpdGggdGhlIG5hbWVAY29kZXsncG5hbWV9LgpAZW5kIGRlZmZuCgoKQGRl ZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJlc3VsdC1jbGVhciBydW5uZXIKClJlbW92ZSBh bGwgcmVzdWx0IHByb3BlcnRpZXMuVGhlIGltcGxlbWVudGF0aW9uIGF1dG9tYXRpY2FsbHkgY2Fs bHNAY29kZXt0ZXN0LXJlc3VsdC1jbGVhcn1hdCB0aGUgc3RhcnQgb2YgYUBjb2Rle3Rlc3QtYXNz ZXJ0fWFuZCBzaW1pbGFyIHByb2NlZHVyZXMuCkBlbmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtcmVzdWx0LWFsaXN0IHJ1bm5lcgoKUmV0dXJucyBhbiBhc3NvY2lhdGlv biBsaXN0IG9mIHRoZSBjdXJyZW50IHJlc3VsdCBwcm9wZXJ0aWVzLkl0IGlzIHVuc3BlY2lmaWVk IGlmIHRoZSByZXN1bHQgc2hhcmVzIHN0YXRlIHdpdGggdGhlIHRlc3QtcnVubmVyLlRoZSByZXN1 bHQgc2hvdWxkIG5vdCBiZSBtb2RpZmllZDsgb24gdGhlIG90aGVyIGhhbmQsIHRoZSByZXN1bHRt YXkgYmUgaW1wbGljaXRseSBtb2RpZmllZCBieSBmdXR1cmVAY29kZXt0ZXN0LXJlc3VsdC1zZXQh fW9yQGNvZGV7dGVzdC1yZXN1bHQtcmVtb3ZlfWNhbGxzLkhvd2V2ZXIsIGFAY29kZXt0ZXN0LXJl c3VsdC1jbGVhcn1kb2VzIG5vdCBtb2RpZnkgdGhlIHJldHVybmVkYWxpc3QuICBUaHVzIHlvdSBj YW5gYGFyY2hpdmUnJ3Jlc3VsdCBvYmplY3RzIGZyb20gcHJldmlvdXMgcnVucy4KQGVuZCBkZWZm bgoKQHN1YnN1YmhlYWRpbmcgU3RhbmRhcmQgcmVzdWx0IHByb3BlcnRpZXMKCgpUaGUgc2V0IG9m IGF2YWlsYWJsZSByZXN1bHQgcHJvcGVydGllcyBpcyBpbXBsZW1lbnRhdGlvbi1zcGVjaWZpYy4K SG93ZXZlciwgaXQgaXMgc3VnZ2VzdGVkIHRoYXQgdGhlIGZvbGxvd2luZyBtaWdodCBiZSBwcm92 aWRlZDoKQHRhYmxlIEBhc2lzCkBpdGVtIEBjb2RleydyZXN1bHQta2luZH0KVGhlIHJlc3VsdCBr aW5kLCBhcyBkZWZpbmVkIHByZXZpb3VzbHkuClRoaXMgaXMgdGhlIG9ubHkgbWFuZGF0b3J5IHJl c3VsdCBwcm9wZXJ0eS4KQGNvZGV7KHRlc3QtcmVzdWx0LWtpbmQgQHZhcntydW5uZXJ9KX0gaXMg ZXF1aXZhbGVudCB0bzoKQGNvZGV7KHRlc3QtcmVzdWx0LXJlZiAgQHZhcntydW5uZXJ9ICdyZXN1 bHQta2luZCl9CgpAaXRlbSBAY29kZXsnc291cmNlLWZpbGV9CkBpdGVteCBAY29kZXsnc291cmNl LWxpbmV9CklmIGtub3duLCB0aGUgbG9jYXRpb24gb2YgdGVzdCBzdGF0ZW1lbnRzIChzdWNoIGFz IEBjb2Rle3Rlc3QtYXNzZXJ0fSkKaW4gdGVzdCBzdWl0ZSBzb3VyY2UgY29kZS4KCkBpdGVtIEBj b2Rleydzb3VyY2UtZm9ybX0KVGhlIHNvdXJjZSBmb3JtLCBpZiBtZWFuaW5nZnVsIGFuZCBrbm93 bi4KCkBpdGVtIEBjb2RleydleHBlY3RlZC12YWx1ZX0KVGhlIGV4cGVjdGVkIG5vbi1lcnJvciBy ZXN1bHQsIGlmIG1lYW5pbmdmdWwgYW5kIGtub3duLgoKQGl0ZW0gQGNvZGV7J2V4cGVjdGVkLWVy cm9yfQpUaGUgQHZhcntlcnJvci10eXBlfXNwZWNpZmllZCBpbiBhIEBjb2Rle3Rlc3QtZXJyb3J9 LCBpZiBpdCBtZWFuaW5nZnVsIGFuZCBrbm93bi4KCkBpdGVtIEBjb2RleydhY3R1YWwtdmFsdWV9 ClRoZSBhY3R1YWwgbm9uLWVycm9yIHJlc3VsdCB2YWx1ZSwgaWYgbWVhbmluZ2Z1bCBhbmQga25v d24uCgpAaXRlbSBAY29kZXsnYWN0dWFsLWVycm9yfQpUaGUgZXJyb3IgdmFsdWUsIGlmIGFuIGVy cm9yIHdhcyBzaWduYWxsZWQgYW5kIGl0IGlzIGtub3duLgpUaGUgYWN0dWFsIGVycm9yIHZhbHVl IGlzIGltcGxlbWVudGF0aW9uLWRlZmluZWQuCgpAZW5kIHRhYmxlCgpAbm9kZSBTUkZJIDY0IFdy aXRpbmcgYSBuZXcgdGVzdC1ydW5uZXIKQHN1YnN1YnNlY3Rpb24gU1JGSSA2NCBXcml0aW5nIGEg bmV3IHRlc3QtcnVubmVyCgoKVGhpcyBzZWN0aW9uIHNwZWNpZmllcyBob3cgdG8gd3JpdGUgYSB0 ZXN0LXJ1bm5lci4KSXQgY2FuIGJlIGlnbm9yZWQgaWYgeW91IGp1c3Qgd2FudCB0byB3cml0ZSB0 ZXN0LWNhc2VzLgoKQHN1YnN1YmhlYWRpbmcgQ2FsbC1iYWNrIGZ1bmN0aW9ucwoKClRoZXNlIGNh bGwtYmFjayBmdW5jdGlvbnMgYXJlIGBgbWV0aG9kcycnIChpbiB0aGUgb2JqZWN0LW9yaWVudGVk IHNlbnNlKQpvZiBhIHRlc3QtcnVubmVyLiBBIG1ldGhvZCBAY29kZXt0ZXN0LXJ1bm5lci1vbi1A dmFye2V2ZW50fX1pcyBjYWxsZWQgYnkgdGhlIGltcGxlbWVudGF0aW9uIHdoZW4gQHZhcntldmVu dH0gaGFwcGVucy4KClRvIGRlZmluZSAoc2V0KSB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gZm9yIEB2 YXJ7ZXZlbnR9IHVzZSB0aGUgZm9sbG93aW5nIGV4cHJlc3Npb24uCihUaGlzIGlzIG5vcm1hbGx5 IGRvbmUgd2hlbiBpbml0aWFsaXppbmcgYSB0ZXN0LXJ1bm5lci4pCgpAY29kZXsodGVzdC1ydW5u ZXItb24tQHZhcntldmVudH0hIEB2YXJ7cnVubmVyfUB2YXJ7ZXZlbnQtZnVuY3Rpb259KX0KCkFu IEB2YXJ7ZXZlbnQtZnVuY3Rpb259IHRha2VzIGEgdGVzdC1ydW5uZXIgYXJndW1lbnQsIGFuZCBw b3NzaWJseSBvdGhlciBhcmd1bWVudHMsIGRlcGVuZGluZyBvbiB0aGUgQHZhcntldmVudH0uCgpU byBleHRyYWN0IChnZXQpIHRoZSBjYWxsYmFjayBmdW5jdGlvbiBmb3IgQHZhcntldmVudH0gZG8g dGhpczoKQGNvZGV7KHRlc3QtcnVubmVyLW9uLUB2YXJ7ZXZlbnR9QHZhcntydW5uZXJ9KX0KClRv IGV4dHJhY3QgY2FsbCB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gZm9yIEB2YXJ7ZXZlbnR9IHVzZSB0 aGUgZm9sbG93aW5nIGV4cHJlc3Npb24uCihUaGlzIGlzIG5vcm1hbGx5IGRvbmUgYnkgdGhlIGlt cGxlbWVudGF0aW9uIGNvcmUuKQpAY29kZXsoKHRlc3QtcnVubmVyLW9uLUB2YXJ7ZXZlbnR9QHZh cntydW5uZXJ9KSBAdmFye3J1bm5lcn1AdmFye290aGVyLWFyZ3N9IEBkb3Rze30pfQoKVGhlIGZv bGxvd2luZyBjYWxsLWJhY2sgaG9va3MgYXJlIGF2YWlsYWJsZS4KCgpAZGVmZm4ge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLXRlc3QtYmVnaW4gcnVubmVyCgpAZGVmZm54IHtTY2hl bWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi10ZXN0LWJlZ2luISBydW5uZXIgb24tdGVzdC1i ZWdpbi1mdW5jdGlvbgoKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gIG9uLXRlc3QtYmVnaW4t ZnVuY3Rpb24gcnVubmVyCgpUaGVvbi10ZXN0LWJlZ2luLWZ1bmN0aW9uaXMgY2FsbGVkIGF0IHRo ZSBzdGFydCBvZiBhbmluZGl2aWR1YWwgdGVzdGNhc2UsIGJlZm9yZSB0aGUgdGVzdCBleHByZXNz aW9uIChhbmQgZXhwZWN0ZWQgdmFsdWUpIGFyZWV2YWx1YXRlZC4KQGVuZCBkZWZmbgoKCkBkZWZm biB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItb24tdGVzdC1lbmQgcnVubmVyCgpAZGVm Zm54IHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi10ZXN0LWVuZCEgcnVubmVyIG9u LXRlc3QtZW5kLWZ1bmN0aW9uCgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSAgb24tdGVzdC1l bmQtZnVuY3Rpb24gcnVubmVyCgpUaGVvbi10ZXN0LWVuZC1mdW5jdGlvbmlzIGNhbGxlZCBhdCB0 aGUgZW5kIG9mIGFuaW5kaXZpZHVhbCB0ZXN0Y2FzZSwgd2hlbiB0aGUgcmVzdWx0IG9mIHRoZSB0 ZXN0IGlzIGF2YWlsYWJsZS4KQGVuZCBkZWZmbgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0g dGVzdC1ydW5uZXItb24tZ3JvdXAtYmVnaW4gcnVubmVyCgpAZGVmZm54IHtTY2hlbWUgUHJvY2Vk dXJlfSB0ZXN0LXJ1bm5lci1vbi1ncm91cC1iZWdpbiEgcnVubmVyIG9uLWdyb3VwLWJlZ2luLWZ1 bmN0aW9uCgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSAgb24tZ3JvdXAtYmVnaW4tZnVuY3Rp b24gcnVubmVyIHN1aXRlLW5hbWUgY291bnQKClRoZW9uLWdyb3VwLWJlZ2luLWZ1bmN0aW9uaXMg Y2FsbGVkIGJ5IGFAY29kZXt0ZXN0LWJlZ2lufSxpbmNsdWRpbmcgYXQgdGhlIHN0YXJ0IG9mIGFA Y29kZXt0ZXN0LWdyb3VwfVRoZXN1aXRlLW5hbWVpcyBhIFNjaGVtZSBzdHJpbmcsYW5kY291bnRp cyBhbiBpbnRlZ2VyIG9yQGNvZGV7I2Z9LgpAZW5kIGRlZmZuCgoKQGRlZmZuIHtTY2hlbWUgUHJv Y2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi1ncm91cC1lbmQgcnVubmVyCgpAZGVmZm54IHtTY2hlbWUg UHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi1ncm91cC1lbmQhIHJ1bm5lciBvbi1ncm91cC1lbmQt ZnVuY3Rpb24KCkBkZWZmbngge1NjaGVtZSBQcm9jZWR1cmV9ICBvbi1ncm91cC1lbmQtZnVuY3Rp b24gcnVubmVyCgpUaGVvbi1ncm91cC1lbmQtZnVuY3Rpb25pcyBjYWxsZWQgYnkgYUBjb2Rle3Rl c3QtZW5kfSxpbmNsdWRpbmcgYXQgdGhlIGVuZCBvZiBhQGNvZGV7dGVzdC1ncm91cH0uCkBlbmQg ZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLWJhZC1jb3Vu dCBydW5uZXIKCkBkZWZmbngge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLWJhZC1j b3VudCEgcnVubmVyIG9uLWJhZC1jb3VudC1mdW5jdGlvbgoKQGRlZmZueCB7U2NoZW1lIFByb2Nl ZHVyZX0gIG9uLWJhZC1jb3VudC1mdW5jdGlvbiBydW5uZXIgYWN0dWFsLWNvdW50IGV4cGVjdGVk LWNvdW50CgpDYWxsZWQgZnJvbUBjb2Rle3Rlc3QtZW5kfShiZWZvcmUgdGhlb24tZ3JvdXAtZW5k LWZ1bmN0aW9uaXMgY2FsbGVkKSBpZiBhbmV4cGVjdGVkLWNvdW50d2FzIHNwZWNpZmllZCBieSB0 aGUgbWF0Y2hpbmdAY29kZXt0ZXN0LWJlZ2lufWFuZCB0aGVleHBlY3RlZC1jb3VudGRvZXMgbm90 IG1hdGNodGhlYWN0dWFsLWNvdW50b2YgdGVzdHMgYWN0dWFsbHkgZXhlY3V0ZWQgb3Igc2tpcHBl ZC4KQGVuZCBkZWZmbgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItb24t YmFkLWVuZC1uYW1lIHJ1bm5lcgoKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5u ZXItb24tYmFkLWVuZC1uYW1lISBydW5uZXIgb24tYmFkLWVuZC1uYW1lLWZ1bmN0aW9uCgpAZGVm Zm54IHtTY2hlbWUgUHJvY2VkdXJlfSAgb24tYmFkLWVuZC1uYW1lLWZ1bmN0aW9uIHJ1bm5lciBi ZWdpbi1uYW1lIGVuZC1uYW1lCgpDYWxsZWQgZnJvbUBjb2Rle3Rlc3QtZW5kfShiZWZvcmUgdGhl b24tZ3JvdXAtZW5kLWZ1bmN0aW9uaXMgY2FsbGVkKSBpZiBhc3VpdGUtbmFtZXdhcyBzcGVjaWZp ZWQsIGFuZCBpdCBkaWQgbm90IHRoYXQgdGhlbmFtZSBpbiB0aGUgbWF0Y2hpbmdAY29kZXt0ZXN0 LWJlZ2lufS4KQGVuZCBkZWZmbgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5u ZXItb24tZmluYWwgcnVubmVyCgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5l ci1vbi1maW5hbCEgcnVubmVyIG9uLWZpbmFsLWZ1bmN0aW9uCgpAZGVmZm54IHtTY2hlbWUgUHJv Y2VkdXJlfSAgb24tZmluYWwtZnVuY3Rpb24gcnVubmVyCgpUaGVvbi1maW5hbC1mdW5jdGlvbnRh a2VzIG9uZSBwYXJhbWV0ZXIgKGEgdGVzdC1ydW5uZXIpYW5kIHR5cGljYWxseSBkaXNwbGF5cyBh IHN1bW1hcnkgKGNvdW50KSBvZiB0aGUgdGVzdHMuVGhlb24tZmluYWwtZnVuY3Rpb25pcyBjYWxs ZWQgYWZ0ZXIgY2FsbGVkIHRoZW9uLWdyb3VwLWVuZC1mdW5jdGlvbmNvcnJlc3BvbmRpb25nIHRv IHRoZSBvdXRlcm1vc3RAY29kZXt0ZXN0LWVuZH1UaGUgZGVmYXVsdCB2YWx1ZSBpc0Bjb2Rle3Rl c3Qtb24tZmluYWwtc2ltcGxlfXdoaWNoIHdyaXRlc3RvIHRoZSBzdGFuZGFyZCBvdXRwdXQgcG9y dCB0aGUgbnVtYmVyIG9mIHRlc3RzIG9mIHRoZSB2YXJpb3VzIGtpbmRzLgpAZW5kIGRlZmZuCgoK VGhlIGRlZmF1bHQgdGVzdC1ydW5uZXIgcmV0dXJuZWQgYnlAY29kZXt0ZXN0LXJ1bm5lci1zaW1w bGV9dXNlcyB0aGUgZm9sbG93aW5nIGNhbGwtYmFjayBmdW5jdGlvbnM6CgpAZGVmZm4ge1NjaGVt ZSBQcm9jZWR1cmV9IHRlc3Qtb24tdGVzdC1iZWdpbi1zaW1wbGUgcnVubmVyCgpAZGVmZm54IHtT Y2hlbWUgUHJvY2VkdXJlfSB0ZXN0LW9uLXRlc3QtZW5kLXNpbXBsZSBydW5uZXIKCkBkZWZmbngg e1NjaGVtZSBQcm9jZWR1cmV9IHRlc3Qtb24tZ3JvdXAtYmVnaW4tc2ltcGxlIHJ1bm5lciBzdWl0 ZS1uYW1lIGNvdW50CgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LW9uLWdyb3VwLWVu ZC1zaW1wbGUgcnVubmVyCgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LW9uLWJhZC1j b3VudC1zaW1wbGUgcnVubmVyIGFjdHVhbC1jb3VudCBleHBlY3RlZC1jb3VudAoKQGRlZmZueCB7 U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1vbi1iYWQtZW5kLW5hbWUtc2ltcGxlIHJ1bm5lciBiZWdp bi1uYW1lIGVuZC1uYW1lCgpZb3UgY2FuIGNhbGwgdGhvc2UgaWYgeW91IHdhbnQgdG8gd3JpdGUg eW91ciBvd24gdGVzdC1ydW5uZXIuCkBlbmQgZGVmZm4KCkBzdWJzdWJoZWFkaW5nIFRlc3QtcnVu bmVyIGNvbXBvbmVudHMKCgpUaGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBhcmUgZm9yIGFjY2Vzc2lu ZyB0aGUgb3RoZXIgY29tcG9uZW50cyBvZiBhIHRlc3QtcnVubmVyLgpUaGV5IHdvdWxkIG5vcm1h bGx5IG9ubHkgYmUgdXNlZCB0byB3cml0ZSBhIG5ldyB0ZXN0LXJ1bm5lciBvcgphIG1hdGNoLXBy ZWRpY2F0ZS4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLXBhc3MtY291 bnQgcnVubmVyCgpSZXR1cm5zIHRoZSBudW1iZXIgb2YgdGVzdHMgdGhhdCBwYXNzZWQsIGFuZCB3 ZXJlIGV4cGVjdGVkIHRvIHBhc3MuCkBlbmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1 cmV9IHRlc3QtcnVubmVyLWZhaWwtY291bnQgcnVubmVyCgpSZXR1cm5zIHRoZSBudW1iZXIgb2Yg dGVzdHMgdGhhdCBmYWlsZWQsIGJ1dCB3ZXJlIGV4cGVjdGVkIHRvIHBhc3MuCkBlbmQgZGVmZm4K CgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLXhwYXNzLWNvdW50IHJ1bm5l cgoKUmV0dXJucyB0aGUgbnVtYmVyIG9mIHRlc3RzIHRoYXQgcGFzc2VkLCBidXQgd2VyZSBleHBl Y3RlZCB0byBmYWlsLgpAZW5kIGRlZmZuCgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0 LXJ1bm5lci14ZmFpbC1jb3VudCBydW5uZXIKClJldHVybnMgdGhlIG51bWJlciBvZiB0ZXN0cyB0 aGF0IGZhaWxlZCwgYW5kIHdlcmUgZXhwZWN0ZWQgdG8gcGFzcy4KQGVuZCBkZWZmbgoKCkBkZWZm biB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItc2tpcC1jb3VudCBydW5uZXIKClJldHVy bnMgdGhlIG51bWJlciBvZiB0ZXN0cyBvciB0ZXN0IGdyb3VwcyB0aGF0IHdlcmUgc2tpcHBlZC4K QGVuZCBkZWZmbgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItdGVzdC1u YW1lIHJ1bm5lcgoKUmV0dXJucyB0aGUgbmFtZSBvZiB0aGUgY3VycmVudCB0ZXN0IG9yIHRlc3Qg Z3JvdXAsIGFzIGEgc3RyaW5nLkR1cmluZyBleGVjdXRpb24gb2ZAY29kZXt0ZXN0LWJlZ2lufXRo aXMgaXMgdGhlIG5hbWUgb2YgdGhldGVzdCBncm91cDsgZHVyaW5nIHRoZSBleGVjdXRpb24gb2Yg YW4gYWN0dWFsIHRlc3QsIHRoaXMgaXMgdGhlIG5hbWVvZiB0aGUgdGVzdC1jYXNlLklmIG5vIG5h bWUgd2FzIHNwZWNpZmllZCwgdGhlIG5hbWUgaXMgdGhlIGVtcHR5IHN0cmluZy4KQGVuZCBkZWZm bgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItZ3JvdXAtcGF0aCBydW5u ZXIKCkEgbGlzdCBvZiBuYW1lcyBvZiBncm91cHMgd2UncmUgbmVzdGVkIGluLCB3aXRoIHRoZSBv dXRlcm1vc3QgZ3JvdXAgZmlyc3QuCkBlbmQgZGVmZm4KCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1 cmV9IHRlc3QtcnVubmVyLWdyb3VwLXN0YWNrIHJ1bm5lcgoKQSBsaXN0IG9mIG5hbWVzIG9mIGdy b3VwcyB3ZSdyZSBuZXN0ZWQgaW4sIHdpdGggdGhlIG91dGVybW9zdCBncm91cCBsYXN0LihUaGlz IGlzIG1vcmUgZWZmaWNpZW50IHRoYW5AY29kZXt0ZXN0LXJ1bm5lci1ncm91cC1wYXRofSxzaW5j ZSBpdCBkb2Vzbid0IHJlcXVpcmUgYW55IGNvcHlpbmcuKQpAZW5kIGRlZmZuCgoKQGRlZmZuIHtT Y2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1hdXgtdmFsdWUgcnVubmVyCgpAZGVmZm54IHtT Y2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1hdXgtdmFsdWUhIHJ1bm5lciBvbi10ZXN0CgpH ZXQgb3Igc2V0IHRoZUBjb2Rle2F1eC12YWx1ZX1maWVsZCBvZiBhIHRlc3QtcnVubmVyLlRoaXMg ZmllbGQgaXMgbm90IHVzZWQgYnkgdGhpcyBBUEkgb3IgdGhlQGNvZGV7dGVzdC1ydW5uZXItc2lt cGxlfXRlc3QtcnVubmVyLCBidXQgbWF5IGJlIHVzZWQgYnkgY3VzdG9tIHRlc3QtcnVubmVycyB0 byBzdG9yZSBleHRyYSBzdGF0ZS4KQGVuZCBkZWZmbgoKCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVy ZX0gdGVzdC1ydW5uZXItcmVzZXQgcnVubmVyCgpSZXNldHMgdGhlIHN0YXRlIG9mIHRoZXJ1bm5l cnRvIGl0cyBpbml0aWFsIHN0YXRlLgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBFeGFtcGxl CgoKVGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgc2ltcGxlIGN1c3RvbSB0ZXN0LXJ1bm5lci4KTG9h ZGluZyB0aGlzIHByb2dyYW0gYmVmb3JlIHJ1bm5pbmcgYSB0ZXN0LXN1aXRlIHdpbGwgaW5zdGFs bAppdCBhcyB0aGUgZGVmYXVsdCB0ZXN0IHJ1bm5lci4KCkBsaXNwCihkZWZpbmUgKG15LXNpbXBs ZS1ydW5uZXIgZmlsZW5hbWUpCiAgKGxldCAoKHJ1bm5lciAodGVzdC1ydW5uZXItbnVsbCkpCgko cG9ydCAob3Blbi1vdXRwdXQtZmlsZSBmaWxlbmFtZSkpCiAgICAgICAgKG51bS1wYXNzZWQgMCkK ICAgICAgICAobnVtLWZhaWxlZCAwKSkKICAgICh0ZXN0LXJ1bm5lci1vbi10ZXN0LWVuZCEgcnVu bmVyCiAgICAgIChsYW1iZGEgKHJ1bm5lcikKICAgICAgICAoY2FzZSAodGVzdC1yZXN1bHQta2lu ZCBydW5uZXIpCiAgICAgICAgICAoKHBhc3MgeHBhc3MpIChzZXQhIG51bS1wYXNzZWQgKCsgbnVt LXBhc3NlZCAxKSkpCiAgICAgICAgICAoKGZhaWwgeGZhaWwpIChzZXQhIG51bS1mYWlsZWQgKCsg bnVtLWZhaWxlZCAxKSkpCiAgICAgICAgICAoZWxzZSAjdCkpKSkKICAgICh0ZXN0LXJ1bm5lci1v bi1maW5hbCEgcnVubmVyCiAgICAgICAobGFtYmRhIChydW5uZXIpCiAgICAgICAgICAoZm9ybWF0 IHBvcnQgIlBhc3NpbmcgdGVzdHM6IH5kLn4lRmFpbGluZyB0ZXN0czogfmQufiUiCiAgICAgICAg ICAgICAgICAgIG51bS1wYXNzZWQgbnVtLWZhaWxlZCkKCSAgKGNsb3NlLW91dHB1dC1wb3J0IHBv cnQpKSkKICAgIHJ1bm5lcikpCih0ZXN0LXJ1bm5lci1mYWN0b3J5CiAobGFtYmRhICgpIChteS1z aW1wbGUtcnVubmVyICIvdG1wL215LXRlc3QubG9nIikpKQpAZW5kIGxpc3AK --=-=-= Content-Type: application/texinfo Content-Disposition: attachment; filename=srfi-64-documented.texi Content-Transfer-Encoding: base64 Content-Description: documented QG5vZGUgU1JGSSA2NCBBYnN0cmFjdApAc3Vic3Vic2VjdGlvbiBTUkZJIDY0IEFic3RyYWN0CgpU aGlzIGRlZmluZXMgYW4gQVBJIGZvciB3cml0aW5nIEBkZm57dGVzdCBzdWl0ZXN9LCB0byBtYWtl IGl0IGVhc3kgdG8KcG9ydGFibHkgdGVzdCBTY2hlbWUgQVBJcywgbGlicmFyaWVzLCBhcHBsaWNh dGlvbnMsIGFuZCBpbXBsZW1lbnRhdGlvbnMuCkEgdGVzdCBzdWl0ZSBpcyBhIGNvbGxlY3Rpb24g b2YgQGRmbnt0ZXN0IGNhc2VzfSB0aGF0IGV4ZWN1dGUgaW4gdGhlCmNvbnRleHQgb2YgYSBAZGZu e3Rlc3QtcnVubmVyfS4gIFRoaXMgc3BlY2lmaWNhdGlvbiBhbHNvIHN1cHBvcnRzCndyaXRpbmcg bmV3IHRlc3QtcnVubmVycywgdG8gYWxsb3cgY3VzdG9taXphdGlvbiBvZiByZXBvcnRpbmcgYW5k CnByb2Nlc3NpbmcgdGhlIHJlc3VsdCBvZiBydW5uaW5nIHRlc3Qgc3VpdGVzLgoKQG5vZGUgU1JG SSA2NCBSYXRpb25hbGUKQHN1YnN1YnNlY3Rpb24gU1JGSSA2NCBSYXRpb25hbGUKClRoZSBTY2hl bWUgY29tbXVuaXR5IG5lZWRzIGEgc3RhbmRhcmQgZm9yIHdyaXRpbmcgdGVzdCBzdWl0ZXMuICBF dmVyeQpTUkZJIG9yIG90aGVyIGxpYnJhcnkgc2hvdWxkIGNvbWUgd2l0aCBhIHRlc3Qgc3VpdGUu ICBTdWNoIGEgdGVzdCBzdWl0ZQptdXN0IGJlIHBvcnRhYmxlLCB3aXRob3V0IHJlcXVpcmluZyBh bnkgbm9uLXN0YW5kYXJkIGZlYXR1cmVzLCBzdWNoIGFzCm1vZHVsZXMuICBUaGUgdGVzdCBzdWl0 ZSBpbXBsZW1lbnRhdGlvbiBvciAicnVubmVyIiBuZWVkIG5vdCBiZQpwb3J0YWJsZSwgYnV0IGl0 IGlzIGRlc2lyYWJsZSB0aGF0IGl0IGJlIHBvc3NpYmxlIHRvIHdyaXRlIGEgcG9ydGFibGUKYmFz aWMgaW1wbGVtZW50YXRpb24uCgpUaGVyZSBhcmUgb3RoZXIgdGVzdGluZyBmcmFtZXdvcmtzIHdy aXR0ZW4gaW4gU2NoZW1lLCBpbmNsdWRpbmcKQHVybHtodHRwczovL2RvY3MucmFja2V0LWxhbmcu b3JnL3JhY2t1bml0LywgUmFja1VuaXR9LiAgSG93ZXZlcgpSYWNrVW5pdCBpcyBub3QgcG9ydGFi bGUuICBJdCBpcyBhbHNvIGEgYml0IG9uIHRoZSB2ZXJib3NlIHNpZGUuICBJdAp3b3VsZCBiZSB1 c2VmdWwgdG8gaGF2ZSBhIGJyaWRnZSBiZXR3ZWVuIHRoaXMgZnJhbWV3b3JrIGFuZCBSYWNrVW5p dCBzbwpSYWNrVW5pdCB0ZXN0cyBjb3VsZCBydW4gdW5kZXIgdGhpcyBmcmFtZXdvcmsgYW5kIHZp Y2UgdmVyc2EuICBUaGVyZQpleGlzdHMgYWxzbyBhdCBsZWFzdCBvbmUgU2NoZW1lIHdyYXBwZXIg cHJvdmlkaW5nIGEgU2NoZW1lIGludGVyZmFjZSB0bwp0aGUgYGBzdGFuZGFyZCcnIEB1cmx7aHR0 cHM6Ly93d3cuanVuaXQub3JnLywgSlVuaXR9IEFQSSBmb3IgSmF2YS4gIEl0CndvdWxkIGJlIHVz ZWZ1bCB0byBoYXZlIGEgYnJpZGdlIHNvIHRoYXQgdGVzdHMgd3JpdHRlbiB1c2luZyB0aGlzCmZy YW1ld29yayBjYW4gcnVuIHVuZGVyIGEgSlVuaXQgcnVubmVyLiAgTmVpdGhlciBvZiB0aGVzZSBm ZWF0dXJlcyBhcmUKcGFydCBvZiB0aGlzIHNwZWNpZmljYXRpb24uCgpUaGlzIEFQSSBtYWtlcyB1 c2Ugb2YgaW1wbGljaXQgZHluYW1pYyBzdGF0ZSwgaW5jbHVkaW5nIGFuIGltcGxpY2l0CmBgdGVz dCBydW5uZXInJy4gIFRoaXMgbWFrZXMgdGhlIEFQSSBjb252ZW5pZW50IGFuZCB0ZXJzZSB0byB1 c2UsIGJ1dCBpdAptYXkgYmUgYSBsaXR0bGUgbGVzcyBlbGVnYW50IGFuZCBgYGNvbXBvc2l0aW9u YWwnJyB0aGFuIHVzaW5nIGV4cGxpY2l0CnRlc3Qgb2JqZWN0cywgc3VjaCBhcyBKVW5pdC1zdHls ZSBmcmFtZXdvcmtzLiAgSXQgaXMgbm90IGNsYWltZWQgdG8KZm9sbG93IGVpdGhlciBvYmplY3Qt b3JpZW50ZWQgb3IgZnVuY3Rpb25hbCBkZXNpZ24gcHJpbmNpcGxlcywgYnV0IEkKaG9wZSBpdCBp cyB1c2VmdWwgYW5kIGNvbnZlbmllbnQgdG8gdXNlIGFuZCBleHRlbmQuCgpUaGlzIHByb3Bvc2Fs IGFsbG93cyBjb252ZXJ0aW5nIGEgU2NoZW1lIHNvdXJjZSBmaWxlIHRvIGEKdGVzdCBzdWl0ZSBi eSBqdXN0IGFkZGluZyBhIGZldyBtYWNyb3MuICBZb3UgZG9uJ3QgaGF2ZSB0bwp3cml0ZSB0aGUg ZW50aXJlIGZpbGUgaW4gYSBuZXcgZm9ybSwgdGh1cyB5b3UgZG9uJ3QgaGF2ZSB0bwpyZS1pbmRl bnQgaXQuCgpBbGwgbmFtZXMgZGVmaW5lZCBieSB0aGUgQVBJIHN0YXJ0IHdpdGggdGhlIHByZWZp eCBAc2FtcHt0ZXN0LX0uICBBbGwKZnVuY3Rpb24tbGlrZSBmb3JtcyBhcmUgZGVmaW5lZCBhcyBz eW50YXguICBUaGV5IG1heSBiZSBpbXBsZW1lbnRlZCBhcwpmdW5jdGlvbnMgb3IgbWFjcm9zIG9y IGJ1aWx0LWlucy4gIFRoZSByZWFzb24gZm9yIHNwZWNpZnlpbmcgdGhlbSBhcwpzeW50YXggaXMg dG8gYWxsb3cgc3BlY2lmaWMgdGVzdHMgdG8gYmUgc2tpcHBlZCB3aXRob3V0IGV2YWx1YXRpbmcK c3ViLWV4cHJlc3Npb25zLCBvciBmb3IgaW1wbGVtZW50YXRpb25zIHRvIGFkZCBmZWF0dXJlcyBz dWNoIGFzIHByaW50aW5nCmxpbmUgbnVtYmVycyBvciBjYXRjaGluZyBleGNlcHRpb25zLgoKQG5v ZGUgU1JGSSA2NCBXcml0aW5nIGJhc2ljIHRlc3Qgc3VpdGVzCkBzdWJzdWJzZWN0aW9uIFNSRkkg NjQgV3JpdGluZyBiYXNpYyB0ZXN0IHN1aXRlcwoKTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBl eGFtcGxlLiAgVGhpcyBpcyBhIGNvbXBsZXRlIHNlbGYtY29udGFpbmVkCnRlc3Qtc3VpdGUuCgpA bGlzcAo7OyBJbml0aWFsaXplIGFuZCBnaXZlIGEgbmFtZSB0byBhIHNpbXBsZSB0ZXN0c3VpdGUu Cih0ZXN0LWJlZ2luICJ2ZWMtdGVzdCIpCihkZWZpbmUgdiAobWFrZS12ZWN0b3IgNSA5OSkpCjs7 IFJlcXVpcmUgdGhhdCBhbiBleHByZXNzaW9uIGV2YWx1YXRlIHRvIHRydWUuCih0ZXN0LWFzc2Vy dCAodmVjdG9yPyB2KSkKOzsgVGVzdCB0aGF0IGFuIGV4cHJlc3Npb24gaXMgZXF2PyB0byBzb21l IG90aGVyIGV4cHJlc3Npb24uCih0ZXN0LWVxdiA5OSAodmVjdG9yLXJlZiB2IDIpKQoodmVjdG9y LXNldCEgdiAyIDcpCih0ZXN0LWVxdiA3ICh2ZWN0b3ItcmVmIHYgMikpCjs7IEZpbmlzaCB0aGUg dGVzdHN1aXRlLCBhbmQgcmVwb3J0IHJlc3VsdHMuCih0ZXN0LWVuZCAidmVjLXRlc3QiKQpAZW5k IGxpc3AKClRoaXMgdGVzdHN1aXRlIGNvdWxkIGJlIHNhdmVkIGluIGl0cyBvd24gc291cmNlIGZp bGUuICBOb3RoaW5nIGVsc2UgaXMKbmVlZGVkOiBXZSBkbyBub3QgcmVxdWlyZSBhbnkgdG9wLWxl dmVsIGZvcm1zLCBzbyBpdCBpcyBlYXN5IHRvIHdyYXAgYW4KZXhpc3RpbmcgcHJvZ3JhbSBvciB0 ZXN0IHRvIHRoaXMgZm9ybSwgd2l0aG91dCBhZGRpbmcgaW5kZW50YXRpb24uICBJdAppcyBhbHNv IGVhc3kgdG8gYWRkIG5ldyB0ZXN0cywgd2l0aG91dCBoYXZpbmcgdG8gbmFtZSBpbmRpdmlkdWFs IHRlc3RzCih0aG91Z2ggdGhhdCBpcyBvcHRpb25hbCkuCgpUZXN0IGNhc2VzIGFyZSBleGVjdXRl ZCBpbiB0aGUgY29udGV4dCBvZiBhIEBkZm57dGVzdCBydW5uZXJ9LCB3aGljaCBpcwphIG9iamVj dCB0aGF0IGFjY3VtdWxhdGVzIGFuZCByZXBvcnRzIHRlc3QgcmVzdWx0cy4gIFRoaXMgc3BlY2lm aWNhdGlvbgpkZWZpbmVzIGhvdyB0byBjcmVhdGUgYW5kIHVzZSBjdXN0b20gdGVzdCBydW5uZXJz LCBidXQgaW1wbGVtZW50YXRpb25zCnNob3VsZCBhbHNvIHByb3ZpZGUgYSBkZWZhdWx0IHRlc3Qg cnVubmVyLiAgSXQgaXMgc3VnZ2VzdGVkIChidXQgbm90CnJlcXVpcmVkKSB0aGF0IGxvYWRpbmcg dGhlIGFib3ZlIGZpbGUgaW4gYSB0b3AtbGV2ZWwgZW52aXJvbm1lbnQgd2lsbApjYXVzZSB0aGUg dGVzdHMgdG8gYmUgZXhlY3V0ZWQgdXNpbmcgYW4gaW1wbGVtZW50YXRpb24tc3BlY2lmaWVkIGRl ZmF1bHQKdGVzdCBydW5uZXIsIGFuZCBAY29kZXt0ZXN0LWVuZH0gd2lsbCBjYXVzZSBhIHN1bW1h cnkgdG8gYmUgZGlzcGxheWVkIGluCmFuIGltcGxlbWVudGF0aW9uLXNwZWNpZmllZCBtYW5uZXIu CgpAc3Vic3ViaGVhZGluZyBTaW1wbGUgdGVzdC1jYXNlcwoKUHJpbWl0aXZlIHRlc3QgY2FzZXMg dGVzdCB0aGF0IGEgZ2l2ZW4gY29uZGl0aW9uIGlzIHRydWUuICBUaGV5IG1heSBoYXZlCmEgbmFt ZS4gIFRoZSBjb3JlIHRlc3QgY2FzZSBmb3JtIGlzIEBjb2Rle3Rlc3QtYXNzZXJ0fToKCkBkZWZm biB7U2NoZW1lIFN5bnRheH0gdGVzdC1hc3NlcnQgW3Rlc3QtbmFtZV0gZXhwcmVzc2lvbgoKVGhp cyBldmFsdWF0ZXMgdGhlIEB2YXJ7ZXhwcmVzc2lvbn0uICBUaGUgdGVzdCBwYXNzZXMgaWYgdGhl IHJlc3VsdCBpcwp0cnVlOyBpZiB0aGUgcmVzdWx0IGlzIGZhbHNlLCBhIHRlc3QgZmFpbHVyZSBp cyByZXBvcnRlZC4gIFRoZSB0ZXN0IGFsc28KZmFpbHMgaWYgYW4gZXhjZXB0aW9uIGlzIHJhaXNl ZCwgYXNzdW1pbmcgdGhlIGltcGxlbWVudGF0aW9uIGhhcyBhIHdheQp0byBjYXRjaCBleGNlcHRp b25zLiAgSG93IHRoZSBmYWlsdXJlIGlzIHJlcG9ydGVkIGRlcGVuZHMgb24gdGhlIHRlc3QKcnVu bmVyIGVudmlyb25tZW50LiAgVGhlIEB2YXJ7dGVzdC1uYW1lfSBpcyBhIHN0cmluZyB0aGF0IG5h bWVzIHRoZSB0ZXN0CmNhc2UuICAoVGhvdWdoIHRoZSBAdmFye3Rlc3QtbmFtZX0gaXMgYSBzdHJp bmcgbGl0ZXJhbCBpbiB0aGUgZXhhbXBsZXMsCml0IGlzIGFuIGV4cHJlc3Npb24uICBJdCBpcyBl dmFsdWF0ZWQgb25seSBvbmNlLikgIEl0IGlzIHVzZWQgd2hlbgpyZXBvcnRpbmcgZXJyb3JzLCBh bmQgYWxzbyB3aGVuIHNraXBwaW5nIHRlc3RzLCBhcyBkZXNjcmliZWQgYmVsb3cuICBJdAppcyBh biBlcnJvciB0byBpbnZva2UgQGNvZGV7dGVzdC1hc3NlcnR9aWYgdGhlcmUgaXMgbm8gY3VycmVu dCB0ZXN0CnJ1bm5lci4KQGVuZCBkZWZmbgoKVGhlIGZvbGxvd2luZyBmb3JtcyBtYXkgYmUgbW9y ZSBjb252ZW5pZW50IHRoYW4gdXNpbmcgQGNvZGV7dGVzdC1hc3NlcnR9CmRpcmVjdGx5OgoKQGRl ZmZuIHtTY2hlbWUgU3ludGF4fSB0ZXN0LWVxdiBbdGVzdC1uYW1lXSBleHBlY3RlZCB0ZXN0LWV4 cHIKClRoaXMgaXMgZXF1aXZhbGVudCB0bzoKCkBsaXNwCih0ZXN0LWFzc2VydCBbQHZhcnt0ZXN0 LW5hbWV9XSAoZXF2PyBAdmFye2V4cGVjdGVkfSBAdmFye3Rlc3QtZXhwcn0pKQpAZW5kIGxpc3AK CkBlbmQgZGVmZm4KClNpbWlsYXJseSBAY29kZXt0ZXN0LWVxdWFsfSBhbmQgQGNvZGV7dGVzdC1l cX0gYXJlIHNob3J0aGFuZCBmb3IKQGNvZGV7dGVzdC1hc3NlcnR9IGNvbWJpbmVkIHdpdGggQGNv ZGV7ZXF1YWw/fSBvciBAY29kZXtlcT99LApyZXNwZWN0aXZlbHk6CgpAZGVmZm4ge1NjaGVtZSBT eW50YXh9IHRlc3QtZXF1YWwgW3Rlc3QtbmFtZV0gZXhwZWN0ZWQgdGVzdC1leHByCkBkZWZmbngg e1NjaGVtZSBTeW50YXh9IHRlc3QtZXEgW3Rlc3QtbmFtZV0gZXhwZWN0ZWQgdGVzdC1leHByCgpI ZXJlIGlzIGEgc2ltcGxlIGV4YW1wbGU6CgpAbGlzcAooZGVmaW5lIChtZWFuIHggeSkgKC8gKCsg eCB5KSAyLjApKQoodGVzdC1lcXYgNCAobWVhbiAzIDUpKQpAZW5kIGxpc3AKQGVuZCBkZWZmbgoK Rm9yIHRlc3RpbmcgYXBwcm94aW1hdGUgZXF1YWxpdHkgb2YgaW5leGFjdCByZWFscwp3ZSBjYW4g dXNlIEBjb2Rle3Rlc3QtYXBwcm94aW1hdGV9OgoKQGRlZmZuIHtTY2hlbWUgU3ludGF4fSB0ZXN0 LWFwcHJveGltYXRlIFt0ZXN0LW5hbWVdIGV4cGVjdGVkIHRlc3QtZXhwciBlcnJvcgoKVGhpcyBp cyBlcXVpdmFsZW50IHRvIChleGNlcHQgdGhhdCBlYWNoIGFyZ3VtZW50IGlzIG9ubHkgZXZhbHVh dGVkCm9uY2UpOgoKQGxpc3AKKHRlc3QtYXNzZXJ0IFt0ZXN0LW5hbWVdCiAgKGFuZCAoPj0gdGVz dC1leHByICgtIGV4cGVjdGVkIGVycm9yKSkKICAgICAgICg8PSB0ZXN0LWV4cHIgKCsgZXhwZWN0 ZWQgZXJyb3IpKSkpCkBlbmQgbGlzcApAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBUZXN0cyBm b3IgY2F0Y2hpbmcgZXJyb3JzCgpXZSBuZWVkIGEgd2F5IHRvIHNwZWNpZnkgdGhhdCBldmFsdWF0 aW9uIEBlbXBoe3Nob3VsZH0gZmFpbC4gIFRoaXMKdmVyaWZpZXMgdGhhdCBlcnJvcnMgYXJlIGRl dGVjdGVkIHdoZW4gcmVxdWlyZWQuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9IHRlc3QtZXJyb3Ig W1t0ZXN0LW5hbWVdIGVycm9yLXR5cGVdIHRlc3QtZXhwcgoKRXZhbHVhdGluZyBAdmFye3Rlc3Qt ZXhwcn0gaXMgZXhwZWN0ZWQgdG8gc2lnbmFsIGFuIGVycm9yLiAgVGhlIGtpbmQgb2YKZXJyb3Ig aXMgaW5kaWNhdGVkIGJ5IEB2YXJ7ZXJyb3ItdHlwZX0uCgpJZiB0aGUgQHZhcntlcnJvci10eXBl fSBpcyBsZWZ0IG91dCwgb3IgaXQgaXMgQGNvZGV7I3R9LCBpdCBtZWFucyAic29tZQpraW5kIG9m IHVuc3BlY2lmaWVkIGVycm9yIHNob3VsZCBiZSBzaWduYWxlZCIuICBGb3IgZXhhbXBsZToKCkBs aXNwCih0ZXN0LWVycm9yICN0ICh2ZWN0b3ItcmVmICcjKDEgMikgOSkpCkBlbmQgbGlzcAoKVGhp cyBzcGVjaWZpY2F0aW9uIGxlYXZlcyBpdCBpbXBsZW1lbnRhdGlvbi1kZWZpbmVkIChvciBmb3Ig YSBmdXR1cmUKc3BlY2lmaWNhdGlvbikgd2hhdCBmb3JtIEB2YXJ7dGVzdC1lcnJvcn0gbWF5IHRh a2UsIHRob3VnaCBhbGwKaW1wbGVtZW50YXRpb25zIG11c3QgYWxsb3cgQGNvZGV7I3R9LiAgU29t ZSBpbXBsZW1lbnRhdGlvbnMgbWF5IHN1cHBvcnQKQHVybHtodHRwczovL3NyZmkuc2NoZW1lcnMu b3JnL3NyZmktMzUvc3JmaS0zNS5odG1sLCBTUkZJLTM1J3MKY29uZGl0aW9uc30sIGJ1dCB0aGVz ZSBhcmUgb25seSBzdGFuZGFyZGl6ZWQgZm9yCkB1cmx7aHR0cHM6Ly9zcmZpLnNjaGVtZXJzLm9y Zy9zcmZpLTM2L3NyZmktMzYuaHRtbCwgU1JGSS0zNidzIEkvTwpjb25kaXRpb25zfSwgd2hpY2gg YXJlIHNlbGRvbSB1c2VmdWwgaW4gdGVzdCBzdWl0ZXMuICBBbiBpbXBsZW1lbnRhdGlvbgptYXkg YWxzbyBhbGxvdyBpbXBsZW1lbnRhdGlvbi1zcGVjaWZpYyBgYGV4Y2VwdGlvbiB0eXBlcycnLiAg Rm9yIGV4YW1wbGUKSmF2YS1iYXNlZCBpbXBsZW1lbnRhdGlvbnMgbWF5IGFsbG93IHRoZSBuYW1l cyBvZiBKYXZhIGV4Y2VwdGlvbgpjbGFzc2VzOgoKQGxpc3AKOzsgS2F3YS1zcGVjaWZpYyBleGFt cGxlCih0ZXN0LWVycm9yIDxqYXZhLmxhbmcuSW5kZXhPdXRPZkJvdW5kc0V4Y2VwdGlvbj4gKHZl Y3Rvci1yZWYgJyMoMSAyKSA5KSkKQGVuZCBsaXNwCgpBbiBpbXBsZW1lbnRhdGlvbiB0aGF0IGNh bm5vdCBjYXRjaCBleGNlcHRpb25zIHNob3VsZCBza2lwCkBjb2Rle3Rlc3QtZXJyb3J9IGZvcm1z LgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBUZXN0aW5nIHN5bnRheAoKVGVzdGluZyBzeW50 YXggaXMgdHJpY2t5LCBlc3BlY2lhbGx5IGlmIHdlIHdhbnQgdG8gY2hlY2sgdGhhdCBpbnZhbGlk CnN5bnRheCBpcyBjYXVzaW5nIGFuIGVycm9yLiAgVGhlIGZvbGxvd2luZyB1dGlsaXR5IGZ1bmN0 aW9uIGNhbiBoZWxwOgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJlYWQtZXZhbC1z dHJpbmcgc3RyaW5nCgpUaGlzIGZ1bmN0aW9uIHBhcnNlcyBAdmFye3N0cmluZ30gKHVzaW5nIEBj b2Rle3JlYWR9KSBhbmQgZXZhbHVhdGVzIHRoZQpyZXN1bHQuICBUaGUgcmVzdWx0IG9mIGV2YWx1 YXRpb24gaXMgcmV0dXJuZWQgZnJvbQpAY29kZXt0ZXN0LXJlYWQtZXZhbC1zdHJpbmd9LiAgQW4g ZXJyb3IgaXMgc2lnbmFsbGVkIGlmIHRoZXJlIGFyZSB1bnJlYWQKY2hhcmFjdGVycyBhZnRlciB0 aGUgQGNvZGV7cmVhZH0gaXMgZG9uZS4gIEZvciBleGFtcGxlOgpAY29kZXsodGVzdC1yZWFkLWV2 YWwtc3RyaW5nICIoKyAzIDQpIil9IEBpe2V2YWx1YXRlcyB0b30gQGNvZGV7N30uCkBjb2Rleyh0 ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigrIDMgNCIpfSBAaXtzaWduYWxzIGFuIGVycm9yfS4KQGNv ZGV7KHRlc3QtcmVhZC1ldmFsLXN0cmluZyAiKCsgMyA0KSAiKX0gQGl7c2lnbmFscyBhbiBlcnJv cn0sIGJlY2F1c2UKdGhlcmUgaXMgZXh0cmEgYGBqdW5rJycgKEBpe2kuZS59IGEgc3BhY2UpIGFm dGVyIHRoZSBsaXN0IGlzIHJlYWQuCgpUaGUgQGNvZGV7dGVzdC1yZWFkLWV2YWwtc3RyaW5nfSB1 c2VkIGluIHRlc3RzOgoKQGxpc3AKKHRlc3QtZXF1YWwgNyAodGVzdC1yZWFkLWV2YWwtc3RyaW5n ICIoKyAzIDQpIikpCih0ZXN0LWVycm9yICh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIigrIDMiKSkK KHRlc3QtZXF1YWwgI1xuZXdsaW5lICh0ZXN0LXJlYWQtZXZhbC1zdHJpbmcgIiNcXG5ld2xpbmUi KSkKKHRlc3QtZXJyb3IgKHRlc3QtcmVhZC1ldmFsLXN0cmluZyAiI1xcbmV3bGluIikpCjs7IFNr aXAgdGhlIG5leHQgMiB0ZXN0cyB1bmxlc3Mgc3JmaS02MiBpcyBhdmFpbGFibGUuCih0ZXN0LXNr aXAgKGNvbmQtZXhwYW5kIChzcmZpLTYyIDApIChlbHNlIDIpKSkKKHRlc3QtZXF1YWwgNSAodGVz dC1yZWFkLWV2YWwtc3RyaW5nICIoKyAxICM7KCogMiAzKSA0KSIpKQoodGVzdC1lcXVhbCAnKHgg eikgKHRlc3QtcmVhZC1zdHJpbmcgIihsaXN0ICd4ICM7J3kgJ3opIikpCkBlbmQgbGlzcApAZW5k IGRlZmZuCgpAc3Vic3ViaGVhZGluZyBUZXN0IGdyb3VwcyBhbmQgcGF0aHMKCkEgQGRmbnt0ZXN0 IGdyb3VwfSBpcyBhIG5hbWVkIHNlcXVlbmNlIG9mIGZvcm1zIGNvbnRhaW5pbmcgdGVzdGNhc2Vz LApleHByZXNzaW9ucywgYW5kIGRlZmluaXRpb25zLiAgRW50ZXJpbmcgYSBncm91cCBzZXRzIHRo ZSBAZGZue3Rlc3QgZ3JvdXAKbmFtZX07IGxlYXZpbmcgYSBncm91cCByZXN0b3JlcyB0aGUgcHJl dmlvdXMgZ3JvdXAgbmFtZS4gIFRoZXNlIGFyZQpkeW5hbWljIChydW4tdGltZSkgb3BlcmF0aW9u cywgYW5kIGEgZ3JvdXAgaGFzIG5vIG90aGVyIGVmZmVjdCBvcgppZGVudGl0eS4gIFRlc3QgZ3Jv dXBzIGFyZSBpbmZvcm1hbCBncm91cGluZ3M6IHRoZXkgYXJlIG5laXRoZXIgU2NoZW1lCnZhbHVl cywgbm9yIGFyZSB0aGV5IHN5bnRhY3RpYyBmb3Jtcy4KQGMgKE1vcmUgZm9ybWFsIDxxPnRlc3Qg c3VpdGU8L3E+IHZhbHVlcyBhcmUgaW50cm9kdWNlZCBiZWxvdy4pCkEgdGVzdCBncm91cCBtYXkg Y29udGFpbiBuZXN0ZWQgaW5uZXIgdGVzdCBncm91cHMuClRoZSBAZGZue3Rlc3QgZ3JvdXAgcGF0 aH0gaXMgYSBsaXN0IG9mIHRoZSBjdXJyZW50bHktYWN0aXZlCihlbnRlcmVkKSB0ZXN0IGdyb3Vw IG5hbWVzLCBvbGRlc3QgKG91dGVybW9zdCkgZmlyc3QuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9 IHRlc3QtYmVnaW4gc3VpdGUtbmFtZSBbY291bnRdCgpBIEBjb2Rle3Rlc3QtYmVnaW59IGVudGVy cyBhIG5ldyB0ZXN0IGdyb3VwLiAgVGhlIEB2YXJ7c3VpdGUtbmFtZX0KYmVjb21lcyB0aGUgY3Vy cmVudCB0ZXN0IGdyb3VwIG5hbWUsIGFuZCBpcyBhZGRlZCB0byB0aGUgZW5kIG9mIHRoZSB0ZXN0 Cmdyb3VwIHBhdGguICBQb3J0YWJsZSB0ZXN0IHN1aXRlcyBzaG91bGQgdXNlIGEgc3RyaW5nIGxp dGVyYWwgZm9yCkB2YXJ7c3VpdGUtbmFtZX07IHRoZSBlZmZlY3Qgb2YgZXhwcmVzc2lvbnMgb3Ig b3RoZXIga2luZHMgb2YgbGl0ZXJhbHMKaXMgdW5zcGVjaWZpZWQuCgpAZW1waHtSYXRpb25hbGU6 fSBJbiBzb21lIHdheXMgdXNpbmcgc3ltYm9scyB3b3VsZCBiZSBwcmVmZXJhYmxlLgpIb3dldmVy LCB3ZSB3YW50IGh1bWFuLXJlYWRhYmxlIG5hbWVzLCBhbmQgc3RhbmRhcmQgU2NoZW1lIGRvZXMg bm90CnByb3ZpZGUgYSB3YXkgdG8gaW5jbHVkZSBzcGFjZXMgb3IgbWl4ZWQtY2FzZSB0ZXh0IGlu IGxpdGVyYWwgc3ltYm9scy4KClRoZSBvcHRpb25hbCBAdmFye2NvdW50fSBtdXN0IG1hdGNoIHRo ZSBudW1iZXIgb2YgdGVzdC1jYXNlcyBleGVjdXRlZCBieQp0aGlzIGdyb3VwLiAgKE5lc3RlZCB0 ZXN0IGdyb3VwcyBjb3VudCBhcyBhIHNpbmdsZSB0ZXN0IGNhc2UgZm9yIHRoaXMKY291bnQuKSAg VGhpcyBleHRyYSB0ZXN0IG1heSBiZSB1c2VmdWwgdG8gY2F0Y2ggY2FzZXMgd2hlcmUgYSB0ZXN0 CmRvZXNuJ3QgZ2V0IGV4ZWN1dGVkIGJlY2F1c2Ugb2Ygc29tZSB1bmV4cGVjdGVkIGVycm9yLgoK QWRkaXRpb25hbGx5LCBpZiB0aGVyZSBpcyBubyBjdXJyZW50bHkgZXhlY3V0aW5nIHRlc3QgcnVu bmVyLApvbmUgaXMgaW5zdGFsbGVkIGluIGFuIGltcGxlbWVudGF0aW9uLWRlZmluZWQgbWFubmVy LgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9IHRlc3QtZW5kIFtzdWl0ZS1uYW1l XQoKQSBAY29kZXt0ZXN0LWVuZH0gbGVhdmVzIHRoZSBjdXJyZW50IHRlc3QgZ3JvdXAuCkFuIGVy cm9yIGlzIHJlcG9ydGVkIGlmIHRoZSBAdmFye3N1aXRlLW5hbWV9IGRvZXMgbm90Cm1hdGNoIHRo ZSBjdXJyZW50IHRlc3QgZ3JvdXAgbmFtZS4KQGMgSWYgaXQgZG9lcyBtYXRjaCBhbiBlYXJsaWVy IG5hbWUgaW4gdGhlIHRlc3QgZ3JvdXAgcGF0aCwgaW50ZXJ2ZW5pbmcKQGMgZ3JvdXBzIGFyZSBs ZWZ0LgoKQWRkaXRpb25hbGx5LCBpZiB0aGUgbWF0Y2hpbmcgQGNvZGV7dGVzdC1iZWdpbn1pbnN0 YWxsZWQgYSBuZXcKdGVzdC1ydW5uZXIsIHRoZW4gdGhlIEBjb2Rle3Rlc3QtZW5kfSB3aWxsIHVu aW5zdGFsbCBpdCwgYWZ0ZXIgcmVwb3J0aW5nCnRoZSBhY2N1bXVsYXRlZCB0ZXN0IHJlc3VsdHMg aW4gYW4gaW1wbGVtZW50YXRpb24tZGVmaW5lZCBtYW5uZXIuCkBlbmQgZGVmZm4KCkBkZWZmbiB7 U2NoZW1lIFN5bnRheH0gdGVzdC1ncm91cCBzdWl0ZS1uYW1lIGRlY2wtb3ItZXhwciBAZG90c3t9 CgpFcXVpdmFsZW50IHRvOgoKQGxpc3AKKGlmIChub3QgKHRlc3QtdG8tc2tpcCUgKHZhciBzdWl0 ZS1uYW1lKSkpCiAgKGR5bmFtaWMtd2luZAogICAgKGxhbWJkYSAoKSAodGVzdC1iZWdpbiAodmFy IHN1aXRlLW5hbWUpKSkKICAgIChsYW1iZGEgKCkgKHZhciBkZWNsLW9yLWV4cHIpIC4uLikKICAg IChsYW1iZGEgKCkgKHRlc3QtZW5kICh2YXIgc3VpdGUtbmFtZSkpKSkpCkBlbmQgbGlzcAoKVGhp cyBpcyB1c3VhbGx5IGVxdWl2YWxlbnQgdG8gZXhlY3V0aW5nIHRoZSBAdmFye2RlY2wtb3ItZXhw cn1zCndpdGhpbiB0aGUgbmFtZWQgdGVzdCBncm91cC4gIEhvd2V2ZXIsIHRoZSBlbnRpcmUgZ3Jv dXAgaXMgc2tpcHBlZAppZiBpdCBtYXRjaGVkIGFuIGFjdGl2ZSBAY29kZXt0ZXN0LXNraXB9IChz ZWUgbGF0ZXIpLgpBbHNvLCB0aGUgQGNvZGV7dGVzdC1lbmR9IGlzIGV4ZWN1dGVkIGluIGNhc2Ug b2YgYW4gZXhjZXB0aW9uLgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBIYW5kbGluZyBzZXQt dXAgYW5kIGNsZWFudXAKCkBkZWZmbiB7U2NoZW1lIFN5bnRheH0gdGVzdC1ncm91cC13aXRoLWNs ZWFudXAgc3VpdGUtbmFtZSBkZWNsLW9yLWV4cHIgQGRvdHN7fSBjbGVhbnVwLWZvcm0KCkV4ZWN1 dGUgZWFjaCBvZiB0aGUgQHZhcntkZWNsLW9yLWV4cHJ9IGZvcm1zIGluIG9yZGVyIChhcyBpbiBh CkB2YXJ7PGJvZHk+fSksIGFuZCB0aGVuIGV4ZWN1dGUgdGhlIEB2YXJ7Y2xlYW51cC1mb3JtfS4g IFRoZSBsYXR0ZXIKc2hvdWxkIGJlIGV4ZWN1dGVkIGV2ZW4gaWYgb25lIG9mIGEgQHZhcntkZWNs LW9yLWV4cHJ9IGZvcm1zIHJhaXNlcyBhbgpleGNlcHRpb24gKGFzc3VtaW5nIHRoZSBpbXBsZW1l bnRhdGlvbiBoYXMgYSB3YXkgdG8gY2F0Y2ggZXhjZXB0aW9ucykuCgpGb3IgZXhhbXBsZToKCkBs aXNwCihsZXQgKChmIChvcGVuLW91dHB1dC1maWxlICJsb2ciKSkpCiAgKHRlc3QtZ3JvdXAtd2l0 aC1jbGVhbnVwICJ0ZXN0LWZpbGUiCiAgICAoZG8tYS1idW5jaC1vZi10ZXN0cyBmKQogICAgKGNs b3NlLW91dHB1dC1wb3J0IGYpKSkKQGVuZCBsaXNwCkBlbmQgZGVmZm4KCkBub2RlIFNSRkkgNjQg Q29uZGl0b25hbCB0ZXN0LXN1aXRlcyBhbmQgb3RoZXIgYWR2YW5jZWQgZmVhdHVyZXMKQHN1YnN1 YnNlY3Rpb24gU1JGSSA2NCBDb25kaXRvbmFsIHRlc3Qtc3VpdGVzIGFuZCBvdGhlciBhZHZhbmNl ZCBmZWF0dXJlcwoKVGhlIGZvbGxvd2luZyBkZXNjcmliZXMgZmVhdHVyZXMgZm9yIGNvbnRyb2xs aW5nIHdoaWNoIHRlc3RzIHRvIGV4ZWN1dGUsCm9yIHNwZWNpZnlpbmcgdGhhdCBzb21lIHRlc3Rz IGFyZSBAZW1waHtleHBlY3RlZH0gdG8gZmFpbC4KCkBzdWJzdWJoZWFkaW5nIFRlc3Qgc3BlY2lm aWVycwoKU29tZXRpbWVzIHdlIHdhbnQgdG8gb25seSBydW4gY2VydGFpbiB0ZXN0cywgb3Igd2Ug a25vdyB0aGF0IGNlcnRhaW4KdGVzdHMgYXJlIGV4cGVjdGVkIHRvIGZhaWwuICBBIEBkZm57dGVz dCBzcGVjaWZpZXJ9IGlzIG9uZS1hcmd1bWVudApmdW5jdGlvbiB0aGF0IHRha2VzIGEgdGVzdC1y dW5uZXIgYW5kIHJldHVybnMgYSBib29sZWFuLiAgVGhlIHNwZWNpZmllcgptYXkgYmUgcnVuIGJl Zm9yZSBhIHRlc3QgaXMgcGVyZm9ybWVkLCBhbmQgdGhlIHJlc3VsdCBtYXkgY29udHJvbAp3aGV0 aGVyIHRoZSB0ZXN0IGlzIGV4ZWN1dGVkLiAgRm9yIGNvbnZlbmllbmNlLCBhIHNwZWNpZmllciBt YXkgYWxzbyBiZQphIG5vbi1wcm9jZWR1cmUgdmFsdWUsIHdoaWNoIGlzIGNvZXJjZWQgdG8gYSBz cGVjaWZpZXIgcHJvY2VkdXJlLCBhcwpkZXNjcmliZWQgYmVsb3cgZm9yIEB2YXJ7Y291bnR9IGFu ZCBAdmFye25hbWV9LgoKQSBzaW1wbGUgZXhhbXBsZSBpczoKCkBsaXNwCihpZiAodmFyIHNvbWUt Y29uZGl0aW9uKSAgKHRlc3Qtc2tpcCAyKSkgOzsgc2tpcCBuZXh0IDIgdGVzdHMKQGVuZCBsaXNw CgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtbWF0Y2gtbmFtZSBuYW1lCgpUaGUgcmVz dWx0aW5nIHNwZWNpZmllciBtYXRjaGVzIGlmIHRoZSBjdXJyZW50IHRlc3QgbmFtZSAoYXMgcmV0 dXJuZWQgYnkKQGNvZGV7dGVzdC1ydW5uZXItdGVzdC1uYW1lfSkgaXMgQGNvZGV7ZXF1YWw/fSB0 byBAdmFye25hbWV9LgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9IHRlc3QtbWF0 Y2gtbnRoIG4gW2NvdW50XQoKVGhpcyBldmFsdWF0ZXMgdG8gYSBAZW1waHtzdGF0ZWZ1bH0gcHJl ZGljYXRlOiBBIGNvdW50ZXIga2VlcHMgdHJhY2sgb2YKaG93IG1hbnkgdGltZXMgaXQgaGFzIGJl ZW4gY2FsbGVkLiAgVGhlIHByZWRpY2F0ZSBtYXRjaGVzIHRoZSBAdmFye259J3RoCnRpbWUgaXQg aXMgY2FsbGVkICh3aGVyZSBAY29kZXsxfSBpcyB0aGUgZmlyc3QgdGltZSksIGFuZCB0aGUgbmV4 dApAc2FtcHsoLSBAdmFye2NvdW50fSAxKX0gdGltZXMsIHdoZXJlIEB2YXJ7Y291bnR9IGRlZmF1 bHRzIHRvIEBjb2RlezF9LgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9IHRlc3Qt bWF0Y2gtYW55IHNwZWNpZmllciBAZG90c3t9CgpUaGUgcmVzdWx0aW5nIHNwZWNpZmllciBtYXRj aGVzIGlmIGFueSBAdmFye3NwZWNpZmllcn0gbWF0Y2hlcy4gIEVhY2gKQHZhcntzcGVjaWZpZXJ9 IGlzIGFwcGxpZWQsIGluIG9yZGVyLCBzbyBzaWRlLWVmZmVjdHMgZnJvbSBhIGxhdGVyCkB2YXJ7 c3BlY2lmaWVyfSBoYXBwZW4gZXZlbiBpZiBhbiBlYXJsaWVyIEB2YXJ7c3BlY2lmaWVyfSBpcyB0 cnVlLgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBTeW50YXh9IHRlc3QtbWF0Y2gtYWxsIHNw ZWNpZmllciBAZG90c3t9CgpUaGUgcmVzdWx0aW5nIHNwZWNpZmllciBtYXRjaGVzIGlmIGVhY2gg QHZhcntzcGVjaWZpZXJ9IG1hdGNoZXMuICBFYWNoCkB2YXJ7c3BlY2lmaWVyfSBpcyBhcHBsaWVk LCBpbiBvcmRlciwgc28gc2lkZS1lZmZlY3RzIGZyb20gYSBsYXRlcgpAdmFye3NwZWNpZmllcn0g aGFwcGVuIGV2ZW4gaWYgYW4gZWFybGllciBAdmFye3NwZWNpZmllcn0gaXMgZmFsc2UuCkBlbmQg ZGVmZm4KCkB2YXJ7Y291bnR9IEBpeyhpLmUuIGFuIGludGVnZXIpfQpDb252ZW5pZW5jZSBzaG9y dC1oYW5kIGZvcjogQHNhbXB7KHRlc3QtbWF0Y2gtbnRoIDEgQHZhcntjb3VudH0pfS4KCkB2YXJ7 bmFtZX0gQGl7KGkuZS4gYSBzdHJpbmcpfQpDb252ZW5pZW5jZSBzaG9ydC1oYW5kIGZvciBAc2Ft cHsodGVzdC1tYXRjaC1uYW1lIEB2YXJ7bmFtZX0pfS4KCkBzdWJzdWJoZWFkaW5nIFNraXBwaW5n IHNlbGVjdGVkIHRlc3RzCgpJbiBzb21lIGNhc2VzIHlvdSBtYXkgd2FudCB0byBza2lwIGEgdGVz dC4KCkBkZWZmbiB7U2NoZW1lIFN5bnRheH0gdGVzdC1za2lwIHNwZWNpZmllcgoKRXZhbHVhdGlu ZyBAY29kZXt0ZXN0LXNraXB9IGFkZHMgdGhlIHJlc3VsdGluZyBAdmFye3NwZWNpZmllcn0gdG8g dGhlCnNldCBvZiBjdXJyZW50bHkgYWN0aXZlIHNraXAtc3BlY2lmaWVycy4gIEJlZm9yZSBlYWNo IHRlc3QgKG9yCkBjb2Rle3Rlc3QtZ3JvdXB9KSB0aGUgc2V0IG9mIGFjdGl2ZSBza2lwLXNwZWNp ZmllcnMgYXJlIGFwcGxpZWQgdG8gdGhlCmFjdGl2ZSB0ZXN0LXJ1bm5lci4gIElmIGFueSBzcGVj aWZpZXIgbWF0Y2hlcywgdGhlbiB0aGUgdGVzdCBpcyBza2lwcGVkLgoKRm9yIGNvbnZlbmllbmNl LCBpZiB0aGUgQHZhcntzcGVjaWZpZXJ9IGlzIGEgc3RyaW5nIHRoYXQgaXMgc3ludGFjdGljCnN1 Z2FyIGZvciBAY29kZXsodGVzdC1tYXRjaC1uYW1lIEB2YXJ7c3BlY2lmaWVyfSl9LiAgRm9yIGV4 YW1wbGU6CgpAbGlzcAoodGVzdC1za2lwICJ0ZXN0LWIiKQoodGVzdC1hc3NlcnQgInRlc3QtYSIp ICAgOzsgZXhlY3V0ZWQKKHRlc3QtYXNzZXJ0ICJ0ZXN0LWIiKSAgIDs7IHNraXBwZWQKQGVuZCBs aXNwCgpBbnkgc2tpcCBzcGVjaWZpZXJzIGludHJvZHVjZWQgYnkgYSBAY29kZXt0ZXN0LXNraXB9 IGFyZSByZW1vdmVkIGJ5IGEKZm9sbG93aW5nIG5vbi1uZXN0ZWQgQGNvZGV7dGVzdC1lbmR9LgoK QGxpc3AKKHRlc3QtYmVnaW4gImdyb3VwMSIpCih0ZXN0LXNraXAgInRlc3QtYSIpCih0ZXN0LWFz c2VydCAidGVzdC1hIikgICA7OyBza2lwcGVkCih0ZXN0LWVuZCAiZ3JvdXAxIikgICAgICA7OyBV bmRvZXMgdGhlIHByaW9yIHRlc3Qtc2tpcAoodGVzdC1hc3NlcnQgInRlc3QtYSIpICAgOzsgZXhl Y3V0ZWQKQGVuZCBsaXNwCkBlbmQgZGVmZm4KCkBzdWJzdWJoZWFkaW5nIEV4cGVjdGVkIGZhaWx1 cmVzCgpTb21ldGltZXMgeW91IGtub3cgYSB0ZXN0IGNhc2Ugd2lsbCBmYWlsLCBidXQgeW91IGRv bid0IGhhdmUgdGltZSB0byBvcgpjYW4ndCBmaXggaXQuICBNYXliZSBhIGNlcnRhaW4gZmVhdHVy ZSBvbmx5IHdvcmtzIG9uIGNlcnRhaW4gcGxhdGZvcm1zLgpIb3dldmVyLCB5b3Ugd2FudCB0aGUg dGVzdC1jYXNlIHRvIGJlIHRoZXJlIHRvIHJlbWluZCB5b3UgdG8gZml4IGl0LgpZb3Ugd2FudCB0 byBub3RlIHRoYXQgc3VjaCB0ZXN0cyBhcmUgZXhwZWN0ZWQgdG8gZmFpbC4KCkBkZWZmbiB7U2No ZW1lIFN5bnRheH0gdGVzdC1leHBlY3QtZmFpbCBzcGVjaWZpZXIKCk1hdGNoaW5nIHRlc3RzICh3 aGVyZSBtYXRjaGluZyBpcyBkZWZpbmVkIGFzIGluIEBjb2Rle3Rlc3Qtc2tpcH0pCmFyZSBleHBl Y3RlZCB0byBmYWlsLiAgVGhpcyBvbmx5IGFmZmVjdHMgdGVzdCByZXBvcnRpbmcsCm5vdCB0ZXN0 IGV4ZWN1dGlvbi4gIEZvciBleGFtcGxlOgoKQGxpc3AKKHRlc3QtZXhwZWN0LWZhaWwgMikKKHRl c3QtZXF2IC4uLikgOzsgZXhwZWN0ZWQgdG8gZmFpbAoodGVzdC1lcXYgLi4uKSA7OyBleHBlY3Rl ZCB0byBmYWlsCih0ZXN0LWVxdiAuLi4pIDs7IGV4cGVjdGVkIHRvIHBhc3MKQGVuZCBsaXNwCkBl bmQgZGVmZm4KCkBub2RlIFNSRkkgNjQgVGVzdC1ydW5uZXIKQHN1YnN1YnNlY3Rpb24gU1JGSSA2 NCBUZXN0LXJ1bm5lcgoKQSBAZGZue3Rlc3QtcnVubmVyfSBpcyBhbiBvYmplY3QgdGhhdCBydW5z IGEgdGVzdC1zdWl0ZSwgYW5kIG1hbmFnZXMgdGhlCnN0YXRlLiAgVGhlIHRlc3QgZ3JvdXAgcGF0 aCwgYW5kIHRoZSBzZXRzIHNraXAgYW5kIGV4cGVjdGVkLWZhaWwKc3BlY2lmaWVycyBhcmUgcGFy dCBvZiB0aGUgdGVzdC1ydW5uZXIuICBBIHRlc3QtcnVubmVyIHdpbGwgYWxzbwp0eXBpY2FsbHkg YWNjdW11bGF0ZSBzdGF0aXN0aWNzIGFib3V0IGV4ZWN1dGVkIHRlc3RzLAoKQGRlZmZuIHtTY2hl bWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lcj8gdmFsdWUKClRydWUgaWYgYW5kIG9ubHkgaWYgQHZh cnt2YWx1ZX0gaXMgYSB0ZXN0LXJ1bm5lciBvYmplY3QuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2No ZW1lIFBhcmFtZXRlcn0gdGVzdC1ydW5uZXItY3VycmVudApAZGVmZm54IHtTY2hlbWUgUGFyYW1l dGVyfSB0ZXN0LXJ1bm5lci1jdXJyZW50IHJ1bm5lcgoKR2V0IG9yIHNldCB0aGUgY3VycmVudCB0 ZXN0LXJ1bm5lci4KQGVuZCBkZWZmbgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1 bm5lci1nZXQKClNhbWUgYXMgQGNvZGV7KHRlc3QtcnVubmVyLWN1cnJlbnQpfSwgYnV0IHRocm93 cyBhbiBleGNlcHRpb24gaWYgdGhlcmUKaXMgbm8gY3VycmVudCB0ZXN0LXJ1bm5lci4KQGVuZCBk ZWZmbgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1zaW1wbGUKCkNyZWF0 ZXMgYSBuZXcgc2ltcGxlIHRlc3QtcnVubmVyLCB0aGF0IHByaW50cyBlcnJvcnMgYW5kIGEgc3Vt bWFyeSBvbgp0aGUgc3RhbmRhcmQgb3V0cHV0IHBvcnQuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2No ZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItbnVsbAoKQ3JlYXRlcyBhIG5ldyB0ZXN0LXJ1bm5l ciwgdGhhdCBkb2VzIG5vdGhpbmcgd2l0aCB0aGUgdGVzdCByZXN1bHRzLgpUaGlzIGlzIG1haW5s eSBtZWFudCBmb3IgZXh0ZW5kaW5nIHdoZW4gd3JpdGluZyBhIGN1c3RvbSBydW5uZXIuCkBlbmQg ZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItY3JlYXRlCgpDcmVh dGUgYSBuZXcgdGVzdC1ydW5uZXIuICBFcXVpdmFsZW50IHRvIEBzYW1weygodGVzdC1ydW5uZXIt ZmFjdG9yeSkpfS4KQGVuZCBkZWZmbgoKQGRlZmZuIHtTY2hlbWUgUGFyYW1ldGVyfSB0ZXN0LXJ1 bm5lci1mYWN0b3J5CkBkZWZmbngge1NjaGVtZSBQYXJhbWV0ZXJ9IHRlc3QtcnVubmVyLWZhY3Rv cnkgZmFjdG9yeQoKR2V0IG9yIHNldCB0aGUgY3VycmVudCB0ZXN0LXJ1bm5lciBmYWN0b3J5LiAg QSBmYWN0b3J5IGlzIGEKemVyby1hcmd1bWVudCBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgYSBuZXcg dGVzdC1ydW5uZXIuICBUaGUgZGVmYXVsdAp2YWx1ZSBpcyBAY29kZXt0ZXN0LXJ1bm5lci1zaW1w bGV9LgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBSdW5uaW5nIHNwZWNpZmljIHRlc3RzIHdp dGggYSBzcGVjaWZpZWQgcnVubmVyCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtYXBw bHkgW3J1bm5lcl0gc3BlY2lmaWVyIEBkb3Rze30gcHJvY2VkdXJlCgpDYWxscyBAdmFye3Byb2Nl ZHVyZX0gd2l0aCBubyBhcmd1bWVudHMgdXNpbmcgdGhlIHNwZWNpZmllZCBAdmFye3J1bm5lcn0K YXMgdGhlIGN1cnJlbnQgdGVzdC1ydW5uZXIuICBJZiBAdmFye3J1bm5lcn0gaXMgb21pdHRlZCwg dGhlbgpAY29kZXsodGVzdC1ydW5uZXItY3VycmVudCl9IGlzIHVzZWQuICAoSWYgdGhlcmUgaXMg bm8gY3VycmVudCBydW5uZXIsCm9uZSBpcyBjcmVhdGVkIGFzIGluIEBjb2Rle3Rlc3QtYmVnaW59 LikgIElmIG9uZSBvciBtb3JlCkB2YXJ7c3BlY2lmaWVyfXMgYXJlIGxpc3RlZCB0aGVuIG9ubHkg dGVzdHMgbWF0Y2hpbmcgdGhlCkB2YXJ7c3BlY2lmaWVyfXMgYXJlIGV4ZWN1dGVkLiAgQSBAdmFy e3NwZWNpZmllcn0gaGFzIHRoZSBzYW1lIGZvcm0gYXMKb25lIHVzZWQgZm9yIEBjb2Rle3Rlc3Qt c2tpcH0uICBBIHRlc3QgaXMgZXhlY3V0ZWQgaWYgaXQgbWF0Y2hlcyBhbnkgb2YKdGhlIEB2YXJ7 c3BlY2lmaWVyfXMgaW4gdGhlIEBjb2Rle3Rlc3QtYXBwbHl9IEBlbXBoe2FuZH0gZG9lcyBub3Qg bWF0Y2gKYW55IGFjdGl2ZSBAY29kZXt0ZXN0LXNraXB9IHNwZWNpZmllcnMuCkBlbmQgZGVmZm4K CkBkZWZmbiB7U2NoZW1lIFN5bnRheH0gdGVzdC13aXRoLXJ1bm5lciBydW5uZXIgZGVjbC1vci1l eHByIEBkb3Rze30KCkV4ZWN1dGVzIGVhY2ggQHZhcntkZWNsLW9yLWV4cHJ9IGluIG9yZGVyIGlu IGEgY29udGV4dCB3aGVyZSB0aGUgY3VycmVudAp0ZXN0LXJ1bm5lciBpcyBAdmFye3J1bm5lcn0u CkBlbmQgZGVmZm4KCkBub2RlIFNSRkkgNjQgVGVzdCByZXN1bHRzCkBzdWJzdWJzZWN0aW9uIFNS RkkgNjQgVGVzdCByZXN1bHRzCgpSdW5uaW5nIGEgdGVzdCBzZXRzIHZhcmlvdXMgc3RhdHVzIHBy b3BlcnRpZXMgaW4gdGhlIGN1cnJlbnQgdGVzdC1ydW5uZXIuClRoaXMgY2FuIGJlIGV4YW1pbmVk IGJ5IGEgY3VzdG9tIHRlc3QtcnVubmVyLApvciAobW9yZSByYXJlbHkpIGluIGEgdGVzdC1zdWl0 ZS4KCkBzdWJzdWJoZWFkaW5nIFJlc3VsdCBraW5kCgpSdW5uaW5nIGEgdGVzdCBtYXkgeWllbGQg b25lIG9mIHRoZSBmb2xsb3dpbmcKc3RhdHVzIHN5bWJvbHM6CgpAdGFibGUgQGFzaXMKQGl0ZW0g QGNvZGV7J3Bhc3N9ClRoZSB0ZXN0IHBhc3NlZCwgYXMgZXhwZWN0ZWQuCgpAaXRlbSBAY29kZXsn ZmFpbH0KVGhlIHRlc3QgZmFpbGVkIChhbmQgd2FzIG5vdCBleHBlY3RlZCB0bykuCgpAaXRlbSBA Y29kZXsneGZhaWx9ClRoZSB0ZXN0IGZhaWxlZCBhbmQgd2FzIGV4cGVjdGVkIHRvLgoKQGl0ZW0g QGNvZGV7J3hwYXNzfQpUaGUgdGVzdCBwYXNzZWQsIGJ1dCB3YXMgZXhwZWN0ZWQgdG8gZmFpbC4K CkBpdGVtIEBjb2Rleydza2lwfQpUaGUgdGVzdCB3YXMgc2tpcHBlZC4KQGVuZCB0YWJsZQoKQGRl ZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJlc3VsdC1raW5kIFtydW5uZXJdCgpSZXR1cm5z IG9uZSBvZiB0aGUgYWJvdmUgcmVzdWx0IGNvZGVzIGZyb20gdGhlIG1vc3QgcmVjZW50IHRlc3Rz LgpSZXR1cm5zIEBjb2RleyNmfSBpZiBubyB0ZXN0cyBoYXZlIGJlZW4gcnVuIHlldC4gIElmIHdl J3ZlIHN0YXJ0ZWQgb24gYQpuZXcgdGVzdCwgYnV0IGRvbid0IGhhdmUgYSByZXN1bHQgeWV0LCB0 aGVuIHRoZSByZXN1bHQga2luZCBpcwpAY29kZXsneGZhaWx9IGlmIHRoZSB0ZXN0IGlzIGV4cGVj dGVkIHRvIGZhaWwsIEBjb2Rleydza2lwfSBpZiB0aGUgdGVzdAppcyBzdXBwb3NlZCB0byBiZSBz a2lwcGVkLCBvciBAY29kZXsjZn0gb3RoZXJ3aXNlLgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVt ZSBQcm9jZWR1cmV9IHRlc3QtcGFzc2VkPyBbcnVubmVyXQoKVHJ1ZSBpZiB0aGUgdmFsdWUgb2Yg QHNhbXB7KHRlc3QtcmVzdWx0LWtpbmQgW0B2YXJ7cnVubmVyfV0pfSBpcyBvbmUgb2YKQGNvZGV7 J3Bhc3N9IG9yIEBjb2Rleyd4cGFzc30uICBUaGlzIGlzIGEgY29udmVuaWVudCBzaG9ydGhhbmQg dGhhdAptaWdodCBiZSB1c2VmdWwgaW4gYSB0ZXN0IHN1aXRlIHRvIG9ubHkgcnVuIGNlcnRhaW4g dGVzdHMgaWYgdGhlCnByZXZpb3VzIHRlc3QgcGFzc2VkLgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVh ZGluZyBUZXN0IHJlc3VsdCBwcm9wZXJ0aWVzCgpBIHRlc3QgcnVubmVyIGFsc28gbWFpbnRhaW5z IGEgc2V0IG9mIG1vcmUgZGV0YWlsZWQKYGByZXN1bHRAdGlle31wcm9wZXJ0aWVzJycgYXNzb2Np YXRlZCB3aXRoIHRoZSBjdXJyZW50IG9yIG1vc3QgcmVjZW50CnRlc3QuICAoSS5lLiB0aGUgcHJv cGVydGllcyBvZiB0aGUgbW9zdCByZWNlbnQgdGVzdCBhcmUgYXZhaWxhYmxlIGFzCmxvbmcgYXMg YSBuZXcgdGVzdCBoYXNuJ3Qgc3RhcnRlZC4pICBFYWNoIHByb3BlcnR5IGhhcyBhIG5hbWUgKGEg c3ltYm9sKQphbmQgYSB2YWx1ZSAoYW55IHZhbHVlKS4gIFNvbWUgcHJvcGVydGllcyBhcmUgc3Rh bmRhcmQgb3Igc2V0IGJ5IHRoZQppbXBsZW1lbnRhdGlvbjsgaW1wbGVtZW50YXRpb25zIGNhbiBh ZGQgbW9yZS4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1yZXN1bHQtcmVmIHJ1bm5l ciBwbmFtZSBbZGVmYXVsdF0KClJldHVybnMgdGhlIHByb3BlcnR5IHZhbHVlIGFzc29jaWF0ZWQg d2l0aCB0aGUgQHZhcntwbmFtZX0gcHJvcGVydHkgbmFtZQooYSBzeW1ib2wpLiAgSWYgdGhlcmUg aXMgbm8gdmFsdWUgYXNzb2NpYXRlZCB3aXRoIEB2YXJ7cG5hbWV9IHJldHVybgpAdmFye2RlZmF1 bHR9LCBvciBAY29kZXsjZn0gaWYgQHZhcntkZWZhdWx0fSBpc24ndCBzcGVjaWZpZWQuCkBlbmQg ZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFN5bnRheH0gdGVzdC1yZXN1bHQtc2V0ISBydW5uZXIgcG5h bWUgdmFsdWUKClNldHMgdGhlIHByb3BlcnR5IHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUgQHZh cntwbmFtZX0gcHJvcGVydHkgbmFtZSB0bwpAdmFye3ZhbHVlfS4gIFVzdWFsbHkgaW1wbGVtZW50 YXRpb24gY29kZSBzaG91bGQgY2FsbCB0aGlzIGZ1bmN0aW9uLCBidXQKaXQgbWF5IGJlIHVzZWZ1 bCBmb3IgYSBjdXN0b20gdGVzdC1ydW5uZXIgdG8gYWRkIGV4dHJhIHByb3BlcnRpZXMuCkBlbmQg ZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1yZXN1bHQtcmVtb3ZlIHJ1bm5l ciBwbmFtZQoKUmVtb3ZlIHRoZSBwcm9wZXJ0eSB3aXRoIHRoZSBuYW1lIEB2YXJ7cG5hbWV9LgpA ZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcmVzdWx0LWNsZWFyIHJ1 bm5lcgoKUmVtb3ZlIGFsbCByZXN1bHQgcHJvcGVydGllcy4gIFRoZSBpbXBsZW1lbnRhdGlvbiBh dXRvbWF0aWNhbGx5IGNhbGxzCkBjb2Rle3Rlc3QtcmVzdWx0LWNsZWFyfSBhdCB0aGUgc3RhcnQg b2YgYSBAY29kZXt0ZXN0LWFzc2VydH0gYW5kCnNpbWlsYXIgcHJvY2VkdXJlcy4KQGVuZCBkZWZm bgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJlc3VsdC1hbGlzdCBydW5uZXIKClJl dHVybnMgYW4gYXNzb2NpYXRpb24gbGlzdCBvZiB0aGUgY3VycmVudCByZXN1bHQgcHJvcGVydGll cy4gIEl0IGlzCnVuc3BlY2lmaWVkIGlmIHRoZSByZXN1bHQgc2hhcmVzIHN0YXRlIHdpdGggdGhl IHRlc3QtcnVubmVyLiAgVGhlIHJlc3VsdApzaG91bGQgbm90IGJlIG1vZGlmaWVkOyBvbiB0aGUg b3RoZXIgaGFuZCwgdGhlIHJlc3VsdCBtYXkgYmUgaW1wbGljaXRseQptb2RpZmllZCBieSBmdXR1 cmUgQGNvZGV7dGVzdC1yZXN1bHQtc2V0IX0gb3IgQGNvZGV7dGVzdC1yZXN1bHQtcmVtb3ZlfQpj YWxscy4gIEhvd2V2ZXIsIGEgQGNvZGV7dGVzdC1yZXN1bHQtY2xlYXJ9IGRvZXMgbm90IG1vZGlm eSB0aGUgcmV0dXJuZWQKYWxpc3QuICBUaHVzIHlvdSBjYW4gYGBhcmNoaXZlJycgcmVzdWx0IG9i amVjdHMgZnJvbSBwcmV2aW91cyBydW5zLgpAZW5kIGRlZmZuCgpAc3Vic3ViaGVhZGluZyBTdGFu ZGFyZCByZXN1bHQgcHJvcGVydGllcwoKVGhlIHNldCBvZiBhdmFpbGFibGUgcmVzdWx0IHByb3Bl cnRpZXMgaXMgaW1wbGVtZW50YXRpb24tc3BlY2lmaWMuCkhvd2V2ZXIsIGl0IGlzIHN1Z2dlc3Rl ZCB0aGF0IHRoZSBmb2xsb3dpbmcgbWlnaHQgYmUgcHJvdmlkZWQ6CkB0YWJsZSBAYXNpcwoKQGl0 ZW0gQGNvZGV7J3Jlc3VsdC1raW5kfQpUaGUgcmVzdWx0IGtpbmQsIGFzIGRlZmluZWQgcHJldmlv dXNseS4KVGhpcyBpcyB0aGUgb25seSBtYW5kYXRvcnkgcmVzdWx0IHByb3BlcnR5LgpAY29kZXso dGVzdC1yZXN1bHQta2luZCBAdmFye3J1bm5lcn0pfSBpcyBlcXVpdmFsZW50IHRvOgpAY29kZXso dGVzdC1yZXN1bHQtcmVmICBAdmFye3J1bm5lcn0gJ3Jlc3VsdC1raW5kKX0KCkBpdGVtIEBjb2Rl eydzb3VyY2UtZmlsZX0KQGl0ZW14IEBjb2Rleydzb3VyY2UtbGluZX0KSWYga25vd24sIHRoZSBs b2NhdGlvbiBvZiB0ZXN0IHN0YXRlbWVudHMgKHN1Y2ggYXMgQGNvZGV7dGVzdC1hc3NlcnR9KQpp biB0ZXN0IHN1aXRlIHNvdXJjZSBjb2RlLgoKQGl0ZW0gQGNvZGV7J3NvdXJjZS1mb3JtfQpUaGUg c291cmNlIGZvcm0sIGlmIG1lYW5pbmdmdWwgYW5kIGtub3duLgoKQGl0ZW0gQGNvZGV7J2V4cGVj dGVkLXZhbHVlfQpUaGUgZXhwZWN0ZWQgbm9uLWVycm9yIHJlc3VsdCwgaWYgbWVhbmluZ2Z1bCBh bmQga25vd24uCgpAaXRlbSBAY29kZXsnZXhwZWN0ZWQtZXJyb3J9ClRoZSBAdmFye2Vycm9yLXR5 cGV9c3BlY2lmaWVkIGluIGEgQGNvZGV7dGVzdC1lcnJvcn0sIGlmIGl0IG1lYW5pbmdmdWwgYW5k IGtub3duLgoKQGl0ZW0gQGNvZGV7J2FjdHVhbC12YWx1ZX0KVGhlIGFjdHVhbCBub24tZXJyb3Ig cmVzdWx0IHZhbHVlLCBpZiBtZWFuaW5nZnVsIGFuZCBrbm93bi4KCkBpdGVtIEBjb2RleydhY3R1 YWwtZXJyb3J9ClRoZSBlcnJvciB2YWx1ZSwgaWYgYW4gZXJyb3Igd2FzIHNpZ25hbGxlZCBhbmQg aXQgaXMga25vd24uClRoZSBhY3R1YWwgZXJyb3IgdmFsdWUgaXMgaW1wbGVtZW50YXRpb24tZGVm aW5lZC4KQGVuZCB0YWJsZQoKQG5vZGUgU1JGSSA2NCBXcml0aW5nIGEgbmV3IHRlc3QtcnVubmVy CkBzdWJzdWJzZWN0aW9uIFNSRkkgNjQgV3JpdGluZyBhIG5ldyB0ZXN0LXJ1bm5lcgoKVGhpcyBz ZWN0aW9uIHNwZWNpZmllcyBob3cgdG8gd3JpdGUgYSB0ZXN0LXJ1bm5lci4gIEl0IGNhbiBiZSBp Z25vcmVkIGlmCnlvdSBqdXN0IHdhbnQgdG8gd3JpdGUgdGVzdC1jYXNlcy4KCkBzdWJzdWJoZWFk aW5nIENhbGwtYmFjayBmdW5jdGlvbnMKClRoZXNlIGNhbGwtYmFjayBmdW5jdGlvbnMgYXJlIGBg bWV0aG9kcycnIChpbiB0aGUgb2JqZWN0LW9yaWVudGVkIHNlbnNlKQpvZiBhIHRlc3QtcnVubmVy LiAgQSBtZXRob2QgQGNvZGV7dGVzdC1ydW5uZXItb24tQHZhcntldmVudH19IGlzIGNhbGxlZApi eSB0aGUgaW1wbGVtZW50YXRpb24gd2hlbiBAdmFye2V2ZW50fSBoYXBwZW5zLgoKVG8gZGVmaW5l IChzZXQpIHRoZSBjYWxsYmFjayBmdW5jdGlvbiBmb3IgQHZhcntldmVudH0gdXNlIHRoZSBmb2xs b3dpbmcKZXhwcmVzc2lvbi4gIChUaGlzIGlzIG5vcm1hbGx5IGRvbmUgd2hlbiBpbml0aWFsaXpp bmcgYSB0ZXN0LXJ1bm5lci4pCgpAY29kZXsodGVzdC1ydW5uZXItb24tQHZhcntldmVudH0hIEB2 YXJ7cnVubmVyfSBAdmFye2V2ZW50LWZ1bmN0aW9ufSl9CgpBbiBAdmFye2V2ZW50LWZ1bmN0aW9u fSB0YWtlcyBhIHRlc3QtcnVubmVyIGFyZ3VtZW50LCBhbmQgcG9zc2libHkgb3RoZXIKYXJndW1l bnRzLCBkZXBlbmRpbmcgb24gdGhlIEB2YXJ7ZXZlbnR9LgoKVG8gZXh0cmFjdCAoZ2V0KSB0aGUg Y2FsbGJhY2sgZnVuY3Rpb24gZm9yIEB2YXJ7ZXZlbnR9IGRvIHRoaXM6CkBjb2Rleyh0ZXN0LXJ1 bm5lci1vbi1AdmFye2V2ZW50fSBAdmFye3J1bm5lcn0pfQoKVG8gZXh0cmFjdCBjYWxsIHRoZSBj YWxsYmFjayBmdW5jdGlvbiBmb3IgQHZhcntldmVudH0gdXNlIHRoZSBmb2xsb3dpbmcKZXhwcmVz c2lvbi4gIChUaGlzIGlzIG5vcm1hbGx5IGRvbmUgYnkgdGhlIGltcGxlbWVudGF0aW9uIGNvcmUu KQpAc2FtcHsoKHRlc3QtcnVubmVyLW9uLUB2YXJ7ZXZlbnR9IEB2YXJ7cnVubmVyfSkgQHZhcnty dW5uZXJ9CkB2YXJ7b3RoZXItYXJnc30gQGRvdHN7fSl9LgoKVGhlIGZvbGxvd2luZyBjYWxsLWJh Y2sgaG9va3MgYXJlIGF2YWlsYWJsZS4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1y dW5uZXItb24tdGVzdC1iZWdpbiBydW5uZXIKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gdGVz dC1ydW5uZXItb24tdGVzdC1iZWdpbiEgcnVubmVyIG9uLXRlc3QtYmVnaW4tZnVuY3Rpb24KQGRl ZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gb24tdGVzdC1iZWdpbi1mdW5jdGlvbiBydW5uZXIKClRo ZSBAdmFye29uLXRlc3QtYmVnaW4tZnVuY3Rpb259IGlzIGNhbGxlZCBhdCB0aGUgc3RhcnQgb2Yg YW4KaW5kaXZpZHVhbCB0ZXN0Y2FzZSwgYmVmb3JlIHRoZSB0ZXN0IGV4cHJlc3Npb24gKGFuZCBl eHBlY3RlZCB2YWx1ZSkgYXJlCmV2YWx1YXRlZC4KCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2NoZW1l IFByb2NlZHVyZX0gdGVzdC1ydW5uZXItb24tdGVzdC1lbmQgcnVubmVyCkBkZWZmbngge1NjaGVt ZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLXRlc3QtZW5kISBydW5uZXIgb24tdGVzdC1lbmQt ZnVuY3Rpb24KQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gb24tdGVzdC1lbmQtZnVuY3Rpb24g cnVubmVyCgpUaGUgQHZhcntvbi10ZXN0LWVuZC1mdW5jdGlvbn0gaXMgY2FsbGVkIGF0IHRoZSBl bmQgb2YgYW4KaW5kaXZpZHVhbCB0ZXN0Y2FzZSwgd2hlbiB0aGUgcmVzdWx0IG9mIHRoZSB0ZXN0 IGlzIGF2YWlsYWJsZS4KQGVuZCBkZWZmbgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0 LXJ1bm5lci1vbi1ncm91cC1iZWdpbiBydW5uZXIKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0g dGVzdC1ydW5uZXItb24tZ3JvdXAtYmVnaW4hIHJ1bm5lciBvbi1ncm91cC1iZWdpbi1mdW5jdGlv bgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSBvbi1ncm91cC1iZWdpbi1mdW5jdGlvbiBydW5u ZXIgc3VpdGUtbmFtZSBjb3VudAoKVGhlIEB2YXJ7b24tZ3JvdXAtYmVnaW4tZnVuY3Rpb259IGlz IGNhbGxlZCBieSBhIEBjb2Rle3Rlc3QtYmVnaW59LAppbmNsdWRpbmcgYXQgdGhlIHN0YXJ0IG9m IGEgQGNvZGV7dGVzdC1ncm91cH0uICBUaGUgQHZhcntzdWl0ZS1uYW1lfSBpcwphIFNjaGVtZSBz dHJpbmcsIGFuZCBAdmFye2NvdW50fSBpcyBhbiBpbnRlZ2VyIG9yIEBjb2RleyNmfS4KQGVuZCBk ZWZmbgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi1ncm91cC1lbmQg cnVubmVyCkBkZWZmbngge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLWdyb3VwLWVu ZCEgcnVubmVyIG9uLWdyb3VwLWVuZC1mdW5jdGlvbgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJl fSBvbi1ncm91cC1lbmQtZnVuY3Rpb24gcnVubmVyCgpUaGUgQHZhcntvbi1ncm91cC1lbmQtZnVu Y3Rpb259IGlzIGNhbGxlZCBieSBhIEBjb2Rle3Rlc3QtZW5kfSwKaW5jbHVkaW5nIGF0IHRoZSBl bmQgb2YgYSBAY29kZXt0ZXN0LWdyb3VwfS4KQGVuZCBkZWZmbgoKQGRlZmZuIHtTY2hlbWUgUHJv Y2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi1iYWQtY291bnQgcnVubmVyCkBkZWZmbngge1NjaGVtZSBQ cm9jZWR1cmV9IHRlc3QtcnVubmVyLW9uLWJhZC1jb3VudCEgcnVubmVyIG9uLWJhZC1jb3VudC1m dW5jdGlvbgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSBvbi1iYWQtY291bnQtZnVuY3Rpb24g cnVubmVyIGFjdHVhbC1jb3VudCBleHBlY3RlZC1jb3VudAoKQ2FsbGVkIGZyb20gQGNvZGV7dGVz dC1lbmR9IChiZWZvcmUgdGhlIEB2YXJ7b24tZ3JvdXAtZW5kLWZ1bmN0aW9ufSBpcwpjYWxsZWQp IGlmIGFuIEB2YXJ7ZXhwZWN0ZWQtY291bnR9IHdhcyBzcGVjaWZpZWQgYnkgdGhlIG1hdGNoaW5n CkBjb2Rle3Rlc3QtYmVnaW59IGFuZCB0aGUgQHZhcntleHBlY3RlZC1jb3VudH0gZG9lcyBub3Qg bWF0Y2ggdGhlCkB2YXJ7YWN0dWFsLWNvdW50fSBvZiB0ZXN0cyBhY3R1YWxseSBleGVjdXRlZCBv ciBza2lwcGVkLgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3QtcnVu bmVyLW9uLWJhZC1lbmQtbmFtZSBydW5uZXIKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gdGVz dC1ydW5uZXItb24tYmFkLWVuZC1uYW1lISBydW5uZXIgb24tYmFkLWVuZC1uYW1lLWZ1bmN0aW9u CkBkZWZmbngge1NjaGVtZSBQcm9jZWR1cmV9IG9uLWJhZC1lbmQtbmFtZS1mdW5jdGlvbiBydW5u ZXIgYmVnaW4tbmFtZSBlbmQtbmFtZQoKQ2FsbGVkIGZyb20gQGNvZGV7dGVzdC1lbmR9IChiZWZv cmUgdGhlIEB2YXJ7b24tZ3JvdXAtZW5kLWZ1bmN0aW9ufSBpcwpjYWxsZWQpIGlmIGEgQHZhcntz dWl0ZS1uYW1lfSB3YXMgc3BlY2lmaWVkLCBhbmQgaXQgZGlkIG5vdCB0aGF0IHRoZQpuYW1lIGlu IHRoZSBtYXRjaGluZyBAY29kZXt0ZXN0LWJlZ2lufS4KQGVuZCBkZWZmbgoKQGRlZmZuIHtTY2hl bWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1vbi1maW5hbCBydW5uZXIKQGRlZmZueCB7U2NoZW1l IFByb2NlZHVyZX0gdGVzdC1ydW5uZXItb24tZmluYWwhIHJ1bm5lciBvbi1maW5hbC1mdW5jdGlv bgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSBvbi1maW5hbC1mdW5jdGlvbiBydW5uZXIKClRo ZSBAdmFye29uLWZpbmFsLWZ1bmN0aW9ufSB0YWtlcyBvbmUgcGFyYW1ldGVyIChhIHRlc3QtcnVu bmVyKSBhbmQKdHlwaWNhbGx5IGRpc3BsYXlzIGEgc3VtbWFyeSAoY291bnQpIG9mIHRoZSB0ZXN0 cy4gIFRoZQpAdmFye29uLWZpbmFsLWZ1bmN0aW9ufSBpcyBjYWxsZWQgYWZ0ZXIgY2FsbGVkIHRo ZQpAdmFye29uLWdyb3VwLWVuZC1mdW5jdGlvbn0gY29ycmVzcG9uZGlvbmcgdG8gdGhlIG91dGVy bW9zdApAY29kZXt0ZXN0LWVuZH0uICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBAY29kZXt0ZXN0LW9u LWZpbmFsLXNpbXBsZX0gd2hpY2gKd3JpdGVzIHRvIHRoZSBzdGFuZGFyZCBvdXRwdXQgcG9ydCB0 aGUgbnVtYmVyIG9mIHRlc3RzIG9mIHRoZSB2YXJpb3VzCmtpbmRzLgpAZW5kIGRlZmZuCgpUaGUg ZGVmYXVsdCB0ZXN0LXJ1bm5lciByZXR1cm5lZCBieSBAY29kZXt0ZXN0LXJ1bm5lci1zaW1wbGV9 IHVzZXMgdGhlCmZvbGxvd2luZyBjYWxsLWJhY2sgZnVuY3Rpb25zOgoKQGRlZmZuIHtTY2hlbWUg UHJvY2VkdXJlfSB0ZXN0LW9uLXRlc3QtYmVnaW4tc2ltcGxlIHJ1bm5lcgpAZGVmZm54IHtTY2hl bWUgUHJvY2VkdXJlfSB0ZXN0LW9uLXRlc3QtZW5kLXNpbXBsZSBydW5uZXIKQGRlZmZueCB7U2No ZW1lIFByb2NlZHVyZX0gdGVzdC1vbi1ncm91cC1iZWdpbi1zaW1wbGUgcnVubmVyIHN1aXRlLW5h bWUgY291bnQKQGRlZmZueCB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1vbi1ncm91cC1lbmQtc2lt cGxlIHJ1bm5lcgpAZGVmZm54IHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LW9uLWJhZC1jb3VudC1z aW1wbGUgcnVubmVyIGFjdHVhbC1jb3VudCBleHBlY3RlZC1jb3VudApAZGVmZm54IHtTY2hlbWUg UHJvY2VkdXJlfSB0ZXN0LW9uLWJhZC1lbmQtbmFtZS1zaW1wbGUgcnVubmVyIGJlZ2luLW5hbWUg ZW5kLW5hbWUKCllvdSBjYW4gY2FsbCB0aG9zZSBpZiB5b3Ugd2FudCB0byB3cml0ZSB5b3VyIG93 biB0ZXN0LXJ1bm5lci4KQGVuZCBkZWZmbgoKQHN1YnN1YmhlYWRpbmcgVGVzdC1ydW5uZXIgY29t cG9uZW50cwoKVGhlIGZvbGxvd2luZyBmdW5jdGlvbnMgYXJlIGZvciBhY2Nlc3NpbmcgdGhlIG90 aGVyIGNvbXBvbmVudHMgb2YgYQp0ZXN0LXJ1bm5lci4gIFRoZXkgd291bGQgbm9ybWFsbHkgb25s eSBiZSB1c2VkIHRvIHdyaXRlIGEgbmV3CnRlc3QtcnVubmVyIG9yIGEgbWF0Y2gtcHJlZGljYXRl LgoKQGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci1wYXNzLWNvdW50IHJ1bm5l cgoKUmV0dXJucyB0aGUgbnVtYmVyIG9mIHRlc3RzIHRoYXQgcGFzc2VkLCBhbmQgd2VyZSBleHBl Y3RlZCB0byBwYXNzLgpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVtZSBQcm9jZWR1cmV9IHRlc3Qt cnVubmVyLWZhaWwtY291bnQgcnVubmVyCgpSZXR1cm5zIHRoZSBudW1iZXIgb2YgdGVzdHMgdGhh dCBmYWlsZWQsIGJ1dCB3ZXJlIGV4cGVjdGVkIHRvIHBhc3MuCkBlbmQgZGVmZm4KCkBkZWZmbiB7 U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXIteHBhc3MtY291bnQgcnVubmVyCgpSZXR1cm5z IHRoZSBudW1iZXIgb2YgdGVzdHMgdGhhdCBwYXNzZWQsIGJ1dCB3ZXJlIGV4cGVjdGVkIHRvIGZh aWwuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXIteGZh aWwtY291bnQgcnVubmVyCgpSZXR1cm5zIHRoZSBudW1iZXIgb2YgdGVzdHMgdGhhdCBmYWlsZWQs IGFuZCB3ZXJlIGV4cGVjdGVkIHRvIHBhc3MuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFBy b2NlZHVyZX0gdGVzdC1ydW5uZXItc2tpcC1jb3VudCBydW5uZXIKClJldHVybnMgdGhlIG51bWJl ciBvZiB0ZXN0cyBvciB0ZXN0IGdyb3VwcyB0aGF0IHdlcmUgc2tpcHBlZC4KQGVuZCBkZWZmbgoK QGRlZmZuIHtTY2hlbWUgUHJvY2VkdXJlfSB0ZXN0LXJ1bm5lci10ZXN0LW5hbWUgcnVubmVyCgpS ZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBjdXJyZW50IHRlc3Qgb3IgdGVzdCBncm91cCwgYXMgYSBz dHJpbmcuICBEdXJpbmcKZXhlY3V0aW9uIG9mIEBjb2Rle3Rlc3QtYmVnaW59IHRoaXMgaXMgdGhl IG5hbWUgb2YgdGhlIHRlc3QgZ3JvdXA7CmR1cmluZyB0aGUgZXhlY3V0aW9uIG9mIGFuIGFjdHVh bCB0ZXN0LCB0aGlzIGlzIHRoZSBuYW1lIG9mIHRoZQp0ZXN0LWNhc2UuICBJZiBubyBuYW1lIHdh cyBzcGVjaWZpZWQsIHRoZSBuYW1lIGlzIHRoZSBlbXB0eSBzdHJpbmcuCkBlbmQgZGVmZm4KCkBk ZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVzdC1ydW5uZXItZ3JvdXAtcGF0aCBydW5uZXIKCkEg bGlzdCBvZiBuYW1lcyBvZiBncm91cHMgd2UncmUgbmVzdGVkIGluLCB3aXRoIHRoZSBvdXRlcm1v c3QgZ3JvdXAKZmlyc3QuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVyZX0gdGVz dC1ydW5uZXItZ3JvdXAtc3RhY2sgcnVubmVyCgpBIGxpc3Qgb2YgbmFtZXMgb2YgZ3JvdXBzIHdl J3JlIG5lc3RlZCBpbiwgd2l0aCB0aGUgb3V0ZXJtb3N0IGdyb3VwCmxhc3QuICAoVGhpcyBpcyBt b3JlIGVmZmljaWVudCB0aGFuIEBjb2Rle3Rlc3QtcnVubmVyLWdyb3VwLXBhdGh9LCBzaW5jZQpp dCBkb2Vzbid0IHJlcXVpcmUgYW55IGNvcHlpbmcuKQpAZW5kIGRlZmZuCgpAZGVmZm4ge1NjaGVt ZSBQcm9jZWR1cmV9IHRlc3QtcnVubmVyLWF1eC12YWx1ZSBydW5uZXIKQGRlZmZueCB7U2NoZW1l IFByb2NlZHVyZX0gdGVzdC1ydW5uZXItYXV4LXZhbHVlISBydW5uZXIgb24tdGVzdAoKR2V0IG9y IHNldCB0aGUgQGNvZGV7YXV4LXZhbHVlfSBmaWVsZCBvZiBhIHRlc3QtcnVubmVyLiAgVGhpcyBm aWVsZCBpcwpub3QgdXNlZCBieSB0aGlzIEFQSSBvciB0aGUgQGNvZGV7dGVzdC1ydW5uZXItc2lt cGxlfSB0ZXN0LXJ1bm5lciwgYnV0Cm1heSBiZSB1c2VkIGJ5IGN1c3RvbSB0ZXN0LXJ1bm5lcnMg dG8gc3RvcmUgZXh0cmEgc3RhdGUuCkBlbmQgZGVmZm4KCkBkZWZmbiB7U2NoZW1lIFByb2NlZHVy ZX0gdGVzdC1ydW5uZXItcmVzZXQgcnVubmVyCgpSZXNldHMgdGhlIHN0YXRlIG9mIHRoZSBAdmFy e3J1bm5lcn0gdG8gaXRzIGluaXRpYWwgc3RhdGUuCkBlbmQgZGVmZm4KCkBzdWJzdWJoZWFkaW5n IEV4YW1wbGUKClRoaXMgaXMgYW4gZXhhbXBsZSBvZiBhIHNpbXBsZSBjdXN0b20gdGVzdC1ydW5u ZXIuCkxvYWRpbmcgdGhpcyBwcm9ncmFtIGJlZm9yZSBydW5uaW5nIGEgdGVzdC1zdWl0ZSB3aWxs IGluc3RhbGwKaXQgYXMgdGhlIGRlZmF1bHQgdGVzdCBydW5uZXIuCgpAbGlzcAooZGVmaW5lICht eS1zaW1wbGUtcnVubmVyIGZpbGVuYW1lKQogIChsZXQgKChydW5uZXIgKHRlc3QtcnVubmVyLW51 bGwpKQoJKHBvcnQgKG9wZW4tb3V0cHV0LWZpbGUgZmlsZW5hbWUpKQogICAgICAgIChudW0tcGFz c2VkIDApCiAgICAgICAgKG51bS1mYWlsZWQgMCkpCiAgICAodGVzdC1ydW5uZXItb24tdGVzdC1l bmQhIHJ1bm5lcgogICAgICAobGFtYmRhIChydW5uZXIpCiAgICAgICAgKGNhc2UgKHRlc3QtcmVz dWx0LWtpbmQgcnVubmVyKQogICAgICAgICAgKChwYXNzIHhwYXNzKSAoc2V0ISBudW0tcGFzc2Vk ICgrIG51bS1wYXNzZWQgMSkpKQogICAgICAgICAgKChmYWlsIHhmYWlsKSAoc2V0ISBudW0tZmFp bGVkICgrIG51bS1mYWlsZWQgMSkpKQogICAgICAgICAgKGVsc2UgI3QpKSkpCiAgICAodGVzdC1y dW5uZXItb24tZmluYWwhIHJ1bm5lcgogICAgICAgKGxhbWJkYSAocnVubmVyKQogICAgICAgICAg KGZvcm1hdCBwb3J0ICJQYXNzaW5nIHRlc3RzOiB+ZC5+JUZhaWxpbmcgdGVzdHM6IH5kLn4lIgog ICAgICAgICAgICAgICAgICBudW0tcGFzc2VkIG51bS1mYWlsZWQpCgkgIChjbG9zZS1vdXRwdXQt cG9ydCBwb3J0KSkpCiAgICBydW5uZXIpKQoodGVzdC1ydW5uZXItZmFjdG9yeQogKGxhbWJkYSAo KSAobXktc2ltcGxlLXJ1bm5lciAiL3RtcC9teS10ZXN0LmxvZyIpKSkKQGVuZCBsaXNwCg== --=-=-= Content-Type: text/plain -- Thanks, Maxim --=-=-=-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v3] doc: Document SRFI 64. Resent-From: Tomas Volf <~@wolfsden.cz> Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Wed, 23 Oct 2024 00:31:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Maxime Devos Cc: "71300@debbugs.gnu.org" <71300@debbugs.gnu.org>, Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxim Cournoyer Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.17296434113748 (code B ref 71300); Wed, 23 Oct 2024 00:31:02 +0000 Received: (at 71300) by debbugs.gnu.org; 23 Oct 2024 00:30:11 +0000 Received: from localhost ([127.0.0.1]:58066 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t3PGN-0000yO-68 for submit@debbugs.gnu.org; Tue, 22 Oct 2024 20:30:11 -0400 Received: from wolfsden.cz ([37.205.8.62]:42088) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1t3PGI-0000x1-Bc for 71300@debbugs.gnu.org; Tue, 22 Oct 2024 20:30:09 -0400 Received: by wolfsden.cz (Postfix, from userid 104) id 519833107ED; Wed, 23 Oct 2024 00:29:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1729643376; bh=UVY1NE4f41snSEWl3fp0h8L/X3w3QbHMexFSiGlZLGw=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=IsXgTBsByF34i5dy42O2HQ2ojDyWv4Awc1f5HTsQiXpuPk6kftWJ36TTV5JCWXdWw pZAn4mdqAEvOTlN6g45zcB15dolEq8IoEd4UiOiQxgU+D13YxMfq31unJhpyD+ChoR 0bt1aQCpeNcxMGsV8AAVhPW8VgXpq1Qj9xKXed8gX3QNGt/j+r2/gN7akgZ7b2FAQb 9zh5SFtL1ulK8iWOQP2LoSxzaCn+tIOrvAWlwXhWktpwdIX0ushc3mZZZmyec2XBCR HPJtsKY6YyAV1acNWhyKXUqIzz9p1Aua1/i7+CeXZor9xL4YytKAgdaj454jR6K7H0 nCkxNf3Auqs084lHyFLkDjdBoQ5gABf9bn6btlhT06AqVWNNtJRqD4PAUsfA0Zm408 X55J4Jo8BlKnciTWrqANIy4NT29czvLqAXmsla7v8Rdb7/yYtE/8V1J2hIQHfkK+Vn tY4lC1EHnbU0/w/BicyG4TfAW3dmIOZgNi1J1xoZGabI8rY4pkzKQE/exrum1+a+SH EbbCSrzi96wjX0tyYJm/62qeDDNfvwa+x6SfK46Gb/iq86bpbchkib/OSbm9DNScFd H22k9XyZ0Kel65qMxoQ6BKAVAS5kPU45wQs9t4taUNlGqUSGQoDUS3Zcqbj1xJllMS I73m5wEfnSQdYnmwsduhfXL8= X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on wolfsden X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from localhost (unknown [128.0.188.242]) by wolfsden.cz (Postfix) with ESMTPSA id DF35A310F17; Wed, 23 Oct 2024 00:29:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1729643375; bh=UVY1NE4f41snSEWl3fp0h8L/X3w3QbHMexFSiGlZLGw=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=RQMDS08dm5O9T3h5UOhVD5SnTDGBaLNUw0LFTlont9x/BqSSQaFMoHL909CXGetR7 s+4VKXQbVm3NBrTjyrVl45SlMHr3NcCI7BTuSteBlBFPEyOxBxnu0KuMisbcN00/ts wh+Dx/PyLQDdeBQA9DdqK2kCtlLcEX+tZj+ukvDZxk7dKRpqkJRzqdF44iaNqZUpsh VTsrgppBbLJGOMoDY84pm8GoE8u7ckscftDPve0qYZWV0nS2SSdIQ6b7zMIm+CVAw+ peC/aV8RwqGu59iLak+59XMg75Fhv8QN1+iOmed/sX4xhm2fj9cqdsDSfAXhwPkuVR XVABOXAJzHhy1TBFJnrgdAeO5fvbxCX29SokObXskRtIvbsRPHpQ5SNzYcPY3UFhLl FEgU8YD4SPVNBvx4wrGiGX02MY+3TJflToMKv/kOk8Cd3ZoqUpJSOreZ7AkU5AJ5lH x4/bv2tGeGK7XUPSP3why88MRAuTYe7j4VN9+UB+cVpw66P3BxAemFCCYkEV76GvuF o0Prvf0kKxqrTz7Xm0iPRqdBwbe0egXMz787rv1hGfIi4LmZBbP6kZAu1V8M9K7tcw kg7SQ6r00LqQcr3xBIPyBro5aW5rMVY/76wHIbcpDP7N/zTZDbsC+HMOERCY17ISd9 bC8d0nk+SbQM/7/XgSdknEao= From: Tomas Volf <~@wolfsden.cz> In-Reply-To: <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> (Maxime Devos's message of "Sun, 29 Sep 2024 21:43:37 +0200") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <877cb3hnvr.fsf@wolfsden.cz> <87r096edvz.fsf@gmail.com> <20240929214340.JKjf2D00f5Amo2z01KjgPd@andre.telenet-ops.be> Date: Wed, 23 Oct 2024 02:29:34 +0200 Message-ID: <87plnr64r5.fsf_-_@wolfsden.cz> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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 =E2=80=9Cleft to the implementation=E2=80=9D -> =E2= =80=9Cwhat Guile does=E2=80=9D is > problematic, since it misleads readers into thinking this is the standard > behaviour (it is after all named SRFI 64, not GRFI 64). > > =E2=80=9CWhat Guile does=E2=80=9D is also important information to have. > > To avoid this problem, when it documents a choice made by Guile, it shoul= d indicate in some way that this is Guile behaviour. > (E.g.: =E2=80=9CIt is left to the implementation what happens when A. Gui= le chooses to > B.=E2=80=9D, or =E2=80=9CIt is left to the implementation what happens wh= en A. Guile currently > chooses to B, but may choose differently in future versions.=E2=80=9D) > >>> I think either of those is fine (albeit describing the Guile's flavor >>> would be preferred), but is should be stated (that the behavior >>There's not really a Guile flavor; it's more like the reference > implementation flavor ;-). The one in Guile is pretty stock. > > Then Guile flavour is stock flavour, and stock flavour isn=E2=80=99t spec= ification > vanilla. From what I=E2=80=99ve heard, it=E2=80=99s not just sprinkles ad= ded to vanilla, it also > has bugs (not the crunchy food kind). Since Ludovic was so kind to merge my patch replacing the SRFI-64 implementation with a new version, to use your wording, Guile flavour is no longer stock flavour, and should be pretty close to specification vanilla. I believe that should simplify documenting it. I explicitly tried to stick as close as possible to the specification. Those few implementation choices I made are described in the info manual for my guile library. For your convenience, HTML version can be found here[0]. The next section (2.9.2) could possibly be of use as well. 0: https://files.wolfsden.cz/manuals/guile-wolfsden/guile-wolfsden-0.0.4.ht= ml#SRFI_002d64-implementation-choices Have a nice day, Tomas --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJCBAEBCgAsFiEEt4NJs4wUfTYpiGikL7/ufbZ/wakFAmcYQ24OHH5Ad29sZnNk ZW4uY3oACgkQL7/ufbZ/wamsphAAjAd36VI3MJQwgLkxM209RlHxljX2yzCr5HXy v6T/gfzrHJP+mxtWswEbuvq1p7Sn+vKnINXy3oCWMmoqJ7soyjAZt/NGT9vps/Ue KkrjyluIMWQm6SvOSR5GTt3iyekXZp70NRZKmRCLPyxg/TBU3v1RRm3m2zYcm70D c2TmdtAY2tL7l+uO1s8DbzMzSsCaELCNWVuqUoVqwhVKIILtDHwQbcLtLeFRy0Ju rvSYca9RUuBrchcr/jD+9zcD7f8q1sryCpRQhq/SObTtggLxEN/BjpnqxDv21LIv 5mxVfYwJ6sL0lPKHxOkadgmbJcmz8tAFGwSsO54+zT6SV0f6itzIJ+bFnJTBLc6j xVZ0PEZt6rm7dOAvvIF7sNFd6j5wFPZ+moDGl81RfA6sawThi0MyK+QByv2N8Bee nWuGLXv7/ozR2XEwDlaQMLcrooQYcQyLBn2JH+57/Ber4Hegs4ShtE1yR0/pZVtZ 0UTOfvbOWdox/4H8ibGqhPDV+EimDl/s7OKupDLUPv7l0n8FB6BhoNsdj0IK5B2x deiUU/Trww4KAxc3FBcylKyHWm2PhqUv1g/7U5Ssr85fpm7eyHl/gDL1ki8FD79L BpPefXdPLZzZ47x9BS6mLHfPbJbe/w9C79YYXlVfJeYcyeJs6PjkUi5KvC4/usj6 VN849SQ= =tkhi -----END PGP SIGNATURE----- --=-=-=-- From unknown Sat Jun 14 19:41:16 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: Maxim Cournoyer Subject: bug#71300: closed (Re: bug#71300: [PATCH v3] doc: Document SRFI 64.) Message-ID: References: <87ldw7fll7.fsf_-_@gnu.org> <20240601021743.808-1-maxim.cournoyer@gmail.com> X-Gnu-PR-Message: they-closed 71300 X-Gnu-PR-Package: guile X-Gnu-PR-Keywords: patch Reply-To: 71300@debbugs.gnu.org Date: Sun, 22 Dec 2024 21:36:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1734903362-10892-1" This is a multi-part message in MIME format... ------------=_1734903362-10892-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #71300: [PATCH v3] doc: Document SRFI 64. which was filed against the guile package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 71300@debbugs.gnu.org. --=20 71300: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D71300 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1734903362-10892-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 71300-done) by debbugs.gnu.org; 22 Dec 2024 21:35:05 +0000 Received: from localhost ([127.0.0.1]:52207 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPTbM-0002jL-JO for submit@debbugs.gnu.org; Sun, 22 Dec 2024 16:35:05 -0500 Received: from eggs.gnu.org ([209.51.188.92]:36326) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPTbL-0002hx-6M for 71300-done@debbugs.gnu.org; Sun, 22 Dec 2024 16:35:03 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tPTbB-000877-KM; Sun, 22 Dec 2024 16:34:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To: From; bh=CZRR7iD+ve44OQL41w8gNtmY8H6ZzzD6Uk3QDCGZPCQ=; b=XlbbJgYgSfTOms2BTNhE 5g34vBrr/Bv0+ao0C754WF1Oyny7xfqv/lXNExHeAVde8HPPUiknIgJAhaAxcZM68/5rlk3lpbCn5 pb2/eIAXdrqRw+OWrMmtMmRwIjBYlZ50BH1zhKqYGBjbTJ0ZSV6E/RiF5rnCwsdqEqG116Dif3l7/ CLt+wkqUfMydPdKj9vXSIhFyVygnulh4h5bysK9ydi4/ySbksbQA8bo4GxRDjIvOE2mNivJQTN1kY FGGzwBBnLAEheoujveO3QuobknBVMmc6I3rghnPQTudtIeLeSWcRrwAaMOIR2F75IjxAHTRP23juP XhpazGUI3EwzJA==; From: =?utf-8?Q?Ludovic_Court=C3=A8s?= To: Maxim Cournoyer Subject: Re: bug#71300: [PATCH v3] doc: Document SRFI 64. In-Reply-To: <20240915042603.8529-1-maxim.cournoyer@gmail.com> (Maxim Cournoyer's message of "Sun, 15 Sep 2024 13:25:46 +0900") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> Date: Sun, 22 Dec 2024 22:34:44 +0100 Message-ID: <87ldw7fll7.fsf_-_@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 71300-done Cc: 71300-done@debbugs.gnu.org, Tomas Volf <~@wolfsden.cz>, Filip =?utf-8?Q?=C5=81ajszczak?= , Maxime Devos X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Maxim, Maxim Cournoyer skribis: > This is an import of the 'Abstract', 'Rationale', and 'Specification' > sections from the upstream specification text, with some manual > adjustment. > > * doc/ref/srfi-modules.texi (SRFI 64): New subsection. Finally applied with the typographical changes below, for consistency with (most of) the rest of the manual. Thanks, Ludo=E2=80=99. --=-=-= Content-Type: text/x-patch Content-Disposition: inline diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index 4bad8abbf..db54428ad 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -56,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page * 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-64:: Writing test suites. * SRFI-67:: Compare procedures * SRFI-69:: Basic hash tables. * SRFI-71:: Extended let-syntax for multiple values. @@ -5295,22 +5295,23 @@ S-expression comments by default. @c This SRFI 64 documentation was "snarfed" from upstream specification @c HTML document using the 'snarfi' script. -@node SRFI 64 -@subsection SRFI 64: A Scheme API for test suites -@cindex SRFI 64 +@node SRFI-64 +@subsection SRFI-64: A Scheme API for Test Suites +@cindex SRFI-64, test suites +@cindex test suites, SRFI-64 @menu -* SRFI 64 Abstract:: -* SRFI 64 Rationale:: -* SRFI 64 Writing basic test suites:: -* SRFI 64 Conditonal test-suites and other advanced features:: -* SRFI 64 Test-runner:: -* SRFI 64 Test results:: -* SRFI 64 Writing a new test-runner:: +* SRFI-64 Abstract:: +* SRFI-64 Rationale:: +* SRFI-64 Writing Basic Test Suites:: +* SRFI-64 Conditonal Test Suites and Other Advanced Features:: +* SRFI-64 Test Runner:: +* SRFI-64 Test Results:: +* SRFI-64 Writing a New Test Runner:: @end menu -@node SRFI 64 Abstract -@subsubsection SRFI 64 Abstract +@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. @@ -5319,8 +5320,8 @@ 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 +@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 @@ -5359,8 +5360,8 @@ syntax is to allow specific tests to be skipped without evaluating sub-expressions, or for implementations to add features such as printing line numbers or catching exceptions. -@node SRFI 64 Writing basic test suites -@subsubsection SRFI 64 Writing basic test suites +@node SRFI-64 Writing Basic Test Suites +@subsubsection SRFI-64 Writing Basic Test Suites Let's start with a simple example. This is a complete self-contained test-suite. @@ -5607,8 +5608,8 @@ For example: @end lisp @end deffn -@node SRFI 64 Conditonal test-suites and other advanced features -@subsubsection SRFI 64 Conditonal test-suites and other advanced features +@node SRFI-64 Conditonal Test Suites and Other Advanced Features +@subsubsection SRFI-64 Conditonal Test Suites and Other Advanced Features The following describes features for controlling which tests to execute, or specifying that some tests are @emph{expected} to fail. @@ -5716,8 +5717,8 @@ not test execution. For example: @end lisp @end deffn -@node SRFI 64 Test-runner -@subsubsection SRFI 64 Test-runner +@node SRFI-64 Test Runner +@subsubsection SRFI-64 Test Runner A @dfn{test-runner} is an object that runs a test-suite, and manages the state. The test group path, and the sets skip and expected-fail @@ -5787,14 +5788,14 @@ Executes each @var{decl-or-expr} in order in a context where the current test-runner is @var{runner}. @end deffn -@node SRFI 64 Test results -@subsubsection SRFI 64 Test results +@node SRFI-64 Test Results +@subsubsection SRFI-64 Test Results Running a test sets various status properties in the current test-runner. This can be examined by a custom test-runner, or (more rarely) in a test-suite. -@subsubheading Result kind +@subsubheading Result Kind Running a test may yield one of the following status symbols: @@ -5912,13 +5913,13 @@ The error value, if an error was signalled and it is known. The actual error value is implementation-defined. @end table -@node SRFI 64 Writing a new test-runner -@subsubsection SRFI 64 Writing a new test-runner +@node SRFI-64 Writing a New Test Runner +@subsubsection SRFI-64 Writing a New Test Runner This section specifies how to write a test-runner. It can be ignored if you just want to write test-cases. -@subsubheading Call-back functions +@subsubheading Call-back Functions These call-back functions are ``methods'' (in the object-oriented sense) of a test-runner. A method @code{test-runner-on-@var{event}} is called --=-=-=-- ------------=_1734903362-10892-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 1 Jun 2024 02:18:14 +0000 Received: from localhost ([127.0.0.1]:55562 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sDEJv-0000D5-R2 for submit@debbugs.gnu.org; Fri, 31 May 2024 22:18:13 -0400 Received: from lists.gnu.org ([209.51.188.17]:47398) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sDEJr-0000Cw-RJ for submit@debbugs.gnu.org; Fri, 31 May 2024 22:18:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sDEJg-00068W-1d for bug-guile@gnu.org; Fri, 31 May 2024 22:17:56 -0400 Received: from mail-yb1-xb2f.google.com ([2607:f8b0:4864:20::b2f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sDEJb-00041r-4H for bug-guile@gnu.org; Fri, 31 May 2024 22:17:55 -0400 Received: by mail-yb1-xb2f.google.com with SMTP id 3f1490d57ef6-dfa65af5367so2285134276.1 for ; Fri, 31 May 2024 19:17:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1717208269; x=1717813069; darn=gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=yD9H3oOn2NRTimz2CTfPltsRFY3CRqyMAQ8Nn9XVlTE=; b=dVGbUOoTtGDNoWyxhLrW7G0iulgyEANtAuHrhLhBkIeXqxchshwcJ8BtZEpBEbB327 DVYDYIMlPbXBJIfT8sEQbWrMMP5mKlBdN5NlZyVIlwIGWfw/yun0GJcsvu4Vt5IuOAu5 etEa+SvMeAn9LW5FdpLonfL4GWe1h7/VqBB8XHOJY4PJG+dhJp7KKbEsdpwdxskSuH56 Mfz7udpSXI21EdkUV2rvPTo8XK1gVU8c8GdCvm3owr+Htzc8Bm0BXVBz1DUILJ/xmmWc 4QKLDFzc18vmD4n+8EqzWqf0mr1IDMYSM0+w5SSWC4pilYAqcME9I5kAhsndivgciQUN HjoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717208269; x=1717813069; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=yD9H3oOn2NRTimz2CTfPltsRFY3CRqyMAQ8Nn9XVlTE=; b=FS/kWLAcXuoHVv6Vws3Oh4Ec+QKMlVTJOYkG9pcLlUK7lQUDH2iWMeZlGrxiwonG6k kMaLE9oS6gY6Vt73v6hgDVBVnBMDVNOB32uLdpfKV9GeHmsOh/CV5LEC4qijiBLOJRt2 q+gpV+NfREc29eulr50cMH1YceKTxk5Yq+8Y1Wy7S72bUzvQNYL/KQWYrhpp1i53Uoz5 EeRn20tvjGKhc5itutSdfjAObVAJciTtUST2zHkkgwnc0DjFqWeFWcviO2ERoXYBvFil qd6hpK1FR4Lwucr3irDhmhDdwOjCPFk45/dl/hjrBiYmFVVtY0FTT5BKN01oTzyYjUnT BqUQ== X-Gm-Message-State: AOJu0Yxtq2iMTktQV+m59V9gjXVAJbP81cidWIt4vPeP/nrQBm6GagAx lFsfxiJJUiNUBKuwmt7zZlqYN/GYgMRENBmFf0XZWfLZVlU1/vrL50jgYw== X-Google-Smtp-Source: AGHT+IGglc1mK4xRUKj4UIk8o1yfrjzaGyjta+CTn3ohXwPhcZhV+gKujhbPlGN0Vf2c41IInI3SkQ== X-Received: by 2002:a25:df93:0:b0:de4:738b:c2ea with SMTP id 3f1490d57ef6-dfa73bec3d6mr3661537276.24.1717208268623; Fri, 31 May 2024 19:17:48 -0700 (PDT) Received: from localhost.localdomain (dsl-205-233-124-92.b2b2c.ca. [205.233.124.92]) by smtp.gmail.com with ESMTPSA id af79cd13be357-794f3061456sm102183085a.78.2024.05.31.19.17.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 May 2024 19:17:48 -0700 (PDT) From: Maxim Cournoyer To: bug-guile@gnu.org Subject: [PATCH v3] doc: Document SRFI 64. Date: Fri, 31 May 2024 22:17:28 -0400 Message-ID: <20240601021743.808-1-maxim.cournoyer@gmail.com> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2607:f8b0:4864:20::b2f; envelope-from=maxim.cournoyer@gmail.com; helo=mail-yb1-xb2f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.3 (-) X-Debbugs-Envelope-To: submit Cc: =?UTF-8?q?Filip=20=C5=81ajszczak?= , Maxime Devos , Maxim Cournoyer X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) This is an import of the 'Abstract', 'Rationale', and 'Specification' sections from the upstream specification text, with some manual adjustment. * doc/ref/srfi-modules.texi (SRFI 64): New subsection. --- Changes in v3: - Add copyright / license information - Replace SchemeUnit mentions with RackUnit Changes in v2: - Fix the category of many definitions doc/ref/guile.texi | 25 +- doc/ref/srfi-modules.texi | 830 +++++++++++++++++++++++++++++++++++++- 2 files changed, 847 insertions(+), 8 deletions(-) diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index bde9f6f75..988d30155 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -24,8 +24,31 @@ any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' -@end copying +Additionally, the documentation of the SRFI 64 module is adapted from +its specification text, which is made available under the following +Expat license: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@end copying @c Notes @c diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index efb9ccca4..0c2ddec81 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -1,7 +1,8 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018, 2019, 2020 +@c Copyright (C) 1996-1997, 2000-2004, 2006-2014, 2017-2020, 2023 @c Free Software Foundation, Inc. +@c Copyright (C) 2005-2006 Per Bothner @c See the file guile.texi for copying conditions. @node SRFI Support @@ -55,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page * 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 64:: A Scheme API for test suites. * SRFI-67:: Compare procedures * SRFI-69:: Basic hash tables. * SRFI-71:: Extended let-syntax for multiple values. @@ -5289,12 +5290,827 @@ 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 +@c This SRFI 64 documentation was "snarfed" from upstream specification +@c HTML document using the 'snarfi' script. +@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}. +@menu +* SRFI 64 Abstract:: +* SRFI 64 Rationale:: +* SRFI 64 Writing basic test suites:: +* SRFI 64 Conditonal test-suites and other advanced features:: +* SRFI 64 Test-runner:: +* SRFI 64 Test results:: +* SRFI 64 Writing a new test-runner:: +@end menu + +@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. + +@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. + +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. + +This proposal allows converting a Scheme source file to a +test suite by just adding a few macros. You don't have to +write the entire file in a new form, thus you don't have to +re-indent it. + +All names defined by the API start with the prefix @samp{test-}. All +function-like forms are defined as syntax. They may be implemented as +functions or macros or built-ins. The reason for specifying them as +syntax is to allow specific tests to be skipped without evaluating +sub-expressions, or for implementations to add features such as printing +line numbers or catching exceptions. + +@node SRFI 64 Writing basic test suites +@subsubsection SRFI 64 Writing basic test suites + +Let's start with a simple example. This is a complete self-contained +test-suite. + +@lisp +;; Initialize and give a name to a simple testsuite. +(test-begin "vec-test") +(define v (make-vector 5 99)) +;; Require that an expression evaluate to true. +(test-assert (vector? v)) +;; Test that an expression is eqv? to some other expression. +(test-eqv 99 (vector-ref v 2)) +(vector-set! v 2 7) +(test-eqv 7 (vector-ref v 2)) +;; Finish the testsuite, and report results. +(test-end "vec-test") +@end lisp + +This testsuite could be saved in its own source file. Nothing else is +needed: We do not require any top-level forms, so it is easy to wrap an +existing program or test to this form, without adding indentation. It +is also easy to add new tests, without having to name individual tests +(though that is optional). + +Test cases are executed in the context of a @dfn{test runner}, which is +a object that accumulates and reports test results. This specification +defines how to create and use custom test runners, but implementations +should also provide a default test runner. It is suggested (but not +required) that loading the above file in a top-level environment will +cause the tests to be executed using an implementation-specified default +test runner, and @code{test-end} will cause a summary to be displayed in +an implementation-specified manner. + +@subsubheading Simple test-cases + +Primitive test cases test that a given condition is true. They may have +a name. The core test case form is @code{test-assert}: + +@deffn {Scheme Syntax} test-assert [test-name] expression + +This evaluates the @var{expression}. The test passes if the result is +true; if the result is false, a test failure is reported. The test also +fails if an exception is raised, assuming the implementation has a way +to catch exceptions. How the failure is reported depends on the test +runner environment. The @var{test-name} is a string that names the test +case. (Though the @var{test-name} is a string literal in the examples, +it is an expression. It is evaluated only once.) It is used when +reporting errors, and also when skipping tests, as described below. It +is an error to invoke @code{test-assert}if there is no current test +runner. +@end deffn + +The following forms may be more convenient than using @code{test-assert} +directly: + +@deffn {Scheme Syntax} test-eqv [test-name] expected test-expr + +This is equivalent to: + +@lisp +(test-assert [@var{test-name}] (eqv? @var{expected} @var{test-expr})) +@end lisp + +@end deffn + +Similarly @code{test-equal} and @code{test-eq} are shorthand for +@code{test-assert} combined with @code{equal?} or @code{eq?}, +respectively: + +@deffn {Scheme Syntax} test-equal [test-name] expected test-expr +@deffnx {Scheme Syntax} test-eq [test-name] expected test-expr + +Here is a simple example: + +@lisp +(define (mean x y) (/ (+ x y) 2.0)) +(test-eqv 4 (mean 3 5)) +@end lisp +@end deffn + +For testing approximate equality of inexact reals +we can use @code{test-approximate}: + +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr error + +This is equivalent to (except that each argument is only evaluated +once): + +@lisp +(test-assert [test-name] + (and (>= test-expr (- expected error)) + (<= test-expr (+ expected error)))) +@end lisp +@end deffn + +@subsubheading Tests for catching errors + +We need a way to specify that evaluation @emph{should} fail. This +verifies that errors are detected when required. + +@deffn {Scheme Syntax} test-error [[test-name] error-type] test-expr + +Evaluating @var{test-expr} is expected to signal an error. The kind of +error is indicated by @var{error-type}. + +If the @var{error-type} is left out, or it is @code{#t}, it means "some +kind of unspecified error should be signaled". For example: + +@lisp +(test-error #t (vector-ref '#(1 2) 9)) +@end lisp + +This specification leaves it implementation-defined (or for a future +specification) what form @var{test-error} may take, though all +implementations must allow @code{#t}. Some implementations may support +@url{https://srfi.schemers.org/srfi-35/srfi-35.html, SRFI-35's +conditions}, but these are only standardized for +@url{https://srfi.schemers.org/srfi-36/srfi-36.html, SRFI-36's I/O +conditions}, which are seldom useful in test suites. An implementation +may also allow implementation-specific ``exception types''. For example +Java-based implementations may allow the names of Java exception +classes: + +@lisp +;; Kawa-specific example +(test-error (vector-ref '#(1 2) 9)) +@end lisp + +An implementation that cannot catch exceptions should skip +@code{test-error} forms. +@end deffn + +@subsubheading Testing syntax + +Testing syntax is tricky, especially if we want to check that invalid +syntax is causing an error. The following utility function can help: + +@deffn {Scheme Procedure} test-read-eval-string string + +This function parses @var{string} (using @code{read}) and evaluates the +result. The result of evaluation is returned from +@code{test-read-eval-string}. An error is signalled if there are unread +characters after the @code{read} is done. For example: +@code{(test-read-eval-string "(+ 3 4)")} @i{evaluates to} @code{7}. +@code{(test-read-eval-string "(+ 3 4")} @i{signals an error}. +@code{(test-read-eval-string "(+ 3 4) ")} @i{signals an error}, because +there is extra ``junk'' (@i{i.e.} a space) after the list is read. + +The @code{test-read-eval-string} used in tests: + +@lisp +(test-equal 7 (test-read-eval-string "(+ 3 4)")) +(test-error (test-read-eval-string "(+ 3")) +(test-equal #\newline (test-read-eval-string "#\\newline")) +(test-error (test-read-eval-string "#\\newlin")) +;; Skip the next 2 tests unless srfi-62 is available. +(test-skip (cond-expand (srfi-62 0) (else 2))) +(test-equal 5 (test-read-eval-string "(+ 1 #;(* 2 3) 4)")) +(test-equal '(x z) (test-read-string "(list 'x #;'y 'z)")) +@end lisp +@end deffn + +@subsubheading Test groups and paths + +A @dfn{test group} is a named sequence of forms containing testcases, +expressions, and definitions. Entering a group sets the @dfn{test group +name}; leaving a group restores the previous group name. These are +dynamic (run-time) operations, and a group has no other effect or +identity. Test groups are informal groupings: they are neither Scheme +values, nor are they syntactic forms. +@c (More formal test suite values are introduced below.) +A test group may contain nested inner test groups. +The @dfn{test group path} is a list of the currently-active +(entered) test group names, oldest (outermost) first. + +@deffn {Scheme Syntax} test-begin suite-name [count] + +A @code{test-begin} enters a new test group. The @var{suite-name} +becomes the current test group name, and is added to the end of the test +group path. Portable test suites should use a string literal for +@var{suite-name}; the effect of expressions or other kinds of literals +is unspecified. + +@emph{Rationale:} In some ways using symbols would be preferable. +However, we want human-readable names, and standard Scheme does not +provide a way to include spaces or mixed-case text in literal symbols. + +The optional @var{count} must match the number of test-cases executed by +this group. (Nested test groups count as a single test case for this +count.) This extra test may be useful to catch cases where a test +doesn't get executed because of some unexpected error. + +Additionally, if there is no currently executing test runner, +one is installed in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-end [suite-name] + +A @code{test-end} leaves the current test group. +An error is reported if the @var{suite-name} does not +match the current test group name. +@c If it does match an earlier name in the test group path, intervening +@c groups are left. + +Additionally, if the matching @code{test-begin}installed a new +test-runner, then the @code{test-end} will uninstall it, after reporting +the accumulated test results in an implementation-defined manner. +@end deffn + +@deffn {Scheme Syntax} test-group suite-name decl-or-expr @dots{} + +Equivalent to: + +@lisp +(if (not (test-to-skip% (var suite-name))) + (dynamic-wind + (lambda () (test-begin (var suite-name))) + (lambda () (var decl-or-expr) ...) + (lambda () (test-end (var suite-name))))) +@end lisp + +This is usually equivalent to executing the @var{decl-or-expr}s +within the named test group. However, the entire group is skipped +if it matched an active @code{test-skip} (see later). +Also, the @code{test-end} is executed in case of an exception. +@end deffn + +@subsubheading Handling set-up and cleanup + +@deffn {Scheme Syntax} test-group-with-cleanup suite-name decl-or-expr @dots{} cleanup-form + +Execute each of the @var{decl-or-expr} forms in order (as in a +@var{}), and then execute the @var{cleanup-form}. The latter +should be executed even if one of a @var{decl-or-expr} forms raises an +exception (assuming the implementation has a way to catch exceptions). + +For example: + +@lisp +(let ((f (open-output-file "log"))) + (test-group-with-cleanup "test-file" + (do-a-bunch-of-tests f) + (close-output-port f))) +@end lisp +@end deffn + +@node SRFI 64 Conditonal test-suites and other advanced features +@subsubsection SRFI 64 Conditonal test-suites and other advanced features + +The following describes features for controlling which tests to execute, +or specifying that some tests are @emph{expected} to fail. + +@subsubheading Test specifiers + +Sometimes we want to only run certain tests, or we know that certain +tests are expected to fail. A @dfn{test specifier} is one-argument +function that takes a test-runner and returns a boolean. The specifier +may be run before a test is performed, and the result may control +whether the test is executed. For convenience, a specifier may also be +a non-procedure value, which is coerced to a specifier procedure, as +described below for @var{count} and @var{name}. + +A simple example is: + +@lisp +(if (var some-condition) (test-skip 2)) ;; skip next 2 tests +@end lisp + +@deffn {Scheme Procedure} test-match-name name + +The resulting specifier matches if the current test name (as returned by +@code{test-runner-test-name}) is @code{equal?} to @var{name}. +@end deffn + +@deffn {Scheme Syntax} test-match-nth n [count] + +This evaluates to a @emph{stateful} predicate: A counter keeps track of +how many times it has been called. The predicate matches the @var{n}'th +time it is called (where @code{1} is the first time), and the next +@samp{(- @var{count} 1)} times, where @var{count} defaults to @code{1}. +@end deffn + +@deffn {Scheme Syntax} test-match-any specifier @dots{} + +The resulting specifier matches if any @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is true. +@end deffn + +@deffn {Scheme Syntax} test-match-all specifier @dots{} + +The resulting specifier matches if each @var{specifier} matches. Each +@var{specifier} is applied, in order, so side-effects from a later +@var{specifier} happen even if an earlier @var{specifier} is false. +@end deffn + +@var{count} @i{(i.e. an integer)} +Convenience short-hand for: @samp{(test-match-nth 1 @var{count})}. + +@var{name} @i{(i.e. a string)} +Convenience short-hand for @samp{(test-match-name @var{name})}. + +@subsubheading Skipping selected tests + +In some cases you may want to skip a test. + +@deffn {Scheme Syntax} test-skip specifier + +Evaluating @code{test-skip} adds the resulting @var{specifier} to the +set of currently active skip-specifiers. Before each test (or +@code{test-group}) the set of active skip-specifiers are applied to the +active test-runner. If any specifier matches, then the test is skipped. + +For convenience, if the @var{specifier} is a string that is syntactic +sugar for @code{(test-match-name @var{specifier})}. For example: + +@lisp +(test-skip "test-b") +(test-assert "test-a") ;; executed +(test-assert "test-b") ;; skipped +@end lisp + +Any skip specifiers introduced by a @code{test-skip} are removed by a +following non-nested @code{test-end}. + +@lisp +(test-begin "group1") +(test-skip "test-a") +(test-assert "test-a") ;; skipped +(test-end "group1") ;; Undoes the prior test-skip +(test-assert "test-a") ;; executed +@end lisp +@end deffn + +@subsubheading Expected failures + +Sometimes you know a test case will fail, but you don't have time to or +can't fix it. Maybe a certain feature only works on certain platforms. +However, you want the test-case to be there to remind you to fix it. +You want to note that such tests are expected to fail. + +@deffn {Scheme Syntax} test-expect-fail specifier + +Matching tests (where matching is defined as in @code{test-skip}) +are expected to fail. This only affects test reporting, +not test execution. For example: + +@lisp +(test-expect-fail 2) +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to fail +(test-eqv ...) ;; expected to pass +@end lisp +@end deffn + +@node SRFI 64 Test-runner +@subsubsection SRFI 64 Test-runner + +A @dfn{test-runner} is an object that runs a test-suite, and manages the +state. The test group path, and the sets skip and expected-fail +specifiers are part of the test-runner. A test-runner will also +typically accumulate statistics about executed tests, + +@deffn {Scheme Procedure} test-runner? value + +True if and only if @var{value} is a test-runner object. +@end deffn + +@deffn {Scheme Parameter} test-runner-current +@deffnx {Scheme Parameter} test-runner-current runner + +Get or set the current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-get + +Same as @code{(test-runner-current)}, but throws an exception if there +is no current test-runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-simple + +Creates a new simple test-runner, that prints errors and a summary on +the standard output port. +@end deffn + +@deffn {Scheme Procedure} test-runner-null + +Creates a new test-runner, that does nothing with the test results. +This is mainly meant for extending when writing a custom runner. +@end deffn + +@deffn {Scheme Procedure} test-runner-create + +Create a new test-runner. Equivalent to @samp{((test-runner-factory))}. +@end deffn + +@deffn {Scheme Parameter} test-runner-factory +@deffnx {Scheme Parameter} test-runner-factory factory + +Get or set the current test-runner factory. A factory is a +zero-argument function that creates a new test-runner. The default +value is @code{test-runner-simple}. +@end deffn + +@subsubheading Running specific tests with a specified runner + +@deffn {Scheme Procedure} test-apply [runner] specifier @dots{} procedure + +Calls @var{procedure} with no arguments using the specified @var{runner} +as the current test-runner. If @var{runner} is omitted, then +@code{(test-runner-current)} is used. (If there is no current runner, +one is created as in @code{test-begin}.) If one or more +@var{specifier}s are listed then only tests matching the +@var{specifier}s are executed. A @var{specifier} has the same form as +one used for @code{test-skip}. A test is executed if it matches any of +the @var{specifier}s in the @code{test-apply} @emph{and} does not match +any active @code{test-skip} specifiers. +@end deffn + +@deffn {Scheme Syntax} test-with-runner runner decl-or-expr @dots{} + +Executes each @var{decl-or-expr} in order in a context where the current +test-runner is @var{runner}. +@end deffn + +@node SRFI 64 Test results +@subsubsection SRFI 64 Test results + +Running a test sets various status properties in the current test-runner. +This can be examined by a custom test-runner, +or (more rarely) in a test-suite. + +@subsubheading Result kind + +Running a test may yield one of the following +status symbols: + +@table @asis +@item @code{'pass} +The test passed, as expected. + +@item @code{'fail} +The test failed (and was not expected to). + +@item @code{'xfail} +The test failed and was expected to. + +@item @code{'xpass} +The test passed, but was expected to fail. + +@item @code{'skip} +The test was skipped. +@end table + +@deffn {Scheme Procedure} test-result-kind [runner] + +Returns one of the above result codes from the most recent tests. +Returns @code{#f} if no tests have been run yet. If we've started on a +new test, but don't have a result yet, then the result kind is +@code{'xfail} if the test is expected to fail, @code{'skip} if the test +is supposed to be skipped, or @code{#f} otherwise. +@end deffn + +@deffn {Scheme Procedure} test-passed? [runner] + +True if the value of @samp{(test-result-kind [@var{runner}])} is one of +@code{'pass} or @code{'xpass}. This is a convenient shorthand that +might be useful in a test suite to only run certain tests if the +previous test passed. +@end deffn + +@subsubheading Test result properties + +A test runner also maintains a set of more detailed +``result@tie{}properties'' associated with the current or most recent +test. (I.e. the properties of the most recent test are available as +long as a new test hasn't started.) Each property has a name (a symbol) +and a value (any value). Some properties are standard or set by the +implementation; implementations can add more. + +@deffn {Scheme Procedure} test-result-ref runner pname [default] + +Returns the property value associated with the @var{pname} property name +(a symbol). If there is no value associated with @var{pname} return +@var{default}, or @code{#f} if @var{default} isn't specified. +@end deffn + +@deffn {Scheme Syntax} test-result-set! runner pname value + +Sets the property value associated with the @var{pname} property name to +@var{value}. Usually implementation code should call this function, but +it may be useful for a custom test-runner to add extra properties. +@end deffn + +@deffn {Scheme Procedure} test-result-remove runner pname + +Remove the property with the name @var{pname}. +@end deffn + +@deffn {Scheme Procedure} test-result-clear runner + +Remove all result properties. The implementation automatically calls +@code{test-result-clear} at the start of a @code{test-assert} and +similar procedures. +@end deffn + +@deffn {Scheme Procedure} test-result-alist runner + +Returns an association list of the current result properties. It is +unspecified if the result shares state with the test-runner. The result +should not be modified; on the other hand, the result may be implicitly +modified by future @code{test-result-set!} or @code{test-result-remove} +calls. However, a @code{test-result-clear} does not modify the returned +alist. Thus you can ``archive'' result objects from previous runs. +@end deffn + +@subsubheading Standard result properties + +The set of available result properties is implementation-specific. +However, it is suggested that the following might be provided: +@table @asis + +@item @code{'result-kind} +The result kind, as defined previously. +This is the only mandatory result property. +@code{(test-result-kind @var{runner})} is equivalent to: +@code{(test-result-ref @var{runner} 'result-kind)} + +@item @code{'source-file} +@itemx @code{'source-line} +If known, the location of test statements (such as @code{test-assert}) +in test suite source code. + +@item @code{'source-form} +The source form, if meaningful and known. + +@item @code{'expected-value} +The expected non-error result, if meaningful and known. + +@item @code{'expected-error} +The @var{error-type}specified in a @code{test-error}, if it meaningful and known. + +@item @code{'actual-value} +The actual non-error result value, if meaningful and known. + +@item @code{'actual-error} +The error value, if an error was signalled and it is known. +The actual error value is implementation-defined. +@end table + +@node SRFI 64 Writing a new test-runner +@subsubsection SRFI 64 Writing a new test-runner + +This section specifies how to write a test-runner. It can be ignored if +you just want to write test-cases. + +@subsubheading Call-back functions + +These call-back functions are ``methods'' (in the object-oriented sense) +of a test-runner. A method @code{test-runner-on-@var{event}} is called +by the implementation when @var{event} happens. + +To define (set) the callback function for @var{event} use the following +expression. (This is normally done when initializing a test-runner.) + +@code{(test-runner-on-@var{event}! @var{runner} @var{event-function})} + +An @var{event-function} takes a test-runner argument, and possibly other +arguments, depending on the @var{event}. + +To extract (get) the callback function for @var{event} do this: +@code{(test-runner-on-@var{event} @var{runner})} + +To extract call the callback function for @var{event} use the following +expression. (This is normally done by the implementation core.) +@samp{((test-runner-on-@var{event} @var{runner}) @var{runner} +@var{other-args} @dots{})}. + +The following call-back hooks are available. + +@deffn {Scheme Procedure} test-runner-on-test-begin runner +@deffnx {Scheme Procedure} test-runner-on-test-begin! runner on-test-begin-function +@deffnx {Scheme Procedure} on-test-begin-function runner + +The @var{on-test-begin-function} is called at the start of an +individual testcase, before the test expression (and expected value) are +evaluated. + +@end deffn + +@deffn {Scheme Procedure} test-runner-on-test-end runner +@deffnx {Scheme Procedure} test-runner-on-test-end! runner on-test-end-function +@deffnx {Scheme Procedure} on-test-end-function runner + +The @var{on-test-end-function} is called at the end of an +individual testcase, when the result of the test is available. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-begin runner +@deffnx {Scheme Procedure} test-runner-on-group-begin! runner on-group-begin-function +@deffnx {Scheme Procedure} on-group-begin-function runner suite-name count + +The @var{on-group-begin-function} is called by a @code{test-begin}, +including at the start of a @code{test-group}. The @var{suite-name} is +a Scheme string, and @var{count} is an integer or @code{#f}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-group-end runner +@deffnx {Scheme Procedure} test-runner-on-group-end! runner on-group-end-function +@deffnx {Scheme Procedure} on-group-end-function runner + +The @var{on-group-end-function} is called by a @code{test-end}, +including at the end of a @code{test-group}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-count runner +@deffnx {Scheme Procedure} test-runner-on-bad-count! runner on-bad-count-function +@deffnx {Scheme Procedure} on-bad-count-function runner actual-count expected-count + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if an @var{expected-count} was specified by the matching +@code{test-begin} and the @var{expected-count} does not match the +@var{actual-count} of tests actually executed or skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-bad-end-name runner +@deffnx {Scheme Procedure} test-runner-on-bad-end-name! runner on-bad-end-name-function +@deffnx {Scheme Procedure} on-bad-end-name-function runner begin-name end-name + +Called from @code{test-end} (before the @var{on-group-end-function} is +called) if a @var{suite-name} was specified, and it did not that the +name in the matching @code{test-begin}. +@end deffn + +@deffn {Scheme Procedure} test-runner-on-final runner +@deffnx {Scheme Procedure} test-runner-on-final! runner on-final-function +@deffnx {Scheme Procedure} on-final-function runner + +The @var{on-final-function} takes one parameter (a test-runner) and +typically displays a summary (count) of the tests. The +@var{on-final-function} is called after called the +@var{on-group-end-function} correspondiong to the outermost +@code{test-end}. The default value is @code{test-on-final-simple} which +writes to the standard output port the number of tests of the various +kinds. +@end deffn + +The default test-runner returned by @code{test-runner-simple} uses the +following call-back functions: + +@deffn {Scheme Procedure} test-on-test-begin-simple runner +@deffnx {Scheme Procedure} test-on-test-end-simple runner +@deffnx {Scheme Procedure} test-on-group-begin-simple runner suite-name count +@deffnx {Scheme Procedure} test-on-group-end-simple runner +@deffnx {Scheme Procedure} test-on-bad-count-simple runner actual-count expected-count +@deffnx {Scheme Procedure} test-on-bad-end-name-simple runner begin-name end-name + +You can call those if you want to write your own test-runner. +@end deffn + +@subsubheading Test-runner components + +The following functions are for accessing the other components of a +test-runner. They would normally only be used to write a new +test-runner or a match-predicate. + +@deffn {Scheme Procedure} test-runner-pass-count runner + +Returns the number of tests that passed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-fail-count runner + +Returns the number of tests that failed, but were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-xpass-count runner + +Returns the number of tests that passed, but were expected to fail. +@end deffn + +@deffn {Scheme Procedure} test-runner-xfail-count runner + +Returns the number of tests that failed, and were expected to pass. +@end deffn + +@deffn {Scheme Procedure} test-runner-skip-count runner + +Returns the number of tests or test groups that were skipped. +@end deffn + +@deffn {Scheme Procedure} test-runner-test-name runner + +Returns the name of the current test or test group, as a string. During +execution of @code{test-begin} this is the name of the test group; +during the execution of an actual test, this is the name of the +test-case. If no name was specified, the name is the empty string. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-path runner + +A list of names of groups we're nested in, with the outermost group +first. +@end deffn + +@deffn {Scheme Procedure} test-runner-group-stack runner + +A list of names of groups we're nested in, with the outermost group +last. (This is more efficient than @code{test-runner-group-path}, since +it doesn't require any copying.) +@end deffn + +@deffn {Scheme Procedure} test-runner-aux-value runner +@deffnx {Scheme Procedure} test-runner-aux-value! runner on-test + +Get or set the @code{aux-value} field of a test-runner. This field is +not used by this API or the @code{test-runner-simple} test-runner, but +may be used by custom test-runners to store extra state. +@end deffn + +@deffn {Scheme Procedure} test-runner-reset runner + +Resets the state of the @var{runner} to its initial state. +@end deffn + +@subsubheading Example + +This is an example of a simple custom test-runner. +Loading this program before running a test-suite will install +it as the default test runner. + +@lisp +(define (my-simple-runner filename) + (let ((runner (test-runner-null)) + (port (open-output-file filename)) + (num-passed 0) + (num-failed 0)) + (test-runner-on-test-end! runner + (lambda (runner) + (case (test-result-kind runner) + ((pass xpass) (set! num-passed (+ num-passed 1))) + ((fail xfail) (set! num-failed (+ num-failed 1))) + (else #t)))) + (test-runner-on-final! runner + (lambda (runner) + (format port "Passing tests: ~d.~%Failing tests: ~d.~%" + num-passed num-failed) + (close-output-port port))) + runner)) +(test-runner-factory + (lambda () (my-simple-runner "/tmp/my-test.log"))) +@end lisp @node SRFI-67 @subsection SRFI-67 - Compare procedures base-commit: 779a83d9c682345802f9a605cb8e2b4892129316 -- 2.41.0 ------------=_1734903362-10892-1-- From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v3] doc: Document SRFI 64. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Mon, 23 Dec 2024 00:15:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 71300-done@debbugs.gnu.org, Tomas Volf <~@wolfsden.cz>, Filip =?UTF-8?Q?=C5=81ajszczak?= , Maxime Devos Received: via spool by 71300-done@debbugs.gnu.org id=D71300.17349128916268 (code D ref 71300); Mon, 23 Dec 2024 00:15:01 +0000 Received: (at 71300-done) by debbugs.gnu.org; 23 Dec 2024 00:14:51 +0000 Received: from localhost ([127.0.0.1]:52475 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPW5y-0001d1-Kv for submit@debbugs.gnu.org; Sun, 22 Dec 2024 19:14:50 -0500 Received: from mail-pl1-f170.google.com ([209.85.214.170]:44425) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPW5v-0001cr-74 for 71300-done@debbugs.gnu.org; Sun, 22 Dec 2024 19:14:49 -0500 Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2164b662090so29281995ad.1 for <71300-done@debbugs.gnu.org>; Sun, 22 Dec 2024 16:14:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1734912826; x=1735517626; darn=debbugs.gnu.org; h=content-transfer-encoding:mime-version:user-agent:message-id:date :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RYpcGIOVGa1AgvmtMhTuNfyJdsQLOY+rLAs4bsJseJA=; b=RvwPcdlK5f9JMC85B3vU0fuSNzFgtwNu5aflg2mWelMQaTIar85RTd6Xh1gD2KvW7j LdwlRcSSLOBmYpNfjNXOO1e5DY6IeWlbaa/iB9kS6p3qJ7to3qeSMUw17/R2J5B0ZFur J47mhec1yPtHFuUSv8sc4ht8EyD8iHkqphRBFfka6NSm8mr+odEo+Rs3PzJfyRuNJ1IT 7NxOTzWxENFpxqJrRcM1T5VUKMaQATTFlG6MpVxitmrYy7j4H6cJXCFo2DHYet4UKOdA 63bKcsBOIge1yhpLZRM9h6AVlJXyMHAbAaiKlCDGgoP342G8T1WkPVmDFdtqO6euznnH ED3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734912826; x=1735517626; h=content-transfer-encoding:mime-version:user-agent:message-id:date :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=RYpcGIOVGa1AgvmtMhTuNfyJdsQLOY+rLAs4bsJseJA=; b=sczh9HMgSJILDRqzOMGO6+K0pih0mq8nvIEnxakrl4KeXUvICQz5xVuot8YCGuFT0u bt8kKfqQDx8hT+Z4pZOx/eAQbq79zG9gQlRUG9x0w5Q4J8iR+nQH19QDmspBx4hwTeOs oN17pGNnaYcELVcPqNWPKlh96jmP0ZMyVjAeIMiSmCE8W6RDvcXhsmrHAN2ZttXxXjYL 6t1Es6ZUcwZFNtXZn8az6PK4jPGbbKnV/l2R0/tAxvceIAMYPIzzm5R8wOEEw2S44RRt JpO8Ed2jNcCtQf2UbxZxMMCXnZiOkYygtcjnAtrUiTkZ092omxMnx4baA2BngFuUDXYX QSaA== X-Gm-Message-State: AOJu0YyES9GAny+ogZnMgYsnTduWdeZfxAHzUmkYZnYEI9Rjivfu6hY8 EMp4p3vSZrvGXNdA/iKMqsZB1SQigt50L77NqTpLSiESzZZ9KTOq X-Gm-Gg: ASbGncsUXPHonDF92ny3K6iivSCrbo51Lag3vd4zoTOUoWLrlcF9YfaCNbgbFFrO6ls iBBdRq0CeyM41oi3kLQnBPqmogtls33c7iUcw45tO3aEn4t3w5d5S/6+A91pYPhLIYtobVgnKNw 8UwVFuTnlsFPWEW/ifbyjWQVcX5Fhutq8n/Go06B1L956K0JdjYlIRryPFOnJEdGwqE7wn+JItW OwPb3qmNtMFOSU/SGfkz5JUfhXk+IRXS9Oo4ACGzAIaEF78x7SmOA== X-Google-Smtp-Source: AGHT+IGBtdDIEkSvyLmKF1rrzr2C9+D8zqxsUzj0agVOkyHBNVdYsvjoCA0j6fdMecbym+2SLilf6g== X-Received: by 2002:a17:903:24e:b0:216:7761:cc49 with SMTP id d9443c01a7336-219e6f26251mr152830075ad.47.1734912826274; Sun, 22 Dec 2024 16:13:46 -0800 (PST) Received: from terra ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-219dc9cdda6sm62278335ad.164.2024.12.22.16.13.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Dec 2024 16:13:45 -0800 (PST) From: Maxim Cournoyer In-Reply-To: <87ldw7fll7.fsf_-_@gnu.org> ("Ludovic =?UTF-8?Q?Court=C3=A8s?="'s message of "Sun, 22 Dec 2024 22:34:44 +0100") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <87ldw7fll7.fsf_-_@gnu.org> Date: Mon, 23 Dec 2024 09:13:35 +0900 Message-ID: <87v7vbw91s.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Ludovic, Ludovic Court=C3=A8s writes: > Hi Maxim, > > Maxim Cournoyer skribis: > >> This is an import of the 'Abstract', 'Rationale', and 'Specification' >> sections from the upstream specification text, with some manual >> adjustment. >> >> * doc/ref/srfi-modules.texi (SRFI 64): New subsection. > > Finally applied with the typographical changes below, for consistency > with (most of) the rest of the manual. Yay! Thank you. I won't need to refer to the old HTML page anymore :-). --=20 Maxim From unknown Sat Jun 14 19:41:16 2025 X-Loop: help-debbugs@gnu.org Subject: bug#71300: [PATCH v3] doc: Document SRFI 64. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Mon, 23 Dec 2024 04:51:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71300 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch To: "Dr. Arne Babenhauserheide" Cc: 71300@debbugs.gnu.org, Ludovic =?UTF-8?Q?Court=C3=A8s?= Received: via spool by 71300-submit@debbugs.gnu.org id=B71300.173492941322076 (code B ref 71300); Mon, 23 Dec 2024 04:51:02 +0000 Received: (at 71300) by debbugs.gnu.org; 23 Dec 2024 04:50:13 +0000 Received: from localhost ([127.0.0.1]:52833 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPaOS-0005jY-Df for submit@debbugs.gnu.org; Sun, 22 Dec 2024 23:50:13 -0500 Received: from mail-pl1-f173.google.com ([209.85.214.173]:58869) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tPaOO-0005hx-Ce for 71300@debbugs.gnu.org; Sun, 22 Dec 2024 23:50:10 -0500 Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-2165448243fso40075795ad.1 for <71300@debbugs.gnu.org>; Sun, 22 Dec 2024 20:50:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1734929342; x=1735534142; darn=debbugs.gnu.org; h=content-transfer-encoding:mime-version:user-agent:message-id:date :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YfeWDNISDvc7UZTZt5f3Uyaf4JDb5hEgkzhtOyqOvoQ=; b=eqgkWOz2Kc4JnfEus6YKV/Y4wXqUIt32jn5lnIFI3GXyOT3IImvgCTvJSVrnc/+eg7 EPBR0QH6drsalW1TcJTjZr1U3TFR74LxQ4AYQfVG1Pxhm4SqthBYLTs+oFZBzwaDR83T pM/rgNjVoxQ9sJ3WGDwSiKmluw0spo0Ef4oZXiVyqbSJuJzfd4DlsBXBSjQsSuGAw8LN kChnsZuA+bGz40BzAOilHRp/eltZSGjE5pAJny5ERk+oW+4/5C3zrrgZIuKCbYPO2+xk 35LG6VmB4yl5K1OVPbo3YIlec5msPRIuOEwxgV/danhQgPvx/gLF4/gcr84GfJdRgAOC gEYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734929342; x=1735534142; h=content-transfer-encoding:mime-version:user-agent:message-id:date :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=YfeWDNISDvc7UZTZt5f3Uyaf4JDb5hEgkzhtOyqOvoQ=; b=g0LXII2wFHVeTYz418UIT+r3ytanROqhQB5hj6CnFnmBxWZZvaZvcN9rLJPO6gvuSr 8r1NcOeJ/0aPTyBfzRS8nMqu1tb3Fyqo4tcZaKCXv86YlTHOXjBVqrO41RSP4WaM2oUw Tv7gwdGtoqR8C82P6db2oOpKv8x8WFSsz+hV7TNBPkgs+OJdxYUAwaYctYph6fHZNADO tPmhJMpOkW/83yivTwyukgUQDq57sFl3ZkOKbYOeBRfpz88OLd3OHlajRaCDeOPYvhcz WRGS4pREAsgWs9Nfy8V6NrwyCBMwSfvRa0kAGiNKKjlJFE24v4BukK9EDxoA93w8HkCd cfAw== X-Gm-Message-State: AOJu0YyZML5D/HtAg8wA6kRuha1sa9mF3RJaSdyl4+0+E+3WvKcWT/9m OSQpfuIYYzywOCb/EeOW6TxQ3w5j3m9IR6SvS1itJrnUFhneJgLe X-Gm-Gg: ASbGncuiceqd/9X67UhZfLSlp+/PXd5mIflL49VfQcxpg+3F8lM4G2Ed68yFqjjTkwA 4e2SOgRKILl3MV8ZvHRkRjhY9UBEF2iKsRRm9P7gL4kn7TETjzpkl+MaE5p768d1dC8a+97T3Uz 1ITfa/BFkr42lAWSpKNOR/5jKAO3AEif/My0iT7dsPKLj+b9JIaGIbycgWzqOwm+LFkp/5PswcX gLPW2djKNXufhTdxB3E5o5+Y3+RHUVucM3T550VSjDLROmPxGB5NA== X-Google-Smtp-Source: AGHT+IFodp5fUe1f7mGpnLDCCnRnt3gxxsr8+S7RBRAVwb1vL5eo1Na81ARCo55A6HMOXb+Zdod3lw== X-Received: by 2002:a17:902:f682:b0:216:6f1e:5799 with SMTP id d9443c01a7336-219e6f14829mr124837425ad.35.1734929342299; Sun, 22 Dec 2024 20:49:02 -0800 (PST) Received: from terra ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-219dc9f5227sm64811475ad.185.2024.12.22.20.49.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Dec 2024 20:49:01 -0800 (PST) From: Maxim Cournoyer In-Reply-To: <87frps2dx7.fsf_-_@web.de> (Arne Babenhauserheide's message of "Sun, 22 Sep 2024 12:14:28 +0200") References: <20240601021743.808-1-maxim.cournoyer@gmail.com> <20240915042603.8529-1-maxim.cournoyer@gmail.com> <87frps2dx7.fsf_-_@web.de> Date: Mon, 23 Dec 2024 13:48:52 +0900 Message-ID: <87ed1zvwaz.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi, Finally acting on this, now that it's already been merged by Ludovic ^^'. "Dr. Arne Babenhauserheide" writes: > Maxim Cournoyer writes: > >> diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi >> index 02da3e2f2..4d408d6cb 100644 >> --- a/doc/ref/srfi-modules.texi >> +++ b/doc/ref/srfi-modules.texi >> @@ -55,7 +56,7 @@ get the relevant SRFI documents from the SRFI home page >> * 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 64:: A Scheme API for test suites. > > If you change this for one, please harmonize the others (with or without > -). Consistency wins here. Ludovic kept the current convention, so that's tackled. >> @@ -5290,12 +5291,827 @@ needed to get SRFI-61 itself. Extended @code{c= ond} is documented in > =E2=80=A6 >> +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. > > Is this relevant for Guile? > If not, I=E2=80=99d take the racket specific part out. It's relevant to the context in which this SRFI was created. Not critical for Guile, but maybe nice for the reader wanting to know the full story. I don't feel strongly about removing it though. >> +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 sub-sentence ("but I hope...") isn=E2=80=99t needed here, I think. I turned it into 'but it is hoped', i.e. neutral tone at least. >> +Test cases are executed in the context of a @dfn{test runner}, which is >> +a object that accumulates and reports test results. This >> specification > > Typo: a object -> an object > > (this might also be a good change/PR for srfi 64 itself =E2=87=92 upstrea= m) Thanks. Fixed, and an upstream PR already submitted for this one and others you found: . >> +defines how to create and use custom test runners, but implementations >> +should also provide a default test runner. It is suggested (but not > > Does Guile provide a default test runner? > =E2=87=92 that may be good to note instead of "should also". I've added to this paragraph documenting what the implementation in Guile does: --8<---------------cut here---------------start------------->8--- modified doc/ref/srfi-modules.texi @@ -5393,7 +5393,25 @@ should also provide a default test runner. It is su= ggested (but not required) that loading the above file in a top-level environment will cause the tests to be executed using an implementation-specified default test runner, and @code{test-end} will cause a summary to be displayed in -an implementation-specified manner. +an implementation-specified manner. The SRFI 64 implementation used in +Guile provides such a default test runner; running the above snippet at +the REPL prints: + +@example +*** Entering test group: vec-test *** +$1 =3D #t +* PASS: +$2 =3D ((pass . 1)) +* PASS: +$3 =3D ((pass . 2)) +* PASS: +$4 =3D ((pass . 3)) +*** Leaving test group: vec-test *** +*** Test suite finished. *** +*** # of expected passes : 3 +@end example + +It also returns the @code{} object. @subsubheading Simple test-cases --8<---------------cut here---------------end--------------->8--- >> +required) that loading the above file in a top-level environment will >> +cause the tests to be executed using an implementation-specified default >> +test runner, and @code{test-end} will cause a summary to be displayed in >> +an implementation-specified manner. > =E2=80=A6 >> +For testing approximate equality of inexact reals >> +we can use @code{test-approximate}: >> + >> +@deffn {Scheme Syntax} test-approximate [test-name] expected test-expr = error >> + >> +This is equivalent to (except that each argument is only evaluated >> +once): >> + >> +@lisp >> +(test-assert [test-name] >> + (and (>=3D test-expr (- expected error)) >> + (<=3D test-expr (+ expected error)))) >> +@end lisp >> +@end deffn > > It would be nice to have an explicit example here. > I've added an example: --8<---------------cut here---------------start------------->8--- @@ -5455,6 +5473,14 @@ once): (and (>=3D test-expr (- expected error)) (<=3D test-expr (+ expected error)))) @end lisp + +Here's an example: +@lisp +(test-approximate "is 22/7 within 1% of =CF=80?" + 3.1415926535 + 22/7 + 1/100) +@end lisp @end deffn @subsubheading Tests for catching errors --8<---------------cut here---------------end--------------->8--- >> +@lisp >> +(test-error #t (vector-ref '#(1 2) 9)) >> +@end lisp >> + >> +This specification leaves it implementation-defined (or for a future >> +specification) what form @var{test-error} may take, though all >> +implementations must allow @code{#t}. > > It would be good to show what Guile accepts instead. I've kept the original text, but appended this paragraph to it: --8<---------------cut here---------------start------------->8--- @@ -5492,6 +5518,23 @@ classes: An implementation that cannot catch exceptions should skip @code{test-error} forms. + +The SRFI 64 implementation in Guile supports specifying @var{error-type} +as either: +@iterate +@item +@code{#f}, meaning the test is @emph{not} expected to produce an error +@item +@code{#t}, meaning the test is expected to produce an error, of any type +@item +A native exception type, as created via @code{make-exception-type} or +@code{make-condition-type} from SRFI-35 +@item +A predicate, which will be applied to the exception caught +to determine whether is it of the right type +@item +A symbol, for the exception kind of legacy +@code{make-exception-from-throw} style exceptions. @end deffn @subsubheading Testing syntax --8<---------------cut here---------------end--------------->8--- > =E2=80=A6 >> +@lisp >> +;; Kawa-specific example >> +(test-error (vector-ref '#(1 2) 9= )) >> +@end lisp > > An example with Guile would be good. I've added this: --8<---------------cut here---------------start------------->8--- @end deffn +Below are some examples valid in Guile: + +@lisp +(test-error "expect old-style exception kind" + 'numerical-overflow + (/ 1 0)) +@end lisp + +@lisp +(use-modules (ice-9 exceptions)) ;for standard exception types + +(test-error "expect a native exception type" + &warning + (raise-exception (make-warning))) + +(test-error "expect a native exception, using predicate" + warning? + (raise-exception (make-warning))) +@end lisp + +@lisp +(use-modules (srfi srfi-35)) + +(test-error "expect a serious SRFI 35 condition type" + &serious + (raise-exception (condition (&serious)))) + +(test-error "expect a serious SRFI 35 condition type, using predicate" + serious-condition? + (raise-exception (condition (&serious)))) +@end lisp + @subsubheading Testing syntax --8<---------------cut here---------------end--------------->8--- >> +@subsubheading Test specifiers >> + >> +Sometimes we want to only run certain tests, or we know that certain >> +tests are expected to fail. A @dfn{test specifier} is one-argument >> +function that takes a test-runner and returns a boolean. The >> specifier > > is *a* one-argument function > (also for upstream) Fixed. > Aside from these, this patch looks good to me. > Thank you! Thank you. As I said, it's been applied already, thanks to Ludovic. I'll try ensure this follow-up also does! --=20 Thanks, Maxim