Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to write test code for delegator contract #747

Closed
ghost opened this issue Mar 26, 2021 · 2 comments
Closed

how to write test code for delegator contract #747

ghost opened this issue Mar 26, 2021 · 2 comments
Labels
C-question Further information is requested

Comments

@ghost
Copy link

ghost commented Mar 26, 2021

Questions
when I want to test delegator contract function, I got error, when I use mockall, also got compile error

test code is here

#![cfg_attr(not(feature = "std"), no_std)]

use ink_lang as ink;

#[ink::contract]
mod delegator {
    use accumulator::Accumulator;
    use adder::Adder;
    use ink_storage::{
        traits::{
            PackedLayout,
            SpreadLayout,
        },
        Lazy,
    };
    use subber::Subber;

    /// Specifies the state of the delegator.
    ///
    /// In `Adder` state the delegator will delegate to the `Adder` contract
    /// and in `Subber` state will delegate to the `Subber` contract.
    ///
    /// The initial state is `Adder`.
    #[derive(
        Debug,
        Copy,
        Clone,
        PartialEq,
        Eq,
        scale::Encode,
        scale::Decode,
        SpreadLayout,
        PackedLayout,
    )]
    #[cfg_attr(
        feature = "std",
        derive(::scale_info::TypeInfo, ::ink_storage::traits::StorageLayout)
    )]
    pub enum Which {
        Adder,
        Subber,
    }

    /// Delegates calls to an adder or subber contract to mutate
    /// a value in an accumulator contract.
    ///
    /// In order to deploy the delegator smart contract we first
    /// have to manually put the code of the accumulator, adder
    /// and subber smart contracts, receive their code hashes from
    /// the signalled events and put their code hash into our
    /// delegator smart contract.
    #[ink(storage)]
    pub struct Delegator {
        /// Says which of adder or subber is currently in use.
        which: Which,
        /// The accumulator smart contract.
        accumulator: Lazy<Accumulator>,
        /// The adder smart contract.
        adder: Lazy<Adder>,
        /// The subber smart contract.
        subber: Lazy<Subber>,
    }

    impl Delegator {
        /// Instantiate a delegator with the given sub-contract codes.
        #[ink(constructor)]
        pub fn new(
            init_value: i32,
            accumulator_code_hash: Hash,
            adder_code_hash: Hash,
            subber_code_hash: Hash,
        ) -> Self {
            let total_balance = Self::env().balance();
            let accumulator = Accumulator::new(init_value)
                .endowment(total_balance / 4)
                .code_hash(accumulator_code_hash)
                .instantiate()
                .expect("failed at instantiating the `Accumulator` contract");
            let adder = Adder::new(accumulator.clone())
                .endowment(total_balance / 4)
                .code_hash(adder_code_hash)
                .instantiate()
                .expect("failed at instantiating the `Adder` contract");
            let subber = Subber::new(accumulator.clone())
                .endowment(total_balance / 4)
                .code_hash(subber_code_hash)
                .instantiate()
                .expect("failed at instantiating the `Subber` contract");
            Self {
                which: Which::Adder,
                accumulator: Lazy::new(accumulator),
                adder: Lazy::new(adder),
                subber: Lazy::new(subber),
            }
        }

        /// Returns the accumulator's value.
        #[ink(message)]
        pub fn get(&self) -> i32 {
            self.accumulator.get()
        }

        /// Delegates the call to either `Adder` or `Subber`.
        #[ink(message)]
        pub fn change(&mut self, by: i32) {
            match self.which {
                Which::Adder => self.adder.inc(by),
                Which::Subber => self.subber.dec(by),
            }
        }

        /// Switches the delegator.
        #[ink(message)]
        pub fn switch(&mut self) {
            match self.which {
                Which::Adder => {
                    self.which = Which::Subber;
                }
                Which::Subber => {
                    self.which = Which::Adder;
                }
            }
        }

    }


    #[cfg(test)]
    mod tests {
        use super::*;
        use ink_lang as ink;

        #[ink::test]
        pub fn default_works() {
            let mut delegator = Delegator::new(1, Hash::from([0x99; 32]),
                                           Hash::from([0x99; 32]), Hash::from([0x99; 32]));
            delegator.change(2);
        }

    }
}

then run cargo test, got error

running 1 test
test delegator::tests::default_works ... FAILED

failures:

---- delegator::tests::default_works stdout ----
thread 'delegator::tests::default_works' panicked at 'not implemented: off-chain environment does not support contract instantiation', /Users/jacksenguo/RustProjects/apron-contracts/ink/crates/env/src/engine/off_chain/impls.rs:373:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    delegator::tests::default_works
@HCastano HCastano added the C-question Further information is requested label Jun 14, 2021
@HCastano
Copy link
Contributor

HCastano commented Jun 14, 2021

@sharkygg This is a limitation of the current testing environment. However, there is a new off-chain environment in the works which will allow for this. See #788.

I was wrong about the new off-chain environement, see the comment below.

@Robbepop
Copy link
Collaborator

Robbepop commented Jun 16, 2021

For off-chain testing purposes it is better to have a constructor like the following:

pub fn new(
            init_value: i32,
            accumulator: Accumulator,
            adder: Adder,
            subber: Subber,
        ) -> Self { ... }

So basically replacing hashes with their concrete contract instances.
This way you do part of the job of the original constructor but have full control over the process in the off-chain testing.

Note that the new off-chain environment won't really fix the previous problems either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants