#lang racket/base (require (for-syntax racket/base racket/syntax syntax/strip-context)) ;; use a separate test file to avoid cycle in loading (define-syntax (test-safe-and-unsafe stx) (syntax-case stx () [(_ . exprs) (with-syntax ([module-without-contracts (generate-temporary)] [module-with-contracts (generate-temporary)]) (replace-context stx #'(begin (module module-without-contracts racket (require rackunit "../main.rkt" "check-values.rkt") . exprs) (require 'module-without-contracts) (module module-with-contracts racket (require rackunit (submod "../main.rkt" safe) "check-values.rkt") . exprs) (require 'module-with-contracts))))])) (test-safe-and-unsafe (check-true (txexpr-tag? 'foo)) (check-false (txexpr-tag? "foo")) (check-false (txexpr-tag? 3)) (check-false (txexpr-tags? 'foo)) (check-true (txexpr-tags? '(foo bar))) (check-true (txexpr-attr? '(key "value"))) (check-false (txexpr-attr? '(key "value" "another"))) (check-false (txexpr-attr? '(key 0 "value"))) (check-true (txexpr-attrs? '())) (check-true (txexpr-attrs? '((key "value")))) (check-true (txexpr-attrs? '((key "value") (foo "bar")))) (check-false (txexpr-attrs? '((key "value") "foo" "bar"))) ; content, not attr (check-false (txexpr-attrs? '(key "value"))) ; not a nested list (check-false (txexpr-attrs? '(("key" "value")))) ; two strings (check-false (txexpr-attrs? '((key value)))) ; two symbols (check-true (txexpr-element? "string")) (check-true (txexpr-element? 'amp)) (check-true (txexpr-element? '(p "string"))) (check-true (txexpr-element? 2)) ; a valid-char, but not in v6.0 xml:xexpr? (check-true (txexpr-element? 65)) ; a valid-char (check-false (txexpr-element? 0)) ; not a valid-char (check-true (txexpr-elements? '("p" "foo" "123"))) (check-true (txexpr-elements? '("p" "foo" 123))) ; includes number (check-true (txexpr-elements? '(p "foo" "123"))) ; includes symbol (check-false (txexpr-elements? "foo")) ; not a list (check-false (txexpr-elements? '(((key "value")) "foo" "bar"))) ; includes attr (check-false (txexpr-elements? '("foo" "bar" ((key "value"))))) ; malformed (check-true (txexpr? '(p))) (check-true (txexpr? '(div 2))) (check-true (txexpr? '(div (div ((foo "bar")) 2)))) (check-true (txexpr? '(p "foo" "bar"))) (check-true (txexpr? '(p ((key "value")) "foo" "bar"))) (check-true (txexpr? '(p 123))) ; content is a number (check-false (txexpr? "foo")) ; not a list with symbol (check-false (txexpr? '(p "foo" "bar" ((key "value"))))) ; malformed (check-false (txexpr? '("p" "foo" "bar"))) ; no name (check-not-exn (λ _ (validate-txexpr '(p)))) (check-not-exn (λ _ (validate-txexpr '(p "foo" "bar")))) (check-not-exn (λ _ (validate-txexpr '(p ((key "value")) "foo" "bar")))) (check-not-exn (λ _ (validate-txexpr '(p () "foo" "bar")))) (check-not-exn (λ _ (validate-txexpr '(p 123)))) ; content is a valid-char (check-exn exn:fail? (λ _ (validate-txexpr "foo"))) ; not a list with symbol (check-exn exn:fail? (λ _ (validate-txexpr '(p "foo" "bar" ((key "value")))))) ; malformed (check-exn exn:fail? (λ _ (validate-txexpr '("p" "foo" "bar")))) ; no name (check-exn exn:fail? (λ _ (validate-txexpr '(root ((id "top")(class 42)))))) ; malformed attrs (check-exn exn:fail? (λ _ (validate-txexpr `(root ,(void))))) ; invalid element type (define-syntax (check-validate-exn-msg stx) (syntax-case stx () [(_ tx) (syntax/loc stx (check-validate-exn-msg tx ""))] [(_ tx msg) (syntax/loc stx (check-equal? (with-handlers ([exn:fail:contract? (λ (e) (exn-message e))]) (validate-txexpr tx)) msg))])) ;; Root element not a list (check-validate-exn-msg "foo" "validate-txexpr: contract violation\n expected: tagged X-expression\n given: \"foo\"") ;; No name (check-validate-exn-msg '("p" "foo" "bar") "validate-txexpr: tag must be a symbol\n tag: \"p\"\n in: '(\"p\" \"foo\" \"bar\")") ;; Invalid element (check-validate-exn-msg '(p "foo" "bar" ((key "value"))) "validate-txexpr: element not a valid element (= txexpr, string, symbol, XML char, cdata, or comment)\n element: '((key \"value\"))\n in: '(p \"foo\" \"bar\" ((key \"value\")))") ;; Malformed attribute list (check-validate-exn-msg '(p ((key "val") "foo" "bar") "hi") "validate-txexpr: attribute is not a list of the form '(symbol \"string\")\n attribute: \"foo\"\n in: '(p ((key \"val\") \"foo\" \"bar\") \"hi\")") ;; Invalid attribute key (check-validate-exn-msg '(root ((id "top") (class 42))) "validate-txexpr: attribute value is not a string\n attribute value: 42\n in: '(root ((id \"top\") (class 42)))") ;; Invalid attribute value (check-validate-exn-msg '(root ((id "top") ("class" 42))) "validate-txexpr: attribute key is not a symbol\n attribute key: \"class\"\n in: '(root ((id \"top\") (\"class\" 42)))") ;; Invalid element type (check-validate-exn-msg `(root ,(void)) "validate-txexpr: element not a valid element (= txexpr, string, symbol, XML char, cdata, or comment)\n element: #\n in: '(root #)") ;; (Deeply nested) No name: error should pinpoint element in 'div txexpr (check-validate-exn-msg '(fine-outer [[type "valid"]] (div (br) ("p" "foo" "bar"))) "validate-txexpr: element not a valid element (= txexpr, string, symbol, XML char, cdata, or comment)\n element: '(\"p\" \"foo\" \"bar\")\n in: '(div (br) (\"p\" \"foo\" \"bar\"))") ;; (Deeply nested) Invalid element: error should pinpoint element in 'p txexpr (check-validate-exn-msg '(fine-outer [[type "valid"]] (div (br) (p "foo" "bar" ((key "value"))))) "validate-txexpr: element not a valid element (= txexpr, string, symbol, XML char, cdata, or comment)\n element: '((key \"value\"))\n in: '(p \"foo\" \"bar\" ((key \"value\")))") ;; (Deeply nested) Malformed attribute list: error should pinpoint attr in 'p txexpr (check-validate-exn-msg '(fine-outer [[type "valid"]] (div (br) (p ((key "val") "foo" "bar") "hi"))) "validate-txexpr: attribute is not a list of the form '(symbol \"string\")\n attribute: \"foo\"\n in: '(p ((key \"val\") \"foo\" \"bar\") \"hi\")") ;; (Deeply nested) Invalid attribute key: error should pinpoint attr key in 'p txexpr (check-validate-exn-msg '(fine-outer [[type "valid"]] (div (br) (p ((id "top") (class 42))))) "validate-txexpr: attribute value is not a string\n attribute value: 42\n in: '(p ((id \"top\") (class 42)))") ;; (Deeply nested) Invalid attribute value: error should pinpoint attr val in 'p txexpr (check-validate-exn-msg '(fine-outer [[type "valid"]] (div (br) (p ((id "top") ("class" 42))))) "validate-txexpr: attribute key is not a symbol\n attribute key: \"class\"\n in: '(p ((id \"top\") (\"class\" 42)))") ;; (Deeply nested) Invalid element type: error should pinpoint element in 'p txexpr (check-validate-exn-msg `(fine-outer [[type "valid"]] (div (br) (p ,(void)))) "validate-txexpr: element not a valid element (= txexpr, string, symbol, XML char, cdata, or comment)\n element: #\n in: '(p #)") (check-txexprs-equal? (make-txexpr 'p) '(p)) (check-txexprs-equal? (make-txexpr 'p '((key "value"))) '(p ((key "value")))) (check-txexprs-equal? (make-txexpr 'p null '("foo" "bar")) '(p "foo" "bar")) (check-txexprs-equal? (make-txexpr 'p '((key "value")) (list "foo" "bar")) '(p ((key "value")) "foo" "bar")) (check-txexprs-equal? (txexpr 'p) '(p)) (check-txexprs-equal? (txexpr 'p '((key "value"))) '(p ((key "value")))) (check-txexprs-equal? (txexpr 'p null '("foo" "bar")) '(p "foo" "bar")) (check-txexprs-equal? (txexpr 'p '((key "value")) (list "foo" "bar")) '(p ((key "value")) "foo" "bar")) (check-txexprs-equal? (txexpr* 'p) '(p)) (check-txexprs-equal? (txexpr* 'p '((key "value"))) '(p ((key "value")))) (check-txexprs-equal? (txexpr* 'p null "foo" "bar") '(p "foo" "bar")) (check-txexprs-equal? (txexpr* 'p '((key "value")) "foo" "bar") '(p ((key "value")) "foo" "bar")) (check-values=? (txexpr->values '(p)) (values 'p null null)) (check-values=? (txexpr->values '(p "foo")) (values 'p null '("foo"))) (check-values=? (txexpr->values '(p ((key "value")))) (values 'p '((key "value")) null)) (check-values=? (txexpr->values '(p ((key "value")) "foo")) (values 'p '((key "value")) '("foo"))) (check-equal? (values->list (txexpr->values '(p))) (txexpr->list '(p))) (check-equal? (values->list (txexpr->values '(p "foo"))) (txexpr->list '(p "foo"))) (check-equal? (values->list (txexpr->values '(p ((key "value"))))) (txexpr->list '(p ((key "value"))))) (check-equal? (values->list (txexpr->values '(p ((key "value")) "foo"))) (txexpr->list '(p ((key "value")) "foo"))) ;; testing the match expander success (check-match '(p ((key "value")) "leaf") (txexpr 'p `((key ,val)) (list "leaf")) (string=? val "value")) ;; testing the match expander failure (check-false (match '(p ((key "value")) "something") [(txexpr 'p _ (list "else")) #true] [_ #false])) (check-false (match "foo" [(txexpr _ _ _) #true] [_ #false])) (check-equal? (get-tag '(p ((key "value"))"foo" "bar" (em "square"))) 'p) (check-equal? (get-attrs '(p ((key "value"))"foo" "bar" (em "square"))) '((key "value"))) (check-equal? (get-elements '(p ((key "value"))"foo" "bar" (em "square"))) '("foo" "bar" (em "square"))) (check-equal? (->txexpr-attr-key "foo") 'foo) (check-equal? (->txexpr-attr-key 'foo) 'foo) (check-equal? (->txexpr-attr-key (string->path "foo")) 'foo) (check-equal? (->txexpr-attr-value "foo") "foo") (check-equal? (->txexpr-attr-value 'foo) "foo") (check-equal? (->txexpr-attr-value (string->path "foo")) "foo") (check-equal? (attrs->hash '((foo "bar"))) '#hasheq((foo . "bar"))) (check-equal? (attrs->hash '((foo "bar") (foo "fraw"))) '#hasheq((foo . "bar"))) (check-equal? (attrs->hash #:hash-style? #t '((foo "bar") (foo "fraw"))) '#hasheq((foo . "fraw"))) (check-equal? (attrs->hash '((foo "bar")) '(foo "fraw")) '#hasheq((foo . "bar"))) (check-equal? (attrs->hash '((foo "bar")) '(foo "fraw") 'foo "dog") '#hasheq((foo . "bar"))) (check-exn exn:fail:contract? (λ _ (attrs->hash 'foo "bar" 'zam))) (check-equal? (sort (hash->attrs '#hash((foo . "bar")(hee . "haw"))) stringhtml '(root (script "3 > 2") "Why is 3 > 2?")) "Why is 3 > 2?") (check-equal? (xexpr->html '(root (div " 2]]>") "Why is 3 > 2?")) "
2]]>
Why is 3 > 2?
") ;; comment (check-equal? (xexpr->html '(root "" "Why is 3 > 2?")) "Why is 3 > 2?") ;; malformed comment: merged with next string (check-equal? (xexpr->html '(root "Why is 3 > 2?")) "<!-- comment -->Why is 3 > 2?") ;; malformed comment: missing double hyphen at end (check-equal? (xexpr->html '(root "