instaweb-test.ss
#lang scheme/base 

(require (for-syntax scheme/base)
         net/url
         scheme/port
         scheme/runtime-path
         (planet schematics/schemeunit:2/test)
         "instaweb.ss")

(define (make-dummy)
  (with-output-to-file "dummy.ss"
    (lambda ()
      (write '(module dummy mzscheme
                (require net/url
                         web-server/dispatchers/dispatch
                         web-server/servlet)
                
                (provide interface-version timeout start)
                
                (define interface-version 'v1)
                (define timeout +inf.0)
                (define (start initial-request)
                  (if (equal? (url->string (request-uri initial-request)) "/dummy.txt")
                      (next-dispatcher)
                      (make-response/full 200
                       "OK"
                       (current-seconds)
                       #"text/plain"
                       '()
                       '("foo\r\n")))))))
    #:exists 'replace))

(define-syntax spawn-instaweb
  (syntax-rules ()
    [(spawn-instaweb args ...)
     (begin (sleep 1)
            (let ([server (thread (lambda () 
                                    (instaweb args ...)))])
              (sleep 1)
              server))]))

(define (read-content url)
  (get-pure-port (string->url url)))

(define-runtime-path here
  ".")

(define instaweb-tests
  (test-suite "instaweb.ss"
    
    (test-case "listen on the correct port and IP"
      (before (make-dummy)
              (let ([server (spawn-instaweb #:port 4567 #:servlet-path "dummy.ss")]
                    [content (read-content "http://127.0.0.1:4567/servlets/dummy.ss")])
                (check string=? (port->string content) "foo\r\n")
                ; check the server is not listening on other ports
                (check-exn exn:fail:network?
                  (lambda ()
                    (read-content "http://127.0.0.1:8123/servlets/dummy.ss")))
                (kill-thread server))))
    
    (test-case "stop reading from stdin if input port returns eof"
      (before
       (make-dummy)
       (let* ([op (open-output-string)]
              [server
               (thread
                (lambda ()
                  (parameterize
                      ((current-input-port (open-input-string ""))
                       (current-output-port op))
                    (instaweb #:port 4567
                              #:listen-ip "127.0.0.1"
                              #:servlet-path "dummy.ss"))))])
         (kill-thread server)
         (let ((content (get-output-string op)))
           (display content)
           (check <=
                  (string-length content)
                  218)))))
    
    (test-case "read default htdocs-paths"
      (around (begin (make-directory "htdocs")
                     (with-output-to-file "htdocs/dummy.txt"
                       (lambda () (display "boo-yah!"))))
              (let ([server (spawn-instaweb #:servlet-path "dummy.ss")])
                (check-equal? (port->string (read-content "http://127.0.0.1:8765/dummy.txt"))
                              "boo-yah!")
                (kill-thread server))
              (begin (delete-file "htdocs/dummy.txt")
                     (delete-directory "htdocs"))))
    
    (test-case "read specified htdocs-path"
      (around (begin (make-directory "public-htdocs")
                     (with-output-to-file "public-htdocs/dummy.txt"
                       (lambda () (display "boo-yah!"))))
              (let ([server (spawn-instaweb #:port 4320
                                            #:servlet-path "dummy.ss"
                                            #:htdocs-paths '("public-htdocs"))])
                (check-equal? (port->string (read-content "http://127.0.0.1:4320/")) "foo\r\n")
                (check-equal? (port->string (read-content "http://127.0.0.1:4320/dummy.txt")) "boo-yah!")
                (kill-thread server))
              (begin (delete-file "public-htdocs/dummy.txt")
                     (delete-directory "public-htdocs"))))))

; Provide statements -----------------------------

(provide instaweb-tests)