diff --git a/swh/model/hypothesis_strategies.py b/swh/model/hypothesis_strategies.py --- a/swh/model/hypothesis_strategies.py +++ b/swh/model/hypothesis_strategies.py @@ -315,13 +315,16 @@ if not only_objects: # Make sure aliases point to actual branches unresolved_aliases = { - target['target'] - for target in branches.values() + branch: target['target'] + for branch, target in branches.items() if (target and target['target_type'] == 'alias' and target['target'] not in branches) - } - for alias in unresolved_aliases: + } + for alias_name, alias_target in unresolved_aliases.items(): + # Override alias branch with one pointing to a real object + # if max_size constraint is reached + alias = alias_target if len(branches) < max_size else alias_name branches[alias] = draw(branch_targets_d(only_objects=True)) # Ensure no cycles between aliases @@ -343,7 +346,8 @@ def snapshots(*, min_size=0, max_size=100, only_objects=False): - return snapshots_d(min_size=0, max_size=100, only_objects=False).map( + return snapshots_d(min_size=min_size, max_size=max_size, + only_objects=only_objects).map( Snapshot.from_dict) diff --git a/swh/model/tests/test_hypothesis_strategies.py b/swh/model/tests/test_hypothesis_strategies.py --- a/swh/model/tests/test_hypothesis_strategies.py +++ b/swh/model/tests/test_hypothesis_strategies.py @@ -6,10 +6,13 @@ import datetime import attr -from hypothesis import given +from hypothesis import given, settings from swh.model.hashutil import DEFAULT_ALGORITHMS -from swh.model.hypothesis_strategies import objects, object_dicts +from swh.model.hypothesis_strategies import ( + objects, object_dicts, snapshots +) +from swh.model.model import TargetType target_types = ( @@ -80,3 +83,42 @@ elif obj_type == 'snapshot': for branch in obj_dict['branches'].values(): assert branch is None or branch['target_type'] in target_types + + +_min_snp_size = 10 +_max_snp_size = 100 + + +@given(snapshots(min_size=_min_snp_size, max_size=_max_snp_size)) +@settings(max_examples=1) +def test_snapshots_strategy(snapshot): + + branches = snapshot.branches + + assert len(branches) >= _min_snp_size + assert len(branches) <= _max_snp_size + + aliases = [] + + # check snapshot integrity + for name, branch in branches.items(): + assert branch is None or branch.target_type.value in target_types + if branch is not None and branch.target_type == TargetType.ALIAS: + aliases.append(name) + assert branch.target in branches + + # check no cycles between aliases + for alias in aliases: + processed_alias = set() + current_alias = alias + while (branches[current_alias] is not None + and branches[current_alias].target_type == TargetType.ALIAS): + assert branches[current_alias].target not in processed_alias + processed_alias.add(current_alias) + current_alias = branches[current_alias].target + + +@given(snapshots(min_size=_min_snp_size, max_size=_min_snp_size)) +@settings(max_examples=1) +def test_snapshots_strategy_fixed_size(snapshot): + assert len(snapshot.branches) == _min_snp_size