{-# LANGUAGE OverloadedStrings #-} module Boilerplate.InterpreterTests where import Boilerplate.Interpreter import Boilerplate.RuleParserTests (fromJSONRule, toJSONRule) import Boilerplate.Types import Data.Map.Strict (Map) import qualified Data.Map.Strict as M import Data.Text (Text) import HsInspect.Types (Type(..)) import Test.Tasty.Hspec -- data Coord = Coordy Double Double egProduct :: Type egProduct = ProductType "Coord" [] False "Coordy" [("Double", []), ("Double", [])] -- data Coord = Coordy { a :: Double, b :: Double} egRecord :: Type egRecord = RecordType "Coord" [] False "Coordy" [("a", "Double", []), ("b", "Double", [])] -- data Union = Wales String | England Int Int | Scotland egSum :: Type egSum = SumType "Union" [] [("Wales", [("String", [])]), ("England", [("Int", []), ("Int", [])]), ("Scotland", [])] -- data Things a b = T a b Double egPolyProduct :: Type egPolyProduct = ProductType "Things" ["a", "b"] False "T" [("a", ["a"]), ("b", ["b"]), ("Double", [])] -- data Logger m = Logger { log :: Text -> m () } egPolyRecord :: Type egPolyRecord = RecordType "Logger" ["m"] False "Logger" [("log", "Text -> m ()", ["m"])] -- data Action a = Admin [a] Text | User a Text egPolySum :: Type egPolySum = SumType "Action" ["a"] [("Admin", [("[a]", ["a"]), ("Text", [])]), ("User", [("a", ["a"]), ("Text", [])])] custom :: Text -> Custom -> Map Text Custom custom key value = M.fromList [(key, value)] spec_interpreter :: Spec spec_interpreter = do it "should interpret ToJSON for products" $ do let options = custom "field" $ Indexed ["x", "y"] interpretRule toJSONRule egProduct options `shouldBe` Right "instance ToJSON Coord where\n\ \ toJSON (Coordy p_1_1 p_1_2) = object [\"x\" .= p_1_1, \"y\" .= p_1_2]\n\ \ toEncoding (Coordy p_1_1 p_1_2) = pairs (\"x\" .= p_1_1 <> \"y\" .= p_1_2)" it "should interpret FromJSON for products" $ do let options = custom "field" $ Indexed ["x", "y"] interpretRule fromJSONRule egProduct options `shouldBe` Right "instance FromJSON Coord where\n\ \ parseJSON = withObject \"Coord\" $ \\v ->\n\ \ Coordy <$> v .: \"x\" <*> v .: \"y\"" it "should interpret FromJSON for records" $ do interpretRule fromJSONRule egRecord M.empty `shouldBe` Right "instance FromJSON Coord where\n\ \ parseJSON = withObject \"Coord\" $ \\v ->\n\ \ Coordy <$> v .: \"a\" <*> v .: \"b\"" it "should interpret ToJSON for polymorphic products" $ do let options = custom "field" $ Indexed ["x", "y", "z"] interpretRule toJSONRule egPolyProduct options `shouldBe` Right "instance (ToJSON a, ToJSON b) => ToJSON (Things a b) where\n\ \ toJSON (T p_1_1 p_1_2 p_1_3) = object [\"x\" .= p_1_1, \"y\" .= p_1_2, \"z\" .= p_1_3]\n\ \ toEncoding (T p_1_1 p_1_2 p_1_3) = pairs (\"x\" .= p_1_1 <> \"y\" .= p_1_2 <> \"z\" .= p_1_3)" it "should interpret ToJSON for polymorphic sum" $ do let options = custom "field" $ Indexed ["x", "y", "z"] interpretRule toJSONRule egPolySum options `shouldBe` Right "instance (ToJSON a) => ToJSON (Action a) where\n\ \ toJSON (Admin p_1_1 p_1_2) = object [\"Admin\" .= object [\"x\" .= p_1_1, \"y\" .= p_1_2]]\n\ \ toJSON (User p_1_1 p_1_2) = object [\"User\" .= object [\"x\" .= p_1_1, \"y\" .= p_1_2]]\n\ \ toEncoding (Admin p_1_1 p_1_2) = pairs . pair \"Admin\" $ pairs (\"x\" .= p_1_1 <> \"y\" .= p_1_2 :: Series)\n\ \ toEncoding (User p_1_1 p_1_2) = pairs . pair \"User\" $ pairs (\"x\" .= p_1_1 <> \"y\" .= p_1_2 :: Series)" it "should interpret ToJSON for records without custom" $ do interpretRule toJSONRule egRecord M.empty `shouldBe` Right "instance ToJSON Coord where\n\ \ toJSON (Coordy p_1_1 p_1_2) = object [\"a\" .= p_1_1, \"b\" .= p_1_2]\n\ \ toEncoding (Coordy p_1_1 p_1_2) = pairs (\"a\" .= p_1_1 <> \"b\" .= p_1_2)" it "should interpret ToJSON for records with custom" $ do let options = custom "field" . Named $ M.fromList [("a", "aa"), ("b", "bb")] interpretRule toJSONRule egRecord options `shouldBe` Right "instance ToJSON Coord where\n\ \ toJSON (Coordy p_1_1 p_1_2) = object [\"aa\" .= p_1_1, \"bb\" .= p_1_2]\n\ \ toEncoding (Coordy p_1_1 p_1_2) = pairs (\"aa\" .= p_1_1 <> \"bb\" .= p_1_2)" it "should interpret ToJSON for sum types" $ do let options = custom "field" . NamedIndexed $ M.fromList [("Wales", ["foo"]), ("England", ["a", "b"]), ("Scotland", [])] interpretRule toJSONRule egSum options `shouldBe` Right "instance ToJSON Union where\n\ \ toJSON (Wales p_1_1) = object [\"Wales\" .= object [\"foo\" .= p_1_1]]\n\ \ toJSON (England p_1_1 p_1_2) = object [\"England\" .= object [\"a\" .= p_1_1, \"b\" .= p_1_2]]\n\ \ toJSON Scotland = object [\"Scotland\" .= object []]\n\ \ toEncoding (Wales p_1_1) = pairs . pair \"Wales\" $ pairs (\"foo\" .= p_1_1 :: Series)\n\ \ toEncoding (England p_1_1 p_1_2) = pairs . pair \"England\" $ pairs (\"a\" .= p_1_1 <> \"b\" .= p_1_2 :: Series)\n\ \ toEncoding Scotland = pairs . pair \"Scotland\" $ emptyObject_" it "should interpret FromJSON for sum types" $ do let options = custom "field" . NamedIndexed $ M.fromList [("Wales", ["foo"]), ("England", ["a", "b"]), ("Scotland", [])] interpretRule fromJSONRule egSum options `shouldBe` Right "instance FromJSON Union where\n\ \ parseJSON = withObject \"Union\" $ \\v ->\n\ \ let withField key parse = (maybe (fail \"\") pure $ H.lookup key v) >>= (withObject (T.unpack key) parse)\n\ \ in (withField \"Wales\" $ \\v' -> Wales <$> v' .: \"foo\")\n\ \ <|> (withField \"England\" $ \\v' -> England <$> v' .: \"a\" <*> v' .: \"b\")\n\ \ <|> (withField \"Scotland\" $ \\_ -> pure Scotland)\n\ \ <|> (fail \"no valid type constructor tags\")" it "should interpret ToJSON for sum types, extra options" $ do let options = M.fromList [("field", NamedIndexed $ M.fromList [("Wales", ["foo"]), ("England", ["a", "b"]), ("Scotland", [])]), ("tag", Named $ M.fromList [("Wales", "dragon"), ("England", "lion"), ("Scotland", "unicorn")])] interpretRule toJSONRule egSum options `shouldBe` Right "instance ToJSON Union where\n\ \ toJSON (Wales p_1_1) = object [\"dragon\" .= object [\"foo\" .= p_1_1]]\n\ \ toJSON (England p_1_1 p_1_2) = object [\"lion\" .= object [\"a\" .= p_1_1, \"b\" .= p_1_2]]\n\ \ toJSON Scotland = object [\"unicorn\" .= object []]\n\ \ toEncoding (Wales p_1_1) = pairs . pair \"dragon\" $ pairs (\"foo\" .= p_1_1 :: Series)\n\ \ toEncoding (England p_1_1 p_1_2) = pairs . pair \"lion\" $ pairs (\"a\" .= p_1_1 <> \"b\" .= p_1_2 :: Series)\n\ \ toEncoding Scotland = pairs . pair \"unicorn\" $ emptyObject_"