fb-0.3: tests/runtests.hs
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Trans.Class (lift)
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 Facebook as FB
import qualified Network.HTTP.Conduit as H
import qualified Test.HUnit as HU
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
[appName, appId, appSecret] <- mapM getEnv ["APP_NAME", "APP_ID", "APP_SECRET"]
return $ FB.Credentials (B.pack appName) (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's name, id and secret on the enviroment"
, "variables APP_NAME, APP_ID and APP_SECRET, respectively. "
, "For example, before running the test you could run in the shell:"
, ""
, " $ export APP_NAME=\"example\""
, " $ export APP_ID=\"458798571203498\""
, " $ export APP_SECRET=\"28a9d0fa4272a14a9287f423f90a48f2304\""
, ""
, "Of course, these 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 "this" "isn't" "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
let runAuth :: FB.FacebookT FB.Auth IO a -> IO a
runAuth = FB.runFacebookT creds manager
runNoAuth :: FB.FacebookT FB.NoAuth IO a -> IO a
runNoAuth = FB.runNoAuthFacebookT manager
hspecX $ do
describe "Facebook.getAppAccessToken" $ do
it "works and returns a valid app access token" $
runAuth $ do
token <- FB.getAppAccessToken
FB.isValid token #?= True
it "throws a FacebookException on invalid credentials" $
FB.runFacebookT invalidCredentials manager $ do
ret <- E.try $ FB.getAppAccessToken
case ret of
Right token -> fail $ show token
Left (_ :: FB.FacebookException) -> lift (return () :: IO ())
describe "Facebook.isValid" $ do
it "returns False on a clearly invalid user access token" $
runNoAuth $ FB.isValid invalidUserAccessToken #?= False
it "returns False on a clearly invalid app access token" $
runNoAuth $ FB.isValid invalidAppAccessToken #?= False
describe "Facebook.OpenGraph.getObject" $ do
it "is able to fetch Facebook's own page" $
runNoAuth $ do
A.Object obj <- FB.getObject "/19292868552" [] Nothing
let Just r = flip A.parseMaybe () $ const $
(,,) <$> obj A..:? "id"
<*> obj A..:? "website"
<*> obj A..:? "name"
just x = Just (x :: Text)
r @?= ( just "19292868552"
, just "http://developers.facebook.com"
, just "Facebook Platform" )
-- Wrappers for HUnit operators using MonadIO
(@?=) :: (Eq a, Show a, MonadIO m) => a -> a -> m ()
v @?= e = liftIO (v HU.@?= e)
(#?=) :: (Eq a, Show a, MonadIO m) => m a -> a -> m ()
m #?= e = m >>= (@?= e)