From 6f7a6dbf5674775e7c5094653bc6638ef4b16908 Mon Sep 17 00:00:00 2001 From: ajet Date: Sat, 19 Sep 2026 06:12:47 -0900 Subject: [PATCH] coverage --- test/tbd/core_test.clj | 50 +++++++++++++++++++++++++++++++++ test/tbd/health/routes_test.clj | 13 +++++++++ test/tbd/math/routes_test.clj | 30 ++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 test/tbd/core_test.clj create mode 100644 test/tbd/health/routes_test.clj create mode 100644 test/tbd/math/routes_test.clj diff --git a/test/tbd/core_test.clj b/test/tbd/core_test.clj new file mode 100644 index 0000000..b301fb7 --- /dev/null +++ b/test/tbd/core_test.clj @@ -0,0 +1,50 @@ +(ns tbd.core-test + (:require [clojure.test :refer [deftest is testing]] + [ring.middleware.defaults :refer [wrap-defaults api-defaults]] + [tbd.core :as core]) + (:import (java.io ByteArrayOutputStream PrintStream) + (java.net ServerSocket))) + +;; Same middleware stack start-server wraps around the app. +(def handler (wrap-defaults core/app api-defaults)) + +(defn request [method uri] + (handler {:request-method method :uri uri :headers {}})) + +(deftest root-test + (let [resp (request :get "/")] + (is (= 200 (:status resp))) + (is (= "text/plain; charset=utf-8" (get-in resp [:headers "Content-Type"]))) + (is (re-find #"/api-docs" (:body resp)))) + (testing "HEAD is served like GET, without a body" + (is (= 200 (:status (request :head "/")))))) + +(deftest swagger-spec-test + (let [resp (request :get "/swagger.json")] + (is (= 200 (:status resp))) + (is (re-find #"/api/ping" (slurp (:body resp)))))) + +(deftest unknown-route-test + (is (= 404 (:status (request :get "/nope"))))) + +(defmacro with-err-silenced + "start-server prints the stack trace via System/err, which with-out-str doesn't capture." + [& body] + `(let [orig# System/err] + (System/setErr (PrintStream. (ByteArrayOutputStream.))) + (try ~@body (finally (System/setErr orig#))))) + +(deftest start-server-failure-test + (testing "a port that is already taken is reported and rethrown" + (let [env-port (System/getenv "PORT")] + (with-open [taken (ServerSocket. (if env-port (parse-long env-port) 0))] + (is (thrown? Throwable + (with-err-silenced + (with-out-str + (core/start-server nil {:port (.getLocalPort taken)}))))))))) + +(deftest main-test + (let [calls (atom 0)] + (with-redefs [core/start-server (fn [& _] (swap! calls inc))] + (core/-main)) + (is (= 1 @calls)))) diff --git a/test/tbd/health/routes_test.clj b/test/tbd/health/routes_test.clj new file mode 100644 index 0000000..30725a2 --- /dev/null +++ b/test/tbd/health/routes_test.clj @@ -0,0 +1,13 @@ +(ns tbd.health.routes-test + (:require [clojure.test :refer [deftest is]] + [reitit.ring :as ring] + [tbd.health.routes :as health])) + +(def handler + (ring/ring-handler (ring/router (health/routes)))) + +(deftest ping-test + (let [resp (handler {:request-method :get :uri "/api/ping"})] + (is (= 200 (:status resp))) + (is (= "text/plain; charset=utf-8" (get-in resp [:headers "Content-Type"]))) + (is (= "pong" (:body resp))))) diff --git a/test/tbd/math/routes_test.clj b/test/tbd/math/routes_test.clj new file mode 100644 index 0000000..4b676e3 --- /dev/null +++ b/test/tbd/math/routes_test.clj @@ -0,0 +1,30 @@ +(ns tbd.math.routes-test + (:require [clojure.edn :as edn] + [clojure.test :refer [deftest is testing]] + [reitit.ring :as ring] + [ring.middleware.params :refer [wrap-params]] + [tbd.math.routes :as math])) + +;; wrap-params populates :query-params, as wrap-defaults does in tbd.core. +(def handler + (wrap-params (ring/ring-handler (ring/router (math/routes))))) + +(defn add [query] + (let [resp (handler {:request-method :get :uri "/api/add" :query-string query})] + (-> resp + (update :body edn/read-string)))) + +(deftest add-route-test + (testing "integers" + (let [resp (add "x=2&y=3")] + (is (= 200 (:status resp))) + (is (= "application/edn; charset=utf-8" (get-in resp [:headers "Content-Type"]))) + (is (= {:result 5} (:body resp))))) + (testing "decimals and negatives" + (is (= {:result 3.5} (:body (add "x=1.5&y=2")))) + (is (= {:result -1} (:body (add "x=2&y=-3"))))) + (testing "missing or non-numeric params are rejected" + (doseq [query [nil "x=2" "y=3" "x=abc&y=3" "x=2&y=abc"]] + (let [resp (add query)] + (is (= 400 (:status resp)) (str "query: " query)) + (is (contains? (:body resp) :error))))))