packages feed

moonlight-pale-0.1.0.0: test/ghc-surface/Expr/SourceCoordinatesSpec.hs

module Expr.SourceCoordinatesSpec (tests) where

import Moonlight.Pale.Ghc.Expr
  ( SourceEndConvention (..),
    SourceRangeFailure (..),
    SourceRegion (..),
    sourceCharRangeEnd,
    sourceCharRangeRegion,
    sourceCharRangeStart,
    sourceCharRangeText,
    sourceRegionCharRangeWith,
  )
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertEqual, assertFailure, testCase)

tests :: TestTree
tests =
  testGroup
    "profile-rewrite.coordinates"
    [ testCase "tab-aware half-open coordinates retain Unicode scalar offsets" $ do
        resolved <- requireRight (sourceRegionCharRangeWith 8 SourceEndHalfOpen canonicalSource (SourceRegion 1 1 1 13))
        assertEqual "start" 0 (sourceCharRangeStart resolved)
        assertEqual "end" 6 (sourceCharRangeEnd resolved)
        assertEqual "slice" (Right "α\tbeta") (sourceCharRangeText canonicalSource resolved),
      testCase "tab-aware inclusive coordinates consume the final source character" $ do
        resolved <- requireRight (sourceRegionCharRangeWith 8 SourceEndInclusive canonicalSource (SourceRegion 1 9 1 12))
        assertEqual "start" 2 (sourceCharRangeStart resolved)
        assertEqual "end" 6 (sourceCharRangeEnd resolved)
        assertEqual "slice" (Right "beta") (sourceCharRangeText canonicalSource resolved),
      testCase "coordinates inside a tab expansion are noninvertible" $
        assertEqual
          "inside tab"
          (Left (SourceRangePositionInsideTab 1 3))
          (sourceRegionCharRangeWith 8 SourceEndHalfOpen canonicalSource (SourceRegion 1 3 1 9)),
      testCase "cross-line half-open coordinates preserve the newline" $ do
        let expectedRegion = SourceRegion 1 9 2 2
        resolved <- requireRight (sourceRegionCharRangeWith 8 SourceEndHalfOpen canonicalSource expectedRegion)
        assertEqual "slice" (Right "beta\nz") (sourceCharRangeText canonicalSource resolved)
        assertEqual "inverse region" (Right expectedRegion) (sourceCharRangeRegion canonicalSource resolved),
      testCase "tab-aware range inversion returns visual columns" $ do
        let expectedRegion = SourceRegion 1 9 1 13
        resolved <- requireRight (sourceRegionCharRangeWith 8 SourceEndHalfOpen canonicalSource expectedRegion)
        assertEqual "visual-column inverse" (Right expectedRegion) (sourceCharRangeRegion canonicalSource resolved),
      testCase "CRLF source is refused" $
        assertEqual
          "CRLF"
          (Left SourceRangeCarriageReturnUnsupported)
          (sourceRegionCharRangeWith 8 SourceEndHalfOpen "x\r\ny\n" (SourceRegion 1 1 1 2)),
      testCase "bare carriage returns are refused" $
        assertEqual
          "bare CR"
          (Left SourceRangeCarriageReturnUnsupported)
          (sourceRegionCharRangeWith 8 SourceEndHalfOpen "x\ry" (SourceRegion 1 1 1 2)),
      testCase "invalid tab stops are refused before conversion" $
        assertEqual
          "tab stop"
          (Left (SourceRangeInvalidTabStop 0))
          (sourceRegionCharRangeWith 0 SourceEndHalfOpen canonicalSource (SourceRegion 1 1 1 2)),
      testCase "inclusive coordinates cannot name the boundary after a line" $
        assertEqual
          "inclusive boundary"
          (Left (SourceRangePositionOutsideSource 1 13))
          (sourceRegionCharRangeWith 8 SourceEndInclusive canonicalSource (SourceRegion 1 9 1 13))
    ]

canonicalSource :: String
canonicalSource = "α\tbeta\nz\n"

requireRight :: Show failure => Either failure value -> IO value
requireRight = either (assertFailure . show) pure