packages feed

ua-parser-0.4: test/src/TestSuite.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE TemplateHaskell   #-}

module Main where


-------------------------------------------------------------------------------
import           Control.Applicative
import           Control.DeepSeq
import           Control.Monad
import           Criterion.Main                 as C
import           Data.Aeson
import           Data.ByteString.Char8          (ByteString)
import           Data.DeriveTH
import           Data.Text                      (Text)
import qualified Data.Text                      as T
import qualified Data.Text.Encoding             as T
import           Data.Yaml
import           System.Environment
import           System.FilePath.Posix
import           Test.Framework                 (defaultMain, testGroup)
import           Test.Framework                 as T
import           Test.Framework.Providers.HUnit as T
import           Test.HUnit                     hiding (Test, path)
import           Text.Regex.PCRE.Light
-------------------------------------------------------------------------------
import           Web.UAParser.Core
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
main = do
  arg <- getArgs
  case arg of
    ["bench"] -> benchMain
    _ -> testMain



                              ------------------
                              -- Benchmarking --
                              ------------------


-------------------------------------------------------------------------------
benchMain = do
  conf <- loadConfig "../regexes.yaml"
  cases <- loadTests "test_user_agent_parser.yaml"
  cases2 <- loadTests "firefox_user_agent_strings.yaml"
  let allC = cases ++ cases2
      ua = bench "UA Parsing" $ nf (map (parseUA conf . uatcString)) allC
  print $ show (length allC) ++ " strings being parsed."
  C.defaultMain [ua]



                                 -------------
                                 -- Testing --
                                 -------------


testMain = T.defaultMain tests
    where
      tests =
        [ uaTests
        , osTests ]


                               ----------------
                               -- UA Testing --
                               ----------------


-------------------------------------------------------------------------------
uaTests = buildTest $ do
  conf <- loadConfig "../regexes.yaml"
  cases <- loadTests "test_user_agent_parser.yaml"
  cases2 <- loadTests "firefox_user_agent_strings.yaml"
  let allC = cases ++ cases2
  return $ testGroup "UA Parsing Tests" $ map (testUAParser conf) allC



-------------------------------------------------------------------------------
testUAParser :: UAConfig -> UserAgentTestCase -> Test
testUAParser config UATC{..} = testCase tn $ do
  case parsed of
    Nothing -> assertFailure "Can't produce UAResult"
    Just UAResult{..} -> do
     assertEqual "family is same" uatcFamily uarFamily
     -- assertEqual "v1 is the same" uatcV1 uarV1
     -- assertEqual "v2 is the same" uatcV2 uarV2
     -- assertEqual "v3 is the same" uatcV3 uarV3
  where
    parsed = parseUA config uatcString
    tn = T.unpack $ T.intercalate "/" ["UA Test: ", uatcFamily, m uatcV1, m uatcV2, m uatcV3]
    m x = maybe "-" id x


                               ----------------
                               -- OS Testing --
                               ----------------



-------------------------------------------------------------------------------
osTests = buildTest $ do
  conf <- loadConfig "../regexes.yaml"
  cases <- loadTests "test_user_agent_parser_os.yaml"
  return $ testGroup "OS Parsing Tests" $ map (testOSParser conf) cases



-------------------------------------------------------------------------------
testOSParser :: UAConfig -> OSTestCase -> Test
testOSParser config OSTC{..} = testCase tn $ do
  case parsed of
    Nothing -> assertFailure "Can't produce OSResult"
    Just OSResult{..} -> do
     assertEqual "family is same" ostcFamily osrFamily
     assertEqual "major is the same" ostcV1 osrV1
     assertEqual "minor is the same" ostcV2  osrV2
     assertEqual "patch is the same" ostcV3  osrV3
     assertEqual "patch_minor is the same" ostcV4  osrV4
  where
    parsed = parseOS config ostcString
    tn = T.unpack $ T.intercalate "/"
         ["OS Test: ", ostcFamily, m ostcV1, m ostcV2, m ostcV3, m ostcV4]
    m x = maybe "-" id x




                           ------------------------
                           -- Loading Test Cases --
                           ------------------------



-------------------------------------------------------------------------------
loadTests :: FromJSON a => FilePath -> IO a
loadTests fp = parseMonad p =<< either error id `fmap` decodeFile' fp'
  where
    fp' = "../test_resources" </> fp
    p (Object x) = x .: "test_cases"


-------------------------------------------------------------------------------
data UserAgentTestCase = UATC {
      uatcString :: ByteString
    , uatcFamily :: Text
    , uatcV1     :: Maybe Text
    , uatcV2     :: Maybe Text
    , uatcV3     :: Maybe Text
    } deriving (Show)


-------------------------------------------------------------------------------
instance FromJSON UserAgentTestCase where
    parseJSON (Object v) =
      UATC <$> T.encodeUtf8 <$> v .: "user_agent_string"
           <*> (v .: "family" <|> return "")
           <*> (v .:? "v1" <|> return Nothing)
           <*> (v .:? "v2" <|> return Nothing)
           <*> (v .:? "v3" <|> return Nothing)


-------------------------------------------------------------------------------
data OSTestCase = OSTC {
      ostcString :: ByteString
    , ostcFamily :: Text
    , ostcV1     :: Maybe Text
    , ostcV2     :: Maybe Text
    , ostcV3     :: Maybe Text
    , ostcV4     :: Maybe Text
    } deriving (Show)


-------------------------------------------------------------------------------
instance FromJSON OSTestCase where
    parseJSON (Object v) =
      OSTC <$> (T.encodeUtf8 <$> v .: "user_agent_string" <|> return "")
           <*> (v .: "family" <|> return "")
           <*> nonBlank (v .:? "major" <|> return Nothing)
           <*> nonBlank (v .:? "minor" <|> return Nothing)
           <*> nonBlank (v .:? "patch" <|> return Nothing)
           <*> nonBlank (v .:? "patch_minor" <|> return Nothing)

-------------------------------------------------------------------------------
nonBlank f = do
  res <- f
  return $ case res of
    Just "" -> Nothing
    Just x -> Just x
    Nothing -> Nothing



$(derives [makeNFData] [''UAResult])