module Network.JSONApi.ResourceSpec where import qualified Data.Aeson as AE import qualified Data.ByteString.Lazy.Char8 as BS import Data.Maybe (isJust, fromJust) import Data.Text (Text, pack) import GHC.Generics (Generic) import Network.JSONApi import TestHelpers (prettyEncode) import Test.Hspec main :: IO () main = hspec spec spec :: Spec spec = do describe "JSON serialization" $ it "can be encoded and decoded from JSON" $ do let encodedJson = BS.unpack . prettyEncode $ toResource testObject let decodedJson = AE.decode (BS.pack encodedJson) :: Maybe (Resource TestObject) isJust decodedJson `shouldBe` True describe "Self links" $ it "can be constructed for a single high level resource" $ do let links = showLink testObject links `shouldBe` mkLinks [ ("self", "/TestObject/1") ] describe "Index links" $ do it "should always start at page 0" $ do let links = indexLinks "/TestObject" $ Pagination (PageSize 10) (PageNum 1) (ResourceCount 20) links `shouldBe` mkLinks [ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10") , ("next","/TestObject?page%5Bnumber%5D=2&page%5Bsize%5D=10") , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("self","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")] it "should never have a negative prev page" $ do let links = indexLinks "/TestObject" $ Pagination (PageSize 10) (PageNum 0) (ResourceCount 20) links `shouldBe` mkLinks [ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10") , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10") , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")] it "should handle a page size of 0" $ do let links = indexLinks "/TestObject" $ Pagination (PageSize 0) (PageNum 0) (ResourceCount 2) links `shouldBe` mkLinks [ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1") , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1") , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")] it "should handle a negative page num" $ do let links = indexLinks "/TestObject" $ Pagination (PageSize 0) (PageNum $ -1) (ResourceCount 2) links `shouldBe` mkLinks [ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1") , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1") , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")] it "should handle a negative resource count" $ do let links = indexLinks "/TestObject" $ Pagination (PageSize 1) (PageNum 0) (ResourceCount $ -1) links `shouldBe` mkLinks [ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("last","/TestObject?page%5Bnumber%5D=-1&page%5Bsize%5D=1") , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1") , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1") , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")] it "should handle nested resource paths" $ do let links = indexLinks "/ParentObject/1/TestObject" $ Pagination (PageSize 10) (PageNum 1) (ResourceCount 20) links `shouldBe` mkLinks [ ("first","/ParentObject/1/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("last","/ParentObject/1/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10") , ("next","/ParentObject/1/TestObject?page%5Bnumber%5D=2&page%5Bsize%5D=10") , ("prev","/ParentObject/1/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10") , ("self","/ParentObject/1/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")] data TestObject = TestObject { myId :: Int , myName :: Text , myAge :: Int , myFavoriteFood :: Text } deriving (Show, Generic) instance AE.ToJSON TestObject instance AE.FromJSON TestObject instance ResourcefulEntity TestObject where resourceIdentifier = pack . show . myId resourceType _ = "TestObject" resourceLinks _ = Just myResourceLinks resourceMetaData _ = Just myResourceMetaData resourceRelationships _ = Nothing relationship :: Relationship relationship = fromJust $ mkRelationship (Just $ Identifier "42" "FriendOfTestObject" Nothing) (Just myResourceLinks) otherRelationship :: Relationship otherRelationship = fromJust $ mkRelationship (Just $ Identifier "49" "CousinOfTestObject" Nothing) (Just myResourceLinks) myResourceLinks :: Links myResourceLinks = mkLinks [ ("self", "/me") , ("related", "/tacos/4") ] myResourceMetaData :: Meta myResourceMetaData = mkMeta (Pagination (PageSize 1) (PageNum 1) (ResourceCount 14)) testObject :: TestObject testObject = TestObject 1 "Fred Armisen" 49 "Pizza"