;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Test-cases
(load-file (concat (file-name-directory load-file-name) "../emmet-mode.el"))
(emmet-defparameter *emmet-test-cases* nil)
(defun emmet-run-test-case (name fn cases)
(let ((res (loop for c in cases
for i to (1- (length cases)) do
(let ((expected (cdr c))
(actual (funcall fn (car c))))
(when (not (equal expected actual))
(princ
(concat "*** [FAIL] | \"" name "\" " (number-to-string i) "\n\n"
(format "%s" (car c)) "\t=>\n\n"
"Expected\n" (format "%s" expected) "\n\nActual\n" (format "%s" actual) "\n\n"))
(return 'fail))))))
(if (not (eql res 'fail))
(princ (concat " [PASS] | \"" name "\" "
(number-to-string (length cases)) " tests.\n")))))
(defun emmet-test-cases (&rest args)
(let ((cmd (car args)))
(cond ((eql cmd 'assign)
(let ((name (cadr args))
(fn (caddr args))
(defs (cadddr args)))
(let ((place (assoc name *emmet-test-cases*)))
(if place
(setf (cdr place) (cons fn defs))
(setq *emmet-test-cases*
(cons (cons name (cons fn defs)) *emmet-test-cases*))))))
(t
(loop for test in (reverse *emmet-test-cases*) do
(let ((name (symbol-name (car test)))
(fn (cadr test))
(cases (cddr test)))
(emmet-run-test-case name fn cases)))))))
(defmacro define-emmet-transform-test-case (name fn &rest tests)
`(emmet-test-cases 'assign ',name
,fn
',(loop for x on tests by #'cddr collect
(cons (car x)
(emmet-join-string (cadr x)
"\n")))))
(defmacro define-emmet-transform-html-test-case (name &rest tests)
`(define-emmet-transform-test-case ,name
'emmet-html-transform
,@tests))
(defmacro define-emmet-unit-test-case (name fn &rest tests)
`(emmet-test-cases 'assign ',name
,fn
',(loop for x on tests by #'cddr collect
(cons (car x) (cadr x)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; XML-abbrev tests
(define-emmet-transform-html-test-case Tags
"a" ("")
"a.x" ("")
"a#q.x" ("")
"a#q.x.y.z" ("")
"#q" ("
")
".x" ("")
"#q.x" ("")
"#q.x.y.z" (""))
(define-emmet-transform-html-test-case Empty-tags
"a/" ("")
"a/.x" ("")
"a/#q.x" ("")
"a/#q.x.y.z" (""))
(define-emmet-transform-html-test-case Self-closing-tags
"input type=text" ("")
"img" ("
")
"img>metadata/*2" ("
"
" "
" "
""))
(define-emmet-transform-html-test-case Siblings
"a+b" (""
"")
"a+b+c" (""
""
"")
"a.x+b" (""
"")
"a#q.x+b" (""
"")
"a#q.x.y.z+b" (""
"")
"a#q.x.y.z+b#p.l.m.n" (""
""))
(define-emmet-transform-html-test-case Tag-expansion
"table+" ("")
"dl+" (""
" "
" "
"
")
"ul+" ("")
"ul++ol+" (""
""
" "
"
")
"ul#q.x.y[m=l]+" (""))
(define-emmet-transform-html-test-case Parent-child
"a>b" ("")
"a>b>c" ("")
"a.x>b" ("")
"a#q.x>b" ("")
"a#q.x.y.z>b" ("")
"a#q.x.y.z>b#p.l.m.n" ("")
"#q>.x" ("")
"a>b+c" (""
" "
" "
"")
"a>b+c>d" (""
" "
" "
""))
(define-emmet-transform-html-test-case Climb-up
"a>b>c^d" (""
" "
" "
"")
"a>b>c^^d" (""
"")
"a*2>b*2>c^d" (""
" "
" "
" "
""
""
" "
" "
" "
"")
"div+a>p>span{foo}+em>b^^^p"
(""
""
" "
" foo"
" "
"
"
""
"")
"div+div>p>span+em^blockquote{foo}"
(""
""
"
"
" "
" "
"
"
"
foo
"
"
"))
(define-emmet-transform-html-test-case Multiplication
"a*1" ("")
"a*2" (""
"")
"a/*2" (""
"")
"a*2+b*2" (""
""
""
"")
"a*2>b*2" (""
" "
" "
""
""
" "
" "
"")
"a>b*2" (""
" "
" "
"")
"a#q.x>b#q.x*2" (""
" "
" "
"")
"a#q.x>b/#q.x*2" (""
" "
" "
""))
(define-emmet-transform-html-test-case Numbering
"a.$x*3" (""
""
"")
"ul>li.item$*3" ("")
"ul>li.item$$$*3" ("")
"ul>li.item$@-*2" ("")
"ul>li.item$@-1000*2" ("")
"a.$*2>b.$$@-*3" (""
" "
" "
" "
""
""
" "
" "
" "
"")
"(div>(a#id$$*2)+b.c$@-3+c#d$)*2"
(""
"")
"a:b$$$-c$$@-:d$@-3-e$$@100/#b.c$*3"
(""
""
"")
"ul>li.item${name: item$ price: $\\$}*3"
(""
" - name: item1 price: 1$
"
" - name: item2 price: 2$
"
" - name: item3 price: 3$
"
"
"))
(define-emmet-transform-html-test-case Properties
"a[x]" ("")
"a[x=]" ("")
"a[x=\"\"]" ("")
"a[x=y]" ("")
"a[x=\"y\"]" ("")
"a[x=\"()\"]" ("")
"a[x m]" ("")
"a[x= m=\"\"]" ("")
"a[x=y m=l]" ("")
"a/[x=y m=l]" ("")
"a#foo[x=y m=l]" ("")
"a.foo[x=y m=l]" ("")
"a#foo.bar.mu[x=y m=l]" ("")
"a/#foo.bar.mu[x=y m=l]" ("")
"a[x=y]+b" (""
"")
"a[x=y]+b[x=y]" (""
"")
"a[x=y]>b" ("")
"a[x=y]>b[x=y]" ("")
"a[x=y]>b[x=y]+c[x=y]" (""
" "
" "
""))
(define-emmet-transform-html-test-case Parentheses
"(a)" ("")
"(a)+(b)" (""
"")
"a>(b)" ("")
"(a>b)>c" ("")
"(a>b)+c" (""
"")
"z+(a>b)+c+k" (""
""
""
"")
"(a)*2" (""
"")
"((a)*2)" (""
"")
"((a))*2" (""
"")
"(a>b)*2" (""
"")
"(a+b)*2" (""
""
""
""))
(define-emmet-transform-html-test-case Text
"a{Click me}" ("Click me")
"a>{Click me}*3" (""
" Click me"
" Click me"
" Click me"
"")
"a{click}+b{here}" ("click"
"here")
"a>{click}+b{here}" (""
" click"
" here"
"")
"p>{Click }+a{here}+{ to continue}"
(""
" Click "
" here"
" to continue"
"
")
"p{Click }+a{here}+{ to continue}"
("Click
"
"here"
" to continue")
"xxx#id.cls[p=1]{txt}"
("txt"))
(define-emmet-unit-test-case Lorem-ipsum
#'emmet-expr
"lorem"
((filter ("html") (text (lorem 30))) . "")
"ipsum"
((filter ("html") (text (lorem 30))) . "")
"p*3>lorem10"
((filter
("html")
(list ((parent-child (tag ("p" t nil nil nil nil)) (text (lorem 10)))
(parent-child (tag ("p" t nil nil nil nil)) (text (lorem 10)))
(parent-child (tag ("p" t nil nil nil nil)) (text (lorem 10)))))) . "")
"ul.generic-list>ipsum3*3"
((filter
("html")
(parent-child
(tag ("ul" t nil ("generic-list") nil nil))
(list ((text (lorem 3))
(text (lorem 3))
(text (lorem 3)))))) . "")
"ul.generic-list>(li>lorem1000)*3"
((filter
("html")
(parent-child
(tag ("ul" t nil ("generic-list") nil nil))
(list ((parent-child
(tag ("li" t nil nil nil nil))
(text (lorem 1000)))
(parent-child
(tag ("li" t nil nil nil nil))
(text (lorem 1000)))
(parent-child
(tag ("li" t nil nil nil nil))
(text (lorem 1000))))))) . ""))
(define-emmet-transform-html-test-case Filter-comment
"a.b|c" (""
""
"")
"#a>.b|c" (""
""
""))
(define-emmet-transform-html-test-case Filter-HAML
"a|haml" ("%a")
"a#q.x.y.z|haml" ("%a#q.x.y.z")
"a#q.x[x=y m=l]|haml" ("%a#q.x{:x => \"y\", :m => \"l\"}")
"div|haml" ("%div")
"div.footer|haml" (".footer")
".footer|haml" (".footer")
"p>{This is haml}*2+a[href=#]+br|haml"
("%p"
" This is haml"
" This is haml"
" %a{:href => \"#\"}"
" %br"))
(define-emmet-transform-html-test-case Filter-Hiccup
"a|hic" ("[:a]")
"a#q.x.y.z|hic" ("[:a#q.x.y.z]")
"a#q.x[x=y m=l]|hic" ("[:a#q.x {:x \"y\", :m \"l\"}]")
".footer|hic" ("[:div.footer]")
"p>a[href=#]+br|hic" ("[:p"
" [:a {:href \"#\"}]"
" [:br]]")
"#q>(a*2>b{x})+p>{m}+b|hic"
("[:div#q"
" [:a [:b \"x\"]]"
" [:a [:b \"x\"]]"
" [:p"
" \"m\""
" [:b]]]"))
(define-emmet-transform-html-test-case Filter-escape
"script[src="]|e" ("<script src=\""\"></script>"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CSS-abbrev tests
(define-emmet-unit-test-case CSS-toknize
#'emmet-css-toknize
"" ("")
"abc" ("abc")
"abc+" ("abc+")
"abc+cde" ("abc" "cde")
"abc++cde" ("abc+" "cde")
"abc+cde+" ("abc" "cde+")
"abc++cde+" ("abc+" "cde+")
"ab:c+0p0x#aa+p0+cde+" ("ab:c+0p0x#aa" "p0" "cde+")
"ab+#0+p+#c+x++cde+" ("ab+#0" "p+#c" "x+" "cde+")
"abc def" ("abc def")
"-abc+-xyz" ("-abc" "-xyz")
"-abc+-10" ("-abc+-10"))
(define-emmet-unit-test-case CSS-parse-arg-number
#'emmet-css-arg-number
"" (error "expected css number arguments")
"0" (("0" "px") . "")
"0-1-2" (("0" "px") . "1-2")
"-100" (("-100" "px") . "")
"-10e-20" (("-10" "em") . "-20")
"35p#a" (("35" "%") . "#a")
" 0p" (("0" "%") . ""))
(define-emmet-unit-test-case CSS-parse-arg-color
#'emmet-css-arg-color
"" (error "expected css color argument")
"abc" (error "expected css color argument")
"#x" (error "expected css color argument")
"#a" ("#aaa" . "")
"#09" ("#090909" . "")
"#3D5-2" ("#3D5" . "-2")
"#1a2B-3" ("#1a2B1a" . "-3")
"#1A2b3x" ("#1A2b31" . "x")
"#1a2B3Cx" ("#1a2B3C" . "x")
"#1A2B3C4D-2" ("#1A2B3C" . "4D-2")
" #abc" ("#abc" . ""))
(define-emmet-unit-test-case CSS-parse-arg-something
#'emmet-css-arg-something
"" (error "expected css argument")
"abc" ("abc" . "")
"abc def" ("abc" . " def")
"url(http://abc.com) auto" ("url(http://abc.com)" . " auto"))
(define-emmet-unit-test-case CSS-parse-args
#'emmet-css-parse-args
"" nil
"1-2--3-4" (("1" "px") ("2" "px") ("-3" "px") ("4" "px"))
"-10-2p-30#abc" (("-10" "px") ("2" "%") ("-30" "px") "#abc")
"1p2x3-4e5x" (("1" "%") ("2" "ex") ("3" "px") ("4" "em") ("5" "ex"))
"#abc#de#f-3" ("#abc" "#dedede" "#fff" ("-3" "px")))
(define-emmet-unit-test-case CSS-split-vendor-prefixes
#'emmet-css-split-vendor-prefixes
"" ("" nil)
"-abc" ("abc" auto)
"-wmso-abc" ("abc" (119 109 115 111)))
(define-emmet-unit-test-case CSS-exprs
#'emmet-css-expr
"" (("" nil nil))
"cl:l+ov:h+bg+" (("cl:l" nil nil) ("ov:h" nil nil) ("bg+" nil nil))
"m10-auto!" (("m" nil t ("10" "px") "auto"))
"bg++c!" (("bg+" nil nil) ("c" nil t))
"m+0-10-10--20!+p0-0" (("m+" nil t ("0" "px") ("10" "px") ("10" "px") ("-20" "px"))
("p" nil nil ("0" "px") ("0" "px")))
"bg+#abc#bc#c-3!" (("bg+" nil t "#abc" "#bcbcbc" "#ccc" ("-3" "px"))))
(defmacro define-emmet-transform-css-test-case (name &rest tests)
`(define-emmet-transform-test-case ,name
'emmet-css-transform
,@tests))
(define-emmet-transform-css-test-case CSS-transform
;; supplying values with units
"m10" ("margin: 10px;")
"m1.5" ("margin: 1.5em;")
"m1.5ex" ("margin: 1.5ex;")
"m1.5x" ("margin: 1.5ex;")
"m10foo" ("margin: 10foo;")
"m10ex20em" ("margin: 10ex 20em;")
"m10x20e" ("margin: 10ex 20em;")
"m10x-5" ("margin: 10ex -5px;")
;; Color values
"c#3" ("color: #333;")
"bd5#0rgb" ("border: 5px rgb(0,0,0);")
"bd5#20rgb" ("border: 5px rgb(32,32,32);")
"bd5#0s" ("border: 5px #000 solid;")
"bd5#2rgbs" ("border: 5px rgb(34,34,34) solid;")
;; Unitless property
"lh2" ("line-height: 2;")
"fw400" ("font-weight: 400;")
;;
"m0+p0-1p2e3x" ("margin: 0px;"
"padding: 0px 1% 2em 3ex;")
"p!+m10e!+f" ("padding: !important;"
"margin: 10em !important;"
"font: ;")
"fs" ("font-style: italic;")
"xxxxxx 0 auto 0e auto!" ("xxxxxx: 0px auto 0em auto !important;")
"p auto+m auto+bg+#F00 x.jpg 10 10 repeat-x"
("padding: auto;"
"margin: auto;"
"background: #F00 url(x.jpg) 10px 10px repeat-x;")
"-bdrs" ("-webkit-border-radius: ;"
"-moz-border-radius: ;"
"border-radius: ;")
"-super-foo" ("-webkit-super-foo: ;"
"-moz-super-foo: ;"
"-ms-super-foo: ;"
"-o-super-foo: ;"
"super-foo: ;")
"-wm-trf" ("-webkit-transform: ;"
"-moz-transform: ;"
"transform: ;")
"@m print 1" ("@media print {"
" 1px"
"}")
"@i http://github.com/smihica/index.css"
("@import url(http://github.com/smihica/index.css);")
)
;; lorem generator test
(let ((name "Lorem-generator"))
(princ
(if (or (not (string-equal (emmet-lorem-generate 0) ""))
(not (= (length (split-string (emmet-lorem-generate 1) " ")) 1))
(not (= (length (split-string (emmet-lorem-generate 22) " ")) 22))
(not (= (length (split-string (emmet-lorem-generate 99) " ")) 99))
(not (= (length (split-string (emmet-lorem-generate 1000) " ")) 1000)))
(concat "*** [FAIL] | \"" name "\".\n")
(concat " [PASS] | \"" name "\" 5 tests.\n"))))
;; Inline tag expansion within HTML/XML markup (regression test)
(defun emmet-inline-expansion-test (lis)
"Tests inline expansion of emmet forms nested inside markup."
(let ((es (car lis))
(emmet-preview-default nil)
(emmet-indent-after-insert t))
(with-temp-buffer
(emmet-mode 1)
(insert "")
(backward-char 6)
(insert es)
(emmet-expand-line nil)
(buffer-string))))
(emmet-run-test-case "Inline Expansion"
#'emmet-inline-expansion-test
'((("span#test") . "
")))
;; indent
;; NOTE: Indent uses indent-region by default,
;; and inserts spaces based on emmet-indentation
;; if emmet-indent-after-insert is nil
(defun emmet-indent-test (lis)
(let ((es (car lis))
(emmet-preview-default nil)
(indent-tabs-mode nil)
(tab-width 2)
(standard-indent 2))
(with-temp-buffer
(emmet-mode 1)
(sgml-mode)
(insert es)
(emmet-expand-line nil)
(buffer-string))))
(let ((emmet-indent-after-insert t))
(emmet-run-test-case "Indentation via indent-region"
#'emmet-indent-test
'((("div>ul>li*3") . ""))))
(let ((emmet-indent-after-insert nil)
(emmet-indentation 2))
(emmet-run-test-case "Indentation via emmet-indentation"
#'emmet-indent-test
'((("div>ul>li*3") . ""))))
;; Old tests for previous indent behavior last seen:
;; commit: f56174e5905a40583b47f9737abee3af8da3faeb
;; start
(emmet-test-cases)