Skip to content

Commit

Permalink
case-insensitive-string-generator
Browse files Browse the repository at this point in the history
  • Loading branch information
miner committed Apr 10, 2021
1 parent 09a6c4f commit cbab91a
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 7 deletions.
8 changes: 4 additions & 4 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
(defproject com.velisco/strgen "0.1.9"
(defproject com.velisco/strgen "0.2.0"
:description "String generator from regular expressions, for use with Clojure test.check and spec"
:url "https://github.com/miner/strgen"
:deploy-repositories {"releases" :clojars}
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
[org.clojure/clojurescript "1.10.439"]
[org.clojure/test.check "1.0.0"]])
:dependencies [[org.clojure/clojure "1.10.3"]
[org.clojure/clojurescript "1.10.844"]
[org.clojure/test.check "1.1.0"]])

15 changes: 13 additions & 2 deletions src/miner/strgen.cljc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
(ns miner.strgen
(:require [miner.strgen.impl :as impl]))
(:require [miner.strgen.impl :as impl]
[clojure.test.check.generators :as gen]))

(defn string-generator
"Returns a test.check generator that generates strings matching the given regular
expression `regex`. (Fancy flags and POXIX extensions are not suppored; see the doc for
expression `regex`. (Fancy flags and POSIX extensions are not suppored; see the doc for
more information about the supported regular expression syntax.) The optional
`or-more-limit` controls the maximum numbers of elements that are generated when matching
a potentially unbounded regex (such as #\"x*\" or #\"y+\"). The default is 9."
Expand All @@ -14,3 +15,13 @@
([regex or-more-limit]
(impl/string-generator regex or-more-limit)))


(defn case-insensitive-string-generator
"Like `string-generator` but case-insensitive so it generates a mix of upper and lowercase
characters for the given regex."

([regex]
(gen/bind (string-generator regex) impl/gen-case-insensitive))

([regex or-more-limit]
(gen/bind (string-generator regex or-more-limit) impl/gen-case-insensitive)))
12 changes: 11 additions & 1 deletion src/miner/strgen/impl.cljc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns miner.strgen.impl
(:require [clojure.set :as set]
[clojure.string :as str]
#?(:cljs cljs.reader)
[clojure.test.check.generators :as gen]))

Expand Down Expand Up @@ -271,7 +272,7 @@
:else (throw (ex-info (str "Unimplemented generator for " (pr-str tree))
{:unimplemented tree}))))

;; this is the only function needed for the public side
;; this is the main function needed for the public side
(defn string-generator
"Returns a test.check generator that generates strings matching the given regular
expression `regex`. (Fancy flags and POXIX extensions are not suppored; see the doc for
Expand All @@ -286,3 +287,12 @@
([regex or-more-limit]
(binding [*or-more-limit* or-more-limit]
(string-generator regex))))

;; also used for the public side, to implement case-insensitive generation
(defn gen-case-insensitive [s]
(let [ups (str/upper-case s)
lows (str/lower-case s)]
(gen/one-of [(gen/elements [s (str/capitalize s) ups lows])
(gen/fmap (fn [bs]
(str/join (map (fn [b low up] (if b up low)) bs lows ups)))
(gen/vector gen/boolean (count s)))])))
17 changes: 17 additions & 0 deletions test/miner/test_strgen.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:clj [clojure.test :refer [deftest is]])
[clojure.test.check.generators :as gen]
[clojure.spec.alpha :as s]
[clojure.string :as str]
[miner.strgen :as sg]))

;; https://github.com/bensu/doo -- need a test runner for CLJS
Expand Down Expand Up @@ -58,3 +59,19 @@
(doseq [re regexes]
(test-spec-re re)))


;; SEM FIXME: Not a complete test as we convert everything back to lowercase before
;; matching. Could break if we changed `regexs` to require uppercase. We should also
;; validate that the generator yields sensible mixed case results.
(defn test-spec-re-case-insensitive
([re] (test-re re *exercise-limit*))
([re limit]
(doseq [[r c] (s/exercise (s/spec (s/and string? #(re-matches re (str/lower-case %)))
:gen #(sg/case-insensitive-string-generator re))
limit)]
(is (= r c)))))

(deftest spec-regexes-case-insensitive
(doseq [re regexes]
(test-spec-re-case-insensitive re)))

0 comments on commit cbab91a

Please sign in to comment.