b3-users 0.1.4

A simple user management system for the Internet Computer
Documentation
// mocks.rs
#![cfg(test)]

use ic_cdk::export::candid::Principal;
use lazy_static::lazy_static;
use proptest::test_runner::TestRunner;
use proptest::{prelude::*, strategy::ValueTree};
use std::{collections::HashMap, sync::RwLock};

use crate::data::account::{UserAccountArgs, UserAccountData};
use crate::data::chain::UserChainData;
use crate::data::transaction::UserTransactionData;
use crate::data::user::{UserData, UserDataArgs, UserDataSettingValue, UserProfileArgs};

const DEFAULT_BYTES: [u8; 29] = [0; 29];
const OWNER_BYTES: [u8; 29] = [1; 29];
const WALLET_CANISTER_BYTES: [u8; 29] = [2; 29];

lazy_static! {
    static ref GENERATED_BYTES: RwLock<[u8; 29]> = RwLock::new(DEFAULT_BYTES);
}

pub fn random_caller() {
    let byte_strategy = any::<[u8; 29]>();

    let bytes_tree = byte_strategy.new_tree(&mut TestRunner::default()).unwrap();

    let bytes = bytes_tree.current();

    *GENERATED_BYTES.write().unwrap() = bytes;
}

pub fn owner_caller() {
    *GENERATED_BYTES.write().unwrap() = OWNER_BYTES;
}

pub fn wallet_canister_caller() {
    *GENERATED_BYTES.write().unwrap() = WALLET_CANISTER_BYTES;
}

pub fn reset_bytes() {
    *GENERATED_BYTES.write().unwrap() = DEFAULT_BYTES;
}

pub fn owner_principal() -> Principal {
    Principal::from_slice(&OWNER_BYTES)
}

pub fn wallet_canister_principal() -> Principal {
    Principal::from_slice(&WALLET_CANISTER_BYTES)
}

pub fn set_caller(principal: Principal) {
    *GENERATED_BYTES.write().unwrap() = principal.as_slice().to_vec().try_into().unwrap();
}

pub fn ic_caller() -> Principal {
    let bytes = GENERATED_BYTES.read().unwrap().clone();

    Principal::from_slice(&bytes)
}

pub fn ic_timestamp() -> u64 {
    u64::from(1667817318 as u64)
}

pub fn random_principal() -> Principal {
    let strategy = principal_strategy();

    strategy
        .new_tree(&mut TestRunner::default())
        .unwrap()
        .current()
}

pub fn principal_strategy() -> impl Strategy<Value = Principal> {
    any::<[u8; 29]>().prop_map(move |bytes| Principal::from_slice(&bytes))
}

impl Arbitrary for UserDataSettingValue {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        prop_oneof![
            any::<String>().prop_map(|value| UserDataSettingValue::StringValue(value)),
            any::<u128>().prop_map(|value| UserDataSettingValue::NumberValue(value)),
            any::<f64>().prop_map(|value| UserDataSettingValue::FloatValue(value)),
            any::<bool>().prop_map(|value| UserDataSettingValue::BoolValue(value))
        ]
        .boxed()
    }
}

impl Arbitrary for UserData {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (
            any::<String>(),
            any::<String>(),
            any::<String>(),
            any::<u128>(),
            any::<UserAccountData>(),
            any::<UserProfileArgs>(),
            any::<HashMap<String, UserDataSettingValue>>(),
        )
            .prop_map(
                |(name, email, password, balance, accounts, profile, settings)| {
                    UserData::new(
                        UserDataArgs {
                            password: Some(password),
                            balance: Some(balance),
                            settings: Some(settings),
                            email: Some(email),
                            name: Some(name),
                            profile: Some(profile),
                        },
                        UserAccountArgs {
                            public_key: accounts.public_key,
                            name: Some(accounts.name),
                            hidden: Some(accounts.hidden),
                            disabled: Some(accounts.disabled),
                        },
                    )
                },
            )
            .boxed()
    }
}

impl Arbitrary for UserProfileArgs {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (
            any::<String>(),
            any::<String>(),
            any::<String>(),
            any::<HashMap<String, String>>(),
        )
            .prop_map(|(full_name, address, phone_number, attributes)| Self {
                full_name: Some(full_name),
                address: Some(address),
                phone_number: Some(phone_number),
                attributes: Some(attributes),
            })
            .boxed()
    }
}

impl Arbitrary for UserDataArgs {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (
            any::<Option<String>>(),
            any::<Option<String>>(),
            any::<Option<u128>>(),
            any::<Option<String>>(),
            any::<Option<UserProfileArgs>>(),
            any::<Option<HashMap<String, UserDataSettingValue>>>(),
        )
            .prop_map(
                |(name, email, balance, password, profile, settings)| UserDataArgs {
                    name,
                    email,
                    balance,
                    password,
                    profile,
                    settings,
                },
            )
            .boxed()
    }
}

impl Arbitrary for UserAccountArgs {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (
            any::<Vec<u8>>(),
            any::<Option<String>>(),
            any::<Option<bool>>(),
            any::<Option<bool>>(),
        )
            .prop_map(|(public_key, name, hidden, disabled)| Self {
                public_key,
                name,
                hidden,
                disabled,
            })
            .boxed()
    }
}

impl Arbitrary for UserAccountData {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (
            any::<Vec<u8>>(),
            any::<String>(),
            any::<bool>(),
            any::<bool>(),
            any::<HashMap<u64, UserChainData>>(),
        )
            .prop_map(|(public_key, name, hidden, disabled, chain_data)| Self {
                public_key,
                name,
                hidden,
                disabled,
                chain_data,
            })
            .boxed()
    }
}

impl Arbitrary for UserChainData {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (any::<UserTransactionData>())
            .prop_map(|transaction| UserChainData::new(transaction))
            .boxed()
    }
}

impl Arbitrary for UserTransactionData {
    type Parameters = ();
    type Strategy = BoxedStrategy<Self>;

    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        (any::<Vec<u8>>(), any::<u64>(), any::<u64>())
            .prop_map(|(data, cycle, timestamp)| UserTransactionData::new(data, cycle, timestamp))
            .boxed()
    }
}