tasty-ant-xml (empty) → 1.0.0
raw patch · 4 files changed
+200/−0 lines, 4 filesdep +basedep +containersdep +generic-derivingsetup-changed
Dependencies added: base, containers, generic-deriving, mtl, reducers, stm, tagged, tasty, transformers, xml
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- Test/Tasty/Runners/AntXML.hs +140/−0
- tasty-ant-xml.cabal +28/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright 2013 Oliver Charles++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Test/Tasty/Runners/AntXML.hs view
@@ -0,0 +1,140 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+-- | Run a 'Tasty.TestTree' and produce an XML file summarising the test results+-- in the same schema that would be produced by Apache Ant's JUnit test runner.+-- This schema can be intepreted by the Jenkins continuous integration server,+-- amongst other tools.+module Test.Tasty.Runners.AntXML (antXMLRunner) where++import Control.Applicative+import Control.Arrow (first)+import Control.Monad.Trans.Class (lift)+import Data.Maybe (fromMaybe)+import Data.Monoid (Monoid(..), Endo(..), Sum(..))+import Data.Proxy (Proxy(..))+import Data.Semigroup.Applicative (Traversal(..))+import Data.Tagged (Tagged(..))+import Data.Typeable (Typeable)+import GHC.Generics (Generic)+import Generics.Deriving.Monoid (memptydefault, mappenddefault)++import qualified Control.Concurrent.STM as STM+import qualified Control.Monad.State as State+import qualified Data.Functor.Compose as Functor+import qualified Data.IntMap as IntMap+import qualified Test.Tasty.Options as Tasty+import qualified Test.Tasty.Providers as Tasty+import qualified Test.Tasty.Runners as Tasty+import qualified Text.XML.Light as XML++--------------------------------------------------------------------------------+newtype AntXMLPath = AntXMLPath FilePath+ deriving (Typeable)++instance Tasty.IsOption (Maybe AntXMLPath) where+ defaultValue = Nothing+ parseValue = Just . Just . AntXMLPath+ optionName = Tagged "xml"+ optionHelp = Tagged "A file path to store the test results in Ant-compatible XML"+++--------------------------------------------------------------------------------+data Summary = Summary { summaryFailures :: Sum Int+ , summaryErrors :: Sum Int+ , summarySuccesses :: Sum Int+ , xmlRenderer :: Endo XML.Element+ } deriving (Generic)++instance Monoid Summary where+ mempty = memptydefault+ mappend = mappenddefault+++--------------------------------------------------------------------------------+-- To run tests using this ingredient, use 'Tasty.defaultMainWithIngredients',+-- passing 'antXMLRunner' as one possible ingredient. This ingredient will run+-- tests if you pass the @--xml@ command line option. For example,+-- @--xml=junit.xml@ will run all the tests and generate @junit.xml@ as output.+antXMLRunner :: Tasty.Ingredient+antXMLRunner = Tasty.TestReporter optionDescription runner+ where+ optionDescription = [ Tasty.Option (Proxy :: Proxy (Maybe AntXMLPath)) ]+ runner options testTree = do+ AntXMLPath path <- Tasty.lookupOption options++ return $ \statusMap ->+ let++ runTest _ testName _ = Traversal $ Functor.Compose $ do+ i <- State.get++ summary <- lift $ STM.atomically $ do+ status <- STM.readTVar $+ fromMaybe (error "Attempted to lookup test by index outside bounds") $+ IntMap.lookup i statusMap++ let testCaseAttributes = map (uncurry XML.Attr . first XML.unqual)+ [ ("name", testName ) ]++ mkSummary contents =+ mempty { xmlRenderer = Endo+ (`appendChild` XML.node (XML.unqual "testcase") contents)+ }++ mkSuccess = (mkSummary testCaseAttributes) { summarySuccesses = Sum 1 }++ mkFailure reason =+ mkSummary ( testCaseAttributes+ , XML.node (XML.unqual "failure") reason+ )++ case status of+ -- If the test is done, generate XML for it+ Tasty.Done result+ | Tasty.resultSuccessful result -> pure mkSuccess+ | otherwise -> pure $+ (mkFailure (Tasty.resultDescription result))+ { summaryFailures = Sum 1 }++ Tasty.Exception e -> pure $+ (mkFailure (show e)) { summaryErrors = Sum 1 }+ + -- Otherwise the test has either not been started or is currently+ -- executing+ _ -> STM.retry++ Const summary <$ State.modify (+ 1)++ runGroup groupName children = Traversal $ Functor.Compose $ do+ Const soFar <- Functor.getCompose $ getTraversal children+ let grouped = appEndo (xmlRenderer soFar) $+ XML.node (XML.unqual "testsuite") $+ XML.Attr (XML.unqual "name") groupName++ pure $ Const+ soFar { xmlRenderer = Endo (`appendChild` grouped)+ }++ in do+ (Const summary, tests) <-+ flip State.runStateT 0 $ Functor.getCompose $ getTraversal $+ Tasty.foldTestTree runTest runGroup options testTree++ writeFile path $+ XML.showTopElement $+ appEndo (xmlRenderer summary) $+ XML.node+ (XML.unqual "testsuites")+ [ XML.Attr (XML.unqual "errors")+ (show . getSum . summaryErrors $ summary)+ , XML.Attr (XML.unqual "failures")+ (show . getSum . summaryFailures $ summary)+ , XML.Attr (XML.unqual "tests") (show tests)+ ]++ return (getSum ((summaryFailures `mappend` summaryErrors) summary) == 0)++ appendChild parent child =+ parent { XML.elContent = XML.elContent parent ++ [ XML.Elem child ] }
+ tasty-ant-xml.cabal view
@@ -0,0 +1,28 @@+name: tasty-ant-xml+version: 1.0.0+synopsis: A tasty ingredient to output test results in XML, using the Ant schema. This XML can be consumed by the Jenkins continuous integration framework.+homepage: http://github.com/ocharles/tasty-ant-xml+license: BSD3+license-file: LICENSE+author: Oliver Charles+maintainer: ollie@ocharles.org.uk+copyright: Oliver Charles 2013+category: Testing+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules: Test.Tasty.Runners.AntXML+ build-depends: + base >= 4.5 && < 5,+ containers >= 0.5.0.0,+ generic-deriving >= 1.6.2,+ mtl >= 2.1.2,+ reducers >= 3.10.1,+ stm >= 2.4.2,+ tagged >= 0.7,+ tasty >= 0.4.0.1,+ transformers >= 0.3.0.0,+ xml >= 1.3.13+ default-language: Haskell98+ ghc-options: -Wall -O2