Thanks! That makes it much nicer to work with raco test
.
Do you have any suggestions for then running those in the repl?
Personally (possibly a bad habit?) I don’t use test suites, just test cases. Either in a test
submodule, or in plain module files in a tests
subdirectory. The info.rkt
at the base directory can control which files raco test
should run (via test-include-paths
and test-omit-paths
).
So do you not run those tests through the repl then? It doesn’t seem like test cases get evaluated when I evaluate the buffer.
DrRacket can be configured to run the test
submodule. In a repl, you can require the test submodule directly with require
+ submod
To check the tests of a single file, I usually run it in DrRacket. To check all tests I use raco test
Interesting maybe it’s something with emacs… I evaluate the test submodule I believe since the repl changes to main.rkt/test>
but the test cases don’t run. They do run if I execute raco test
I don’t use emacs much, and I haven’t tried with tests. You can force entering the test submodule with this: (require (only-in racket/enter dynamic-enter!)
(only-in syntax/location quote-module-path))
(dynamic-enter! (quote-module-path test))
Not ideal though, but at least you can try it and see if something happens
If you simply evaluate a rackunit
form like check-equal?
, and it succeeds, it prints nothing. It only prints failures.
So when you put tests in a test
submodule, and run that submodule in Racket Mode, it runs the submodule like any other. There’s nothing special.
There is some “test runner” stuff to collect info on the number of tests that pass, and print that at the end. But Racket Mode doesn’t do that when simply running the test
submodule.
:face_palm: that was the problem
If you just want reassurance the tests ran, at all, you could put a (displayln "tests ran!")
at the end of the test
submodule
If you want the stats about how many, etc., I’m not sure but rackunit
may have a thing you could call to print that? I’m not sure.
Oh I like the displayln
idea just for safety.
(Personally, I usually just want to know if tests fail. Don’t want noise about them passing. So this has never bothered me much. But I appreciate not everyone feels the same way.)
Yeah I can get the stats if I use test-suite
with run-tests
from rackunit/text-ui
, but then I have to manually collect all the tests.
Maybe I should work on creating something similar to what Clojure has with test-all
. You would call it plain and it would automatically collect all the test suites and excute them.
So, I do run raco test
a lot, automatically, and get those stats.
But when I’m drilled down on one source file, I usually don’t care.
Usually, tests silently passing is the exact opposite of my problem — usually plenty of tests are failing. :slightly_smiling_face:
And I’m in that test submodule in the REPL, exploring and figuring out why.
So, again, that’s why it’s been OK for me, but, again, I understand it’s not everyone’s M.O.
Also I totally get that it sucks that there’s no affirmative indication that the tests ran, at all, and that can be unsettling if someone is new to rackunit
and the workflow. That totally makes sense.
Makes complete sense. I like that. It’s very linux style (succeed silently).
btw for packages, e.g. if you have an info.rkt
, then raco test -p <pkg-name>
is the Clojure test-all AFAIK
And I usually have that in a makefile, and also it runs on CI.
Ah good to know. My next task was going to be configuring the test paths info.rkt
so I could just run raco test
. Since right now I have to explicitly provide the package name.
From emacs I sometimes do M-x compile
and enter make setup test
and it builds my Racket project and run the tests.
If all your .rkt files are in one dir, you could just do something like raco test .
IIRC
I haven’t tried but I don’t think you need a package to use an info.rkt file in the base directory.
If you run raco test .
in the directory where the info.rkt is, I think it will look it up (to be confirmed though)
This will also look in subdirectories I think
Oh cool.
Yeah I think my experience with Clojure is more things work only if you’ve Set Up a Formal Project Infrastructure. Whereas with Racket more things can work with a formal project but also work in “more causual” or ad hoc ways.
Thanks for all the help everyone. I definitely feel like I have a solid test workflow now!
(as a rough rule of thumb, and probably not 100% true. Like I believe Clojure has gotten better recently about running files from the command line, ad hoc)
I’d like to split a string into a list of strings-of-length–2, that is, “deadbeef” —> (list “de” “ad” “be” “ef”). That’s because what I really want is the bytes from a hex string. What is the idiomatic way to do this?
See in-slice
That’s so nice! Thanks!
one more pretty useful thing I didn’t know existed!
Neither did I. But it seems it splits the string in lists of characters.
Yes, I’ll treat that myself now. I mean, that’s what I think sorawee’s pointer is.
Otherwise you have the obvious: (let ([s "abcde"])
(define len (string-length s))
(for/list ([i (in-range 0 len 2)])
(substring s i (min (+ i 2) len))))
; '("ab" "cd" "e")
For strings of even length, you can use: (let* ([s "deadbeef"] [n (string-length s)])
(for/list ([from (in-range 0 (+ n 1) 2)] [to (in-range 2 (+ n 1) 2)])
(substring s from to)))
:smile:
Laurent’s version is better!
Lol. That’s what I call parallelism!
Here’s my contribution: (it does work with non-even-length strings [because in-slice does]) (define (hex->bytes hex-str)
(define ls-of-hex
(for/list ([ls (in-slice 2 hex-str)])
(list->string ls)))
(list->bytes (map (λ (b) (string->number b 16)) ls-of-hex)))
You can avoid map
, since that’s what for/list
does
(define (hex->bytes hex-str)
(list->bytes
(for/list ([ls (in-slice 2 hex-str)])
(string->number (list->string ls) 16))))
(map f (map g xs))
= (map (compose1 f g) xs)
With less allocation
(of course, assuming effect free functions)
Brain teaser: Predict the output of: (map map (list list) (list (list map map)))
Another one if you hadn’t had enough: (map apply (list list map) (list (list map) (list list (list map))))
Brain teaser: find a normal form of ((lambda (lambda) (lambda lambda)) (lambda (lambda) (lambda lambda)))
Wonder whether notjack’s tool can fix that one. :wink:
I’ve made a generator, so now I can flood! (apply apply (list list (list (list (list map apply map)) map apply)))
idk if this was covered above, but for very simple test stats you can look at rackunit/log
and (test-log)
most fail, and most of the rest are pretty dull like (apply list ...)
and (map list ...)
Still finds (apply map (list list (list apply)))
and (apply apply (list list list (list list)))
:smile:
Is this a version of the Y-combinator? Or at least some fix-point combinator?
It’s known as omega. One way to look at it is that it’s a specialization of the Y combinator to make a non-terminating term.
I also like using test submodules typically. For one thing, it allows testing private functions that aren’t exported. However, occasionally, it’s easier to create a separate file of just tests to avoid circular require
dependencies.
Here’s one convolution way to produce the empty list: (apply map (list map (list) (list)))
Here’s an even better one: (apply apply (list map apply (list (list))))