use crate::file_format::{
AddressIdentifierIndex, CompiledModule, FunctionDefinition, FunctionHandle, IdentifierIndex,
ModuleHandle, ModuleHandleIndex, StructDefinition, TableIndex,
};
use move_core_types::{account_address::AccountAddress, identifier::Identifier};
use proptest::{
collection::{btree_set, vec, SizeRange},
prelude::*,
sample::Index as PropIndex,
};
mod constants;
mod functions;
mod metadata;
mod signature;
mod types;
use constants::ConstantPoolGen;
use functions::{
FnDefnMaterializeState, FnHandleMaterializeState, FunctionDefinitionGen, FunctionHandleGen,
};
use crate::proptest_types::{
metadata::MetadataGen,
signature::SignatureGen,
types::{StDefnMaterializeState, StructDefinitionGen, StructHandleGen},
};
use std::collections::{BTreeSet, HashMap};
pub type TableSize = u16;
impl CompiledModule {
pub fn valid_strategy(size: usize) -> impl Strategy<Value = Self> {
CompiledModuleStrategyGen::new(size as TableSize).generate()
}
}
#[derive(Clone, Debug)]
pub struct CompiledModuleStrategyGen {
size: usize,
field_count: SizeRange,
struct_type_params: SizeRange,
parameters_count: SizeRange,
return_count: SizeRange,
func_type_params: SizeRange,
acquires_count: SizeRange,
random_sigs_count: SizeRange,
tokens_per_random_sig_count: SizeRange,
code_len: SizeRange,
}
impl CompiledModuleStrategyGen {
pub fn new(size: TableSize) -> Self {
Self {
size: size as usize,
field_count: (0..5).into(),
struct_type_params: (0..3).into(),
parameters_count: (0..4).into(),
return_count: (0..3).into(),
func_type_params: (0..3).into(),
acquires_count: (0..2).into(),
random_sigs_count: (0..5).into(),
tokens_per_random_sig_count: (0..5).into(),
code_len: (0..50).into(),
}
}
#[inline]
pub fn zeros_all(&mut self) -> &mut Self {
self.field_count = 0.into();
self.struct_type_params = 0.into();
self.parameters_count = 0.into();
self.return_count = 0.into();
self.func_type_params = 0.into();
self.acquires_count = 0.into();
self.random_sigs_count = 0.into();
self.tokens_per_random_sig_count = 0.into();
self
}
pub fn generate(self) -> impl Strategy<Value = CompiledModule> {
let self_idx_strat = any::<PropIndex>();
let address_pool_strat = btree_set(any::<AccountAddress>(), 1..=self.size);
let identifiers_strat = btree_set(any::<Identifier>(), 5..=self.size + 5);
let constant_pool_strat = ConstantPoolGen::strategy(0..=self.size, 0..=self.size);
let metadata_strat = MetadataGen::strategy(0..=self.size);
let module_handles_strat = vec(any::<(PropIndex, PropIndex)>(), 1..=self.size);
let struct_handles_strat = vec(
StructHandleGen::strategy(self.struct_type_params.clone()),
1..=self.size,
);
let struct_defs_strat = vec(
StructDefinitionGen::strategy(
self.field_count.clone(),
self.struct_type_params.clone(),
),
1..=self.size,
);
let random_sigs_strat = vec(
SignatureGen::strategy(self.tokens_per_random_sig_count),
self.random_sigs_count,
);
let function_handles_strat = vec(
FunctionHandleGen::strategy(
self.parameters_count.clone(),
self.return_count.clone(),
self.func_type_params.clone(),
),
1..=self.size,
);
let function_defs_strat = vec(
FunctionDefinitionGen::strategy(
self.return_count.clone(),
self.parameters_count.clone(),
self.func_type_params.clone(),
self.acquires_count.clone(),
self.code_len,
),
1..=self.size,
);
let friends_strat = vec(any::<(PropIndex, PropIndex)>(), 1..=self.size);
(
self_idx_strat,
(
address_pool_strat,
identifiers_strat,
constant_pool_strat,
metadata_strat,
),
module_handles_strat,
(struct_handles_strat, struct_defs_strat),
random_sigs_strat,
(function_handles_strat, function_defs_strat),
friends_strat,
)
.prop_map(
|(
self_idx_gen,
(address_identifier_gens, identifier_gens, constant_pool_gen, metdata_gen),
module_handles_gen,
(struct_handle_gens, struct_def_gens),
random_sigs_gens,
(function_handle_gens, function_def_gens),
friend_decl_gens,
)| {
let address_identifiers: Vec<_> = address_identifier_gens.into_iter().collect();
let address_identifiers_len = address_identifiers.len();
let identifiers: Vec<_> = identifier_gens.into_iter().collect();
let identifiers_len = identifiers.len();
let constant_pool = constant_pool_gen.constant_pool();
let constant_pool_len = constant_pool.len();
let metadata = metdata_gen.metadata();
let mut module_handles_set = BTreeSet::new();
let mut module_handles = vec![];
for (address, name) in module_handles_gen {
let mh = ModuleHandle {
address: AddressIdentifierIndex(
address.index(address_identifiers_len) as TableIndex
),
name: IdentifierIndex(name.index(identifiers_len) as TableIndex),
};
if module_handles_set.insert((mh.address, mh.name)) {
module_handles.push(mh);
}
}
let module_handles_len = module_handles.len();
let self_module_handle_idx =
ModuleHandleIndex(self_idx_gen.index(module_handles_len) as TableIndex);
let friend_decl_set: BTreeSet<_> = friend_decl_gens
.into_iter()
.map(|(address_gen, name_gen)| ModuleHandle {
address: AddressIdentifierIndex(
address_gen.index(address_identifiers_len) as TableIndex,
),
name: IdentifierIndex(name_gen.index(identifiers_len) as TableIndex),
})
.collect();
let friend_decls = friend_decl_set.into_iter().collect();
let mut struct_handles = vec![];
if module_handles_len > 1 {
let mut struct_handles_set = BTreeSet::new();
for struct_handle_gen in struct_handle_gens.into_iter() {
let sh = struct_handle_gen.materialize(
self_module_handle_idx,
module_handles_len,
identifiers_len,
);
if struct_handles_set.insert((sh.module, sh.name)) {
struct_handles.push(sh);
}
}
}
let mut state = StDefnMaterializeState::new(
self_module_handle_idx,
identifiers_len,
struct_handles,
);
let mut struct_def_to_field_count: HashMap<usize, usize> = HashMap::new();
let mut struct_defs: Vec<StructDefinition> = vec![];
for struct_def_gen in struct_def_gens {
if let (Some(struct_def), offset) = struct_def_gen.materialize(&mut state) {
struct_defs.push(struct_def);
if offset > 0 {
struct_def_to_field_count.insert(struct_defs.len() - 1, offset);
}
}
}
let StDefnMaterializeState { struct_handles, .. } = state;
let mut signatures: Vec<_> = random_sigs_gens
.into_iter()
.map(|sig_gen| sig_gen.materialize(&struct_handles))
.collect();
let mut function_handles: Vec<FunctionHandle> = vec![];
if module_handles_len > 1 {
let mut state = FnHandleMaterializeState::new(
self_module_handle_idx,
module_handles_len,
identifiers_len,
&struct_handles,
signatures,
);
for function_handle_gen in function_handle_gens {
if let Some(function_handle) =
function_handle_gen.materialize(&mut state)
{
function_handles.push(function_handle);
}
}
signatures = state.signatures();
}
let mut state = FnDefnMaterializeState::new(
self_module_handle_idx,
identifiers_len,
constant_pool_len,
&struct_handles,
&struct_defs,
signatures,
function_handles,
struct_def_to_field_count,
);
let mut function_defs: Vec<FunctionDefinition> = vec![];
for function_def_gen in function_def_gens {
if let Some(function_def) = function_def_gen.materialize(&mut state) {
function_defs.push(function_def);
}
}
let (
signatures,
function_handles,
field_handles,
struct_def_instantiations,
function_instantiations,
field_instantiations,
) = state.return_tables();
CompiledModule {
version: crate::file_format_common::VERSION_MAX,
module_handles,
self_module_handle_idx,
struct_handles,
function_handles,
field_handles,
friend_decls,
struct_def_instantiations,
function_instantiations,
field_instantiations,
struct_defs,
function_defs,
signatures,
identifiers,
address_identifiers,
constant_pool,
metadata,
}
},
)
}
}
pub(crate) fn prop_index_avoid(gen: PropIndex, avoid: usize, pool_size: usize) -> usize {
assert!(pool_size > 1);
assert!(pool_size > avoid);
let rand = gen.index(pool_size);
if rand != avoid {
return rand;
}
let rand_inc = rand.checked_add(1).unwrap();
if rand_inc != pool_size {
return rand_inc;
}
rand.checked_sub(1).unwrap()
}