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.
  -}
  
  module RTSJSONTest (main) where
  
  import Control.Monad.ST
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.Char8 as Char8
  import Data.Int (Int64)
  import Data.Text (Text)
  import Data.Text.Arbitrary ()
  import qualified Data.Text.Encoding as Text
  import Test.HUnit hiding (assert)
  import Test.QuickCheck
  import Test.QuickCheck.Monadic
  
  import TestRunner
  import qualified Util.Buffer as Buffer
  import Util.Testing
  
  import Glean.Init (withUnitTest)
  import qualified Glean.RTS as RTS
  import qualified Glean.RTS.Foreign.JSON as RTS
  
  prop_number :: Int64 -> Property
  prop_number n =
    runST (Buffer.fillByteString 21 $ Buffer.alloc 21 $ RTS.encodeNumber n)
    ===
    Char8.pack (show n)
  
  prop_number_roundtrip :: Int64 -> Property
  prop_number_roundtrip n = monadicIO $ do
    let !enc = runST $
          Buffer.fillByteString 21 $ Buffer.alloc 21 $ RTS.encodeNumber n
    m <- run $ RTS.withParsed enc $ \val -> case val of
      RTS.Int m -> return m
      _ -> fail "not a number"
    assert (m == n)
  
  prop_string_roundtrip :: Text -> Property
  prop_string_roundtrip t = monadicIO $ do
    enc <- run $ RTS.unsafeWithByteStringRef utf8 $ \ref -> stToIO $ do
      n <- RTS.getStringEscapedSize ref
      Buffer.fillByteString n $ do
        Buffer.ascii '\"'
        Buffer.alloc n $ \p -> do
          RTS.escapeString ref p n
          return n
        Buffer.ascii '\"'
    s <- run $ RTS.withParsed enc $ \val -> case val of
      RTS.String ref -> RTS.derefByteString ref
      _ -> fail "not a string"
    assert (s == utf8)
    where
      utf8 = Text.encodeUtf8 t
  
  prop_mangled_string_roundtrip :: Text -> Property
  prop_mangled_string_roundtrip t = monadicIO $ do
    enc <- run $ RTS.unsafeWithMangledStringRef (mangle utf8)
      $ \ref -> stToIO $ do
        n <- RTS.getMangledStringEscapedSize ref
        Buffer.fillByteString n $ do
          Buffer.ascii '\"'
          Buffer.alloc n $ \p -> do
            RTS.escapeMangledString ref p n
            return n
          Buffer.ascii '\"'
    s <- run $ RTS.withParsed enc $ \val -> case val of
      RTS.String ref -> RTS.derefByteString ref
      _ -> fail "not a string"
    assert (s == utf8)
    where
      utf8 = Text.encodeUtf8 t
  
      mangle s =
        BS.pack (concatMap (\c -> if c == 0 then [0,1] else [c]) $ BS.unpack s)
        <>
        BS.pack [0,0]
  
  main :: IO ()
  main = withUnitTest $ testRunner $ TestList
    [ TestLabel "number" $ TestCase $ assertProperty "mismatch"
        prop_number
    , TestLabel "number_roundtrip" $ TestCase $ assertProperty "mismatch"
        prop_number_roundtrip
    , TestLabel "string_roundtrip" $ TestCase $ assertProperty "mismatch"
        prop_string_roundtrip
    , TestLabel "mangled_string_roundtrip" $ TestCase $ assertProperty "mismatch"
        prop_mangled_string_roundtrip
    ]
  