{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} -- | -- Module : Network.Ethereum.Test.ComplexStorageSpec -- Copyright : Alexander Krupenkin 2016 -- License : BSD3 -- -- Maintainer : mail@akru.me -- Stability : experimental -- Portability : unportable -- -- ComplexStorage is a Solidity contract which has global variables of -- several different types. The point of this test is to test the encoding -- of a complicated Solidity tuple, consisting of dynamically and statically -- sized components. -- module Network.Ethereum.Test.ComplexStorageSpec where import Control.Concurrent.Async (async, wait) import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Control.Monad.IO.Class (liftIO) import Data.Default (def) import Network.Ethereum hiding (convert) import Network.Ethereum.Api.Types (Filter (..)) import Network.Ethereum.Contract (new) import Network.Ethereum.Contract.TH import Network.Ethereum.Test.Utils import Test.Hspec [abiFrom|test/contracts/ComplexStorage.json|] deploy :: IO Address deploy = do Just address <- web3 $ withAccount () $ withParam id $ new ComplexStorageContract putStrLn $ "ComplexStorage: " ++ show address return address spec :: Spec spec = deploy `before` complexStorageSpec complexStorageSpec :: SpecWith Address complexStorageSpec = do describe "can interact with a ComplexStorage contract" $ do -- todo: these should ideally be arbitrary! let sUint = 1 sInt = -1 sBool = True sInt224 = 221 sBools = [True, False] sInts = [1, 1, -3] sString = "hello" sBytes16 = "\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78" sByte2sElem = "\x12\x34" sByte2sVec = [sByte2sElem, sByte2sElem, sByte2sElem, sByte2sElem] sByte2s = [sByte2sVec, sByte2sVec] it "can set the values of a ComplexStorage and validate them with an event" $ \storage -> do let fltr = (def :: Filter ValsSet) { filterAddress = Just [storage] } -- kick off listening for the ValsSet event vals <- newEmptyMVar fiber <- async . web3 $ event fltr $ \vs -> do liftIO $ putMVar vals vs pure TerminateEvent -- kick off tx _ <- contract storage $ setValues sUint sInt sBool sInt224 sBools sInts sString sBytes16 sByte2s -- wait for its ValsSet event wait fiber (ValsSet vsA vsB vsC vsD vsE vsF vsG vsH vsI) <- takeMVar vals vsA `shouldBe` sUint vsB `shouldBe` sInt vsC `shouldBe` sBool vsD `shouldBe` sInt224 vsE `shouldBe` sBools vsF `shouldBe` sInts vsG `shouldBe` sString vsH `shouldBe` sBytes16 vsI `shouldBe` sByte2s it "can verify that it set the values correctly" $ \storage -> do -- Write a values _ <- contract storage $ setValues sUint sInt sBool sInt224 sBools sInts sString sBytes16 sByte2s -- Read a couple of values (uintVal', intVal', boolVal', int224Val', boolsVal, intsVal, stringVal', bytes16Val', bytes2s) <- contract storage $ (,,,,,,,,) <$> uintVal <*> intVal <*> boolVal <*> int224Val <*> boolVectorVal 0 <*> intListVal 0 <*> stringVal <*> bytes16Val <*> bytes2VectorListVal 0 0 uintVal' `shouldBe` sUint intVal' `shouldBe` sInt boolVal' `shouldBe` sBool int224Val' `shouldBe` sInt224 boolsVal `shouldBe` True intsVal `shouldBe` head sInts stringVal' `shouldBe` sString bytes16Val' `shouldBe` sBytes16 bytes2s `shouldBe` sByte2sElem it "can decode a complicated value correctly" $ \storage -> do -- Write a values _ <- contract storage $ setValues sUint sInt sBool sInt224 sBools sInts sString sBytes16 sByte2s -- Read a all values allVals <- contract storage getVals allVals `shouldBe` (sUint, sInt, sBool, sInt224, sBools, sInts, sString, sBytes16, sByte2s)