X-Git-Url: http://git.hcoop.net/clinton/parenscript.git/blobdiff_plain/cdf9ab0e8107d306244a3c10ee02b10ce4d8c629..cb8f8e58295db370220ad7c2f0f3d8d48fdc2442:/t/ps-tests.lisp diff --git a/t/ps-tests.lisp b/t/ps-tests.lisp index a2328a0..1dbe3ff 100644 --- a/t/ps-tests.lisp +++ b/t/ps-tests.lisp @@ -1,5 +1,6 @@ (in-package :ps-test) -;; Other tests not in the reference + +;;; Hand-written unit tests (eval-when (:compile-toplevel :load-toplevel :execute) (def-suite ps-tests)) @@ -14,20 +15,19 @@ "x += 'middle' + 'after';") (test-ps-js setf-side-effects - (progn - (let ((x 10)) - (defun side-effect() - (setf x 4) - (return 3)) - (setf x (+ 2 (side-effect) x 5)))) - " -var x = 10; + (progn + (let* ((x 10)) + (defun side-effect() + (setf x 4) + (return 3)) + (setf x (+ 2 (side-effect) x 5)))) + "var x = 10; function sideEffect() { x = 4; return 3; }; x = 2 + sideEffect() + x + 5;") -;; Parenscript used to optimize to much: +;; Parenscript used to optimize too much: ;; var x = 10; ;; function sideEffect() { ;; x = 4; @@ -47,7 +47,7 @@ x = 2 + sideEffect() + x + 5;") (test-ps-js method-call-string (.to-string "hi") "'hi'.toString()") (test-ps-js method-call-lit-object (.to-string (create :to-string (lambda () - (return "it works")))) + (return "it works")))) "( { toString : function () { return 'it works'; } } ).toString()") (test-ps-js method-call-variable @@ -65,47 +65,29 @@ x = 2 + sideEffect() + x + 5;") "( function () { alert(10); } ).toString()") (test-ps-js method-call-lambda-call (.to-string ((lambda (x) (return x)) 10)) - "(function (x) { return x; }) (10).toString()") + "(function (x) { return x; })(10).toString()") (test no-whitespace-before-dot - (let* ((str (compile-script '(.to-string ((lambda (x) (return x)) 10)))) + (let* ((str (ps1* '(.to-string ((lambda (x) (return x)) 10)))) (dot-pos (position #\. str :test #'char=)) (char-before (elt str (1- dot-pos))) (a-parenthesis #\))) (is (char= char-before a-parenthesis)))) -;; A problem with long nested operator, when the statement spanned several rows -;; the rows would not be joined together correctly. -(test-ps-js bug-dwim-join - (alert (html ((:div :id 777 - :style (css-inline :border "1pxsssssssssss" - :font-size "x-small" - :height (* 2 200) - :width (* 2 300)))))) - "alert -('
')") ;";This line should start with a plus character. - - (test-ps-js simple-slot-value - (let ((foo (create :a 1))) - (alert (slot-value foo 'a))) - "{ - var foo = { a : 1 }; - alert(foo.a); - }") + (let* ((foo (create :a 1))) + (alert (slot-value foo 'a))) + "var foo = { a : 1 }; + alert(foo.a);") (test-ps-js buggy-slot-value - (let ((foo (create :a 1)) - (slot-name "a")) + (let* ((foo (create :a 1)) + (slot-name "a")) (alert (slot-value foo slot-name))) - "{ - var foo = { a : 1 }; + " var foo = { a : 1 }; var slotName = 'a'; alert(foo[slotName]); - }"); Last line was alert(foo.slotName) before bug-fix. + "); Last line was alert(foo.slotName) before bug-fix. (test-ps-js buggy-slot-value-two (slot-value foo (get-slot-name)) @@ -150,7 +132,7 @@ x = 2 + sideEffect() + x + 5;") (3 (alert "Three")) (t (alert "Something else"))) "switch (blorg[i]) { - case 1: ; + case 1: case 2: alert('Below three'); break; @@ -184,11 +166,9 @@ x = 2 + sideEffect() + x + 5;") ("u0080" . ,(code-char 128)) ;;Character over 127. Actually valid, parenscript escapes them to be sure. ("uABCD" . ,(code-char #xabcd)))));; Really above ascii. (loop for (js-escape . lisp-char) in escapes - for generated = (compile-script `(let ((x ,(format nil "hello~ahi" lisp-char))))) - for wanted = (format nil "{ - var x = 'hello\\~ahi'; -}" js-escape) - do (is (string= generated wanted))))) + for generated = (ps1* `(let* ((x ,(format nil "hello~ahi" lisp-char))))) + for wanted = (format nil "var x = 'hello\\~ahi';" js-escape) + do (is (string= (normalize-js-code generated) wanted))))) (test-ps-js complicated-symbol-name1 grid-rows[foo].bar @@ -211,10 +191,10 @@ x = 2 + sideEffect() + x + 5;") "(!zoo ? foo : bar).x") (test script-star-eval1 - (is (string= "x = 1; y = 2;" (normalize-js-code (script* '(setf x 1) '(setf y 2)))))) + (is (string= "x = 1; y = 2;" (normalize-js-code (ps* '(setf x 1) '(setf y 2)))))) (test script-star-eval2 - (is (string= "x = 1;" (normalize-js-code (script* '(setf x 1)))))) + (is (string= "x = 1;" (normalize-js-code (ps* '(setf x 1)))))) (test-ps-js slot-value-null1 (slot-value foo nil) @@ -238,21 +218,434 @@ x = 2 + sideEffect() + x + 5;") (test defsetf1 (ps (defsetf baz (x y) (newval) `(set-baz ,x ,y ,newval))) - (is (string= "var PS_GS_2 = 1; var PS_GS_3 = 2; var PS_GS_1 = 3; setBaz(PS_GS_2, PS_GS_3, PS_GS_1);" - (normalize-js-code (let ((ps::*gen-script-name-counter* 0)) + (is (string= "var _js2 = 1; var _js3 = 2; var _js1 = 3; setBaz(_js2, _js3, _js1);" + (normalize-js-code (let* ((ps:*ps-gensym-counter* 0)) (ps (setf (baz 1 2) 3))))))) (test defsetf-short (ps (defsetf baz set-baz "blah")) (is (string= "setBaz(1, 2, 3, 'foo');" (normalize-js-code (ps (setf (baz 1 2 3) "foo")))))) +(test defun-setf1 + (is (and (string= (normalize-js-code (ps:ps (defun (setf some-thing) (new-val i1 i2) + (setf (aref *some-thing* i1 i2) new-val)))) + "function __setf_someThing(newVal, i1, i2) { SOMETHING[i1][i2] = newVal; };") + (string= (normalize-js-code (ps:ps-doc (setf (some-thing 1 2) "foo"))) + "var _js2 = 1; var _js3 = 2; var _js1 = 'foo'; __setf_someThing(_js1, _js2, _js3);")))) + (test-ps-js defun-optional1 (defun test-opt (&optional x) (return (if x "yes" "no"))) "function testOpt(x) { - x = undefined === x && null || x; - return x ? 'yes' : 'no'; + if (x === undefined) { + x = null; + }; + return x ? 'yes' : 'no'; +}") + +(test-ps-js defun-optional2 + (defun foo (x &optional y) (+ x y)) + "function foo(x, y) { + if (y === undefined) { + y = null; + }; + x + y; +}") + +(test-ps-js defun-optional3 + (defun blah (&optional (x 0)) + (return x)) + "function blah(x) { + if (x === undefined) { + x = 0; + }; + return x; }") (test-ps-js return-nothing (return) "return null") + +(test-ps-js set-timeout + (do-set-timeout (10) (alert "foo")) + "setTimeout(function () { alert('foo'); }, 10)") +(test-ps-js operator-precedence + (* 3 (+ 4 5) 6) + "3 * (4 + 5) * 6") + +(test-ps-js operators-1 + (in prop obj) + "prop in obj") + +(test-ps-js incf1 + (incf foo bar) + "foo += bar") + +(test-ps-js decf1 + (decf foo bar) + "foo -= bar") + +(test-ps-js incf2 + (incf x 5) + "x += 5") + +(test-ps-js decf2 + (decf y 10) + "y -= 10") + +(test-ps-js setf-conditional + (setf foo (if x 1 2)) + "foo = x ? 1 : 2;") + +(test-ps-js obj-literal-numbers + (create 1 "foo") + "{ 1 : 'foo' }") + +(test-ps-js obj-literal-strings + (create "foo" 2) + "{ 'foo' : 2 }") + +(test-ps-js slot-value-string + (slot-value foo "bar") + "foo['bar']") + +(test-ps-js slot-value-progn + (slot-value (progn (some-fun "abc") "123") "length") + "(someFun('abc'), '123')['length']") + +(test-ps-js method-call-block + (.to-string (progn (some-fun "abc") "123")) + "(someFun('abc'), '123').toString()") + +(test-ps-js create-blank + (create) + "{ }") + +(test-ps-js blank-object-literal + {} + "{ }") + +(test-ps-js object-literal-1 + ({}) + "{ }") + +(test-ps-js object-literal-2 + ({} a 1 b 2) + "{a: 1, b: 2 }") + +(test-ps-js array-literal1 + [] + "[]") + +(test-ps-js array-literal2 + ([]) + "[]") + +(test-ps-js array-literal3 + ([] 1 2 3) + "[1, 2, 3]") + +(test-ps-js array-literal4 + ([] 1 (2 3)) + "[1, [2, 3]]") + +(test-ps-js array-literal5 + ([] (1 2) ("a" "b")) + "[[1, 2], ['a', 'b']]") + +(test-ps-js defun-rest1 + (defun foo (&rest bar) (alert bar[1])) + "function foo() { + var bar = []; + for (var i2 = 0; i2 < arguments.length - 0; i2 += 1) { + bar[i2] = arguments[i2 + 0]; + }; + alert(bar[1]); +}") + +(test-ps-js defun-rest2 + (defun foo (baz &rest bar) (return (+ baz (aref bar 1)))) + "function foo(baz) { + var bar = []; + for (var i2 = 0; i2 < arguments.length - 1; i2 += 1) { + bar[i2] = arguments[i2 + 1]; + }; + return baz + bar[1]; +}") + +(test-ps-js defun-keyword1 + (defun zoo (foo bar &key baz) (return (+ foo bar baz))) + "function zoo(foo, bar, _js1) { + if (_js1 === undefined) { + _js1 = { }; + }; + return foo + bar + _js1.baz; +}") + +(test-ps-js defun-keyword2 + (defun zoo (&key baz) (return (* baz baz))) + "function zoo(_js1) { + if (_js1 === undefined) { + _js1 = { }; + }; + return _js1.baz * _js1.baz; +}") + +(test-ps-js defun-keyword3 + (defun zoo (&key baz (bar 4)) (return (* baz bar))) + "function zoo(_js1) { + if (_js1 === undefined) { + _js1 = { }; + }; + if (_js1.bar === undefined) { + _js1.bar = 4; + }; + return _js1.baz * _js1.bar; +}") + +(test-ps-js keyword-funcall1 + (func :baz 1) + "func({ baz : 1 })") + +(test-ps-js keyword-funcall2 + (func :baz 1 :bar foo) + "func({ baz : 1, bar : foo })") + +(test-ps-js keyword-funcall3 + (fun a b :baz c) + "fun(a, b, { baz : c })") + +(test-ps-js cond1 + (cond ((= x 1) 1)) + "if (x == 1) { + 1; +}") + +(test-ps-js cond2 + (cond ((= x 1) 2) ((= y (* x 4)) (foo "blah") (* x y))) + "if (x == 1) { + 2; +} else if (y == x * 4) { + foo('blah'); + x * y; +}") + +(test-ps-js if-exp-without-else-returns-null + (return (if x 1)) + "return x ? 1 : null") + +(test-ps-js progn-expression-single-statement + (return (progn (* x y))) + "return x * y") + +(test-ps-js cond-expression1 + (defun foo () (return (cond ((< 1 2) (bar "foo") (* 4 5))))) + "function foo() { + return 1 < 2 ? (bar('foo'), 4 * 5) : null; +}") + +(test-ps-js cond-expression2 + (defun foo () (return (cond ((< 2 1) "foo") ((= 7 7) "bar")))) + "function foo() { + return 2 < 1 ? 'foo' : (7 == 7 ? 'bar' : null); +}") + +(test-ps-js cond-expression-final-t-clause + (defun foo () (return (cond ((< 1 2) (bar "foo") (* 4 5)) ((= a b) (+ c d)) ((< 1 2 3 4 5) x) (t "foo")))) + "function foo() { + return 1 < 2 ? (bar('foo'), 4 * 5) : (a == b ? c + d : (1 < 2 < 3 < 4 < 5 ? x : 'foo')); +}") + +(test-ps-js cond-expression-middle-t-clause ;; should this signal a warning? + (defun foo () (return (cond ((< 2 1) 5) (t "foo") ((< 1 2) "bar")))) + "function foo() { + return 2 < 1 ? 5 : 'foo'; +}") + +(test-ps-js funcall-if-expression + (document.write + (if (= *linkornot* 1) + (ps-html ((:a :href "#" + :onclick (lisp (ps-inline (transport)))) + img)) + img)) + "document.write(LINKORNOT == 1 ? '' + img + '' : img)") + +(test-ps-js negate-number-literal ;; ok, this was broken and fixed before, but no one bothered to add the test! + (- 1) + "-1") + +(test macro-environment1 + (is (string= (normalize-js-code (let* ((macroname (gensym))) + (ps* `(defmacro ,macroname (x) `(+ ,x 123)) + `(defun test1 () + (macrolet ((,macroname (x) `(aref data ,x))) + (when (,macroname x) + (setf (,macroname x) 123))))))) + (normalize-js-code +"function test1() { + if (data[x]) { + data[x] = 123; + }; +}; +")))) + +(test-ps-js ampersand-whole-1 + (macrolet ((foo (&whole foo bar baz) + (declare (ignore bar baz)) + (format nil "~a" foo))) + (foo 1 2)) + "'(FOO 1 2)';") + +(test-ps-js keyword-consistent + :x + "'x'") + +(test-ps-js simple-symbol-macrolet + (symbol-macrolet ((x 1)) x) + "1;") + +(test-ps-js compound-symbol-macrolet + (symbol-macrolet ((x 123) + (y (* 2 x))) + y) + "2 * 123;") + +(test-ps-js define-symbol-macro + (progn (define-symbol-macro tst-sym-macro 2) + tst-sym-macro) + "2;") + +(test-ps-js expression-progn + (defun f () (return (progn (foo) (if x 1 2)))) + "function f() { + return (foo(), x ? 1 : 2); +}") + +(test-ps-js let-decl-in-expression + (defun f (x) (return (if x 1 (let* ((foo x)) foo)))) + "function f(x) { + var foo; + return x ? 1 : (foo = x, foo); +}") + +(test-ps-js special-var1 + (progn (defvar *foo*) (let* ((*foo* 2)) (* *foo* 2))) + "var FOO; +var tempstackvar1; +try { + tempstackvar1 = FOO; + FOO = 2; + FOO * 2; +} finally { + FOO = tempstackvar1; + delete tempstackvar1; +};") + +(test-ps-js special-var2 + (progn (defvar *foo*) (let* ((*baz* 3) (*foo* 2)) (* *foo* 2 *baz*))) + "var FOO; +var BAZ = 3; +var tempstackvar1; +try { + tempstackvar1 = FOO; + FOO = 2; + FOO * 2 * BAZ; +} finally { + FOO = tempstackvar1; + delete tempstackvar1; +}; +") + +(test-ps-js literal1 + (setf x undefined) + "x = undefined;") + +(test-ps-js literal2 + (aref this x) + "this[x]") + +(test-ps-js setf-dec1 + (setf x (- 1 x 2)) + "x = 1 - x - 2;") + +(test-ps-js setf-dec2 + (setf x (- x 1 2)) + "x = x - 1 - 2;") + +(test-ps-js special-char-equals + blah= + "blahequals") + +(test-ps-js setf-operator-priority + (return (or (slot-value cache id) + (setf (slot-value cache id) (document.get-element-by-id id)))) + "return cache[id] || (cache[id] = document.getElementById(id))") + +(test-ps-js aref-operator-priority + (aref (if (and x (> (length x) 0)) + (aref x 0) + y) + z) + "(x && x.length > 0 ? x[0] : y)[z]") + +(test-ps-js aref-operator-priority1 + (aref (or (slot-value x 'y) + (slot-value a 'b)) + z) + "(x.y || a.b)[z]") + +(test-ps-js aref-operator-priority2 + (aref (if a b c) 0) + "(a ? b : c)[0]") + +(test-ps-js negative-operator-priority + (- (if x y z)) + "-(x ? y : z)") + +(test-ps-js op-p1 + (new (or a b)) + "new (a || b)") + +(test-ps-js op-p2 + (delete (if a (or b c) d)) + "delete (a ? b || c : d)") + +(test-ps-js op-p3 + (not (if (or x (not y)) z)) + "!(x || !y ? z : null)") + +(test-ps-js op-p4 + (- (- (* 1 2) 3)) + "-(1 * 2 - 3)") + +(test-ps-js op-p5 + (instanceof (or a b) (if x y z)) + "((a || b) instanceof (x ? y : z))") + +(test-ps-js op-p6 + (doeach (x (or a b))) + "for (var x in (a || b)) { };") + +(test-ps-js op-p7 + (or x (if (= x 0) "zero" "empty")) + "x || (x == 0 ? 'zero' : 'empty')") + +(test-ps-js named-op-expression + (throw (if a b c)) + "throw a ? b : c") + +(test-ps-js named-op-expression1 + (typeof (or x y)) + "typeof (x || y)") + +(test-ps-js aref-array-expression + (aref (or a b c) 0) + "(a || b || c)[0]") + +(test-ps-js slot-value-operator + (slot-value (or a b c) 'd) + "(a || b || c).d") + +(test-ps-js slot-value-parens + (slot-value (slot-value foo 'bar) 'baz) + "foo.bar.baz")