mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-26 03:04:48 +03:00
Replace Lint.Test by the it's new version
This commit is contained in:
parent
bf5a7dad8b
commit
003336a735
@ -1,13 +1,57 @@
|
||||
module Lint.Test exposing (LintResult, errorWithoutRange, expectErrors, expectErrorsWithoutRange, location, run)
|
||||
module Lint.Test exposing
|
||||
( LintResult, run
|
||||
, ExpectedError, expectErrors, expectNoErrors, error, atExactly
|
||||
)
|
||||
|
||||
{-| Module that helps you test your linting rules, using [`elm-test`](https://package.elm-lang.org/packages/elm-explorations/test/latest).
|
||||
|
||||
TODO Add instructions and examples
|
||||
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
|
||||
|
||||
|
||||
# Tips on testing
|
||||
|
||||
|
||||
## What should you test?
|
||||
|
||||
TODO Add helpful tips
|
||||
|
||||
TODO Rework API, we can do something much nicer than this
|
||||
|
||||
-}
|
||||
|
||||
import Array exposing (Array)
|
||||
@ -15,79 +59,508 @@ 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
|
||||
|
||||
|
||||
{-| Alias for the result of a lint rule being applied on a string containing Elm code.
|
||||
{-| The result of running a rule on a `String` containing source code.
|
||||
-}
|
||||
type alias LintResult =
|
||||
Result (List String) (List Error)
|
||||
type LintResult
|
||||
= ParseFailure
|
||||
| SuccessfulRun CodeInspector (List Error)
|
||||
|
||||
|
||||
{-| Run a `Rule` on a string and get the errors reported by it. If the string is
|
||||
not valid Elm code, this will return a `Result` of type `Err`.
|
||||
type alias CodeInspector =
|
||||
{ getCodeAtLocation : Range -> Maybe String
|
||||
, checkIfLocationIsAmbiguous : Error -> String -> Expectation
|
||||
}
|
||||
|
||||
Note that to be valid, a code needs to start with a module definition followed by
|
||||
a line break like `module A exposing (..)\n`.
|
||||
|
||||
{-| 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 SourceCode
|
||||
= 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 sourceCode)
|
||||
, checkIfLocationIsAmbiguous = checkIfLocationIsAmbiguousInSourceCode (SourceCode 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
|
||||
import Test exposing (Test, describe, test)
|
||||
import The.Rule.You.Want.To.Test exposing (rule)
|
||||
|
||||
testRule : String -> LintResult
|
||||
testRule string =
|
||||
"module A exposing (..)\n\n"
|
||||
++ string
|
||||
|> Lint.Test.run rule
|
||||
Lint.Test.run rule string
|
||||
|
||||
tests : List Test
|
||||
-- In this example, the rule we're testing is `NoDebug`
|
||||
tests : Test
|
||||
tests =
|
||||
[ test "should not report normal function calls" <|
|
||||
\() ->
|
||||
testRule "a = Debug.log"
|
||||
|> Lint.Test.expectErrors
|
||||
[ error (Lint.Test.location ( 3, 5 ) ( 3, 14 )) ]
|
||||
]
|
||||
describe "NoDebug"
|
||||
[ test "should not report calls to normal functions" <|
|
||||
\() ->
|
||||
testRule """module A exposing (..)
|
||||
a = foo n"""
|
||||
|> Lint.Test.expectNoErrors
|
||||
]
|
||||
|
||||
-}
|
||||
run : Rule -> String -> Result (List String) (List Error)
|
||||
run rule str =
|
||||
lintSource [ ( Critical, rule ) ] str
|
||||
|> Result.map (List.map (\( severity, { message, range } ) -> Rule.error message range))
|
||||
expectNoErrors : LintResult -> Expectation
|
||||
expectNoErrors lintResult =
|
||||
case lintResult of
|
||||
ParseFailure ->
|
||||
Expect.fail parsingErrorMessage
|
||||
|
||||
SuccessfulRun _ errors ->
|
||||
Expect.true
|
||||
("I expected no errors but found:\n\n" ++ (List.map errorToString errors |> String.join "\n"))
|
||||
(List.isEmpty errors)
|
||||
|
||||
|
||||
expectErrors : List Error -> LintResult -> Expectation
|
||||
expectErrors expectedErrors result =
|
||||
case result of
|
||||
Err errors ->
|
||||
Expect.fail <| String.join "\n" errors
|
||||
{-| Assert that the rule reprted some errors, by specifying which one.
|
||||
|
||||
Ok errors ->
|
||||
Expect.equal expectedErrors errors
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
||||
expectErrorsWithoutRange : List Error -> LintResult -> Expectation
|
||||
expectErrorsWithoutRange expectedErrors result =
|
||||
case result of
|
||||
Err errors ->
|
||||
Expect.fail <| String.join "\n" errors
|
||||
{-| Create an expectation for an error.
|
||||
|
||||
Ok errors ->
|
||||
Expect.equal
|
||||
(errorMessages expectedErrors)
|
||||
(errorMessages errors)
|
||||
`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
|
||||
}
|
||||
|
||||
|
||||
errorMessages : List Error -> List String
|
||||
errorMessages errors =
|
||||
List.map Rule.errorMessage errors
|
||||
getUnder : ExpectedError -> String
|
||||
getUnder (ExpectedError expectedError) =
|
||||
case expectedError.under of
|
||||
Under str ->
|
||||
str
|
||||
|
||||
UnderExactly str _ ->
|
||||
str
|
||||
|
||||
|
||||
errorWithoutRange : String -> Error
|
||||
errorWithoutRange message =
|
||||
Rule.error message (location ( 0, 0 ) ( 0, 0 ))
|
||||
{-| 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 }
|
||||
|
||||
|
||||
location : ( Int, Int ) -> ( Int, Int ) -> Range
|
||||
location ( rowStart, columnStart ) ( rowEnd, columnEnd ) =
|
||||
{ start = { row = rowStart, column = columnStart }
|
||||
, end = { row = rowEnd, column = columnEnd }
|
||||
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 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 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\n```\n" ++ str ++ "\n```")
|
||||
|
||||
|
||||
checkIfLocationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> Expectation
|
||||
checkIfLocationIsAmbiguousInSourceCode ((SourceCode sourceCodeContent) as sourceCode) error_ under =
|
||||
let
|
||||
occurrencesInSourceCode : List Int
|
||||
occurrencesInSourceCode =
|
||||
String.indexes under sourceCodeContent
|
||||
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_ ++ "`"
|
||||
|
||||
|
||||
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 there are multiple occurrences for this piece of code, and 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_)
|
||||
|
||||
|
||||
underMismatchError : Error -> String -> String -> String
|
||||
underMismatchError error_ under codeAtLocation =
|
||||
"""I found an error with the right message, but at the wrong location:
|
||||
|
||||
Message: `""" ++ Rule.errorMessage error_ ++ """`
|
||||
|
||||
I saw it under: """ ++ formatSourceCode codeAtLocation ++ """
|
||||
|
||||
But I expected to see it under: """ ++ formatSourceCode under
|
||||
|
||||
|
||||
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 sourceCode) under position =
|
||||
let
|
||||
linesBeforeAndIncludingPosition : List String
|
||||
linesBeforeAndIncludingPosition =
|
||||
sourceCode
|
||||
|> String.slice 0 position
|
||||
|> String.lines
|
||||
|
||||
startRow : Int
|
||||
startRow =
|
||||
List.length linesBeforeAndIncludingPosition
|
||||
in
|
||||
-- TODO Get these values right
|
||||
{ start =
|
||||
{ row = startRow
|
||||
, column = -1
|
||||
}
|
||||
, end =
|
||||
{ row = startRow + (under |> String.indexes "\n" |> List.length)
|
||||
, column = under |> String.indexes "\n" |> List.length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 ++ " } }"
|
||||
|
||||
|
||||
errorToString : Error -> String
|
||||
errorToString error_ =
|
||||
"- \"" ++ Rule.errorMessage error_ ++ "\" at " ++ Debug.toString (Rule.errorRange error_)
|
||||
|
||||
|
||||
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"
|
||||
++ (List.map expectedErrorToString (expected :: restOfExpectedErrors) |> String.join "\n")
|
||||
|
||||
|
||||
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) =
|
||||
"- " ++ expectedError.message
|
||||
|
@ -1,568 +0,0 @@
|
||||
module Lint.Test2 exposing
|
||||
( LintResult, run
|
||||
, ExpectedError, expectErrors, expectNoErrors, error, atExactly
|
||||
)
|
||||
|
||||
{-| Module that helps you test your linting rules, using [`elm-test`](https://package.elm-lang.org/packages/elm-explorations/test/latest).
|
||||
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
import The.Rule.You.Want.To.Test exposing (rule)
|
||||
|
||||
testRule : String -> LintResult
|
||||
testRule string =
|
||||
Lint.Test2.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.Test2.expectNoErrors
|
||||
, test "should report Debug.log use" <|
|
||||
\() ->
|
||||
testRule """module A exposing (..)
|
||||
a = Debug.log "some" "message\""""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
{ message = "Forbidden use of Debug"
|
||||
, under = "Debug.log"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
# Running tests
|
||||
|
||||
@docs LintResult, run
|
||||
|
||||
|
||||
# Making assertions
|
||||
|
||||
@docs ExpectedError, expectErrors, expectNoErrors, error, atExactly
|
||||
|
||||
TODO Add instructions and examples
|
||||
|
||||
|
||||
# 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 of an error. Use [`error`](#error) to create one.
|
||||
-}
|
||||
type ExpectedError
|
||||
= ExpectedError
|
||||
{ message : String
|
||||
, under : Under
|
||||
}
|
||||
|
||||
|
||||
type Under
|
||||
= Under String
|
||||
| UnderExactly String Range
|
||||
|
||||
|
||||
type SourceCode
|
||||
= 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 sourceCode)
|
||||
, checkIfLocationIsAmbiguous = checkIfLocationIsAmbiguousInSourceCode (SourceCode 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.Test2 exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
import The.Rule.You.Want.To.Test exposing (rule)
|
||||
|
||||
testRule : String -> LintResult
|
||||
testRule string =
|
||||
Lint.Test2.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.Test2.expectNoErrors
|
||||
]
|
||||
|
||||
-}
|
||||
expectNoErrors : LintResult -> Expectation
|
||||
expectNoErrors lintResult =
|
||||
case lintResult of
|
||||
ParseFailure ->
|
||||
Expect.fail parsingErrorMessage
|
||||
|
||||
SuccessfulRun _ errors ->
|
||||
Expect.true
|
||||
("I expected no errors but found:\n\n" ++ (List.map errorToString errors |> String.join "\n"))
|
||||
(List.isEmpty errors)
|
||||
|
||||
|
||||
{-| 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.
|
||||
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
import The.Rule.You.Want.To.Test exposing (rule)
|
||||
|
||||
testRule : String -> LintResult
|
||||
testRule string =
|
||||
Lint.Test2.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.Test2.expectErrors
|
||||
[ Lint.Test2.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.Test2.expectErrors
|
||||
[ Lint.Test2.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.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }
|
||||
, Lint.Test2.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
|> Lint.Test2.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 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 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\n```\n" ++ str ++ "\n```")
|
||||
|
||||
|
||||
checkIfLocationIsAmbiguousInSourceCode : SourceCode -> Error -> String -> Expectation
|
||||
checkIfLocationIsAmbiguousInSourceCode ((SourceCode sourceCodeContent) as sourceCode) error_ under =
|
||||
let
|
||||
occurrencesInSourceCode : List Int
|
||||
occurrencesInSourceCode =
|
||||
String.indexes under sourceCodeContent
|
||||
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_ ++ "`"
|
||||
|
||||
|
||||
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 there are multiple occurrences for this piece of code, and 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_)
|
||||
|
||||
|
||||
underMismatchError : Error -> String -> String -> String
|
||||
underMismatchError error_ under codeAtLocation =
|
||||
"""I found an error with the right message, but at the wrong location:
|
||||
|
||||
Message: `""" ++ Rule.errorMessage error_ ++ """`
|
||||
|
||||
I saw it under: """ ++ formatSourceCode codeAtLocation ++ """
|
||||
|
||||
But I expected to see it under: """ ++ formatSourceCode under
|
||||
|
||||
|
||||
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 sourceCode) under position =
|
||||
let
|
||||
linesBeforeAndIncludingPosition : List String
|
||||
linesBeforeAndIncludingPosition =
|
||||
sourceCode
|
||||
|> String.slice 0 position
|
||||
|> String.lines
|
||||
|
||||
startRow : Int
|
||||
startRow =
|
||||
List.length linesBeforeAndIncludingPosition
|
||||
in
|
||||
-- TODO Get these values right
|
||||
{ start =
|
||||
{ row = startRow
|
||||
, column = -1
|
||||
}
|
||||
, end =
|
||||
{ row = startRow + (under |> String.indexes "\n" |> List.length)
|
||||
, column = under |> String.indexes "\n" |> List.length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 ++ " } }"
|
||||
|
||||
|
||||
errorToString : Error -> String
|
||||
errorToString error_ =
|
||||
"- \"" ++ Rule.errorMessage error_ ++ "\" at " ++ Debug.toString (Rule.errorRange error_)
|
||||
|
||||
|
||||
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"
|
||||
++ (List.map expectedErrorToString (expected :: restOfExpectedErrors) |> String.join "\n")
|
||||
|
||||
|
||||
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) =
|
||||
"- " ++ expectedError.message
|
@ -1,13 +1,13 @@
|
||||
module DefaultPatternPositionTest exposing (all)
|
||||
|
||||
import Lint.Rule.DefaultPatternPosition exposing (PatternPosition(..), rule)
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Lint.Test exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
|
||||
|
||||
testRule : PatternPosition -> String -> LintResult
|
||||
testRule patternPosition =
|
||||
Lint.Test2.run (rule patternPosition)
|
||||
Lint.Test.run (rule patternPosition)
|
||||
|
||||
|
||||
message : String -> String
|
||||
@ -26,7 +26,7 @@ a = case b of
|
||||
Foo -> 1
|
||||
"""
|
||||
|> testRule ShouldBeFirst
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report when default pattern is at the expected position (last)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
@ -36,7 +36,7 @@ a = case b of
|
||||
_ -> 1
|
||||
"""
|
||||
|> testRule ShouldBeLast
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report when there is no default pattern (first)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
@ -45,7 +45,7 @@ a = case b of
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule ShouldBeFirst
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report when there is no default pattern (last)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
@ -54,7 +54,7 @@ a = case b of
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule ShouldBeLast
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report an error when the default pattern is not at the expected position (first) (opposite expected position)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
@ -64,8 +64,8 @@ a = case b of
|
||||
_ -> 1
|
||||
"""
|
||||
|> testRule ShouldBeFirst
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message "first"
|
||||
, under = "_"
|
||||
}
|
||||
@ -79,8 +79,8 @@ a = case b of
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule ShouldBeFirst
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message "first"
|
||||
, under = "_"
|
||||
}
|
||||
@ -94,8 +94,8 @@ a = case b of
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule ShouldBeLast
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message "last"
|
||||
, under = "_"
|
||||
}
|
||||
@ -109,8 +109,8 @@ a = case b of
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule ShouldBeLast
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message "last"
|
||||
, under = "_"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
module NoDebugTest exposing (all)
|
||||
|
||||
import Lint.Rule.NoDebug exposing (rule)
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Lint.Test exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ testRule : String -> LintResult
|
||||
testRule string =
|
||||
"module A exposing (..)\n\n"
|
||||
++ string
|
||||
|> Lint.Test2.run rule
|
||||
|> Lint.Test.run rule
|
||||
|
||||
|
||||
message : String
|
||||
@ -28,12 +28,12 @@ c = debug
|
||||
e = debug.log n
|
||||
d = debug.log n
|
||||
"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report Debug.log use" <|
|
||||
\() ->
|
||||
testRule "a = Debug.log"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -41,8 +41,8 @@ d = debug.log n
|
||||
, test "should report Debug.log calls" <|
|
||||
\() ->
|
||||
testRule "a = Debug.log z"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -53,23 +53,23 @@ d = debug.log n
|
||||
a = Debug.log z
|
||||
b = Debug.log z
|
||||
"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }
|
||||
, Lint.Test2.error
|
||||
|> Lint.Test.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }
|
||||
, Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } }
|
||||
|> Lint.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } }
|
||||
]
|
||||
, test "should report Debug.crash calls" <|
|
||||
\() ->
|
||||
testRule "a = Debug.crash 1"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.crash"
|
||||
}
|
||||
@ -77,8 +77,8 @@ b = Debug.log z
|
||||
, test "should report any Debug method" <|
|
||||
\() ->
|
||||
testRule "a = Debug.foo 1"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.foo"
|
||||
}
|
||||
@ -86,8 +86,8 @@ b = Debug.log z
|
||||
, test "should report Debug in a binary expression" <|
|
||||
\() ->
|
||||
testRule "a = ( Debug.log z ) + 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -95,8 +95,8 @@ b = Debug.log z
|
||||
, test "should report Debug in a << binary expression" <|
|
||||
\() ->
|
||||
testRule "a = fn << Debug.log"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -104,8 +104,8 @@ b = Debug.log z
|
||||
, test "should report Debug in a pipe expression" <|
|
||||
\() ->
|
||||
testRule "a = fn |> Debug.log z"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -113,8 +113,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an list expression" <|
|
||||
\() ->
|
||||
testRule "a = [ Debug.log z y ]"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -122,8 +122,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an record expression" <|
|
||||
\() ->
|
||||
testRule "a = { foo = Debug.log z y }"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -131,8 +131,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an record update expression" <|
|
||||
\() ->
|
||||
testRule "a = { model | foo = Debug.log z y }"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -140,8 +140,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an lambda expression" <|
|
||||
\() ->
|
||||
testRule "a = (\\foo -> Debug.log z foo)"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -149,8 +149,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an if expression condition" <|
|
||||
\() ->
|
||||
testRule "a = if Debug.log a b then True else False"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -158,8 +158,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an if expression then branch" <|
|
||||
\() ->
|
||||
testRule "a = if True then Debug.log a b else False"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -167,8 +167,8 @@ b = Debug.log z
|
||||
, test "should report Debug in an if expression else branch" <|
|
||||
\() ->
|
||||
testRule "a = if True then True else Debug.log a b"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -179,8 +179,8 @@ b = Debug.log z
|
||||
a = case Debug.log a b of
|
||||
_ -> []
|
||||
"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -191,8 +191,8 @@ a = case Debug.log a b of
|
||||
a = case a of
|
||||
_ -> Debug.log a b
|
||||
"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -203,8 +203,8 @@ a = case a of
|
||||
a = let b = Debug.log a b
|
||||
in b
|
||||
"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
@ -215,8 +215,8 @@ a = let b = Debug.log a b
|
||||
a = let b = c
|
||||
in Debug.log a b
|
||||
"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = message
|
||||
, under = "Debug.log"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
module NoExtraBooleanComparisonTest exposing (all)
|
||||
|
||||
import Lint.Rule.NoExtraBooleanComparison exposing (rule)
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Lint.Test exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ testRule : String -> LintResult
|
||||
testRule string =
|
||||
"module A exposing (..)\n\n"
|
||||
++ string
|
||||
|> Lint.Test2.run rule
|
||||
|> Lint.Test.run rule
|
||||
|
||||
|
||||
tests : List Test
|
||||
@ -17,7 +17,7 @@ tests =
|
||||
[ test "should not report condition without an operator" <|
|
||||
\() ->
|
||||
testRule "a = if n then 1 else 2"
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report condition with integer operators" <|
|
||||
\() ->
|
||||
testRule """
|
||||
@ -26,16 +26,16 @@ b = if n <= 1 then 1 else 2
|
||||
c = if n > 1 then 1 else 2
|
||||
d = if n >= 1 then 1 else 2
|
||||
"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report condition using `not`" <|
|
||||
\() ->
|
||||
testRule "a = if not n then 1 else 2"
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report condition with `expr == True`" <|
|
||||
\() ->
|
||||
testRule "a = if b == True then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `True`"
|
||||
, under = "b == True"
|
||||
}
|
||||
@ -43,8 +43,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `True == expr`" <|
|
||||
\() ->
|
||||
testRule "a = if True == b then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `True`"
|
||||
, under = "True == b"
|
||||
}
|
||||
@ -52,8 +52,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `expr == False`" <|
|
||||
\() ->
|
||||
testRule "a = if b == False then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `False`"
|
||||
, under = "b == False"
|
||||
}
|
||||
@ -61,8 +61,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `False == expr`" <|
|
||||
\() ->
|
||||
testRule "a = if False == b then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `False`"
|
||||
, under = "False == b"
|
||||
}
|
||||
@ -70,8 +70,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `expr /= True`" <|
|
||||
\() ->
|
||||
testRule "a = if b /= True then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `True`"
|
||||
, under = "b /= True"
|
||||
}
|
||||
@ -79,8 +79,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `True /= expr`" <|
|
||||
\() ->
|
||||
testRule "a = if True /= b then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `True`"
|
||||
, under = "True /= b"
|
||||
}
|
||||
@ -88,8 +88,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `expr /= False`" <|
|
||||
\() ->
|
||||
testRule "a = if b /= False then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `False`"
|
||||
, under = "b /= False"
|
||||
}
|
||||
@ -97,8 +97,8 @@ d = if n >= 1 then 1 else 2
|
||||
, test "should report condition with `False /= expr`" <|
|
||||
\() ->
|
||||
testRule "a = if False /= b then 1 else 2"
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Unnecessary comparison with `False`"
|
||||
, under = "False /= b"
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
module NoImportingEverythingTest exposing (all)
|
||||
|
||||
import Lint.Rule.NoImportingEverything exposing (Configuration, rule)
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Lint.Test exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
|
||||
|
||||
testRule : Configuration -> String -> LintResult
|
||||
testRule options =
|
||||
Lint.Test2.run (rule options)
|
||||
Lint.Test.run (rule options)
|
||||
|
||||
|
||||
tests : List Test
|
||||
@ -18,33 +18,33 @@ tests =
|
||||
import Html
|
||||
import Http"""
|
||||
|> testRule { exceptions = [] }
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report imports that expose functions by name" <|
|
||||
\() ->
|
||||
"""module A exposing (..)
|
||||
import Html exposing (a)
|
||||
import Http exposing (a, b)"""
|
||||
|> testRule { exceptions = [] }
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report imports that expose everything" <|
|
||||
\() ->
|
||||
"""module A exposing (..)
|
||||
import Html exposing (..)"""
|
||||
|> testRule { exceptions = [] }
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Do not expose everything from Html"
|
||||
, under = ".."
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 23 }, end = { row = 2, column = 25 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 23 }, end = { row = 2, column = 25 } }
|
||||
]
|
||||
, test "should report imports from sub-modules" <|
|
||||
\() ->
|
||||
"""module A exposing (a)
|
||||
import Html.App exposing (..)"""
|
||||
|> testRule { exceptions = [] }
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Do not expose everything from Html.App"
|
||||
, under = ".."
|
||||
}
|
||||
@ -54,8 +54,8 @@ import Html.App exposing (..)"""
|
||||
"""module A exposing (a)
|
||||
import Html.Foo.Bar exposing (..)"""
|
||||
|> testRule { exceptions = [] }
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Do not expose everything from Html.Foo.Bar"
|
||||
, under = ".."
|
||||
}
|
||||
@ -65,26 +65,26 @@ import Html.Foo.Bar exposing (..)"""
|
||||
"""module A exposing (a)
|
||||
import Html exposing (..)"""
|
||||
|> testRule { exceptions = [ "Html" ] }
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report imports from sub-modules that are in the exception list" <|
|
||||
\() ->
|
||||
"""module A exposing (a)
|
||||
import Html.App exposing (..)"""
|
||||
|> testRule { exceptions = [ "Html.App" ] }
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report imports from sub-modules (multiple dots)" <|
|
||||
\() ->
|
||||
"""module A exposing (a)
|
||||
import Html.Foo.Bar exposing (..)"""
|
||||
|> testRule { exceptions = [ "Html.Foo.Bar" ] }
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report imports whose parent is ignored" <|
|
||||
\() ->
|
||||
"""module A exposing (a)
|
||||
import Html.Foo.Bar exposing (..)"""
|
||||
|> testRule { exceptions = [ "Html" ] }
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Do not expose everything from Html.Foo.Bar"
|
||||
, under = ".."
|
||||
}
|
||||
@ -94,8 +94,8 @@ import Html.Foo.Bar exposing (..)"""
|
||||
"""module A exposing (a)
|
||||
import Html exposing (..)"""
|
||||
|> testRule { exceptions = [ "Html.App" ] }
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Do not expose everything from Html"
|
||||
, under = ".."
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
module NoUnusedVariablesTest exposing (all)
|
||||
|
||||
import Lint.Rule.NoUnusedVariables exposing (rule)
|
||||
import Lint.Test2 exposing (LintResult)
|
||||
import Lint.Test exposing (LintResult)
|
||||
import Test exposing (Test, describe, test)
|
||||
|
||||
|
||||
testRule : String -> LintResult
|
||||
testRule =
|
||||
Lint.Test2.run rule
|
||||
Lint.Test.run rule
|
||||
|
||||
|
||||
tests : List Test
|
||||
@ -16,19 +16,19 @@ tests =
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report used top-level variables" <|
|
||||
\() ->
|
||||
testRule """module A exposing (b)
|
||||
a n = 1
|
||||
b = a 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused top-level variables" <|
|
||||
\() ->
|
||||
testRule """module A exposing (b)
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `a` is not used"
|
||||
, under = "a"
|
||||
}
|
||||
@ -38,33 +38,33 @@ a = 1"""
|
||||
testRule """module A exposing (b)
|
||||
a: Int
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `a` is not used"
|
||||
, under = "a"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 3, column = 1 }, end = { row = 3, column = 2 } }
|
||||
|> Lint.Test.atExactly { start = { row = 3, column = 1 }, end = { row = 3, column = 2 } }
|
||||
]
|
||||
, test "should not report unused top-level variables if everything is exposed" <|
|
||||
\() ->
|
||||
testRule """module A exposing (..)
|
||||
a n = 1
|
||||
b = a 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused top-level variables that are exposed by name" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a, b)
|
||||
a = 1
|
||||
b = 2"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused top-level variables that are exposed by name, but report others" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a, b)
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `c` is not used"
|
||||
, under = "c"
|
||||
}
|
||||
@ -74,21 +74,21 @@ c = 3"""
|
||||
testRule """port module A exposing (..)
|
||||
a n = 1
|
||||
b = a 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused top-level variables that are exposed by name (port module)" <|
|
||||
\() ->
|
||||
testRule """port module A exposing (a, b)
|
||||
a = 1
|
||||
b = 2"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused top-level variables that are exposed by name, but report others (port module)" <|
|
||||
\() ->
|
||||
testRule """port module A exposing (a, b)
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `c` is not used"
|
||||
, under = "c"
|
||||
}
|
||||
@ -98,8 +98,8 @@ c = 3"""
|
||||
testRule """module A exposing (a)
|
||||
a = let b = 1
|
||||
in 2"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `b` is not used"
|
||||
, under = "b"
|
||||
}
|
||||
@ -109,20 +109,20 @@ a = let b = 1
|
||||
testRule """module A exposing (a, b)
|
||||
a = let b = 1
|
||||
in 2"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `b` is not used"
|
||||
, under = "b"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 9 }, end = { row = 2, column = 10 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 9 }, end = { row = 2, column = 10 } }
|
||||
]
|
||||
, test "should report unused functions from let even if they are exposed by name" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
a = let b param = 1
|
||||
in 2"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `b` is not used"
|
||||
, under = "b"
|
||||
}
|
||||
@ -132,8 +132,8 @@ a = let b param = 1
|
||||
testRule """module A exposing (..)
|
||||
a = let b = 1
|
||||
in 2"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `b` is not used"
|
||||
, under = "b"
|
||||
}
|
||||
@ -144,14 +144,14 @@ a = let b = 1
|
||||
b = 1
|
||||
a = let c = 1
|
||||
in b + c"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report top-level variables used inside let declarations" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
b = 1
|
||||
a = let c = b
|
||||
in c"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report top-level variables used in nested lets" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
@ -164,24 +164,24 @@ a = let
|
||||
b + c + e
|
||||
in
|
||||
d"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report variables from let declarations that are used in the expression" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
a = let c = 1
|
||||
in c"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused function parameters" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
a n = 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused imported functions" <|
|
||||
\() ->
|
||||
testRule """module A exposing (b)
|
||||
import Foo exposing (a)"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Imported variable `a` is not used"
|
||||
, under = "a"
|
||||
}
|
||||
@ -190,16 +190,16 @@ import Foo exposing (a)"""
|
||||
\() ->
|
||||
testRule """module A exposing (d)
|
||||
import Foo exposing (C, a, b)"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Imported variable `b` is not used"
|
||||
, under = "b"
|
||||
}
|
||||
, Lint.Test2.error
|
||||
, Lint.Test.error
|
||||
{ message = "Imported variable `a` is not used"
|
||||
, under = "a"
|
||||
}
|
||||
, Lint.Test2.error
|
||||
, Lint.Test.error
|
||||
{ message = "Imported type `C` is not used"
|
||||
, under = "C"
|
||||
}
|
||||
@ -212,30 +212,30 @@ import Foo exposing (C, a, b)"""
|
||||
testRule """module A exposing (a)
|
||||
a = case thing of
|
||||
Foo b c -> []"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
|
||||
-- Should B and C be reported if they are not used? Probably.
|
||||
, test "should report unused custom type declarations" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type A = B | C"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Type `A` is not used"
|
||||
, under = "A"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 6 }, end = { row = 2, column = 7 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 6 }, end = { row = 2, column = 7 } }
|
||||
]
|
||||
, test "should report unused type aliases declarations" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Type `A` is not used"
|
||||
, under = "A"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 12 }, end = { row = 2, column = 13 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 12 }, end = { row = 2, column = 13 } }
|
||||
]
|
||||
, test "should not report type used in a signature" <|
|
||||
\() ->
|
||||
@ -243,63 +243,63 @@ type alias A = { a : B }"""
|
||||
type alias A = { a : B }
|
||||
a : A
|
||||
a = {a = 1}"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type used in a signature with multiple arguments" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }
|
||||
a : String -> A
|
||||
a str = {a = str}"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type used in a signature with parameterized types (as generic type)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }
|
||||
a : A B
|
||||
a = []"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type used in a signature with parameterized types (as parameter)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }
|
||||
a : List A
|
||||
a = []"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type used in a signature with a record" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }
|
||||
a : { c: A }
|
||||
a str = {c = str}"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type used in a signature with a generic record" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type alias A = { a : B }
|
||||
a : { r | c: A }
|
||||
a str = {c = str}"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report type if it's exposed" <|
|
||||
\() ->
|
||||
testRule """module A exposing (A)
|
||||
type A a = B a"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report custom type if it's exposed with its sub-types" <|
|
||||
\() ->
|
||||
testRule """module A exposing (A(..))
|
||||
type A = B | C | D"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused variable even if it's present in a generic type" <|
|
||||
\() ->
|
||||
testRule """module A exposing (A)
|
||||
a = 1
|
||||
type A a = B a"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `a` is not used"
|
||||
, under = "a"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 2 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 2 } }
|
||||
]
|
||||
, test "should report unused variable even if it's present in a generic record type" <|
|
||||
\() ->
|
||||
@ -307,19 +307,19 @@ type A a = B a"""
|
||||
r = 1
|
||||
a : { r | c: A }
|
||||
a str = {c = str}"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `r` is not used"
|
||||
, under = "r"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 2 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 2 } }
|
||||
]
|
||||
, test "should report unused operator import" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Parser exposing ((</>))"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Imported operator `</>` is not used"
|
||||
, under = "(</>)"
|
||||
}
|
||||
@ -329,23 +329,23 @@ import Parser exposing ((</>))"""
|
||||
testRule """module A exposing (a)
|
||||
import Parser exposing ((</>))
|
||||
a = 1 </> 2"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report used operator (prefix)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Parser exposing ((</>))
|
||||
a = (</>) 2"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused opaque types" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
type A = A Int"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Type `A` is not used"
|
||||
, under = "A"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 6 }, end = { row = 2, column = 7 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 6 }, end = { row = 2, column = 7 } }
|
||||
]
|
||||
, test "should not report used opaque types" <|
|
||||
\() ->
|
||||
@ -353,13 +353,13 @@ type A = A Int"""
|
||||
type A = A Int
|
||||
a : A
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused import" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Imported module `Html` is not used"
|
||||
, under = "Html"
|
||||
}
|
||||
@ -368,8 +368,8 @@ import Html"""
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html.Styled.Attributes"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Imported module `Html.Styled.Attributes` is not used"
|
||||
, under = "Html.Styled.Attributes"
|
||||
}
|
||||
@ -378,41 +378,41 @@ import Html.Styled.Attributes"""
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html.Styled.Attributes exposing (..)"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused variable even if a homonym from a module is used" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
href = 1
|
||||
a = Html.Styled.Attributes.href"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Variable `href` is not used"
|
||||
, under = "href"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 1 }, end = { row = 2, column = 5 } }
|
||||
]
|
||||
, test "should not report used import (function access)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html.Styled.Attributes
|
||||
a = Html.Styled.Attributes.href"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report unused import if it is aliased" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html.Styled.Attributes as Html
|
||||
a = Html.href"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused import alias" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Html.Styled.Attributes as Html"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Module alias `Html` is not used"
|
||||
, under = "Html"
|
||||
}
|
||||
|> Lint.Test2.atExactly { start = { row = 2, column = 34 }, end = { row = 2, column = 38 } }
|
||||
|> Lint.Test.atExactly { start = { row = 2, column = 34 }, end = { row = 2, column = 38 } }
|
||||
]
|
||||
, test "should not report import that exposes a used exposed type" <|
|
||||
\() ->
|
||||
@ -420,14 +420,14 @@ import Html.Styled.Attributes as Html"""
|
||||
import B exposing (C(..))
|
||||
a : C
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report import that exposes an unused exposed type (but whose subtype is potentially used)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import B exposing (C(..))
|
||||
a : D
|
||||
a = 1"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should not report types that are used in ports" <|
|
||||
\() ->
|
||||
testRule """module A exposing (output, input)
|
||||
@ -435,14 +435,14 @@ import Json.Decode
|
||||
import Json.Encode
|
||||
port output : Json.Encode.Value -> Cmd msg
|
||||
port input : (Json.Decode.Value -> msg) -> Sub msg"""
|
||||
|> Lint.Test2.expectNoErrors
|
||||
|> Lint.Test.expectNoErrors
|
||||
, test "should report unused ports (ingoing)" <|
|
||||
\() ->
|
||||
testRule """module A exposing (a)
|
||||
import Json.Decode
|
||||
port input : (Json.Decode.Value -> msg) -> Sub msg"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Port `input` is not used (Warning: Removing this port may break your application if it is used in the JS code)"
|
||||
, under = "input"
|
||||
}
|
||||
@ -452,8 +452,8 @@ port input : (Json.Decode.Value -> msg) -> Sub msg"""
|
||||
testRule """module A exposing (a)
|
||||
import Json.Encode
|
||||
port output : Json.Encode.Value -> Cmd msg"""
|
||||
|> Lint.Test2.expectErrors
|
||||
[ Lint.Test2.error
|
||||
|> Lint.Test.expectErrors
|
||||
[ Lint.Test.error
|
||||
{ message = "Port `output` is not used (Warning: Removing this port may break your application if it is used in the JS code)"
|
||||
, under = "output"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user