2021-10-22 12:59:51 +03:00
|
|
|
{-# LANGUAGE TypeApplications #-}
|
|
|
|
|
2021-08-22 20:25:55 +03:00
|
|
|
module AnalyzerTest where
|
|
|
|
|
2021-10-22 12:59:51 +03:00
|
|
|
import Data.Either (isRight)
|
2021-08-22 20:25:55 +03:00
|
|
|
import Test.Tasty.Hspec
|
2021-11-11 15:26:20 +03:00
|
|
|
import Wasp.Analyzer
|
|
|
|
import qualified Wasp.Analyzer.TypeChecker as TC
|
2021-11-25 14:36:42 +03:00
|
|
|
import Wasp.AppSpec.Action (Action)
|
|
|
|
import qualified Wasp.AppSpec.Action as Action
|
2021-11-11 15:26:20 +03:00
|
|
|
import Wasp.AppSpec.App (App)
|
|
|
|
import qualified Wasp.AppSpec.App as App
|
2021-11-25 01:18:25 +03:00
|
|
|
import qualified Wasp.AppSpec.App.Auth as Auth
|
2021-11-25 16:02:26 +03:00
|
|
|
import qualified Wasp.AppSpec.App.Db as Db
|
|
|
|
import qualified Wasp.AppSpec.App.Server as Server
|
2021-11-11 15:26:20 +03:00
|
|
|
import Wasp.AppSpec.Core.Ref (Ref (..))
|
2021-11-25 01:18:25 +03:00
|
|
|
import Wasp.AppSpec.Entity (Entity)
|
|
|
|
import qualified Wasp.AppSpec.Entity as Entity
|
2021-11-25 12:47:50 +03:00
|
|
|
import Wasp.AppSpec.ExtImport (ExtImport (..), ExtImportName (..))
|
2021-11-25 14:57:46 +03:00
|
|
|
import Wasp.AppSpec.JSON (JSON (..))
|
2021-11-11 15:26:20 +03:00
|
|
|
import Wasp.AppSpec.Page (Page)
|
|
|
|
import qualified Wasp.AppSpec.Page as Page
|
2021-11-25 14:26:48 +03:00
|
|
|
import Wasp.AppSpec.Query (Query)
|
|
|
|
import qualified Wasp.AppSpec.Query as Query
|
2021-11-25 14:02:02 +03:00
|
|
|
import Wasp.AppSpec.Route (Route)
|
|
|
|
import qualified Wasp.AppSpec.Route as Route
|
2021-08-22 20:25:55 +03:00
|
|
|
|
|
|
|
spec_Analyzer :: Spec
|
|
|
|
spec_Analyzer = do
|
|
|
|
describe "Analyzer" $ do
|
|
|
|
it "Analyzes a well-typed example" $ do
|
|
|
|
let source =
|
|
|
|
unlines
|
|
|
|
[ "app Todo {",
|
|
|
|
" title: \"Todo App\",",
|
2021-11-25 01:18:25 +03:00
|
|
|
" head: [\"foo\", \"bar\"],",
|
|
|
|
" auth: {",
|
|
|
|
" userEntity: User,",
|
|
|
|
" methods: [EmailAndPassword],",
|
2021-11-25 14:57:46 +03:00
|
|
|
" },",
|
|
|
|
" dependencies: {=json",
|
|
|
|
" \"redux\": \"^4.0.5\"",
|
2021-11-25 16:02:26 +03:00
|
|
|
" json=},",
|
|
|
|
" server: {",
|
|
|
|
" setupFn: import { setupServer } from \"@ext/bar.js\"",
|
|
|
|
" },",
|
|
|
|
" db: {",
|
|
|
|
" system: PostgreSQL",
|
|
|
|
" }",
|
2021-10-22 12:59:51 +03:00
|
|
|
"}",
|
2021-11-25 01:18:25 +03:00
|
|
|
"",
|
|
|
|
"entity User {=psl test psl=}",
|
|
|
|
"",
|
2021-11-25 12:47:50 +03:00
|
|
|
"page HomePage {",
|
|
|
|
" component: import Home from \"@ext/pages/Main\"",
|
|
|
|
"}",
|
|
|
|
"",
|
|
|
|
"page ProfilePage {",
|
|
|
|
" component: import { profilePage } from \"@ext/pages/Profile\",",
|
|
|
|
" authRequired: true",
|
2021-11-25 14:02:02 +03:00
|
|
|
"}",
|
|
|
|
"",
|
2021-11-25 14:26:48 +03:00
|
|
|
"route HomeRoute { path: \"/\", page: HomePage }",
|
|
|
|
"",
|
|
|
|
"query getUsers {",
|
|
|
|
" fn: import { getAllUsers } from \"@ext/foo.js\",",
|
|
|
|
" entities: [User]",
|
2021-11-25 14:36:42 +03:00
|
|
|
"}",
|
|
|
|
"",
|
|
|
|
"action updateUser {",
|
|
|
|
" fn: import { updateUser } from \"@ext/foo.js\",",
|
|
|
|
" entities: [User],",
|
|
|
|
" auth: true",
|
2021-11-25 14:26:48 +03:00
|
|
|
"}"
|
2021-10-22 12:59:51 +03:00
|
|
|
]
|
2021-11-25 14:26:48 +03:00
|
|
|
|
2021-10-22 12:59:51 +03:00
|
|
|
let decls = analyze source
|
2021-11-25 14:26:48 +03:00
|
|
|
|
2021-11-10 18:27:27 +03:00
|
|
|
let expectedApps =
|
|
|
|
[ ( "Todo",
|
|
|
|
App.App
|
|
|
|
{ App.title = "Todo App",
|
2021-11-25 01:18:25 +03:00
|
|
|
App.head = Just ["foo", "bar"],
|
|
|
|
App.auth =
|
|
|
|
Just
|
|
|
|
Auth.Auth
|
|
|
|
{ Auth.userEntity = Ref "User" :: Ref Entity,
|
|
|
|
Auth.methods = [Auth.EmailAndPassword],
|
|
|
|
Auth.onAuthFailedRedirectTo = Nothing
|
2021-11-25 14:57:46 +03:00
|
|
|
},
|
2021-11-25 16:02:26 +03:00
|
|
|
App.dependencies = Just $ JSON "\n \"redux\": \"^4.0.5\"\n ",
|
|
|
|
App.server =
|
|
|
|
Just
|
|
|
|
Server.Server
|
|
|
|
{ Server.setupFn = Just $ ExtImport (ExtImportField "setupServer") "@ext/bar.js"
|
|
|
|
},
|
|
|
|
App.db = Just Db.Db {Db.system = Just Db.PostgreSQL}
|
2021-11-10 18:27:27 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
]
|
2021-10-22 12:59:51 +03:00
|
|
|
takeDecls @App <$> decls `shouldBe` Right expectedApps
|
2021-11-25 14:26:48 +03:00
|
|
|
|
2021-11-10 18:27:27 +03:00
|
|
|
let expectedPages =
|
|
|
|
[ ( "HomePage",
|
|
|
|
Page.Page
|
2021-11-25 12:47:50 +03:00
|
|
|
{ Page.component = ExtImport (ExtImportModule "Home") "@ext/pages/Main",
|
|
|
|
Page.authRequired = Nothing
|
|
|
|
}
|
|
|
|
),
|
|
|
|
( "ProfilePage",
|
|
|
|
Page.Page
|
|
|
|
{ Page.component = ExtImport (ExtImportField "profilePage") "@ext/pages/Profile",
|
|
|
|
Page.authRequired = Just True
|
2021-11-10 18:27:27 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
]
|
2021-10-22 12:59:51 +03:00
|
|
|
takeDecls @Page <$> decls `shouldBe` Right expectedPages
|
2021-11-25 14:26:48 +03:00
|
|
|
|
2021-11-25 01:18:25 +03:00
|
|
|
let expectedEntities =
|
|
|
|
[ ( "User",
|
|
|
|
Entity.Entity (Entity.PSL " test ")
|
|
|
|
)
|
|
|
|
]
|
|
|
|
takeDecls @Entity <$> decls `shouldBe` Right expectedEntities
|
2021-10-22 12:59:51 +03:00
|
|
|
|
2021-11-25 14:02:02 +03:00
|
|
|
let expectedRoutes =
|
|
|
|
[ ( "HomeRoute",
|
|
|
|
Route.Route {Route.path = "/", Route.page = Ref "HomePage"}
|
|
|
|
)
|
|
|
|
]
|
|
|
|
takeDecls @Route <$> decls `shouldBe` Right expectedRoutes
|
|
|
|
|
2021-11-25 14:26:48 +03:00
|
|
|
let expectedQueries =
|
|
|
|
[ ( "getUsers",
|
|
|
|
Query.Query
|
|
|
|
{ Query.fn = ExtImport (ExtImportField "getAllUsers") "@ext/foo.js",
|
2021-11-25 14:36:42 +03:00
|
|
|
Query.entities = Just [Ref "User"],
|
|
|
|
Query.auth = Nothing
|
2021-11-25 14:26:48 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
]
|
|
|
|
takeDecls @Query <$> decls `shouldBe` Right expectedQueries
|
|
|
|
|
2021-11-25 14:36:42 +03:00
|
|
|
let expectedAction =
|
|
|
|
[ ( "updateUser",
|
|
|
|
Action.Action
|
|
|
|
{ Action.fn = ExtImport (ExtImportField "updateUser") "@ext/foo.js",
|
|
|
|
Action.entities = Just [Ref "User"],
|
|
|
|
Action.auth = Just True
|
|
|
|
}
|
|
|
|
)
|
|
|
|
]
|
|
|
|
takeDecls @Action <$> decls `shouldBe` Right expectedAction
|
|
|
|
|
2021-10-22 12:59:51 +03:00
|
|
|
it "Returns a type error if unexisting declaration is referenced" $ do
|
|
|
|
let source =
|
|
|
|
unlines
|
2021-11-25 14:02:02 +03:00
|
|
|
[ "route HomeRoute { path: \"/\", page: NonExistentPage }"
|
2021-08-22 20:25:55 +03:00
|
|
|
]
|
2021-11-25 14:02:02 +03:00
|
|
|
takeDecls @Route <$> analyze source `shouldBe` Left (TypeError $ TC.UndefinedIdentifier "NonExistentPage")
|
2021-10-22 12:59:51 +03:00
|
|
|
|
|
|
|
it "Returns a type error if referenced declaration is of wrong type" $ do
|
|
|
|
let source =
|
|
|
|
unlines
|
2021-11-25 14:02:02 +03:00
|
|
|
[ "route HomeRoute { path: \"/\", page: HomeRoute }"
|
2021-10-22 12:59:51 +03:00
|
|
|
]
|
2021-11-25 14:02:02 +03:00
|
|
|
takeDecls @Route <$> analyze source `shouldSatisfy` isAnalyzerOutputTypeError
|
2021-10-22 12:59:51 +03:00
|
|
|
|
|
|
|
it "Works when referenced declaration is declared after the reference." $ do
|
|
|
|
let source =
|
|
|
|
unlines
|
2021-11-25 14:02:02 +03:00
|
|
|
[ "route HomeRoute { path: \"/\", page: HomePage }",
|
|
|
|
"page HomePage { component: import Home from \"@ext/HomePage.js\" }"
|
2021-10-22 12:59:51 +03:00
|
|
|
]
|
|
|
|
isRight (analyze source) `shouldBe` True
|
|
|
|
|
|
|
|
isAnalyzerOutputTypeError :: Either AnalyzeError a -> Bool
|
|
|
|
isAnalyzerOutputTypeError (Left (TypeError _)) = True
|
|
|
|
isAnalyzerOutputTypeError _ = False
|