haskoin-script-0.0.1: tests/Network/Haskoin/Script/Tests.hs
module Network.Haskoin.Script.Tests (tests) where
import Test.QuickCheck.Property (Property, (==>))
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Control.Applicative ((<$>))
import Data.Bits (setBit, testBit)
import Data.Binary (Word8)
import qualified Data.ByteString as BS
( singleton
, length
, tail
, head
, pack
)
import Network.Haskoin.Protocol.Arbitrary ()
import Network.Haskoin.Script.Arbitrary (ScriptOpInt(..))
import Network.Haskoin.Script
import Network.Haskoin.Crypto
import Network.Haskoin.Protocol
import Network.Haskoin.Util
tests :: [Test]
tests =
[ testGroup "Script Parser"
[ testProperty "decode . encode OP_1 .. OP_16" testScriptOpInt
, testProperty "decode . encode ScriptOutput" testScriptOutput
, testProperty "decode . encode ScriptInput" testScriptInput
, testProperty "decode . encode ScriptHashInput" testScriptHashInput
, testProperty "sorting MultiSig scripts" testSortMulSig
]
, testGroup "Script SigHash"
[ testProperty "canonical signatures" testCanonicalSig
, testProperty "decode . encode SigHash" binSigHash
, testProperty "decode SigHash from Word8" binSigHashByte
, testProperty "encodeSigHash32 is 4 bytes long" testEncodeSH32
, testProperty "decode . encode TxSignature" binTxSig
, testProperty "decodeCanonical . encode TxSignature" binTxSigCanonical
, testProperty "Testing txSigHash with SigSingle" testSigHashOne
]
]
{- Script Parser -}
testScriptOpInt :: ScriptOpInt -> Bool
testScriptOpInt (ScriptOpInt i) = (intToScriptOp <$> scriptOpToInt i) == Right i
testScriptOutput :: ScriptOutput -> Bool
testScriptOutput so = (decodeOutput $ encodeOutput so) == Right so
testScriptInput :: ScriptInput -> Bool
testScriptInput si = (decodeInput $ encodeInput si) == Right si
testScriptHashInput :: ScriptHashInput -> Bool
testScriptHashInput sh = (decodeScriptHash $ encodeScriptHash sh) == Right sh
testSortMulSig :: ScriptOutput -> Bool
testSortMulSig out = case out of
(PayMulSig _ _) -> check $ sortMulSig out
_ -> True
where check (PayMulSig ps _)
| length ps <= 1 = True
| otherwise = snd $ foldl f (head ps,True) $ tail ps
check _ = False
f (a,t) b | t && encode' a <= encode' b = (b,True)
| otherwise = (b,False)
{- Script SigHash -}
testCanonicalSig :: TxSignature -> Bool
testCanonicalSig ts@(TxSignature _ sh)
| isSigUnknown sh = isLeft $ decodeCanonicalSig bs
| otherwise = isRight (decodeCanonicalSig bs) &&
isCanonicalHalfOrder (txSignature ts)
where bs = encodeSig ts
binSigHash :: SigHash -> Bool
binSigHash sh = (decode' $ encode' sh) == sh
binSigHashByte :: Word8 -> Bool
binSigHashByte w
| w == 0x01 = res == SigAll False
| w == 0x02 = res == SigNone False
| w == 0x03 = res == SigSingle False
| w == 0x81 = res == SigAll True
| w == 0x82 = res == SigNone True
| w == 0x83 = res == SigSingle True
| testBit w 7 = res == SigUnknown True w
| otherwise = res == SigUnknown False w
where res = decode' $ BS.singleton w
testEncodeSH32 :: SigHash -> Bool
testEncodeSH32 sh = BS.length bs == 4 && BS.head bs == w && BS.tail bs == zs
where bs = encodeSigHash32 sh
w = BS.head $ encode' sh
zs = BS.pack [0,0,0]
binTxSig :: TxSignature -> Bool
binTxSig ts = (fromRight $ decodeSig $ encodeSig ts) == ts
binTxSigCanonical :: TxSignature -> Bool
binTxSigCanonical ts@(TxSignature _ sh)
| isSigUnknown sh = isLeft $ decodeCanonicalSig $ encodeSig ts
| otherwise = (fromRight $ decodeCanonicalSig $ encodeSig ts) == ts
testSigHashOne :: Tx -> Script -> Bool -> Property
testSigHashOne tx s acp = not (null $ txIn tx) ==>
if length (txIn tx) > length (txOut tx)
then res == (setBit 0 248)
else res /= (setBit 0 248)
where res = txSigHash tx s (length (txIn tx) - 1) (SigSingle acp)