Very much better! Generating tests for n-arg functions which are ninety

percent correct (five failures in 775 assertions).
This commit is contained in:
Simon Brooke 2014-08-14 21:43:35 +01:00
parent 0125723c83
commit 61b6983294
3 changed files with 3449 additions and 509 deletions

View file

@ -4,20 +4,34 @@
clojure.math.combinatorics))
(defn maybe-quote [val]
(defn maybe-quote
"Convert val into a form in which, after being passed through the pretty
printer, it will be reconstituted in a form useful to the test"
[val]
(let [mval (try
(macroexpand val)
(catch Exception any val))]
(cond
(= true val) true
(nil? val) nil
(number? val) val
(string? val) val
(keyword? val) val
(vector? val) val
(map? val) val
(symbol? val) (list 'symbol (str val))
true (list 'quote val)))
(and (seq mval) (= (first mval) 'quote)) val
true (list 'quote val))))
(defn generate-assertion [fnname args]
(defn generate-assertion
"Generate an appropiate assertion for these arguments passed to this function"
(print (str "Generating assertion for " (cons fnname args)))
[fnname args]
(let [doc-string (str "Generating assertion for " (cons fnname args))]
(try
(let [val (eval (cons fnname args))]
(list 'is (list '= (cons fnname args) (maybe-quote val))))
(catch Exception e (list 'is (list 'thrown? (.getClass e) (cons fnname args))))))
(list 'is (list '= (cons fnname args) (maybe-quote val)) doc-string))
(catch Exception e
(list 'is (list 'thrown? (.getClass e) (cons fnname args)))))))
(defn constant? [arg]
(not (or
@ -36,6 +50,8 @@
(defn find-interesting-args [sexpr extra-vars]
"Find things in sexpr which would be even more interesting if passed as arguments to it"
(apply list
(set
(concat generic-args extra-vars
(flatten
(map
@ -43,7 +59,7 @@
(integer? %) (list % (inc %) (dec %))
(number? %) (list % (+ % 0.0001) (- % 0.0001))
true %)
(constants sexpr)))))
(constants sexpr)))))))
(defn n-of [arg n]
@ -55,28 +71,34 @@
;; This version of generate-test tries to generate good tests for functions of one
;; argument. It works.
;; (defn generate-test [fndef extra-vars]
;; "Generate a test for this function definition"
;; (cond (or (= (first fndef) 'def)(= (first fndef) 'defn))
;; (let [name (first (rest fndef))
;; potential-args (find-interesting-args fndef extra-vars)]
;; (list 'deftest (symbol (str "test-" name))
;; (concat (list 'testing (str name))
;; (map #(generate-assertion name (list %)) potential-args))))))
;; This version of generate-test tries to generate good tests for functions of one or more than one
;; argument. Unfortunately, it is borked.
(defn generate-test [fndef extra-vars]
(defn generate-test-1 [fndef extra-vars]
"Generate a test for this function definition"
(cond (or (= (first fndef) 'def)(= (first fndef) 'defn))
(let [name (first (rest fndef))
potential-args (find-interesting-args fndef extra-vars)]
(list 'deftest (symbol (str "test-" name))
(concat (list 'testing (str name))
(map #(generate-assertion name (list %)) potential-args))))))
;; This version of generate-test tries to generate good tests for functions of one or more than one
;; argument. Unfortunately, it is borked.
(defn generate-test-n [fndef extra-vars]
"Generate a test for this function definition"
(cond (or (= (first fndef) 'def)(= (first fndef) 'defn))
(let [name (first (rest fndef))
arg-list (nth fndef 2)
potential-args (map maybe-quote (find-interesting-args fndef extra-vars))]
(print potential-args)
(try
(list 'deftest (symbol (str "test-" name))
(concat (list 'testing (str name))
(map #(generate-assertion name %)
(cond (vector? (nth fndef 2)) (apply cartesian-product (n-of potential-args (count (nth fndef 2))))
true (map #(list %) potential-args)))))
(cond
(vector? arg-list)
(apply cartesian-product
(n-of potential-args (count arg-list)))
true
(map #(list %) potential-args)))))
(catch Exception any)))))
;; generating a test file
@ -135,7 +157,7 @@
(defn generate-tests [filename]
"Generate a suite of characterisation tests for the file indicated by this filename.
filename: the file path name of a file containing Clojure code to be tested."
* `filename`: the file path name of a file containing Clojure code to be tested."
(let [fn (clean-filename filename)
pn (packagename-from-filename filename)
extra-vars (find-vars-in-file filename)]
@ -150,12 +172,16 @@
(while (.ready eddi)
(println "reading...")
(let [form (read eddi false nil)]
(try
(cond (= (first form) 'defn)
(do
(println (first (rest form)) "...")
(pprint (generate-test form extra-vars) dickens)
(pprint (generate-test-n form extra-vars) dickens)
(.write dickens "\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n")
))))
))
(catch Exception any
(.write dickens
"\n\n;; ERROR while attempting to generate\n\n")))))
(.write dickens "\n\n;; end of file ;;\n\n")
(.flush dickens))))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
(ns testgen.manual_test
(:require [clojure.test :refer :all]
[testgen.core :refer :all]))
(deftest find-interesting-args-test
(testing "find-interesting-args"
(let [args (find-interesting-args
'(defn find-interesting-args [sexpr extra-vars]
"Find things in sexpr which would be even more interesting if passed as arguments to it"
(concat generic-args extra-vars
(flatten
(map
#(cond
(integer? %) (list % (inc %) (dec %))
(number? %) (list % (+ % 0.0001) (- % 0.0001))
true %)
(constants sexpr))))) nil)]
(is (= args '(nil
0
0.0
()
"Find things in sexpr which would be even more interesting if passed as arguments to it"
(quote (a :b "c"))
:test
true
1.0E-4
2.0E-4
"test"))
"Fix: I ran it, and this is what it produced")
(is (= (find-interesting-args nil nil)
'(nil 0 () (quote (a :b "c")) :test true "test"))
"Fix: I ran it, and this is what it produced"))))
(deftest n-of-test
(testing "n-of"
(is (nil? (n-of true 0)) "Zero of anything should be nil")
(is (nil? (n-of nil 0)) "Zero of anything should be nil")
(is (nil? (n-of 4 0)) "Zero of anything should be nil")
(is (nil? (n-of '(a) 0)) "Zero of anything should be nil")
(is (nil? (n-of "a" 0)) "Zero of anything should be nil")
(is (empty?
(remove true?
(map
#(let [result (n-of % 4)]
(is (= (count result) 4)
"4 of anything should be 4")
(is (= (first result) %)
"the first of four of anything should be that thing"))
generic-args))))))
(deftest generate-assertion-test
(testing "generate-assertion"
(is (= (generate-assertion '+ '( 1 2))
'(is (= (+ 1 2) 3) "Generating assertion for (+ 1 2)"))
"This is what we're aiming for")))