mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-26 03:04:48 +03:00
Move error messages out of Lint.Test and into Lint.Test.ErrorMessage
This commit is contained in:
parent
1d3333f489
commit
b6464dbff2
@ -1,638 +0,0 @@
|
|||||||
module Lint.Internal.Test exposing
|
|
||||||
( LintResult, run
|
|
||||||
, ExpectedError, expectErrors, expectNoErrors, error, atExactly
|
|
||||||
, parsingErrorMessage, messageMismatchError, wrongLocationError, didNotExpectErrors
|
|
||||||
, underMismatchError, notEnoughErrors, tooManyErrors, locationIsAmbiguousInSourceCodeError
|
|
||||||
)
|
|
||||||
|
|
||||||
{-| Module that helps you test your linting rules, using [`elm-test`](https://package.elm-lang.org/packages/elm-explorations/test/latest).
|
|
||||||
|
|
||||||
import Lint.Test exposing (LintResult)
|
|
||||||
import Test exposing (Test, describe, test)
|
|
||||||
import The.Rule.You.Want.To.Test exposing (rule)
|
|
||||||
|
|
||||||
testRule : String -> LintResult
|
|
||||||
testRule string =
|
|
||||||
Lint.Test.run rule string
|
|
||||||
|
|
||||||
-- In this example, the rule we're testing is `NoDebug`
|
|
||||||
tests : Test
|
|
||||||
tests =
|
|
||||||
describe "NoDebug"
|
|
||||||
[ test "should not report calls to normal functions" <|
|
|
||||||
\() ->
|
|
||||||
testRule """module A exposing (..)
|
|
||||||
a = foo n"""
|
|
||||||
|> Lint.Test.expectNoErrors
|
|
||||||
, test "should report Debug.log use" <|
|
|
||||||
\() ->
|
|
||||||
testRule """module A exposing (..)
|
|
||||||
a = Debug.log "some" "message\""""
|
|
||||||
|> Lint.Test.expectErrors
|
|
||||||
[ Lint.Test.error
|
|
||||||
{ message = "Forbidden use of Debug"
|
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Running tests
|
|
||||||
|
|
||||||
@docs LintResult, run
|
|
||||||
|
|
||||||
|
|
||||||
# Making assertions
|
|
||||||
|
|
||||||
@docs ExpectedError, expectErrors, expectNoErrors, error, atExactly
|
|
||||||
|
|
||||||
|
|
||||||
# Error messages
|
|
||||||
|
|
||||||
@docs parsingErrorMessage, messageMismatchError, wrongLocationError, didNotExpectErrors
|
|
||||||
@docs underMismatchError, notEnoughErrors, tooManyErrors, locationIsAmbiguousInSourceCodeError
|
|
||||||
|
|
||||||
|
|
||||||
# Tips on testing
|
|
||||||
|
|
||||||
|
|
||||||
## What should you test?
|
|
||||||
|
|
||||||
TODO Add helpful tips
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Array exposing (Array)
|
|
||||||
import Elm.Syntax.Range exposing (Range)
|
|
||||||
import Expect exposing (Expectation)
|
|
||||||
import Lint exposing (Severity(..), lintSource)
|
|
||||||
import Lint.Rule as Rule exposing (Error, Rule)
|
|
||||||
import List.Extra
|
|
||||||
|
|
||||||
|
|
||||||
{-| The result of running a rule on a `String` containing source code.
|
|
||||||
-}
|
|
||||||
type LintResult
|
|
||||||
= ParseFailure
|
|
||||||
| SuccessfulRun CodeInspector (List Error)
|
|
||||||
|
|
||||||
|
|
||||||
type alias CodeInspector =
|
|
||||||
{ getCodeAtLocation : Range -> Maybe String
|
|
||||||
, checkIfLocationIsAmbiguous : Error -> String -> Expectation
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| An expectation for an error. Use [`error`](#error) to create one.
|
|
||||||
-}
|
|
||||||
type ExpectedError
|
|
||||||
= ExpectedError
|
|
||||||
{ message : String
|
|
||||||
, under : Under
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Under
|
|
||||||
= Under String
|
|
||||||
| UnderExactly String Range
|
|
||||||
|
|
||||||
|
|
||||||
type alias SourceCode =
|
|
||||||
String
|
|
||||||
|
|
||||||
|
|
||||||
{-| Run a `Rule` on a `String` containing source code. You can then use
|
|
||||||
[`expectNoErrors`](#expectNoErrors) or [`expectErrors`](#expectErrors) to assert
|
|
||||||
the errors reported by the rule.
|
|
||||||
|
|
||||||
The source code needs to be syntactically valid Elm code. If the code
|
|
||||||
can't be parsed, the test will fail regardless of the expectations you set on it.
|
|
||||||
|
|
||||||
Note that t be syntactically valid, you need at least a module declaration at the
|
|
||||||
top of the file (like `module A exposing (..)`) and one declaration (like `a = 1`).
|
|
||||||
You can't just have an expression like `1 + 2`.
|
|
||||||
|
|
||||||
-}
|
|
||||||
run : Rule -> String -> LintResult
|
|
||||||
run rule sourceCode =
|
|
||||||
case lintSource [ ( Critical, rule ) ] sourceCode of
|
|
||||||
Ok errors ->
|
|
||||||
SuccessfulRun
|
|
||||||
{ getCodeAtLocation = getCodeAtLocationInSourceCode sourceCode
|
|
||||||
, checkIfLocationIsAmbiguous = checkIfLocationIsAmbiguousInSourceCode sourceCode
|
|
||||||
}
|
|
||||||
(List.map (\( _, error_ ) -> Rule.error error_.message error_.range) errors)
|
|
||||||
|
|
||||||
Err _ ->
|
|
||||||
ParseFailure
|
|
||||||
|
|
||||||
|
|
||||||
{-| Assert that the rule reprted no errors. Note, this is equivalent to using [`expectErrors`](#expectErrors)
|
|
||||||
like `expectErrors []`.
|
|
||||||
|
|
||||||
import Lint.Test exposing (LintResult)
|
|
||||||
import Test exposing (Test, describe, test)
|
|
||||||
import The.Rule.You.Want.To.Test exposing (rule)
|
|
||||||
|
|
||||||
testRule : String -> LintResult
|
|
||||||
testRule string =
|
|
||||||
Lint.Test.run rule string
|
|
||||||
|
|
||||||
-- In this example, the rule we're testing is `NoDebug`
|
|
||||||
tests : Test
|
|
||||||
tests =
|
|
||||||
describe "NoDebug"
|
|
||||||
[ test "should not report calls to normal functions" <|
|
|
||||||
\() ->
|
|
||||||
testRule """module A exposing (..)
|
|
||||||
a = foo n"""
|
|
||||||
|> Lint.Test.expectNoErrors
|
|
||||||
]
|
|
||||||
|
|
||||||
-}
|
|
||||||
expectNoErrors : LintResult -> Expectation
|
|
||||||
expectNoErrors lintResult =
|
|
||||||
case lintResult of
|
|
||||||
ParseFailure ->
|
|
||||||
Expect.fail parsingErrorMessage
|
|
||||||
|
|
||||||
SuccessfulRun _ errors ->
|
|
||||||
Expect.true
|
|
||||||
(didNotExpectErrors errors)
|
|
||||||
(List.isEmpty errors)
|
|
||||||
|
|
||||||
|
|
||||||
didNotExpectErrors : List Error -> String
|
|
||||||
didNotExpectErrors errors =
|
|
||||||
"""I expected no errors but found:
|
|
||||||
|
|
||||||
""" ++ (List.map errorToString errors |> String.join "\n ")
|
|
||||||
|
|
||||||
|
|
||||||
{-| Assert that the rule reprted some errors, by specifying which one.
|
|
||||||
|
|
||||||
Assert which errors are reported using [`error`](#error). The test will fail if
|
|
||||||
a different number of errors than expected are reported, or if the message or the
|
|
||||||
location is incorrect.
|
|
||||||
|
|
||||||
The errors should be in the order of where they appear in the source code. An error
|
|
||||||
at the start of the source code should appear earlier in the list than
|
|
||||||
an error at the end of the source code.
|
|
||||||
|
|
||||||
import Lint.Test exposing (LintResult)
|
|
||||||
import Test exposing (Test, describe, test)
|
|
||||||
import The.Rule.You.Want.To.Test exposing (rule)
|
|
||||||
|
|
||||||
testRule : String -> LintResult
|
|
||||||
testRule string =
|
|
||||||
Lint.Test.run rule string
|
|
||||||
|
|
||||||
-- In this example, the rule we're testing is `NoDebug`
|
|
||||||
tests : Test
|
|
||||||
tests =
|
|
||||||
describe "NoDebug"
|
|
||||||
[ test "should report Debug.log use" <|
|
|
||||||
\() ->
|
|
||||||
testRule """module A exposing (..)
|
|
||||||
a = Debug.log "some" "message\""""
|
|
||||||
|> Lint.Test.expectErrors
|
|
||||||
[ Lint.Test.error
|
|
||||||
{ message = "Forbidden use of Debug"
|
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
-}
|
|
||||||
expectErrors : List ExpectedError -> LintResult -> Expectation
|
|
||||||
expectErrors expectedErrors lintResult =
|
|
||||||
case lintResult of
|
|
||||||
ParseFailure ->
|
|
||||||
Expect.fail parsingErrorMessage
|
|
||||||
|
|
||||||
SuccessfulRun codeInspector errors ->
|
|
||||||
checkAllErrorsMatch codeInspector expectedErrors errors
|
|
||||||
|
|
||||||
|
|
||||||
{-| Create an expectation for an error.
|
|
||||||
|
|
||||||
`message` should be the message you're expecting to be shown to the user.
|
|
||||||
|
|
||||||
`under` is the part of the code where you are expecting the error to be shown to
|
|
||||||
the user. If it helps, imagine `under` to be the text under which the squiggly
|
|
||||||
lines will appear if the error appeared in an editor.
|
|
||||||
|
|
||||||
tests : Test
|
|
||||||
tests =
|
|
||||||
describe "NoDebug"
|
|
||||||
[ test "should report Debug.log use" <|
|
|
||||||
\() ->
|
|
||||||
testRule """module A exposing (..)
|
|
||||||
a = Debug.log "some" "message\""""
|
|
||||||
|> Lint.Test.expectErrors
|
|
||||||
[ Lint.Test.error
|
|
||||||
{ message = "Forbidden use of Debug"
|
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
If there are multiple locations where the value of `under` appears, the test will
|
|
||||||
fail unless you use [`atExactly`](#atExactly) to remove any ambiguity of where the
|
|
||||||
error should be used.
|
|
||||||
|
|
||||||
-}
|
|
||||||
error : { message : String, under : String } -> ExpectedError
|
|
||||||
error input =
|
|
||||||
ExpectedError
|
|
||||||
{ message = input.message
|
|
||||||
, under = Under input.under
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getUnder : ExpectedError -> String
|
|
||||||
getUnder (ExpectedError expectedError) =
|
|
||||||
case expectedError.under of
|
|
||||||
Under str ->
|
|
||||||
str
|
|
||||||
|
|
||||||
UnderExactly str _ ->
|
|
||||||
str
|
|
||||||
|
|
||||||
|
|
||||||
{-| Precise the exact position where the error should be shown to the user. This
|
|
||||||
is only necessary when the `under` field is ambiguous.
|
|
||||||
|
|
||||||
`atExactly` takes a record with start and end positions.
|
|
||||||
|
|
||||||
tests : Test
|
|
||||||
tests =
|
|
||||||
describe "NoDebug"
|
|
||||||
[ test "should report multiple Debug.log calls" <|
|
|
||||||
\() ->
|
|
||||||
testRule """
|
|
||||||
a = Debug.log z
|
|
||||||
b = Debug.log z
|
|
||||||
"""
|
|
||||||
|> Lint.Test.expectErrors
|
|
||||||
[ Lint.Test.error
|
|
||||||
{ message = message
|
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
|> Lint.Test.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }
|
|
||||||
, Lint.Test.error
|
|
||||||
{ message = message
|
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
|> Lint.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } }
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
Tip: By default, do not provide this field. If the test fails because there is some
|
|
||||||
ambiguity, the test error will give you a recommendation of what to use as a parameter
|
|
||||||
of `atExactly`, so you do not have to bother writing this hard to write argument.
|
|
||||||
|
|
||||||
-}
|
|
||||||
atExactly : { start : { row : Int, column : Int }, end : { row : Int, column : Int } } -> ExpectedError -> ExpectedError
|
|
||||||
atExactly range ((ExpectedError expectedError_) as expectedError) =
|
|
||||||
ExpectedError { expectedError_ | under = UnderExactly (getUnder expectedError) range }
|
|
||||||
|
|
||||||
|
|
||||||
checkAllErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> Expectation
|
|
||||||
checkAllErrorsMatch codeInspector expectedErrors errors =
|
|
||||||
checkErrorsMatch codeInspector expectedErrors errors
|
|
||||||
|> List.reverse
|
|
||||||
|> (\expectations -> Expect.all expectations ())
|
|
||||||
|
|
||||||
|
|
||||||
checkErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> List (() -> Expectation)
|
|
||||||
checkErrorsMatch codeInspector expectedErrors errors =
|
|
||||||
case ( expectedErrors, errors ) of
|
|
||||||
( [], [] ) ->
|
|
||||||
[ always Expect.pass ]
|
|
||||||
|
|
||||||
( expected :: restOfExpectedErrors, error_ :: restOfErrors ) ->
|
|
||||||
checkErrorMatch codeInspector expected error_ :: checkErrorsMatch codeInspector restOfExpectedErrors restOfErrors
|
|
||||||
|
|
||||||
( expected :: restOfExpectedErrors, [] ) ->
|
|
||||||
[ always <| Expect.fail <| notEnoughErrors (expected :: restOfExpectedErrors) ]
|
|
||||||
|
|
||||||
( [], error_ :: restOfErrors ) ->
|
|
||||||
[ always <| Expect.fail <| tooManyErrors (error_ :: restOfErrors) ]
|
|
||||||
|
|
||||||
|
|
||||||
checkErrorMatch : CodeInspector -> ExpectedError -> Error -> (() -> Expectation)
|
|
||||||
checkErrorMatch codeInspector ((ExpectedError expectedError_) as expectedError) error_ =
|
|
||||||
Expect.all
|
|
||||||
[ always <| Expect.true (messageMismatchError expectedError error_) (expectedError_.message == Rule.errorMessage error_)
|
|
||||||
, checkMessageAppearsUnder codeInspector error_ expectedError
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
checkMessageAppearsUnder : CodeInspector -> Error -> ExpectedError -> (() -> Expectation)
|
|
||||||
checkMessageAppearsUnder codeInspector error_ (ExpectedError expectedError) =
|
|
||||||
case codeInspector.getCodeAtLocation (Rule.errorRange error_) of
|
|
||||||
Just codeAtLocation ->
|
|
||||||
case expectedError.under of
|
|
||||||
Under under ->
|
|
||||||
Expect.all
|
|
||||||
[ always <|
|
|
||||||
Expect.true
|
|
||||||
(underMismatchError error_ { under = under, codeAtLocation = codeAtLocation })
|
|
||||||
(codeAtLocation == under)
|
|
||||||
, always <| codeInspector.checkIfLocationIsAmbiguous error_ under
|
|
||||||
]
|
|
||||||
|
|
||||||
UnderExactly under range ->
|
|
||||||
Expect.all
|
|
||||||
[ always <|
|
|
||||||
Expect.true
|
|
||||||
(underMismatchError error_ { under = under, codeAtLocation = codeAtLocation })
|
|
||||||
(codeAtLocation == under)
|
|
||||||
, always <|
|
|
||||||
Expect.true
|
|
||||||
(wrongLocationError error_ range under)
|
|
||||||
(Rule.errorRange error_ == range)
|
|
||||||
]
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
always <| Expect.fail impossibleStateError
|
|
||||||
|
|
||||||
|
|
||||||
getCodeAtLocationInSourceCode : SourceCode -> Range -> Maybe String
|
|
||||||
getCodeAtLocationInSourceCode sourceCode =
|
|
||||||
let
|
|
||||||
lines : Array String
|
|
||||||
lines =
|
|
||||||
String.lines sourceCode
|
|
||||||
|> Array.fromList
|
|
||||||
in
|
|
||||||
\{ start, end } ->
|
|
||||||
if start.row == end.row then
|
|
||||||
Array.get (start.row - 1) lines
|
|
||||||
|> Maybe.map (String.slice (start.column - 1) (end.column - 1))
|
|
||||||
|
|
||||||
else
|
|
||||||
let
|
|
||||||
firstLine : Maybe String
|
|
||||||
firstLine =
|
|
||||||
Array.get (start.row - 1) lines
|
|
||||||
|> Maybe.map (String.dropLeft (start.column - 1))
|
|
||||||
|
|
||||||
lastLine : Maybe String
|
|
||||||
lastLine =
|
|
||||||
Array.get (end.row - 1) lines
|
|
||||||
|> Maybe.map (String.dropRight end.column)
|
|
||||||
in
|
|
||||||
[ [ firstLine ]
|
|
||||||
, Array.slice start.row (end.row - 1) lines
|
|
||||||
|> Array.toList
|
|
||||||
|> List.map Just
|
|
||||||
, [ lastLine ]
|
|
||||||
]
|
|
||||||
|> List.concat
|
|
||||||
|> List.filterMap identity
|
|
||||||
|> String.join "\n"
|
|
||||||
|> Just
|
|
||||||
|
|
||||||
|
|
||||||
formatSourceCode : String -> String
|
|
||||||
formatSourceCode string =
|
|
||||||
let
|
|
||||||
lines =
|
|
||||||
String.lines string
|
|
||||||
in
|
|
||||||
if List.length lines == 1 then
|
|
||||||
"`" ++ string ++ "`"
|
|
||||||
|
|
||||||
else
|
|
||||||
lines
|
|
||||||
|> List.map (\str -> " " ++ str)
|
|
||||||
|> String.join "\n"
|
|
||||||
|> (\str -> "```\n" ++ str ++ "\n ```")
|
|
||||||
|
|
||||||
|
|
||||||
checkIfLocationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> Expectation
|
|
||||||
checkIfLocationIsAmbiguousInSourceCode sourceCode error_ under =
|
|
||||||
let
|
|
||||||
occurrencesInSourceCode : List Int
|
|
||||||
occurrencesInSourceCode =
|
|
||||||
String.indexes under sourceCode
|
|
||||||
in
|
|
||||||
Expect.true
|
|
||||||
(locationIsAmbiguousInSourceCodeError sourceCode error_ under occurrencesInSourceCode)
|
|
||||||
(List.length occurrencesInSourceCode == 1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ERROR MESSAGES
|
|
||||||
|
|
||||||
|
|
||||||
parsingErrorMessage : String
|
|
||||||
parsingErrorMessage =
|
|
||||||
"""I could not parse the test source code, because it was not syntactically valid Elm code.
|
|
||||||
|
|
||||||
Maybe you forgot to add the module definition at the top, like:
|
|
||||||
|
|
||||||
`module A exposing (..)`"""
|
|
||||||
|
|
||||||
|
|
||||||
messageMismatchError : ExpectedError -> Error -> String
|
|
||||||
messageMismatchError (ExpectedError expectedError) error_ =
|
|
||||||
"""I was looking for the error with the following message:
|
|
||||||
|
|
||||||
`""" ++ expectedError.message ++ """`
|
|
||||||
|
|
||||||
but I found the following error message:
|
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ "`"
|
|
||||||
|
|
||||||
|
|
||||||
underMismatchError : Error -> { under : String, codeAtLocation : String } -> String
|
|
||||||
underMismatchError error_ { under, codeAtLocation } =
|
|
||||||
"""I found an error with the following message:
|
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ """`
|
|
||||||
|
|
||||||
which I was expecting, but I found it under:
|
|
||||||
|
|
||||||
""" ++ formatSourceCode codeAtLocation ++ """
|
|
||||||
|
|
||||||
when I was expecting it under:
|
|
||||||
|
|
||||||
""" ++ formatSourceCode under ++ """
|
|
||||||
|
|
||||||
Hint: Maybe you're passing the `Range` of a wrong node when calling `Rule.error`"""
|
|
||||||
|
|
||||||
|
|
||||||
wrongLocationError : Error -> Range -> String -> String
|
|
||||||
wrongLocationError error_ range under =
|
|
||||||
"""I was looking for the error with the following message:
|
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ """`
|
|
||||||
|
|
||||||
under the following code:
|
|
||||||
|
|
||||||
""" ++ formatSourceCode under ++ """
|
|
||||||
|
|
||||||
and I found it, but the exact location you specified is not the one I found. I was expecting the error at:
|
|
||||||
|
|
||||||
""" ++ rangeAsString range ++ """
|
|
||||||
|
|
||||||
but I found it at:
|
|
||||||
|
|
||||||
""" ++ rangeAsString (Rule.errorRange error_)
|
|
||||||
|
|
||||||
|
|
||||||
listOccurrencesAsLocations : SourceCode -> String -> List Int -> String
|
|
||||||
listOccurrencesAsLocations sourceCode under occurrences =
|
|
||||||
occurrences
|
|
||||||
|> List.map
|
|
||||||
(\occurrence ->
|
|
||||||
occurrence
|
|
||||||
|> positionAsRange sourceCode under
|
|
||||||
|> rangeAsString
|
|
||||||
|> (++) " - "
|
|
||||||
)
|
|
||||||
|> String.join "\n"
|
|
||||||
|
|
||||||
|
|
||||||
positionAsRange : SourceCode -> String -> Int -> Range
|
|
||||||
positionAsRange sourceCode under position =
|
|
||||||
let
|
|
||||||
linesBeforeAndIncludingPosition : List String
|
|
||||||
linesBeforeAndIncludingPosition =
|
|
||||||
sourceCode
|
|
||||||
|> String.slice 0 position
|
|
||||||
|> String.lines
|
|
||||||
|
|
||||||
startRow : Int
|
|
||||||
startRow =
|
|
||||||
List.length linesBeforeAndIncludingPosition
|
|
||||||
|
|
||||||
startColumn : Int
|
|
||||||
startColumn =
|
|
||||||
linesBeforeAndIncludingPosition
|
|
||||||
|> List.Extra.last
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|> String.length
|
|
||||||
|> (+) 1
|
|
||||||
|
|
||||||
linesInUnder : List String
|
|
||||||
linesInUnder =
|
|
||||||
String.lines under
|
|
||||||
|
|
||||||
endRow : Int
|
|
||||||
endRow =
|
|
||||||
startRow + List.length linesInUnder - 1
|
|
||||||
|
|
||||||
endColumn : Int
|
|
||||||
endColumn =
|
|
||||||
if startRow == endRow then
|
|
||||||
startColumn + String.length under
|
|
||||||
|
|
||||||
else
|
|
||||||
linesInUnder
|
|
||||||
|> List.Extra.last
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|> String.length
|
|
||||||
|> (+) 1
|
|
||||||
in
|
|
||||||
{ start =
|
|
||||||
{ row = startRow
|
|
||||||
, column = startColumn
|
|
||||||
}
|
|
||||||
, end =
|
|
||||||
{ row = endRow
|
|
||||||
, column = endColumn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
errorToString : Error -> String
|
|
||||||
errorToString error_ =
|
|
||||||
"- \"" ++ Rule.errorMessage error_ ++ "\" at " ++ rangeAsString (Rule.errorRange error_)
|
|
||||||
|
|
||||||
|
|
||||||
rangeAsString : Range -> String
|
|
||||||
rangeAsString { start, end } =
|
|
||||||
"{ start = { row = " ++ String.fromInt start.row ++ ", column = " ++ String.fromInt start.column ++ " }, end = { row = " ++ String.fromInt end.row ++ ", column = " ++ String.fromInt end.column ++ " } }"
|
|
||||||
|
|
||||||
|
|
||||||
notEnoughErrors : List ExpectedError -> String
|
|
||||||
notEnoughErrors missingExpectedErrors =
|
|
||||||
let
|
|
||||||
numberOfErrors : Int
|
|
||||||
numberOfErrors =
|
|
||||||
List.length missingExpectedErrors
|
|
||||||
in
|
|
||||||
"I expected to see "
|
|
||||||
++ String.fromInt numberOfErrors
|
|
||||||
++ " more "
|
|
||||||
++ pluralizeErrors numberOfErrors
|
|
||||||
++ ":\n\n"
|
|
||||||
++ (missingExpectedErrors
|
|
||||||
|> List.map expectedErrorToString
|
|
||||||
|> String.join "\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
wrapInQuotes : String -> String
|
|
||||||
wrapInQuotes string =
|
|
||||||
"\"" ++ string ++ "\""
|
|
||||||
|
|
||||||
|
|
||||||
tooManyErrors : List Error -> String
|
|
||||||
tooManyErrors extraErrors =
|
|
||||||
let
|
|
||||||
numberOfErrors : Int
|
|
||||||
numberOfErrors =
|
|
||||||
List.length extraErrors
|
|
||||||
in
|
|
||||||
"I found "
|
|
||||||
++ String.fromInt numberOfErrors
|
|
||||||
++ " "
|
|
||||||
++ pluralizeErrors numberOfErrors
|
|
||||||
++ " too many:\n\n"
|
|
||||||
++ (extraErrors
|
|
||||||
|> List.map errorToString
|
|
||||||
|> String.join "\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
locationIsAmbiguousInSourceCodeError : SourceCode -> Error -> String -> List Int -> String
|
|
||||||
locationIsAmbiguousInSourceCodeError sourceCode error_ under occurrencesInSourceCode =
|
|
||||||
"""Your test passes, but where the message appears is ambiguous.
|
|
||||||
|
|
||||||
You are looking for the following error message:
|
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ """`
|
|
||||||
|
|
||||||
and expecting to see it under:
|
|
||||||
|
|
||||||
""" ++ formatSourceCode under ++ """
|
|
||||||
|
|
||||||
I found """ ++ String.fromInt (List.length occurrencesInSourceCode) ++ """ locations where that code appeared. Please use `Lint.Rule.atExactly` to make the part you were targetting unambiguous.
|
|
||||||
|
|
||||||
Tip: I found them at:
|
|
||||||
""" ++ listOccurrencesAsLocations sourceCode under occurrencesInSourceCode
|
|
||||||
|
|
||||||
|
|
||||||
impossibleStateError : String
|
|
||||||
impossibleStateError =
|
|
||||||
"Oh no! I'm in an impossible state. I found an error at a location that I could not find back. Please let me know and give me an SSCCE (http://sscce.org/) here: https://github.com/jfmengels/elm-lint/issues."
|
|
||||||
|
|
||||||
|
|
||||||
pluralizeErrors : Int -> String
|
|
||||||
pluralizeErrors n =
|
|
||||||
case n of
|
|
||||||
1 ->
|
|
||||||
"error"
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
|
|
||||||
expectedErrorToString : ExpectedError -> String
|
|
||||||
expectedErrorToString (ExpectedError expectedError) =
|
|
||||||
"- " ++ wrapInQuotes expectedError.message
|
|
@ -59,7 +59,7 @@ import Elm.Syntax.Range exposing (Range)
|
|||||||
import Expect exposing (Expectation)
|
import Expect exposing (Expectation)
|
||||||
import Lint exposing (Severity(..), lintSource)
|
import Lint exposing (Severity(..), lintSource)
|
||||||
import Lint.Rule as Rule exposing (Error, Rule)
|
import Lint.Rule as Rule exposing (Error, Rule)
|
||||||
import List.Extra
|
import Lint.Test.ErrorMessage as ErrorMessage
|
||||||
|
|
||||||
|
|
||||||
{-| The result of running a rule on a `String` containing source code.
|
{-| The result of running a rule on a `String` containing source code.
|
||||||
@ -89,8 +89,8 @@ type Under
|
|||||||
| UnderExactly String Range
|
| UnderExactly String Range
|
||||||
|
|
||||||
|
|
||||||
type SourceCode
|
type alias SourceCode =
|
||||||
= SourceCode String
|
String
|
||||||
|
|
||||||
|
|
||||||
{-| Run a `Rule` on a `String` containing source code. You can then use
|
{-| Run a `Rule` on a `String` containing source code. You can then use
|
||||||
@ -110,8 +110,8 @@ run rule sourceCode =
|
|||||||
case lintSource [ ( Critical, rule ) ] sourceCode of
|
case lintSource [ ( Critical, rule ) ] sourceCode of
|
||||||
Ok errors ->
|
Ok errors ->
|
||||||
SuccessfulRun
|
SuccessfulRun
|
||||||
{ getCodeAtLocation = getCodeAtLocationInSourceCode (SourceCode sourceCode)
|
{ getCodeAtLocation = getCodeAtLocationInSourceCode sourceCode
|
||||||
, checkIfLocationIsAmbiguous = checkIfLocationIsAmbiguousInSourceCode (SourceCode sourceCode)
|
, checkIfLocationIsAmbiguous = checkIfLocationIsAmbiguousInSourceCode sourceCode
|
||||||
}
|
}
|
||||||
(List.map (\( _, error_ ) -> Rule.error error_.message error_.range) errors)
|
(List.map (\( _, error_ ) -> Rule.error error_.message error_.range) errors)
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ run rule sourceCode =
|
|||||||
ParseFailure
|
ParseFailure
|
||||||
|
|
||||||
|
|
||||||
{-| Assert that the rule reprted no errors. Note, this is equivalent to using [`expectErrors`](#expectErrors)
|
{-| Assert that the rule reported no errors. Note, this is equivalent to using [`expectErrors`](#expectErrors)
|
||||||
like `expectErrors []`.
|
like `expectErrors []`.
|
||||||
|
|
||||||
import Lint.Test exposing (LintResult)
|
import Lint.Test exposing (LintResult)
|
||||||
@ -146,15 +146,15 @@ expectNoErrors : LintResult -> Expectation
|
|||||||
expectNoErrors lintResult =
|
expectNoErrors lintResult =
|
||||||
case lintResult of
|
case lintResult of
|
||||||
ParseFailure ->
|
ParseFailure ->
|
||||||
Expect.fail parsingErrorMessage
|
Expect.fail ErrorMessage.parsingFailure
|
||||||
|
|
||||||
SuccessfulRun _ errors ->
|
SuccessfulRun _ errors ->
|
||||||
Expect.true
|
Expect.true
|
||||||
("I expected no errors but found:\n\n" ++ (List.map errorToString errors |> String.join "\n"))
|
(ErrorMessage.didNotExpectErrors errors)
|
||||||
(List.isEmpty errors)
|
(List.isEmpty errors)
|
||||||
|
|
||||||
|
|
||||||
{-| Assert that the rule reprted some errors, by specifying which one.
|
{-| Assert that the rule reported some errors, by specifying which one.
|
||||||
|
|
||||||
Assert which errors are reported using [`error`](#error). The test will fail if
|
Assert which errors are reported using [`error`](#error). The test will fail if
|
||||||
a different number of errors than expected are reported, or if the message or the
|
a different number of errors than expected are reported, or if the message or the
|
||||||
@ -193,7 +193,7 @@ expectErrors : List ExpectedError -> LintResult -> Expectation
|
|||||||
expectErrors expectedErrors lintResult =
|
expectErrors expectedErrors lintResult =
|
||||||
case lintResult of
|
case lintResult of
|
||||||
ParseFailure ->
|
ParseFailure ->
|
||||||
Expect.fail parsingErrorMessage
|
Expect.fail ErrorMessage.parsingFailure
|
||||||
|
|
||||||
SuccessfulRun codeInspector errors ->
|
SuccessfulRun codeInspector errors ->
|
||||||
checkAllErrorsMatch codeInspector expectedErrors errors
|
checkAllErrorsMatch codeInspector expectedErrors errors
|
||||||
@ -235,16 +235,6 @@ error input =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getUnder : ExpectedError -> String
|
|
||||||
getUnder (ExpectedError expectedError) =
|
|
||||||
case expectedError.under of
|
|
||||||
Under str ->
|
|
||||||
str
|
|
||||||
|
|
||||||
UnderExactly str _ ->
|
|
||||||
str
|
|
||||||
|
|
||||||
|
|
||||||
{-| Precise the exact position where the error should be shown to the user. This
|
{-| Precise the exact position where the error should be shown to the user. This
|
||||||
is only necessary when the `under` field is ambiguous.
|
is only necessary when the `under` field is ambiguous.
|
||||||
|
|
||||||
@ -283,60 +273,18 @@ atExactly range ((ExpectedError expectedError_) as expectedError) =
|
|||||||
ExpectedError { expectedError_ | under = UnderExactly (getUnder expectedError) range }
|
ExpectedError { expectedError_ | under = UnderExactly (getUnder expectedError) range }
|
||||||
|
|
||||||
|
|
||||||
checkAllErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> Expectation
|
getUnder : ExpectedError -> String
|
||||||
checkAllErrorsMatch codeInspector expectedErrors errors =
|
getUnder (ExpectedError expectedError) =
|
||||||
checkErrorsMatch codeInspector expectedErrors errors
|
case expectedError.under of
|
||||||
|> List.reverse
|
Under str ->
|
||||||
|> (\expectations -> Expect.all expectations ())
|
str
|
||||||
|
|
||||||
|
UnderExactly str _ ->
|
||||||
checkErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> List (() -> Expectation)
|
str
|
||||||
checkErrorsMatch codeInspector expectedErrors errors =
|
|
||||||
case ( expectedErrors, errors ) of
|
|
||||||
( [], [] ) ->
|
|
||||||
[ always Expect.pass ]
|
|
||||||
|
|
||||||
( expected :: restOfExpectedErrors, error_ :: restOfErrors ) ->
|
|
||||||
checkErrorMatch codeInspector expected error_ :: checkErrorsMatch codeInspector restOfExpectedErrors restOfErrors
|
|
||||||
|
|
||||||
( expected :: restOfExpectedErrors, [] ) ->
|
|
||||||
[ always <| Expect.fail <| notEnoughErrors expected restOfExpectedErrors ]
|
|
||||||
|
|
||||||
( [], error_ :: restOfErrors ) ->
|
|
||||||
[ always <| Expect.fail <| tooManyErrors error_ restOfErrors ]
|
|
||||||
|
|
||||||
|
|
||||||
checkErrorMatch : CodeInspector -> ExpectedError -> Error -> (() -> Expectation)
|
|
||||||
checkErrorMatch codeInspector ((ExpectedError expectedError_) as expectedError) error_ =
|
|
||||||
Expect.all
|
|
||||||
[ always <| Expect.true (messageMismatchError expectedError error_) (expectedError_.message == Rule.errorMessage error_)
|
|
||||||
, checkMessageAppearsUnder codeInspector error_ expectedError
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
checkMessageAppearsUnder : CodeInspector -> Error -> ExpectedError -> (() -> Expectation)
|
|
||||||
checkMessageAppearsUnder codeInspector error_ (ExpectedError expectedError) =
|
|
||||||
case codeInspector.getCodeAtLocation (Rule.errorRange error_) of
|
|
||||||
Just codeAtLocation ->
|
|
||||||
case expectedError.under of
|
|
||||||
Under under ->
|
|
||||||
Expect.all
|
|
||||||
[ always <| Expect.true (underMismatchError error_ under codeAtLocation) (codeAtLocation == under)
|
|
||||||
, always <| codeInspector.checkIfLocationIsAmbiguous error_ under
|
|
||||||
]
|
|
||||||
|
|
||||||
UnderExactly under range ->
|
|
||||||
Expect.all
|
|
||||||
[ always <| Expect.true (underMismatchError error_ under codeAtLocation) (codeAtLocation == under)
|
|
||||||
, always <| Expect.true (wrongLocationError error_ range under) (Rule.errorRange error_ == range)
|
|
||||||
]
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
always <| Expect.fail impossibleStateError
|
|
||||||
|
|
||||||
|
|
||||||
getCodeAtLocationInSourceCode : SourceCode -> Range -> Maybe String
|
getCodeAtLocationInSourceCode : SourceCode -> Range -> Maybe String
|
||||||
getCodeAtLocationInSourceCode (SourceCode sourceCode) =
|
getCodeAtLocationInSourceCode sourceCode =
|
||||||
let
|
let
|
||||||
lines : Array String
|
lines : Array String
|
||||||
lines =
|
lines =
|
||||||
@ -372,233 +320,91 @@ getCodeAtLocationInSourceCode (SourceCode sourceCode) =
|
|||||||
|> Just
|
|> Just
|
||||||
|
|
||||||
|
|
||||||
formatSourceCode : String -> String
|
|
||||||
formatSourceCode string =
|
|
||||||
let
|
|
||||||
lines =
|
|
||||||
String.lines string
|
|
||||||
in
|
|
||||||
if List.length lines == 1 then
|
|
||||||
"`" ++ string ++ "`"
|
|
||||||
|
|
||||||
else
|
|
||||||
lines
|
|
||||||
|> List.map (\str -> " " ++ str)
|
|
||||||
|> String.join "\n"
|
|
||||||
|> (\str -> "\n\n```\n" ++ str ++ "\n```")
|
|
||||||
|
|
||||||
|
|
||||||
checkIfLocationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> Expectation
|
checkIfLocationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> Expectation
|
||||||
checkIfLocationIsAmbiguousInSourceCode ((SourceCode sourceCodeContent) as sourceCode) error_ under =
|
checkIfLocationIsAmbiguousInSourceCode sourceCode error_ under =
|
||||||
let
|
let
|
||||||
occurrencesInSourceCode : List Int
|
occurrencesInSourceCode : List Int
|
||||||
occurrencesInSourceCode =
|
occurrencesInSourceCode =
|
||||||
String.indexes under sourceCodeContent
|
String.indexes under sourceCode
|
||||||
in
|
in
|
||||||
Expect.true
|
Expect.true
|
||||||
(locationIsAmbiguousInSourceCodeError sourceCode error_ under occurrencesInSourceCode)
|
(ErrorMessage.locationIsAmbiguousInSourceCode sourceCode error_ under occurrencesInSourceCode)
|
||||||
(List.length occurrencesInSourceCode == 1)
|
(List.length occurrencesInSourceCode == 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ERROR MESSAGES
|
-- RUNNING THE CHECKS
|
||||||
|
|
||||||
|
|
||||||
parsingErrorMessage : String
|
checkAllErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> Expectation
|
||||||
parsingErrorMessage =
|
checkAllErrorsMatch codeInspector expectedErrors errors =
|
||||||
"""I could not parse the test source code, because it was not syntactically valid Elm code.
|
checkErrorsMatch codeInspector expectedErrors errors
|
||||||
|
|> List.reverse
|
||||||
Maybe you forgot to add the module definition at the top, like:
|
|> (\expectations -> Expect.all expectations ())
|
||||||
|
|
||||||
module A exposing (..)"""
|
|
||||||
|
|
||||||
|
|
||||||
messageMismatchError : ExpectedError -> Error -> String
|
checkErrorsMatch : CodeInspector -> List ExpectedError -> List Error -> List (() -> Expectation)
|
||||||
messageMismatchError (ExpectedError expectedError) error_ =
|
checkErrorsMatch codeInspector expectedErrors errors =
|
||||||
"""I was looking for the error with the following message:
|
case ( expectedErrors, errors ) of
|
||||||
|
( [], [] ) ->
|
||||||
|
[ always Expect.pass ]
|
||||||
|
|
||||||
`""" ++ expectedError.message ++ """`
|
( expected :: restOfExpectedErrors, error_ :: restOfErrors ) ->
|
||||||
|
checkErrorMatch codeInspector expected error_ :: checkErrorsMatch codeInspector restOfExpectedErrors restOfErrors
|
||||||
|
|
||||||
but I found the following error message:
|
( expected :: restOfExpectedErrors, [] ) ->
|
||||||
|
[ always <| Expect.fail <| ErrorMessage.expectedMoreErrors <| List.map extractExpectedErrorData (expected :: restOfExpectedErrors) ]
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ "`"
|
( [], error_ :: restOfErrors ) ->
|
||||||
|
[ always <| Expect.fail <| ErrorMessage.tooManyErrors (error_ :: restOfErrors) ]
|
||||||
|
|
||||||
|
|
||||||
wrongLocationError : Error -> Range -> String -> String
|
checkErrorMatch : CodeInspector -> ExpectedError -> Error -> (() -> Expectation)
|
||||||
wrongLocationError error_ range under =
|
checkErrorMatch codeInspector ((ExpectedError expectedError_) as expectedError) error_ =
|
||||||
"""I was looking for the error with the following message:
|
Expect.all
|
||||||
|
[ \_ ->
|
||||||
`""" ++ Rule.errorMessage error_ ++ """`
|
(expectedError_.message == Rule.errorMessage error_)
|
||||||
|
|> Expect.true
|
||||||
under the following code:
|
(ErrorMessage.messageMismatch
|
||||||
|
(extractExpectedErrorData expectedError)
|
||||||
""" ++ formatSourceCode under ++ """
|
error_
|
||||||
|
)
|
||||||
and I found it, but the exact location you specified is not the one I found. I was expecting the error at:
|
, checkMessageAppearsUnder codeInspector error_ expectedError
|
||||||
|
]
|
||||||
""" ++ rangeAsString range ++ """
|
|
||||||
|
|
||||||
but I found it at:
|
|
||||||
|
|
||||||
""" ++ rangeAsString (Rule.errorRange error_)
|
|
||||||
|
|
||||||
|
|
||||||
underMismatchError : Error -> String -> String -> String
|
checkMessageAppearsUnder : CodeInspector -> Error -> ExpectedError -> (() -> Expectation)
|
||||||
underMismatchError error_ under codeAtLocation =
|
checkMessageAppearsUnder codeInspector error_ (ExpectedError expectedError) =
|
||||||
"""I found an error with the right message, but at the wrong location:
|
case codeInspector.getCodeAtLocation (Rule.errorRange error_) of
|
||||||
|
Just codeAtLocation ->
|
||||||
|
case expectedError.under of
|
||||||
|
Under under ->
|
||||||
|
Expect.all
|
||||||
|
[ always <|
|
||||||
|
Expect.true
|
||||||
|
(ErrorMessage.underMismatch error_ { under = under, codeAtLocation = codeAtLocation })
|
||||||
|
(codeAtLocation == under)
|
||||||
|
, always <| codeInspector.checkIfLocationIsAmbiguous error_ under
|
||||||
|
]
|
||||||
|
|
||||||
Message: `""" ++ Rule.errorMessage error_ ++ """`
|
UnderExactly under range ->
|
||||||
|
Expect.all
|
||||||
|
[ always <|
|
||||||
|
Expect.true
|
||||||
|
(ErrorMessage.underMismatch error_ { under = under, codeAtLocation = codeAtLocation })
|
||||||
|
(codeAtLocation == under)
|
||||||
|
, always <|
|
||||||
|
Expect.true
|
||||||
|
(ErrorMessage.wrongLocation error_ range under)
|
||||||
|
(Rule.errorRange error_ == range)
|
||||||
|
]
|
||||||
|
|
||||||
I saw it under: """ ++ formatSourceCode codeAtLocation ++ """
|
Nothing ->
|
||||||
|
always <| Expect.fail ErrorMessage.impossibleState
|
||||||
But I expected to see it under: """ ++ formatSourceCode under
|
|
||||||
|
|
||||||
|
|
||||||
listOccurrencesAsLocations : SourceCode -> String -> List Int -> String
|
extractExpectedErrorData : ExpectedError -> ErrorMessage.ExpectedErrorData
|
||||||
listOccurrencesAsLocations sourceCode under occurrences =
|
extractExpectedErrorData ((ExpectedError expectedErrorContent) as expectedError) =
|
||||||
occurrences
|
{ message = expectedErrorContent.message
|
||||||
|> List.map
|
, under = getUnder expectedError
|
||||||
(\occurrence ->
|
|
||||||
occurrence
|
|
||||||
|> positionAsRange sourceCode under
|
|
||||||
|> rangeAsString
|
|
||||||
|> (++) " - "
|
|
||||||
)
|
|
||||||
|> String.join "\n"
|
|
||||||
|
|
||||||
|
|
||||||
positionAsRange : SourceCode -> String -> Int -> Range
|
|
||||||
positionAsRange (SourceCode sourceCode) under position =
|
|
||||||
let
|
|
||||||
linesBeforeAndIncludingPosition : List String
|
|
||||||
linesBeforeAndIncludingPosition =
|
|
||||||
sourceCode
|
|
||||||
|> String.slice 0 position
|
|
||||||
|> String.lines
|
|
||||||
|
|
||||||
startRow : Int
|
|
||||||
startRow =
|
|
||||||
List.length linesBeforeAndIncludingPosition
|
|
||||||
|
|
||||||
startColumn : Int
|
|
||||||
startColumn =
|
|
||||||
linesBeforeAndIncludingPosition
|
|
||||||
|> List.Extra.last
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|> String.length
|
|
||||||
|> (+) 1
|
|
||||||
|
|
||||||
linesInUnder : List String
|
|
||||||
linesInUnder =
|
|
||||||
String.lines under
|
|
||||||
|
|
||||||
endRow : Int
|
|
||||||
endRow =
|
|
||||||
startRow + List.length linesInUnder - 1
|
|
||||||
|
|
||||||
endColumn : Int
|
|
||||||
endColumn =
|
|
||||||
if startRow == endRow then
|
|
||||||
startColumn + String.length under
|
|
||||||
|
|
||||||
else
|
|
||||||
linesInUnder
|
|
||||||
|> Debug.log "linesInUnder"
|
|
||||||
|> List.Extra.last
|
|
||||||
|> Debug.log "last"
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|> String.length
|
|
||||||
|> (+) 1
|
|
||||||
in
|
|
||||||
{ start =
|
|
||||||
{ row = startRow
|
|
||||||
, column = startColumn
|
|
||||||
}
|
|
||||||
, end =
|
|
||||||
{ row = endRow
|
|
||||||
, column = endColumn
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
errorToString : Error -> String
|
|
||||||
errorToString error_ =
|
|
||||||
"- \"" ++ Rule.errorMessage error_ ++ "\" at " ++ rangeAsString (Rule.errorRange error_)
|
|
||||||
|
|
||||||
|
|
||||||
rangeAsString : Range -> String
|
|
||||||
rangeAsString { start, end } =
|
|
||||||
"{ start = { row = " ++ String.fromInt start.row ++ ", column = " ++ String.fromInt start.column ++ " }, end = { row = " ++ String.fromInt end.row ++ ", column = " ++ String.fromInt end.column ++ " } }"
|
|
||||||
|
|
||||||
|
|
||||||
notEnoughErrors : ExpectedError -> List ExpectedError -> String
|
|
||||||
notEnoughErrors expected restOfExpectedErrors =
|
|
||||||
let
|
|
||||||
numberOfErrors : Int
|
|
||||||
numberOfErrors =
|
|
||||||
List.length restOfExpectedErrors + 1
|
|
||||||
in
|
|
||||||
"I expected to see "
|
|
||||||
++ String.fromInt numberOfErrors
|
|
||||||
++ " more "
|
|
||||||
++ pluralizeErrors numberOfErrors
|
|
||||||
++ ":\n\n"
|
|
||||||
++ (List.map expectedErrorToString (expected :: restOfExpectedErrors) |> String.join "\n")
|
|
||||||
|
|
||||||
|
|
||||||
wrapInQuotes : String -> String
|
|
||||||
wrapInQuotes string =
|
|
||||||
"\"" ++ string ++ "\""
|
|
||||||
|
|
||||||
|
|
||||||
tooManyErrors : Error -> List Error -> String
|
|
||||||
tooManyErrors error_ restOfErrors =
|
|
||||||
let
|
|
||||||
numberOfErrors : Int
|
|
||||||
numberOfErrors =
|
|
||||||
List.length restOfErrors + 1
|
|
||||||
in
|
|
||||||
"I found "
|
|
||||||
++ String.fromInt numberOfErrors
|
|
||||||
++ " "
|
|
||||||
++ pluralizeErrors numberOfErrors
|
|
||||||
++ " too many:\n"
|
|
||||||
++ (List.map errorToString (error_ :: restOfErrors) |> String.join "\n")
|
|
||||||
|
|
||||||
|
|
||||||
locationIsAmbiguousInSourceCodeError : SourceCode -> Error -> String -> List Int -> String
|
|
||||||
locationIsAmbiguousInSourceCodeError sourceCode error_ under occurrencesInSourceCode =
|
|
||||||
"""Your test passes, but where the message appears is ambiguous.
|
|
||||||
|
|
||||||
You are looking for the following error message:
|
|
||||||
|
|
||||||
`""" ++ Rule.errorMessage error_ ++ """`
|
|
||||||
|
|
||||||
and expecting to see it under:
|
|
||||||
|
|
||||||
""" ++ formatSourceCode under ++ """
|
|
||||||
|
|
||||||
I found """ ++ String.fromInt (List.length occurrencesInSourceCode) ++ """ locations where that code appeared. Please use `Lint.Rule.atExactly` to make the part you were targetting unambiguous.
|
|
||||||
|
|
||||||
Tip: I found them at:
|
|
||||||
""" ++ listOccurrencesAsLocations sourceCode under occurrencesInSourceCode
|
|
||||||
|
|
||||||
|
|
||||||
impossibleStateError : String
|
|
||||||
impossibleStateError =
|
|
||||||
"Oh no! I'm in an impossible state. I found an error at a location that I could not find back. Please let me know and give me an SSCCE (http://sscce.org/) here: https://github.com/jfmengels/elm-lint/issues."
|
|
||||||
|
|
||||||
|
|
||||||
pluralizeErrors : Int -> String
|
|
||||||
pluralizeErrors n =
|
|
||||||
case n of
|
|
||||||
1 ->
|
|
||||||
"error"
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
|
|
||||||
expectedErrorToString : ExpectedError -> String
|
|
||||||
expectedErrorToString (ExpectedError expectedError) =
|
|
||||||
"- " ++ wrapInQuotes expectedError.message
|
|
||||||
|
270
src/Lint/Test/ErrorMessage.elm
Normal file
270
src/Lint/Test/ErrorMessage.elm
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
module Lint.Test.ErrorMessage exposing
|
||||||
|
( ExpectedErrorData
|
||||||
|
, parsingFailure, messageMismatch, wrongLocation, didNotExpectErrors
|
||||||
|
, underMismatch, expectedMoreErrors, tooManyErrors, locationIsAmbiguousInSourceCode
|
||||||
|
, impossibleState
|
||||||
|
)
|
||||||
|
|
||||||
|
{-| Error messages for the `Lint.Test` module.
|
||||||
|
|
||||||
|
|
||||||
|
# Error messages
|
||||||
|
|
||||||
|
@docs ExpectedErrorData
|
||||||
|
@docs parsingFailure, messageMismatch, wrongLocation, didNotExpectErrors
|
||||||
|
@docs underMismatch, expectedMoreErrors, tooManyErrors, locationIsAmbiguousInSourceCode
|
||||||
|
@docs impossibleState
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Elm.Syntax.Range exposing (Range)
|
||||||
|
import Lint.Rule as Rule exposing (Error, Rule)
|
||||||
|
import List.Extra
|
||||||
|
|
||||||
|
|
||||||
|
{-| An expectation for an error. Use [`error`](#error) to create one.
|
||||||
|
-}
|
||||||
|
type alias ExpectedErrorData =
|
||||||
|
{ message : String
|
||||||
|
, under : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SourceCode =
|
||||||
|
String
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- ERROR MESSAGES
|
||||||
|
|
||||||
|
|
||||||
|
didNotExpectErrors : List Error -> String
|
||||||
|
didNotExpectErrors errors =
|
||||||
|
"""I expected no errors but found:
|
||||||
|
|
||||||
|
""" ++ (List.map errorToString errors |> String.join "\n ")
|
||||||
|
|
||||||
|
|
||||||
|
parsingFailure : String
|
||||||
|
parsingFailure =
|
||||||
|
"""I could not parse the test source code, because it was not syntactically valid Elm code.
|
||||||
|
|
||||||
|
Maybe you forgot to add the module definition at the top, like:
|
||||||
|
|
||||||
|
`module A exposing (..)`"""
|
||||||
|
|
||||||
|
|
||||||
|
messageMismatch : ExpectedErrorData -> Error -> String
|
||||||
|
messageMismatch expectedError error_ =
|
||||||
|
"""I was looking for the error with the following message:
|
||||||
|
|
||||||
|
`""" ++ expectedError.message ++ """`
|
||||||
|
|
||||||
|
but I found the following error message:
|
||||||
|
|
||||||
|
`""" ++ Rule.errorMessage error_ ++ "`"
|
||||||
|
|
||||||
|
|
||||||
|
underMismatch : Error -> { under : String, codeAtLocation : String } -> String
|
||||||
|
underMismatch error_ { under, codeAtLocation } =
|
||||||
|
"""I found an error with the following message:
|
||||||
|
|
||||||
|
`""" ++ Rule.errorMessage error_ ++ """`
|
||||||
|
|
||||||
|
which I was expecting, but I found it under:
|
||||||
|
|
||||||
|
""" ++ formatSourceCode codeAtLocation ++ """
|
||||||
|
|
||||||
|
when I was expecting it under:
|
||||||
|
|
||||||
|
""" ++ formatSourceCode under ++ """
|
||||||
|
|
||||||
|
Hint: Maybe you're passing the `Range` of a wrong node when calling `Rule.error`"""
|
||||||
|
|
||||||
|
|
||||||
|
wrongLocation : Error -> Range -> String -> String
|
||||||
|
wrongLocation error_ range under =
|
||||||
|
"""I was looking for the error with the following message:
|
||||||
|
|
||||||
|
`""" ++ Rule.errorMessage error_ ++ """`
|
||||||
|
|
||||||
|
under the following code:
|
||||||
|
|
||||||
|
""" ++ formatSourceCode under ++ """
|
||||||
|
|
||||||
|
and I found it, but the exact location you specified is not the one I found. I was expecting the error at:
|
||||||
|
|
||||||
|
""" ++ rangeAsString range ++ """
|
||||||
|
|
||||||
|
but I found it at:
|
||||||
|
|
||||||
|
""" ++ rangeAsString (Rule.errorRange error_)
|
||||||
|
|
||||||
|
|
||||||
|
listOccurrencesAsLocations : SourceCode -> String -> List Int -> String
|
||||||
|
listOccurrencesAsLocations sourceCode under occurrences =
|
||||||
|
occurrences
|
||||||
|
|> List.map
|
||||||
|
(\occurrence ->
|
||||||
|
occurrence
|
||||||
|
|> positionAsRange sourceCode under
|
||||||
|
|> rangeAsString
|
||||||
|
|> (++) " - "
|
||||||
|
)
|
||||||
|
|> String.join "\n"
|
||||||
|
|
||||||
|
|
||||||
|
positionAsRange : SourceCode -> String -> Int -> Range
|
||||||
|
positionAsRange sourceCode under position =
|
||||||
|
let
|
||||||
|
linesBeforeAndIncludingPosition : List String
|
||||||
|
linesBeforeAndIncludingPosition =
|
||||||
|
sourceCode
|
||||||
|
|> String.slice 0 position
|
||||||
|
|> String.lines
|
||||||
|
|
||||||
|
startRow : Int
|
||||||
|
startRow =
|
||||||
|
List.length linesBeforeAndIncludingPosition
|
||||||
|
|
||||||
|
startColumn : Int
|
||||||
|
startColumn =
|
||||||
|
linesBeforeAndIncludingPosition
|
||||||
|
|> List.Extra.last
|
||||||
|
|> Maybe.withDefault ""
|
||||||
|
|> String.length
|
||||||
|
|> (+) 1
|
||||||
|
|
||||||
|
linesInUnder : List String
|
||||||
|
linesInUnder =
|
||||||
|
String.lines under
|
||||||
|
|
||||||
|
endRow : Int
|
||||||
|
endRow =
|
||||||
|
startRow + List.length linesInUnder - 1
|
||||||
|
|
||||||
|
endColumn : Int
|
||||||
|
endColumn =
|
||||||
|
if startRow == endRow then
|
||||||
|
startColumn + String.length under
|
||||||
|
|
||||||
|
else
|
||||||
|
linesInUnder
|
||||||
|
|> List.Extra.last
|
||||||
|
|> Maybe.withDefault ""
|
||||||
|
|> String.length
|
||||||
|
|> (+) 1
|
||||||
|
in
|
||||||
|
{ start =
|
||||||
|
{ row = startRow
|
||||||
|
, column = startColumn
|
||||||
|
}
|
||||||
|
, end =
|
||||||
|
{ row = endRow
|
||||||
|
, column = endColumn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
errorToString : Error -> String
|
||||||
|
errorToString error_ =
|
||||||
|
"- \"" ++ Rule.errorMessage error_ ++ "\" at " ++ rangeAsString (Rule.errorRange error_)
|
||||||
|
|
||||||
|
|
||||||
|
rangeAsString : Range -> String
|
||||||
|
rangeAsString { start, end } =
|
||||||
|
"{ start = { row = " ++ String.fromInt start.row ++ ", column = " ++ String.fromInt start.column ++ " }, end = { row = " ++ String.fromInt end.row ++ ", column = " ++ String.fromInt end.column ++ " } }"
|
||||||
|
|
||||||
|
|
||||||
|
expectedMoreErrors : List ExpectedErrorData -> String
|
||||||
|
expectedMoreErrors missingExpectedErrors =
|
||||||
|
let
|
||||||
|
numberOfErrors : Int
|
||||||
|
numberOfErrors =
|
||||||
|
List.length missingExpectedErrors
|
||||||
|
in
|
||||||
|
"I expected to see "
|
||||||
|
++ String.fromInt numberOfErrors
|
||||||
|
++ " more "
|
||||||
|
++ pluralizeErrors numberOfErrors
|
||||||
|
++ ":\n\n"
|
||||||
|
++ (missingExpectedErrors
|
||||||
|
|> List.map expectedErrorToString
|
||||||
|
|> String.join "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
wrapInQuotes : String -> String
|
||||||
|
wrapInQuotes string =
|
||||||
|
"\"" ++ string ++ "\""
|
||||||
|
|
||||||
|
|
||||||
|
tooManyErrors : List Error -> String
|
||||||
|
tooManyErrors extraErrors =
|
||||||
|
let
|
||||||
|
numberOfErrors : Int
|
||||||
|
numberOfErrors =
|
||||||
|
List.length extraErrors
|
||||||
|
in
|
||||||
|
"I found "
|
||||||
|
++ String.fromInt numberOfErrors
|
||||||
|
++ " "
|
||||||
|
++ pluralizeErrors numberOfErrors
|
||||||
|
++ " too many:\n\n"
|
||||||
|
++ (extraErrors
|
||||||
|
|> List.map errorToString
|
||||||
|
|> String.join "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
locationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> List Int -> String
|
||||||
|
locationIsAmbiguousInSourceCode sourceCode error_ under occurrencesInSourceCode =
|
||||||
|
"""Your test passes, but where the message appears is ambiguous.
|
||||||
|
|
||||||
|
You are looking for the following error message:
|
||||||
|
|
||||||
|
`""" ++ Rule.errorMessage error_ ++ """`
|
||||||
|
|
||||||
|
and expecting to see it under:
|
||||||
|
|
||||||
|
""" ++ formatSourceCode under ++ """
|
||||||
|
|
||||||
|
I found """ ++ String.fromInt (List.length occurrencesInSourceCode) ++ """ locations where that code appeared. Please use `Lint.Rule.atExactly` to make the part you were targetting unambiguous.
|
||||||
|
|
||||||
|
Tip: I found them at:
|
||||||
|
""" ++ listOccurrencesAsLocations sourceCode under occurrencesInSourceCode
|
||||||
|
|
||||||
|
|
||||||
|
impossibleState : String
|
||||||
|
impossibleState =
|
||||||
|
"Oh no! I'm in an impossible state. I found an error at a location that I could not find back. Please let me know and give me an SSCCE (http://sscce.org/) here: https://github.com/jfmengels/elm-lint/issues."
|
||||||
|
|
||||||
|
|
||||||
|
pluralizeErrors : Int -> String
|
||||||
|
pluralizeErrors n =
|
||||||
|
if n == 1 then
|
||||||
|
"error"
|
||||||
|
|
||||||
|
else
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
|
||||||
|
expectedErrorToString : ExpectedErrorData -> String
|
||||||
|
expectedErrorToString expectedError =
|
||||||
|
"- " ++ wrapInQuotes expectedError.message
|
||||||
|
|
||||||
|
|
||||||
|
formatSourceCode : String -> String
|
||||||
|
formatSourceCode string =
|
||||||
|
let
|
||||||
|
lines =
|
||||||
|
String.lines string
|
||||||
|
in
|
||||||
|
if List.length lines == 1 then
|
||||||
|
"`" ++ string ++ "`"
|
||||||
|
|
||||||
|
else
|
||||||
|
lines
|
||||||
|
|> List.map (\str -> " " ++ str)
|
||||||
|
|> String.join "\n"
|
||||||
|
|> (\str -> "```\n" ++ str ++ "\n ```")
|
@ -2,29 +2,29 @@ module ErrorMessageTest exposing (all)
|
|||||||
|
|
||||||
import Elm.Syntax.Range exposing (Range)
|
import Elm.Syntax.Range exposing (Range)
|
||||||
import Expect
|
import Expect
|
||||||
import Lint.Internal.Test exposing (ExpectedError, LintResult)
|
|
||||||
import Lint.Rule as Rule exposing (Error)
|
import Lint.Rule as Rule exposing (Error)
|
||||||
|
import Lint.Test.ErrorMessage as ErrorMessage exposing (ExpectedErrorData)
|
||||||
import Test exposing (Test, describe, test)
|
import Test exposing (Test, describe, test)
|
||||||
|
|
||||||
|
|
||||||
all : Test
|
all : Test
|
||||||
all =
|
all =
|
||||||
describe "Test.ErrorMessage"
|
describe "Test.ErrorMessage"
|
||||||
[ parsingErrorMessageTest
|
[ parsingFailureTest
|
||||||
, didNotExpectErrorsTest
|
, didNotExpectErrorsTest
|
||||||
, messageMismatchErrorTest
|
, messageMismatchTest
|
||||||
, underMismatchErrorTest
|
, underMismatchTest
|
||||||
, wrongLocationErrorTest
|
, wrongLocationTest
|
||||||
, notEnoughErrorsTest
|
, expectedMoreErrorsTest
|
||||||
, tooManyErrorsTest
|
, tooManyErrorsTest
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
parsingErrorMessageTest : Test
|
parsingFailureTest : Test
|
||||||
parsingErrorMessageTest =
|
parsingFailureTest =
|
||||||
test "parsingErrorMessage" <|
|
test "parsingFailure" <|
|
||||||
\() ->
|
\() ->
|
||||||
Lint.Internal.Test.parsingErrorMessage
|
ErrorMessage.parsingFailure
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I could not parse the test source code, because it was not syntactically valid Elm code.
|
I could not parse the test source code, because it was not syntactically valid Elm code.
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ didNotExpectErrorsTest =
|
|||||||
, Rule.error "Some other error" dummyRange
|
, Rule.error "Some other error" dummyRange
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.didNotExpectErrors errors
|
ErrorMessage.didNotExpectErrors errors
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I expected no errors but found:
|
I expected no errors but found:
|
||||||
|
|
||||||
@ -53,23 +53,22 @@ I expected no errors but found:
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
messageMismatchErrorTest : Test
|
messageMismatchTest : Test
|
||||||
messageMismatchErrorTest =
|
messageMismatchTest =
|
||||||
test "messageMismatchError" <|
|
test "messageMismatch" <|
|
||||||
\() ->
|
\() ->
|
||||||
let
|
let
|
||||||
expectedError : ExpectedError
|
expectedError : ExpectedErrorData
|
||||||
expectedError =
|
expectedError =
|
||||||
Lint.Internal.Test.error
|
{ message = "Forbidden use of Debug"
|
||||||
{ message = "Forbidden use of Debug"
|
, under = "Debug.log"
|
||||||
, under = "Debug.log"
|
}
|
||||||
}
|
|
||||||
|
|
||||||
error : Error
|
error : Error
|
||||||
error =
|
error =
|
||||||
Rule.error "Forbidden use of Debu" dummyRange
|
Rule.error "Forbidden use of Debu" dummyRange
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.messageMismatchError expectedError error
|
ErrorMessage.messageMismatch expectedError error
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I was looking for the error with the following message:
|
I was looking for the error with the following message:
|
||||||
|
|
||||||
@ -80,9 +79,9 @@ but I found the following error message:
|
|||||||
`Forbidden use of Debu`""")
|
`Forbidden use of Debu`""")
|
||||||
|
|
||||||
|
|
||||||
underMismatchErrorTest : Test
|
underMismatchTest : Test
|
||||||
underMismatchErrorTest =
|
underMismatchTest =
|
||||||
describe "underMismatchError"
|
describe "underMismatch"
|
||||||
[ test "with single-line extracts" <|
|
[ test "with single-line extracts" <|
|
||||||
\() ->
|
\() ->
|
||||||
let
|
let
|
||||||
@ -90,7 +89,7 @@ underMismatchErrorTest =
|
|||||||
error =
|
error =
|
||||||
Rule.error "Some error" dummyRange
|
Rule.error "Some error" dummyRange
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.underMismatchError
|
ErrorMessage.underMismatch
|
||||||
error
|
error
|
||||||
{ under = "abcd"
|
{ under = "abcd"
|
||||||
, codeAtLocation = "abcd = 1"
|
, codeAtLocation = "abcd = 1"
|
||||||
@ -116,7 +115,7 @@ Hint: Maybe you're passing the `Range` of a wrong node when calling `Rule.error`
|
|||||||
error =
|
error =
|
||||||
Rule.error "Some other error" dummyRange
|
Rule.error "Some other error" dummyRange
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.underMismatchError
|
ErrorMessage.underMismatch
|
||||||
error
|
error
|
||||||
{ under = "abcd =\n 1\n + 2"
|
{ under = "abcd =\n 1\n + 2"
|
||||||
, codeAtLocation = "abcd =\n 1"
|
, codeAtLocation = "abcd =\n 1"
|
||||||
@ -145,9 +144,9 @@ Hint: Maybe you're passing the `Range` of a wrong node when calling `Rule.error`
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
wrongLocationErrorTest : Test
|
wrongLocationTest : Test
|
||||||
wrongLocationErrorTest =
|
wrongLocationTest =
|
||||||
describe "wrongLocationError"
|
describe "wrongLocation"
|
||||||
[ test "with single-line extracts" <|
|
[ test "with single-line extracts" <|
|
||||||
\() ->
|
\() ->
|
||||||
let
|
let
|
||||||
@ -157,7 +156,7 @@ wrongLocationErrorTest =
|
|||||||
"Some error"
|
"Some error"
|
||||||
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.wrongLocationError
|
ErrorMessage.wrongLocation
|
||||||
error
|
error
|
||||||
{ start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
{ start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
||||||
"abcd"
|
"abcd"
|
||||||
@ -187,7 +186,7 @@ but I found it at:
|
|||||||
"Some other error"
|
"Some other error"
|
||||||
{ start = { row = 4, column = 1 }, end = { row = 5, column = 3 } }
|
{ start = { row = 4, column = 1 }, end = { row = 5, column = 3 } }
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.wrongLocationError
|
ErrorMessage.wrongLocation
|
||||||
error
|
error
|
||||||
{ start = { row = 2, column = 1 }, end = { row = 3, column = 3 } }
|
{ start = { row = 2, column = 1 }, end = { row = 3, column = 3 } }
|
||||||
"abcd =\n 1"
|
"abcd =\n 1"
|
||||||
@ -214,24 +213,22 @@ but I found it at:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
notEnoughErrorsTest : Test
|
expectedMoreErrorsTest : Test
|
||||||
notEnoughErrorsTest =
|
expectedMoreErrorsTest =
|
||||||
test "notEnoughErrors" <|
|
test "expectedMoreErrors" <|
|
||||||
\() ->
|
\() ->
|
||||||
let
|
let
|
||||||
missingErrors : List ExpectedError
|
missingErrors : List ExpectedErrorData
|
||||||
missingErrors =
|
missingErrors =
|
||||||
[ Lint.Internal.Test.error
|
[ { message = "Forbidden use of Debug"
|
||||||
{ message = "Forbidden use of Debug"
|
, under = "Debug.log"
|
||||||
, under = "Debug.log"
|
}
|
||||||
}
|
, { message = "Forbidden use of Debug"
|
||||||
, Lint.Internal.Test.error
|
, under = "Debug.log"
|
||||||
{ message = "Forbidden use of Debug"
|
}
|
||||||
, under = "Debug.log"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.notEnoughErrors missingErrors
|
ErrorMessage.expectedMoreErrors missingErrors
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I expected to see 2 more errors:
|
I expected to see 2 more errors:
|
||||||
|
|
||||||
@ -253,7 +250,7 @@ tooManyErrorsTest =
|
|||||||
{ start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
{ start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.tooManyErrors extraErrors
|
ErrorMessage.tooManyErrors extraErrors
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I found 1 error too many:
|
I found 1 error too many:
|
||||||
|
|
||||||
@ -272,7 +269,7 @@ I found 1 error too many:
|
|||||||
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.tooManyErrors extraErrors
|
ErrorMessage.tooManyErrors extraErrors
|
||||||
|> Expect.equal (String.trim """
|
|> Expect.equal (String.trim """
|
||||||
I found 2 errors too many:
|
I found 2 errors too many:
|
||||||
|
|
||||||
@ -282,9 +279,9 @@ I found 2 errors too many:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
locationIsAmbiguousInSourceCodeErrorTest : Test
|
locationIsAmbiguousInSourceCodeTest : Test
|
||||||
locationIsAmbiguousInSourceCodeErrorTest =
|
locationIsAmbiguousInSourceCodeTest =
|
||||||
describe "locationIsAmbiguousInSourceCodeError"
|
describe "locationIsAmbiguousInSourceCode"
|
||||||
[ test "with single-line extracts" <|
|
[ test "with single-line extracts" <|
|
||||||
\() ->
|
\() ->
|
||||||
let
|
let
|
||||||
@ -302,7 +299,7 @@ locationIsAmbiguousInSourceCodeErrorTest =
|
|||||||
"Some error"
|
"Some error"
|
||||||
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
{ start = { row = 3, column = 1 }, end = { row = 3, column = 5 } }
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.locationIsAmbiguousInSourceCodeError
|
ErrorMessage.locationIsAmbiguousInSourceCode
|
||||||
sourceCode
|
sourceCode
|
||||||
error
|
error
|
||||||
under
|
under
|
||||||
@ -341,7 +338,7 @@ Tip: I found them at:
|
|||||||
"Some other error"
|
"Some other error"
|
||||||
{ start = { row = 3, column = 1 }, end = { row = 4, column = 3 } }
|
{ start = { row = 3, column = 1 }, end = { row = 4, column = 3 } }
|
||||||
in
|
in
|
||||||
Lint.Internal.Test.locationIsAmbiguousInSourceCodeError
|
ErrorMessage.locationIsAmbiguousInSourceCode
|
||||||
sourceCode
|
sourceCode
|
||||||
error
|
error
|
||||||
under
|
under
|
||||||
|
Loading…
Reference in New Issue
Block a user