packages feed

toxcore-0.2.0: test/Network/Tox/C/ToxSpec.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE Trustworthy #-}
module Network.Tox.C.ToxSpec where

import           Control.Applicative               ((<$>), (<*>))
import qualified Crypto.Saltine.Internal.ByteSizes as Sodium (boxPK, boxSK)
import qualified Data.ByteString                   as BS
import           Data.ByteString.Arbitrary         (fromABS)
import           Data.Default.Class                (def)
import           Test.Hspec
import           Test.QuickCheck
import           Test.QuickCheck.Arbitrary         (arbitraryBoundedEnum,
                                                    genericShrink)

import qualified Network.Tox.C                     as C


instance Arbitrary C.ProxyType where
  shrink = genericShrink
  arbitrary = arbitraryBoundedEnum

instance Arbitrary C.SavedataType where
  shrink = genericShrink
  arbitrary = arbitraryBoundedEnum

instance Arbitrary BS.ByteString where
  shrink bs = if BS.null bs then [] else BS.inits bs
  arbitrary = fromABS <$> arbitrary

-- | Ensure that the hostname has a chance of being valid.
filterHost :: C.Options -> C.Options
filterHost o@C.Options{C.proxyHost = h} = o{C.proxyHost = filter (`elem` hostChars) h}
  where
    hostChars = ".-_" ++ ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z']

instance Arbitrary C.Options where
  shrink = map filterHost . genericShrink
  arbitrary = fmap filterHost $ C.Options
    <$> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary
    <*> arbitrary


getRight :: (Monad m, Show a) => Either a b -> m b
getRight (Left  l) = fail $ show l
getRight (Right r) = return r


must :: Show a => IO (Either a b) -> IO b
must = (getRight =<<)


spec :: Spec
spec = do
  describe "tox_version_is_compatible" $
    it "is compatible with the major/minor/patch of the linked library" $
      C.tox_version_is_compatible
        C.tox_version_major
        C.tox_version_minor
        C.tox_version_patch
      `shouldBe` True

  describe "Constants" $
    it "has constants equal to the hstox expected key size" $ do
      fromIntegral C.tox_public_key_size `shouldBe` Sodium.boxPK
      fromIntegral C.tox_secret_key_size `shouldBe` Sodium.boxSK
      C.tox_address_size `shouldBe` C.tox_public_key_size + 6
      C.tox_max_name_length `shouldBe` 128
      C.tox_max_status_message_length `shouldBe` 1007
      C.tox_max_friend_request_length `shouldBe` 1016
      C.tox_max_message_length `shouldBe` C.tox_max_custom_packet_size - 1
      C.tox_max_custom_packet_size `shouldBe` 1373
      C.tox_max_filename_length `shouldBe` 255
      C.tox_hash_length `shouldBe` C.tox_file_id_length

  describe "Options" $ do
    it "can be marshalled to C and back" $
      property $ \options -> do
        res <- C.withOptions options C.peekToxOptions
        res `shouldBe` Right options

    it "is saved correctly by pokeToxOptions" $
      property $ \options0 options1 -> do
        res <- C.withOptions options0 $ \ptr -> do
          C.pokeToxOptions options1 ptr (return ())
          C.peekToxOptions ptr
        res `shouldBe` Right options0

    it "has a 'def' that is equivalent to the C default options" $ do
      res <- C.withToxOptions C.peekToxOptions
      res `shouldBe` Right def

  describe "nospam" $
    it "can be retrieved after being set" $
      property $ \nospam ->
        must $ C.withDefaultTox $ \tox -> do
          C.tox_self_set_nospam tox nospam
          nospam' <- C.tox_self_get_nospam tox
          nospam' `shouldBe` nospam

  describe "public key" $ do
    it "is a prefix of the address" $
      must $ C.withDefaultTox $ \tox -> do
        pk <- C.toxSelfGetPublicKey tox
        addr <- C.toxSelfGetAddress tox
        BS.unpack addr `shouldStartWith` BS.unpack pk

    it "is not equal to the secret key" $
      must $ C.withDefaultTox $ \tox -> do
        pk <- C.toxSelfGetPublicKey tox
        sk <- C.toxSelfGetSecretKey tox
        pk `shouldNotBe` sk