Accessing Internal Symbols of a Package in Testing Package - testing

I have a program that I'd like to test using prove. Currently, I have a separate package for the tests. The problem I'm facing is that I don't really want to have to export every symbol from the primary package (I'm only exporting one currently), but I want to be able to access everything from the testing package.
Using main-package::symbol works, but is ugly and a bad idea I'm guessing. Is there some better way to do this without having to export all my symbols just for testing them? I've considered using the same package for writing the tests, but I don't want to have to have a (:use :prove) in my main package when I'm only using it for the testing code. Is there some way to do something like (:use :package) but only for one file? If there is, would it make sense to use that here?

You could separate the tests into their own system. That way your main system won't have a dependency on prove at all. In the test system you can load the same source files, but different package definitions (this of course assumes you put your package definitions in a different file, rather than using the strange custom of putting them on top of your source file...).
For example, the main program might look like this:
foo.asd:
;; Here I'm obviously putting the package def in the same file
(in-package :cl-user)
(defpackage :foo-asd
(:use :cl :asdf))
(in-package :foo-asd)
(defsystem "foo"
:components ((:file "foo-package")
(:file "foo")))
foo-package.lisp:
(in-package :cl-user)
(defpackage :foo
(:use :cl)
(:export :foo))
foo.lisp:
(in-package :foo)
(defun foo (x)
(+ (bar x)
(bar x)))
(defun bar (x)
(* x x))
And the test system in the same directory:
foo-test.asd:
(in-package :cl-user)
(defpackage :foo-test-asd
(:use :cl :asdf))
(in-package :foo-test-asd)
(defsystem "foo-test"
:depends-on (:prove)
:components ((:file "foo-test-package")
(:file "foo")
(:file "foo-test")))
foo-test-package.lisp
(in-package :cl-user)
(defpackage :foo
(:use :cl :prove))
foo-test.lisp:
(in-package :foo)
(plan 2)
(is (bar 2)
4)
(is (foo 2)
8)
(finalize)
This lets you easily run your tests in a new image (to make sure that the version of the code that's actually on your disk works) with something like sbcl --noinform --eval "(ql:quickload :foo-test)" --eval "(sb-ext:quit)". You could of course put the tests behind a function if you want.

Related

Should I define separate module for every file in my Guile project?

Let me explain my problem by comparison. In Common Lisp I could split package definitions to several files, it was enough to declare in each of them that it's in-package and load them.
However in Guile Scheme it looks like I should define-module, separate for each file? Well I still can load some files like in CL and it looks like working, define-modules seems not limited to a single file it is located in like in CL, but I get warnings about undefined names (those that are defined in loaded files), so it gives me feeling that it's not what Guile expects. Is there (1) some way of splitting module across several files like in CL, or (2) should I stick to use-module autoload feature and define-module for each file separatelly?
Indeed in Guile you can load inside a define-module but it will report unbound variable at compile time.
The idiomatic way is the define-module in every file:
;; in earth-software-system.scm
(define-module (earth-software-system))
(use-modules (earth-software-system bullet-train))
(use-modules (srfi srfi-9))
(re-export bullet-train) ;; possibly re-exporting imported bindings
...
Then in earth-software-system/bullet-train.scm you can have:
;; in earth-software-system/bullet-train.scm
(define-module (earth-software-system bullet-train))
(use-modules (srfi srfi-9))
(define-public bullet-train 42)
...
Mind the fact that define-public and a single import per use-modules is not widespread. Here is an example from GNU Guix project that rely on define-module to import and export:
(define-module (guix cpio)
#:use-module ((guix build utils) #:select (dump-port))
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-11)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
#:use-module (ice-9 match)
#:export (cpio-header?
make-cpio-header
file->cpio-header
file->cpio-header*
write-cpio-header
read-cpio-header
write-cpio-archive))
Also nowadays I prefer the import form which is more easy to the mind that use-modules:
;; in earth-software-system.scm
(define-module (earth-software-system))
(import (prefix (earth-software-system bullet-train) 'bt:)
(import (srfi srfi-9))
(re-export bt:bullet-train) ;; possibly re-exporting imported bindings
...
The prefix syntax is also more easy to the mind than the equivalent using use-modules. This is inspired from R6RS library form and R7RS define-library form. I do not recommend to use library form in Guile since it doesn't report lines correctly.
GNU Guile allow to import forms even if they are not exported using the ## syntax for instance to test some tricky behavior.
You might replace load with include but I never used it in Guile

dynamic-require a module with respect to the current module path in Racket (Or how to find the current module path in Racket)

If I want to optionally require a module at runtime, I can use [dynamic-require'1. This works great if I want to require a package that has been installed, for example:
(dynamic-require 'racket/match 'match)
This will (provided I have racket/match installed), require racket/match and evaluate to the match binding in that library.
However, I run into trouble when I want to require a local, non installed module. Let's say I have some module called eat.rkt, which provides one function: bite:
#lang racket ;; eat.rkt
(provide bite)
(define (bite) "Nom nom")
Now lets say we want to make a lunch.rkt module that requires eat.rkt, and calls the function. Furthermore, lets suppose I put them in the same directory:
#lang racket ;; lunch.rkt
(require "eat.rkt")
(bite) ; => Nom Nom
This is fine because I used static require, but this falls apart when I want to do a dynamic-require:
#lang racket ;; lunch2.rkt
(define bite (dynamic-require "eat.rkt" 'bite)
(bite) ; => Nom Nom
While this appears to be fine, it turns out that the module required by dynamic-require is NOT required based on the module's path, but on current-directory. So, if I run the program in the directory the module is defined, that's fine, but if I'm in another directory, everything breaks:
$ racket lunch2.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch2.rkt
; default-load-handler: cannot open module file
Obviously I could just change the current-directory to this module's directory if I know where it is. But if I don't know this module's path, is there any way to get it? Or, more directly, is it possible to dynamic-require a module relative to the requiring's module path?
The define-runtime-path form defines a path that will be available at runtime and is independent of the current-directory. Use it to define the path to the module you want to require dynamically, for example:
#lang racket
(require racket/runtime-path)
(define-runtime-path eat "eat.rkt")
(dynamic-require eat 'bite)
The easiest way to dynamic-require a module relative to the current module path (which is to say the path where the module is saved), is to get that module path and append it your relative module.
You can do this with #%variable-reference and variable-reference->module-path-index. (You may also want to use variable-reference->resolved-module-path for other situations, but we will not do it here.) Composing these two functions gives us a module-path-index? to the module being defined. (Or in general, the module that the #%variable-reference came from.)
So, we can a variable like:
(define here (variable-reference->module-path-index (#%variable-reference)))
Now all that is left is to compose this here path with the relative path to the module we want to require. We are looking for the module path analogy of build-path, if you will.
It turns out that the function we are looking for is: module-path-index-join, which takes a base path and a relative path and appends them together. The result will look something like:
(module-path-index-join "eat.rkt" here)
(Yes, it is backwards of what you would expect from build-path, but the base path comes second for this function.)
The resulting module, lunch3.rkt looks like:
#lang racket
(define here (variable-reference->module-path-index (#%variable-reference)))
(define bite (dynamic-require (module-path-index-join "eat.rkt" here) 'bite))
And now lunch3.rkt will require eat.rkt relative to where its defined, not based on the current-directory:
$ racket lunch3.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch3.rkt
"Nom Nom"
Thank you to Matthew Flatt for helping with this answer.

Invoke `racket` in a Racket script

General question:
Can I invoke the current racket executable from within a running Racket script?
Basically, I'd like a replacement for (system "racket ...") in the case that (find-executable-path "racket") does not return a path to the Racket executable I'm currently using.
Context:
What I really want is to try compiling a few expressions and assert that they raise compilation errors. This is for unit testing.
I don't believe you need to step outside of the executable here. Try this:
#lang racket
(require syntax/modread)
;; define a namespace anchor to attach a namespace to:
(define-namespace-anchor anchor)
;; define a namespace for expansion:
(define target-namespace (namespace-anchor->namespace anchor))
(define program-to-compile
"#lang racket
(+ 3 4)")
;; go ahead and expand
(with-module-reading-parameterization
(λ()
(parameterize ([current-namespace target-namespace])
(expand
(read-syntax
"bogus-filename"
(open-input-string program-to-compile))))))
I think I'm correct when I say that Racket is singularly clean in its ability to provide the compiler to running programs in a disciplined way.
If your goal is just to compile some racket expressions, you can do that just with either compile or compile-syntax. An example file would be:
#lang racket
(require rackunit)
(define tests
(list #'(+ 1 "3")
#'(void void)
#'(string-append 4)))
(for/list ([t (in-list test)])
(check-exn exn:fail?
(lambda () (compile t))))
Where exn:fail? is whatever exception you are looking for.
Furthermore, if you have some common syntax context you want to run your test in, you can use #` #,. So your code would end up something like this:
#lang racket
(require rackunit)
(define tests
(list #'(+ 1 "3")
#'(void void)
#'(string-append 4)))
(for/list ([t (in-list test)])
(check-exn exn:fail?
(lambda () (compile #`(module anonymous racket
#,t)))))
Finally, if your code is stored on your computer, you can use John's solution, while using file->string to convert the file into a string.
For small tests, you can also use convert-compile-time-error from the syntax/macro-testing library. It turns an expression that causes a compile-time error into an expression that raises a run-time error when evaluated. The expression uses the environment where it occurs in the module, including local bindings; you don't have to fiddle with namespaces and eval.
(check-exn #rx"bad syntax"
(lambda () (convert-compile-time-error (lambda))))
There's also convert-syntax-error (on the same page).

Running other modules' submodules

I'd like to selectively run a Racket module's submodules from another module. Please help me fill in the blanks!
File 1
#lang racket/base
;; <big file, lots of code>
(module+ small-tests
;; basic correctness checks
(displayln "Small tests pass!")
)
(module+ big-tests
;; heavy duty stress tests
(displayln "Big tests pass!")
)
File 2
#lang racket/base
(module+ main
;; Trigger either the small-tests or the big-tests,
;; depending on what's written here.
(require '???)
)
It would also be great if running the big tests would automatically run the small tests, too.
The submod form is used to require a module's submodule.
As an example:
#lang racket
(module A racket
(module+ main
(displayln "Hello World")))
(module B racket
(require (submod ".." A main)))
(require 'B)
Thanks to Leif and Alexis's hints, the way to get File 2 to run the small-tests submodule is to replace the '??? with:
(submod "file1.rkt" small-tests)
Also, editing the big-tests submodule to include the line:
(require (submod ".." small-tests))
will cause both small & big tests to run when File 2 executes (require (submod "file1.rkt" big-tests)).

Common Lisp equivalent to Haskell's main function?

Haskell's main function does just what I want: evaluate when the file is loaded by itself (e.g. ./myfile.hs or runhaskell myfile.hs) and in no other case. main will not be called when the file is imported by another file. newLISP also has this functionality.
Is there equivalent code for Common Lisp?
I read the source code for CLISP. Here's what happens when the user enters clisp myfile.lisp or ./myfile.lisp:
CLISP saves myfile.lisp as p->argv_execute_file.
CLISP creates the expression (LOAD "p->argv_execute_file") and pushes it onto the Lisp stack.
CLISP saves any additional command-line arguments in a list.
CLISP stores the arguments in the Lisp variable *args*.
CLISP never makes a Lisp variable referring to p->argv_execute_file, so there is no way to discern whether myfile.lisp was loaded directly, by the user in the REPL, or by another Lisp file. If only (car *args*) were myfile.lisp, my task would be easy.
Note: Shebangs give CLISP trouble if the file is loaded from the REPL, so I put this code in ~/.clisprc.lisp:
(set-dispatch-macro-character #\# #\!
(lambda (stream character n)
(declare (ignore character n))
(read-line stream nil nil t)
nil))
I found a solution. It's a bit of shell trickery, but it works. I'll soon modify this to work on CL implementations other than CLISP.
#!/bin/sh
#|
exec clisp -q -q $0 $0 ${1+"$#"}
exit
|#
;;; Usage: ./scriptedmain.lisp
(defun main (args)
(format t "Hello World!~%")
(quit))
;;; With help from Francois-Rene Rideau
;;; http://tinyurl.com/cli-args
(let ((args
#+clisp ext:*args*
#+sbcl sb-ext:*posix-argv*
#+clozure (ccl::command-line-arguments)
#+gcl si:*command-args*
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
#+cmu extensions:*command-line-strings*
#+allegro (sys:command-line-arguments)
#+lispworks sys:*line-arguments-list*
))
(if (member (pathname-name *load-truename*)
args
:test #'(lambda (x y) (search x y :test #'equalp)))
(main args)))
(eval-when (situation*) ...)
Update sorry for the confusing answer.
I could be wrong, but it seems to be impossible to do what you want exactly. I would make a shell script and call clisp -i myfile.lisp -x (main).
Is there any reason to not make it executable (described here)?
P.S. Common Lisp is a language and clisp is one of the implementations.