{-# LANGUAGE QuasiQuotes #-} module GeneratorSpec where import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.Map as Map import TestImport type UserId = Int type NonEmptyUserId = NonEmpty UserId resources :: [ResourceTree String] resources = [parseRoutes| /api ApiP: /users/#UserId UsersR GET /users/#Int/foo UsersFooR GET /users/#NonEmptyUserId/bar UsersBarR GET /users/#Other/baz UsersBazR GET |] spec :: Spec spec = do describe "genFlowClasses" $ do it "should generate classes" $ do let classes = genFlowClasses Map.empty [] [] resources map className classes `shouldBe` [ "PATHS_TYPE_paths" , "PATHS_TYPE_paths_static_pages" , "PATHS_TYPE_paths_api" ] it "should identify path variable types" $ do let classes = genFlowClasses Map.empty [] [] resources apiClass = find ((== "PATHS_TYPE_paths_api") . className) classes map classMembers apiClass `shouldBe` Just [ Method "users" [ Path "api" , Path "users" , Dyn NumberT ] , Method "users_bar" [ Path "api" , Path "users" , Dyn (NonEmptyT NumberT) , Path "bar" ] , Method "users_baz" [ Path "api" , Path "users" , Dyn StringT , Path "baz" ] , Method "users_foo" [ Path "api" , Path "users" , Dyn NumberT , Path "foo" ] ] it "should respect overrides " $ do let classes = genFlowClasses (Map.fromList [("UserId", StringT)]) [] [] resources apiClass = find ((== "PATHS_TYPE_paths_api") . className) classes map classMembers apiClass `shouldBe` Just [ Method "users" [ Path "api" , Path "users" , Dyn StringT ] , Method "users_bar" [ Path "api" , Path "users" , Dyn (NonEmptyT StringT) , Path "bar" ] , Method "users_baz" [ Path "api" , Path "users" , Dyn StringT , Path "baz" ] , Method "users_foo" [ Path "api" , Path "users" , Dyn NumberT , Path "foo" ] ] describe "classesToFlow" $ do it "should generate formal parameters for each path variable" $ do let cls = [ Class "x" [ Method "y" [ Path "x" , Dyn StringT , Path "y" , Dyn NumberT , Path "z" , Dyn StringT ] ] ] normalizeText (classesToFlow cls) `shouldBe` normalizeText [st| class x { y(a: string, aa: number, aaa: string): string { return this.root + '/x/' + a + '/y/' + aa.toString() + '/z/' + aaa + ''; } root: string; constructor(root: string) { this.root = root; } } |] it "should avoid name shadowing in nested binders" $ do let cls = [ Class "x" [ Method "y" [ Path "x" , Dyn (NonEmptyT (NonEmptyT NumberT)) , Path "y" ] ] ] normalizeText (classesToFlow cls) `shouldBe` normalizeText [st| class x { y(a: Array>): string { return this.root + '/x/' + a.map(function(a1) { return a1.map(function(a2) { return a2.toString() }).join(',') }).join(',') + '/y'; } root: string; constructor(root: string) { this.root = root; } } |] describe "genFlowSource" $ it "should work end-to-end" $ do let source = genFlowSource Map.empty [] [] "'test'" resources normalizeText source `shouldBe` normalizeText [st| /* @flow */ class PATHS_TYPE_paths { api : PATHS_TYPE_paths_api; static_pages : PATHS_TYPE_paths_static_pages; root: string; constructor(root: string) { this.root = root; this.api = new PATHS_TYPE_paths_api(root); this.static_pages = new PATHS_TYPE_paths_static_pages(root); } } class PATHS_TYPE_paths_static_pages { root: string; constructor(root: string) { this.root = root; } } class PATHS_TYPE_paths_api { users(a: number): string { return this.root + '/api/users/' + a.toString() + ''; } users_bar(a: Array): string { return this.root + '/api/users/' + a.map(function(a1) { return a1.toString() }).join(',') + '/bar'; } users_baz(a: string): string { return this.root + '/api/users/' + a + '/baz'; } users_foo(a: number): string { return this.root + '/api/users/' + a.toString() + '/foo'; } root: string; constructor(root: string) { this.root = root; } } var PATHS: PATHS_TYPE_paths = new PATHS_TYPE_paths('test'); |]