diff --git a/examples/solidity/bad/nobytecode.sol b/examples/solidity/bad/nobytecode.sol new file mode 100644 index 00000000..2990f91c --- /dev/null +++ b/examples/solidity/bad/nobytecode.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.24; + +contract Abstract { + function nothere() pure public {} + function echidna_nothere() pure public {} +} diff --git a/examples/solidity/bad/nocontract.sol b/examples/solidity/bad/nocontract.sol new file mode 100644 index 00000000..2990f91c --- /dev/null +++ b/examples/solidity/bad/nocontract.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.24; + +contract Abstract { + function nothere() pure public {} + function echidna_nothere() pure public {} +} diff --git a/examples/solidity/bad/nofuncs.sol b/examples/solidity/bad/nofuncs.sol new file mode 100644 index 00000000..4bc0fa43 --- /dev/null +++ b/examples/solidity/bad/nofuncs.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.4.24; + +contract Abstract {} diff --git a/examples/solidity/bad/notests.sol b/examples/solidity/bad/notests.sol new file mode 100644 index 00000000..865a209a --- /dev/null +++ b/examples/solidity/bad/notests.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.24; + +contract Abstract { + function f() pure public returns (int) {return 0;} +} diff --git a/examples/solidity/bad/onlytests.sol b/examples/solidity/bad/onlytests.sol new file mode 100644 index 00000000..ee244d6b --- /dev/null +++ b/examples/solidity/bad/onlytests.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.24; + +contract Abstract { + function echidna_f() pure public returns (int) {return 0;} +} diff --git a/examples/solidity/bad/testargs.sol b/examples/solidity/bad/testargs.sol new file mode 100644 index 00000000..aa37284a --- /dev/null +++ b/examples/solidity/bad/testargs.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.24; + +contract Abstract { + function f() pure public {} + function echidna_f(int x) pure public returns (int) {return 0;} +} diff --git a/src/test/Spec.hs b/src/test/Spec.hs index 3230fdf3..4b15534d 100644 --- a/src/test/Spec.hs +++ b/src/test/Spec.hs @@ -1,13 +1,16 @@ +{-# LANGUAGE LambdaCase #-} + import Test.Tasty import Test.Tasty.HUnit import Echidna.ABI (SolCall) import Echidna.Campaign (Campaign(..), tests, campaign, TestState(..)) import Echidna.Config (defaultConfig, parseConfig, sConf) -import Echidna.Solidity (loadSolTests, quiet) +import Echidna.Solidity (SolException(..), loadSolidity, loadSolTests, quiet) import Echidna.Transaction (Tx, call) import Control.Lens +import Control.Monad.Catch (MonadCatch(..)) import Control.Monad.Reader (runReaderT) import Data.Maybe (isJust, maybe) import Data.Text (Text, unpack) @@ -17,10 +20,34 @@ import System.Directory (withCurrentDirectory) main :: IO () main = withCurrentDirectory "./examples/solidity" . defaultMain $ - testGroup "Echidna" [solidityTests] + testGroup "Echidna" [compilationTests, integrationTests] + +-- Compilation tests + +compilationTests :: TestTree +compilationTests = testGroup "Compilation and loading tests" + [ loadFails "bad/nocontract.sol" (Just "c") "failed to warn on contract not found" $ + \case ContractNotFound{} -> True; _ -> False + , loadFails "bad/nobytecode.sol" Nothing "failed to warn on abstract contract" $ + \case NoBytecode{} -> True; _ -> False + , loadFails "bad/nofuncs.sol" Nothing "failed to warn on no functions found" $ + \case NoFuncs{} -> True; _ -> False + , loadFails "bad/notests.sol" Nothing "failed to warn on no tests found" $ + \case NoTests{} -> True; _ -> False + , loadFails "bad/onlytests.sol" Nothing "failed to warn on no non-tests found" $ + \case OnlyTests{} -> True; _ -> False + , loadFails "bad/testargs.sol" Nothing "failed to warn on test args found" $ + \case TestArgsFound{} -> True; _ -> False + ] + +loadFails :: FilePath -> Maybe Text -> String -> (SolException -> Bool) -> TestTree +loadFails fp c e p = testCase fp . catch tryLoad $ assertBool e . p where + tryLoad = runReaderT (loadSolidity fp c >> pure ()) $ defaultConfig & sConf . quiet .~ True + +-- Integration Tests -solidityTests :: TestTree -solidityTests = testGroup "Solidity Integration Testing" +integrationTests :: TestTree +integrationTests = testGroup "Solidity Integration Testing" [ testContract "basic/true.sol" Nothing [ ("echidna_true failed", not . solved "echidna_true") ] , testContract "basic/flags.sol" Nothing