1{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE ViewPatterns #-}
3{-# LANGUAGE DataKinds #-}
10import Data.Version (Version(..))
13import Data.Maybe (fromMaybe)
14import Data.List ((\\))
16import qualified Data.Text as T
19import qualified Language.PureScript as P
20import qualified Language.PureScript.Docs as Docs
21import Language.PureScript.Docs.AsMarkdown (codeToString)
22import qualified Language.PureScript.Publish as Publish
23import qualified Language.PureScript.Publish.ErrorsWarnings as Publish
27publishOpts :: Publish.PublishOptions
28publishOpts = Publish.defaultPublishOptions
29 { Publish.publishGetVersion = return testVersion
30 , Publish.publishWorkingTreeDirty = return ()
32 where testVersion = ("v999.0.0", Version [999,0,0] [])
35main = pushd "examples/docs" $ do
36 res <- Publish.preparePackage publishOpts
38 Left e -> Publish.printErrorToStdout e >> exitFailure
39 Right Docs.Package{..} ->
40 forM_ testCases $ \(P.moduleNameFromString . T.pack -> mn, pragmas) ->
41 let mdl = takeJust ("module not found in docs: " ++ T.unpack (P.runModuleName mn))
42 (find ((==) mn . Docs.modName) pkgModules)
43 in forM_ pragmas (`runAssertionIO` mdl)
46takeJust :: String -> Maybe a -> a
47takeJust msg = fromMaybe (error msg)
50 -- | Assert that a particular declaration is documented with the given
52 = ShouldBeDocumented P.ModuleName String [String]
53 -- | Assert that a particular declaration is not documented
54 | ShouldNotBeDocumented P.ModuleName String
55 -- | Assert that a particular declaration exists, but without a particular
57 | ChildShouldNotBeDocumented P.ModuleName String String
58 -- | Assert that a particular declaration has a particular type class
60 | ShouldBeConstrained P.ModuleName String String
61 -- | Assert that a particular typeclass declaration has a functional
63 | ShouldHaveFunDeps P.ModuleName String [([String],[String])]
64 -- | Assert that a particular value declaration exists, and its type
65 -- satisfies the given predicate.
66 | ValueShouldHaveTypeSignature P.ModuleName String (ShowFn (P.Type -> Bool))
67 -- | Assert that a particular type alias exists, and its corresponding
68 -- type, when rendered, matches a given string exactly
69 -- fields: module, type synonym name, expected type
70 | TypeSynonymShouldRenderAs P.ModuleName String String
73newtype ShowFn a = ShowFn a
75instance Show (ShowFn a) where
79 -- | A declaration was not documented, but should have been
80 = NotDocumented P.ModuleName String
81 -- | A child declaration was not documented, but should have been
82 | ChildrenNotDocumented P.ModuleName String [String]
83 -- | A declaration was documented, but should not have been
84 | Documented P.ModuleName String
85 -- | A child declaration was documented, but should not have been
86 | ChildDocumented P.ModuleName String String
87 -- | A constraint was missing.
88 | ConstraintMissing P.ModuleName String String
89 -- | A functional dependency was missing.
90 | FunDepMissing P.ModuleName String [([String], [String])]
91 -- | A declaration had the wrong "type" (ie, value, type, type class)
92 -- Fields: declaration title, expected "type", actual "type".
93 | WrongDeclarationType P.ModuleName String String String
94 -- | A value declaration had the wrong type (in the sense of "type
95 -- checking"), eg, because the inferred type was used when the explicit type
97 -- Fields: module name, declaration name, actual type.
98 | ValueDeclarationWrongType P.ModuleName String P.Type
99 -- | A Type synonym has been rendered in an unexpected format
100 -- Fields: module name, declaration name, expected rendering, actual rendering
101 | TypeSynonymMismatch P.ModuleName String String String
106 | Fail AssertionFailure
109runAssertion :: Assertion -> Docs.Module -> AssertionResult
110runAssertion assertion Docs.Module{..} =
112 ShouldBeDocumented mn decl children ->
113 case findChildren decl (declarationsFor mn) of
115 Fail (NotDocumented mn decl)
116 Just actualChildren ->
117 case children \\ actualChildren of
119 cs -> Fail (ChildrenNotDocumented mn decl cs)
121 ShouldNotBeDocumented mn decl ->
122 case findChildren decl (declarationsFor mn) of
124 Fail (Documented mn decl)
128 ChildShouldNotBeDocumented mn decl child ->
129 case findChildren decl (declarationsFor mn) of
131 if child `elem` children
132 then Fail (ChildDocumented mn decl child)
135 Fail (NotDocumented mn decl)
137 ShouldBeConstrained mn decl tyClass ->
138 case find ((==) decl . Docs.declTitle) (declarationsFor mn) of
140 Fail (NotDocumented mn decl)
141 Just Docs.Declaration{..} ->
143 Docs.ValueDeclaration ty ->
144 if checkConstrained ty tyClass
146 else Fail (ConstraintMissing mn decl tyClass)
148 Fail (WrongDeclarationType mn decl "value"
149 (Docs.declInfoToString declInfo))
151 ShouldHaveFunDeps mn decl fds ->
152 case find ((==) decl . Docs.declTitle) (declarationsFor mn) of
154 Fail (NotDocumented mn decl)
155 Just Docs.Declaration{..} ->
157 Docs.TypeClassDeclaration _ _ fundeps ->
160 else Fail (FunDepMissing mn decl fds)
162 Fail (WrongDeclarationType mn decl "value"
163 (Docs.declInfoToString declInfo))
165 ValueShouldHaveTypeSignature mn decl (ShowFn tyPredicate) ->
166 case find ((==) decl . Docs.declTitle) (declarationsFor mn) of
168 Fail (NotDocumented mn decl)
169 Just Docs.Declaration{..} ->
171 Docs.ValueDeclaration ty ->
175 (ValueDeclarationWrongType mn decl ty)
177 Fail (WrongDeclarationType mn decl "value"
178 (Docs.declInfoToString declInfo))
180 TypeSynonymShouldRenderAs mn decl expected ->
181 case find ((==) decl . Docs.declTitle) (declarationsFor mn) of
183 Fail (NotDocumented mn decl)
184 Just Docs.Declaration{..} ->
186 Docs.TypeSynonymDeclaration [] ty ->
187 let actual = codeToString (Docs.renderType ty) in
188 if actual == expected
190 else Fail (TypeSynonymMismatch mn decl expected actual)
192 Fail (WrongDeclarationType mn decl "synonym"
193 (Docs.declInfoToString declInfo))
199 else fromMaybe [] (lookup mn modReExports)
202 fmap childrenTitles . find ((==) title . Docs.declTitle)
204 childrenTitles = map Docs.cdeclTitle . Docs.declChildren
206checkConstrained :: P.Type -> String -> Bool
207checkConstrained ty tyClass =
208 -- Note that we don't recurse on ConstrainedType if none of the constraints
209 -- match; this is by design, as constraints should be moved to the front
212 P.ConstrainedType cs _ | any (matches tyClass) cs ->
215 checkConstrained ty' tyClass
220 (==) className . T.unpack . P.runProperName . P.disqualify . P.constraintClass
222runAssertionIO :: Assertion -> Docs.Module -> IO ()
223runAssertionIO assertion mdl = do
224 putStrLn ("In " ++ T.unpack (P.runModuleName (Docs.modName mdl)) ++ ": " ++ show assertion)
225 case runAssertion assertion mdl of
228 putStrLn ("Failed: " <> show reason)
231testCases :: [(String, [Assertion])]
234 [ -- From dependencies
235 ShouldBeDocumented (n "Prelude") "Unit" []
236 , ShouldNotBeDocumented (n "Prelude") "unit"
239 , ShouldBeDocumented (n "Example2") "one" []
240 , ShouldNotBeDocumented (n "Example2") "two"
243 [ ShouldBeDocumented (n "Example2") "one" []
244 , ShouldBeDocumented (n "Example2") "two" []
248 [ ShouldBeDocumented (n "UTF8") "thing" []
252 [ ShouldBeDocumented (n "Transitive2") "transitive3" []
256 [ ShouldBeDocumented (n "Prelude") "Boolean2" ["True"]
257 , ChildShouldNotBeDocumented (n "Prelude") "Boolean2" "False"
261 [ ShouldBeDocumented (n "Prelude") "Unit" []
262 , ShouldBeDocumented (n "DuplicateNames") "unit" []
263 , ShouldNotBeDocumented (n "Prelude") "unit"
267 [ ShouldBeDocumented (n "MultiVirtual1") "foo" []
268 , ShouldBeDocumented (n "MultiVirtual2") "bar" []
269 , ShouldBeDocumented (n "MultiVirtual2") "baz" []
273 [ ShouldBeDocumented (n "Clash1") "value" []
274 , ShouldBeDocumented (n "Clash1") "Type" []
275 , ShouldBeDocumented (n "Clash1") "TypeClass" ["typeClassMember"]
278 , ("SolitaryTypeClassMember",
279 [ ShouldBeDocumented (n "SomeTypeClass") "member" []
280 , ShouldNotBeDocumented (n "SomeTypeClass") "SomeClass"
281 , ShouldBeConstrained (n "SomeTypeClass") "member" "SomeClass"
284 , ("ReExportedTypeClass",
285 [ ShouldBeDocumented (n "SomeTypeClass") "SomeClass" ["member"]
288 , ("TypeClassWithoutMembers",
289 [ ShouldBeDocumented (n "TypeClassWithoutMembersIntermediate") "SomeClass" []
290 , ChildShouldNotBeDocumented (n "TypeClassWithoutMembersIntermediate") "SomeClass" "member"
293 , ("TypeClassWithFunDeps",
294 [ ShouldHaveFunDeps (n "TypeClassWithFunDeps") "TypeClassWithFunDeps" [(["a","b"], ["c"]), (["c"], ["d","e"])]
298 [ ShouldBeDocumented (n "NewOperators2") "(>>>)" []
301 , ("ExplicitTypeSignatures",
302 [ ValueShouldHaveTypeSignature (n "ExplicitTypeSignatures") "explicit" (ShowFn (hasTypeVar "something"))
303 , ValueShouldHaveTypeSignature (n "ExplicitTypeSignatures") "anInt" (ShowFn (P.tyInt ==))
304 , ValueShouldHaveTypeSignature (n "ExplicitTypeSignatures") "aNumber" (ShowFn (P.tyNumber ==))
305 , ValueShouldHaveTypeSignature (n "ExplicitTypeSignatures") "nestedForAll" (renderedType "forall c. (forall a b. c)")
308 , ("ConstrainedArgument",
309 [ TypeSynonymShouldRenderAs (n "ConstrainedArgument") "WithoutArgs" "forall a. (Partial => a) -> a"
310 , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "WithArgs" "forall a. (Foo a => a) -> a"
311 , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithoutArgs" "forall a. ((Partial, Partial) => a) -> a"
312 , TypeSynonymShouldRenderAs (n "ConstrainedArgument") "MultiWithArgs" "forall a b. ((Foo a, Foo b) => a) -> a"
316 [ ValueShouldHaveTypeSignature (n "TypeOpAliases") "test1" (renderedType "forall a b. a ~> b")
317 , ValueShouldHaveTypeSignature (n "TypeOpAliases") "test2" (renderedType "forall a b c. a ~> b ~> c")
318 , ValueShouldHaveTypeSignature (n "TypeOpAliases") "test3" (renderedType "forall a b c d. a ~> (b ~> c) ~> d")
319 , ValueShouldHaveTypeSignature (n "TypeOpAliases") "test4" (renderedType "forall a b c d. ((a ~> b) ~> c) ~> d")
320 , ValueShouldHaveTypeSignature (n "TypeOpAliases") "third" (renderedType "forall a b c. a × b × c -> c")
325 n = P.moduleNameFromString . T.pack
328 getAny . P.everythingOnTypes (<>) (Any . isVar varName)
330 isVar varName (P.TypeVar name) | varName == T.unpack name = True
333 renderedType expected =
334 ShowFn $ \ty -> codeToString (Docs.renderType ty) == expected
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list