convex-tasty-streaming
Safe HaskellSafe-Inferred
LanguageHaskell2010

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 Tasty IsOption instance carrying an optional location. Tasty propagates options from localOption down into every child leaf through PlusTestOptions nodes, so we use it as a side channel between the user-facing API boundary and the streaming ingredient.
  • withSrcLoc — a HasCallStack-instrumented combinator that captures the immediate caller's source location and attaches it to a TestTree via localOption.
  • PackageRootOpt — a Tasty IsOption carrying the optional absolute path to the cabal package containing the user's Main.hs. Populated by defaultMainStreaming from the top of the HasCallStack call-stack and consumed by the streaming reporter / list ingredient to populate the packageRoot field on SuiteStarted.
  • callerPackageRoot / findPackageRootFromFile — helpers that walk up from a source file to the nearest enclosing .cabal directory.

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

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 

Instances

Instances details
FromJSON SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

ToJSON SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Generic SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Associated Types

type Rep SrcLocRange :: Type -> Type #

Show SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Eq SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Ord SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

type Rep SrcLocRange Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

type Rep SrcLocRange = D1 ('MetaData "SrcLocRange" "Convex.Tasty.Streaming.SrcLoc" "convex-tasty-streaming-0.1.0.0-inplace" 'False) (C1 ('MetaCons "SrcLocRange" 'PrefixI 'True) ((S1 ('MetaSel ('Just "slrFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "slrStartLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int)) :*: (S1 ('MetaSel ('Just "slrStartCol") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: (S1 ('MetaSel ('Just "slrEndLine") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Just "slrEndCol") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int)))))

newtype SrcLocOpt Source #

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) 

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 .cabal file 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 .cabal file and contains the relative path on disk (i.e. D </> relativePath exists). The first match in a depth-first traversal wins. This copes with the common monorepo layout where packages live under src/*/ 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 

Instances

Instances details
FromJSON SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

ToJSON SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Generic SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Associated Types

type Rep SrcLocRanges :: Type -> Type #

Show SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

Eq SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

type Rep SrcLocRanges Source # 
Instance details

Defined in Convex.Tasty.Streaming.SrcLoc

type Rep SrcLocRanges = D1 ('MetaData "SrcLocRanges" "Convex.Tasty.Streaming.SrcLoc" "convex-tasty-streaming-0.1.0.0-inplace" 'False) (C1 ('MetaCons "SrcLocRanges" 'PrefixI 'True) ((S1 ('MetaSel ('Just "slrsFile") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "slrsStartLines") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Int])) :*: (S1 ('MetaSel ('Just "slrsStartCols") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Int]) :*: (S1 ('MetaSel ('Just "slrsEndLines") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Int]) :*: S1 ('MetaSel ('Just "slrsEndCols") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Int])))))