tricorder-0.2.0.0: test/Unit/Tricorder/Build/EvalCommentSpec.hs
module Unit.Tricorder.Build.EvalCommentSpec (spec_EvalComment) where
import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, shouldSatisfy)
import Text.Megaparsec (parse)
import Tricorder.Build.EvalComment qualified as Eval
spec_EvalComment :: Spec
spec_EvalComment = do
describe "singleLineEvalCommentP" testSingleLine
describe "multiLineEvalCommentP" testMultiLine
describe "blockCommentEvalP" testBlockComment
describe "findComments" testFindComments
--------------------------------------------------------------------------------
-- singleLineEvalCommentP
--------------------------------------------------------------------------------
testSingleLine :: Spec
testSingleLine = do
it "parses a basic expression" do
parse Eval.singleLineEvalCommentP "" "-- $> 1 + 2"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "1 + 2"}
it "handles no space between marker and expression" do
parse Eval.singleLineEvalCommentP "" "-- $>expr"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "strips leading whitespace from the expression" do
parse Eval.singleLineEvalCommentP "" "-- $> expr"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "captures the full expression including inner spaces" do
parse Eval.singleLineEvalCommentP "" "-- $> foo bar baz"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "foo bar baz"}
it "stops at a newline, not consuming it" do
parse Eval.singleLineEvalCommentP "" "-- $> expr\nnext line"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "fails when there is no expression after the marker" do
parse Eval.singleLineEvalCommentP "" "-- $>" `shouldSatisfy` isLeft
it "fails on the multi-line opening marker" do
parse Eval.singleLineEvalCommentP "" "-- $$> expr -- <$$" `shouldSatisfy` isLeft
it "fails on other text between comment start and eval marker" do
parse Eval.singleLineEvalCommentP "" "-- foo $> 1 + 2" `shouldSatisfy` isLeft
it "fails on unrelated text" do
parse Eval.singleLineEvalCommentP "" "hello world" `shouldSatisfy` isLeft
--------------------------------------------------------------------------------
-- multiLineEvalCommentP
--------------------------------------------------------------------------------
testMultiLine :: Spec
testMultiLine = do
it "parses a single content line, stripping the -- prefix" do
parse Eval.multiLineEvalCommentP "" "-- $$>\n-- expr\n-- <$$"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "parses multiple content lines, stripping -- prefixes" do
parse Eval.multiLineEvalCommentP "" "-- $$>\n-- foo\n-- bar\n-- <$$"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "foo\nbar"}
it "preserves relative indentation after stripping -- prefix" do
parse Eval.multiLineEvalCommentP "" "-- $$>\n-- let x = 1\n-- y = 2\n-- in x + y\n-- <$$"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "let x = 1\n y = 2\nin x + y"}
it "handles -- with no trailing space" do
parse Eval.multiLineEvalCommentP "" "-- $$>\n--expr\n-- <$$"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "parse multi-line eval comment in a single line" do
parse Eval.multiLineEvalCommentP "" "-- $$> expr <$$"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "expr"}
it "fails when the closing marker is absent" do
parse Eval.multiLineEvalCommentP "" "-- $$>\n-- expr" `shouldSatisfy` isLeft
it "fails on the single-line marker" do
parse Eval.multiLineEvalCommentP "" "-- $> expr" `shouldSatisfy` isLeft
it "fails on unrelated text" do
parse Eval.multiLineEvalCommentP "" "hello world" `shouldSatisfy` isLeft
--------------------------------------------------------------------------------
-- blockCommentEvalP
--------------------------------------------------------------------------------
testBlockComment :: Spec
testBlockComment = do
it "parses a single-line expression on its own line" do
parse Eval.blockCommentEvalP "" "{- $$>\n2 + 2\n<$$ -}"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "2 + 2"}
it "parses an inline one-liner" do
parse Eval.blockCommentEvalP "" "{- $$> 2 + 2 <$$ -}"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "2 + 2"}
it "parses a multi-line expression preserving layout" do
parse Eval.blockCommentEvalP "" "{- $$>\nlet x = 1\n y = 2\nin x + y\n<$$ -}"
`shouldBe` Right Eval.Comment {lineNumber = 1, expression = "let x = 1\n y = 2\nin x + y"}
it "fails when the closing marker is absent" do
parse Eval.blockCommentEvalP "" "{- $$>\nexpr" `shouldSatisfy` isLeft
it "fails on the line-comment multi-line eval marker" do
parse Eval.blockCommentEvalP "" "-- $$> expr" `shouldSatisfy` isLeft
it "fails on the single-line eval marker" do
parse Eval.blockCommentEvalP "" "{- $> expr -}" `shouldSatisfy` isLeft
it "fails on unrelated text" do
parse Eval.blockCommentEvalP "" "hello world" `shouldSatisfy` isLeft
--------------------------------------------------------------------------------
-- findComments
--------------------------------------------------------------------------------
testFindComments :: Spec
testFindComments = do
it "returns empty list for empty text" do
Eval.findComments "" `shouldMatchList` []
it "returns empty list when there are no eval comments" do
Eval.findComments "hello world\nno comments here" `shouldMatchList` []
it "finds a single single-line eval comment" do
Eval.findComments "x = 1\n-- $> x\ny = 2"
`shouldMatchList` [Eval.Comment {lineNumber = 2, expression = "x"}]
it "finds multiple single-line eval comments in source order" do
Eval.findComments "-- $> a\n-- $> b"
`shouldMatchList` [ Eval.Comment {lineNumber = 1, expression = "a"}
, Eval.Comment {lineNumber = 2, expression = "b"}
]
it "reports correct line numbers" do
Eval.findComments "line1\nline2\n-- $> expr\nline4"
`shouldMatchList` [Eval.Comment {lineNumber = 3, expression = "expr"}]
it "ignores lines that look like partial markers" do
Eval.findComments "-- $\n-- $> expr"
`shouldMatchList` [Eval.Comment {lineNumber = 2, expression = "expr"}]
it "does not match an eval marker embedded in another comment" do
Eval.findComments "-- foo -- $> expr" `shouldMatchList` []
it "does not match an inline eval marker appearing after code" do
Eval.findComments "x = 1 -- $> x" `shouldMatchList` []
it "finds a multi-line eval comment, stripping -- prefixes" do
Eval.findComments "-- $$>\n-- expr\n-- <$$"
`shouldMatchList` [Eval.Comment {lineNumber = 1, expression = "expr"}]
it "finds a block comment eval" do
Eval.findComments "{- $$>\nexpr\n<$$ -}"
`shouldMatchList` [Eval.Comment {lineNumber = 1, expression = "expr"}]
it "finds both single-line and multi-line eval comments" do
Eval.findComments "-- $> a\n-- $$>\n-- b\n-- <$$"
`shouldMatchList` [ Eval.Comment {lineNumber = 1, expression = "a"}
, Eval.Comment {lineNumber = 2, expression = "b"}
]
it "finds both single-line and block comment eval comments" do
Eval.findComments "-- $> a\n{- $$>\nb\n<$$ -}"
`shouldMatchList` [ Eval.Comment {lineNumber = 1, expression = "a"}
, Eval.Comment {lineNumber = 2, expression = "b"}
]