Unicode Clojure unit test output - unit-testing

When unit testing some code that translates ascii sequences into unicode characters I have found a problem with the output of Clojure tests.
I have tested that my terminal can output unicode characters (by cat-ing the test files) and that works fine, so the problem seems related to leiningen, Clojure or clojure.test somehow.
Here's an example test (using the Greek section of unicode - I will also be using Greek extended but I assume the same problems will apply):
(deftest bc-string-w-comma
(is (= "αβγ, ΑΒΓ" (parse "abg,*a*b*g"))))
It is meant to fail due to the missing space in the input. The output from lein test is the following:
Testing parse_perseus.test.betacode
FAIL in (bc-string-w-comma) (betacode.clj:15)
expected: (= "???, ???" (parse "abg,*a*b*g"))
actual: (not (= "???, ???" "???,???"))
Testing parse_perseus.test.core
Testing parse_perseus.test.pluralise
Ran 10 tests containing 59 assertions.
1 failures, 0 errors.
What am I doing wrong here? Is this a terminal emulation problem or something clojure-related? I have the same problem running code in the REPL with Slime/swank/emacs. The REPL in emacs only outputs question marks for unicode output (although emacs is quite capable of understanding unicode).
I have tried running this in Terminal and iTerm (OS X) with the same results.

It turns out that you can pass options to java to force the output encoding of *out* so that unicode works, like this:
java -Dfile.encoding=utf-8 -cp lib/clojure-1.2.0.jar:lib/clojure-contrib-1.2.0.jar clojure.main -i src/whatever.clj
As I'm using Leiningen, I added this property to my project.clj file:
(defproject project_name "1.0.0-SNAPSHOT"
:description "A Clojure Project"
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]]
:dev-dependencies [[swank-clojure "1.2.0"]]
:jvm-opts ["-Dfile.encoding=utf-8"])

Clojure itself seems in the clear (this is Ubuntu 10.10, gnome-terminal, OpenJDK):
john#woc-desktop$ java -cp /home/john/.m2/repository/org/clojure/clojure/1.2.0/clojure-1.2.0.jar:/home/john/.m2/repository/org/clojure/clojure-contrib/1.2.0/clojure-contrib-1.2.0.jar clojure.main
Clojure 1.2.0
user=> (use 'clojure.test)
nil
user=> (defn parse [s] "αβγ,ΑΒΓ")
#'user/parse
user=> (deftest greek (is (= "αβγ, ΑΒΓ" (parse ""))))
#'user/greek
user=> (run-tests)
Testing user
FAIL in (greek) (NO_SOURCE_FILE:3)
expected: (= "αβγ, ΑΒΓ" (parse ""))
actual: (not (= "αβγ, ΑΒΓ" "αβγ,ΑΒΓ"))
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:type :summary, :test 1, :pass 0, :fail 1, :error 0}
user=>
But it does break emacs/swank/clojure-maven-plugin/maven
at REPL in emacs:
> (is "αβγ""αβγ")
slime-net-send: Coding system iso-latin-1-unix not suitable for "000052(:emacs-rex (swank:listener-eval \"(is \\\"αβγ\\\"\\\"αβγ\\\")
\") \"user\" :repl-thread 33)
"
If I use maven, the simple pom file below, and mvn clojure:repl then it's ok:
[INFO] [clojure:repl {execution: default-cli}]
Clojure 1.2.0
user=> (use 'clojure.test) (is "αβγ""αβγ")
nil
"αβγ"
user=> (defn parse [s] "αβγ,ΑΒΓ")
#'user/parse
user=> (deftest greek (is (= "αβγ, ΑΒΓ" (parse ""))))
#'user/greek
user=> (run-tests)
Testing user
FAIL in (greek) (NO_SOURCE_FILE:3)
expected: (= "αβγ, ΑΒΓ" (parse ""))
actual: (not (= "αβγ, ΑΒΓ" "αβγ,ΑΒΓ"))
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:type :summary, :test 1, :pass 0, :fail 1, :error 0}
user=>
but if I add the jline library using this snippet:
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<version>0.9.94</version>
</dependency>
then I get:
[INFO] [clojure:repl {execution: default-cli}]
[INFO] Enabling JLine support
Clojure 1.2.0
user=> (use 'clojure.test) (is "αβγ""αβγ")
nil
"���"
user=> (defn parse [s] "αβγ,ΑΒΓ")
#'user/parse
user=> (deftest greek (is (= "αβγ, ΑΒΓ" (parse ""))))
#'user/greek
user=> (run-tests)
Testing user
FAIL in (greek) (NO_SOURCE_FILE:3)
expected: (= "���, ���" (parse ""))
actual: (not (= "���, ���" "���,���"))
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:type :summary, :test 1, :pass 0, :fail 1, :error 0}
user=>
Which looks awfully like your error. So it may be that the problem is in jLine, or some other piece which Leiningen and maven have in common which is associated with jLine.
Or of course, there may be two independent unicode-related failures.
Here is my maven pom.xml file in case anyone is trying to debug this.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.aspden</groupId>
<artifactId>maven-clojure-simple</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven-clojure-simple</name>
<description>maven, clojure: simple project</description>
<repositories>
<repository>
<id>clojure</id>
<url>http://build.clojure.org/releases</url>
</repository>
<repository>
<id>central</id>
<url>http://repo1.maven.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<version>1.3.5-SNAPSHOT</version>
</plugin>
</plugins>
</build>
</project>
I appreciate this is not an answer, but i thought it might be helpful.

Related

Adding unit-tests to Clojure CLI tools and deps.edn

I'm used to using Clojure with Leiningen.
But I have a new project that I booted into existence with LightMod. And it uses CLI tools and deps.
This works but I now want to add some unit testing to it.
So here's (a slightly simplified version of) my deps.edn file :
{:paths ["src" "resources"],
:aliases
{
:dev
{:extra-deps
{orchestra #:mvn{:version "2018.12.06-2"},
expound #:mvn{:version "0.7.2"},
nightlight #:mvn{:version "RELEASE"},
com.bhauman/figwheel-main #:mvn{:version "0.2.0"}},
:main-opts ["dev.clj"]},
:test
{:extra-paths ["test"]
:extra-deps {com.cognitect/test-runner {:git/url "https://github.com/cognitect-labs/test-runner.git" :sha "209b64504cb3bd3b99ecfec7937b358a879f55c1"}}
:main-opts ["-m" "cognitect.test-runner"]}
:prod
{:extra-deps
{leiningen #:mvn{:version "2.9.0"},
org.clojure/clojurescript #:mvn{:version "1.10.439"}},
:main-opts ["prod.clj"]},
:app
{:extra-deps
{
markdown-clj {:mvn/version "1.10.1"}
instaparse {
:mvn/version"1.4.10"
}
... MORE ...
}}}}
Now this file has worked OK with both :dev and :prod compilation.
But now I've just added the :test alias.
And put my tests into test/myns/core_tests.clj
However, when I try to run tests, I get this
Could not locate markdown/core__init.class, markdown/core.clj or markdown/core.cljc on classpath
So my interpretation. While the :dev and the :prod branches are successfully pulling in all the dependencies in the :app branch. The :test branch is not pulling in markdown. (And probably none of the other dependencies declared in :app
So why should this be? And how can I explicitly tell my :test clause that it needs to use all the same dependencies that are used in :dev and :prod?
You can use the Kaocha test runner for this. A working template project can be found here. It even includes the ability to compile Java source files as well as Clojure.
To get started, set up deps.edn like so
{:paths ["src/clj"]
:deps {
cambium/cambium.codec-simple {:mvn/version "0.9.3"}
cambium/cambium.core {:mvn/version "0.9.3"}
cambium/cambium.logback.core {:mvn/version "0.4.3"}
org.clojure/clojure {:mvn/version "1.10.1"}
prismatic/schema {:mvn/version "1.1.12"}
tupelo {:mvn/version "0.9.200"}
}
:aliases {:test {
:extra-deps {lambdaisland/kaocha {:mvn/version "1.0-612"}}
}}
}
and add another file tests.edn to configure Kaocha:
; ***** Be sure to use tagged reader literal '#kaocha/v1' *****
#kaocha/v1 {:tests
[{:id :unit
:test-paths ["test/clj"]
:ns-patterns ["^tst..*"]
}]
; :reporter kaocha.report.progress/report
; :plugins [:kaocha.plugin/profiling :kaocha.plugin/notifier]
}
then create a short shell script to launch Koacha in the subdir ./bin. Name it bin/kaocha with contents:
#!/bin/bash
clojure -A:test -m kaocha.runner "$#"
Now you are ready to go! A test file:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test) )
(dotest
(is= 5 (+ 2 3))
(isnt= 9 (+ 2 3))
(throws? (/ 1 0)) ; verify that an illegal operation throws an exception
(is= 3 (add2 1 2))
(throws? (add2 1 "two"))) ; Prismatic Schema will throw since "two" is not a number
; NOTE: Clojure Deps/CLI can't handle Java source code at present
and we are off to the races:
~/io.tupelo/clj-template > bin/kaocha
[(.....)]
1 tests, 5 assertions, 0 failures.

How to suppress output to stderr in a clojure program

I want to produce a command line version of a clojure library using clojure/tools.cli and lein bin. This works fine except I am getting output to stderr when I run the script. This particular library has functions that override some basic functions, so naturally there are warnings when the clojure code is compiled. I know this is generally a bad idea but after careful consideration in this case I believe it is the best way to go. How do I stop these messages from appearing every time I run the script?
I added slf4j-nop to the dependencies as recommended in the monger documentation to suppress unwanted messages from monger, and this works, but has no effect on the warnings from the clojure compiler.
I have also tried using slf4j-log as detailed here: suppress output from `clojure.tools.logging` but without success.
Here is some of the code:
project.clj
(defproject image-search "0.1.0-SNAPSHOT"
:description "Search for images containing specific metadata"
:url "http://github.com/soulflyer/image-search"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/tools.cli "0.3.3"]
[org.slf4j/slf4j-nop "1.7.21"]
[image-lib "0.1.1-SNAPSHOT"]]
:main image-search.command-line
:bin {:name "image-search"
:bin-path "~/bin"})
and command_line.clj:
(ns image-search.command-line
(:require [image-search.core :refer [open all-images ifeq ifin ]]
[clojure.tools.cli :refer :all])
(:gen-class))
(def cli-options
[["-c" "--count" "Counts the results"]
["-D" "--database DATABASE" "specifies database to use"
:default "photos"]
["-I" "--image-collection IMAGE-COLLECTION" "specifies the image collection"
:default "images"]
["-K" "--keyword-collection KEYWORD-COLLECTION" "specifies the keyword collection"
:default "keywords"]
["-h" "--help"]
["-i" "--iso ISO" "Search on ISO value"]
["-s" "--shutter SHUTTER-SPEED" "search on SHUTTER-SPEED"]
["-f" "--aperture APERTURE" "search on APERTURE"]
["-y" "--year YEAR" "search on YEAR"]
["-m" "--month MONTH" "search on MONTH"]
["-M" "--model MODEL" "search by camera model"]
["-p" "--project PROJECT" "search photos in PROJECT"]
["-k" "--keyword KEYWORD" "search for KEYWORD"]])
(defn print-count [pics]
(println (count pics)))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(let [{:keys [options arguments errors summary]} (parse-opts args cli-options)
output-function (if (:count options) print-count open)]
(-> all-images
(ifeq :ISO-Speed-Ratings (:iso options))
(ifeq :Year (:year options))
(ifeq :Month (:month options))
(ifin :Project (:project options))
(ifeq :F-Number (:aperture options))
(ifin :Keywords (:keyword options))
(ifin :Model (:model options))
(output-function))))
I run lein bin, then run the executable it produces and get something like this:
(master) image-search: image-search -i 640 -c
WARNING: or already refers to: #'clojure.core/or in namespace: image-search.core, being replaced by: #'image-search.core/or
WARNING: and already refers to: #'clojure.core/and in namespace: image-search.core, being replaced by: #'image-search.core/and
Note that the 2 warning are referring to functions I don't use in the command line version. I am not even including them. They are not in the list given to refer when I :require the library. They are, however, important to the library when I'm using it from the repl or cider. So I really don't want to rename them.
You can remove the warning by adding following to your (ns image-search.core) declaration:
(ns image-search.core
(:refer-clojure :exclude [or and])
With that change you can still use the original Clojure's or and and by fully qualifying them:
`clojure.core/or`
`clojure.core/and`
Without that change the compiler warns you that you are overriding your namespace binding of or and and as they are by default bound to functions from clojure.core/or and clojure/and vars.

I can't run a basic clojurescript.test sample

I'm trying to run a basic test with
https://github.com/cemerick/clojurescript.test
I've created a simple project such as:
(defproject sampleproj "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2014"]
]
:plugins [[lein-cljsbuild "1.0.0"]
[com.cemerick/clojurescript.test "0.2.2"]]
:cljsbuild {:builds [{:source-paths ["src-js" "test-js"]
:compiler {:output-to "target/cljs/testable.js"
:optimizations :whitespace
:pretty-print true}}]
:test-commands {"unit-tests" ["phantomjs" :runner
"this.literal_js_was_evaluated=true"
"target/cljs/testable.js"]}}
)
Both folders src-js and test-js exist since I intend to put all my clojurescript files there.
In my test-js/sampleproj folder I copied the sample test in the documentation:
(ns sampleproj.sampletest
(:require-macros [cemerick.cljs.test
:refer (is deftest with-test run-tests testing test-var)])
(:require [cemerick.cljs.test :as t]))
(deftest somewhat-less-wat
(is (= "{}[]" (+ {} []))))
(deftest javascript-allows-div0
(is (= js/Infinity (/ 1 0) (/ (int 1) (int 0)))))
(with-test
(defn pennies->dollar-string
[pennies]
{:pre [(integer? pennies)]}
(str "$" (int (/ pennies 100)) "." (mod pennies 100)))
(testing "assertions are nice"
(is (thrown-with-msg? js/Error #"integer?" (pennies->dollar-string 564.2)))))
Now if I try to run the tests
-> % lein cljsbuild test
Compiling ClojureScript.
Running ClojureScript test: unit-tests
ReferenceError: Can't find variable: cemerick
phantomjs://webpage.evaluate():2
phantomjs://webpage.evaluate():5
phantomjs://webpage.evaluate():5
ReferenceError: Can't find variable: cemerick
phantomjs://webpage.evaluate():2
phantomjs://webpage.evaluate():5
phantomjs://webpage.evaluate():5
Subprocess failed
I'm fairly new to clojurescript so probably I'm missing something.
Update:
My environment
-> % lein -v
Leiningen 2.3.4 on Java 1.7.0_06 Java HotSpot(TM) 64-Bit Server VM
-> % phantomjs -v
1.9.2
-> % java -version
java version "1.7.0_06"
Java(TM) SE Runtime Environment (build 1.7.0_06-b24)
Java HotSpot(TM) 64-Bit Server VM (build 23.2-b09, mixed mode)
Are macros located right into clj sources ?
After that th compiler shoud compiler you cemeric macros to javascript.
You propably have dependencies right in project.clj
This hasn't been answered, so I will. You need to specify your dependency for clojurescript.test : [com.cemerick/clojurescript.test "0.3.1"]

Running a JAR file created by Leiningen

I have the following code in the file project.clj:
(defproject pinger "0.0.1-SNAPSHOT"
:description "A website availability tester"
:dependencies [[org.clojure/clojure "1.3.0"]]
:main pinger.core)
(ns pinger.core
(:import (java.net URL HttpURLConnection))
(:gen-class))
(defn response-code [address]
(let [conn ^HttpURLConnection (.openConnection (URL. address))
code (.getResponseCode conn)]
(when (< code 400)
(-> conn .getInputStream .close))
code))
(defn available? [address]
(= 200 (response-code address)))
(defn -main []
(let [addresses '("http://google.com"
"http://amazon.com"
"http://google.com/badurl")]
(while true
(doseq [address addresses]
(println (available? address)))
(Thread/sleep (* 1000 60)))))
I create an uberjar:
C:\Documents and Settings\vreinpa\My Documents\Books\ProgrammingClojure\code\src
\pinger>lein uberjar
Cleaning up.
Copying 1 file to C:\Documents and Settings\vreinpa\My Documents\Books\Programmi
ngClojure\code\src\pinger\lib
Warning: *classpath* not declared dynamic and thus is not dynamically rebindable
, but its name suggests otherwise. Please either indicate ^:dynamic *classpath*
or change the name.
Copying 1 file to C:\Documents and Settings\vreinpa\My Documents\Books\Programmi
ngClojure\code\src\pinger\lib
Created C:\Documents and Settings\vreinpa\My Documents\Books\ProgrammingClojure\
code\src\pinger/pinger-0.0.1-SNAPSHOT.jar
Including pinger-0.0.1-SNAPSHOT.jar
Including clojure-1.3.0.jar
Created C:\Documents and Settings\vreinpa\My Documents\Books\ProgrammingClojure\
code\src\pinger/pinger-0.0.1-SNAPSHOT-standalone.jar
I then try to run that uberjar and get the following error:
C:\Documents and Settings\vreinpa\My Documents\Books\ProgrammingClojure\code\src
\pinger>java -jar pinger-0.0.1-SNAPSHOT-standalone.jar
Exception in thread "main" java.lang.NoClassDefFoundError: pinger/core
Caused by: java.lang.ClassNotFoundException: pinger.core
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: pinger.core. Program will exit.
What am I doing wrong here?
As I said in response to your other question, the project.clj file is not the place to put source code - project.clj is loaded by leiningen to set up your project configuration and putting arbitrary code there is not guaranteed to work at all, and will certainly mess up the loading of namespaces you defined in there. follow the conventions for source libs and put the files under the src directory in your project tree.
$ lein new pinger
$ cd pinger
$ lein deps
pinger/project.clj
(defproject pinger "0.0.1-SNAPSHOT"
:description "A website availability tester"
:dependencies [[org.clojure/clojure "1.3.0"]]
:main pinger.core)
pinger/src/pinger/core.clj
(ns pinger.core
(:import (java.net URL HttpURLConnection))
(:gen-class))
(defn response-code [address]
(let [conn ^HttpURLConnection (.openConnection (URL. address))
code (.getResponseCode conn)]
(when (< code 400)
(-> conn .getInputStream .close))
code))
(defn available? [address]
(= 200 (response-code address)))
(defn -main []
(let
[addresses
'("http://google.com"
"http://amazon.com"
"http://google.com/badurl")]
(while true
(doseq [address addresses]
(println (available? address)))
(Thread/sleep (* 1000 60)))))
$ cd pinger
$ lein uberjar
absolute path
$ java -jar /vagrant/MyClojure/pinger/target/pinger-0.0.1-SNAPSHOT-standalone.jar
or
relative path from project.clj
$ java -jar ./target/pinger-0.0.1-SNAPSHOT-standalone.jar

Using Clojure to unit test Java

One of the ways to get an organization to accept an alternate JVM language is to first use it for unit testing Java code -- "Boss, I am just going to write some unit tests in XXX. It'll never go out into production."
Are there any tutorials for doing this in Clojure?
I have just started using Scala to do this to test a Java REST server. Writing the tests in Scala allows me to embed expected XML output, mock the database calls with literal List objects, etc., not to mention that traits make it very easy to abstract out common code for the tests.
Basically what you need is clojure.test (or one of the many other clojure test libs) and standard Clojure Java interop.
Example:
(ns example.test-java-util
(:use
[clojure.test])
(:import [java.util HashSet]))
(defn new-empty-set []
(HashSet.))
(deftest test-empty-set
(is (= 0 (.size (new-empty-set))))
(is (= true (.isEmpty (new-empty-set))))
(is (= (new-empty-set) (new-empty-set))))
(deftest test-add-remove
(is (= (new-empty-set)
(doto (new-empty-set)
(.add "xyz")
(.remove "xyz")))))
And you would then run them in a variety of ways. Build tools like Maven using the maven clojure plugin run them automatically as part of "mvn test". In a repl, you can do something like:
example.test-java-util> (run-tests 'example.test-java-util)
Testing example.test-java-util
Ran 1 tests containing 4 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 4, :fail 0, :error 0}
Here is an example using Leiningen, test.check and assuming a standard Maven layout:
pom.xml
project.clj
src
main
java
quicktest
Discontinuities.java
test
clojure
quicktest
test_discontinuities.clj
The Java function to test:
package quicktest;
public class Discontinuities {
public static double f5(double x) {
return x / (x-5);
}
}
The Clojure test case:
(ns quicktest.test-discontinuities
(:import [quicktest Discontinuities])
(:require [clojure.test :refer :all]
[clojure.test.check :as tc]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as prop]
[clojure.test.check.clojure-test :as ct :refer (defspec)]))
(deftest test-single-case
(is (= 2.0 (Discontinuities/f5 10))))
(defspec test-discontinuities 1e4
(prop/for-all [x gen/nat ]
(let [y (Discontinuities/f5 x)]
(is (<= y x)))))
The project:
(defproject quicktest/discontinuities "0.1"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/test.check "0.9.0"]]
:java-source-paths ["src/main/java"]
:test-paths ["src/test/clojure"])
The pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>quicktest</groupId>
<artifactId>discontinuities</artifactId>
<version>0.1</version>
</project>
Run with:
mvn compile
lein deps
lein test
Results
The flaw in the function is quickly found:
FAIL in (test-discontinuities) (test_discontinuities.clj:13)
expected: (<= y x)
actual: (not (<= Infinity 5))
{:test-var "test-discontinuities",
:result false,
:seed 1431128331945,
:failing-size 23,
:num-tests 24,
:fail [5],
:shrunk {:total-nodes-visited 3, :depth 0, :result false, :smallest [5]}}