3 (:export
#:run-all-tests
))
4 (defpackage :domtest-tests
9 ;;;; allgemeine Hilfsfunktionen
11 (defmacro string-case
(keyform &rest clauses
)
12 (let ((key (gensym "key")))
13 `(let ((,key
,keyform
))
14 (declare (ignorable ,key
))
17 for
(keys . forms
) in clauses
18 for test
= (etypecase keys
19 (string `(string= ,key
,keys
))
20 (sequence `(find ,key
',keys
:test
'string
=))
25 (defun rcurry (function &rest args
)
26 (lambda (&rest more-args
)
27 (apply function
(append more-args args
))))
29 (defmacro for
((&rest clauses
) &rest body-forms
)
30 `(%for
,clauses
(progn ,@body-forms
)))
32 (defmacro for
* ((&rest clauses
) &rest body-forms
)
33 `(%for
* ,clauses
(progn ,@body-forms
)))
35 (defmacro %for
((&rest clauses
) body-form
&rest finally-forms
)
36 (for-aux 'for clauses body-form finally-forms
))
38 (defmacro %for
* ((&rest clauses
) body-form
&rest finally-forms
)
39 (for-aux 'for
* clauses body-form finally-forms
))
41 (defmacro for-finish
()
44 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
45 (defun for-aux (kind clauses body-form finally-forms
)
46 ` (loop ,@ (loop for firstp
= t then nil
47 for %clauses
= clauses then
(rest %clauses
)
48 for clause
= (first %clauses
) then
(first %clauses
)
49 while
(and %clauses
(listp clause
))
50 append
(cons (ecase kind
51 (for (if firstp
'as
'and
))
53 (if (= 2 (length clause
))
54 (list (first clause
) '= (second clause
))
57 finally
(return (append result %clauses
)))
59 finally
(progn ,@finally-forms
))))
62 ;;;; spezielle Hilfsfunktionen
65 (runes:rod-string
(dom:tag-name elt
)))
67 (defmacro with-attributes
((&rest attributes
) element
&body body
)
68 (let ((e (gensym "element")))
70 ,@(mapcar (lambda (var)
71 `(,var
(dom:get-attribute
,e
,(symbol-name var
))))
75 (defun map-child-elements (result-type fn element
&key name
)
79 (if (and (eq (dom:node-type node
) :element
)
81 (equal (tag-name node
) name
)))
84 (dom:child-nodes element
))))
86 (defmacro do-child-elements
((var element
&key name
) &body body
)
88 (map-child-elements nil
(lambda (,var
) ,@body
) ,element
:name
,name
)))
90 (defun find-child-element (name element
)
91 (do-child-elements (child element
:name name
)
95 (unless (stringp name
)
96 (setf name
(runes:rod-string name
)))
97 (if (zerop (length name
))
99 (intern name
:domtest-tests
)))
101 (defun replace-studly-caps (str)
102 (unless (stringp str
)
103 (setf str
(runes:rod-string str
)))
104 ;; s/([A-Z][a-z])/-\1/
105 (with-output-to-string (out)
106 (with-input-from-string (in str
)
107 (for ((c = (read-char in nil nil
))
108 (previous = nil then c
)
109 (next = (peek-char nil in nil nil
))
112 (upper-case-p c
) next
(lower-case-p next
)
113 (not (lower-case-p previous
)))
114 (write-char #\- out
))
115 (write-char (char-downcase c
) out
)
116 (when (and (lower-case-p c
) next
(upper-case-p next
))
117 (write-char #\- out
))))))
119 (defun intern-dom (name)
120 (setf name
(replace-studly-caps name
))
122 (setf name
(string-upcase name
)))
125 (defun child-elements (element)
126 (map-child-elements 'list
#'identity element
))
128 (defun parse-java-literal (str)
130 (setf str
(runes:string-rod str
)))
132 ((zerop (length str
)) nil
)
133 ((runes:rod
= str
#"true")
135 ((runes:rod
= str
#"false")
137 ((digit-char-p (runes:rune-char
(elt str
0)))
138 (parse-integer (runes:rod-string str
)))
139 ((runes:rune
= (elt str
0) #.
(runes:char-rune
#\"))
140 (let ((v (make-array 1 :fill-pointer
0 :adjustable t
)))
141 (for* ((i = 1 :then
(1+ i
))
143 :until
(runes:rune
= c
#.
(runes:char-rune
#\")))
144 (if (runes:rune
= c
#.
(runes:char-rune
#\\))
151 (#/n
(vector-push-extend #/newline v
(length v
)))
152 ((#/\\ #/\") (vector-push-extend #/\\ v
(length v
)))))
153 (vector-push-extend c v
(length v
))))
154 (make-array (length v
) :element-type
'runes
:rune
:initial-contents v
)))
158 (defun maybe-setf (place form
)
164 (if (zerop (length str
)) nil str
))
167 ;;;; dom1-interfaces.xml auslesen
169 (defparameter *methods
* '())
170 (defparameter *fields
* '())
172 (declaim (special *directory
*))
173 (declaim (special *files-directory
*))
175 (defun read-members (&optional
(directory *directory
*))
176 (let* ((pathname (merge-pathnames "build/dom2-interfaces.xml" directory
))
177 (builder (rune-dom:make-dom-builder
))
178 (library (dom:document-element
179 (cxml:parse-file pathname builder
:recode nil
)))
182 (do-child-elements (interface library
:name
"interface")
183 (do-child-elements (method interface
:name
"method")
184 (let ((parameters (find-child-element "parameters" method
)))
185 (push (cons (dom:get-attribute method
"name")
186 (map-child-elements 'list
187 (rcurry #'dom
:get-attribute
"name")
191 (do-child-elements (attribute interface
:name
"attribute")
192 (push (dom:get-attribute attribute
"name") fields
)))
193 (values methods fields
)))
196 ;;;; Conditions uebersetzen
198 (defun translate-condition (element)
199 (string-case (tag-name element
)
200 ("equals" (translate-equals element
))
201 ("notEquals" (translate-not-equals element
))
202 ("contentType" (translate-content-type element
))
203 ("implementationAttribute" (assert-have-implementation-attribute element
))
204 ("isNull" (translate-is-null element
))
205 ("not" (translate-is-null element
))
206 ("notNull" (translate-not-null element
))
207 ("or" (translate-or element
))
208 ("same" (translate-same element
))
209 ("less" (translate-less element
))
210 (t (error "unknown condition: ~A" element
))))
212 (defun equalsp (a b test
)
213 (when (dom:named-node-map-p a
)
214 (setf a
(dom:items a
)))
215 (when (dom:named-node-map-p b
)
216 (setf b
(dom:items b
)))
217 (if (and (typep a
'sequence
) (typep b
'sequence
))
218 (null (set-exclusive-or (coerce a
'list
) (coerce b
'list
) :test test
))
222 (or (equal a b
) (and (runes::rodp a
) (runes::rodp b
) (runes:rod
= a b
))))
225 (or (equalp a b
) (and (runes::rodp a
) (runes::rodp b
) (runes:rod-equal a b
))))
227 (defun translate-equals (element)
228 (with-attributes (|actual| |expected| |ignoreCase|
) element
229 `(equalsp ,(%intern |actual|
)
230 ,(parse-java-literal |expected|
)
231 ',(if (parse-java-literal |ignoreCase|
) '%equal
'%equal
))))
233 (defun translate-not-equals (element)
234 `(not ,(translate-equals element
)))
236 (defun translate-same (element)
237 (with-attributes (|actual| |expected|
) element
238 `(eql ,(%intern |actual|
) ,(parse-java-literal |expected|
))))
240 (defun translate-less (element)
241 (with-attributes (|actual| |expected|
) element
242 `(< ,(%intern |actual|
) ,(parse-java-literal |expected|
))))
244 (defun translate-or (element)
245 `(or ,@(map-child-elements 'list
#'translate-condition element
)))
247 (defun translate-instance-of (element)
248 (with-attributes (|obj| |type|
) element
249 `(eq (dom:node-type
,(%intern |obj|
))
250 ',(string-case (runes:rod-string |type|
)
251 ("Document" :document
)
252 ("DocumentFragment" :document-fragment
)
255 ("CDATASection" :cdata-section
)
258 ("DocumentType" :document-type
)
259 ("Notation" :notation
)
261 ("EntityReference" :entity-reference
)
262 ("ProcessingInstruction" :processing-instruction
)
263 (t (error "unknown interface: ~A" |type|
))))))
265 (defun translate-is-null (element)
266 (with-attributes (|obj|
) element
267 `(null ,(%intern |obj|
))))
269 (defun translate-not-null (element)
270 (with-attributes (|obj|
) element
273 (defun translate-content-type (element) ;XXX verstehe ich nicht
274 (with-attributes (|type|
) element
275 `(equal ,|type|
"text/xml")))
277 (defun translate-uri-equals (element)
280 |scheme| |path| |host| |file| |name| |query| |fragment| |isAbsolute|
)
283 `(let ((uri (net.uri
:parse-uri
(runes:rod-string
,(%intern |actual|
)))))
284 (flet ((uri-directory (path)
286 (make-pathname :directory
(pathname-directory path
))))
288 (namestring (make-pathname :name
(pathname-name path
)
289 :type
(pathname-type path
))))
291 (pathname-name path
))
292 (maybe-equal (expected actual
)
294 (%equal
(runes::rod expected
) (runes::rod actual
))
296 (and (maybe-equal ,(parse-java-literal |scheme|
)
297 (net.uri
:uri-scheme uri
))
298 (maybe-equal ,(parse-java-literal |host|
)
299 (net.uri
:uri-host uri
))
300 (maybe-equal ,(parse-java-literal |path|
)
301 (uri-directory (net.uri
:uri-path uri
)))
302 (maybe-equal ,(parse-java-literal |file|
)
303 (uri-file (net.uri
:uri-path uri
)))
304 (maybe-equal ,(parse-java-literal |name|
)
305 (uri-name (net.uri
:uri-path uri
)))
306 (maybe-equal ,(parse-java-literal |query|
)
307 (net.uri
:uri-query uri
))
308 (maybe-equal ,(parse-java-literal |fragment|
)
309 (net.uri
:uri-fragment uri
)))))))
312 ;;;; Statements uebersetzen
314 (defun translate-statement (element)
315 (string-case (tag-name element
)
316 ("append" (translate-append element
))
317 ("assertDOMException" (translate-assert-domexception element
))
318 ("assertEquals" (translate-assert-equals element
))
319 ("assertNotNull" (translate-assert-not-null element
))
320 ("assertInstanceOf" (translate-assert-instance-of element
))
321 ("assertNull" (translate-assert-null element
))
322 ("assertSame" (translate-assert-same element
))
323 ("assertSize" (translate-assert-size element
))
324 ("assertTrue" (translate-assert-true element
))
325 ("assertFalse" (translate-assert-false element
))
326 ("assertURIEquals" (translate-assert-uri-equals element
))
327 ("assign" (translate-assign element
))
328 ("for-each" (translate-for-each element
))
329 ("fail" (translate-fail element
))
330 ("hasFeature" (translate-has-feature element
))
331 ("if" (translate-if element
))
332 ("implementation" (translate-implementation element
))
333 ("increment" (translate-unary-assignment '+ element
))
334 ("decrement" (translate-unary-assignment '- element
))
335 ("length" (translate-length element
))
336 ("load" (translate-load element
))
337 ("nodeType" (translate-node-type element
))
338 ("plus" (translate-binary-assignment '+ element
))
339 ("try" (translate-try element
))
340 ("while" (translate-while element
))
341 (t (translate-member element
))))
343 (defun translate-binary-assignment (fn element
)
344 (with-attributes (|var| |op1| |op2|
) element
345 (maybe-setf (%intern |var|
)
346 `(,fn
,(parse-java-literal |op1|
)
347 ,(parse-java-literal |op2|
)))))
349 (defun translate-assign (element)
350 (with-attributes (|var| |value|
) element
351 (maybe-setf (%intern |var|
) (parse-java-literal |value|
))))
353 (defun translate-unary-assignment (fn element
)
354 (with-attributes (|var| |value|
) element
355 (maybe-setf (%intern |var|
)
356 `(,fn
,(%intern |var|
) ,(parse-java-literal |value|
)))))
358 (defun translate-load (load)
359 (with-attributes (|var| |href| |willBeModified|
) load
360 (maybe-setf (%intern |var|
)
361 `(load-file ,|href|
,(parse-java-literal |willBeModified|
)))))
363 (defun translate-implementation (elt)
364 (with-attributes (|var|
) elt
365 (maybe-setf (%intern |var|
) `'rune-dom
:implementation
)))
367 (defun translate-length (load)
368 ;; XXX Soweit ich sehe unterscheiden die Tests nicht zwischen
369 ;; der Laenge von DOMString und der length()-Methode der uebrigen
370 ;; Interfaces. Also unterscheiden wir das erstmal manuell.
371 (with-attributes (|var| |obj|
) load
372 (let ((obj (%intern |obj|
)))
373 (maybe-setf (%intern |var|
)
374 `(if (typep ,obj
'sequence
)
376 (dom:length
,obj
))))))
378 (defun translate-call (call method
)
379 (let ((name (car method
))
380 (args (mapcar (lambda (name)
381 (parse-java-literal (dom:get-attribute call name
)))
383 (with-attributes (|var| |obj|
) call
384 (maybe-setf (%intern |var|
)
385 `(,(intern-dom name
) ,(%intern |obj|
) ,@args
)))))
387 (defun translate-get (call name
)
388 (with-attributes (|var| |value| |obj|
) call
390 ((nullify |var|
) ;get
391 (maybe-setf (%intern |var|
) `(,(intern-dom name
) ,(%intern |obj|
))))
392 ((nullify |value|
) ;set
393 `(setf (,(intern-dom name
) ,(%intern |obj|
))
394 ,(parse-java-literal |value|
)))
398 (defun translate-has-feature (element)
399 (with-attributes (|obj| |var| |feature| |version|
) element
401 (translate-member element
)
402 (maybe-setf (%intern |var|
)
403 `(dom:has-feature
'rune-dom
:implementation
404 ,(parse-java-literal |feature|
)
405 ,(parse-java-literal |version|
))))))
407 (defun translate-fail (element)
408 (declare (ignore element
))
411 (defun translate-node-type (element)
412 ;; XXX Das muessten eigentlich ints sein, sind aber Keywords in CXML.
413 (with-attributes (|var| |obj|
) element
414 (maybe-setf (%intern |var|
)
415 `(ecase (dom:node-type
,(%intern |obj|
))
420 (:entity-reference
5)
422 (:processing-instruction
7)
426 (:document-fragment
11)
429 (defun translate-member (element)
430 (let* ((name (dom:tag-name element
))
431 (method (find name
*methods
* :key
#'car
:test
#'runes
:rod
=))
432 (field (find name
*fields
* :test
#'runes
:rod
=)))
434 (method (translate-call element method
))
435 (field (translate-get element field
))
436 (t (error "unknown element ~A" element
)))))
438 (defun translate-assert-equals (element)
439 `(assert ,(translate-equals element
)))
441 (defun translate-assert-same (element)
442 `(assert ,(translate-same element
)))
444 (defun translate-assert-null (element)
445 (with-attributes (|actual|
) element
446 `(assert (null ,(%intern |actual|
)))))
448 (defun translate-assert-not-null (element)
449 (with-attributes (|actual|
) element
450 `(assert ,(%intern |actual|
))))
452 (defun translate-assert-size (element)
453 (with-attributes (|collection| |size|
) element
454 `(let ((collection ,(%intern |collection|
)))
455 (when (dom:named-node-map-p collection
)
456 (setf collection
(dom:items collection
)))
457 (assert (eql (length collection
) ,(parse-java-literal |size|
))))))
459 (defun translate-assert-instance-of (element)
460 `(assert ,(translate-instance-of element
)))
462 (defun translate-if (element)
463 (destructuring-bind (condition &rest rest
)
464 (child-elements element
)
467 (when (equal (tag-name r
) "else")
468 (setf else
(child-elements r
))
472 (,(translate-condition condition
)
473 ,@(mapcar #'translate-statement
(reverse then
)))
475 ,@(mapcar #'translate-statement else
))))))
477 (defun translate-while (element)
478 (destructuring-bind (condition &rest body
)
479 (child-elements element
)
481 while
,(translate-condition condition
)
482 do
(progn ,@(mapcar #'translate-statement body
)))))
484 (defun translate-assert-domexception (element)
485 (do-child-elements (c element
)
486 (unless (equal (tag-name c
) "metadata")
488 `(block assert-domexception
490 ((rune-dom::dom-exception
492 (when (eq (rune-dom::dom-exception-key c
)
493 ,(intern (tag-name c
) :keyword
))
494 (return-from assert-domexception
)))))
496 (error "expected exception ~A" ,(tag-name c
))))))))
498 (defun translate-catch (catch return
)
500 ,@(map-child-elements
503 `(when (eq (rune-dom::dom-exception-key c
)
504 ,(intern (runes:rod-string
(dom:get-attribute exception
"code"))
506 ,@(translate-body exception
)
510 (defun translate-try (element)
513 ((rune-dom::dom-exception
515 (do-child-elements (c element
:name
"catch") (return c
))
516 '(return-from try
))))
517 ,@(map-child-elements 'list
519 (if (equal (tag-name c
) "catch")
521 (translate-statement c
)))
524 (defun translate-append (element)
525 (with-attributes (|collection| |item|
) element
526 (let ((c (%intern |collection|
))
527 (i (%intern |item|
)))
528 (maybe-setf c
`(append ,c
(list ,i
))))))
530 (defun translate-assert-true (element)
531 (with-attributes (|actual|
) element
532 `(assert ,(if (nullify |actual|
)
535 (do-child-elements (c element
) (return c
)))))))
537 (defun translate-assert-false (element)
538 (with-attributes (|actual|
) element
539 `(assert (not ,(%intern |actual|
)))))
541 (defun translate-assert-uri-equals (element)
542 `(assert ,(translate-uri-equals element
)))
545 ;;;; Tests uebersetzen
547 (defun translate-body (element)
548 (map-child-elements 'list
#'translate-statement element
))
550 (defun translate-for-each (element)
551 (with-attributes (|collection| |member|
) element
552 `(let ((collection ,(%intern |collection|
)))
553 (when (dom:named-node-map-p collection
)
554 (setf collection
(dom:items collection
)))
555 (map nil
(lambda (,(%intern |member|
)) ,@(translate-body element
))
558 (defun assert-have-implementation-attribute (element)
559 (let ((attribute (runes:rod-string
(dom:get-attribute element
"name"))))
560 (string-case attribute
561 ;; fixme: expandEntityReferences sollten wir auch mal anschalten, wo
562 ;; wir uns schon die muehe machen...
564 (setf cxml
::*validate
* t
))
566 ;; ??? dom 2 ohne namespace-support gibt's doch gar nicht,
567 ;; ausser vielleicht in html-only implementationen, und dann sollen
568 ;; sie halt auf hasFeature "XML" testen.
571 (format t
"~&implementationAttribute ~A not supported, skipping test~%"
573 (throw 'give-up nil
)))))
575 (defun slurp-test (pathname)
577 (multiple-value-setq (*methods
* *fields
*) (read-members)))
579 (let* ((builder (rune-dom:make-dom-builder
))
580 (cxml::*validate
* nil
) ;dom1.dtd is buggy
581 (test (dom:document-element
582 (cxml:parse-file pathname builder
:recode nil
)))
586 (declare (ignorable title
))
587 (do-child-elements (e test
)
588 (string-case (tag-name e
)
590 (let ((title-element (find-child-element "title" e
)))
591 (setf title
(dom:data
(dom:first-child title-element
)))))
593 (push (list (%intern
(dom:get-attribute e
"name"))
594 (string-case (runes:rod-string
595 (dom:get-attribute e
"type"))
596 (("byte" "short" "int" "long") 0)
599 (let ((value (dom:get-attribute e
"value")))
601 (push `(setf ,(%intern
(dom:get-attribute e
"name"))
602 ,(parse-java-literal value
))
604 (do-child-elements (member e
:name
"member") e
605 (push `(setf ,(%intern
(dom:get-attribute e
"name"))
606 (append ,(%intern
(dom:get-attribute e
"name"))
611 (dom:child-nodes member
)
614 ("implementationAttribute"
615 (assert-have-implementation-attribute e
))
617 (push (translate-statement e
) code
))))
619 (let ((*files-directory
* ,*files-directory
*) ;fuer copy&paste:
621 (declare (ignorable ,@(mapcar #'car bindings
)))
622 ,@(reverse code
))))))
624 (defun load-file (name &optional will-be-modified-p
)
625 (declare (ignore will-be-modified-p
))
626 (setf name
(runes:rod-string name
))
628 (make-pathname :name name
:type
"xml" :defaults
*files-directory
*)
629 (rune-dom:make-dom-builder
)
632 (defparameter *bad-tests
*
633 '("hc_elementnormalize2.xml"
634 "hc_nodereplacechildnewchildexists.xml"
635 "characterdatadeletedatanomodificationallowederr.xml"))
637 (defun dribble-tests (directory)
638 (let ((base (slot-value (asdf:find-system
:cxml
) 'asdf
::relative-pathname
)))
639 (with-open-file (*standard-output
*
640 (merge-pathnames "DOMTEST" base
)
642 :if-exists
:supersede
)
643 (run-all-tests directory
))))
645 (defun run-all-tests (*directory
* &optional verbose
)
646 (let* ((cxml::*redefinition-warning
* nil
)
651 (flet ((parse (test-directory)
652 (let* ((all-tests (merge-pathnames "alltests.xml" test-directory
))
653 (builder (rune-dom:make-dom-builder
))
654 (suite (dom:document-element
655 (cxml:parse-file all-tests builder
:recode nil
)))
657 (merge-pathnames "files/" test-directory
)))
658 (do-child-elements (member suite
)
660 (or (equal (dom:tag-name member
) "metadata")
661 (member (runes:rod-string
662 (dom:get-attribute member
"href"))
667 (run (test-directory suite
)
668 (print test-directory
)
669 (let ((*files-directory
*
670 (merge-pathnames "files/" test-directory
)))
671 (do-child-elements (member suite
)
672 (let ((href (runes:rod-string
673 (dom:get-attribute member
"href"))))
674 (unless (or (runes:rod
= (dom:tag-name member
) #"metadata")
675 (member href
*bad-tests
* :test
'equal
))
676 (format t
"~&~D/~D ~A~%" i n href
)
677 (let ((lisp (slurp-test
678 (merge-pathnames href test-directory
))))
683 (with-simple-restart (skip-test "Skip this test")
685 (let ((cxml::*validate
* nil
))
686 (funcall (compile nil lisp
)))
687 (serious-condition (c)
689 (format t
"~&TEST FAILED: ~A~&" c
))))))
691 (let* ((d1 (merge-pathnames "tests/level1/core/" *directory
*))
692 (d2 (merge-pathnames "tests/level2/core/" *directory
*))
697 (format t
"~&~D/~D tests failed; ~D test~:P were skipped"
698 nfailed ntried
(- n ntried
))))
700 (defun run-test (*directory
* level href
)
701 (let* ((test-directory
703 (1 (merge-pathnames "tests/level1/core/" *directory
*))
704 (2 (merge-pathnames "tests/level2/core/" *directory
*))))
705 (*files-directory
* (merge-pathnames "files/" test-directory
))
706 (lisp (slurp-test (merge-pathnames href test-directory
)))
707 (cxml::*validate
* nil
))
711 (funcall (compile nil lisp
)))))
714 (domtest::run-all-tests
"/home/david/2001/DOM-Test-Suite/")
717 (domtest::run-test
"/home/david/2001/DOM-Test-Suite/"
719 "attrcreatedocumentfragment.xml")