| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Convex.Tasty.Streaming.SrcLoc
Description
Source-location tracking for tests streamed by the Tasty ingredient.
This module provides:
SrcLocRange— a JSON-friendly source range type matching the shape used elsewhere in this repo (file, startLine, startCol, endLine, endCol).SrcLocOpt— a TastyIsOptioninstance carrying an optional location. Tasty propagates options fromlocalOptiondown into every child leaf throughPlusTestOptionsnodes, so we use it as a side channel between the user-facing API boundary and the streaming ingredient.withSrcLoc— aHasCallStack-instrumented combinator that captures the immediate caller's source location and attaches it to aTestTreevialocalOption.PackageRootOpt— a TastyIsOptioncarrying the optional absolute path to the cabal package containing the user'sMain.hs. Populated bydefaultMainStreamingfrom the top of theHasCallStackcall-stack and consumed by the streaming reporter / list ingredient to populate thepackageRootfield onSuiteStarted.callerPackageRoot/findPackageRootFromFile— helpers that walk up from a source file to the nearest enclosing.cabaldirectory.
This is intentionally kept separate from any specific test provider
(HUnit, QuickCheck, etc.) so that user-facing
shims and library-internal wrappers (e.g. propRunActions) can share the
same machinery.
Synopsis
- data SrcLocRange = SrcLocRange {
- slrFile :: !Text
- slrStartLine :: !Int
- slrStartCol :: !Int
- slrEndLine :: !Int
- slrEndCol :: !Int
- newtype SrcLocOpt = SrcLocOpt (Maybe SrcLocRange)
- withSrcLoc :: HasCallStack => TestTree -> TestTree
- currentSrcLocRange :: HasCallStack => Maybe SrcLocRange
- fromGhcSrcLoc :: SrcLoc -> SrcLocRange
- newtype PackageRootOpt = PackageRootOpt (Maybe Text)
- callerPackageRoot :: HasCallStack => IO (Maybe FilePath)
- findPackageRootFromFile :: FilePath -> IO (Maybe FilePath)
- data SrcLocRanges = SrcLocRanges {
- slrsFile :: !Text
- slrsStartLines :: [Int]
- slrsStartCols :: [Int]
- slrsEndLines :: [Int]
- slrsEndCols :: [Int]
- groupRanges :: [SrcLocRange] -> [SrcLocRanges]
- ungroupRanges :: [SrcLocRanges] -> [SrcLocRange]
Documentation
data SrcLocRange Source #
A source-location range, semantically equivalent to the LSP/editor
file:startLine:startCol-endLine:endCol shape.
The end position is typically one past the end of the function-name token
(e.g. just past testCase), not the end of the user's full expression —
HasCallStack does not give us expression spans.
Constructors
| SrcLocRange | |
Fields
| |
Instances
Internal Tasty option carrying the source-location of a test definition.
Not user-settable from the command line; it is only ever populated via
withSrcLoc (or, transitively, the Convex.Tasty.HUnit /
Convex.Tasty.QuickCheck shims).
Constructors
| SrcLocOpt (Maybe SrcLocRange) |
withSrcLoc :: HasCallStack => TestTree -> TestTree Source #
Annotate a TestTree with the caller's source location.
Use withFrozenCallStack at the call site if you are writing a shim that
delegates to this combinator, so that the captured location reflects the
shim's caller rather than the shim itself.
currentSrcLocRange :: HasCallStack => Maybe SrcLocRange Source #
Capture the immediate caller's location from the implicit CallStack.
Returns Nothing if the call stack is empty (e.g. when called from a
context without a HasCallStack chain reaching a real call site).
fromGhcSrcLoc :: SrcLoc -> SrcLocRange Source #
Convert a GHC SrcLoc to our JSON-friendly SrcLocRange.
newtype PackageRootOpt Source #
Internal Tasty option carrying the absolute path of the cabal package
that contains the user's Main.hs test entry point.
Populated by defaultMainStreaming from the top of
the HasCallStack call-stack (which points at the user's Main.hs) by
walking up the directory tree until a .cabal file is found. Consumed by
the streaming JSON reporter and the --list-tests-json ingredient to
populate the packageRoot field of the SuiteStarted event.
Not user-settable from the command line. defaultValue is
PackageRootOpt Nothing; when no .cabal file can be located above the
caller, the field is omitted from JSON output.
Constructors
| PackageRootOpt (Maybe Text) |
Instances
| Show PackageRootOpt Source # | |
Defined in Convex.Tasty.Streaming.SrcLoc Methods showsPrec :: Int -> PackageRootOpt -> ShowS # show :: PackageRootOpt -> String # showList :: [PackageRootOpt] -> ShowS # | |
| Eq PackageRootOpt Source # | |
Defined in Convex.Tasty.Streaming.SrcLoc Methods (==) :: PackageRootOpt -> PackageRootOpt -> Bool # (/=) :: PackageRootOpt -> PackageRootOpt -> Bool # | |
| IsOption PackageRootOpt Source # | |
Defined in Convex.Tasty.Streaming.SrcLoc | |
callerPackageRoot :: HasCallStack => IO (Maybe FilePath) Source #
Resolve the caller's package root from a HasCallStack constraint.
Returns the absolute path of the directory containing the package's
.cabal file, or Nothing when no match can be located.
The strategy combines two signals from the top of the call stack:
srcLocPackage— the GHC-internal package identifier of the calling module, e.g."convex-testing-interface-0.1.0.0-inplace-convex-testing-interface-test". The first"-digit"token of that string marks the start of the package version; everything before it is the package name.srcLocFile— the GHC-recorded source file path, typically package-relative (e.g."test/Spec.hs").
If a package name can be extracted, we search downward from the current
working directory for a directory containing both a matching
<name>.cabal file and the relative source file. If the package
name is unavailable or no match is found, we fall back to the
file-based search in findPackageRootFromFile.
Intended to be invoked at the very top of a test entry point (e.g. from
defaultMainStreaming) so that the captured
location corresponds to the user's Main.hs.
findPackageRootFromFile :: FilePath -> IO (Maybe FilePath) Source #
Resolve the cabal package containing the given source file.
The input is typically a srcLocFile value: an absolute path
when GHC was run from the package directory, but in practice (under
cabal run and cabal test) a path relative to the package directory
such as "test/Spec.hs". The current working directory of a cabal run
process is the workspace root (the directory containing
cabal.project), not the package directory.
Resolution strategy:
- If the path is absolute, walk up its parent directories until a
directory containing any
.cabalfile is found. Return that directory. - If the path is relative, recursively scan downward from the current
working directory (bounded by
searchDepth) for any directory that both contains a.cabalfile and contains the relative path on disk (i.e.D </> relativePathexists). The first match in a depth-first traversal wins. This copes with the common monorepo layout where packages live undersrc/*/relative to the workspace root.
The search is bounded to avoid exploring the entire filesystem in
pathological setups. Hidden directories (those starting with .),
dist-newstyle, and common build/dependency directories are skipped
to keep the cost predictable.
Returns Nothing when no match is found.
IOExceptions from filesystem operations are caught and treated as
empty/absent so that permission errors on unrelated subtrees do not
abort the walk.
data SrcLocRanges Source #
Many ranges in one file, for more efficient JSON serialization
Constructors
| SrcLocRanges | |
Fields
| |
Instances
groupRanges :: [SrcLocRange] -> [SrcLocRanges] Source #
ungroupRanges :: [SrcLocRanges] -> [SrcLocRange] Source #