I'm trying to set up a server to run extensive random tests against a Racket program, and want to have output from these tests sent to logs in files. How can I log output from tests to a file?
Tests from rackunit return #<void>, not a string, so trying to use (call-with-output-file ... with the tests only adds #<void> to the output file.
(call-with-output-file "testing.txt"
(λ (out)
(display <TESTS> out))
#:exists 'append)
The output file should log the test results or errors if there are any. Any help is appreciated.
Instead of running checks by themselves, which print to stderr and return #<void>, put the checks in a test suite, so that you can use run-tests from rackunit/text-ui.
#lang racket
(require rackunit rackunit/text-ui)
(define-test-suite testing
<TESTS>)
(.... something something (run-tests testing) ....)
However, the run-tests function seems to use current-error-port, not current-output-port, to print test failures, so within your call-with-output-file, you need to set the current-error-port to out.
(call-with-output-file "testing.txt"
(λ (out)
(parameterize ([current-error-port out])
(run-tests testing)))
#:exists 'append)
Related
I'm trying to learn Common Lisp, and found a simple webserver sample:
#!/usr/local/bin/sbcl --script
;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(when (probe-file quicklisp-init)
(load quicklisp-init)))
(ql:quickload "cl-who")
(ql:quickload "hunchentoot")
(ql:quickload "parenscript")
(defpackage :vote
(:use :cl :cl-who :hunchentoot :parenscript))
(in-package :vote)
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 8080))
(hunchentoot:define-easy-handler (say-yo :uri "/yo") (name)
(setf (hunchentoot:content-type*) "text/plain")
(format nil "Hey~#[ ~A~]!" name))
I'm running it with --script so I can iterate over the code and keep testing it.
The problem is - the script finishes right after launching the server, so I cannot test it.
How could I make the program keep running until I CTRL+D/CTRL+C it?
I could use something like loop and sleep, but it would be too cumbersome - ie, an active wait.
If you're willing to use Ctrl-D, you can use --load instead of --script to load your file. After the file is loaded, you get dropped into a REPL, from which you can use Ctrl-D to quit.
While that may be workable, it might also make sense to consider a timer with a default parameter that can be overridden on the command line, so that the system shuts down after some expiration time. Otherwise, you could inadvertently leave a web server running.
I have tried a few methods, one of them being:
(define (program) (find-system-path 'pref-file))
I have read from the documentation (after attempting the above code) and have noticed it is not what i'd need to use, obviously :) Any ideas?
Would also like to save this information to a variables. VBS example:
script = WScript.ScriptFullName
#lang racket
(display "Program name: ")
(displayln (find-system-path 'run-file))
Output (if saved as "test.rkt" and run with the command racket test.rkt):
Program name: test.rkt
From the racket console REPL, (find-system-path 'run-file) will return #<path:racket>. I didn't try it in DrRacket.
It's a very easy scheme function
(define member?
(lambda (a lat)
(cond
((null? lat) #f)
(else (or (eq? (car lat) a)
(member? a (cdr lat))
))
)
)
)
However, when I pressed ,d or ,F in vim to run this function, there is an error
/home/oo/tmp/t.scm:64 read-error: no dispatch function defined for
#\F
Line: 4, Column: 21, File-Position: 64
Stream: #<SB-SYS:FD-STREAM for "file /home/oo/tmp/t.scm" {AC84DA9}>
Chris already pointed out that you tried to use Scheme code with a Common Lisp swank server.
You need to run a Scheme swank server (e.g. swank-mit-scheme.scm, also included in Slimv).
Normally Slimv should autodetect MIT scheme on Linux without any tweaking in the .vimrc. For the autodetection to work properly you need MIT Scheme installed and the scheme command be available.
I suggest that you remove any Slimv related settings from your .vimrc. Then load the .scm in Vim and type this command:
:echo SlimvSwankCommand()
If Scheme was autodetected then this should print the command that runs the Scheme swank server (search for swank-mit-scheme.scm in the output). If the autodetection was unsuccessful then either you don't have the scheme command or Slimv did not find swank-mit-scheme.scm. In this case you need to tell Slimv the command to run the Scheme swank server. You can do in by adding a similar command to your .vimrc:
let g:slimv_swank_cmd = '! xterm -e scheme --load /your-path-to/slime/contrib/swank-mit-scheme.scm &'
But do this only if autodetection fails. If you need some more assistance, please feel free to contact me, I'm the author of Slimv.
I'm trying to feed flymake output from Haxe compiler, but I don't know how to tell it where the make file lives (ideally, I'd use nxml file instead). So far I have this in the Makefile:
BIN = ./bin
MAIN = com.wunderwafer.Main
SWF = wunderwafer.swf
SWFSETTINGS = -debug -swf-version 10 -swf-header 800:600:31
HFLAGS = -main $(MAIN) $(SWFSETTINGS) -cp ./src -swf $(BIN)/$(SWF)
HC = haxe
default: compile
compile: $(HC) $(HFLAGS)
clean:
$(RM) -r $(BIN)/*
.PHONY: check-syntax
check-syntax:
$(HC) $(HFLAGS)
If I run it later like so:
$ make -k check-syntax
It produces the expected output. However flymake isn't able to find the Makefile (or so it seems) because the files I'm trying to check are deeper inside the src directory.
What is the way to configure flymake so it knows where the makefile is? (or, even better, just execute a shell command, because the common way to compile Haxe code is by using *.nxml settings file.
EDIT:
It looks like I'm getting closer, lots of thanks, but flymake is doing something strange, and I can't understand what exactly it does, so, here's the log:
received 65 byte(s) of output from process 967
file /home/wvxvw/projects/wafer/src/com/wunderwafer/map/Battlefield.hx, init=haxe-flymake-init
parsed 'Error : Invalid class name /home/wvxvw/projects/wafer/build.nxml', no line-err-info
file /home/wvxvw/projects/wafer/src/com/wunderwafer/map/Battlefield.hx, init=haxe-flymake-init
process 967 exited with code 1
cleaning up using haxe-flymake-cleanup
deleted file /tmp/flymake-Battlefield-855Cad.hx
Battlefield.hx: 0 error(s), 0 warning(s) in 0.15 second(s)
switched OFF Flymake mode for buffer Battlefield.hx due to fatal status CFGERR, warning Configuration error has occurred while running (haxe /home/wvxvw/projects/wafer/build.nxml)
The command I'm trying to make it run looks like this:
(defun haxe-flymake-get-cmdline (source base-dir)
"Gets the cmd line for running a flymake session in a Haxe buffer.
This gets called by flymake itself. The output is a list of two elements:
the command to run, and a list of arguments. The resulting command is like:
$ haxe ${project-root}/build.nxml
"
(message "base-dir %s" (file-name-as-directory base-dir))
(list *haxe-compiler*
(list
(concat (file-name-as-directory base-dir)
*build-nxml*))))
The message printed looks like this:
base-dir /home/wvxvw/projects/wafer/
So, as far as I could understand, the resulting command should be:
haxe /home/wvxvw/projects/wafer/build.nxml
But it looks like flymake either adds something in front of the argument or afterwards, which makes Haxe compiler generate the error "Error : Invalid class name" - this error would be given if there was one extra argument, which the compiler would have understood as an extra class to compile. But the log doesn't show what is being sent...
EDIT 2:
I've added:
#!/usr/bin/env bash
echo "$#" > /home/wvxvw/projects/wafer/log
And made flymake invoke this script instead of the compiler, and it passes only one argument, just as I would expect it... sigh
It's a good question. I don't know a simple way of adding in a new "flavor" of make tool into flymake. I know of a way, it's just not simple. This is what I did for php codesniffer - it will be similar for any arbitrary make tool.
First, define an install fn.
(defun fly/phpcs-install ()
"install flymake stuff for PHP CodeSniffer files."
(add-to-list
'flymake-err-line-patterns
(list fly/phpcs-error-pattern 1 2 3 4))
(let* ((key "\\.php\\'")
(phpentry (assoc key flymake-allowed-file-name-masks)))
(if phpentry
(setcdr phpentry '(fly/phpcs-init fly/phpcs-cleanup))
(add-to-list
'flymake-allowed-file-name-masks
(list key 'fly/phpcs-init 'fly/phpcs-cleanup)))))
This installs a new entry into the flymake alist, keyed on .php as a file extension. The entry in flymake's list basically relates the file extension to a pair of functions, one for init and one for cleanup.
The init fn simply returns the command to run to check syntax. This can be a shell command, with the appropriate arguments. For codesniffer this fn looks like this:
(defun fly/phpcs-init ()
"initialize flymake for PHP using the PHP CodeSniffer tool."
(let ((create-temp-f 'fly/phpcs-create-temp-intemp)
(use-relative-base-dir t)
(use-relative-source t)
(get-cmdline-f 'fly/phpcs-get-cmdline)
args
temp-source-file-name)
(setq temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)
args (flymake-get-syntax-check-program-args
temp-source-file-name "."
use-relative-base-dir use-relative-source
get-cmdline-f))
args))
Yikes! Down the rabbit hole we go. The get-cmdline fn looks like this:
(defun fly/phpcs-get-cmdline (source base-dir)
"Gets the cmd line for running a flymake session in a PHP buffer.
This gets called by flymake itself. The output is a list of two elements:
the command to run, and a list of arguments. The resulting command is like:
php.exe -d auto_append_file="" -d auto_prepend_file="" phpcs\scripts\phpcs --report=emacs file.php
"
(list fly/phpcs-phpexe
(list
"-d" "auto_append_file=''"
"-d" "auto_prepend_file=''"
(concat (file-name-as-directory fly/phpcs-phpcs-dir)
"scripts\\phpcs")
(concat "--standard=" fly/phpcs-standard)
"--report=emacs"
"-s" ;; show the fullname of the rule being violated
(expand-file-name source))))
You can see the full elisp at http://www.emacswiki.org/emacs/flyphpcs.el
There's probably a simpler way. I just don't know it.
I'm trying to create a "system" command for clisp that works like this
(setq result (system "pwd"))
;;now result is equal to /my/path/here
I have something like this:
(defun system (cmd)
(ext:run-program :output :stream))
But, I am not sure how to transform a stream into a string. I've reviewed the hyperspec and google more than a few times.
edit: working with Ranier's command and using with-output-to-stream,
(defun system (cmd)
(with-output-to-string (stream)
(ext:run-program cmd :output stream)))
And then trying to run grep, which is in my path...
[11]> (system "grep")
*** - STRING: argument #<OUTPUT STRING-OUTPUT-STREAM> should be a string, a
symbol or a character
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [12]> :r2
Something like this?
Version 2:
(defun copy-stream (in out)
(loop for line = (read-line in nil nil)
while line
do (write-line line out)))
(defun system (cmd)
(with-open-stream (s1 (ext:run-program cmd :output :stream))
(with-output-to-string (out)
(copy-stream s1 out))))
[6]> (system "ls")
"#.emacs#
Applications
..."
Per the CLISP documentation on run-program, the :output argument should be one of
:terminal - writes to the terminal
:stream - creates and returns an input stream from which you can read
a pathname designator - writes to the designated file
nil - ignores the output
If you're looking to collect the output into a string, you'll have to use a read-write copying loop to transfer the data from the returned stream to a string. You already have with-output-to-string in play, per Rainer's suggestion, but instead of providing that output stream to run-program, you'll need to write to it yourself, copying the data from the input stream returned by run-program.
You are asking specifically about clisp. I'll add here that
if you are using Clozure CL then you can also easily run os subprocesses.
Some examples:
;;; Capture the output of the "uname" program in a lisp string-stream
;;; and return the generated string (which will contain a trailing
;;; newline.)
? (with-output-to-string (stream)
(run-program "uname" '("-r") :output stream))
;;; Write a string to *STANDARD-OUTPUT*, the hard way.
? (run-program "cat" () :input (make-string-input-stream "hello") :output t)
;;; Find out that "ls" doesn't expand wildcards.
? (run-program "ls" '("*.lisp") :output t)
;;; Let the shell expand wildcards.
? (run-program "sh" '("-c" "ls *.lisp") :output t)
Do a search for run-program in the CCL docs located here: http://ccl.clozure.com/ccl-documentation.html
There are a couple nice Lisp ways of doing this in this stackoverflow answer: Making a system call that returns the stdout output as a string Once again, Rainer to the rescue. Thanks Ranier.
This is a shorter one
(defun system(cmd)
(ext:shell (string cmd)))
> (system '"cd ..; ls -lrt; pwd")