Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ pom.xml.asc
.lein-failures
.lein-plugins
.lein-env
/.lein-repl-history
/.repl
23 changes: 20 additions & 3 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
(defproject ring-mock "0.1.3"
(defproject ring-mock "0.1.4-SNAPSHOT"
:description "A library for creating mock Ring request maps"
:dependencies [[org.clojure/clojure "1.2.1"]]
:plugins [[codox "0.6.1"]])
:dependencies [[org.clojure/clojure "1.5.0"]]
:profiles {:dev {:dependencies [[com.cemerick/clojurescript.test "0.0.2"]]}}
:plugins [; [codox "0.6.1"]
[lein-cljsbuild "0.3.0"]]
:hooks [leiningen.cljsbuild]
:cljsbuild {:builds
[{:compiler {:output-to "target/ring-mock-debug.js"
:optimizations :whitespace
:pretty-print true}
:source-paths ["src"]}
{:compiler {:output-to "target/ring-mock-test.js"
:optimizations :advanced
:pretty-print true}
:source-paths ["test"]}
{:compiler {:output-to "target/ring-mock.js"
:optimizations :advanced
:pretty-print false}
:source-paths ["src"]}]
:test-commands {"unit-tests" ["runners/phantomjs.js" "target/ring-mock-test.js"]}})
23 changes: 23 additions & 0 deletions runners/phantomjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env phantomjs

// reusable phantomjs script for running clojurescript.test tests
// see http://github.com/cemerick/clojurescript.test for more info

var p = require('webpage').create();
p.injectJs(require('system').args[1]);

p.onConsoleMessage = function (x) { console.log(x); };
p.evaluate(function () {
cemerick.cljs.test.set_print_fn_BANG_(function(x) {
x = x.replace(/\n/g, "");
console.log(x);
});
});

var success = p.evaluate(function () {
var results = cemerick.cljs.test.run_all_tests();
console.log(results);
return cemerick.cljs.test.successful_QMARK_(results);
});

phantom.exit(success ? 0 : 1);
104 changes: 104 additions & 0 deletions src/ring/mock/request.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
(ns ring.mock.request
"Functions to create mock request maps."
(:import goog.Uri)
(:require [clojure.string :as string]))

(defn- encode-params
"Turn a map of parameters into a urlencoded string."
[params]
(let [encode #(-> (js/encodeURIComponent %1)
(string/replace "%20" "+"))]
(string/join "&"
(for [[k v] params]
(str (encode (name k)) "="
(encode (str v)))))))

(defn header
"Add a HTTP header to the request map."
[request header value]
(let [header (string/lower-case (name header))]
(assoc-in request [:headers header] (str value))))

(defn content-type
"Set the content type of the request map."
[request mime-type]
(-> request
(assoc :content-type mime-type)
(header :content-type mime-type)))

(defn content-length
"Set the content length of the request map."
[request length]
(-> request
(assoc :content-length length)
(header :content-length length)))

(defn- combined-query
"Create a query string from a URI and a map of parameters."
[request params]
(let [query (:query-string request)]
(if (or query params)
(string/join "&"
(remove string/blank?
[query (encode-params params)])))))

(defn- merge-query
"Merge the supplied parameters into the query string of the request."
[request params]
(assoc request :query-string (combined-query request params)))

(defn query-string
"Set the query string of the request to a string or a map of parameters."
[request params]
(if (map? params)
(assoc request :query-string (encode-params params))
(assoc request :query-string params)))

(defmulti body
"Set the body of the request. The supplied body value can be a string or
a map of parameters to be url-encoded."
{:arglists '([request body-value])}
(fn [request x] (type x)))

(defmethod body cljs.core/ObjMap [request params]
(-> request
(content-type "application/x-www-form-urlencoded")
(body (encode-params params))))

(defmethod body nil [request params]
request)

(defmethod body :default [request content]
(let [content (str content)]
(-> request
(content-length (count content))
(assoc :body content))))

(defn request
"Create a minimal valid request map from a HTTP method keyword, a string
containing a URI, and an optional map of parameters that will be added to
the query string of the URI. The URI can be relative or absolute. Relative
URIs are assumed to go to http://localhost."
([method uri]
(request method uri nil))
([method uri params]
(let [uri (Uri/parse uri)
host (if (string/blank? (.getDomain uri)) "localhost" (.getDomain uri))
port (if (not= (.getPort uri) -1) (.getPort uri))
scheme (.getScheme uri)
path (.getPath uri)
query (if-not (string/blank? (.getQuery uri)) (.getQuery uri))
request {:server-port (or port 80)
:server-name host
:remote-addr "localhost"
:uri (if (string/blank? path) "/" path)
:query-string query
:scheme (if (string/blank? scheme)
:http (keyword scheme))
:request-method method
:headers {"host" (if port
(str host ":" port)
host)}}]
(if (#{:get :head} method)
(merge-query request params)
(body request params)))))
6 changes: 3 additions & 3 deletions test/ring/mock/test/request.clj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
(is (= (:uri (request :get "http://example.com")) "/")))
(testing "added params in :get"
(is (= (:query-string (request :get "/" {:x "y" :z "n"}))
"x=y&z=n"))
"z=n&x=y"))
(is (= (:query-string (request :get "/?a=b" {:x "y"}))
"a=b&x=y"))
(is (= (:query-string (request :get "/?" {:x "y"}))
Expand All @@ -47,7 +47,7 @@
(testing "added params in :post"
(let [req (request :post "/" {:x "y" :z "n"})]
(is (= (slurp (:body req))
"x=y&z=n"))
"z=n&x=y"))
(is (nil? (:query-string req))))
(let [req (request :post "/?a=b" {:x "y"})]
(is (= (slurp (:body req))
Expand All @@ -69,7 +69,7 @@
"a=b"))))
(testing "added params in :put"
(let [req (request :put "/" {:x "y" :z "n"})]
(is (= (slurp (:body req)) "x=y&z=n")))))
(is (= (slurp (:body req)) "z=n&x=y")))))

(deftest test-header
(is (= (header {} "X-Foo" "Bar")
Expand Down
111 changes: 111 additions & 0 deletions test/ring/mock/test/request.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
(ns ring.mock.test.request
(:require-macros [cemerick.cljs.test :refer [is deftest testing]])
(:require [cemerick.cljs.test :as t]
[ring.mock.request :refer [body content-length content-type header request query-string]]))

(deftest test-request
(testing "relative uri"
(is (= (request :get "/foo")
{:server-port 80
:server-name "localhost"
:remote-addr "localhost"
:uri "/foo"
:query-string nil
:scheme :http
:request-method :get
:headers {"host" "localhost"}})))
(testing "absolute uri"
(let [request (request :post "https://example.com:8443/foo?bar=baz" {"quux" "zot"})
literal-request (dissoc request :body)
body (:body request)]
(is (= literal-request
{:server-port 8443
:server-name "example.com"
:remote-addr "localhost"
:uri "/foo"
:query-string "bar=baz"
:scheme :https
:request-method :post
:content-type "application/x-www-form-urlencoded"
:content-length 8
:headers {"host" "example.com:8443"
"content-type" "application/x-www-form-urlencoded"
"content-length" "8"}}))
(is (= body "quux=zot"))))
(testing "nil path"
(is (= (:uri (request :get "http://example.com")) "/")))
(testing "added params in :get"
(is (= (:query-string (request :get "/" {:x "y" :z "n"}))
"x=y&z=n"))
(is (= (:query-string (request :get "/?a=b" {:x "y"}))
"a=b&x=y"))
(is (= (:query-string (request :get "/?" {:x "y"}))
"x=y"))
(is (= (:query-string (request :get "/" {:x "a b"}))
"x=a+b")))
(testing "added params in :post"
(let [req (request :post "/" {:x "y" :z "n"})]
(is (= (:body req)
"x=y&z=n"))
(is (nil? (:query-string req))))
(let [req (request :post "/?a=b" {:x "y"})]
(is (= (:body req)
"x=y"))
(is (= (:query-string req)
"a=b")))
(let [req (request :post "/?" {:x "y"})]
(is (= (:body req)
"x=y"))
(is (nil? (:query-string req))))
(let [req (request :post "/" {:x "a b"})]
(is (= (:body req)
"x=a+b"))
(is (nil? (:query-string req))))
(let [req (request :post "/?a=b")]
(is (nil? (:body req)))
(is (= (:query-string req)
"a=b"))))
(testing "added params in :put"
(let [req (request :put "/" {:x "y" :z "n"})]
(is (= (:body req) "x=y&z=n")))))

(deftest test-header
(is (= (header {} "X-Foo" "Bar")
{:headers {"x-foo" "Bar"}}))
(is (= (header {} :x-foo "Bar")
{:headers {"x-foo" "Bar"}})))

(deftest test-content-type
(is (= (content-type {} "text/html")
{:content-type "text/html"
:headers {"content-type" "text/html"}})))

(deftest test-content-length
(is (= (content-length {} 10)
{:content-length 10
:headers {"content-length" "10"}})))

(deftest test-query-string
(testing "string"
(is (= (query-string {} "a=b")
{:query-string "a=b"})))
(testing "map of params"
(is (= (query-string {} {:a "b"})
{:query-string "a=b"})))
(testing "overwriting"
(is (= (-> {}
(query-string {:a "b"})
(query-string {:c "d"}))
{:query-string "c=d"}))))

(deftest test-body
(testing "string body"
(let [resp (body {} "Hello World")]
(is (= (:body resp) "Hello World"))
(is (= (:content-length resp) 11))))
(testing "map body"
(let [resp (body {} {:foo "bar"})]
(is (= (:body resp) "foo=bar"))
(is (= (:content-length resp) 7))
(is (= (:content-type resp)
"application/x-www-form-urlencoded")))))