1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
(ns clj-yaml.core-test
(:require [clojure.test :refer (deftest testing is)]
[clojure.string :as string]
[clj-yaml.core :refer [parse-string unmark generate-string]])
(:import [java.util Date]
(org.yaml.snakeyaml.error YAMLException)
(org.yaml.snakeyaml.constructor DuplicateKeyException)))
(def nested-hash-yaml
"root:\n childa: a\n childb: \n grandchild: \n greatgrandchild: bar\n")
(def list-yaml
"--- # Favorite Movies\n- Casablanca\n- North by Northwest\n- The Man Who Wasn't There")
(def hashes-lists-yaml "
items:
- part_no: A4786
descrip: Water Bucket (Filled)
price: 1.47
quantity: 4
- part_no: E1628
descrip: High Heeled \"Ruby\" Slippers
price: 100.27
quantity: 1
owners:
- Dorthy
- Wicked Witch of the East
")
(def inline-list-yaml
"--- # Shopping list
[milk, pumpkin pie, eggs, juice]
")
(def inline-hash-yaml
"{name: John Smith, age: 33}")
(def list-of-hashes-yaml "
- {name: John Smith, age: 33}
- name: Mary Smith
age: 27
")
(def hashes-of-lists-yaml "
men: [John Smith, Bill Jones]
women:
- Mary Smith
- Susan Williams
")
(def typed-data-yaml "
the-bin: !!binary 0101")
(def io-file-typed-data-yaml "
!!java.io.File")
(def set-yaml "
--- !!set
? Mark McGwire
? Sammy Sosa
? Ken Griff")
(deftest parse-hash
(let [parsed (parse-string "foo: bar")]
(is (= "bar" (parsed :foo)))))
(deftest parse-hash-with-numeric-key
(let [parsed (parse-string "123: 456")]
(is (= 456 (parsed 123)))))
(deftest parse-hash-with-complex-key
(let [parsed (parse-string "[1, 2]: 3")]
(is (= 3 (parsed [1, 2])))))
(deftest parse-nested-hash
(let [parsed (parse-string nested-hash-yaml)]
(is (= "a" ((parsed :root) :childa)))
(is (= "bar" ((((parsed :root) :childb) :grandchild) :greatgrandchild)))))
(deftest parse-list
(let [parsed (parse-string list-yaml)]
(is (= "Casablanca" (first parsed)))
(is (= "North by Northwest" (nth parsed 1)))
(is (= "The Man Who Wasn't There" (nth parsed 2)))))
(deftest parse-nested-hash-and-list
(let [parsed (parse-string hashes-lists-yaml)]
(is (= "A4786" ((first (parsed :items)) :part_no)))
(is (= "Dorthy" (first ((nth (parsed :items) 1) :owners))))))
(deftest parse-inline-list
(let [parsed (parse-string inline-list-yaml)]
(is (= "milk" (first parsed)))
(is (= "pumpkin pie" (nth parsed 1)))
(is (= "eggs" (nth parsed 2)))
(is (= "juice" (last parsed)))))
(deftest parse-inline-hash
(let [parsed (parse-string inline-hash-yaml)]
(is (= "John Smith" (parsed :name)))
(is (= 33 (parsed :age)))))
(deftest parse-list-of-hashes
(let [parsed (parse-string list-of-hashes-yaml)]
(is (= "John Smith" ((first parsed) :name)))
(is (= 33 ((first parsed) :age)))
(is (= "Mary Smith" ((nth parsed 1) :name)))
(is (= 27 ((nth parsed 1) :age)))))
(deftest hashes-of-lists
(let [parsed (parse-string hashes-of-lists-yaml)]
(is (= "John Smith" (first (parsed :men))))
(is (= "Bill Jones" (last (parsed :men))))
(is (= "Mary Smith" (first (parsed :women))))
(is (= "Susan Williams" (last (parsed :women))))))
(deftest h-set
(is (= #{"Mark McGwire" "Ken Griff" "Sammy Sosa"}
(parse-string set-yaml))))
(deftest typed-data
(let [parsed (parse-string typed-data-yaml)]
(is (= (Class/forName "[B") (type (:the-bin parsed))))))
(deftest disallow-arbitrary-typed-data
(is (thrown? org.yaml.snakeyaml.error.YAMLException
(parse-string io-file-typed-data-yaml))))
(deftest keywordized
(is (= "items"
(-> hashes-lists-yaml
(parse-string :keywords false)
ffirst))))
(deftest not-keywordized-in-lists
(is (every? string?
(-> "[{b: c, c: d}]"
(parse-string :keywords false)
first
keys))))
(deftest marking-source-position-works
(let [parsed (parse-string inline-list-yaml :mark true)]
;; The list starts at the beginning of line 1.
(is (= 1 (-> parsed :start :line)))
(is (= 0 (-> parsed :start :column)))
;; The first item starts at the second character of line 1.
(is (= 1 (-> parsed unmark first :start :line)))
(is (= 1 (-> parsed unmark first :start :column)))
;; The first item ends at the fifth character of line 1.
(is (= 1 (-> parsed unmark first :end :line)))
(is (= 5 (-> parsed unmark first :end :column)))))
(deftest text-wrapping
(let [data
{:description
"Big-picture diagram showing how our top-level systems and stakeholders interact"}]
(testing "long lines of text should not be wrapped"
;; clj-yaml 0.5.6 used SnakeYAML 1.13 which by default did *not* split long lines.
;; clj-yaml 0.6.0 upgraded to SnakeYAML 1.23 which by default *did* split long lines.
;; This test ensures that generate-string uses the older behavior by default, for the sake
;; of stability, i.e. backwards compatibility.
(is
(= "{description: Big-picture diagram showing how our top-level systems and stakeholders interact}\n"
(generate-string data))))))
(deftest dump-opts
(let [data [{:age 33 :name "jon"} {:age 44 :name "boo"}]]
(is (= "- age: 33\n name: jon\n- age: 44\n name: boo\n"
(generate-string data :dumper-options {:flow-style :block})))
(is (= "[{age: 33, name: jon}, {age: 44, name: boo}]\n"
(generate-string data :dumper-options {:flow-style :flow})))))
(deftest parse-time
(testing "clj-time parses timestamps with more than millisecond precision correctly."
(let [timestamp "2001-11-23 15:02:31.123456 -04:00"
expected 1006542151123]
(is (= (.getTime ^Date (parse-string timestamp)) expected)))))
(deftest maps-are-ordered
(let [parsed (parse-string hashes-lists-yaml)
[first second] (:items parsed)]
(is (= (keys first) '(:part_no :descrip :price :quantity)))
(is (= (keys second)'(:part_no :descrip :price :quantity :owners)))))
(deftest nulls-are-fine
(testing "nil does not blow up"
(let [res (parse-string "- f:")]
(is (= [{:f nil}] res))
(is (str res)))))
(deftest emoji-can-be-parsed
(let [yaml "{emoji: 💣}"]
(is (= yaml (-> yaml
(generate-string)
(parse-string)
(string/trim)))))
(testing "emoji in comments are OK too"
(let [yaml "# 💣 emoji in a comment\n42"]
(is (= 42 (parse-string yaml))))))
(def too-many-aliases
(->> (range 51)
(map #(str "b" % ": *a"))
(cons "a: &a [\"a\",\"a\"]")
(string/join "\n")))
(deftest max-aliases-for-collections-works
(is (thrown-with-msg? YAMLException #"Number of aliases" (parse-string too-many-aliases)))
(is (parse-string too-many-aliases :max-aliases-for-collections 51)))
(def recursive-yaml "
---
&A
- *A: *A
")
(deftest allow-recursive-works
(is (thrown-with-msg? YAMLException #"Recursive" (parse-string recursive-yaml)))
(is (parse-string recursive-yaml :allow-recursive-keys true)))
(def duplicate-keys-yaml "
a: 1
a: 1
")
(deftest allow-recursive-works
(is (parse-string duplicate-keys-yaml))
(is (thrown-with-msg? DuplicateKeyException #"found duplicate key" (parse-string duplicate-keys-yaml :allow-duplicate-keys false))))
|