-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

import Control.Applicative hiding (empty)
import Control.Arrow ((***))
import Control.Exception (SomeException, catch)
import Control.Monad (unless, when)
import Control.Monad.IO.Class
import Data.Aeson
import Data.ByteString (ByteString, empty)
import Data.HashMap.Strict (HashMap)
import Data.Maybe
import Data.String
import Data.Text (Text)
import Data.Time.LocalTime.TimeZone.Series
import Prelude
import System.Directory
import System.Environment (lookupEnv)
import TextShow
import Text.Read (readMaybe)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as LBS8
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text

import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Snap.Core
import Snap.Http.Server

import Duckling.Core
import Duckling.Data.TimeZone
import Duckling.Dimensions (allDimensions)
import Duckling.Resolve (DucklingTime)

createIfMissing :: FilePath -> IO ()
createIfMissing f = do
  exists <- doesFileExist f
  unless exists $ writeFile f ""

shouldLog :: Maybe ConfigLog -> Bool
shouldLog Nothing = False
shouldLog (Just ConfigNoLog) = False
shouldLog _ = True

setupLogs :: Config a b -> IO ()
setupLogs conf = do
  let shouldLogErrors = shouldLog $ getErrorLog conf
  let shouldLogAccesses = shouldLog $ getAccessLog conf

  when (shouldLogErrors || shouldLogAccesses) $ createDirectoryIfMissing False "log"
  when shouldLogErrors $ createIfMissing "log/error.log"
  when shouldLogAccesses $ createIfMissing "log/access.log"

loadTZs :: IO (HashMap Text TimeZoneSeries)
loadTZs = do
  let defaultPath = "/usr/share/zoneinfo/"
  let fallbackPath = "/etc/zoneinfo/"
  loadTimeZoneSeries defaultPath `catch` (\(_ :: SomeException) -> loadTimeZoneSeries fallbackPath)

main :: IO ()
main = do
  tzs <- loadTZs
  p <- lookupEnv "PORT"
  conf <- commandLineConfig $
    maybe defaultConfig (`setPort` defaultConfig) (readMaybe =<< p)
  setupLogs conf
  httpServe conf $
    ifTop (writeBS "quack!") <|>
    route
      [ ("targets", method GET targetsHandler)
      , ("parse", method POST $ parseHandler tzs)
      ]

-- | Return which languages have which dimensions
targetsHandler :: Snap ()
targetsHandler = do
  modifyResponse $ setHeader "Content-Type" "application/json"
  writeLBS $ encode $
    HashMap.fromList $ map dimText $ HashMap.toList supportedDimensions
  where
    dimText :: (Lang, [Seal Dimension]) -> (Text, [Text])
    dimText = (Text.toLower . showt) *** map (\(Seal d) -> toName d)

-- | Parse some text into the given dimensions
parseHandler :: HashMap Text TimeZoneSeries -> Snap ()
parseHandler tzs = do
  modifyResponse $ setHeader "Content-Type" "application/json"
  t <- getPostParam "text"
  l <- getPostParam "lang"
  ds <- getPostParam "dims"
  tz <- getPostParam "tz"
  loc <- getPostParam "locale"
  ref <- getPostParam "reftime"
  latent <- getPostParam "latent"

  case t of
    Nothing -> do
      modifyResponse $ setResponseStatus 422 "Bad Input"
      writeBS "Need a 'text' parameter to parse"
    Just tx -> do
      let timezone = parseTimeZone tz
      now <- liftIO $ currentReftime tzs timezone

      let
        lang = parseLang l

        context = Context
          { referenceTime = maybe now (parseRefTime timezone) ref
          , locale = maybe (makeLocale lang Nothing) parseLocale loc
          }
        options = Options {withLatent = parseLatent latent}

        cleanupDims =
            LBS8.filter (/= '\\') -- strip out escape chars people throw in
          . stripSuffix "\"" -- remove trailing double quote
          . stripPrefix "\"" -- remote leading double quote

          where
            stripSuffix suffix str = fromMaybe str $ LBS.stripSuffix suffix str
            stripPrefix prefix str = fromMaybe str $ LBS.stripPrefix prefix str

        dims = fromMaybe (allDimensions lang) $ do
          queryDims <- fmap (cleanupDims . LBS.fromStrict) ds
          txtDims <- decode @[Text] queryDims
          pure $ mapMaybe parseDimension txtDims

        parsedResult = parse (Text.decodeUtf8 tx) context options dims

      writeLBS $ encode parsedResult
  where
    defaultLang = EN
    defaultLocale = makeLocale defaultLang Nothing
    defaultTimeZone = "America/Los_Angeles"
    defaultLatent = False

    parseDimension :: Text -> Maybe (Seal Dimension)
    parseDimension x = fromName x <|> fromCustomName x
      where
        fromCustomName :: Text -> Maybe (Seal Dimension)
        fromCustomName name = HashMap.lookup name m
        m = HashMap.fromList
          [ -- ("my-dimension", Seal (CustomDimension MyDimension))
          ]

    parseTimeZone :: Maybe ByteString -> Text
    parseTimeZone = maybe defaultTimeZone Text.decodeUtf8

    parseLocale :: ByteString -> Locale
    parseLocale x = maybe defaultLocale (`makeLocale` mregion) mlang
      where
        (mlang, mregion) = case chunks of
          [a, b] -> (readMaybe a :: Maybe Lang, readMaybe b :: Maybe Region)
          _      -> (Nothing, Nothing)
        chunks = map Text.unpack
          $ Text.split (== '_') $ Text.toUpper $ Text.decodeUtf8 x

    parseLang :: Maybe ByteString -> Lang
    parseLang l = fromMaybe defaultLang $ l >>=
      readMaybe . Text.unpack . Text.toUpper . Text.decodeUtf8

    parseRefTime :: Text -> ByteString -> DucklingTime
    parseRefTime timezone refTime = makeReftime tzs timezone utcTime
      where
        milliseconds = readMaybe $ Text.unpack $ Text.decodeUtf8 refTime
        utcTime = case milliseconds of
          Just msec -> posixSecondsToUTCTime $ fromInteger msec / 1000
          Nothing -> error "Please use milliseconds since epoch for reftime"

    parseLatent :: Maybe ByteString -> Bool
    parseLatent x = fromMaybe defaultLatent
      (readMaybe (Text.unpack $ Text.toTitle $ Text.decodeUtf8 $ fromMaybe empty x)::Maybe Bool)


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

import Prelude
import Duckling.Ranking.Generate

main :: IO ()
main = regenAllClassifiers


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE OverloadedStrings #-}

module Duckling.Data.TimeZone
  ( loadTimeZoneSeries
  ) where

import qualified Control.Exception as E
import Control.Monad.Extra
import Data.Either
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.HashSet as HashSet
import Data.String
import qualified Data.Text as Text
import Data.Time (TimeZone(..))
import Data.Text (Text)
import Data.Time.LocalTime.TimeZone.Olson
import Data.Time.LocalTime.TimeZone.Series
import System.Directory
import System.FilePath.Posix

import Prelude

-- | Reference implementation for pulling TimeZoneSeries data from local
-- Olson files.
-- Many linux distros have Olson data in "/usr/share/zoneinfo/"
loadTimeZoneSeries :: FilePath -> IO (HashMap Text TimeZoneSeries)
loadTimeZoneSeries base = do
  files <- getFiles base
  tzSeries <- mapM parseOlsonFile files
  -- This data is large, will live a long time, and essentially be constant,
  -- so it's a perfect candidate for compact regions
  return $ HashMap.fromList $ rights tzSeries
  where
    -- Multiple versions of the data can exist. We intentionally ignore the
    -- posix and right formats
    ignored_dirs = HashSet.fromList $ map (base </>)
      [ "posix", "right" ]

    -- Recursively crawls a directory to list every file underneath it,
    -- ignoring certain directories as needed
    getFiles :: FilePath -> IO [FilePath]
    getFiles dir = do
      fsAll <- getDirectoryContents dir
      let
        fs = filter notDotFile fsAll
        full_fs = map (dir </>) fs
      (dirs, files) <- partitionM doesDirectoryExist full_fs

      subdirs <- concatMapM getFiles
        [ d | d <- dirs, not $ HashSet.member d ignored_dirs ]

      return $ files ++ subdirs

    -- Attempts to read a file in Olson format and returns its
    -- canonical name (file path relative to the base) and the data
    parseOlsonFile :: FilePath
                   -> IO (Either E.ErrorCall (Text, TimeZoneSeries))
    parseOlsonFile f = E.try $ do
      r <- getTimeZoneSeriesFromOlsonFile f
      return (Text.pack $ makeRelative base f, r)

    notDotFile s = not $ elem s [".", ".."]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}

module Duckling.Ranking.Generate
  ( regenAllClassifiers
  , regenClassifiers
  , regenLangClassifiers
  ) where

import Data.HashSet (HashSet)
import Language.Haskell.Exts as F
import Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.HashSet as HashSet
import qualified Data.Text as Text

import Duckling.Dimensions.Types
import Duckling.Locale
import Duckling.Ranking.Train
import Duckling.Ranking.Types
import Duckling.Rules
import Duckling.Testing.Types
import qualified Duckling.Region as R
import qualified Duckling.Time.AR.Corpus as ARTime
import qualified Duckling.Time.BG.Corpus as BGTime
import qualified Duckling.Time.CA.Corpus as CATime
import qualified Duckling.Time.DA.Corpus as DATime
import qualified Duckling.Time.DE.Corpus as DETime
import qualified Duckling.Time.EL.Corpus as ELTime
import qualified Duckling.Time.EN.Corpus as ENTime
import qualified Duckling.Time.EN.CA.Corpus as EN_CATime
import qualified Duckling.Time.EN.GB.Corpus as EN_GBTime
import qualified Duckling.Time.EN.US.Corpus as EN_USTime
import qualified Duckling.Time.ES.Corpus as ESTime
import qualified Duckling.Time.FR.Corpus as FRTime
import qualified Duckling.Time.GA.Corpus as GATime
import qualified Duckling.Time.HR.Corpus as HRTime
import qualified Duckling.Time.HE.Corpus as HETime
import qualified Duckling.Time.HU.Corpus as HUTime
import qualified Duckling.Time.IT.Corpus as ITTime
import qualified Duckling.Time.JA.Corpus as JATime
import qualified Duckling.Time.KO.Corpus as KOTime
import qualified Duckling.Time.NB.Corpus as NBTime
import qualified Duckling.Time.NL.Corpus as NLTime
import qualified Duckling.Time.NL.BE.Corpus as NL_BETime
import qualified Duckling.Time.PL.Corpus as PLTime
import qualified Duckling.Time.PT.Corpus as PTTime
import qualified Duckling.Time.RO.Corpus as ROTime
import qualified Duckling.Time.RU.Corpus as RUTime
import qualified Duckling.Time.SV.Corpus as SVTime
import qualified Duckling.Time.TR.Corpus as TRTime
import qualified Duckling.Time.UK.Corpus as UKTime
import qualified Duckling.Time.VI.Corpus as VITime
import qualified Duckling.Time.ZH.Corpus as ZHTime
import qualified Duckling.Time.ZH.CN.Corpus as ZH_CNTime
import qualified Duckling.Time.ZH.HK.Corpus as ZH_HKTime
import qualified Duckling.Time.ZH.MO.Corpus as ZH_MOTime
import qualified Duckling.Time.ZH.TW.Corpus as ZH_TWTime

-- -----------------------------------------------------------------
-- Main

regenAllClassifiers :: IO ()
regenAllClassifiers = do
  -- Regen default classifiers for langs
  mapM_ (regenClassifiers . defaultLocale) [minBound .. maxBound]
  -- Regen classifiers for locales
  mapM_ regenClassifiers locales
  where
    defaultLocale :: Lang -> Locale
    defaultLocale lang = makeLocale lang Nothing
    f :: [Locale] -> Lang -> HashSet Region -> [Locale]
    f res lang countries =
      res ++ [makeLocale lang (Just c) | c <- HashSet.toList countries]
    locales = HashMap.foldlWithKey' f [] allLocales

regenLangClassifiers :: Lang -> IO ()
regenLangClassifiers lang = do
  regenClassifiers $ makeLocale lang Nothing
  mapM_ (regenClassifiers . makeLocale lang . Just)
    $ HashMap.lookupDefault HashSet.empty lang allLocales

-- | Run this function to overwrite the file with Classifiers data
regenClassifiers :: Locale -> IO ()
regenClassifiers locale = do
  putStrLn $ "Regenerating " ++ filepath ++ "..."
  writeFile filepath $
    (headerComment ++) $
    prettyPrintWithMode baseMode $ (noLoc <$) m
  putStrLn "Done!"
  where
    moduleName = show locale

    filepath = "Duckling/Ranking/Classifiers/" ++ moduleName ++ ".hs"

    rules = rulesFor locale . HashSet.singleton $ Seal Time

    -- | The trained classifier to write out
    classifiers = makeClassifiers rules trainSet

    -- | The training set (corpus)
    trainSet = getCorpus locale

    -- Data structure for the module
    m = Module () (Just header) pragmas imports decls

    -- Declares the top level options pragma
    pragmas = [ LanguagePragma () [Ident () "OverloadedStrings"] ]

    -- Declares the header for the module
    -- "module Duckling.Ranking.Classifiers (classifiers) where"
    header = ModuleHead ()
      (ModuleName () $ "Duckling.Ranking.Classifiers." ++ moduleName)
      Nothing $
      Just $ ExportSpecList ()
       [ EVar () (unQual "classifiers")
       ]

    -- All imports the file will need
    imports =
      [ genImportModule "Data.String"
      , genImportModule "Prelude"
      , (genImportModule "Data.HashMap.Strict")
        { importQualified = True
        , importAs = Just (ModuleName () "HashMap")
        }
      , genImportModule "Duckling.Ranking.Types"
      ]

    -- The code body
    decls =
      [ -- Type Signature
        TypeSig () [Ident () "classifiers"] (TyCon () (unQual "Classifiers"))
        -- function body
      , FunBind ()
          [ Match () (Ident () "classifiers") []
              (UnGuardedRhs () (genList classifiers)) Nothing
          ]
      ]

    headerComment :: String
    headerComment = "\
\-- Copyright (c) 2016-present, Facebook, Inc.\n\
\-- All rights reserved.\n\
\--\n\
\-- This source code is licensed under the BSD-style license found in the\n\
\-- LICENSE file in the root directory of this source tree. An additional grant\n\
\-- of patent rights can be found in the PATENTS file in the same directory.\n\n\
\-----------------------------------------------------------------\n\
\-- Auto-generated by regenClassifiers\n\
\--\n\
\-- DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\
\--  @" ++ "generated\n\
\-----------------------------------------------------------------\n"

-- | Retrieves the corpus for the locale.
-- The corpus is all the language examples + all the locale examples, if any.
-- Locales don't provide a corpus as contexts need to agree.
getCorpus :: Locale -> Corpus
getCorpus (Locale lang Nothing) = getDefaultCorpusForLang lang
getCorpus locale@(Locale lang (Just region)) =
  withLocale (getCorpusForLang lang) locale $ getExamplesForLocale lang region

-- | For backward compatibility.
getDefaultCorpusForLang :: Lang -> Corpus
getDefaultCorpusForLang = \case
  EN -> ENTime.defaultCorpus
  NL -> NLTime.defaultCorpus
  lang -> getCorpusForLang lang

getCorpusForLang :: Lang -> Corpus
getCorpusForLang = \case
  AF -> (testContext, testOptions, [])
  AR -> ARTime.corpus
  BG -> BGTime.corpus
  BN -> (testContext, testOptions, [])
  CA -> CATime.corpus
  CS -> (testContext, testOptions, [])
  DA -> DATime.corpus
  DE -> DETime.corpus
  EL -> ELTime.corpus
  EN -> ENTime.corpus
  ES -> ESTime.corpus
  ET -> (testContext, testOptions, [])
  FI -> (testContext, testOptions, [])
  FA -> (testContext, testOptions, [])
  FR -> FRTime.corpus
  GA -> GATime.corpus
  HR -> HRTime.corpus
  HE -> HETime.corpus
  HU -> HUTime.corpus
  HI -> (testContext, testOptions, [])
  ID -> (testContext, testOptions, [])
  IS -> (testContext, testOptions, [])
  IT -> ITTime.corpus
  JA -> JATime.corpus
  KA -> (testContext, testOptions, [])
  KM -> (testContext, testOptions, [])
  KN -> (testContext, testOptions, [])
  KO -> KOTime.corpus
  LO -> (testContext, testOptions, [])
  ML -> (testContext, testOptions, [])
  MN -> (testContext, testOptions, [])
  MY -> (testContext, testOptions, [])
  NB -> NBTime.corpus
  NE -> (testContext, testOptions, [])
  NL -> NLTime.corpus
  PL -> PLTime.corpus
  PT -> PTTime.corpus
  RO -> ROTime.corpus
  RU -> RUTime.corpus
  SK -> (testContext, testOptions, [])
  SV -> SVTime.corpus
  SW -> (testContext, testOptions, [])
  TA -> (testContext, testOptions, [])
  TE -> (testContext, testOptions, [])
  TH -> (testContext, testOptions, [])
  TR -> TRTime.corpus
  UK -> UKTime.corpus
  VI -> VITime.corpus
  ZH -> ZHTime.corpus

getExamplesForLocale :: Lang -> Region -> [Example]
getExamplesForLocale EN R.CA = EN_CATime.allExamples
getExamplesForLocale EN GB = EN_GBTime.allExamples
getExamplesForLocale EN US = EN_USTime.allExamples
getExamplesForLocale NL BE = NL_BETime.allExamples
getExamplesForLocale ZH CN = ZH_CNTime.allExamples
getExamplesForLocale ZH HK = ZH_HKTime.allExamples
getExamplesForLocale ZH MO = ZH_MOTime.allExamples
getExamplesForLocale ZH TW = ZH_TWTime.allExamples
getExamplesForLocale _ _   = []

-- -----------------------------------------------------------------
-- Source generators

-- | Generates a line for an import
--
-- `genImportModule "Foo.Bar"` spits out:
-- "import Foo.Bar" in the code
genImportModule :: String -> ImportDecl ()
genImportModule name = ImportDecl
  { importAnn = ()
  , importModule = ModuleName () name
  , importQualified = False
  , importSrc = False
  , importSafe = False
  , importPkg = Nothing
  , importAs = Nothing
  , importSpecs = Nothing
  }

-- | Creates the expression to build the HashMap object
genList :: Classifiers -> Exp ()
genList cs = appFromList $ map genClassifier $ HashMap.toList cs
  where
    -- "fromList ..."
    appFromList exprs = App ()
      (Var () (Qual () (ModuleName () "HashMap") (Ident () "fromList")))
      (List () exprs)

    -- ("name", Classifier { okData ....
    genClassifier (name, Classifier{..}) =
      let uname = Text.unpack name in
      Tuple () Boxed
        [ Lit () $ F.String () uname uname
        , RecConstr () (unQual "Classifier")
            [ genClassData okData "okData"
            , genClassData koData "koData"
            ]
        ]

    -- ClassData { prior = -0.123, unseen = ...
    genClassData ClassData{..} name = FieldUpdate () (unQual name) $
      RecConstr () (unQual "ClassData")
        [ FieldUpdate () (unQual "prior") $ floatSym prior
        , FieldUpdate () (unQual "unseen") $ floatSym unseen
        , FieldUpdate () (unQual "likelihoods") $
            appFromList $ map genLikelihood $ HashMap.toList likelihoods
        , FieldUpdate () (unQual "n") $
            Lit () (Int () (fromIntegral n) (show n))
        ]

    -- ("feature", 0.0)
    genLikelihood (f, d) =
      let uf = Text.unpack f in
      Tuple () Boxed
        [ Lit () $ F.String () uf uf
        , floatSym d
        ]

-- Helper to print out doubles
floatSym :: Double -> Exp ()
floatSym val
  | isInfinite val = if val < 0
      then NegApp () inf
      else inf
  | otherwise = Lit () (Frac () (realToFrac val) $ show val)
  where
    inf = Var () $ unQual "infinity"

-- Helper for unqualified things
unQual :: String -> QName ()
unQual name = UnQual () (Ident () name)

-- -----------------------------------------------------------------
-- Printing helpers

baseMode :: PPHsMode
baseMode = PPHsMode
  { classIndent   = 2
  , doIndent      = 3
  , multiIfIndent = 3
  , caseIndent    = 2
  , letIndent     = 2
  , whereIndent   = 2
  , onsideIndent  = 2
  , spacing       = True
  , layout        = PPOffsideRule
  , linePragmas   = False
  }


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE RecordWildCards #-}

module Duckling.Ranking.Train
  ( makeClassifiers
  ) where

import Data.HashSet (HashSet)
import Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.HashSet as HashSet
import qualified Data.List as List

import Duckling.Engine
import Duckling.Ranking.Extraction
import Duckling.Ranking.Types
import Duckling.Resolve
import Duckling.Testing.Types
import Duckling.Types

-- -----------------------------------------------------------------
-- Probabilistic layer
-- Naive Bayes classifier with Laplace smoothing
-- Train one classifier per rule, based on the test corpus.

makeClassifiers :: [Rule] -> Corpus -> Classifiers
makeClassifiers rules corpus = HashMap.map train $ makeDataset rules corpus

-- | Train a classifier for a single rule
train :: [Datum] -> Classifier
train datums = Classifier {okData = okClass, koData = koClass}
  where
    total = List.length datums
    (ok, ko) = List.partition snd datums
    merge :: [BagOfFeatures] -> BagOfFeatures -> BagOfFeatures
    merge xs m = List.foldl' (HashMap.unionWith (+)) m xs
    okCounts = merge (map fst ok) HashMap.empty
    koCounts = merge (map fst ko) HashMap.empty
    vocSize = HashMap.size $ HashMap.union okCounts koCounts
    okClass = makeClass okCounts total (List.length ok) vocSize
    koClass = makeClass koCounts total (List.length ko) vocSize

-- | Compute prior and likelihoods log-probabilities for one class.
makeClass :: BagOfFeatures -> Int -> Int -> Int -> ClassData
makeClass feats total classTotal vocSize = ClassData
  { prior = prior
  , unseen = unseen
  , likelihoods = likelihoods
  , n = classTotal
  }
  where
    prior = log $ fromIntegral classTotal / fromIntegral total
    denum = vocSize + sum (HashMap.elems feats)
    unseen = log $ 1.0 / (fromIntegral denum + 1.0)
    likelihoods = HashMap.map (\x ->
      log $ (fromIntegral x + 1.0) / fromIntegral denum
      ) feats

-- | Augment the dataset with one example.
-- | Add all the nodes contributing to the resolutions of the input sentence.
-- | Classes:
-- | 1) True (node contributed to a token passing test predicate)
-- | 2) False (node didn't contribute to any passing tokens)
makeDataset1 :: [Rule] -> Context -> Options -> Dataset -> Example -> Dataset
makeDataset1 rules context options dataset (sentence, predicate) = dataset'
  where
    tokens = parseAndResolve rules sentence context options
    (ok, ko) = List.partition (predicate context) tokens
    subnodes :: Node -> HashSet Node
    subnodes node@(Node{..}) = case children of
      [] -> HashSet.empty
      cs -> HashSet.unions $ HashSet.singleton node:map subnodes cs
    nodesOK = HashSet.unions $ map (subnodes . node) ok
    nodesKO = HashSet.difference
      (HashSet.unions $ map (subnodes . node) ko) nodesOK
    updateDataset :: Class -> HashSet Node -> Dataset -> Dataset
    updateDataset klass nodes dataset =
      HashSet.foldl' (\dataset node@Node {..} ->
        case rule of
          Just rule -> HashMap.insertWith (++) rule
            [(extractFeatures node, klass)] dataset
          Nothing -> dataset
        ) dataset nodes
    dataset' = updateDataset False nodesKO $ updateDataset True nodesOK dataset

-- | Build a dataset (rule name -> datums)
makeDataset :: [Rule] -> Corpus -> Dataset
makeDataset rules (context, options, examples) =
   List.foldl' (makeDataset1 rules context options) HashMap.empty examples


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Main where

import Data.String
import Test.Tasty

import Duckling.Tests
import Prelude

main :: IO ()
main = defaultMain tests


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE NoRebindableSyntax #-}

module Duckling.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty
import Test.Tasty.HUnit

import qualified Duckling.Api.Tests as Api
import qualified Duckling.Dimensions.Tests as Dimensions
import qualified Duckling.Engine.Tests as Engine

tests :: TestTree
tests = testGroup "Duckling Tests"
  [ Api.tests
  , Dimensions.tests
  , Engine.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import qualified Duckling.AmountOfMoney.AR.Tests as AR
import qualified Duckling.AmountOfMoney.CA.Tests as CA
import qualified Duckling.AmountOfMoney.EN.Tests as EN
import qualified Duckling.AmountOfMoney.BG.Tests as BG
import qualified Duckling.AmountOfMoney.ES.Tests as ES
import qualified Duckling.AmountOfMoney.FR.Tests as FR
import qualified Duckling.AmountOfMoney.GA.Tests as GA
import qualified Duckling.AmountOfMoney.HE.Tests as HE
import qualified Duckling.AmountOfMoney.HR.Tests as HR
import qualified Duckling.AmountOfMoney.ID.Tests as ID
import qualified Duckling.AmountOfMoney.IT.Tests as IT
import qualified Duckling.AmountOfMoney.KA.Tests as KA
import qualified Duckling.AmountOfMoney.KO.Tests as KO
import qualified Duckling.AmountOfMoney.MN.Tests as MN
import qualified Duckling.AmountOfMoney.NB.Tests as NB
import qualified Duckling.AmountOfMoney.NL.Tests as NL
import qualified Duckling.AmountOfMoney.PT.Tests as PT
import qualified Duckling.AmountOfMoney.RO.Tests as RO
import qualified Duckling.AmountOfMoney.RU.Tests as RU
import qualified Duckling.AmountOfMoney.SV.Tests as SV
import qualified Duckling.AmountOfMoney.TR.Tests as TR
import qualified Duckling.AmountOfMoney.VI.Tests as VI
import qualified Duckling.AmountOfMoney.ZH.Tests as ZH

tests :: TestTree
tests = testGroup "AmountOfMoney Tests"
  [ AR.tests
  , BG.tests
  , CA.tests
  , EN.tests
  , ES.tests
  , FR.tests
  , GA.tests
  , HE.tests
  , HR.tests
  , ID.tests
  , IT.tests
  , KA.tests
  , KO.tests
  , MN.tests
  , NB.tests
  , NL.tests
  , PT.tests
  , RO.tests
  , RU.tests
  , SV.tests
  , TR.tests
  , VI.tests
  , ZH.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.AR.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.AR.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "AR Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.BG.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.BG.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "BG Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.CA.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.CA.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CA Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.EN.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty
import Test.Tasty.HUnit

import Duckling.AmountOfMoney.EN.Corpus
import Duckling.Dimensions.Types
import Duckling.Locale
import Duckling.Testing.Asserts
import Duckling.Testing.Types (testContext, testOptions, withLocale)
import Duckling.Types (Range(..))
import qualified Duckling.AmountOfMoney.EN.AU.Corpus as AU
import qualified Duckling.AmountOfMoney.EN.BZ.Corpus as BZ
import qualified Duckling.AmountOfMoney.EN.CA.Corpus as CA
import qualified Duckling.AmountOfMoney.EN.GB.Corpus as GB
import qualified Duckling.AmountOfMoney.EN.IN.Corpus as IN
import qualified Duckling.AmountOfMoney.EN.IE.Corpus as IE
import qualified Duckling.AmountOfMoney.EN.JM.Corpus as JM
import qualified Duckling.AmountOfMoney.EN.NZ.Corpus as NZ
import qualified Duckling.AmountOfMoney.EN.PH.Corpus as PH
import qualified Duckling.AmountOfMoney.EN.TT.Corpus as TT
import qualified Duckling.AmountOfMoney.EN.US.Corpus as US
import qualified Duckling.AmountOfMoney.EN.ZA.Corpus as ZA
import qualified Duckling.Region as R

tests :: TestTree
tests = testGroup "EN Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  , makeNegativeCorpusTest [Seal AmountOfMoney] negativeCorpus
  , localeTests
  , intersectTests
  , rangeTests
  , latentTests
  ]

localeTests :: TestTree
localeTests = testGroup "Locale Tests"
  [ testGroup "EN_AU Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeAU AU.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeAU AU.negativeExamples
    ]
   , testGroup "EN_BZ Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeBZ BZ.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeBZ BZ.negativeExamples
    ]
   , testGroup "EN_CA Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeCA CA.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeCA CA.negativeExamples
    ]
   , testGroup "EN_GB Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeGB GB.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeGB GB.negativeExamples
    ]
   , testGroup "EN_IE Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeIE IE.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeIE IE.negativeExamples
    ]
   , testGroup "EN_IN Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeIN IN.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeIN IN.negativeExamples
    ]
   , testGroup "EN_JM Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeJM JM.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeJM JM.negativeExamples
    ]
   , testGroup "EN_NZ Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeNZ NZ.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeNZ NZ.negativeExamples
    ]
   , testGroup "EN_PH Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localePH PH.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localePH PH.negativeExamples
    ]
    , testGroup "EN_TT Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeTT TT.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeTT TT.negativeExamples
    ]
    , testGroup "EN_US Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeUS US.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeUS US.negativeExamples
    ]
    , testGroup "EN_ZA Tests"
    [ makeCorpusTest [Seal AmountOfMoney]
      $ withLocale corpus localeZA ZA.allExamples
    , makeNegativeCorpusTest [Seal AmountOfMoney]
      $ withLocale negativeCorpus localeZA ZA.negativeExamples
    ]
  ]
  where
    localeAU = makeLocale EN $ Just AU
    localeBZ = makeLocale EN $ Just BZ
    localeCA = makeLocale EN $ Just R.CA
    localeGB = makeLocale EN $ Just GB
    localeIE = makeLocale EN $ Just IE
    localeIN = makeLocale EN $ Just IN
    localeJM = makeLocale EN $ Just JM
    localeNZ = makeLocale EN $ Just NZ
    localePH = makeLocale EN $ Just PH
    localeTT = makeLocale EN $ Just TT
    localeUS = makeLocale EN $ Just US
    localeZA = makeLocale EN $ Just ZA

intersectTests :: TestTree
intersectTests = testCase "Intersect Test" $
  mapM_ (analyzedNTest testContext testOptions . withTargets [Seal AmountOfMoney]) xs
  where
    xs = [ ("7c7", 2)
         , ("7c7c", 3)
         , ("10 dollars 0.17", 2)
         , ("1.1 dollars 6", 2)
         , ("10 cents and 8 cents", 2)
         , ("10 dollars and 2 dollars", 2)
         , ("between 4.1 dollars and 4 dollars", 3)
         , ("between 4 dollars and 7 euros", 2)
         ]

rangeTests :: TestTree
rangeTests = testCase "Range Test" $
  mapM_ (analyzedRangeTest testContext testOptions . withTargets [Seal AmountOfMoney]) xs
  where
    xs = [ ("between 3 and 1 dollars", Range 14 23)
         , ("between 1 and between 2 and 3 dollars", Range 14 37)
         , ("10 cents and 0.1", Range 0 8)
         , ("Pay Kiran1 10eur", Range 11 16)
         ]

latentTests :: TestTree
latentTests = makeCorpusTest [Seal AmountOfMoney] latentCorpus


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.ES.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.AmountOfMoney.ES.Corpus

tests :: TestTree
tests = testGroup "ES Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.FR.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.FR.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FR Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.GA.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.AmountOfMoney.GA.Corpus

tests :: TestTree
tests = testGroup "GA Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.HE.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.HE.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HE Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.HR.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.AmountOfMoney.HR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HR Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.ID.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.AmountOfMoney.ID.Corpus

tests :: TestTree
tests = testGroup "ID Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.IT.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.IT.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "IT Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.KA.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.AmountOfMoney.KA.Corpus

tests :: TestTree
tests = testGroup "KA Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.KO.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.AmountOfMoney.KO.Corpus

tests :: TestTree
tests = testGroup "KO Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.MN.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.MN.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "MN Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.NB.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.AmountOfMoney.NB.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "NB Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.NL.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.NL.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "NL Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.PT.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.AmountOfMoney.PT.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "PT Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.RO.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.RO.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "RO Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  , makeNegativeCorpusTest [Seal AmountOfMoney] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.RU.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.RU.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "RU Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.SV.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.AmountOfMoney.SV.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "SV Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.TR.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.TR.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "TR Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.VI.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.AmountOfMoney.VI.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "VI Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.AmountOfMoney.ZH.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.AmountOfMoney.ZH.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "ZH Tests"
  [ makeCorpusTest [Seal AmountOfMoney] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Api.Tests
  ( tests
  ) where

import Data.List (sortOn)
import Data.Text (Text)
import Prelude
import Test.Tasty
import Test.Tasty.HUnit
import qualified Data.HashMap.Strict as HashMap
import qualified Data.HashSet as HashSet

import Duckling.Api
import Duckling.Dimensions.Types
import Duckling.Locale
import Duckling.Testing.Asserts
import Duckling.Testing.Types
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral

tests :: TestTree
tests = testGroup "API Tests"
  [ parseTest
  , rankTest
  , rangeTest
  , supportedDimensionsTest
  ]

parseTest :: TestTree
parseTest = testCase "Parse Test" $
  case parse sentence testContext testOptions [Seal Numeral] of
    [] -> assertFailure "empty result"
    (Entity dim body (RVal _ v) start end _ _:_) -> do
      assertEqual "dim" "number" dim
      assertEqual "body" "42" body
      assertEqual "value" val (toJText v)
      assertEqual "start" 4 start
      assertEqual "end" 6 end
  where
    sentence = "hey 42 there"
    val = toJText TNumeral.NumeralValue {TNumeral.vValue = 42.0}

rankTest :: TestTree
rankTest = testGroup "Rank Tests"
  [ rankFilterTest
  , rankOrderTest
  ]

rankFilterTest :: TestTree
rankFilterTest = testCase "Rank Filter Tests" $ do
  mapM_ check
    [ ( "in 2 minutes"
      , [Seal Numeral, Seal Duration, Seal Time]
      , [Seal Time]
      )
    , ( "in 2 minutes, about 42 degrees"
      , [Seal Numeral, Seal Temperature, Seal Time]
      , [Seal Time, Seal Temperature]
      )
    , ( "today works... and tomorrow at 9pm too"
      , [Seal Numeral, Seal Time]
      , [Seal Time, Seal Time]
      )
    , ( "between 9:30 and 11:00 on thursday or Saturday and Thanksgiving Day"
      , [Seal Numeral, Seal Time]
      , [Seal Time, Seal Time, Seal Time]
      )
    , ("the day after tomorrow 5pm", [Seal Time], [Seal Time])
    , ("the day after tomorrow 5pm", [Seal Time, Seal Numeral], [Seal Time])
    , ("the day after tomorrow 5pm", [], [Seal Time])
    ]
  where
    check :: (Text, [Seal Dimension], [Seal Dimension]) -> IO ()
    check (sentence, targets, expected) =
      let go = analyze sentence testContext testOptions $ HashSet.fromList targets
          actual = flip map go $
                     \(Resolved{node=Node{token=Token d _}}) -> Seal d
      in assertEqual ("wrong winners for " ++ show sentence) expected actual

rankOrderTest :: TestTree
rankOrderTest = testCase "Rank Order Tests" $ do
  mapM_ check
    [ ("tomorrow at 5PM or 8PM", [Seal Time])
    , ("321 12 3456 ... 7", [Seal Numeral])
    , ("42 today 23 tomorrow", [Seal Numeral, Seal Time])
    ]
  where
    check (s, targets) =
      let tokens = analyze s testContext testOptions $ HashSet.fromList targets
        in assertEqual "wrong ordering" (sortOn range tokens) tokens

rangeTest :: TestTree
rangeTest = testCase "Range Tests" $ do
  mapM_ (analyzedFirstTest testContext testOptions) xs
  where
    xs = map (\(input, targets, range) -> (input, targets, f range))
             [ ( "order status 3233763377", [Seal PhoneNumber], Range 13 23 )
             , ( "  3233763377  "         , [Seal PhoneNumber], Range  2 12 )
             , ( " -3233763377"           , [Seal PhoneNumber], Range  2 12 )
             , ( "  now"                  , [Seal Time]       , Range  2  5 )
             , ( "   Monday  "            , [Seal Time]       , Range  3  9 )
             , ( "  next   week "         , [Seal Time]       , Range  2 13 )
             , ( "   42\n\n"              , [Seal Numeral]    , Range  3  5 )
             ]
    f :: Range -> TestPredicate
    f expected _ (Resolved {range = actual}) = expected == actual

supportedDimensionsTest :: TestTree
supportedDimensionsTest = testCase "Supported Dimensions Test" $ do
  mapM_ check
    [ ( AR
      , [ Seal Email, Seal AmountOfMoney, Seal PhoneNumber, Seal Url
        , Seal Duration, Seal Numeral, Seal Ordinal, Seal Time, Seal Volume
        , Seal Temperature, Seal Quantity, Seal CreditCardNumber
        ]
      )
    , ( PL
      , [ Seal Email, Seal AmountOfMoney, Seal PhoneNumber, Seal Url
        , Seal Duration, Seal Numeral, Seal Ordinal, Seal Time
        , Seal CreditCardNumber
        ]
      )
    ]
  where
    check :: (Lang, [Seal Dimension]) -> IO ()
    check (l, expected) = case HashMap.lookup l supportedDimensions of
      Nothing -> assertFailure $ "no dimensions for " ++ show l
      Just actual ->
        assertEqual ("wrong dimensions for " ++ show l)
        (HashSet.fromList expected) (HashSet.fromList actual)


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE OverloadedStrings #-}

module Duckling.CreditCardNumber.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.CreditCardNumber.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CreditCardNumber Tests"
  [ makeCorpusTest [Seal CreditCardNumber] corpus
  , makeNegativeCorpusTest [Seal CreditCardNumber] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Dimensions.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import qualified Duckling.AmountOfMoney.Tests as AmountOfMoney
import qualified Duckling.CreditCardNumber.Tests as CreditCardNumber
import qualified Duckling.Distance.Tests as Distance
import qualified Duckling.Duration.Tests as Duration
import qualified Duckling.Email.Tests as Email
import qualified Duckling.Numeral.Tests as Numeral
import qualified Duckling.Ordinal.Tests as Ordinal
import qualified Duckling.PhoneNumber.Tests as PhoneNumber
import qualified Duckling.Quantity.Tests as Quantity
import qualified Duckling.Temperature.Tests as Temperature
import qualified Duckling.Time.Tests as Time
import qualified Duckling.Volume.Tests as Volume
import qualified Duckling.Url.Tests as Url

tests :: TestTree
tests = testGroup "Dimensions Tests"
  [ AmountOfMoney.tests
  , CreditCardNumber.tests
  , Distance.tests
  , Duration.tests
  , Email.tests
  , Numeral.tests
  , Ordinal.tests
  , PhoneNumber.tests
  , Quantity.tests
  , Temperature.tests
  , Time.tests
  , Volume.tests
  , Url.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import qualified Duckling.Distance.BG.Tests as BG
import qualified Duckling.Distance.CA.Tests as CA
import qualified Duckling.Distance.CS.Tests as CS
import qualified Duckling.Distance.DE.Tests as DE
import qualified Duckling.Distance.EN.Tests as EN
import qualified Duckling.Distance.ES.Tests as ES
import qualified Duckling.Distance.FR.Tests as FR
import qualified Duckling.Distance.GA.Tests as GA
import qualified Duckling.Distance.HR.Tests as HR
import qualified Duckling.Distance.IT.Tests as IT
import qualified Duckling.Distance.KM.Tests as KM
import qualified Duckling.Distance.KO.Tests as KO
import qualified Duckling.Distance.MN.Tests as MN
import qualified Duckling.Distance.NL.Tests as NL
import qualified Duckling.Distance.PT.Tests as PT
import qualified Duckling.Distance.RO.Tests as RO
import qualified Duckling.Distance.RU.Tests as RU
import qualified Duckling.Distance.TR.Tests as TR
import qualified Duckling.Distance.SV.Tests as SV
import qualified Duckling.Distance.ZH.Tests as ZH

tests :: TestTree
tests = testGroup "Distance Tests"
  [ BG.tests
  , CA.tests
  , CS.tests
  , DE.tests
  , EN.tests
  , ES.tests
  , FR.tests
  , GA.tests
  , HR.tests
  , IT.tests
  , KM.tests
  , KO.tests
  , MN.tests
  , NL.tests
  , PT.tests
  , RO.tests
  , RU.tests
  , TR.tests
  , SV.tests
  , ZH.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.BG.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.BG.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "BG Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.CA.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Distance.CA.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CA Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.CS.Tests
  ( tests ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.CS.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CS Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.DE.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.DE.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "DE Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.EN.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.EN.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "EN Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.ES.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.ES.Corpus

tests :: TestTree
tests = testGroup "ES Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.FR.Tests
  ( tests ) where
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.FR.Corpus

tests :: TestTree
tests = testGroup "FR Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.GA.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.GA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "GA Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.HR.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.HR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HR Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.IT.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.IT.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "IT Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.KM.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.KM.Corpus

tests :: TestTree
tests = testGroup "KM Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.KO.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.KO.Corpus

tests :: TestTree
tests = testGroup "KO Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.MN.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.MN.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "MN Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.NL.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.NL.Corpus

tests :: TestTree
tests = testGroup "NL Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.PT.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.PT.Corpus

tests :: TestTree
tests = testGroup "PT Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.RO.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Testing.Asserts
import Duckling.Distance.RO.Corpus

tests :: TestTree
tests = testGroup "RO Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.RU.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.RU.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "RU Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.SV.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.SV.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "SV Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Distance.TR.Tests
  ( tests ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Distance.TR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "TR Tests"
  [ makeCorpusTest [Seal Distance] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import qualified Duckling.Duration.AR.Tests as AR
import qualified Duckling.Duration.BG.Tests as BG
import qualified Duckling.Duration.CA.Tests as CA
import qualified Duckling.Duration.EL.Tests as EL
import qualified Duckling.Duration.EN.Tests as EN
import qualified Duckling.Duration.ES.Tests as ES
import qualified Duckling.Duration.FR.Tests as FR
import qualified Duckling.Duration.GA.Tests as GA
import qualified Duckling.Duration.HI.Tests as HI
import qualified Duckling.Duration.HU.Tests as HU
import qualified Duckling.Duration.JA.Tests as JA
import qualified Duckling.Duration.KA.Tests as KA
import qualified Duckling.Duration.KO.Tests as KO
import qualified Duckling.Duration.MN.Tests as MN
import qualified Duckling.Duration.NB.Tests as NB
import qualified Duckling.Duration.NL.Tests as NL
import qualified Duckling.Duration.PL.Tests as PL
import qualified Duckling.Duration.PT.Tests as PT
import qualified Duckling.Duration.RO.Tests as RO
import qualified Duckling.Duration.RU.Tests as RU
import qualified Duckling.Duration.SV.Tests as SV
import qualified Duckling.Duration.TR.Tests as TR
import qualified Duckling.Duration.UK.Tests as UK
import qualified Duckling.Duration.ZH.Tests as ZH

tests :: TestTree
tests = testGroup "Duration Tests"
  [ AR.tests
  , BG.tests
  , CA.tests
  , EL.tests
  , EN.tests
  , ES.tests
  , FR.tests
  , GA.tests
  , HI.tests
  , HU.tests
  , JA.tests
  , KA.tests
  , KO.tests
  , MN.tests
  , NB.tests
  , NL.tests
  , PL.tests
  , PT.tests
  , RO.tests
  , RU.tests
  , SV.tests
  , TR.tests
  , UK.tests
  , ZH.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.AR.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.AR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "AR Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.BG.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.BG.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "BG Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.CA.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Duration.CA.Corpus
import Duckling.Dimensions.Types
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CA Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.DE.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.DE.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "ES Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.EL.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.EL.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "EL Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.EN.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty
import Test.Tasty.HUnit

import Duckling.Dimensions.Types
import Duckling.Duration.EN.Corpus
import Duckling.Testing.Asserts
import Duckling.Testing.Types hiding (examples)
import Duckling.Types (Range(..))

tests :: TestTree
tests = testGroup "EN Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  , rangeTests
  ]

rangeTests :: TestTree
rangeTests = testCase "Range Test" $
  mapM_ (analyzedRangeTest testContext testOptions . withTargets [Seal Duration]) xs
  where
    xs = [ ("1 hour 111565513", Range 0 6) -- ruleDurationHoursAndMinutes to accept valid minutes
         ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.ES.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.ES.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "ES Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.FR.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.FR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FR Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.GA.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.GA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "GA Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.HI.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.HI.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HI Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.HU.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.HU.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HU Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.JA.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.JA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "JA Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.KA.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.KA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "KA Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.KO.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.KO.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "KO Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.MN.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.MN.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "MN Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.NB.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.NB.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "NB Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.NL.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.NL.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "NL Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.PL.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.PL.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "PL Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.PT.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.PT.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "PT Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.RO.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.RO.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "RO Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.RU.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.RU.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "RU Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.SV.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.SV.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "SV Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.TR.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.TR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "TR Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.UK.Tests
  ( tests
  ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.UK.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "UK Tests"
  [ makeCorpusTest [Seal Duration] corpus
  , makeNegativeCorpusTest [Seal Duration] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Duration.ZH.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Duration.ZH.Corpus
import Duckling.Testing.Asserts
import Duckling.Testing.Types

tests :: TestTree
tests = testGroup "ZH Tests"
  [ makeCorpusTest [Seal Duration] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.Corpus
import Duckling.Testing.Asserts
import qualified Duckling.Email.DE.Tests as DE
import qualified Duckling.Email.EN.Tests as EN
import qualified Duckling.Email.FR.Tests as FR
import qualified Duckling.Email.IS.Tests as IS
import qualified Duckling.Email.IT.Tests as IT

tests :: TestTree
tests = testGroup "Email Tests"
  [ makeCorpusTest [Seal Email] corpus
  , makeNegativeCorpusTest [Seal Email] negativeCorpus
  , DE.tests
  , EN.tests
  , FR.tests
  , IS.tests
  , IT.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.DE.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.DE.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "DE Tests"
  [ makeCorpusTest [Seal Email] corpus
  , makeNegativeCorpusTest [Seal Email] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.EN.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.EN.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "EN Tests"
  [ makeCorpusTest [Seal Email] corpus
  , makeNegativeCorpusTest [Seal Email] negativeCorpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.FR.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.FR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FR Tests"
  [ makeCorpusTest [Seal Email] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.IS.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.IS.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "IS Tests"
  [ makeCorpusTest [Seal Email] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Email.IT.Tests
  ( tests
  ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Email.IT.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "IT Tests"
  [ makeCorpusTest [Seal Email] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE OverloadedStrings #-}

module Duckling.Engine.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty
import Test.Tasty.HUnit

import Duckling.Engine
import Duckling.Locale (Lang(..))
import Duckling.Types
import Duckling.Regex.Types

tests :: TestTree
tests = testGroup "Engine Tests"
  [ emptyRegexTest
  , unicodeAndRegexTest
  ]

emptyRegexTest :: TestTree
emptyRegexTest = testCase "Empty Regex Test" $
  case regex "()" of
    Regex regex -> assertEqual "empty result" [] $
      runDuckling $ lookupRegexAnywhere "hey" EN regex
    _ -> assertFailure "expected a regex"

unicodeAndRegexTest :: TestTree
unicodeAndRegexTest = testCase "Unicode and Regex Test" $
  case regex "\\$([0-9]*)" of
    Regex regex -> do --
      assertEqual "" expected $
        runDuckling $ lookupRegexAnywhere "\128526 $35" EN regex
    _ -> assertFailure "expected a regex"
  where
  expected =
    [ Node
      { nodeRange = Range 2 5
      , token = Token RegexMatch (GroupMatch ["35"])
      , children = []
      , rule = Nothing
      }
    ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.Tests (tests) where

import Data.String
import Prelude
import Test.Tasty

import qualified Duckling.Numeral.AF.Tests as AF
import qualified Duckling.Numeral.AR.Tests as AR
import qualified Duckling.Numeral.BG.Tests as BG
import qualified Duckling.Numeral.BN.Tests as BN
import qualified Duckling.Numeral.CA.Tests as CA
import qualified Duckling.Numeral.CS.Tests as CS
import qualified Duckling.Numeral.DA.Tests as DA
import qualified Duckling.Numeral.DE.Tests as DE
import qualified Duckling.Numeral.EL.Tests as EL
import qualified Duckling.Numeral.EN.Tests as EN
import qualified Duckling.Numeral.ES.Tests as ES
import qualified Duckling.Numeral.ET.Tests as ET
import qualified Duckling.Numeral.FI.Tests as FI
import qualified Duckling.Numeral.FA.Tests as FA
import qualified Duckling.Numeral.FR.Tests as FR
import qualified Duckling.Numeral.GA.Tests as GA
import qualified Duckling.Numeral.HE.Tests as HE
import qualified Duckling.Numeral.HI.Tests as HI
import qualified Duckling.Numeral.HR.Tests as HR
import qualified Duckling.Numeral.HU.Tests as HU
import qualified Duckling.Numeral.ID.Tests as ID
import qualified Duckling.Numeral.IS.Tests as IS
import qualified Duckling.Numeral.IT.Tests as IT
import qualified Duckling.Numeral.JA.Tests as JA
import qualified Duckling.Numeral.KA.Tests as KA
import qualified Duckling.Numeral.KM.Tests as KM
import qualified Duckling.Numeral.KN.Tests as KN
import qualified Duckling.Numeral.KO.Tests as KO
import qualified Duckling.Numeral.LO.Tests as LO
import qualified Duckling.Numeral.ML.Tests as ML
import qualified Duckling.Numeral.MN.Tests as MN
import qualified Duckling.Numeral.MY.Tests as MY
import qualified Duckling.Numeral.NB.Tests as NB
import qualified Duckling.Numeral.NE.Tests as NE
import qualified Duckling.Numeral.NL.Tests as NL
import qualified Duckling.Numeral.PL.Tests as PL
import qualified Duckling.Numeral.PT.Tests as PT
import qualified Duckling.Numeral.RO.Tests as RO
import qualified Duckling.Numeral.RU.Tests as RU
import qualified Duckling.Numeral.SK.Tests as SK
import qualified Duckling.Numeral.SV.Tests as SV
import qualified Duckling.Numeral.SW.Tests as SW
import qualified Duckling.Numeral.TA.Tests as TA
import qualified Duckling.Numeral.TE.Tests as TE
import qualified Duckling.Numeral.TH.Tests as TH
import qualified Duckling.Numeral.TR.Tests as TR
import qualified Duckling.Numeral.UK.Tests as UK
import qualified Duckling.Numeral.VI.Tests as VI
import qualified Duckling.Numeral.ZH.Tests as ZH

tests :: TestTree
tests = testGroup "Numeral Tests"
  [ AF.tests
  , AR.tests
  , BG.tests
  , BN.tests
  , CA.tests
  , CS.tests
  , DA.tests
  , DE.tests
  , EL.tests
  , EN.tests
  , ES.tests
  , ET.tests
  , FA.tests
  , FR.tests
  , FI.tests
  , GA.tests
  , HE.tests
  , HI.tests
  , HR.tests
  , HU.tests
  , ID.tests
  , IS.tests
  , IT.tests
  , JA.tests
  , KA.tests
  , KM.tests
  , KN.tests
  , KO.tests
  , LO.tests
  , ML.tests
  , MN.tests
  , MY.tests
  , NB.tests
  , NE.tests
  , NL.tests
  , PL.tests
  , PT.tests
  , RO.tests
  , RU.tests
  , SK.tests
  , SV.tests
  , SW.tests
  , TA.tests
  , TE.tests
  , TH.tests
  , TR.tests
  , UK.tests
  , VI.tests
  , ZH.tests
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.AF.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.AF.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "AF Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.AR.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Locale
import Duckling.Numeral.AR.Corpus
import Duckling.Testing.Asserts
import Duckling.Testing.Types hiding (examples)
import qualified Duckling.Numeral.AR.EG.Corpus as EG

tests :: TestTree
tests = testGroup "AR Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  , localeTests
  ]

localeTests :: TestTree
localeTests = testGroup "Locale Tests"
  [ testGroup "AR_EG Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeEG EG.allExamples
    ]
  ]
  where
    localeEG = makeLocale AR $ Just EG


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.BG.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.BG.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "BG Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


--Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.BN.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.BN.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "BN Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.CA.Tests
  ( tests ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.CA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CA Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.CS.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.CS.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "CS Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.DA.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.DA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "DA Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.DE.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.DE.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "DE Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.EL.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.EL.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "EL Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

{-# LANGUAGE OverloadedStrings #-}

module Duckling.Numeral.EN.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty
import Test.Tasty.HUnit

import Duckling.Dimensions.Types
import Duckling.Numeral.EN.Corpus
import Duckling.Numeral.Types
import Duckling.Testing.Asserts
import Duckling.Testing.Types
import Duckling.Types (Range(..))

tests :: TestTree
tests = testGroup "EN Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  , surroundTests
  , intersectTests
  , rangeTests
  ]

surroundTests :: TestTree
surroundTests = testCase "Surround Tests" $
  mapM_ (analyzedFirstTest testContext testOptions .
    withTargets [Seal Numeral]) xs
  where
    xs = concat
      [ examples (NumeralValue 3)
                 [ "3km"
                 ]
      , examples (NumeralValue 100000)
                 [ "100kâ‚¬"
                 , "100k\x20ac"
                 ]
      , examples (NumeralValue 10.99)
                 [ "10.99$"
                 ]
      ]

intersectTests :: TestTree
intersectTests = testCase "Intersect Test" $
  mapM_ (analyzedNTest testContext testOptions . withTargets [Seal Numeral]) xs
  where
    xs = [ ("10 millions minus 10", 2)
         ]

rangeTests :: TestTree
rangeTests = testCase "Range Test" $
  mapM_ (analyzedRangeTest testContext testOptions . withTargets [Seal Numeral]) xs
  where
    xs = [ ("negative negative 5", Range 9 19) -- prevent double negatives
         , ("negative-5", Range 8 10) -- prevent double negatives
         , ("- -5", Range 2 4) -- prevent clash with engine tokenizer
         ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.ES.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Locale
import Duckling.Numeral.ES.Corpus
import Duckling.Testing.Asserts
import Duckling.Testing.Types hiding (examples)
import qualified Duckling.Numeral.ES.AR.Corpus as AR
import qualified Duckling.Numeral.ES.CL.Corpus as CL
import qualified Duckling.Numeral.ES.CO.Corpus as CO
import qualified Duckling.Numeral.ES.ES.Corpus as ES
import qualified Duckling.Numeral.ES.MX.Corpus as MX
import qualified Duckling.Numeral.ES.PE.Corpus as PE
import qualified Duckling.Numeral.ES.VE.Corpus as VE
import qualified Duckling.Region as R
  ( Region
      ( AR
      , ES
      )
  )

tests :: TestTree
tests = testGroup "ES Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  , localeTests
  ]

localeTests :: TestTree
localeTests = testGroup "Locale Tests"
  [ testGroup "ES_AR Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeAR AR.allExamples
    ]
  , testGroup "ES_CL Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeCL CL.allExamples
    ]
  , testGroup "ES_CO Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeCO CO.allExamples
    ]
  , testGroup "ES_ES Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeES ES.allExamples
    ]
  , testGroup "ES_MX Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeMX MX.allExamples
    ]
  , testGroup "ES_PE Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localePE PE.allExamples
    ]
  , testGroup "ES_VE Tests"
    [ makeCorpusTest [Seal Numeral] $ withLocale corpus localeVE VE.allExamples
    ]
  ]
  where
    localeAR = makeLocale ES $ Just R.AR
    localeCL = makeLocale ES $ Just CL
    localeCO = makeLocale ES $ Just CO
    localeES = makeLocale ES $ Just R.ES
    localeMX = makeLocale ES $ Just MX
    localePE = makeLocale ES $ Just PE
    localeVE = makeLocale ES $ Just VE


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.ET.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.ET.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "ET Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.FA.Tests
  ( tests ) where

import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.FA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FA Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.FI.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.FI.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FI Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.FR.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.FR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "FR Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.GA.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.GA.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "GA Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.HE.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.HE.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HE Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


--Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.HI.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.HI.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HI Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.HR.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.HR.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HR Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.HU.Tests
  ( tests ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.HU.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "HU Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.ID.Tests
  ( tests ) where

import Prelude
import Data.String
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.ID.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "ID Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]


-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.

module Duckling.Numeral.IS.Tests
  ( tests
  ) where

import Data.String
import Prelude
import Test.Tasty

import Duckling.Dimensions.Types
import Duckling.Numeral.IS.Corpus
import Duckling.Testing.Asserts

tests :: TestTree
tests = testGroup "IS Tests"
  [ makeCorpusTest [Seal Numeral] corpus
  ]