From 58d7dba6be314bae223e707dc3d045752ef82691 Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Sat, 11 Apr 2026 21:36:24 +0300 Subject: Validate conflicting trie parameter names Throw on conflicting param, optional, and wildcard names at the same trie position and add cross-runtime tests to enforce the behavior. --- test/ruuter/core_test.cljc | 107 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) (limited to 'test/ruuter/core_test.cljc') diff --git a/test/ruuter/core_test.cljc b/test/ruuter/core_test.cljc index 9f47212..d9150e6 100644 --- a/test/ruuter/core_test.cljc +++ b/test/ruuter/core_test.cljc @@ -348,3 +348,110 @@ (ruuter/route [{:path "/hello" :method :get :response "just a string"}] {:uri "/hello" :request-method :get}))))) + +;; -- Conflicting Parameter Name Tests -- + +#?(:clj + (deftest conflicting-param-names-test + (testing "Conflicting :param names — throws exception" + (is (thrown? clojure.lang.ExceptionInfo + (ruuter/route [{:path "/user/:id" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/user/:x" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/user/42" :request-method :get})))) + + (testing "Conflicting :param names across methods — throws exception" + (is (thrown? clojure.lang.ExceptionInfo + (ruuter/route [{:path "/user/:id" :method :get + :response (fn [req] {:status 200 :body "get"})} + {:path "/user/:x" :method :post + :response (fn [req] {:status 200 :body "post"})}] + {:uri "/user/42" :request-method :get}))))) + + :cljs + (deftest conflicting-param-names-test + (testing "Conflicting :param names — throws exception" + (is (thrown? ExceptionInfo + (ruuter/route [{:path "/user/:id" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/user/:x" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/user/42" :request-method :get})))) + + (testing "Conflicting :param names across methods — throws exception" + (is (thrown? ExceptionInfo + (ruuter/route [{:path "/user/:id" :method :get + :response (fn [req] {:status 200 :body "get"})} + {:path "/user/:x" :method :post + :response (fn [req] {:status 200 :body "post"})}] + {:uri "/user/42" :request-method :get})))))) + +#?(:clj + (deftest conflicting-optional-names-test + (testing "Conflicting :optional names — throws exception" + (is (thrown? clojure.lang.ExceptionInfo + (ruuter/route [{:path "/search/:q?" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/search/:query?" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/search/clojure" :request-method :get}))))) + + :cljs + (deftest conflicting-optional-names-test + (testing "Conflicting :optional names — throws exception" + (is (thrown? ExceptionInfo + (ruuter/route [{:path "/search/:q?" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/search/:query?" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/search/clojure" :request-method :get})))))) + +#?(:clj + (deftest conflicting-wildcard-names-test + (testing "Conflicting :wildcard names — throws exception" + (is (thrown? clojure.lang.ExceptionInfo + (ruuter/route [{:path "/files/:path*" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/files/:glob*" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/files/a/b/c" :request-method :get})))) + + (testing "Same wildcard name with different methods — no conflict" + (is (= {:status 200 :body "get-files"} + (ruuter/route [{:path "/files/:path*" :method :get + :response {:status 200 :body "get-files"}} + {:path "/files/:path*" :method :delete + :response {:status 200 :body "delete-files"}}] + {:uri "/files/a/b/c" :request-method :get}))) + (is (= {:status 200 :body "delete-files"} + (ruuter/route [{:path "/files/:path*" :method :get + :response {:status 200 :body "get-files"}} + {:path "/files/:path*" :method :delete + :response {:status 200 :body "delete-files"}}] + {:uri "/files/a/b/c" :request-method :delete}))))) + + :cljs + (deftest conflicting-wildcard-names-test + (testing "Conflicting :wildcard names — throws exception" + (is (thrown? ExceptionInfo + (ruuter/route [{:path "/files/:path*" :method :get + :response (fn [req] {:status 200 :body "first"})} + {:path "/files/:glob*" :method :get + :response (fn [req] {:status 200 :body "second"})}] + {:uri "/files/a/b/c" :request-method :get})))) + + (testing "Same wildcard name with different methods — no conflict" + (is (= {:status 200 :body "get-files"} + (ruuter/route [{:path "/files/:path*" :method :get + :response {:status 200 :body "get-files"}} + {:path "/files/:path*" :method :delete + :response {:status 200 :body "delete-files"}}] + {:uri "/files/a/b/c" :request-method :get}))) + (is (= {:status 200 :body "delete-files"} + (ruuter/route [{:path "/files/:path*" :method :get + :response {:status 200 :body "get-files"}} + {:path "/files/:path*" :method :delete + :response {:status 200 :body "delete-files"}}] + {:uri "/files/a/b/c" :request-method :delete})))))) + -- cgit v1.2.3