1
+ {-# LANGUAGE ViewPatterns #-}
2
+
1
3
module Echidna.Output.Source where
2
4
3
5
import Prelude hiding (writeFile )
4
6
5
7
import Data.Aeson (ToJSON (.. ), FromJSON (.. ), withText )
8
+ import Data.ByteString qualified as BS
6
9
import Data.Foldable
7
10
import Data.List (nub , sort )
8
11
import Data.Maybe (fromMaybe , mapMaybe )
@@ -28,8 +31,6 @@ import Echidna.Types.Coverage (OpIx, unpackTxResults, CoverageMap)
28
31
import Echidna.Types.Tx (TxResult (.. ))
29
32
import Echidna.Types.Signature (getBytecodeMetadata )
30
33
31
- type FilePathText = Text
32
-
33
34
saveCoverages
34
35
:: [CoverageFileType ]
35
36
-> Int
@@ -78,20 +79,18 @@ coverageFileExtension Txt = ".txt"
78
79
ppCoveredCode :: CoverageFileType -> SourceCache -> [SolcContract ] -> CoverageMap -> IO Text
79
80
ppCoveredCode fileType sc cs s | null s = pure " Coverage map is empty"
80
81
| otherwise = do
81
- let allFiles = zipWith (\ (srcPath, _rawSource) srcLines -> (srcPath, V. map decodeUtf8 srcLines))
82
- sc. files
83
- sc. lines
84
- -- ^ Collect all the possible lines from all the files
82
+ -- List of covered lines during the fuzzing campaing
85
83
covLines <- srcMapCov sc s cs
86
- -- ^ List of covered lines during the fuzzing campaing
87
84
let
85
+ -- Collect all the possible lines from all the files
86
+ allFiles = (\ (path, src) -> (path, V. fromList (decodeUtf8 <$> BS. split 0xa src))) <$> Map. elems sc. files
87
+ -- Excludes lines such as comments or blanks
88
88
runtimeLinesMap = buildRuntimeLinesMap sc cs
89
- -- ^ Excludes lines such as comments or blanks
89
+ -- Pretty print individual file coverage
90
90
ppFile (srcPath, srcLines) =
91
91
let runtimeLines = fromMaybe mempty $ Map. lookup srcPath runtimeLinesMap
92
92
marked = markLines fileType srcLines runtimeLines (fromMaybe Map. empty (Map. lookup srcPath covLines))
93
93
in T. unlines (changeFileName srcPath : changeFileLines (V. toList marked))
94
- -- ^ Pretty print individual file coverage
95
94
topHeader = case fileType of
96
95
Lcov -> " TN:\n "
97
96
Html -> " <style> code { white-space: pre-wrap; display: block; background-color: #eee; }" <>
@@ -102,7 +101,7 @@ ppCoveredCode fileType sc cs s | null s = pure "Coverage map is empty"
102
101
" </style>"
103
102
Txt -> " "
104
103
-- ^ Text to add to top of the file
105
- changeFileName fn = case fileType of
104
+ changeFileName ( T. pack -> fn) = case fileType of
106
105
Lcov -> " SF:" <> fn
107
106
Html -> " <b>" <> HTML. text fn <> " </b>"
108
107
Txt -> fn
@@ -158,11 +157,11 @@ getMarker ErrorOutOfGas = 'o'
158
157
getMarker _ = ' e'
159
158
160
159
-- | Given a source cache, a coverage map, a contract returns a list of covered lines
161
- srcMapCov :: SourceCache -> CoverageMap -> [SolcContract ] -> IO (Map FilePathText (Map Int [TxResult ]))
160
+ srcMapCov :: SourceCache -> CoverageMap -> [SolcContract ] -> IO (Map FilePath (Map Int [TxResult ]))
162
161
srcMapCov sc covMap contracts = do
163
162
Map. unionsWith Map. union <$> mapM linesCovered contracts
164
163
where
165
- linesCovered :: SolcContract -> IO (Map Text (Map Int [TxResult ]))
164
+ linesCovered :: SolcContract -> IO (Map FilePath (Map Int [TxResult ]))
166
165
linesCovered c =
167
166
case Map. lookup (getBytecodeMetadata c. runtimeCode) covMap of
168
167
Just vec -> VU. foldl' (\ acc covInfo -> case covInfo of
@@ -193,7 +192,7 @@ srcMapForOpLocation contract opIx =
193
192
194
193
-- | Builds a Map from file paths to lines that can be executed, this excludes
195
194
-- for example lines with comments
196
- buildRuntimeLinesMap :: SourceCache -> [SolcContract ] -> Map Text (S. Set Int )
195
+ buildRuntimeLinesMap :: SourceCache -> [SolcContract ] -> Map FilePath (S. Set Int )
197
196
buildRuntimeLinesMap sc contracts =
198
197
Map. fromListWith (<>)
199
198
[(k, S. singleton v) | (k, v) <- mapMaybe (srcMapCodePos sc) srcMaps]
0 commit comments