content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    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 CPP #-}
  module UnitTests (main) where
  
  import Test.HUnit
  import TestRunner
  
  import Util.ByteString
  import Util.Aeson
  import qualified Util.Text as UT
  import Data.Aeson.Types
  import Data.Aeson (decode)
  import Data.ByteString (packCString, packCStringLen, ByteString)
  
  import Foreign.Storable
  import Foreign.C.String
  import Foreign.C.Types
  import Foreign.Marshal.Array (advancePtr)
  import Foreign.Ptr (nullPtr, Ptr)
  
  import TextShow
  
  intToByteStringTest :: Test
  intToByteStringTest = TestCase $ do
    assertEqual "min int" (intToByteString minBound) "-9223372036854775808"
    assertEqual "max int" (intToByteString maxBound) "9223372036854775807"
    assertEqual "zero" (intToByteString 0) "0"
  
  parseValueStrictTest :: Test
  parseValueStrictTest = TestCase $ do
    assertEqual "false" (Right $ Bool False) $ parseValueStrict' "false"
    assertEqual "0.1" (Right $ Number 0.1) $ parseValueStrict' "0.1"
    assertEqual "consume all input" (Left "endOfInput") $
      parseValueStrict' "falsee"
  
  #ifdef FACEBOOK
  -- | We've patched the official aeson library to handle NaN. See #5183005
  -- This test ensures that we notice if we forget to patch on upgrade.
  parseNaN :: Test
  parseNaN = TestCase $
    case decode "[NaN]" of
      Just [a :: Double] ->
        assertBool "NaN" $ isNaN a
      _ -> assertFailure "couldn't parse NaN"
  #endif
  
  withCStringLenTest :: Test
  withCStringLenTest = TestCase $
    UT.withCStringLen "Hello World" $ \(ptr, _) -> do
      val <- peek ptr
      assertEqual "first character" val (castCharToCChar 'H')
  
  useByteStringsAsCStringsTest :: Test
  useByteStringsAsCStringsTest = TestCase $
    useByteStringsAsCStrings ["hello", "world"] $ \ptr -> do
      hello <- packCString =<< peek ptr
      world <- packCString =<< peek (advancePtr ptr 1)
      term <- peek $ advancePtr ptr 2
      assertEqual "first word" hello "hello"
      assertEqual "second word" world "world"
      assertEqual "terminator" term nullPtr
  
  -- This should probably be a QuickCheck Property
  bsListAsCStrLenArrTest :: [ByteString] -> Test
  bsListAsCStrLenArrTest bs = TestCase $
    bsListAsCStrLenArr bs $ \strPtr lenPtr len -> do
      let packBS :: CSize -> IO ByteString
          packBS i = packCStringLen =<< (,)
                     <$> peek (getPtr strPtr)
                     <*> (fromIntegral <$> peek (getPtr lenPtr))
              where getPtr :: Storable a => Ptr a -> Ptr a
                    getPtr = (`advancePtr` fromIntegral i)
      got <- mapM packBS [0..len - 1]
      assertEqual "same list" got bs
  
  data MyEnum = MyA | MyB
    deriving (Bounded, Enum, Eq, Show)
  
  instance UT.TextRead MyEnum
  instance TextShow MyEnum where
    showb MyA = "MyA"
    showb MyB = "MyB"
  
  readTextTest :: Test
  readTextTest = TestCase $ do
    assertEqual "myA" (Just MyA) (UT.readText "MyA")
    assertEqual "Nothing" (Nothing :: Maybe MyEnum) (UT.readText "MyC")
  
  insertCommasAndAndTest :: Test
  insertCommasAndAndTest = TestCase $ do
    assertEqual "null" "" $ UT.insertCommasAndAnd []
    assertEqual "singleton" "foo" $ UT.insertCommasAndAnd ["foo"]
    assertEqual "pair" "foo and bar" $ UT.insertCommasAndAnd ["foo", "bar"]
    assertEqual "triple" "foo, bar, and baz" $
      UT.insertCommasAndAnd ["foo", "bar", "baz"]
    assertEqual "quad" "foo, bar, baz, and quux" $
      UT.insertCommasAndAnd ["foo", "bar", "baz", "quux"]
    assertEqual "10" "1, 2, 3, 4, 5, 6, 7, 8, 9, and 10" $
      UT.insertCommasAndAnd [ showt (i::Int) | i <- [1..10] ]
  
  main :: IO ()
  main = testRunner $ TestList
    [ TestLabel "intToByteString" intToByteStringTest
    , TestLabel "parseValueStrictTest" parseValueStrictTest
  #ifdef FACEBOOK
    , TestLabel "parseNaN" parseNaN
  #endif
    , TestLabel "withCStringLen" withCStringLenTest
    , TestLabel "useByteStringsAsCStrings" useByteStringsAsCStringsTest
    , TestLabel "bsListAsCStrLenArr" (bsListAsCStrLenArrTest ["hello", "world"])
    , TestLabel "readText" readTextTest
    , TestLabel "insertCommasAndAnd" insertCommasAndAndTest
    ]
  