content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE QuasiQuotes #-}
  import Test.Hspec
  
  import JsonToHaskell
  import Data.Maybe
  import Data.Aeson
  import qualified Data.ByteString.Lazy as BL
  import qualified Data.ByteString.Lazy.Char8 as BC
  import qualified Data.Text as T
  import Text.RawString.QQ (r)
  
  shouldRender :: BL.ByteString -> T.Text -> Expectation
  shouldRender inp out =
      (jsonToHaskell simpleOptions{_includeHeader=False, _includeInstances=False} (fromMaybe (error $ "bad json: " <> BC.unpack inp) $ decode inp))
        `shouldBe` T.strip out
  
  
  main :: IO ()
  main = hspec spec
  
  -- TODO: Should probably alphabetize records internally to ensure consistent order.
  spec :: Spec
  spec = do
      describe "analyze" $ do
          it "should build a record with all types" $ do
                  [r|
  { "a": 1
  , "b": "hi"
  , "c": [null]
  , "d": 2.5
  }
                  |]
                 `shouldRender`
                  [r|
  data Model = Model
    { modelA :: Double
    , modelD :: Double
    , modelB :: Text
    , modelC :: [Maybe Value]
    } deriving (Show, Eq, Ord)
                  |]
          it "should share records definitions for identical subrecords" $ do
                  [r|
  { "a": { "name": "bob", "age": 20 }
  , "b": { "name": "alice", "age": 22 }
  }
                  |]
                 `shouldRender`
                  [r|
  data A = A
    { aAge :: Double
    , aName :: Text
    } deriving (Show, Eq, Ord)
  
  data Model = Model
    { modelA :: A
    , modelB :: A
    } deriving (Show, Eq, Ord)
                  |]
          it "should pick good names for differing records which share field names" $ do
                  [r|
  { "a": { "field": {"name": "bob" } }
  , "b": { "field": {"age": 22 } }
  }
                  |]
                 `shouldRender`
                  [r|
  data A = A
    { aField :: Field
    } deriving (Show, Eq, Ord)
  
  data B = B
    { bField :: Field2
    } deriving (Show, Eq, Ord)
  
  data Field = Field
    { fieldName :: Text
    } deriving (Show, Eq, Ord)
  
  data Field2 = Field2
    { field2Age :: Double
    } deriving (Show, Eq, Ord)
  
  data Model = Model
    { modelA :: A
    , modelB :: B
    } deriving (Show, Eq, Ord)
                  |]
          it "should pick the best name if there are multiple possible names but some conflict" $ do
                  [r|
  { "a": { "field": {"name": "bob" } }
  , "b": { "field": {"age": 22 } }
  , "c": { "other": {"age": 22 } }
  }
                  |]
                 `shouldRender`
                  [r|
  data A = A
    { aField :: Field
    } deriving (Show, Eq, Ord)
  
  data B = B
    { bField :: Other
    } deriving (Show, Eq, Ord)
  
  data C = C
    { cOther :: Other
    } deriving (Show, Eq, Ord)
  
  data Field = Field
    { fieldName :: Text
    } deriving (Show, Eq, Ord)
  
  data Model = Model
    { modelA :: A
    , modelB :: B
    , modelC :: C
    } deriving (Show, Eq, Ord)
  
  data Other = Other
    { otherAge :: Double
    } deriving (Show, Eq, Ord)
                  |]
  
          it "should sanitize weird field and record names" $ do
                  [r|
  { "'t\"!h.*#e nam9e": {"'9sub--field": "bob" }
  }
                  |]
                 `shouldRender`
                  [r|
  data Model = Model
    { modelTheNam9e :: TheNam9e
    } deriving (Show, Eq, Ord)
  
  data TheNam9e = TheNam9e
    { theNam9eSubField :: Text
    } deriving (Show, Eq, Ord)
                  |]
  