packages feed

hpc-threshold 0.1.0.1 → 0.1.0.2

raw patch · 7 files changed

+131/−140 lines, 7 files

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for hpc-threshold +## 0.1.0.2++Change the module name to HPCThreshold.+ ## 0.1.0.1  Added more documentation.
app/Main.hs view
@@ -1,6 +1,6 @@ module Main where -import Lib+import HPCThreshold import System.Exit  main :: IO ()
hpc-threshold.cabal view
@@ -2,11 +2,11 @@ -- -- see: https://github.com/sol/hpack ----- hash: 430b6966ee845f290543a6c8947d35feda02426dfb190eec88e3f92020f042f0+-- hash: da7496f9be2296b4dff3d2e626512cf322514acefdbf3e55fa9cb287d4322641  name:           hpc-threshold-version:        0.1.0.1-synopsis:       Configurable code coverage threshold for Haskell+version:        0.1.0.2+synopsis:       Ensure the code coverage is above configured thresholds description:    Please see the README on Github at <https://github.com/eckyputrady/hpc-threshold#readme> category:       Development homepage:       https://github.com/eckyputrady/hpc-threshold#readme@@ -38,7 +38,7 @@     , interpolate     , pcre-heavy   exposed-modules:-      Lib+      HPCThreshold   other-modules:       Paths_hpc_threshold   default-language: Haskell2010@@ -69,6 +69,6 @@     , hpc-threshold     , hspec   other-modules:-      LibSpec+      HPCThresholdSpec       Paths_hpc_threshold   default-language: Haskell2010
+ src/HPCThreshold.hs view
@@ -0,0 +1,58 @@+module HPCThreshold where++import Text.Regex.PCRE.Heavy+import Data.ByteString (ByteString)+import Data.String.Interpolate++data Threshold = Threshold+  { thresholdName :: String+  , thresholdRegex :: ByteString+  , thresholdValue :: Double+  } deriving (Read, Show, Eq)++type Coverage = Double+type ThresholdEvaluationResult = (Threshold, Coverage, Bool)++extractCoverage :: String -> ByteString -> Coverage+extractCoverage src regexStr =+  case compileM regexStr [] of+    Left e ->+      error $ "Unable to compile regex " ++ show regexStr ++ ": " ++ e +    Right regex ->+      case scan regex src of+        (_, coverage:_):_ ->+          read coverage+        _ ->+          0++evaluate :: String -> Threshold -> ThresholdEvaluationResult+evaluate src threshold =+  let +    coverage =+      extractCoverage src (thresholdRegex threshold)+    isPass =+      coverage >= thresholdValue threshold+  in+    (threshold, coverage, isPass)++reportThreshold :: ThresholdEvaluationResult -> String+reportThreshold (Threshold tName _ tValue, coverage, isPass) =+  let+    remark = if isPass then "✓" else "·" :: String+    sign = if isPass then "≥" else "<" :: String+  in+    [i|#{remark} #{tName}: #{coverage}% (#{sign} #{tValue}%)|]++evaluateAndReport :: String -> [Threshold] -> (String, Bool)+evaluateAndReport src thresholds =+  let+    evalResults = map (evaluate src) thresholds+    isAllThresholdPass = all (\(_, _, isPass) -> isPass) evalResults+    reportSummary =+      if isAllThresholdPass+        then "Code coverage threshold check: PASS"+        else "Code coverage threshold check: FAIL"+    report = unlines $ reportSummary : map reportThreshold evalResults+  in+    (report, isAllThresholdPass)+
− src/Lib.hs
@@ -1,71 +0,0 @@-module Lib where--import Text.Regex.PCRE.Heavy-import Data.ByteString (ByteString)-import Data.String.Interpolate---- | Data structure for a single threshold configuration.-data Threshold = Threshold-  { thresholdName :: String-  , thresholdRegex :: ByteString-  , thresholdValue :: Double-  } deriving (Read, Show, Eq)--type Coverage = Double---- | The result of evaluation. The _3 indicates whether the coverage passes the threshold or not.-type ThresholdEvaluationResult = (Threshold, Coverage, Bool)---- | Extract the coverage from input string using a regex string-extractCoverage -  :: String -- ^ The input string-  -> ByteString -- ^ The regex to extract the coverage. The regex should contain `(\\d+)` capture otherwise the coverage is always be 0.-  -> Coverage -- ^ The extracted coverage-extractCoverage src regexStr =-  case compileM regexStr [] of-    Left e ->-      error $ "Unable to compile regex " ++ show regexStr ++ ": " ++ e -    Right regex ->-      case scan regex src of-        (_, coverage:_):_ ->-          read coverage-        _ ->-          0---- | Evaluate the given string against the given threshold, producing an evaluation result-evaluate :: String -> Threshold -> ThresholdEvaluationResult-evaluate src threshold =-  let -    coverage =-      extractCoverage src (thresholdRegex threshold)-    isPass =-      coverage >= thresholdValue threshold-  in-    (threshold, coverage, isPass)---- | Produce a human-friendly output of the evaluation result-reportThreshold :: ThresholdEvaluationResult -> String-reportThreshold (Threshold tName _ tValue, coverage, isPass) =-  let-    remark = if isPass then "✓" else "·" :: String-    sign = if isPass then "≥" else "<" :: String-  in-    [i|#{remark} #{tName}: #{coverage}% (#{sign} #{tValue}%)|]---- | Evaluate a string against a list of thresholds configuration and produce a report-evaluateAndReport-  :: String -- ^ The input string-  -> [Threshold] -- ^ The list of thresholds-  -> (String, Bool) -- ^ Pair of report and whether there is any coverage under thresholds-evaluateAndReport src thresholds =-  let-    evalResults = map (evaluate src) thresholds-    isAllThresholdPass = all (\(_, _, isPass) -> isPass) evalResults-    reportSummary =-      if isAllThresholdPass-        then "Code coverage threshold check: PASS"-        else "Code coverage threshold check: FAIL"-    report = unlines $ reportSummary : map reportThreshold evalResults-  in-    (report, isAllThresholdPass)-
+ test/HPCThresholdSpec.hs view
@@ -0,0 +1,63 @@+module HPCThresholdSpec where++import Test.Hspec+import qualified Control.Exception as E+import qualified Control.DeepSeq as D+import HPCThreshold++spec :: Spec+spec = do+  describe "Threshold" $+    it "should be parsable from string" $ do+      let threshold = Threshold "abc" "(\\d+)% abc" 80+      (read . show) threshold `shouldBe` threshold++  describe "extractCoverage" $ do+    it "should fail with invalid regexStr" $+      (E.evaluate . D.force) (extractCoverage "irrelevant" "ab(c")+        `shouldThrow` anyErrorCall+    it "should return 0 for regex with no digit capture" $+      extractCoverage "12% abc" "abc" `shouldBe` 0+    it "should return 0 if input string does not match regex" $+      extractCoverage "12% abc" "(\\d+) abc" `shouldBe` 0+    it "should capture the coverage" $+      extractCoverage "12% abc" "(\\d+)% abc" `shouldBe` 12++  describe "evaluate" $ do+    let threshold = Threshold "abc" "(\\d+)% abc" 80+    it "should correctly evaluate coverage < threshold as FAIL" $+      evaluate "10% abc" threshold `shouldBe` (threshold, 10, False)+    it "should correctly evaluate coverage == threshold as PASS" $+      evaluate "80% abc" threshold `shouldBe` (threshold, 80, True)+    it "should correctly evaluate coverage > threshold as PASS" $+      evaluate "100% abc" threshold `shouldBe` (threshold, 100, True)++  describe "reportThreshold" $ do+    it "should print passing result correctly" $ do+      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 80, True)+      reportThreshold evalResult `shouldBe` "✓ abc: 80.0% (≥ 80.0%)"+    it "should print failing result correctly" $ do+      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 70, False)+      reportThreshold evalResult `shouldBe` "· abc: 70.0% (< 80.0%)"++  describe "evaluateAndReport" $ do+    let thresholds =+          [ Threshold "abc" "(\\d+)% abc" 80+          , Threshold "def" "(\\d+)% def" 80+          ]+    it "should report passing result correctly" $+      evaluateAndReport "80% abc -- 80% def" thresholds `shouldBe`+        ( unlines [ "Code coverage threshold check: PASS"+                  , "✓ abc: 80.0% (≥ 80.0%)"+                  , "✓ def: 80.0% (≥ 80.0%)"+                  ]+        , True+        )+    it "should report failing result correctly" $+      evaluateAndReport "70% abc -- 80% def" thresholds `shouldBe`+        ( unlines [ "Code coverage threshold check: FAIL"+                  , "· abc: 70.0% (< 80.0%)"+                  , "✓ def: 80.0% (≥ 80.0%)"+                  ]+        , False+        )
− test/LibSpec.hs
@@ -1,63 +0,0 @@-module LibSpec where--import Test.Hspec-import qualified Control.Exception as E-import qualified Control.DeepSeq as D-import Lib--spec :: Spec-spec = do-  describe "Threshold" $-    it "should be parsable from string" $ do-      let threshold = Threshold "abc" "(\\d+)% abc" 80-      (read . show) threshold `shouldBe` threshold--  describe "extractCoverage" $ do-    it "should fail with invalid regexStr" $-      (E.evaluate . D.force) (extractCoverage "irrelevant" "ab(c")-        `shouldThrow` anyErrorCall-    it "should return 0 for regex with no digit capture" $-      extractCoverage "12% abc" "abc" `shouldBe` 0-    it "should return 0 if input string does not match regex" $-      extractCoverage "12% abc" "(\\d+) abc" `shouldBe` 0-    it "should capture the coverage" $-      extractCoverage "12% abc" "(\\d+)% abc" `shouldBe` 12--  describe "evaluate" $ do-    let threshold = Threshold "abc" "(\\d+)% abc" 80-    it "should correctly evaluate coverage < threshold as FAIL" $-      evaluate "10% abc" threshold `shouldBe` (threshold, 10, False)-    it "should correctly evaluate coverage == threshold as PASS" $-      evaluate "80% abc" threshold `shouldBe` (threshold, 80, True)-    it "should correctly evaluate coverage > threshold as PASS" $-      evaluate "100% abc" threshold `shouldBe` (threshold, 100, True)--  describe "reportThreshold" $ do-    it "should print passing result correctly" $ do-      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 80, True)-      reportThreshold evalResult `shouldBe` "✓ abc: 80.0% (≥ 80.0%)"-    it "should print failing result correctly" $ do-      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 70, False)-      reportThreshold evalResult `shouldBe` "· abc: 70.0% (< 80.0%)"--  describe "evaluateAndReport" $ do-    let thresholds =-          [ Threshold "abc" "(\\d+)% abc" 80-          , Threshold "def" "(\\d+)% def" 80-          ]-    it "should report passing result correctly" $-      evaluateAndReport "80% abc -- 80% def" thresholds `shouldBe`-        ( unlines [ "Code coverage threshold check: PASS"-                  , "✓ abc: 80.0% (≥ 80.0%)"-                  , "✓ def: 80.0% (≥ 80.0%)"-                  ]-        , True-        )-    it "should report failing result correctly" $-      evaluateAndReport "70% abc -- 80% def" thresholds `shouldBe`-        ( unlines [ "Code coverage threshold check: FAIL"-                  , "· abc: 70.0% (< 80.0%)"-                  , "✓ def: 80.0% (≥ 80.0%)"-                  ]-        , False-        )