core: proper uuid support — fix random-uuid, add parse-uuid, real uuid values

uuid support was broken end to end (jolt-6s2): random-uuid built malformed
strings ((string/format "%x") with no zero-padding, so hex groups came out
short, and no variant bits), uuid? was hardcoded false, the #uuid data reader
was identity (bare string), and parse-uuid didn't exist. Nothing tested it.

A UUID is now an immutable tagged struct {:jolt/type :jolt/uuid :str <lower>}
(make-uuid, types.janet) — struct value equality gives case-insensitive = and
map-key/set hashing for free, and the evaluator treats it as self-evaluating
(like chars). random-uuid emits a correct RFC 4122 v4 (zero-padded 8-4-4-4-12,
version nibble 4, variant 8-b). parse-uuid validates the canonical shape,
returns nil on a bad string, throws on a non-string (Clojure 1.11). uuid? is
an overlay tag predicate. str renders the bare string; pr-str renders
#uuid "..." and round-trips.

Tests: uuid-spec (30 cases: format, parse edge cases from the suite, value
semantics, reader literal), 6 conformance cases x3 modes. The suite's
parse_uuid/random_uuid/uuid_qmark files now contribute: 4049 -> 4074 pass,
71 clean files; baselines raised.
This commit is contained in:
Yogthos 2026-06-10 10:27:24 -04:00
parent c14c129627
commit e44a7a9820
7 changed files with 112 additions and 10 deletions

51
test/spec/uuid-spec.janet Normal file
View file

@ -0,0 +1,51 @@
# Specification: UUID support — random-uuid, parse-uuid, uuid?, #uuid literal.
# UUIDs are immutable tagged structs {:jolt/type :jolt/uuid :str "<lowercase>"}:
# value equality, usable as map keys, case-normalized at construction.
(use ../support/harness)
(defspec "uuid / random-uuid"
["returns a uuid" "true" "(uuid? (random-uuid))"]
["str is 36 chars" "36" "(count (str (random-uuid)))"]
["8-4-4-4-12 shape" "[8 4 4 4 12]" "(do (require (quote [clojure.string :as s])) (mapv count (s/split (str (random-uuid)) #\"-\")))"]
["version nibble is 4" "\\4" "(nth (str (random-uuid)) 14)"]
["variant nibble 8-b" "true" "(contains? #{\\8 \\9 \\a \\b} (nth (seq (str (random-uuid))) 19))"]
["distinct" "10" "(count (set (repeatedly 10 random-uuid)))"]
["all hex digits" "true" "(every? (fn [c] (contains? (set (seq \"0123456789abcdef-\")) c)) (seq (str (random-uuid))))"])
(defspec "uuid / parse-uuid"
["valid round-trips" "\"b6883c0a-0342-4007-9966-bc2dfa6b109e\""
"(str (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\"))"]
["parses to uuid" "true" "(uuid? (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\"))"]
["case-insensitive =" "true"
"(= (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\") (parse-uuid \"B6883C0A-0342-4007-9966-BC2DFA6B109E\"))"]
["empty -> nil" "nil" "(parse-uuid \"\")"]
["short -> nil" "nil" "(parse-uuid \"0\")"]
["garbage -> nil" "nil" "(parse-uuid \"df0993\")"]
["too long -> nil" "nil" "(parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109eb\")"]
["leading extra -> nil" "nil" "(parse-uuid \"ab6883c0a-0342-4007-9966-bc2dfa6b109e\")"]
["non-hex -> nil" "nil" "(parse-uuid \"g6883c0a-0342-4007-9966-bc2dfa6b109e\")"]
["bad dashes -> nil" "nil" "(parse-uuid \"b6883c0a00342-4007-9966-bc2dfa6b109e\")"]
["non-string throws" :throws "(parse-uuid 1000)"]
["keyword throws" :throws "(parse-uuid :key)"]
["map throws" :throws "(parse-uuid {})"])
(defspec "uuid / value semantics"
["equal by value" "true"
"(= (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\") (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\"))"]
["unequal differs" "false"
"(= (random-uuid) (random-uuid))"]
["works as map key" ":v"
"(let [u (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")] (get {u :v} (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")))"]
["works in a set" "true"
"(contains? #{(parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")} (parse-uuid \"B6883C0A-0342-4007-9966-BC2DFA6B109E\"))"]
["uuid? false on string" "false" "(uuid? \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")"]
["uuid? false on nil" "false" "(uuid? nil)"])
(defspec "uuid / #uuid reader literal"
["reads to uuid" "true" "(uuid? #uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")"]
["= parse-uuid" "true"
"(= #uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\" (parse-uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\"))"]
["str of literal" "\"b6883c0a-0342-4007-9966-bc2dfa6b109e\""
"(str #uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")"]
["pr-str round-trips" "\"#uuid \\\"b6883c0a-0342-4007-9966-bc2dfa6b109e\\\"\""
"(pr-str #uuid \"b6883c0a-0342-4007-9966-bc2dfa6b109e\")"])