From 8d04e654773dbb53fd3361d9c5995bb55bee8aa9 Mon Sep 17 00:00:00 2001 From: tooooolong Date: Fri, 3 Apr 2026 22:31:49 +0800 Subject: [PATCH] fix cobertura source roots --- .gitignore | 1 + deps.edn | 3 +- src/cloverage/coverage/cobertura.clj | 17 +++++++- test/cloverage/coverage/cobertura_test.clj | 46 ++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 test/cloverage/coverage/cobertura_test.clj diff --git a/.gitignore b/.gitignore index 881b458..4f2bf35 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ pom.xml.asc *.class /.lein-* /.nrepl-port +.cpcache/ .hgignore .hg/ diff --git a/deps.edn b/deps.edn index 56e1d5e..63cac0f 100644 --- a/deps.edn +++ b/deps.edn @@ -10,8 +10,9 @@ ;; published JAR. Adjust the require and run-tests call for your own project. :test {:extra-paths ["dev" "test"] + :extra-deps {cloverage/cloverage {:mvn/version "1.2.4"}} :main-opts ["-e" - "(require 'example.core-test 'clojure.test)(let [r (clojure.test/run-tests 'example.core-test)](System/exit (if (pos? (+ (:fail r) (:error r))) 1 0)))"]} + "(require 'example.core-test 'cloverage.coverage.cobertura-test 'clojure.test)(let [r (apply clojure.test/run-tests ['example.core-test 'cloverage.coverage.cobertura-test])](System/exit (if (pos? (+ (:fail r) (:error r))) 1 0)))"]} ;; Run cloverage with the Cobertura XML reporter: ;; clj -M:coverage diff --git a/src/cloverage/coverage/cobertura.clj b/src/cloverage/coverage/cobertura.clj index 4536e57..865ac13 100644 --- a/src/cloverage/coverage/cobertura.clj +++ b/src/cloverage/coverage/cobertura.clj @@ -56,6 +56,18 @@ [file] (str/replace (str file) java.io.File/separator "/")) +(defn- source-roots + "Returns Cobertura source roots from cloverage args, preserving order." + [args] + (let [roots (->> (:src-ns-path args) + (map normalize-path) + (map #(str/replace % #"/+$" "")) + (remove str/blank?) + distinct)] + (if (seq roots) + roots + ["src"]))) + ;; --------------------------------------------------------------------------- ;; XML sexp builders ;; --------------------------------------------------------------------------- @@ -109,10 +121,11 @@ :forms - raw coverage forms collection :args - parsed cloverage CLI options :project - Leiningen project map" - [{:keys [output forms]}] + [{:keys [output forms args]}] (let [output-file (io/file output "cobertura.xml") stats (doall (file-stats forms)) forms-by-file (group-by :file forms) + sources (source-roots args) total-covered (reduce + 0 (map #(or (:covered-lines %) 0) stats)) total-instrd (reduce + 0 (map #(or (:instrd-lines %) 0) stats)) timestamp (quot (System/currentTimeMillis) 1000) @@ -142,7 +155,7 @@ :complexity "0" :version "1" :timestamp (str timestamp)} - [:sources [:source "src"]] + (into [:sources] (map (fn [source] [:source source]) sources)) (into [:packages] pkg-sexps)]] (io/make-parents output-file) diff --git a/test/cloverage/coverage/cobertura_test.clj b/test/cloverage/coverage/cobertura_test.clj new file mode 100644 index 0000000..5800a7c --- /dev/null +++ b/test/cloverage/coverage/cobertura_test.clj @@ -0,0 +1,46 @@ +(ns cloverage.coverage.cobertura-test + (:require [clojure.java.io :as io] + [clojure.test :refer [deftest is]] + [clojure.xml :as xml] + [cloverage.coverage.cobertura :as cobertura])) + +(def ^:private sample-forms + [{:file "exchange/api/restful/accounts.clj" + :lib 'exchange.api.restful.accounts + :line 42 + :text "(accounts)" + :tracked true + :covered true + :hits 1}]) + +(defn- report-xml + [src-ns-path] + (let [output-dir (.toFile (java.nio.file.Files/createTempDirectory "cobertura-report" + (make-array java.nio.file.attribute.FileAttribute 0)))] + (cobertura/report {:output (.getAbsolutePath output-dir) + :forms sample-forms + :args {:src-ns-path src-ns-path}}) + (with-open [in (io/input-stream (io/file output-dir "cobertura.xml"))] + (xml/parse in)))) + +(defn- xml-elements + [doc tag] + (filter #(= tag (:tag %)) + (tree-seq map? :content doc))) + +(defn- xml-text + [element] + (apply str (filter string? (:content element)))) + +(deftest report-uses-src-ns-path-for-sources + (let [doc (report-xml ["src/main/clojure"]) + sources (map xml-text (xml-elements doc :source)) + class-node (first (xml-elements doc :class))] + (is (= ["src/main/clojure"] sources)) + (is (= "exchange/api/restful/accounts.clj" + (get-in class-node [:attrs :filename]))))) + +(deftest report-supports-multiple-source-roots + (let [doc (report-xml ["src/main/clojure" "src/shared/clojure"]) + sources (map xml-text (xml-elements doc :source))] + (is (= ["src/main/clojure" "src/shared/clojure"] sources))))