Dynamically generating rackunit test-suite: tests pass and also raise exception - racket

I am trying to dynamically generate a bunch of test cases.
Basically I want to run the same tests several times with different values. Maybe there's a better way to do that, if so let me know, I haven't found it yet.
I found make-test-suite which says you can pass it a list of test-case instances.
So I made a for/fold loop which collects the test cases generated for each set of values into a flat list.
What I don't understand is it seems to successfully run all the tests while also raising an exception:
tests->test-suite-action received #<void> in list of tests (#<void> #<void> #<void> #<void> #<void> #<void> #<void> #<void>), which is not a test.
context...:
/usr/share/racket/pkgs/rackunit-lib/rackunit/private/test-suite.rkt:139:7
/usr/share/racket/pkgs/rackunit-lib/rackunit/private/test-suite.rkt:136:2
/usr/share/racket/pkgs/rackunit-lib/rackunit/private/test-suite.rkt:61:0: apply-test-suite
/usr/share/racket/pkgs/rackunit-lib/rackunit/text-ui.rkt:91:0: run-tests
"/write-thru-hash/tests.rkt": [running body]
temp35_0
for-loop
run-module-instance!
/usr/share/racket/pkgs/compiler-lib/compiler/commands/test.rkt:179:16
...
1 1 write-thru-hash/tests.rkt
8 tests passed
rkt-write-thru-hash_tests_1 exited with code 1
I put a writeln in each of my test cases and I see those lines printed out where I abbreviated with ... above. So I know the tests are actually running.
(The tests also ran and worked fine before I multiplied them with the for/fold loop and just built them in the body of test-suite)
My tests.rkt code looks like:
(define test-cases-list
(for/fold ([test-cases (list)])
([db-type (list 'sqlite 'postgres)])
(append test-cases
(list
(test-case/fixture "basic operations" ... )
(test-case/fixture "complex serializable keys and values" ... )
(test-case/fixture "custom table-name" ... )
(test-case/fixture "use initial src-hash" ... )))))
(define db-tests
(make-test-suite "db-tests" test-cases-list))
(I'm using the fixture library https://docs.racket-lang.org/fixture/)
UPDATE:
Actually I think the writeln in my test cases are printing at definition time ... i.e. they are running too early because they are outside of the test-suite context.
I guess the tail check in each test-case returns #<void>, so I have filled a list with the results of the tests (voids) rather than the test cases themselves and given that to the test suite, hence the error.
But then I don't see how to actually use make-test-suite...?

Eventually found a simple way to do this.
My problem was in trying to have several variations of my test cases all dynamically generated into one test-suite. I did not find a way to get that to work, I suspect I would have to write a macro.
Instead the simple way is to dynamically define multiple test-suite instances and then loop over a list of them to run them:
(define db-test-suites
(for/list ([db-type (list 'sqlite 'postgres)]
[db-conn-fixture (list sqlite-connection-delete-after-use
postgres-connection)])
(define suite-name (format "db-tests: ~a" db-type))
(test-suite suite-name
(test-case/fixture "basic operations"
#:fixture db-conn-fixture
(define db-conn (fixture-value db-conn-fixture))
...)
(test-case/fixture "complex serializable keys and values"
#:fixture db-conn-fixture
(define db-conn (fixture-value db-conn-fixture))
...))))
(for ([current-test-suite db-test-suites])
(run-tests current-test-suite))
UPDATE:
I also found a way to actually use make-test-suite:
(define all-tests (make-test-suite "db-test-suites" db-test-suites))
(run-tests all-tests)
This takes advantage of the fact that a test-suite can contain other nested test-suites. I think this form is nicer (a single run-tests call) than the one above (multiple run-tests calls in a for loop).
All my problems in the original question were in trying to pre-define a bunch of test-case instances outside of a test-suite container. But here we pass make-test-suite a list of test-suite instances, allowing the tests within them to defer running until we later call run-tests.

Related

How to write a function in a Lisp. Compile that Lisp file. and then run that Lisp program

Write, compile, and test a funtion in Common Lisp that takes a list and counts the total of positive integers in the List. Must compile then execute .lisp file containing the function. after compilation of that file start to pass it list where after the results for the result to be produced therefore testing the correctness of the function.
I have the function. I can run it rawly by putting if directly into the Lisp command line. Simply put I just need to figure out how to compile the file and then pass it list on the terminal to test it.
(count-if #'(lamda (x) (> x 0))
i need to compile that
then for example pass it this ex:: ( 1 2 3 4 5)
and the result should be :: 5
this is because their are 5 values that equal more then 0
Write a file:
$ echo "(defun test () (print :test))" > test.lisp
In the same directory, start you Common Lisp environment (example with CCL), you have a REPL; compile the file:
? (compile-file "test.lisp")
#P"/tmp/test.lx64fsl"
NIL
NIL
Note that if you try to run the test function, there will be an error because it is undefined in your environment.
Load the resulting object file; if you load "test", the object file is used if available; you could have called load directly on the ".lisp" file, but then there are no guarantees the file is compiled or interpreted. That's a minor detail here, you probably should not care about compiling or not at this point.
? (load "test")
Now, test is available in your environment, you can call it:
? (test)
:TEST ;; what the function printed
:TEST ;; the returned value, automatically printed by the REPL
Without restarting the Lisp environment, you can edit the file, and reload it.
This is a minimalistic setup but that should be enough for starting.

How to read space separated integers in racket

I looked at the documentation https://docs.racket-lang.org/reference/input-and-output.html but I find it to be very confusing and I feel like it contains a lot of extra information I don't need for such a simple task.
I would like to read two space separated integers and store them in variables.
example input:
1 2
I would like to define and x and y whose values are 1 and 2 respectively.
There are a lot of ways to do this. I’ll give you three.
Option 1: Use the built-in read
The read function reads s-expressions. Conveniently, integers are valid s-expressions, and it skips whitespace, too. This means you can just call read twice on an input port to produce two datums:
> (let ([in (open-input-string "1 2")])
(values (read in) (read in)))
1
2
This has a drawback, though: there are a lot of things that are valid s-expressions that aren’t numbers, so you might get a lot of garbage back if you’re not careful. For example:
> (let ([in (open-input-string "#f (hello world)")])
(values (read in) (read in)))
#f
'(hello world)
You’d probably need to do some post-processing to ensure what you get back is what you expect. This also won’t necessarily consume all the input, so if it’s important there’s nothing else after the numbers, you’d need to check that separately, too.
Option 2: Use a regular expression
Regular expressions are a pretty easy way to handle simple cases like this. In this example, the regexp literal #px"^(\\d+) (\\d+)$" is a simple way to express the pattern you mention in your question. You can use this to extract the numeric parts of the string:
> (regexp-match #px"^(\\d+) (\\d+)$" "1 2")
'("1 2" "1" "2")
You can combine this with string->number to get numbers out:
> (let ([matches (regexp-match #px"^(\\d+) (\\d+)$" "1 2")])
(values (string->number (second matches))
(string->number (third matches))))
1
2
This has the advantage of ensuring the input matches precisely, and it’s safe, fast, and simple. However, one downside is that it will not provide good error messages if the parsing fails, regexp-match will simply produce #f.
Option 3: Use a parser combinator library
Racket has a number of libraries designed for parsing. These can scale to parsing far more complicated things that two numbers, but they also work fine for simple situations. I will show an example using megaparsack, since it’s my library, and I like it.
You can use megaparsack to write a parser that parses two integers separated by a space:
(require data/applicative
data/monad
megaparsack
megaparsack/text)
(define 2-integers/p
(do [x <- integer/p]
(char/p #\space)
[y <- integer/p]
(pure (cons x y))))
This parser is obviously more complicated than the regexp, but it also does more, and it’s much more extensible and composable. You can use this parser to get the numbers you want:
> (parse-result! (parse-string 2-integers/p "1 2"))
'(1 . 2)
However, unlike the regular expression, it will automatically provide good error messages when a parse fails:
> (parse-result! (parse-string 2-integers/p "1 "))
string:1:1: parse error
unexpected: end of input
expected: integer

Point of quoting multiple times in lisp? (eg '''''a)

Is there a use in being able to quote multiple times?
Like 'a is different from ''a and (quote a) is different from (quote (quote a))
I mean, why not have it so that ''a is the same as 'a or even ''''''''a. quote would quote if the argument it's given has not been quoted already and that way ''''a would evaluate to 'a.
The way it is feels wrong to me because I think the question should be: is it quoted? and not how many times has it been quoted? none? once? a 100 times?
Nesting quotes is largely useless. It might happen in the output of a compiler for the backquote syntax, but I can't think of any reason why you would do that, even in nested macros. If you find yourself cascading quotes, that probably means you've inserted the expression in a backquote template at the wrong unquote level.
Concretely, suppose you have written something like this:
````(,,,,'''''a) ;; goal is to be left with ('a) at the end of four eval rounds
But here, the commas and quotes basically cancel and you can do it like this:
````('a)
There is no need to assign the form ''''a to the innermost backquote, and have it work backwards toward 'a across multiple evaluations. Just assign 'a to the outermost level and you're done.
Another example would be a slight modification of the above. We expect four evaluation rounds to happen, and in the very last round a is substituted for the binding which it has in the environment of that evaluation:
````(,,,,''''a) ;; only four quotes this time
So now, after three evals of the result of the above backquote, we are left with (a) and if we eval that, it wants to call the function a. But, again, we could achieve the same thing like this:
````(a)
Exactly like before, three evals produce (a) and one more wants to call a.
Now what if the symbol a is not literally a, but computed? Say a is to be replaced by b:
(let ((a 'b))
````(,,,''',a))
The substitution has to happen in the first evaluation of the backquote, inside the let, and so the b needs four commas on the left, so that it connects to the outermost backquote. The resulting object is equivalent to
```(,,,'''a)
In this example, we cannot just cancel the three commas and quotes. However, the customary way is to have the two interspersed:
(let ((a 'b))
````(,',',',a)) ;; instead of ,,,''',a
Each evaluation round strips away a quote but then adds one back. The first substitution replaces ,a with b, but then protects it with the quote. Then in the next round, the comma before that quote causes ,'b to be replaced with b, but another quote before that protects it once again, and so on.
That is to say, the two situations in which you might see directly compounded quotes doing something useful would be: triply (or more) nested backquote (rare to begin with!) in which someone used ,,'',expr instead of ,',',expr; and superfluous use of multiple quotes used to combat the multiple evaluation of some form that was needlessly submerged into multiple evaluation rounds.
Of course there is. When the expression is evaluated more than once and you need to pass the expression through more than one evaluation as is. Remember, when writing macros, the expression is usually evaluated twice (once during expansion and once as the macro result) and in some rare cases may need to be evaluated even more times.
#Kaz is no doubt right about usual practice, but I would agree with #JanHudec about what is appropriate for CL. 'a means the same thing as (quote a), and ''a means the same thing as (quote (quote a)). What you're suggesting, user1076329, is that evaluating (quote (quote a)) should have the same result as evaluating (quote a). It feels contrary to the spirit of CL to make it difficult for a function to return 'a. (Suppose, for example, that you were writing a program that would generate Lisp source code to be written to a file and evaluated later? Or writing a program that generates Lisp source code for a program that writes Lisp programs? Lisp is designed to make it easy to do this sort of thing.) You can and should use macros in many cases, but in essence a macro is just way of constructing lists and then evaluating them. You should be able to construct the same lists without macros or backquote, even if they make it easier.

Is Lisp the only language with REPL?

There are languages other than Lisp (ruby, scala) that say they use REPL (Read, Eval, Print, Loop), but it is unclear whether what is meant by REPL is the same as in Lisp. How is Lisp REPL different from non-Lisp REPL?
The idea of a REPL comes from the Lisp community. There are other forms of textual interactive interfaces, for example the command line interface. Some textual interfaces also allow a subset of some kind of programming language to be executed.
REPL stands for READ EVAL PRINT LOOP: (loop (print (eval (read)))).
Each of the four above functions are primitive Lisp functions.
In Lisp the REPL is not a command line interpreter (CLI). READ does not read commands and the REPL does not execute commands. READ reads input data in s-expression format and converts it to internal data. Thus the READ function can read all kinds of s-expressions - not just Lisp code.
READ reads a s-expression. This is a data-format that also supports encoding source code. READ returns Lisp data.
EVAL takes Lisp source code in the form of Lisp data and evaluates it. Side effects can happen and EVAL returns one or more values. How EVAL is implemented, with an interpreter or a compiler, is not defined. Implementations use different strategies.
PRINT takes Lisp data and prints it to the output stream as s-expressions.
LOOP just loops around this. In real-life a REPL is more complicated and includes error handling and sub-loops, so-called break loops. In case of an error one gets just another REPL, with added debug commands, in the context of the error. The value produced in one iteration also can be reused as input for the next evaluation.
Since Lisp is both using code-as-data and functional elements, there are slight differences to other programming languages.
Languages that are similar, those will provide also similar interactive interfaces. Smalltalk for example also allows interactive execution, but it does not use a data-format for I/O like Lisp does. Same for any Ruby/Python/... interactive interface.
Question:
So how significant is the original idea of READing EXPRESSIONS, EVALuating them and PRINTing their values? Is that important in relation to what other languages do: reading text, parsing it, executing it, optionally print something and optionally printing a return value? Often the return value is not really used.
So there are two possible answers:
a Lisp REPL is different to most other textual interactive interfaces, because it is based on the idea of data I/O of s-expressions and evaluating these.
a REPL is a general term describing textual interactive interfaces to programming language implementations or subsets of those.
REPLs in Lisp
In real implementations Lisp REPLs have a complex implementation and provide a lot of services, up to clickable presentations (Symbolics, CLIM, SLIME) of input and output objects. Advanced REPL implementations are for example available in SLIME (a popular Emacs-based IDE for Common Lisp), McCLIM, LispWorks and Allegro CL.
Example for a Lisp REPL interaction:
a list of products and prices:
CL-USER 1 > (setf *products* '((shoe (100 euro))
(shirt (20 euro))
(cap (10 euro))))
((SHOE (100 EURO)) (SHIRT (20 EURO)) (CAP (10 EURO)))
an order, a list of product and amount:
CL-USER 2 > '((3 shoe) (4 cap))
((3 SHOE) (4 CAP))
The price for the order, * is a variable containing the last REPL value. It does not contain this value as a string, but the real actual data.
CL-USER 3 > (loop for (n product) in *
sum (* n (first (second (find product *products*
:key 'first)))))
340
But you can also compute Lisp code:
Let's take a function which adds the squares of its two args:
CL-USER 4 > '(defun foo (a b) (+ (* a a) (* b b)))
(DEFUN FOO (A B) (+ (* A A) (* B B)))
The fourth element is just the arithmetic expression. * refers to the last value:
CL-USER 5 > (fourth *)
(+ (* A A) (* B B))
Now we add some code around it to bind the variables a and b to some numbers. We are using the Lisp function LIST to create a new list.
CL-USER 6 > (list 'let '((a 12) (b 10)) *)
(LET ((A 12) (B 10)) (+ (* A A) (* B B)))
Then we evaluate the above expression. Again, * refers to the last value.
CL-USER 7 > (eval *)
244
There are several variables which are updated with each REPL interaction. Examples are *, ** and *** for the previous values. There is also + for the previous input. These variables have as values not strings, but data objects. + will contain the last result of the read operation of the REPL. Example:
What is the value of the variable *print-length*?
CL-USER 8 > *print-length*
NIL
Let's see how a list gets read and printed:
CL-USER 9 > '(1 2 3 4 5)
(1 2 3 4 5)
Now let's set the above symbol *print-length* to 3. ++ refers to the second previous input read, as data. SET sets a symbols value.
CL-USER 10 > (set ++ 3)
3
Then above list prints differently. ** refers to the second previous result - data, not text.
CL-USER 11 > **
(1 2 3 ...)
Seeing as the concept of a REPL is to just Read, Eval, Print & Loop it's not too suprising that there are REPLs for many languages:
C/C++
C#/LINQ
Erlang
Haskell (on windows)
Java
Javascript
Julia
Perl
Python
Ruby
Scala
Smalltalk -- I learned it on a REPL!
I think it is interesting to compare two approaches. A bare bones REPL loop in a Lisp system would look like this:
(loop (print (eval (read))))
Here are two actual Forth implementations of a REPL loop. I'm leaving nothing out here -- this is the full code to these loops.
: DO-QUIT ( -- ) ( R: i*x -- )
EMPTYR
0 >IN CELL+ ! \ set SOURCE-ID to 0
POSTPONE [
BEGIN \ The loop starts here
REFILL \ READ from standard input
WHILE
INTERPRET \ EVALUATE what was read
STATE # 0= IF ." OK" THEN \ PRINT
CR
REPEAT
;
: quit
sp0 # 'tib !
blk off
[compile] [
begin
rp0 # rp!
status
query \ READ
run \ EVALUATE
state # not
if ." ok" then \ PRINT
again \ LOOP
;
Lisp and Forth do completely different things, particularly in the EVAL part, but also in the PRINT part. Yet, they share the fact that a program in both languages is run by feeding its source code to their respective loops, and in both cases code is just data (though in Forth case it is more like data is also code).
I suspect what anyone saying only LISP has a REPL is that the READ loop reads DATA, which is parsed by EVAL, and a program is created because CODE is also DATA. This distinction is interesting in many respects about the difference between Lisp and other languages, but as far as REPL goes, it doesn't matter at all.
Let's consider this from the outside:
READ -- returns input from stdin
EVAL -- process said input as an expression in the language
PRINT -- print EVAL's result
LOOP -- go back to READ
Without going into implementation details, one can't distinguish a Lisp REPL from, for example, a Ruby REPL. As functions, they are the same.
I guess you could say that Scala's "REPL" is an "RCRPL": Read, Compile, Run, Print. But since the compiler is kept "hot" in memory, it's pretty fast for ongoing interactions--it just takes a few seconds to start up.
There are a number of people that consider a REPL to needs to behave exactly like it does in LISP, or it's not a true REPL. Rather, they consider it something different, like a CLI (command line interpreter). Honestly, I tend to think that if it follows the basic flow of:
read input from the user
evaluate that input
print the output
loop back to the read
then it's a REPL. As noted, there are a lot of languages that have the above capability.
See this reddit thread for an example of such a discussion.
How is Lisp REPL different from non-Lisp REPL?
Let's compare Common Lisp's REPL with Python's IPython.
The main two points are:
Lisp is an image-based language. There is no need to restart the process/the REPL/the whole app after a change. We compile our code function by function (with compiler warnings etc).
we don't loose state. Even more, when we update class definitions, our objects in the REPL are also updated, following rules we have control upon. That way we can hot-reload code in a running system.
In Python, typically, you start IPython or you are dropped into ipdb. You define some data until you try out your new function. You edit your source, and you want to try again, so you quit IPython and you start the whole process again. In Lisp (Common Lisp mainly), not at all, it's all more interactive.
There's a nice project called multi-repl which exposes various REPLs via Node.JS:
https://github.com/evilhackerdude/multi-repl
If you look at the list of supported languages, it's quite clear that not only Lisp has the concept of a REPL.
clj (clojure)
ghci (ghc)
ipython
irb (ruby)
js (spidermonkey)
node
python
sbcl
v8
In fact implementing a trivial one in Ruby is fairly easy:
repl = -> prompt { print prompt; puts(" => %s" % eval(gets.chomp!)) }
loop { repl[">> "] }

Apply-recur macro in Clojure

I'm not very familiar with Clojure/Lisp macros. I would like to write apply-recur macro which would have same meaning as (apply recur ...)
I guess there is no real need for such macro but I think it's a good exercise. So I'm asking for your solution.
Well, there really is no need for that, if only because recur cannot take varargs (a recur to the top of the function takes a single final seqable argument grouping all arguments pass the last required argument). This doesn't affect the validity of the exercise, of course.
However, there is a problem in that a "proper" apply-recur should presumably handle argument seqs returned by arbitrary expressions and not only literals:
;; this should work...
(apply-recur [1 2 3])
;; ...and this should have the same effect...
(apply-recur (vector 1 2 3))
;; ...as should this, if (foo) returns [1 2 3]
(apply-recur (foo))
However, the value of an arbitrary expression such as (foo) is simply not available, in general, at macro expansion time. (Perhaps (vector 1 2 3) might be assumed to always yield the same value, but foo might mean different things at different times (one reason eval wouldn't work), be a let-bound local rather than a Var (another reason eval wouldn't work) etc.)
Thus to write a fully general apply-recur, we would need to be able to determine how many arguments a regular recur form would expect and have (apply-recur some-expression) expand to something like
(let [seval# some-expression]
(recur (nth seval# 0)
(nth seval# 1)
...
(nth seval# n-1))) ; n-1 being the number of the final parameter
(The final nth might need to be nthnext if we're dealing with varargs, which presents a problem similar to what is described in the next paragraph. Also, it would be a good idea to add an assertion to check the length of the seqable returned by some-expression.)
I am not aware of any method to determine the proper arity of a recur at a particular spot in the code at macro-expansion time. That does not mean one isn't available -- that's something the compiler needs to know anyway, so perhaps there is a way to extract that information from its internals. Even so, any method for doing that would almost certainly need to rely on implementation details which might change in the future.
Thus the conclusion is this: even if it is at all possible to write such a macro (which might not even be the case), it is likely that any implementation would be very fragile.
As a final remark, writing an apply-recur which would only be capable of dealing with literals (actually the general structure of the arg seq would need to be given as a literal; the arguments themselves -- not necessarily, so this could work: (apply-recur [foo bar baz]) => (recur foo bar baz)) would be fairly simple. I'm not spoiling the exercise by giving away the solution, but, as a hint, consider using ~#.
apply is a function that takes another function as an argument. recur is a special form, not a function, so it cannot be passed to apply.