nix-lang-0.1.0.0: test/ExactPrint.hs
module ExactPrint where
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Nix.Lang.Annotation
import Nix.Lang.ExactPrint
import qualified Nix.Lang.ExactPrint.Operations as Ops
import Nix.Lang.Parser
import Nix.Lang.Span
import Nix.Lang.Types
import Nix.Lang.Utils
import Test.Tasty
import Test.Tasty.HUnit
import Text.Megaparsec (eof, errorBundlePretty)
import Utils
tests :: TestTree
tests =
testGroup
"exact print"
[ testGroup
"state and layout"
[ testCase "line comments are collected" lineCommentsCollected,
testCase "block comments are collected" blockCommentsCollected,
testCase "file-leading comments attach to root node prior comments" fileLeadingCommentsAttachToRoot,
testCase "file-trailing comments attach to root node following comments" fileTrailingCommentsAttachToRoot,
testCase "list carries tokenized delimiter annotations" listCarriesTokenizedDelimiters,
testCase "list layout prep rewrites delimiters to deltas" listLayoutPrepRewritesDelimitersToDeltas,
testCase "paren layout prep rewrites close delimiter to delta" parenLayoutPrepRewritesCloseDelimiterToDelta,
testCase "set layout prep rewrites close delimiter to delta" setLayoutPrepRewritesCloseDelimiterToDelta,
testCase "let layout prep rewrites in token to delta" letLayoutPrepRewritesInTokenToDelta,
testCase "if layout prep rewrites then/else tokens to deltas" ifLayoutPrepRewritesThenElseTokensToDeltas,
testCase "with layout prep rewrites semicolon to delta" withLayoutPrepRewritesSemicolonToDelta,
testCase "assert layout prep rewrites semicolon to delta" assertLayoutPrepRewritesSemicolonToDelta,
testCase "has-attr layout prep rewrites question token to delta" hasAttrLayoutPrepRewritesQuestionToDelta,
testCase "select layout prep rewrites or token to delta" selectLayoutPrepRewritesOrTokenToDelta,
testCase "deltaFromAnchor same line computes column delta" deltaFromAnchorSameLine,
testCase "deltaFromAnchor multiline computes line and indentation" deltaFromAnchorMultiline,
testCase "renderGapFromDeltaText renders whitespace" renderGapFromDeltaTextRendersWhitespace,
testCase "advanceCursor tracks newlines" advanceCursorTracksNewlines,
testCase "assert carries tokenized keyword and semicolon annotations" assertCarriesTokenizedDelimiters,
testCase "set carries tokenized brace annotations" setCarriesTokenizedBraces,
testCase "assert carries typed keyword and semicolon spans" assertAnnotationsCollected,
testCase "set carries typed annotation comments" setCarriesTypedAnnComments,
testCase "isSubspanOf checks end columns" isSubspanOfChecksEndColumns
],
testGroup
"roundtrip"
[ testCase "exact print roundtrips quoted string source" exactPrintRoundtripsQuotedStringSource,
testCase "exact print roundtrips env path" exactPrintRoundtripsEnvPath,
testCase "exact print roundtrips multiline list" exactPrintRoundtripsMultilineList,
testCase "exact print roundtrips multiline set" exactPrintRoundtripsMultilineSet,
testCase "exact print roundtrips multiline let" exactPrintRoundtripsMultilineLet,
testCase "exact print roundtrips multiline if" exactPrintRoundtripsMultilineIf,
testCase "exact print roundtrips multiline with" exactPrintRoundtripsMultilineWith,
testCase "exact print roundtrips multiline assert" exactPrintRoundtripsMultilineAssert,
testCase "exact print roundtrips multiline has-attr" exactPrintRoundtripsMultilineHasAttr,
testCase "exact print roundtrips multiline select or" exactPrintRoundtripsMultilineSelectOr,
testCase "exact print roundtrips sample fixture" exactPrintRoundtripsSampleFixture,
testCase "exact print preserves lambda comments from sample shape" exactPrintPreservesLambdaCommentShape,
testCase "exact print preserves inline close comment without whitespace" exactPrintPreservesCommentNoWhitespace,
testCase "exact print preserves trailing comma set pattern" exactPrintPreservesTrailingCommaSetPattern,
testCase "exact print preserves interpolated select attr path" exactPrintPreservesInterpolatedSelectAttrPath,
testCase "exact print safe API preserves trailing as-pattern" exactPrintSafeApiPreservesTrailingAsPattern,
testCase "exact print preserves quoted string source text" exactPrintPreservesQuotedStringSource,
testCase "exact print preserves indented string source text" exactPrintPreservesIndentedStringSource,
testCase "exact print preserves literal path" exactPrintPreservesLiteralPath,
testCase "exact print preserves interpolated path structurally" exactPrintPreservesInterpolatedPath,
testCase "exact print preserves env path" exactPrintPreservesEnvPath,
testCase "exact print preserves dynamic attr binding" exactPrintPreservesDynamicAttrBinding,
testCase "exact print preserves dynamic string attr binding" exactPrintPreservesDynamicStringAttrBinding,
testCase "exact print preserves structural dynamic interpol attr binding" exactPrintPreservesStructuralDynamicInterpolAttrBinding,
testCase "exact print preserves inherit binding" exactPrintPreservesInheritBinding,
testCase "exact print preserves lambda var pattern" exactPrintPreservesLambdaVarPattern,
testCase "exact print preserves lambda set pattern" exactPrintPreservesLambdaSetPattern,
testCase "exact print preserves multiline lambda chain layout" exactPrintPreservesMultilineLambdaChainLayout,
testCase "exact print preserves application" exactPrintPreservesApplication,
testCase "exact print preserves has-attr" exactPrintPreservesHasAttr,
testCase "exact print preserves with expression" exactPrintPreservesWithExpr,
testCase "exact print preserves assert expression" exactPrintPreservesAssertExpr,
testCase "exact print emits file leading and trailing comments" exactPrintEmitsRootComments,
testCase "exact print emits list trailing comments before close" exactPrintEmitsClosingDelimitedComments,
testCase "exact print preserves multiline list layout" exactPrintPreservesMultilineListLayout,
testCase "exact print preserves multiline set layout" exactPrintPreservesMultilineSetLayout,
testCase "exact print preserves multiline let layout" exactPrintPreservesMultilineLetLayout,
testCase "exact print preserves multiline if layout" exactPrintPreservesMultilineIfLayout
],
referenceExactPrintFixtureTests
]
assertExactPrintRoundtripExpr :: T.Text -> Assertion
assertExactPrintRoundtripExpr src =
case runNixParser (nixExpr <* eof) "<expr>" src of
(Right expr, _) -> renderExactText expr @?= src
(Left err, _) -> assertFailure $ errorBundlePretty err
assertExactPrintRoundtripFile :: FilePath -> T.Text -> Assertion
assertExactPrintRoundtripFile fp src =
case runNixParser nixFile fp src of
(Right expr, _) -> renderExactText expr @?= src
(Left err, _) -> assertFailure $ errorBundlePretty err
lineCommentsCollected :: Assertion
lineCommentsCollected = do
expr <- parseFileOrFail "<comments>" "{\n # hello\n x = 1;\n}"
case expr of
NixSet _ _ (L _ [L _ (NixNormalBinding _ (L _ (NixAttrPath ann _)) _)]) ->
assertBool "expected collected line comment on first attr path" $ any isHelloLine (priorComments (acComments (aapCommon ann)))
_ -> assertFailure $ "expected set expression, got: " <> show expr
where
isHelloLine (L _ (LineComment txt)) = txt == " hello"
isHelloLine _ = False
blockCommentsCollected :: Assertion
blockCommentsCollected = do
expr <- parseFileOrFail "<comments>" "[ a /* hello */ ]"
case expr of
NixList ann _ -> assertBool "expected collected block comment before closing bracket" $ any isHelloBlock (followingComments (acComments (alnCommon ann)))
_ -> assertFailure $ "expected list expression, got: " <> show expr
where
isHelloBlock (L _ (BlockComment txt)) = txt == " hello "
isHelloBlock _ = False
fileLeadingCommentsAttachToRoot :: Assertion
fileLeadingCommentsAttachToRoot = do
expr <- parseFileOrFail "<comments>" "# hello\n1"
case expr of
NixLit ann _ -> assertBool "expected file-leading comment on root prior comments" $ any isHelloLine (priorComments (acComments ann))
_ -> assertFailure $ "expected literal expression, got: " <> show expr
where
isHelloLine (L _ (LineComment txt)) = txt == " hello"
isHelloLine _ = False
fileTrailingCommentsAttachToRoot :: Assertion
fileTrailingCommentsAttachToRoot = do
expr <- parseFileOrFail "<comments>" "1\n# hello"
case expr of
NixLit ann _ -> assertBool "expected file-trailing comment on root following comments" $ any isHelloLine (followingComments (acComments ann))
_ -> assertFailure $ "expected literal expression, got: " <> show expr
where
isHelloLine (L _ (LineComment txt)) = txt == " hello"
isHelloLine _ = False
listCarriesTokenizedDelimiters :: Assertion
listCarriesTokenizedDelimiters = do
expr <- parseExprOrFail "[1 2 3]"
case expr of
NixList ann _ -> do
annToken (alnOpenS ann) @?= AnnOpenS
annToken (alnCloseS ann) @?= AnnCloseS
annTokenSrcSpan (alnOpenS ann) @?= Just (mkSrcSpan "<expr>" (1, 1) (1, 2))
annTokenSrcSpan (alnCloseS ann) @?= Just (mkSrcSpan "<expr>" (1, 7) (1, 8))
_ -> assertFailure $ "expected list expression, got: " <> show expr
listLayoutPrepRewritesDelimitersToDeltas :: Assertion
listLayoutPrepRewritesDelimitersToDeltas = do
expr <- parseExprOrFail "[\n a\n b\n]"
case expr of
NixList ann xs -> do
let ann' = Ops.prepareListLayout ann xs
annTokenSrcSpan (alnOpenS ann') @?= annTokenSrcSpan (alnOpenS ann)
annTokenDelta (alnCloseS ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (alnCloseS ann') @?= Nothing
_ -> assertFailure $ "expected list expression, got: " <> show expr
parenLayoutPrepRewritesCloseDelimiterToDelta :: Assertion
parenLayoutPrepRewritesCloseDelimiterToDelta = do
expr <- parseExprOrFail "(\n 1\n)"
case expr of
NixPar ann inner -> do
let ann' = Ops.prepareParLayout ann (unLoc inner)
annTokenSrcSpan (apnOpenP ann') @?= annTokenSrcSpan (apnOpenP ann)
annTokenDelta (apnCloseP ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (apnCloseP ann') @?= Nothing
_ -> assertFailure $ "expected parenthesized expression, got: " <> show expr
setLayoutPrepRewritesCloseDelimiterToDelta :: Assertion
setLayoutPrepRewritesCloseDelimiterToDelta = do
expr <- parseExprOrFail "{\n x = 1;\n}"
case expr of
NixSet ann _ (L _ bindings) -> do
let ann' = Ops.prepareSetLayout ann bindings
annTokenSrcSpan (asOpenC ann') @?= annTokenSrcSpan (asOpenC ann)
annTokenDelta (asCloseC ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (asCloseC ann') @?= Nothing
_ -> assertFailure $ "expected set expression, got: " <> show expr
letLayoutPrepRewritesInTokenToDelta :: Assertion
letLayoutPrepRewritesInTokenToDelta = do
expr <- parseExprOrFail "let\n x = 1;\nin\n x"
case expr of
NixLet ann (L _ bindings) body -> do
let ann' = Ops.prepareLetLayout ann bindings (unLoc body)
annTokenDelta (alIn ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (alIn ann') @?= Nothing
_ -> assertFailure $ "expected let expression, got: " <> show expr
ifLayoutPrepRewritesThenElseTokensToDeltas :: Assertion
ifLayoutPrepRewritesThenElseTokensToDeltas = do
expr <- parseExprOrFail "if\n a\nthen\n b\nelse\n c"
case expr of
NixIf ann cond thenExpr elseExpr -> do
let ann' = Ops.prepareIfLayout ann (unLoc cond) (unLoc thenExpr) (unLoc elseExpr)
annTokenDelta (aifThen ann') @?= Just (DeltaPos 1 0)
annTokenDelta (aifElse ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (aifThen ann') @?= Nothing
annTokenSrcSpan (aifElse ann') @?= Nothing
_ -> assertFailure $ "expected if expression, got: " <> show expr
withLayoutPrepRewritesSemicolonToDelta :: Assertion
withLayoutPrepRewritesSemicolonToDelta = do
expr <- parseExprOrFail "with\n l\n;\n 1"
case expr of
NixWith ann scope body -> do
let ann' = Ops.prepareWithLayout ann (unLoc scope) (unLoc body)
annTokenDelta (awSemicolon ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (awSemicolon ann') @?= Nothing
_ -> assertFailure $ "expected with expression, got: " <> show expr
assertLayoutPrepRewritesSemicolonToDelta :: Assertion
assertLayoutPrepRewritesSemicolonToDelta = do
expr <- parseExprOrFail "assert\n a == 1\n;\n 2"
case expr of
NixAssert ann assertion body -> do
let ann' = Ops.prepareAssertLayout ann (unLoc assertion) (unLoc body)
annTokenDelta (aaSemicolon ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (aaSemicolon ann') @?= Nothing
_ -> assertFailure $ "expected assert expression, got: " <> show expr
hasAttrLayoutPrepRewritesQuestionToDelta :: Assertion
hasAttrLayoutPrepRewritesQuestionToDelta = do
expr <- parseExprOrFail "a\n?\n b"
case expr of
NixHasAttr ann lhs rhs -> do
let ann' = Ops.prepareHasAttrLayout ann (unLoc lhs) (unLoc rhs)
annTokenDelta (ahaQuestion ann') @?= Just (DeltaPos 1 0)
annTokenSrcSpan (ahaQuestion ann') @?= Nothing
_ -> assertFailure $ "expected has-attr expression, got: " <> show expr
selectLayoutPrepRewritesOrTokenToDelta :: Assertion
selectLayoutPrepRewritesOrTokenToDelta = do
expr <- parseExprOrFail "a.b.c\nor\n d.e"
case expr of
NixSelect ann lhs path (Just defExpr) -> do
let ann' = Ops.prepareSelectLayout ann (unLoc lhs) (unLoc path) (Just defExpr)
case aslOr ann' of
Just tok -> do
annTokenDelta tok @?= Just (DeltaPos 1 0)
annTokenSrcSpan tok @?= Nothing
Nothing -> assertFailure "expected or token"
_ -> assertFailure $ "expected select expression, got: " <> show expr
deltaFromAnchorSameLine :: Assertion
deltaFromAnchorSameLine =
Ops.deltaFromAnchor (mkSrcSpan "<test>" (1, 1) (1, 4)) (mkSrcSpan "<test>" (1, 7) (1, 8)) @?= DeltaPos 0 3
deltaFromAnchorMultiline :: Assertion
deltaFromAnchorMultiline =
Ops.deltaFromAnchor (mkSrcSpan "<test>" (1, 3) (1, 8)) (mkSrcSpan "<test>" (3, 5) (3, 6)) @?= DeltaPos 2 4
renderGapFromDeltaTextRendersWhitespace :: Assertion
renderGapFromDeltaTextRendersWhitespace = do
Ops.renderGapFromDeltaText (DeltaPos 0 3) @?= " "
Ops.renderGapFromDeltaText (DeltaPos 2 4) @?= "\n\n "
advanceCursorTracksNewlines :: Assertion
advanceCursorTracksNewlines =
Ops.advanceCursor (Ops.RenderCursor 1 1) "ab\n c" @?= Ops.RenderCursor 2 3
assertAnnotationsCollected :: Assertion
assertAnnotationsCollected = do
expr <- parseExprOrFail "assert a == 1; 2"
case expr of
NixAssert ann _ _ -> do
fmap srcSpanStartColumn (annTokenSrcSpan (aaAssert ann)) @?= Just 1
fmap srcSpanStartColumn (annTokenSrcSpan (aaSemicolon ann)) @?= Just 14
_ -> assertFailure $ "expected assert expression, got: " <> show expr
assertCarriesTokenizedDelimiters :: Assertion
assertCarriesTokenizedDelimiters = do
expr <- parseExprOrFail "assert a == 1; 2"
case expr of
NixAssert ann _ _ -> do
annToken (aaAssert ann) @?= AnnAssert
annToken (aaSemicolon ann) @?= AnnSemicolon
annTokenSrcSpan (aaAssert ann) @?= Just (mkSrcSpan "<expr>" (1, 1) (1, 7))
annTokenSrcSpan (aaSemicolon ann) @?= Just (mkSrcSpan "<expr>" (1, 14) (1, 15))
_ -> assertFailure $ "expected assert expression, got: " <> show expr
setCarriesTokenizedBraces :: Assertion
setCarriesTokenizedBraces = do
expr <- parseExprOrFail "{ x = 1; }"
case expr of
NixSet ann _ _ -> do
annToken (asOpenC ann) @?= AnnOpenC
annToken (asCloseC ann) @?= AnnCloseC
annTokenSrcSpan (asOpenC ann) @?= Just (mkSrcSpan "<expr>" (1, 1) (1, 2))
annTokenSrcSpan (asCloseC ann) @?= Just (mkSrcSpan "<expr>" (1, 10) (1, 11))
_ -> assertFailure $ "expected set expression, got: " <> show expr
setCarriesTypedAnnComments :: Assertion
setCarriesTypedAnnComments = do
expr <- parseFileOrFail "<comments>" "{\n # hello\n x = 1;\n}"
case expr of
NixSet ann _ _ -> do
fmap srcSpanStartColumn (annTokenSrcSpan (asOpenC ann)) @?= Just 1
fmap srcSpanStartColumn (annTokenSrcSpan (asCloseC ann)) @?= Just 1
acComments (asCommon ann) @?= emptyComments
_ -> assertFailure $ "expected set expression, got: " <> show expr
isSubspanOfChecksEndColumns :: Assertion
isSubspanOfChecksEndColumns = do
let parent = mkSrcSpan "<test>" (1, 1) (1, 5)
inside = mkSrcSpan "<test>" (1, 2) (1, 5)
outside = mkSrcSpan "<test>" (1, 2) (1, 6)
assertBool "subspan ending at parent column should be inside" $ inside `isSubspanOf` parent
assertBool "subspan ending after parent column should be outside" $ not (outside `isSubspanOf` parent)
exactPrintPreservesQuotedStringSource :: Assertion
exactPrintPreservesQuotedStringSource = do
case runNixParser (nixExpr <* eof) "<expr>" "\"a$${b}c\"" of
(Right expr, _) -> renderExactText expr @?= "\"a$${b}c\""
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintRoundtripsQuotedStringSource :: Assertion
exactPrintRoundtripsQuotedStringSource = assertExactPrintRoundtripExpr "\"a$${b}c\""
exactPrintRoundtripsEnvPath :: Assertion
exactPrintRoundtripsEnvPath = assertExactPrintRoundtripExpr "<nixpkgs/nixos>"
exactPrintRoundtripsMultilineList :: Assertion
exactPrintRoundtripsMultilineList = assertExactPrintRoundtripFile "<list>" "[\n a\n b\n]"
exactPrintRoundtripsMultilineSet :: Assertion
exactPrintRoundtripsMultilineSet = assertExactPrintRoundtripFile "<set>" "{\n x = 1;\n y = 2;\n}"
exactPrintRoundtripsMultilineLet :: Assertion
exactPrintRoundtripsMultilineLet = assertExactPrintRoundtripFile "<let>" "let\n x = 1;\nin\n x"
exactPrintRoundtripsMultilineIf :: Assertion
exactPrintRoundtripsMultilineIf = assertExactPrintRoundtripFile "<if>" "if\n a\nthen\n b\nelse\n c"
exactPrintRoundtripsMultilineWith :: Assertion
exactPrintRoundtripsMultilineWith = assertExactPrintRoundtripFile "<with>" "with\n l\n;\n 1"
exactPrintRoundtripsMultilineAssert :: Assertion
exactPrintRoundtripsMultilineAssert = assertExactPrintRoundtripFile "<assert>" "assert\n a == 1\n;\n 2"
exactPrintRoundtripsMultilineHasAttr :: Assertion
exactPrintRoundtripsMultilineHasAttr = assertExactPrintRoundtripFile "<has-attr>" "a\n?\n b"
exactPrintRoundtripsMultilineSelectOr :: Assertion
exactPrintRoundtripsMultilineSelectOr = assertExactPrintRoundtripFile "<select>" "a.b.c\nor\n d.e"
exactPrintRoundtripsSampleFixture :: Assertion
exactPrintRoundtripsSampleFixture = do
src <- T.readFile "test/sample.nix"
assertExactPrintRoundtripFile "test/sample.nix" (maybe src id (T.stripSuffix "\n" src))
exactPrintPreservesLambdaCommentShape :: Assertion
exactPrintPreservesLambdaCommentShape =
assertExactPrintRoundtripFile
"<lambda-comments>"
"let\n # comment f\n f =\n x:\n # comment y\n y:\n x;\nin f"
exactPrintPreservesCommentNoWhitespace :: Assertion
exactPrintPreservesCommentNoWhitespace =
assertExactPrintRoundtripFile "<comment-no-ws>" "{ comment_no_ws = [a/**/]; }"
exactPrintPreservesTrailingCommaSetPattern :: Assertion
exactPrintPreservesTrailingCommaSetPattern =
assertExactPrintRoundtripFile "<param-comma>" "{x,}: x"
exactPrintPreservesInterpolatedSelectAttrPath :: Assertion
exactPrintPreservesInterpolatedSelectAttrPath =
assertExactPrintRoundtripFile "<sel-interpol>" "a.b.${c}.\"d\".\"${\"e\"}\""
exactPrintSafeApiPreservesTrailingAsPattern :: Assertion
exactPrintSafeApiPreservesTrailingAsPattern = do
case runNixParser nixFile "<lambda>" "{x}@a: x" of
(Right expr, _) -> renderExactTextM expr @?= Right "{x}@a: x"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesIndentedStringSource :: Assertion
exactPrintPreservesIndentedStringSource = do
case runNixParser (nixExpr <* eof) "<expr>" "''a${b}c''" of
(Right expr, _) -> renderExactText expr @?= "''a${b}c''"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesLiteralPath :: Assertion
exactPrintPreservesLiteralPath = do
case runNixParser (nixExpr <* eof) "<expr>" "./nix" of
(Right expr, _) -> renderExactText expr @?= "./nix"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesInterpolatedPath :: Assertion
exactPrintPreservesInterpolatedPath = do
case runNixParser (nixExpr <* eof) "<expr>" "./${a}-${b}/c/d${e}" of
(Right expr, _) -> renderExactText expr @?= "./${a}-${b}/c/d${e}"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesEnvPath :: Assertion
exactPrintPreservesEnvPath = do
case runNixParser (nixExpr <* eof) "<expr>" "<nixpkgs/nixos>" of
(Right expr, _) -> renderExactText expr @?= "<nixpkgs/nixos>"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesDynamicAttrBinding :: Assertion
exactPrintPreservesDynamicAttrBinding = do
case runNixParser nixFile "<set>" "{ \"${dynamic}\".${attr} = g; }" of
(Right expr, _) -> renderExactText expr @?= "{ \"${dynamic}\".${attr} = g; }"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesDynamicStringAttrBinding :: Assertion
exactPrintPreservesDynamicStringAttrBinding = do
case runNixParser nixFile "<set>" "{ \"a${b}c\" = g; }" of
(Right expr, _) -> renderExactText expr @?= "{ \"a${b}c\" = g; }"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesStructuralDynamicInterpolAttrBinding :: Assertion
exactPrintPreservesStructuralDynamicInterpolAttrBinding = do
case runNixParser nixFile "<set>" "{ ${a + b} = g; }" of
(Right expr, _) -> renderExactText expr @?= "{ ${a + b} = g; }"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesInheritBinding :: Assertion
exactPrintPreservesInheritBinding = do
case runNixParser nixFile "<set>" "{ inherit (s) m g; }" of
(Right expr, _) -> renderExactText expr @?= "{ inherit (s) m g; }"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesLambdaVarPattern :: Assertion
exactPrintPreservesLambdaVarPattern = do
case runNixParser nixFile "<lambda>" "x: x" of
(Right expr, _) -> renderExactText expr @?= "x: x"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesLambdaSetPattern :: Assertion
exactPrintPreservesLambdaSetPattern = do
case runNixParser nixFile "<lambda>" "{ x ? 1, y ? {}, ... }: x" of
(Right expr, _) -> renderExactText expr @?= "{ x ? 1, y ? {}, ... }: x"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesMultilineLambdaChainLayout :: Assertion
exactPrintPreservesMultilineLambdaChainLayout =
assertExactPrintRoundtripFile "<lambda-multiline>" "x:\n y:\n x"
exactPrintPreservesApplication :: Assertion
exactPrintPreservesApplication = do
case runNixParser nixFile "<app>" "a b c" of
(Right expr, _) -> renderExactText expr @?= "a b c"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesHasAttr :: Assertion
exactPrintPreservesHasAttr = do
case runNixParser nixFile "<has-attr>" "a ? b" of
(Right expr, _) -> renderExactText expr @?= "a ? b"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesWithExpr :: Assertion
exactPrintPreservesWithExpr = do
case runNixParser nixFile "<with>" "with l; 1" of
(Right expr, _) -> renderExactText expr @?= "with l; 1"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesAssertExpr :: Assertion
exactPrintPreservesAssertExpr = do
case runNixParser nixFile "<assert>" "assert a == 1; 2" of
(Right expr, _) -> renderExactText expr @?= "assert a == 1; 2"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintEmitsRootComments :: Assertion
exactPrintEmitsRootComments = do
case runNixParser nixFile "<comments>" "# hello\n1\n# bye" of
(Right expr, _) -> renderExactText expr @?= "# hello\n1\n# bye"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintEmitsClosingDelimitedComments :: Assertion
exactPrintEmitsClosingDelimitedComments = do
case runNixParser nixFile "<comments>" "[ a /* hello */ ]" of
(Right expr, _) -> renderExactText expr @?= "[ a /* hello */ ]"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesMultilineListLayout :: Assertion
exactPrintPreservesMultilineListLayout = do
case runNixParser nixFile "<list>" "[\n a\n b\n]" of
(Right expr, _) -> renderExactText expr @?= "[\n a\n b\n]"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesMultilineSetLayout :: Assertion
exactPrintPreservesMultilineSetLayout = do
case runNixParser nixFile "<set>" "{\n x = 1;\n y = 2;\n}" of
(Right expr, _) -> renderExactText expr @?= "{\n x = 1;\n y = 2;\n}"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesMultilineLetLayout :: Assertion
exactPrintPreservesMultilineLetLayout = do
case runNixParser nixFile "<let>" "let\n x = 1;\nin\n x" of
(Right expr, _) -> renderExactText expr @?= "let\n x = 1;\nin\n x"
(Left err, _) -> assertFailure $ errorBundlePretty err
exactPrintPreservesMultilineIfLayout :: Assertion
exactPrintPreservesMultilineIfLayout = do
case runNixParser nixFile "<if>" "if\n a\nthen\n b\nelse\n c" of
(Right expr, _) -> renderExactText expr @?= "if\n a\nthen\n b\nelse\n c"
(Left err, _) -> assertFailure $ errorBundlePretty err
referenceExactPrintFixtureTests :: TestTree
referenceExactPrintFixtureTests =
testGroup
"reference exact-print fixtures"
[ testGroup "roundtrip" (fixtureRoundtripCase <$> roundtripFixtures)
]
fixtureRoundtripCase :: FilePath -> TestTree
fixtureRoundtripCase relPath =
testCase relPath $ do
src <- T.readFile fullPath
assertExactPrintRoundtripFile fullPath (dropTrailingNewline src)
where
fullPath = fixtureRoot <> "/" <> relPath
fixtureRoot :: FilePath
fixtureRoot = "test/fixtures/nixfmt"
roundtripFixtures :: [FilePath]
roundtripFixtures =
[ "correct/string-with-single-quote-at-end.nix",
"correct/paths-with-interpolations.nix",
"correct/quotes-in-inherit.nix",
"correct/blank-line-in-interpolation.nix",
"correct/indented-string.nix"
]
dropTrailingNewline :: T.Text -> T.Text
dropTrailingNewline text = maybe text id (T.stripSuffix "\n" text)