test(spec): numbers, strings, predicates — fix variadic <, seq?, index-of
Add spec suites for numbers/arithmetic, strings (str + clojure.string), and type/value predicates. Bugs they caught and fixed: - <, >, <=, >= were binary-only; now variadic ((< 1 2 3) chains) - seq? was true for vectors; vectors are not ISeq in Clojure, so (seq? [1]) is now false (true only for lists/lazy-seqs) - clojure.string/index-of and last-index-of were 1-based (stray inc); now 0-based per Clojure Corrected a systematic-coverage assertion that encoded the old seq? bug. jpm test green, conformance 218/218.
This commit is contained in:
parent
b353d625f1
commit
68d6b1d6c1
6 changed files with 178 additions and 12 deletions
|
|
@ -108,24 +108,23 @@
|
|||
s)))
|
||||
|
||||
(defn index-of
|
||||
|
||||
"0-based index of the first occurrence of value in s, or nil."
|
||||
([s value]
|
||||
(let [idx (str-find value s)]
|
||||
(when idx (inc idx))))
|
||||
(str-find value s))
|
||||
([s value from]
|
||||
(let [idx (str-find value (subs s from))]
|
||||
(when idx (+ from (inc idx))))))
|
||||
(when idx (+ from idx)))))
|
||||
|
||||
(defn last-index-of
|
||||
|
||||
([s value]
|
||||
(let [r (str-reverse-b s) sval (str-reverse-b value)
|
||||
idx (str-find sval r)]
|
||||
(when idx (inc (- (count s) (+ idx (count value)))))))
|
||||
(when idx (- (count s) (+ idx (count value))))))
|
||||
([s value from]
|
||||
(let [sub (subs s 0 from) r (str-reverse-b sub) sval (str-reverse-b value)
|
||||
idx (str-find sval r)]
|
||||
(when idx (inc (- from (+ idx (count value))))))))
|
||||
(when idx (- from (+ idx (count value)))))))
|
||||
|
||||
(defn re-quote-replacement
|
||||
"Escape special characters (backslash and dollar) in a regex replacement
|
||||
|
|
|
|||
|
|
@ -87,7 +87,9 @@
|
|||
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
|
||||
(defn core-vector? [x] (jvec? x))
|
||||
(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false)))
|
||||
(defn core-seq? [x] (or (array? x) (tuple? x) (pvec? x) (plist? x) (lazy-seq? x)))
|
||||
# seq? is true only for actual sequences (lists, lazy-seqs) — NOT vectors, which
|
||||
# are not ISeq in Clojure. (A Janet array represents a Clojure list/seq result.)
|
||||
(defn core-seq? [x] (or (array? x) (plist? x) (lazy-seq? x)))
|
||||
(defn core-coll? [x] (or (array? x) (tuple? x) (pvec? x) (plist? x) (struct? x) (phm? x) (set? x) (lazy-seq? x)))
|
||||
|
||||
(defn core-true? [x] (= true x))
|
||||
|
|
@ -239,10 +241,17 @@
|
|||
|
||||
(defn core-not= [& args] (not (apply core-= args)))
|
||||
|
||||
(defn core-< [a b] (< a b))
|
||||
(defn core-> [a b] (> a b))
|
||||
(defn core-<= [a b] (<= a b))
|
||||
(defn core->= [a b] (>= a b))
|
||||
# Comparisons are variadic: (< a b c) means a < b < c.
|
||||
(defn- chain-cmp [op xs]
|
||||
(var ok true) (var i 0)
|
||||
(while (and ok (< i (dec (length xs))))
|
||||
(unless (op (in xs i) (in xs (+ i 1))) (set ok false))
|
||||
(++ i))
|
||||
ok)
|
||||
(defn core-< [& xs] (chain-cmp < xs))
|
||||
(defn core-> [& xs] (chain-cmp > xs))
|
||||
(defn core-<= [& xs] (chain-cmp <= xs))
|
||||
(defn core->= [& xs] (chain-cmp >= xs))
|
||||
|
||||
# ============================================================
|
||||
# Collections
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
(assert (= true (ct-eval ctx "(set? #{1 2})")) "set?")
|
||||
(assert (= false (ct-eval ctx "(set? [1 2])")) "set? false")
|
||||
(assert (= true (ct-eval ctx "(seq? '(1 2))")) "seq? list")
|
||||
(assert (= true (ct-eval ctx "(seq? [1 2])")) "seq? vector")
|
||||
# vectors are not ISeq in Clojure — (seq? [1 2]) is false
|
||||
(assert (= false (ct-eval ctx "(seq? [1 2])")) "seq? vector is false")
|
||||
(assert (= true (ct-eval ctx "(coll? [1 2])")) "coll? vec")
|
||||
(assert (= true (ct-eval ctx "(coll? '(1 2))")) "coll? list")
|
||||
(assert (= true (ct-eval ctx "(coll? {})")) "coll? map")
|
||||
|
|
|
|||
63
test/spec/numbers-spec.janet
Normal file
63
test/spec/numbers-spec.janet
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Specification: numbers & arithmetic.
|
||||
(use ../support/harness)
|
||||
|
||||
(defspec "numbers / arithmetic"
|
||||
["add" "6" "(+ 1 2 3)"]
|
||||
["add zero args" "0" "(+)"]
|
||||
["subtract" "5" "(- 10 3 2)"]
|
||||
["negate" "-5" "(- 5)"]
|
||||
["multiply" "24" "(* 2 3 4)"]
|
||||
["multiply zero args" "1" "(*)"]
|
||||
["divide" "2" "(/ 10 5)"]
|
||||
["divide to fraction" "0.5" "(/ 1 2)"]
|
||||
["inc" "6" "(inc 5)"]
|
||||
["dec" "4" "(dec 5)"]
|
||||
["quot" "3" "(quot 10 3)"]
|
||||
["rem" "1" "(rem 10 3)"]
|
||||
["mod" "2" "(mod -1 3)"]
|
||||
["rem negative" "-1" "(rem -1 3)"]
|
||||
["max" "9" "(max 3 9 1)"]
|
||||
["min" "1" "(min 3 9 1)"]
|
||||
["abs" "5" "(abs -5)"]
|
||||
["promoting + alias" "3" "(+' 1 2)"]
|
||||
["inc' alias" "6" "(inc' 5)"])
|
||||
|
||||
(defspec "numbers / comparison"
|
||||
["less than" "true" "(< 1 2 3)"]
|
||||
["less than false" "false" "(< 1 3 2)"]
|
||||
["greater than" "true" "(> 3 2 1)"]
|
||||
["<=" "true" "(<= 1 1 2)"]
|
||||
[">=" "true" "(>= 3 3 2)"]
|
||||
["= numbers" "true" "(= 2 2)"]
|
||||
["= different" "false" "(= 2 3)"]
|
||||
["== numeric" "true" "(== 2 2)"]
|
||||
["not=" "true" "(not= 1 2)"]
|
||||
["compare less" "-1" "(compare 1 2)"]
|
||||
["compare equal" "0" "(compare 1 1)"]
|
||||
["compare greater" "1" "(compare 2 1)"])
|
||||
|
||||
(defspec "numbers / predicates"
|
||||
["zero?" "true" "(zero? 0)"]
|
||||
["pos?" "true" "(pos? 5)"]
|
||||
["neg?" "true" "(neg? -5)"]
|
||||
["even?" "true" "(even? 4)"]
|
||||
["odd?" "true" "(odd? 3)"]
|
||||
["number?" "true" "(number? 5)"]
|
||||
["number? false" "false" "(number? :a)"]
|
||||
["int?" "true" "(int? 5)"]
|
||||
["pos-int?" "true" "(pos-int? 5)"]
|
||||
["neg-int?" "true" "(neg-int? -5)"]
|
||||
["nat-int? zero" "true" "(nat-int? 0)"]
|
||||
["nat-int? neg" "false" "(nat-int? -1)"]
|
||||
["ratio? false" "false" "(ratio? 5)"])
|
||||
|
||||
(defspec "numbers / bit-ops & math"
|
||||
["bit-and" "4" "(bit-and 12 6)"]
|
||||
["bit-or" "14" "(bit-or 12 6)"]
|
||||
["bit-xor" "10" "(bit-xor 12 6)"]
|
||||
["bit-shift-left" "8" "(bit-shift-left 1 3)"]
|
||||
["bit-shift-right" "2" "(bit-shift-right 8 2)"]
|
||||
["bit-set" "8" "(bit-set 0 3)"]
|
||||
["bit-clear" "13" "(bit-clear 15 1)"]
|
||||
["bit-test true" "true" "(bit-test 4 2)"]
|
||||
["bigint 64-bit" "\"9000000000\"" "(str (bigint 9000000000))"])
|
||||
61
test/spec/predicates-spec.janet
Normal file
61
test/spec/predicates-spec.janet
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Specification: type & value predicates.
|
||||
(use ../support/harness)
|
||||
|
||||
(defspec "predicates / nil & boolean"
|
||||
["nil? true" "true" "(nil? nil)"]
|
||||
["nil? false" "false" "(nil? 0)"]
|
||||
["some? true" "true" "(some? 0)"]
|
||||
["some? on nil" "false" "(some? nil)"]
|
||||
["true?" "true" "(true? true)"]
|
||||
["false?" "true" "(false? false)"]
|
||||
["boolean? true" "true" "(boolean? false)"]
|
||||
["not nil" "true" "(not nil)"]
|
||||
["not 0 is false" "false" "(not 0)"]
|
||||
["boolean of nil" "false" "(boolean nil)"]
|
||||
["boolean of value" "true" "(boolean 5)"])
|
||||
|
||||
(defspec "predicates / types"
|
||||
["string?" "true" "(string? \"x\")"]
|
||||
["number?" "true" "(number? 1)"]
|
||||
["keyword?" "true" "(keyword? :a)"]
|
||||
["symbol?" "true" "(symbol? (quote a))"]
|
||||
["char?" "true" "(char? \\a)"]
|
||||
["fn? on fn" "true" "(fn? inc)"]
|
||||
["ifn? on keyword" "true" "(ifn? :a)"]
|
||||
["vector?" "true" "(vector? [1])"]
|
||||
["list?" "true" "(list? (list 1))"]
|
||||
["map?" "true" "(map? {:a 1})"]
|
||||
["set?" "true" "(set? #{1})"]
|
||||
["coll? vector" "true" "(coll? [1])"]
|
||||
["coll? map" "true" "(coll? {:a 1})"]
|
||||
["coll? on number" "false" "(coll? 1)"]
|
||||
["seq? list" "true" "(seq? (list 1))"]
|
||||
["seq? vector" "false" "(seq? [1])"]
|
||||
["sequential? vector" "true" "(sequential? [1])"]
|
||||
["associative? map" "true" "(associative? {:a 1})"]
|
||||
["associative? vec" "true" "(associative? [1])"]
|
||||
["indexed? vector" "true" "(indexed? [1])"]
|
||||
["counted? vector" "true" "(counted? [1])"])
|
||||
|
||||
(defspec "predicates / idents"
|
||||
["ident? keyword" "true" "(ident? :a)"]
|
||||
["ident? symbol" "true" "(ident? (quote a))"]
|
||||
["simple-keyword?" "true" "(simple-keyword? :a)"]
|
||||
["qualified-keyword?" "true" "(qualified-keyword? :a/b)"]
|
||||
["simple-symbol?" "true" "(simple-symbol? (quote a))"]
|
||||
["qualified-symbol?" "true" "(qualified-symbol? (quote a/b))"]
|
||||
["name of keyword" "\"a\"" "(name :a)"]
|
||||
["name of qualified" "\"b\"" "(name :a/b)"]
|
||||
["namespace" "\"a\"" "(namespace :a/b)"]
|
||||
["namespace simple" "nil" "(namespace :a)"])
|
||||
|
||||
(defspec "predicates / equality & identity"
|
||||
["= same" "true" "(= 1 1)"]
|
||||
["= vectors" "true" "(= [1 2] [1 2])"]
|
||||
["= vector & list" "true" "(= [1 2] (list 1 2))"]
|
||||
["= maps" "true" "(= {:a 1} {:a 1})"]
|
||||
["= sets" "true" "(= #{1 2} #{2 1})"]
|
||||
["= nested" "true" "(= {:a [1 2]} {:a [1 2]})"]
|
||||
["not= differs" "true" "(not= [1 2] [1 3])"]
|
||||
["identical? same kw" "true" "(identical? :a :a)"]
|
||||
["compare strings" "-1" "(compare \"a\" \"b\")"])
|
||||
33
test/spec/strings-spec.janet
Normal file
33
test/spec/strings-spec.janet
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Specification: strings (str + clojure.string).
|
||||
(use ../support/harness)
|
||||
|
||||
(defspec "string / str & basics"
|
||||
["str concat" "\"abc\"" "(str \"a\" \"b\" \"c\")"]
|
||||
["str of numbers" "\"12\"" "(str 1 2)"]
|
||||
["str nil is empty" "\"\"" "(str nil)"]
|
||||
["str mixed" "\"a1:b\"" "(str \"a\" 1 :b)"]
|
||||
["str of coll" "\"[1 2]\"" "(str [1 2])"]
|
||||
["count" "3" "(count \"abc\")"]
|
||||
["subs from" "\"bc\"" "(subs \"abc\" 1)"]
|
||||
["subs range" "\"b\"" "(subs \"abc\" 1 2)"]
|
||||
["string? true" "true" "(string? \"x\")"]
|
||||
["seq of string" "[\\a \\b]" "(seq \"ab\")"])
|
||||
|
||||
(defspec "clojure.string"
|
||||
["join" "\"a,b,c\"" "(do (require (quote [clojure.string :as s])) (s/join \",\" [\"a\" \"b\" \"c\"]))"]
|
||||
["join no sep" "\"abc\"" "(do (require (quote [clojure.string :as s])) (s/join [\"a\" \"b\" \"c\"]))"]
|
||||
["split" "[\"a\" \"b\"]" "(do (require (quote [clojure.string :as s])) (s/split \"a,b\" #\",\"))"]
|
||||
["split-lines" "[\"a\" \"b\"]" "(do (require (quote [clojure.string :as s])) (s/split-lines \"a\\nb\"))"]
|
||||
["upper-case" "\"ABC\"" "(do (require (quote [clojure.string :as s])) (s/upper-case \"abc\"))"]
|
||||
["lower-case" "\"abc\"" "(do (require (quote [clojure.string :as s])) (s/lower-case \"ABC\"))"]
|
||||
["capitalize" "\"Abc\"" "(do (require (quote [clojure.string :as s])) (s/capitalize \"abc\"))"]
|
||||
["trim" "\"x\"" "(do (require (quote [clojure.string :as s])) (s/trim \" x \"))"]
|
||||
["triml" "\"x \"" "(do (require (quote [clojure.string :as s])) (s/triml \" x \"))"]
|
||||
["blank? true" "true" "(do (require (quote [clojure.string :as s])) (s/blank? \" \"))"]
|
||||
["blank? false" "false" "(do (require (quote [clojure.string :as s])) (s/blank? \"x\"))"]
|
||||
["includes?" "true" "(do (require (quote [clojure.string :as s])) (s/includes? \"hello\" \"ell\"))"]
|
||||
["starts-with?" "true" "(do (require (quote [clojure.string :as s])) (s/starts-with? \"hello\" \"he\"))"]
|
||||
["ends-with?" "true" "(do (require (quote [clojure.string :as s])) (s/ends-with? \"hello\" \"lo\"))"]
|
||||
["replace" "\"hexxo\"" "(do (require (quote [clojure.string :as s])) (s/replace \"hello\" \"l\" \"x\"))"]
|
||||
["reverse" "\"cba\"" "(do (require (quote [clojure.string :as s])) (s/reverse \"abc\"))"]
|
||||
["index-of" "2" "(do (require (quote [clojure.string :as s])) (s/index-of \"hello\" \"l\"))"])
|
||||
Loading…
Add table
Add a link
Reference in a new issue