(ns hiccup.core-test
(:require [clojure.test :refer :all]
[hiccup.core :refer :all]))
(deftest tag-names
(testing "basic tags"
(is (= (html [:div]) "
"))
(is (= (html ["div"]) ""))
(is (= (html ['div]) "")))
(testing "tag syntax sugar"
(is (= (html [:div#foo]) ""))
(is (= (html [:div.foo]) ""))
(is (= (html [:div.foo (str "bar" "baz")])
"barbaz
"))
(is (= (html [:div.a.b]) ""))
(is (= (html [:div.a.b.c]) ""))
(is (= (html [:div#foo.bar.baz])
""))))
(deftest tag-contents
(testing "empty tags"
(is (= (html [:div]) ""))
(is (= (html [:h1]) ""))
(is (= (html [:script]) ""))
(is (= (html [:text]) ""))
(is (= (html [:a]) ""))
(is (= (html [:iframe]) ""))
(is (= (html [:title]) ""))
(is (= (html [:section]) ""))
(is (= (html [:select]) ""))
(is (= (html [:object]) ""))
(is (= (html [:video]) "")))
(testing "void tags"
(is (= (html [:br]) "
"))
(is (= (html [:link]) ""))
(is (= (html [:colgroup {:span 2}] "")))
(is (= (html [:colgroup [:col]] ""))))
(testing "tags containing text"
(is (= (html [:text "Lorem Ipsum"]) "Lorem Ipsum")))
(testing "contents are concatenated"
(is (= (html [:body "foo" "bar"]) "foobar"))
(is (= (html [:body [:p] [:br]]) "
")))
(testing "seqs are expanded"
(is (= (html [:body (list "foo" "bar")]) "foobar"))
(is (= (html (list [:p "a"] [:p "b"])) "a
b
")))
(testing "keywords are turned into strings"
(is (= (html [:div :foo]) "foo
")))
(testing "vecs don't expand - error if vec doesn't have tag name"
(is (thrown? IllegalArgumentException
(html (vector [:p "a"] [:p "b"])))))
(testing "tags can contain tags"
(is (= (html [:div [:p]]) ""))
(is (= (html [:div [:b]]) "
"))
(is (= (html [:p [:span [:a "foo"]]])
"foo
"))))
(deftest tag-attributes
(testing "tag with blank attribute map"
(is (= (html [:xml {}]) "")))
(testing "tag with populated attribute map"
(is (= (html [:xml {:a "1", :b "2"}]) ""))
(is (= (html [:img {"id" "foo"}]) "
"))
(is (= (html [:img {'id "foo"}]) "
"))
(is (= (html [:xml {:a "1", 'b "2", "c" "3"}])
"")))
(testing "attribute values are escaped"
(is (= (html [:div {:id "\""}]) "")))
(testing "boolean attributes"
(is (= (html [:input {:type "checkbox" :checked true}])
""))
(is (= (html [:input {:type "checkbox" :checked false}])
"")))
(testing "nil attributes"
(is (= (html [:span {:class nil} "foo"])
"foo")))
(testing "resolving conflicts between attributes in the map and tag"
(is (= (html [:div.foo {:class "bar"} "baz"])
"baz
"))
(is (= (html [:div#bar.foo {:id "baq"} "baz"])
"baz
")))
;; Not released yet
#_(testing "tag with vector class"
(is (= (html [:div.foo {:class ["bar"]} "baz"])
"baz
"))
(is (= (html [:div.foo {:class [:bar]} "baz"])
"baz
"))
(is (= (html [:div.foo {:class [:bar "box"]} "baz"])
"baz
"))
(is (= (html [:div.foo {:class ["bar" "box"]} "baz"])
"baz
"))
(is (= (html [:div.foo {:class [:bar :box]} "baz"])
"baz
"))))
(deftest compiled-tags
(testing "tag content can be vars"
(is (= (let [x "foo"] (html [:span x])) "foo")))
(testing "tag content can be forms"
(is (= (html [:span (str (+ 1 1))]) "2"))
(is (= (html [:span ({:foo "bar"} :foo)]) "bar")))
(testing "attributes can contain vars"
(let [x "foo"]
(is (= (html [:xml {:x x}]) ""))
(is (= (html [:xml {x "x"}]) ""))
(is (= (html [:xml {:x x} "bar"]) "bar"))))
(testing "attributes are evaluated"
(is (= (html [:img {:src (str "/foo" "/bar")}])
"
"))
(is (= (html [:div {:id (str "a" "b")} (str "foo")])
"foo
")))
(testing "type hints"
(let [string "x"]
(is (= (html [:span ^String string]) "x"))))
(testing "optimized forms"
(is (= (html [:ul (for [n (range 3)]
[:li n])])
""))
(is (= (html [:div (if true
[:span "foo"]
[:span "bar"])])
"foo
")))
(testing "values are evaluated only once"
(let [times-called (atom 0)
foo #(swap! times-called inc)]
(html [:div (foo)])
(is (= @times-called 1))))
(testing "defer evaluation of non-literal class names when combined with tag classes"
(let [x "attr-class"]
(is (= (html [:div.tag-class {:class x}])
"")))))
(deftest render-modes
(testing "closed tag"
(is (= (html [:p] [:br]) "
"))
(is (= (html {:mode :xhtml} [:p] [:br]) "
"))
(is (= (html {:mode :html} [:p] [:br]) "
"))
(is (= (html {:mode :xml} [:p] [:br]) "
"))
(is (= (html {:mode :sgml} [:p] [:br]) "
")))
(testing "boolean attributes"
(is (= (html {:mode :xml} [:input {:type "checkbox" :checked true}])
""))
(is (= (html {:mode :sgml} [:input {:type "checkbox" :checked true}])
"")))
(testing "laziness and binding scope"
(is (= (html {:mode :sgml} [:html [:link] (list [:link])])
""))))