;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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+" ("" "
    " "
  1. " "
") "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=\"&quot;\"></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") . "
\n
    \n
  • \n
  • \n
  • \n
\n
")))) (let ((emmet-indent-after-insert nil) (emmet-indentation 2)) (emmet-run-test-case "Indentation via emmet-indentation" #'emmet-indent-test '((("div>ul>li*3") . "
\n
    \n
  • \n
  • \n
  • \n
\n
")))) ;; Old tests for previous indent behavior last seen: ;; commit: f56174e5905a40583b47f9737abee3af8da3faeb ;; start (emmet-test-cases)