• Stars
    star
    215
  • Rank 183,925 (Top 4 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created over 10 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A utility library for test.check

test.chuck

Circle CI

test.chuck is a utility library for test.check.




       (this space intentionally left blank)



Obtention

Please note that as of version 0.2.0, test.chuck (mostly) supports ClojureScript, and requires a minimum Clojure version of 1.7.0. Using ClojureScript requires a minimum test.check version of 0.8.0.

Dependency coordinates:

;; deps.edn
{
  com.gfredericks/test.chuck {:mvn/version "0.2.13"}
}
;; leiningen
[com.gfredericks/test.chuck "0.2.14"]

Usage

General Helpers

(require '[com.gfredericks.test.chuck :as chuck])

times

A helper function for being able to scale your test run count with an environment variable. To use with defspec, simply wrap your test-count argument in a call to times:

(defspec foo-bar-test (chuck/times 20)
  ...)

This will normally run the test 20 times, but if you set the TEST_CHECK_FACTOR environment variable to e.g. 3.5, it will run the tests 70 times.

In ClojureScript, TEST_CHECK_FACTOR will be retrieved at compile-time.

Generators

(require '[com.gfredericks.test.chuck.generators :as gen'])

There are a few minor generators and helpers, see the docstrings for details:

  • for (described below)
  • string-from-regex (described below)
  • subsequence (for subsets and similar)
  • cap-size
  • partition
  • map->hash-map
  • sub-map
  • bounded-int
  • double

for

A macro that uses the syntax of clojure.core/for to provide the functionality of gen/bind, gen/fmap, gen/such-that, and gen/tuple:

(gen'/for [len gen/nat
           bools (gen/vector gen/boolean len)]
  [len bools])

(gen/sample *1)
;; => ([0 []]
;;     [0 []]
;;     [2 [false true]]
;;     [3 [true false true]]
;;     [1 [true]]
;;     [5 [true true false false true]]
;;     [2 [false false]]
;;     [1 [true]]
;;     [8 [true false false true false false false false]]
;;     [1 [true]])
(gen'/for [:parallel [n1 gen/nat
                      n2 gen/nat]
           :when ^{:max-tries 20} (coprime? n1 n2)
           :let [product (* n1 n2)]]
  {:n product, :factors [n1 n2]})

(gen/sample *1)
;; => ({:n 1, :factors [1 1]}
;;     {:n 0, :factors [1 0]}
;;     {:n 2, :factors [1 2]}
;;     {:n 0, :factors [0 1]}
;;     {:n 6, :factors [3 2]}
;;     {:n 20, :factors [4 5]}
;;     {:n 0, :factors [1 0]}
;;     {:n 4, :factors [1 4]}
;;     {:n 24, :factors [3 8]}
;;     {:n 14, :factors [2 7]})

string-from-regex

string-from-regex is a suspiciously robust generator that will generate strings matching a regular expression:

user> (gen/sample (gen'/string-from-regex #"([☃-♥]{3}|B(A|OO)M)*"))
(""
 "☍♛☽"
 ""
 "♂♡☱BAM"
 "♥☩♏BAMBAM"
 ""
 "☓☪☤BAMBAMBOOMBOOM☑☔☟"
 ""
 "BOOM☻☘☌☏☜♋BAM♑♒♛BAMBAM"
 "BOOMBAM♅☧♉☎☐♘BOOM☥♜☐")

It does not work with every regular expression, but its goal is to correctly recognize (and report) the usage of unsupported features, and to handle supported features in a comprehensive way.

Shrinking

Generated strings shrink in a natural way:

(def gen-cool-string
  (gen'/string-from-regex
   #"This string has (1 [A-Z]|[2-9]\d* [A-Z]'s)((, (1 [A-Z]|[2-9]\d* [A-Z]'s))*, and (1 [A-Z]|[2-9]\d* [A-Z]'s))?\."))

(def bad-prop
  (prop/for-all [s gen-cool-string]
    (not (re-find #"1 F" s))))

(t.c/quick-check 1000 bad-prop)
=>
{:fail ["This string has 6309694848500700538 H's, 79102649012623413352 F's, 1 F, 59860 U's, 1 T, 1 W, 1 B, and 1 M."],
 :failing-size 26,
 :num-tests 27,
 :result false,
 :seed 1418877588316,
 :shrunk {:depth 8,
          :result false,
          :smallest ["This string has 1 A, 1 F, and 1 A."],
          :total-nodes-visited 27}}
Unsupported regex features

Some of these could be supported with a bit of effort.

  • All flags: (?i), (?s), etc.
  • Lookahead and lookbehind
  • Reluctant and Possesive quantifiers: X??, X*+, etc.
    • I'm not sure what these would mean anyhow
  • Anchors: \b, ^, \A, $...
  • Backreferences
    • This is tricky at least because it introduces the possibility of unmatchable expressions
  • Character class intersections
  • The hex syntax for unicode characters outside the BMP: \x{10001}
  • Named character classes: \p{IsAlphabetic}, \P{ASCII}, ...

Properties

com.gfredericks.test.chuck.properties/for-all is an alternative to clojure.test.check.properties/for-all that uses the for macro to interpret the binding clauses:

(require [com.gfredericks.test.chuck.properties :as prop'])

(prop'/for-all [a gen/pos-int
                :when (even? a)
                :let [b (/ a 2)]
                xs (gen/vector gen/int b)]
  (= (count xs) b))

Alternate clojure.test integration

The com.gfredericks.test.chuck.clojure-test namespace contains a couple macros that let you write property-based tests using the side-effecting (is ...) assertions normally used with clojure.test.

The checking macro is intended to be used with clojure.test/deftest:

(require '[clojure.test :refer [deftest is]]
         '[com.gfredericks.test.chuck.clojure-test :refer [checking]])

(deftest my-test
  (checking "that positive numbers are positive" 100
    [x gen/s-pos-int]
    (is (pos? x))
    (is (> x 0))))

The for-all macro is intended to be used with clojure.test.check.clojure-test/defspec:

(require '[clojure.test.check.clojure-test :refer [defspec]]
         '[com.gfredericks.test.chuck.clojure-test :refer [for-all]])

(defspec positive-number-positivity-spec 100
  (for-all [x gen/s-pos-int]
    (is (pos? x))
    (is (> x 0))))

More details in this blog post.

Contributing

I welcome pull requests for any test.check utility that seems halfway reasonable.

Development

Running tests

For clj, be sure to use leiningen 2.5.2. (so it picks up .cljc files) and do as usual:

$ lein test

For cljs bensu/doo is configured so the tests can be run with:

$ lein doo node node-test

Minimum required node version for lein doo is 0.12. It also works on 4.0.0. nvm might be used to switch node versions

To run with slimer.js, phantom or rhino:

# replace {js-env} with phantom, slimer or rhino
$ lein doo {js-env} test

Acknowledgments

  • @lackita for creating com.gfredericks.test.chuck.clojure-test
  • @weavejester for creating the original regex->string code
  • @miner for various help with the string-from-regex generator
  • @nberger for adapting to cljc format for ClojureScript, and general maintenance help

License

Copyright © 2016 Gary Fredericks

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

More Repositories

1

quinedb

QuineDB is a quine that is also a key-value store.
Shell
580
star
2

vcr-clj

Generic IO playback for clojure
Clojure
109
star
3

debug-repl

A Clojure debug repl as nrepl middleware
Clojure
100
star
4

schpec

A utility library for clojure.spec
Clojure
45
star
5

exact

Portable exact arithmetic for Clojure[script]
Clojure
41
star
6

qubits

Qubits in Clojure
Clojure
40
star
7

seventy-one

71 in Clojure
Clojure
39
star
8

schema-bijections

Bijecting prismatic schemas
Clojure
36
star
9

how-to-ns

A Clojure linter for Stuart Sierra's how-to-ns standard
Clojure
33
star
10

catch-data

Clojure data-based exception handling
Clojure
32
star
11

clj-usage-graph

Haxy usage graphs for Clojure projects
Clojure
25
star
12

currj

Currying in Clojure
Clojure
20
star
13

dot-slash-2

Clojure library for creating (dev) namespaces of proxy vars
Clojure
17
star
14

user.clj

A library for loading clojure user files
Clojure
16
star
15

pg-serializability-bug

Reproduction code for Postgres BUG #13667
Shell
16
star
16

like-format-but-with-named-args

A function like clojure.core/format but with named args.
Clojure
13
star
17

dotfiles

dots and files
Shell
13
star
18

repl-utils

My repl utility things
Clojure
13
star
19

lein-lein

A collection of Leiningen plugins for doing all sorts of useful things
Clojure
13
star
20

the-halting-project

What's the simplest Turing Machine with unknown behavior?
Clojure
13
star
21

cljs-numbers

Hacking up some rich numerics for clojurescript
Clojure
12
star
22

lein-all-my-files-should-end-with-exactly-one-newline-character

A Clojure linter that enforces end-of-file newlines.
Clojure
11
star
23

clomp

A Stomp client library for Clojure.
Clojure
11
star
24

org-editor

Some clojure code for reading and writing org files
Clojure
8
star
25

corncob-cigar

Leiningen utilities.
Clojure
8
star
26

instant-coffee

Easy CoffeeScript without node.js
Clojure
7
star
27

webscale

Casual file-based persistence in Clojure.
Clojure
7
star
28

forty-two

Clojure number-to-words conversion
Clojure
7
star
29

persistent_js

Persistent Data Structures for JavaScript
Ruby
7
star
30

four

Random numbers in Clojure
Clojure
7
star
31

replog

Clojure repl history tracking
Clojure
6
star
32

bitalgs

Some code that visualizes hash functions
Clojure
6
star
33

vbox

A web-app front-end for VirtualBox
Ruby
5
star
34

lib-2367

Class generation utilities for Clojure
Clojure
5
star
35

dot-slash

Basic Leiningen plugin to setup a custom repl utils namespace
Clojure
5
star
36

4clojure-logic

The core.logic problems I assembled for a Chicago Clojure workshop.
Clojure
5
star
37

lib-5141

Simple customizable HTTP proxy in Clojure
Clojure
4
star
38

clojure-useless

A collection of utility functions that won't improve your Clojure code
Clojure
4
star
39

ranguages

Regular Language Manipulation in Clojure
Clojure
4
star
40

bijector

Bijections in Clojure
Clojure
4
star
41

compare

Helper functions for clojure.core/compare.
Clojure
4
star
42

misquote

Simple unquoting in Clojure
Clojure
4
star
43

test-check-workshop

Materials for my test.check workshop
Clojure
4
star
44

z

Simple complex numbers in Clojure
Clojure
3
star
45

eiPlog

event server
JavaScript
3
star
46

rubiks-cljube

Clojure
3
star
47

haystack

Dataset Difference Debugging in Clojure
Clojure
2
star
48

greengrocer

Web testing for Clojure
Clojure
2
star
49

tictactoe

It can't lose.
Clojure
2
star
50

2012-12-18

Support code for core.logic workshop
Clojure
2
star
51

git-git

Managing your swarm of git repositories.
Clojure
2
star
52

minus

Diffing/patching for Clojure data
Clojure
2
star
53

chess-clj

Messing around with chess and clojure
Clojure
2
star
54

referee

A library for handling exceptions across thread boundaries.
Clojure
1
star
55

lib-4642

This is not a project
Clojure
1
star
56

lein-env-version

Set leiningen project version with an environment variable.
Clojure
1
star
57

system-slash-exit

(System/exit n) in clojure
Clojure
1
star
58

engorge

Parsing/printing emacs org files in Clojure
Clojure
1
star
59

lib-7607

Casual Computational Combinatorics Framework
Clojure
1
star
60

lazy-prime-sieve

Clojure
1
star
61

bespoke-primes

The code behind http://gfredericks.com/sandbox/bespoke-primes
Clojure
1
star
62

ridge

A clojuresque lisp interpreted in Haskell
Haskell
1
star
63

cerealizer

Data serializationish-or-something libary for Ruby
Ruby
1
star
64

git-annex-utils

Some things I keep doing with git-annex
Clojure
1
star
65

data

My data
1
star
66

lib-4395

Clojure & algebra
Clojure
1
star
67

flexnum

Liberating numbers in ruby
Ruby
1
star