(module sql-quote-unit-test mzscheme
(require (lib "unitsig.ss")
(lib "string.ss" "srfi" "13")
(lib "time.ss" "srfi" "19"))
(require (planet "spgsql.ss" ("schematics" "spgsql.plt" 2)))
(require (file "../era.ss")
(file "../test-base.ss")
(file "../test-data.ss")
(file "../type.ss")
(file "../generic/sql-sig.ss")
(file "sql-quote-unit.ss"))
(provide sql-quote-unit-tests)
(define-values/invoke-unit/sig sql-quote^ sql-quote@)
(define sql-quote-unit-tests
(test-suite
"sql-quote-unit.ss"
(test-equal?
"quote-id wraps symbol id in \"double quotes\""
(quote-id 'my-id)
"\"my-id\"")
(test-equal?
"quote-id wraps string id in \"double quotes\""
(quote-id "my-id")
"\"my-id\"")
(test-equal?
"quote-data quotes writes strings 'in quotes'"
(quote-data type:text "Hi Mom!")
"'Hi Mom!'")
(test-equal?
"quote-data escapes ' characters in quoted strings"
(quote-data type:text "'There's too much confusion!'")
"'''There''s too much confusion!'''")
(test-equal?
"quote-data converts numbers to strings"
(quote-data type:integer/1 2)
"2")
(test-equal?
"quote-data converts boolean #t correctly"
(quote-data type:boolean/t #t)
"true")
(test-equal?
"quote-data converts boolean #f correctly"
(quote-data type:boolean/t #f)
"false")
(test-equal?
"quote-data converts #f id to NULL"
(quote-data type:id #f)
"NULL")
(test-equal?
"quote-data converts number id to string"
(quote-data type:id 2)
"2")
(test-equal?
"quote-data converts #f revision to NULL"
(quote-data type:revision #f)
"NULL")
(test-equal?
"quote-data converts number revision to string"
(quote-data type:revision 2)
"2")
(test-case
"quote-data quotes time-tai data correctly"
(check-equal? (quote-data type:time-tai #f) "NULL" "Test 1 failed")
(check-equal? (quote-data type:time-tai (make-time time-tai 0 0)) "'1970-01-01 00:00:00.000000000'" "Test 2 failed")
(check-equal? (quote-data type:time-tai (make-time time-tai 1 0)) "'1970-01-01 00:00:00.000000001'" "Test 3 failed")
(check-equal? (quote-data type:time-tai (make-time time-tai 1000 0)) "'1970-01-01 00:00:00.000001000'" "Test 4 failed")
(check-equal? (quote-data type:time-tai (make-time time-tai 123456789 0)) "'1970-01-01 00:00:00.123456789'" "Test 5 failed")
(check-equal? (quote-data type:time-tai (make-time time-tai 123456789 1)) "'1970-01-01 00:00:01.123456789'" "Test 6 failed")
(check-equal? (quote-data type:time-tai time1) "'2001-01-01 01:01:01.000000000'" "Test 7 failed")
(check-equal? (quote-data type:time-tai time2) "'2002-02-02 02:02:02.000000000'" "Test 8 failed")
(check-equal? (quote-data type:time-tai time3) "'9999-01-01 01:01:01.000000000'" "Test 8 failed"))
(test-case
"quote-data raises exn on type mismatch: id"
(check-exn exn:fail:snooze? (lambda () (quote-data type:id "123")))
(check-not-exn (lambda () (quote-data type:id 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:id 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:id #t)))
(check-not-exn (lambda () (quote-data type:id #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:id time1))))
(test-case
"quote-data raises exn on type mismatch: revision"
(check-exn exn:fail:snooze? (lambda () (quote-data type:revision "123")))
(check-not-exn (lambda () (quote-data type:revision 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:revision 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:revision #t)))
(check-not-exn (lambda () (quote-data type:revision #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:revision time1))))
(test-case
"quote-data raises exn on type mismatch: text"
(check-not-exn (lambda () (quote-data type:text "123")))
(check-exn exn:fail:snooze? (lambda () (quote-data type:text 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:text 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:text #t)))
(check-not-exn (lambda () (quote-data type:text #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:text time1))))
(test-case
"quote-data raises exn on type mismatch: integer"
(check-exn exn:fail:snooze? (lambda () (quote-data type:integer "123")))
(check-not-exn (lambda () (quote-data type:integer 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:integer 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:integer #t)))
(check-not-exn (lambda () (quote-data type:integer #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:integer time1))))
(test-case
"quote-data raises exn on type mismatch: symbol"
(check-exn exn:fail:snooze? (lambda () (quote-data type:symbol "123")))
(check-exn exn:fail:snooze? (lambda () (quote-data type:symbol 123)))
(check-not-exn (lambda () (quote-data type:symbol 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:symbol #t)))
(check-not-exn (lambda () (quote-data type:symbol #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:symbol #t)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:symbol time1))))
(test-case
"quote-data raises exn on type mismatch: boolean"
(check-exn exn:fail:snooze? (lambda () (quote-data type:boolean "123")))
(check-exn exn:fail:snooze? (lambda () (quote-data type:boolean 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:boolean 'abc)))
(check-not-exn (lambda () (quote-data type:boolean #t)))
(check-not-exn (lambda () (quote-data type:boolean #f)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:boolean time1))))
(test-case
"quote-data raises exn on type mismatch: time-tai"
(check-exn exn:fail:snooze? (lambda () (quote-data type:time-tai "123")))
(check-exn exn:fail:snooze? (lambda () (quote-data type:time-tai 123)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:time-tai 'abc)))
(check-exn exn:fail:snooze? (lambda () (quote-data type:time-tai #t)))
(check-not-exn (lambda () (quote-data type:time-tai #f)))
(check-not-exn (lambda () (quote-data type:time-tai time1))))
(test-exn
"quote-data raises exception with unknown type"
exn:fail:contract?
(lambda () (quote-data 'foo "hello")))
(test-exn
"unquote-data raises exception with unknown type"
exn:fail:contract?
(lambda () (unquote-data 'foo "hello")))
(test-case
"unquote-data converts normal data correctly"
(check equal? (unquote-data type:text "foo") "foo")
(check equal? (unquote-data type:integer/1 2) 2)
(check equal? (unquote-data type:id 2) 2)
(check equal? (unquote-data type:revision 2) 2)
(check equal? (unquote-data type:symbol "abc") 'abc)
(check equal? (unquote-data type:boolean/t #t) #t)
(check equal? (unquote-data type:boolean/t #f) #f))
(test-case
"unquote-data converts normal time-tai data correctly"
(check-exn exn:fail:snooze? (lambda () (unquote-data type:time-tai "")) "Test 1 failed")
(check-equal? (unquote-data type:time-tai (make-sql-timestamp 9999 1 1 1 1 1 0 0)) time3 "Test 2 failed")
(check-equal? (unquote-data type:time-tai (make-sql-timestamp 1234 12 23 12 34 56 123456000 0))
(date->time-tai (make-srfi:date 123456000 56 34 12 23 12 1234 0))
"Test 3 failed"))
(test-case
"unquote-data converts blank and null data correctly"
(check equal? (unquote-data type:text "") "")
(check equal? (unquote-data type:text sql-null) #f)
(check equal? (unquote-data type:integer/1 0) 0)
(check equal? (unquote-data type:integer/1 sql-null) #f)
(check equal? (unquote-data type:id 0) 0)
(check equal? (unquote-data type:revision sql-null) #f)
(check equal? (unquote-data type:revision 0) 0)
(check equal? (unquote-data type:id sql-null) #f)
(check equal? (unquote-data type:symbol "") '||)
(check equal? (unquote-data type:symbol sql-null) #f)
(check equal? (unquote-data type:boolean/t #f) #f)
(check equal? (unquote-data type:boolean/t sql-null) #f)
(check equal? (unquote-data type:time-tai sql-null) #f))
(test-equal?
"data-unquoter works on non-null values"
(let ([unquote (make-data-unquoter (list type:id type:revision type:text type:integer/1 type:symbol type:boolean/t type:time-tai))])
(unquote (vector 1 2 "abc" 3 "def" #t (make-sql-timestamp 1234 12 23 12 34 56 123456000 0))))
(vector 1 2 "abc" 3 'def #t (date->time-tai (make-srfi:date 123456000 56 34 12 23 12 1234 0))))
(test-equal?
"data-unquoter works on null values"
(let ([unquote (make-data-unquoter (list type:id type:revision type:text type:integer/1 type:symbol type:boolean/t type:time-tai))])
(unquote (vector sql-null sql-null sql-null sql-null sql-null sql-null sql-null)))
(vector #f #f #f #f #f #f #f))
))
)