;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; tests (use utf8) (define *pass* 0) (define *fail* 0) #; (define-macro (test form . opt) (if (pair? opt) (let ((res (gensym)) (expect (gensym))) `(let ((,res (condition-case ,form (exn () '(error ,(gensym))))) (,expect ,(car opt))) (if (equal? ,res ,expect) (begin (set! *pass* (+ 1 *pass*)) (display "[ OK ] ") (write ',form) (display " => ") (write ,res) (newline)) (begin (set! *fail* (+ 1 *fail*)) (display "[FAIL] ") (write ',form) (display " => ") (write ,res) (display " [expected ") (write ,expect) (display "]") (newline))))) `(begin (write ',form) (display " => ") (write ,form) (newline)))) (define (exn-condition->list cnd) (list ((condition-property-accessor 'exn 'location #f) cnd) ((condition-property-accessor 'exn 'message #f) cnd) ((condition-property-accessor 'exn 'arguments #f) cnd)) ) (define-macro (test form . opt) (let ((res (gensym)) (expect (gensym))) `(let ((,res (condition-case ,form (exn () (list 'error ',(gensym) "exception" (exn-condition->list exn))))) (,expect ,(optional opt #t))) (if (equal? ,res ,expect) (begin (set! *pass* (+ 1 *pass*)) (display "[ OK ] ") (write ',form) (display " => ") (write ,res) (newline)) (begin (set! *fail* (+ 1 *fail*)) (display "[FAIL] ") (write ',form) (display " => ") (write ,res) (display " [expected ") (write ,expect) (display "]") (newline)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; R5RS (test (string-length "漢字") 2) (test (char->integer (string-ref "漢字" 0)) 28450) ;;(define str "漢字") (define str (string-copy "漢字")) (test (begin (string-set! str 0 (string-ref "赤" 0)) str) "赤字") (test (begin (string-set! str 1 (string-ref "外" 0)) str) "赤外") (test (begin (string-set! str 1 #\x) str) "赤x") (test (begin (string-set! str 1 (string-ref "々" 0)) str) "赤々") (test (substring "文字列" 0) "文字列") (test (substring "文字列" 1) "字列") (test (substring "文字列" 2) "列") (test (substring "文字列" 0 1) "文") (test (substring "文字列" 1 2) "字") (test (substring "文字列" 0 2) "文字") (define *string* "文字列") (define *list* '("文" "字" "列")) (define *chars* '(25991 23383 21015)) (test (map char->integer (string->list "文字列")) *chars*) (test (map string (map integer->char *chars*)) *list*) (test (list->string (map integer->char '(25991 23383 21015))) *string*) (test (make-string 3 (string-ref "列" 0)) "列列列") (test (let ((s (string-copy "abc"))) (string-fill! s (string-ref "文" 0)) s) "文文文") (test (with-input-from-string "全角ハンカク" (lambda () (read-char) (read-char) (read-char))) (string-ref "ハ" 0)) (test (with-output-to-string (lambda () (write-char (string-ref "個" 0)) (write-char (string-ref "々" 0)))) "個々") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; library (test (with-output-to-string (lambda () (print "出" (string-ref "力" 0) "改行"))) "出力改行\n") (test (with-output-to-string (lambda () (print* "出" (string-ref "力" 0) ""))) "出力") (test (reverse-list->string (map (cut string-ref <> 0) '("列" "字" "文" "→" "ト" "ス" "リ" "逆"))) "逆リスト→文字列") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; extras (test (with-input-from-string "这是中文" (cut read-string 2)) "这是") (test (with-output-to-string (cut write-string "这是中文" 2)) "这是") (test (conc (with-input-from-string "我爱你" (cut read-token (lambda (c) (memv c (map (cut string-ref <> 0) '("爱" "您" "我")))))) "她") "我爱她") (test (string-chop "第一第二第三" 2) '("第一" "第二" "第三")) (test (string-chop "第一第二第三…" 2) '("第一" "第二" "第三" "…")) (test (string-split "a,bc、第,f几" ",、") '("a" "bc" "第" "f几")) (test (string-translate "我爱你" "我你" "你我") "你爱我") (test (substring=? "日本語" "日本語") #t) (test (substring=? "日本語" "日本") #t) (test (substring=? "日本" "日本語") #t) (test (substring=? "日本語" "本語" 1) #t) (test (substring=? "日本語" "本" 1 0 1) #t) (test (substring=? "听说上海的东西很贵" "上海的东西很便宜" 2 0 5) #t) (test (substring-index "上海" "听说上海的东西很贵") 2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SRFI-13 (use utf8-srfi-13) (test (string-null? "") #t) (test (string-every (lambda (c) (not (char-alphabetic? c))) "日本語に戻りましょう") #t) (test (string-any (lambda (c) (eqv? c (string-ref "白" 0))) "black: 黒 white: 白") #t) (test (string-tabulate (lambda (i) (integer->char (inexact->exact (+ (* -135.5 i i) (* 275.5 i) 19968)))) 3) "一二三") ;; this is the same as substring, why extend it in SRFI-13? (test (string-copy "春夏秋冬") "春夏秋冬") (test (string-copy "春夏秋冬" 2) "秋冬") (test (string-copy "春夏秋冬" 1 3) "夏秋") (let ((a (string-copy "春夏秋冬")) (b "ABCD")) (test (begin (string-copy! a 0 b) a) "ABCD")) (let ((a (string-copy "春夏秋冬")) (b "ABCD")) (test (begin (string-copy! a 0 b 3) a) "D夏秋冬")) (let ((a (string-copy "春夏秋冬")) (b "ABCD")) (test (begin (string-copy! a 0 b 0 2) a) "AB秋冬")) (let ((a (string-copy "春夏秋冬")) (b (string-copy "ABCD"))) (test (begin (string-copy! b 0 a) b) "春夏秋冬")) (let ((a (string-copy "春夏秋冬")) (b (string-copy "ABCD"))) (test (begin (string-copy! b 0 a 1) b) "夏秋冬D")) (let ((a (string-copy "春夏秋冬")) (b (string-copy "ABCD"))) (test (begin (string-copy! b 0 a 2 4) b) "秋冬CD")) ;; again, these are just variations of substring (test (string-take "春夏秋冬" 1) "春") (test (string-take "春夏秋冬" 2) "春夏") (test (string-drop "春夏秋冬" 1) "夏秋冬") (test (string-drop "春夏秋冬" 2) "秋冬") (test (string-take-right "春夏秋冬" 1) "冬") (test (string-take-right "春夏秋冬" 2) "秋冬") (test (string-drop-right "春夏秋冬" 1) "春夏秋") (test (string-drop-right "春夏秋冬" 2) "春夏") (let ((pad-char (string-ref "…" 0))) (test (string-pad "弱肉強食" 2 pad-char) "強食") (test (string-pad "弱肉強食" 4 pad-char) "弱肉強食") (test (string-pad "弱肉強食" 5 pad-char) "…弱肉強食") (test (string-pad "弱肉強食" 7 pad-char) "………弱肉強食") (test (string-pad "弱肉強食" 4 pad-char 1) "…肉強食") (test (string-pad "弱肉強食" 4 pad-char 1 3) "……肉強") (test (string-pad-right "弱肉強食" 2 pad-char) "弱肉") (test (string-pad-right "弱肉強食" 4 pad-char) "弱肉強食") (test (string-pad-right "弱肉強食" 5 pad-char) "弱肉強食…") (test (string-pad-right "弱肉強食" 7 pad-char) "弱肉強食………") (test (string-pad-right "弱肉強食" 4 pad-char 1) "肉強食…") (test (string-pad-right "弱肉強食" 4 pad-char 1 3) "肉強……") ) (let ((trim-char (string-ref "…" 0))) (test (string-trim "……弱肉強食……" trim-char) "弱肉強食……") (test (string-trim-right "……弱肉強食……" trim-char) "……弱肉強食") (test (string-trim-both "……弱肉強食……" trim-char) "弱肉強食") ) (let ((proc< (cut list '< <>)) (proc= (cut list '= <>)) (proc> (cut list '> <>)) (s1 "御世話になっております") (s2 "お世話になります")) (test (string-compare s1 s2 proc< proc= proc>) '(> 0)) (test (string-compare s1 s2 proc< proc= proc> 1 7 1) '(< 5)) (test (string-compare s1 s2 proc< proc= proc> 1 3 1 3) '(= 3)) ) ;; string= string<> string< string> string<= string>= ;; string-ci= string-ci<> string-ci< string-ci> string-ci<= string-ci>= (test (and (string= "麻布" "麻布") #t) #t) (test (and (string= "麻布" "麻布十番") #t) #f) (test (and (string= "西麻布" "麻布" 1) #t) #t) (test (and (string= "西麻布の辺" "麻布" 1 3) #t) #t) (test (and (string= "西麻布の辺" "元麻布に" 1 3 1 3) #t) #t) (test (and (string<> "西麻布の辺" "元麻布に" 1 3) #t) #t) (test (and (string< "あいうえお" "あいうえお") #t) #f) (test (and (string< "あいうえお" "あいうえお" 1) #t) #f) (test (and (string< "あいうえお" "あいうえお" 0 3) #t) #t) (test (and (string< "あいうえお" "あいうえお" 0 3 1) #t) #t) (test (and (string< "あいうえお" "あいうえお" 0 3 1 4) #t) #t) (test (and (string<= "あいうえお" "あいうえお") #t) #t) (test (and (string<= "あいうえお" "あいうえお" 1) #t) #f) (test (and (string> "あいうえお" "あいうえお") #t) #f) (test (and (string> "あいうえお" "あいうえお" 1) #t) #t) (test (and (string>= "あいうえお" "あいうえお") #t) #t) (test (and (string>= "あいうえお" "あいうえお" 1 3 2) #t) #f) (test (integer? (string-hash "abc"))) (test (integer? (string-ci-hash "abc"))) (test (not (= (string-hash "abc") (string-hash "abd")))) (test (= (string-ci-hash "abc") (string-ci-hash "aBc") (string-ci-hash "ABC"))) (test (= (string-hash "いうえ" #xFFFF) (string-hash "あいうえ" #xFFFF 1) (string-hash "あいうえお" #xFFFF 1 4)) #t) (test (string-prefix? "麻布" "麻布十番") #t) (test (string-prefix? "元麻布" "麻布十番") #f) (test (string-prefix? "元麻布" "麻布十番" 1) #t) (test (string-prefix? "元麻布" "麻" 1 2) #t) (test (string-suffix? "十番" "麻布十番") #t) (test (string-suffix? "九番" "麻布十番") #f) (test (string-suffix? "元麻布" "東麻布" 1) #t) (test (string-suffix? "元麻布" "東麻布" 1 3) #t) (test (string-prefix-length "麻布" "麻布十番") 2) (test (string-prefix-length "元麻布" "麻布十番") 0) (test (string-prefix-length "元麻布" "麻布十番" 1) 2) (test (string-prefix-length "元麻布" "麻" 1 2) 1) (test (string-suffix-length "十番" "麻布十番") 2) (test (string-suffix-length "九番" "麻布十番") 1) (test (string-suffix-length "元麻布" "東麻布" 1) 2) (test (string-suffix-length "元麻布" "東麻布" 1 3) 2) (test (string-index "文字列の文字検索" (string-ref "字" 0)) 1) (test (string-index-right "文字列の文字検索" (string-ref "字" 0)) 5) (test (string-skip "文字列no関数kensaku" (lambda (c) (not (char-alphabetic? c)))) 3) (test (string-skip "文字列no関数kensaku" (lambda (c) (not (char-alphabetic? c))) 5) 7) (test (string-skip-right "文字列no関数kensaku" (lambda (c) (not (char-alphabetic? c)))) 13) (test (string-skip-right "文字列no関数kensaku" (lambda (c) (not (char-alphabetic? c))) 0 5) 4) (test (string-count "aびcでぃeえふgえち" (lambda (c) (not (char-alphabetic? c)))) 7) (test (string-contains "eek -- what a geek." "ee" 12 18) 15) (test (string-contains-ci "eek -- what a gEek." "ee" 12 18) 15) (test (string-contains "この釘は引き抜き難い釘だ" "釘") 2) (test (string-contains "この釘は引き抜き難い釘だ" "釘" 4) 10) (test (string-titlecase "英語でsundayの最初の文字をtitlecase(小文字)と書く") "英語でSundayの最初の文字をTitlecase(小文字)と書く") ;; (test (let ((s "英語でsundayの最初の文字をtitlecase(小文字)と書く")) ;; (string-titlecase! s) ;; s) ;; "英語でSundayの最初の文字をTitlecase(小文字)と書く") (test (string-upcase "英語でufoはupcaseと書く") "英語でUFOはUPCASEと書く") ;; (test (let ((s "英語でufoはupcaseと書く")) ;; (string-upcase! s) ;; s) ;; "英語でUFOはUPCASEと書く") (test (string-downcase "英語でAPPLEはDOWNCASEと書く") "英語でappleはdowncaseと書く") ;; (test (let ((s "英語でAPPLEはDOWNCASEと書く")) ;; (string-downcase! s) ;; s) ;; "英語でappleはdowncaseと書く") (test (string-map char-upcase "文x字x列") "文X字X列") (test (string-map! char-upcase (string-copy "文x字x列")) "文X字X列") (test (string-map (lambda (c) (if (char-alphabetic? c) (string-ref "字" 0) #\a)) "字x字x字") "a字a字a") (test (map string (string-fold cons '() "東京特許許可局今日急遽許可却下")) '("下" "却" "可" "許" "遽" "急" "日" "今" "局" "可" "許" "許" "特" "京" "東")) (test (map string (string-fold-right cons '() "東京特許許可局今日急遽許可却下")) '("東" "京" "特" "許" "許" "可" "局" "今" "日" "急" "遽" "許" "可" "却" "下")) (test (string-unfold (cut = <> 5) (lambda (i) (integer->char (+ i 12354))) (cut + <> 1) 0) "あぃいぅう") (test (string-unfold-right (cut = <> 5) (lambda (i) (integer->char (+ i 12354))) (cut + <> 1) 0) "うぅいぃあ") (test (string-reverse "一a二b三c") "c三b二a一") (test (let ((s (string-copy "一a二b三c"))) (string-reverse! s) s) "c三b二a一") (test (let ((s "赤パジャマ黄パジャマ茶パジャマ") (ls '())) (string-for-each (lambda (c) (set! ls (cons c ls))) s) (map string ls)) '("マ" "ャ" "ジ" "パ" "茶" "マ" "ャ" "ジ" "パ" "黄" "マ" "ャ" "ジ" "パ" "赤")) (test (let ((sum 0)) (string-for-each-index (lambda (i) (set! sum (+ sum i))) "赤パジャマ") sum) 10) (test (xsubstring "abcdef" 2) "cdefab") (test (xsubstring "abcdef" -2) "efabcd") (test (xsubstring "abc" 0 7) "abcabca") (test (let ((s1 (string-copy "ABCDEF")) (s2 "abc")) (string-xcopy! s1 1 s2 0 5) s1) "Aabcab") (test (string-replace "英語" "日本" 0 1) "日本語") (test (string-replace "英語" "日本語" 0 1 0 2) "日本語") (test (string-tokenize "文字列を引き裂く" (string->char-set "字列引裂文")) '("文字列" "引" "裂")) (test (string-filter "文字列を引き裂く" (lambda (c) (not (char-set-contains? (string->char-set "きくを") c)))) "文字列引裂") (test (string-delete "文字列を引き裂く" (string->char-set "きくを")) "文字列引裂") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SRFI-14 (sanity only, these are tested more heavily in iset) (use utf8-srfi-14) (test (char-set? (->char-set "あいうえお")) #t) (test (char-set-empty? (char-set)) #t) (test (char-set-size (char-set)) 0) (test (char-set-size (->char-set "あいうえお")) 5) (test (char-set-count (lambda (c) (not (eqv? c (string-ref "う" 0)))) (->char-set "あいうえお")) 4) (test (let ((cs (->char-set "あいうえお"))) (char-set= cs (char-set-copy cs))) #t) (test (char-set= (->char-set "あいうえお") (->char-set "おえういあ")) #t) (test (char-set<= (->char-set "あいうえお") (->char-set "おえういあ")) #t) (test (char-set<= (->char-set "あおい") (->char-set "おえういあ")) #t) (test (char-set<= (->char-set "おえういあ") (->char-set "あおい")) #f) (test (char-set>= (->char-set "おえういあ") (->char-set "あいうえお")) #t) (test (char-set>= (->char-set "おえういあ") (->char-set "あおい")) #t) (test (char-set>= (->char-set "あおい") (->char-set "おえういあ")) #f) (test (let ((cs (->char-set "あいうえお"))) (char-set-every (cut char-set-contains? cs <>) cs)) #t) (test (let ((cs1 (->char-set "あおい")) (cs2 (->char-set "あいうえお"))) (char-set-every (cut char-set-contains? cs1 <>) cs2)) #f) (test (let ((cs1 (->char-set "あおい")) (cs2 (->char-set "あいうえお"))) (char-set-any (cut char-set-contains? cs1 <>) cs2)) #t) (test (char-set-any char-alphabetic? (->char-set "あいうえお")) #f) (test (char-set-contains? (->char-set "あa字") (string-ref "あ" 0)) #t) (test (char-set-contains? (->char-set "あa字") (string-ref "a" 0)) #t) (test (char-set-contains? (->char-set "あa字") (string-ref "字" 0)) #t) (test (char-set-contains? (->char-set "あa字") (string-ref "い" 0)) #f) (test (char-set= (->char-set "a") (char-set-filter char-alphabetic? (->char-set "あa字"))) #t) (test (char-set= (->char-set "あa字") (char-set-adjoin (->char-set "あ字") #\a)) #t) (test (char-set= (->char-set "あ字") (char-set-delete (->char-set "あa字") #\a)) #t) (test (map string (sort (char-set-fold cons '() (->char-set "あいうえお")) charchar-set "一二三") (char-set-unfold (lambda (i) (integer->char (inexact->exact (+ (* -135.5 i i) (* 275.5 i) 19968)))) (cut >= <> 3) add1 0)) #t) (test (char-set= (->char-set "ABCあ") (char-set-map char-upcase (->char-set "abcあ"))) #t) (test (let ((sum 0)) (char-set-for-each (lambda _ (set! sum (+ sum 1))) (->char-set "ABCあ")) sum) 4) (test (char-set= (->char-set "あいうえお") (char-set-union (->char-set "えい") (->char-set "うあお"))) #t) (test (char-set= (->char-set "あおい") (char-set-intersection (->char-set "あいうえお") (->char-set "いおあ"))) #t) (test (char-set= (->char-set "あお") (char-set-difference (->char-set "あいうえお") (->char-set "うえい"))) #t) (test (char-set= (->char-set "あおえかき") (char-set-xor (->char-set "あいうえお") (->char-set "きういか"))) #t) (test (char-set= (->char-set "あぃいぅうぇ") (ucs-range->char-set #x3042 #x3048)) #t) (let ((cs (char-set-complement char-set:letter))) (test (char-set-contains? cs #\a) #f) (test (char-set-contains? cs (string-ref "あ" 0)) #t) ) (let ((cs (char-set-complement (ucs-range->char-set #x3042 #x3090)))) (test (char-set-contains? cs #\a) #t) (test (char-set-contains? cs (string-ref "あ" 0)) #f) ) (test (char-set-contains? char-set:lower-case #\a) #t) (test (char-set-contains? char-set:lower-case #\A) #f) (test (char-set-contains? char-set:lower-case (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:upper-case #\a) #f) (test (char-set-contains? char-set:upper-case #\A) #t) (test (char-set-contains? char-set:upper-case (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:title-case #\a) #f) (test (char-set-contains? char-set:title-case #\A) #f) (test (char-set-contains? char-set:letter #\a) #t) (test (char-set-contains? char-set:letter #\0) #f) (test (char-set-contains? char-set:letter (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:digit #\0) #t) (test (char-set-contains? char-set:digit #\a) #f) (test (char-set-contains? char-set:digit (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:hex-digit #\f) #t) (test (char-set-contains? char-set:hex-digit #\g) #f) (test (char-set-contains? char-set:hex-digit (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:letter+digit #\z) #t) (test (char-set-contains? char-set:letter+digit #\.) #f) (test (char-set-contains? char-set:letter+digit (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:punctuation #\.) #t) (test (char-set-contains? char-set:punctuation #\a) #f) (test (char-set-contains? char-set:punctuation (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:symbol #\+) #t) (test (char-set-contains? char-set:symbol #\.) #f) (test (char-set-contains? char-set:symbol (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:whitespace #\newline) #t) (test (char-set-contains? char-set:whitespace #\_) #f) (test (char-set-contains? char-set:whitespace (string-ref " " 0)) #f) (test (char-set-contains? char-set:blank #\space) #t) (test (char-set-contains? char-set:blank #\newline) #f) (test (char-set-contains? char-set:blank (string-ref " " 0)) #f) (test (char-set-contains? char-set:graphic #\a) #t) (test (char-set-contains? char-set:graphic #\space) #f) (test (char-set-contains? char-set:graphic (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:printing #\space) #t) (test (char-set-contains? char-set:printing (integer->char 0)) #f) (test (char-set-contains? char-set:printing (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:iso-control (integer->char 0)) #t) (test (char-set-contains? char-set:iso-control #\a) #f) (test (char-set-contains? char-set:iso-control (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:ascii #\a) #t) (test (char-set-contains? char-set:ascii (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:empty #\a) #f) (test (char-set-contains? char-set:empty (string-ref "あ" 0)) #f) (test (char-set-contains? char-set:full #\a) #t) (test (char-set-contains? char-set:full (string-ref "あ" 0)) #t) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; regex (test (string-match "a.c" "abc") '("abc")) (test (string-match "a.c" "aうc") '("aうc")) (test (string-match "a.c" "ac") #f) (test (string-match "a.*c" "aうc") '("aうc")) (test (string-match "a[あい0-9えお]c" "a0c") '("a0c")) (test (string-match "a[あい0-9えお]c" "aいc") '("aいc")) (test (string-match "a[あい0-9えお]c" "aうc") #f) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; report (display "Tests complete.") (newline) (display "Pass: ") (display *pass*) (newline) (display "Fail: ") (display *fail*) (newline)