Last active
March 13, 2026 21:33
-
-
Save wdhowe/3aa8b882a14a50e5ddb317458e46e8c6 to your computer and use it in GitHub Desktop.
Clojure reflection warnings test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns myorg.myproject.reflection-test | |
| "Tests for detecting reflection warnings in the codebase. | |
| Usage: | |
| clj -X:test :patterns '[\".*reflection.*\"]' | |
| Lenient - prints warnings but passes | |
| clj -X:test :patterns '[\".*reflection.*\"]' :includes '[:strict]' | |
| Strict - fails on any warnings" | |
| (:require [clojure.test :refer [deftest is testing]]) | |
| (:import [java.io PrintWriter StringWriter])) | |
| (def ^:private project-namespaces | |
| "All project namespaces to check for reflection warnings. | |
| Include core (which loads its dependencies via :reload-all) | |
| and any other namespaces not reached transitively via core." | |
| '[myorg.myproject.core | |
| myorg.myproject.other]) | |
| (defn- collect-reflection-warnings | |
| "Reload all namespaces with *warn-on-reflection* and capture warnings." | |
| [] | |
| (let [warnings (StringWriter.)] | |
| (binding [*warn-on-reflection* true | |
| *err* (PrintWriter. warnings)] | |
| (doseq [ns-sym project-namespaces] | |
| (require ns-sym :reload-all))) | |
| (str warnings))) | |
| (def ^:private own-ns-prefix | |
| "Classpath prefix for this project's namespaces. | |
| Captured at compile time when *ns* is correctly bound." | |
| (str/join "/" (-> (str *ns*) | |
| (str/replace "-" "_") | |
| (str/split #"\.") | |
| drop-last))) | |
| (defn- filter-own-warnings | |
| "Filter reflection warnings to only those from our own namespaces. | |
| Third-party library warnings are not actionable." | |
| [warnings] | |
| (->> (str/split-lines warnings) | |
| (filter #(str/includes? % own-ns-prefix)) | |
| (str/join "\n"))) | |
| (deftest check-reflection-warnings | |
| (testing "Compile all namespaces and print any reflection warnings" | |
| (let [warnings (filter-own-warnings (collect-reflection-warnings))] | |
| (when (seq warnings) | |
| (println "Reflection warnings:\n" warnings))))) | |
| (deftest ^:strict check-reflection-warnings-strict | |
| (testing "Compile all namespaces and fail if reflection warnings exist" | |
| (let [warnings (filter-own-warnings (collect-reflection-warnings))] | |
| (is (empty? warnings) | |
| (str "Reflection warnings found:\n" warnings))))) | |
| ;;; Optionally pair with the aliases below to exclude/include the strict test. ;;; | |
| :aliases | |
| { | |
| ;; Run tests: clj -X:test OR clj -M:test (excludes :strict tests by default) | |
| :test {:extra-paths ["test"] | |
| :extra-deps {org.clojure/test.check {:mvn/version "1.1.2"} | |
| io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"}} | |
| ;; For clj -X:test | |
| :exec-fn cognitect.test-runner.api/test | |
| :exec-args {:excludes [:strict]} | |
| ;; For clj -M:test (calls System/exit) | |
| :main-opts ["-m" "cognitect.test-runner" "-e" ":strict"]} | |
| ;; Run strict reflection tests: clj -X:test-reflection OR clj -M:test-reflection | |
| :test-reflection {:extra-paths ["test"] | |
| :extra-deps {org.clojure/test.check {:mvn/version "1.1.2"} | |
| io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"}} | |
| ;; For clj -X:test-reflection | |
| :exec-fn cognitect.test-runner.api/test | |
| :exec-args {:patterns [".*reflection.*"] | |
| :includes [:strict]} | |
| ;; For clj -M:test-reflection (calls System/exit) | |
| :main-opts ["-m" "cognitect.test-runner" | |
| "-r" ".*reflection.*" | |
| "-i" ":strict"]} | |
| } | |
| ;;; Snippet to add to core.clj or another file to verify reflection test is working ;;; | |
| (defn- reflection-test-trigger "No type hint; trigger reflection warning." [s] | |
| (.length s)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment