mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-26 03:04:48 +03:00
1134 lines
40 KiB
Elm
1134 lines
40 KiB
Elm
|
module Docs.ReviewLinksAndSectionsTest exposing (all)
|
||
|
|
||
|
import Docs.ReviewLinksAndSections exposing (rule)
|
||
|
import Elm.Project
|
||
|
import Json.Decode
|
||
|
import Review.Project as Project exposing (Project)
|
||
|
import Review.Test
|
||
|
import Test exposing (Test, describe, test)
|
||
|
|
||
|
|
||
|
|
||
|
-- TODO Report links to dependencies?
|
||
|
-- TODO Force links to dependencies to be for the minimal version?
|
||
|
-- TODO Report unmatched `[foo]`?
|
||
|
-- TODO Report unused `[foo]: #b` links? (only if there are no "unmatched errors")
|
||
|
|
||
|
|
||
|
all : Test
|
||
|
all =
|
||
|
describe "Docs.ReviewLinksAndSections"
|
||
|
[ localLinkTests
|
||
|
, linksToOtherFilesTest
|
||
|
, linksDependingOnExposition
|
||
|
, linksThroughPackageRegistryTest
|
||
|
, duplicateSectionsTests
|
||
|
, unnecessaryLinksTests
|
||
|
, externalResourcesTests
|
||
|
, linksWithAltTextTests
|
||
|
]
|
||
|
|
||
|
|
||
|
localLinkTests : Test
|
||
|
localLinkTests =
|
||
|
describe "Local links"
|
||
|
[ test "should not report link to an existing sibling section from declaration documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report a link to an unknown sibling section from declaration documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report link to an existing sibling section from module documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
|
||
|
import B
|
||
|
b = 1
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report a link to an unknown sibling section from module documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
|
||
|
import B
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report link to an existing sibling section from port documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
port a : String -> Cmd msg
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report a link to an unknown sibling section from port documentation" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
port a : String -> Cmd msg
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report a link to a known sibling section from declaration documentation when everything is exposed" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report a link to an unknown sibling section from declaration documentation when everything is exposed" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report link references that target existing sections" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
{-| this is a [link] reference
|
||
|
|
||
|
[link]: #b
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report link references that link to missing sections" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| this is a [link] reference
|
||
|
|
||
|
[link]: #b
|
||
|
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should consider an exposed type alias to be an existing section" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
type alias B = {}
|
||
|
{-| [link](#B)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should consider an exposed custom type to be an existing section" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
type B = C
|
||
|
{-| [link](#B)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should consider an exposed port to be an existing section" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
port b : Int -> Cmd msg
|
||
|
|
||
|
{-| [link](#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should consider an infix declaration to be an existing section (operator exists)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
infix right 5 (++) = append
|
||
|
|
||
|
{-| [link](#++)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should consider an infix declaration to be an existing section (operator doesn't exist)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](#++)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#++"
|
||
|
}
|
||
|
]
|
||
|
, test "should consider a header inside a function documentation comment to be an existing section (h1)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
# Section
|
||
|
-}
|
||
|
b = 1
|
||
|
{-| [link](#section)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should consider a header inside a function documentation comment to be an existing section (h2)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
## Section
|
||
|
-}
|
||
|
b = 1
|
||
|
{-| [link](#section)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not consider a 'h7' header inside a function documentation comment to be an existing section" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
####### Section
|
||
|
-}
|
||
|
b = 1
|
||
|
{-| [link](#section)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#section"
|
||
|
}
|
||
|
]
|
||
|
, test "should consider a header inside a module documentation comment to be an existing section" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
# Section
|
||
|
-}
|
||
|
|
||
|
import B
|
||
|
|
||
|
b = 1
|
||
|
{-| [link](#section)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should slugify complex headings" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
# Section *with* ~some~ _spaces_ and\\_ $thi.ngs . links
|
||
|
|
||
|
### `section`
|
||
|
### question?
|
||
|
|
||
|
-}
|
||
|
b = 1
|
||
|
{-|
|
||
|
[1](#section-_with_-some-_spaces_-and-_-thi-ngs-links)
|
||
|
[2](#-section-)
|
||
|
[3](#question-)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to unknown modules" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](B-C)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module B.C"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "B-C"
|
||
|
}
|
||
|
]
|
||
|
, test "should report multiple links on the same line" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](#b) [link](#c) [link](#d) [link](#e)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
, Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#c"
|
||
|
}
|
||
|
, Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#d"
|
||
|
}
|
||
|
, Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#e"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
linksToOtherFilesTest : Test
|
||
|
linksToOtherFilesTest =
|
||
|
describe "Links to other files"
|
||
|
[ test "should report links to sections in unknown modules" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](B#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module B"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "B#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to existing sections in a different module" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](B#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module B exposing (b)
|
||
|
b = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModules rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to missing sections in a different module" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](B#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module B exposing (c)
|
||
|
c = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModules rule
|
||
|
|> Review.Test.expectErrorsForModules
|
||
|
[ ( "A"
|
||
|
, [ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "B#b"
|
||
|
}
|
||
|
]
|
||
|
)
|
||
|
]
|
||
|
, test "should not report links to existing sections in a different module (using ./)" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](./B#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module B exposing (b)
|
||
|
b = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModules rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to missing sections in a different module (using ./)" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](./B#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module B exposing (c)
|
||
|
c = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModules rule
|
||
|
|> Review.Test.expectErrorsForModules
|
||
|
[ ( "A"
|
||
|
, [ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "./B#b"
|
||
|
}
|
||
|
]
|
||
|
)
|
||
|
]
|
||
|
, test "should not report links to existing sections inside the README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A\n[link](#a)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to missing sections inside the README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A\n[link](#b)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to existing sections inside the README (using ./)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A\n[link](./#a)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to missing sections inside the README (using ./)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A\n[link](./#b)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "./#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to existing sections from another module inside the README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./A#a)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to missing sections from another module inside the README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./A#b)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "./A#b"
|
||
|
}
|
||
|
]
|
||
|
, test "should report links to README when there is no README (without slug)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](./)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to missing README"
|
||
|
, details = [ "elm-review only looks for a 'README.md' located next to your 'elm.json'. Maybe it's positioned elsewhere or named differently?" ]
|
||
|
, under = "./"
|
||
|
}
|
||
|
]
|
||
|
, test "should report links to README when there is no README (with slug)" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a)
|
||
|
{-| [link](./#b)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to missing README"
|
||
|
, details = [ "elm-review only looks for a 'README.md' located next to your 'elm.json'. Maybe it's positioned elsewhere or named differently?" ]
|
||
|
, under = "./#b"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
linksThroughPackageRegistryTest : Test
|
||
|
linksThroughPackageRegistryTest =
|
||
|
describe "Links through the package registry"
|
||
|
[ test "should report links to unknown modules for the current version" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/Unknown)
|
||
|
-}
|
||
|
a = 2
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "https://package.elm-lang.org/packages/author/package/1.0.0/Unknown"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to known modules for the current version" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/A)
|
||
|
-}
|
||
|
a = 2
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links to known modules for the current version (with trailing slash)" <|
|
||
|
\() ->
|
||
|
[ """module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/A/)
|
||
|
-}
|
||
|
a = 2
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to unknown modules for latest" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/latest/Unknown)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "https://package.elm-lang.org/packages/author/package/latest/Unknown"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links for different version of the package" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/2.3.4/Unknown)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to unknown section of README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/#unknown)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A" } packageProjectWithoutFiles)
|
||
|
rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to a non-existing section or element"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "https://package.elm-lang.org/packages/author/package/1.0.0/#unknown"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to known sections of README" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/2.3.4/#a)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "# A" } packageProjectWithoutFiles)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links for different packages" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-| [link](https://package.elm-lang.org/packages/other-author/package/latest/Unknown/)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
]
|
||
|
|
||
|
|
||
|
linksDependingOnExposition : Test
|
||
|
linksDependingOnExposition =
|
||
|
describe "Links depending on exposition"
|
||
|
[ test "should not report links from non-exposed modules to non-exposed modules" <|
|
||
|
\() ->
|
||
|
[ """module NotExposed exposing (a)
|
||
|
{-| [link](./AlsoNotExposed)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module AlsoNotExposed exposing (b)
|
||
|
b = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProject rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links from non-exposed modules to exposed modules" <|
|
||
|
\() ->
|
||
|
"""module NotExposed exposing (a)
|
||
|
{-| [link](./Exposed)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProject rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links from exposed modules to exposed modules" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (a)
|
||
|
{-| [link](./Exposed)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProject rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links from exposed modules to non-exposed modules" <|
|
||
|
\() ->
|
||
|
[ """module Exposed2 exposing (a)
|
||
|
{-| [link](./NotExposed)
|
||
|
-}
|
||
|
a = 2
|
||
|
""", """module NotExposed exposing (b)
|
||
|
b = 1
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProject rule
|
||
|
|> Review.Test.expectErrorsForModules
|
||
|
[ ( "Exposed2"
|
||
|
, [ Review.Test.error
|
||
|
{ message = "Link in public documentation points to non-exposed module"
|
||
|
, details = [ "Users will not be able to follow the link." ]
|
||
|
, under = "./NotExposed"
|
||
|
}
|
||
|
]
|
||
|
)
|
||
|
]
|
||
|
, test "should not report links from non-exposed sections to non-exposed sections" <|
|
||
|
\() ->
|
||
|
[ """module Exposed2 exposing (b)
|
||
|
b = a
|
||
|
|
||
|
{-| [link](./Exposed3#hidden)
|
||
|
-}
|
||
|
a = 1
|
||
|
""", """module Exposed3 exposing (exposed)
|
||
|
exposed = 2
|
||
|
|
||
|
{-|
|
||
|
# Hidden
|
||
|
-}
|
||
|
a = 3
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProject rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links from non-exposed sections to exposed sections" <|
|
||
|
\() ->
|
||
|
[ """module Exposed2 exposing (b)
|
||
|
b = a
|
||
|
|
||
|
{-| [link](./Exposed3#exposed)
|
||
|
-}
|
||
|
a = 1
|
||
|
""", """module Exposed3 exposing (exposed)
|
||
|
exposed = 2
|
||
|
|
||
|
{-|
|
||
|
# Hidden
|
||
|
-}
|
||
|
a = 3
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProject rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links from exposed sections to non-exposed sections" <|
|
||
|
\() ->
|
||
|
[ """module Exposed2 exposing (b)
|
||
|
{-| [link](./Exposed3#hidden)
|
||
|
-}
|
||
|
b = 1
|
||
|
""", """module Exposed3 exposing (exposed)
|
||
|
exposed = 2
|
||
|
|
||
|
{-|
|
||
|
# Hidden
|
||
|
-}
|
||
|
a = 3
|
||
|
""" ]
|
||
|
|> Review.Test.runOnModulesWithProjectData packageProject rule
|
||
|
|> Review.Test.expectErrorsForModules
|
||
|
[ ( "Exposed2"
|
||
|
, [ Review.Test.error
|
||
|
{ message = "Link in public documentation points to non-exposed section"
|
||
|
, details = [ "Users will not be able to follow the link." ]
|
||
|
, under = "./Exposed3#hidden"
|
||
|
}
|
||
|
]
|
||
|
)
|
||
|
]
|
||
|
, test "should report links from README to non-exposed modules" <|
|
||
|
\() ->
|
||
|
"""module NotExposed exposing (a)
|
||
|
a = 1
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./NotExposed)" } packageProject)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link in public documentation points to non-exposed module"
|
||
|
, details = [ "Users will not be able to follow the link." ]
|
||
|
, under = "./NotExposed"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links from README to exposed modules" <|
|
||
|
\() ->
|
||
|
"""module NotExposed exposing (a)
|
||
|
a = 1
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./Exposed)" } packageProject)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links from README to non-exposed sections" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (a)
|
||
|
a = 1
|
||
|
{-|
|
||
|
# Section
|
||
|
-}
|
||
|
b = 1
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./Exposed2#section)" } packageProject)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link in public documentation points to non-exposed section"
|
||
|
, details = [ "Users will not be able to follow the link." ]
|
||
|
, under = "./Exposed2#section"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links from README to non-exposed sections in non-package projects" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (a)
|
||
|
a = 1
|
||
|
{-|
|
||
|
# Section
|
||
|
-}
|
||
|
b = 1
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = "[link](./Exposed2#section)" } Project.new)
|
||
|
rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
]
|
||
|
|
||
|
|
||
|
duplicateSectionsTests : Test
|
||
|
duplicateSectionsTests =
|
||
|
describe "Duplicate sections"
|
||
|
[ test "should report duplicate sections (declaration doc comment)" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (error, exposed)
|
||
|
{-|
|
||
|
# Error
|
||
|
-}
|
||
|
exposed = 1
|
||
|
|
||
|
error = 1
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Duplicate section"
|
||
|
, details = [ "There are multiple sections that will result in the same id, meaning that links may point towards the wrong element." ]
|
||
|
, under = "# Error"
|
||
|
}
|
||
|
]
|
||
|
, test "should report duplicate sections (module doc comment)" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (error)
|
||
|
{-|
|
||
|
# Error
|
||
|
-}
|
||
|
|
||
|
error = 1
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Duplicate section"
|
||
|
, details = [ "There are multiple sections that will result in the same id, meaning that links may point towards the wrong element." ]
|
||
|
, under = "# Error"
|
||
|
}
|
||
|
]
|
||
|
, test "should report duplicate sections (all in declaration doc comments)" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (error)
|
||
|
{-|
|
||
|
# Some section
|
||
|
|
||
|
# Some Section
|
||
|
-}
|
||
|
|
||
|
error = 1
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Duplicate section"
|
||
|
, details = [ "There are multiple sections that will result in the same id, meaning that links may point towards the wrong element." ]
|
||
|
, under = "# Some Section"
|
||
|
}
|
||
|
]
|
||
|
, test "should report duplicate sections in README" <|
|
||
|
\() ->
|
||
|
"""module Exposed2 exposing (a)
|
||
|
a = 1
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData
|
||
|
(Project.addReadme { path = "README.md", content = """
|
||
|
# Some section
|
||
|
|
||
|
# Some Section
|
||
|
""" } packageProject)
|
||
|
rule
|
||
|
|> Review.Test.expectErrorsForReadme
|
||
|
[ Review.Test.error
|
||
|
{ message = "Duplicate section"
|
||
|
, details = [ "There are multiple sections that will result in the same id, meaning that links may point towards the wrong element." ]
|
||
|
, under = "# Some Section"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
unnecessaryLinksTests : Test
|
||
|
unnecessaryLinksTests =
|
||
|
describe "Unnecessary links"
|
||
|
[ test "should report links to #" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](#)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link to empty section is unnecessary"
|
||
|
, details = [ "Links to # not followed by an id don't provide any value to the user. I suggest to either strip the # or remove the link." ]
|
||
|
, under = "#"
|
||
|
}
|
||
|
]
|
||
|
, test "should report links to a module with #" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](A#)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link to empty section is unnecessary"
|
||
|
, details = [ "Links to # not followed by an id don't provide any value to the user. I suggest to either strip the # or remove the link." ]
|
||
|
, under = "A#"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
externalResourcesTests : Test
|
||
|
externalResourcesTests =
|
||
|
describe "External resources"
|
||
|
[ test "should not report links to external resources without a protocol when the project is not a package" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](www.google.com)
|
||
|
![](./image.png)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should not report links to external resources with a protocol" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](https://foo.com)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to an external resource without a protocol" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](foo.com)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link to unknown resource without a protocol"
|
||
|
, details =
|
||
|
[ "I have trouble figuring out what kind of resource is linked here."
|
||
|
, "If it should link to a module, then they should be in the form 'Some-Module-Name'."
|
||
|
, "If it's a link to an external resource, they should start with a protocol, like `https://www.fruits.com`, otherwise the link will point to an unknown resource on package.elm-lang.org."
|
||
|
]
|
||
|
, under = "foo.com"
|
||
|
}
|
||
|
]
|
||
|
, test "should not report links to images with a protocol" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](https://www.image.com/image.png)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to images without a protocol" <|
|
||
|
\() ->
|
||
|
"""module A exposing (..)
|
||
|
{-|
|
||
|
[link](./image.png)
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link to unknown resource without a protocol"
|
||
|
, details =
|
||
|
[ "I have trouble figuring out what kind of resource is linked here."
|
||
|
, "If it should link to a module, then they should be in the form 'Some-Module-Name'."
|
||
|
, "If it's a link to an external resource, they should start with a protocol, like `https://www.fruits.com`, otherwise the link will point to an unknown resource on package.elm-lang.org."
|
||
|
]
|
||
|
, under = "./image.png"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
linksWithAltTextTests : Test
|
||
|
linksWithAltTextTests =
|
||
|
describe "Alt text in links"
|
||
|
[ test "should report links to unknown modules in links with alt text after a slug" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](Unknown#section "alt-text")
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "Unknown#section"
|
||
|
}
|
||
|
]
|
||
|
, test "should ignore alt text in links with a slug" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](#b "alt-text")
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectNoErrors
|
||
|
, test "should report links to unknown modules in links with alt text without a slug" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](Unknown "alt-text")
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.run rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "Unknown"
|
||
|
}
|
||
|
]
|
||
|
, test "should report absolute links to unknown modules in links with alt text with a slug" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/Unknown "alt-text")
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "https://package.elm-lang.org/packages/author/package/1.0.0/Unknown"
|
||
|
}
|
||
|
]
|
||
|
, test "should report absolute links to unknown modules in links with alt text without a slug" <|
|
||
|
\() ->
|
||
|
"""module A exposing (a, b)
|
||
|
b = 1
|
||
|
|
||
|
{-| [link](https://package.elm-lang.org/packages/author/package/1.0.0/Unknown#section "alt-text")
|
||
|
-}
|
||
|
a = 2
|
||
|
"""
|
||
|
|> Review.Test.runWithProjectData packageProjectWithoutFiles rule
|
||
|
|> Review.Test.expectErrors
|
||
|
[ Review.Test.error
|
||
|
{ message = "Link points to non-existing module Unknown"
|
||
|
, details = [ "This is a dead link." ]
|
||
|
, under = "https://package.elm-lang.org/packages/author/package/1.0.0/Unknown#section"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
|
||
|
|
||
|
packageProject : Project
|
||
|
packageProject =
|
||
|
Project.addModule
|
||
|
{ path = "src/Exposed", source = "module Exposed exposing (exposed)\nexposed = 1" }
|
||
|
packageProjectWithoutFiles
|
||
|
|
||
|
|
||
|
packageProjectWithoutFiles : Project
|
||
|
packageProjectWithoutFiles =
|
||
|
case Json.Decode.decodeString Elm.Project.decoder elmJson of
|
||
|
Ok project ->
|
||
|
Project.new
|
||
|
|> Project.addElmJson
|
||
|
{ path = "elm.json"
|
||
|
, raw = elmJson
|
||
|
, project = project
|
||
|
}
|
||
|
|
||
|
Err err ->
|
||
|
Debug.todo ("Invalid elm.json supplied to test: " ++ Debug.toString err)
|
||
|
|
||
|
|
||
|
elmJson : String
|
||
|
elmJson =
|
||
|
"""{
|
||
|
"type": "package",
|
||
|
"name": "author/package",
|
||
|
"summary": "Summary",
|
||
|
"license": "BSD-3-Clause",
|
||
|
"version": "1.0.0",
|
||
|
"exposed-modules": [
|
||
|
"Exposed",
|
||
|
"Exposed2",
|
||
|
"Exposed3"
|
||
|
],
|
||
|
"elm-version": "0.19.0 <= v < 0.20.0",
|
||
|
"dependencies": {
|
||
|
"elm/core": "1.0.0 <= v < 2.0.0"
|
||
|
},
|
||
|
"test-dependencies": {}
|
||
|
}"""
|