packages feed

fb-0.2.1: tests/runtests.hs

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.Text (Text)
import Data.Time (parseTime)
import System.Environment (getEnv)
import System.Exit (exitFailure)
import System.IO.Error (isDoesNotExistError)

import qualified Data.Aeson as A
import qualified Data.Aeson.Types as A
import qualified Data.ByteString.Char8 as B
import qualified Control.Exception.Lifted as E
import qualified Data.Conduit as C
import qualified Facebook as FB
import qualified Facebook.OpenGraph as FBOG
import qualified Network.HTTP.Conduit as H

import Test.HUnit
import Test.Hspec.Core (Example(..))
import Test.Hspec.Monadic
-- import Test.Hspec.QuickCheck
import Test.Hspec.HUnit ()


-- | Grab the Facebook credentials from the environment.
getCredentials :: IO FB.Credentials
getCredentials = tryToGet `E.catch` showHelp
    where
      tryToGet = do
        [appId, appSecret] <- mapM getEnv ["APP_ID", "APP_SECRET"]
        return $ FB.Credentials (B.pack appId) (B.pack appSecret)

      showHelp exc | not (isDoesNotExistError exc) = E.throw exc
      showHelp _ = do
        putStrLn $ unlines
          [ "In order to run the tests from the 'fb' package, you need"
          , "developer access to a Facebook app.  The tests are designed"
          , "so that your app isn't going to be hurt, but we may not"
          , "create a Facebook app for this purpose and then distribute"
          , "its secret keys in the open."
          , ""
          , "Please give your app id and app secret on the enviroment"
          , "variables APP_ID and APP_SECRET, respectively.  For example,"
          , "before running the test you could run in the shell:"
          , ""
          , "  $ export APP_ID=\"458798571203498\""
          , "  $ export APP_SECRET=\"28a9d0fa4272a14a9287f423f90a48f2304\""
          , ""
          , "Of course, the values above aren't valid and you need to"
          , "replace them with your own."
          , ""
          , "(Exiting now with a failure code.)"]
        exitFailure


invalidCredentials :: FB.Credentials
invalidCredentials = FB.Credentials "not" "valid"

invalidUserAccessToken :: FB.AccessToken FB.User
invalidUserAccessToken = FB.UserAccessToken "invalid" farInTheFuture
    where
      Just farInTheFuture = parseTime (error "farInTheFuture") "%Y" "3000"
      -- It's actually important to use 'farInTheFuture' since we
      -- don't want any tests rejecting this invalid user access
      -- token before even giving it to Facebook.

invalidAppAccessToken :: FB.AccessToken FB.App
invalidAppAccessToken = FB.AppAccessToken "invalid"


main :: IO ()
main = H.withManager $ \manager -> liftIO $ do
  creds <- getCredentials
  hspecX $ do
    describe "Facebook.getAppAccessToken" $ do
      it "works and returns a valid app access token" $ do
        token <- FB.getAppAccessToken creds manager
        valid <- FB.isValid token manager
        liftIO (valid @?= True)
      it "throws a FacebookException on invalid credentials" $ do
        ret <- E.try $ FB.getAppAccessToken invalidCredentials manager
        case ret  of
          Right token                      -> fail $ show token
          Left (_ :: FB.FacebookException) -> return ()

    describe "Facebook.isValid" $ do
      it "returns False on a clearly invalid user access token" $ do
        valid <- FB.isValid invalidUserAccessToken manager
        liftIO (valid @?= False)
      it "returns False on a clearly invalid app access token" $ do
        valid <- FB.isValid invalidAppAccessToken manager
        liftIO (valid @?= False)

    describe "Facebook.OpenGraph.getObject" $ do
      it "is able to fetch Facebook's own page" $ do
        A.Object obj <- FBOG.getObject "/19292868552" [] Nothing manager
        let Just r = flip A.parseMaybe () $ const $
                     (,,) <$> obj A..:? "id"
                          <*> obj A..:? "website"
                          <*> obj A..:? "name"
            just x = Just (x :: Text)
        liftIO $ r @?= ( just "19292868552"
                       , just "http://developers.facebook.com"
                       , just "Facebook Platform" )


-- | Sad, orphan instance.
instance (m ~ IO, r ~ ()) => Example (C.ResourceT m r) where
    evaluateExample = evaluateExample . C.runResourceT