def get_case_strategy( endpoint: Endpoint, hooks: Optional[Dict[str, Hook]] = None) -> st.SearchStrategy: """Create a strategy for a complete test case. Path & endpoint are static, the others are JSON schemas. """ strategies = {} static_kwargs: Dict[str, Any] = {"endpoint": endpoint} try: for parameter in PARAMETERS: value = getattr(endpoint, parameter) if value is not None: if parameter == "path_parameters": strategies[parameter] = ( from_schema(value).filter(filter_path_parameters).map( quote_all) # type: ignore ) elif parameter in ("headers", "cookies"): strategies[parameter] = from_schema(value).filter( is_valid_header) # type: ignore elif parameter == "query": strategies[parameter] = from_schema(value).filter( is_valid_query) # type: ignore else: strategies[parameter] = from_schema(value) # type: ignore else: static_kwargs[parameter] = None return _get_case_strategy(endpoint, static_kwargs, strategies, hooks) except AssertionError: raise InvalidSchema("Invalid schema for this endpoint")
def get_case_strategy(endpoint: Endpoint) -> st.SearchStrategy: """Create a strategy for a complete test case. Path & endpoint are static, the others are JSON schemas. """ strategies = {} static_kwargs = { "path": endpoint.path, "method": endpoint.method, "base_url": endpoint.base_url } try: for parameter in PARAMETERS: value = getattr(endpoint, parameter) if value is not None: if parameter == "path_parameters": strategies[parameter] = ( from_schema(value).filter( filter_path_parameters) # type: ignore .map(quote_all) # type: ignore ) elif parameter == "headers": strategies[parameter] = from_schema(value).filter( is_valid_header) # type: ignore else: strategies[parameter] = from_schema(value) # type: ignore else: static_kwargs[parameter] = None return _get_case_strategy(endpoint, static_kwargs, strategies) except AssertionError: raise InvalidSchema("Invalid schema for this endpoint")
def _merge_semantics_helper(data, s1, s2, combined): note(combined) ic = data.draw(from_schema(combined), label="combined") i1 = data.draw(from_schema(s1), label="s1") i2 = data.draw(from_schema(s2), label="s2") assert is_valid(ic, s1) assert is_valid(ic, s2) assert is_valid(i1, s2) == is_valid(i1, combined) assert is_valid(i2, s1) == is_valid(i2, combined)
def prepare_strategy(parameter: str, value: Dict[str, Any]) -> st.SearchStrategy: if parameter == "path_parameters": return from_schema(value).filter(filter_path_parameters).map( quote_all) # type: ignore if parameter in ("headers", "cookies"): return from_schema(value).filter(is_valid_header) # type: ignore if parameter == "query": return from_schema(value).filter(is_valid_query) # type: ignore return from_schema(value) # type: ignore
def get_case_strategy(endpoint: Endpoint) -> st.SearchStrategy: return st.builds( Case, path=st.just(endpoint.path), method=st.just(endpoint.method), path_parameters=from_schema(endpoint.path_parameters), headers=from_schema(endpoint.headers), query=from_schema(endpoint.query), body=from_schema(endpoint.body), )
def test_merge_semantics(data, s1, s2): assume(canonicalish(s1) != FALSEY and canonicalish(s2) != FALSEY) combined = merged([s1, s2]) assume(combined is not None) assume(combined != FALSEY) note(combined) ic = data.draw(from_schema(combined), label="combined") i1 = data.draw(from_schema(s1), label="s1") i2 = data.draw(from_schema(s2), label="s2") assert is_valid(ic, s1) and is_valid(ic, s2) assert is_valid(i1, s2) == is_valid(i1, combined) assert is_valid(i2, s1) == is_valid(i2, combined)
def get_case_strategy(endpoint: Endpoint) -> st.SearchStrategy: """Create a strategy for a complete test case. Path & endpoint are static, the others are JSON schemas. """ return st.builds( Case, path=st.just(endpoint.path), method=st.just(endpoint.method), path_parameters=from_schema(endpoint.path_parameters), headers=from_schema(endpoint.headers), query=from_schema(endpoint.query), body=from_schema(endpoint.body), )
def schema(dataclass): schema = lambda dataclass: hypothesis_jsonschema.from_schema(dataclass.schema()) def test_get(get_client, tmp_path): client = get_client() tmp_file = tmp_path / 'test.txt' tmp_file.write_text('test') response = client.get("/api/contents/test.txt") assert response.status_code == 200 #assert response.json() @hypothesis.given(body=schema(RenameModel)) def test_rename(get_client, tmp_path, body): client = get_client() tmp_file = tmp_path / 'test.txt' tmp_file.write_text('test') response = client.patch( '/api/contents/test.txt', json=body ) new_name = body['path'] assert response.json()['path'] == new_name
class TestMsgVote: def test_schema_valid(self, msg_examples): for m in msg_examples[MsgVote]: assert_serdes_consistent(MsgVote, m) assert_serdes_exact(MsgVote, m) @pytest.mark.slow @settings(suppress_health_check=[ HealthCheck.too_slow, HealthCheck.filter_too_much ]) @given(m=from_schema(MsgVote.__schema__)) def test_serdes_consistent(self, m): assert_serdes_consistent(MsgVote, m) def test_matches_meta(self): assert MsgVote.type == "gov/MsgVote" assert MsgVote.action == "vote" @given(other=st.text()) def test_constructor_validates_addresses(self, acc_address, other): """MsgVote should validate `voter` to be AccAddress.""" assume(not is_acc_address(other)) with pytest.raises(InvalidAccAddress): MsgVote(proposal_id=1, voter=other, option="") A = MsgVote(proposal_id=1, voter=acc_address, option="") assert A.voter == acc_address
class TestMsgWithdrawValidatorCommission: def test_schema_valid(self, msg_examples): for m in msg_examples[MsgWithdrawValidatorCommission]: assert_serdes_consistent(MsgWithdrawValidatorCommission, m) assert_serdes_exact(MsgWithdrawValidatorCommission, m) @pytest.mark.serdes @pytest.mark.slow @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much]) @given(m=from_schema(MsgWithdrawValidatorCommission.__schema__)) def test_serdes_consistent(self, m): assert_serdes_consistent(MsgWithdrawValidatorCommission, m) def test_matches_meta(self): assert ( MsgWithdrawValidatorCommission.type == "distribution/MsgWithdrawValidatorCommission" ) assert MsgWithdrawValidatorCommission.action == "withdraw_validator_commission" @given(other=st.text()) def test_constructor_validates_addresses(self, val_address, other): """MsgWithdrawValidatorCommission should validate `validator_address` to be ValAddress. """ assume(not is_val_address(other)) with pytest.raises(InvalidValAddress): MsgWithdrawValidatorCommission(validator_address=other) A = MsgWithdrawValidatorCommission(validator_address=val_address) assert A.validator_address == val_address
def test_can_generate_for_test_suite_schema(data, name): note(suite[name]) value = data.draw(from_schema(suite[name])) try: jsonschema.validate(value, suite[name]) except jsonschema.exceptions.SchemaError: jsonschema.Draft4Validator(suite[name]).validate(value)
def test_canonicalises_to_equivalent_fixpoint(schema_strategy, data): """Check that an object drawn from an arbitrary schema is valid.""" schema = data.draw(schema_strategy, label="schema") cc = canonicalish(schema) assert cc == canonicalish(cc) instance = data.draw(JSON_STRATEGY | from_schema(cc), label="instance") assert is_valid(instance, schema) == is_valid(instance, cc)
class TestMsgSwap: def test_schema_valid(self, msg_examples): for m in msg_examples[MsgSwap]: assert_serdes_consistent(MsgSwap, m) assert_serdes_exact(MsgSwap, m) @pytest.mark.serdes @pytest.mark.slow @settings(suppress_health_check=[ HealthCheck.too_slow, HealthCheck.filter_too_much ]) @given(m=from_schema(MsgSwap.__schema__)) def test_serdes_consistent(self, m): assert_serdes_consistent(MsgSwap, m) def test_matches_meta(self): assert MsgSwap.type == "market/MsgSwap" assert MsgSwap.action == "swap" @given(other=st.text()) def test_constructor_validates_addresses(self, acc_address, other): """MsgSwap should validate `trader` to be AccAddress. """ assume(not is_acc_address(other)) with pytest.raises(InvalidAccAddress): MsgSwap(trader=other, offer_coin=Coin("uluna", 100), ask_denom="umnt") A = MsgSwap(trader=acc_address, offer_coin=Coin("uluna", 100), ask_denom="umnt") assert A.trader == acc_address
class TestCoinsSerdes: @pytest.mark.serdes @pytest.mark.slow @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much]) @given(c=from_schema(Coins.__schema__)) def test_serdes_consistent(self, c): assert_serdes_consistent(Coins, c)
def generate_experiment_strategy(path, size, level=1, position=[0]): # pylint: disable=W0102 """generate strategies from a schema path and current input size""" json_schema = read.read_schema(path) # pylint: disable=W0102, R1705 def detect_level_and_position(schema, level=1, position=[0], index_position=0): """A dummy function to store the data to file for experiment""" if level == 0: return schema else: if isinstance(schema, list): subschema = schema[position[index_position]] elif isinstance(schema["items"], dict): subschema = schema["items"] elif isinstance(schema["items"], list): subschema = schema["items"][position[index_position]] return detect_level_and_position(subschema, level - 1, position, index_position + 1) js = detect_level_and_position(json_schema, level, position) double_experiment_size(js, size) strategy = [] for j in json_schema: strategy.append(from_schema(j)) return strategy
def test_custom_strategies(): register_string_format( "even_4_digits", strategies.from_regex(r"\A[0-9]{4}\Z").filter( lambda x: int(x) % 2 == 0)) endpoint = make_endpoint( **{ "query": { "required": ["id"], "type": "object", "additionalProperties": False, "properties": { "id": { "type": "string", "format": "even_4_digits" } }, } }) result = strategies.builds( Case, path=strategies.just(endpoint.path), method=strategies.just(endpoint.method), query=from_schema(endpoint.query), ).example() assert len(result.query["id"]) == 4 assert int(result.query["id"]) % 2 == 0
class TestMsgDelegateFeedConsent: def test_schema_valid(self, msg_examples): for m in msg_examples[MsgDelegateFeedConsent]: assert_serdes_consistent(MsgDelegateFeedConsent, m) assert_serdes_exact(MsgDelegateFeedConsent, m) @pytest.mark.slow @settings(suppress_health_check=[ HealthCheck.too_slow, HealthCheck.filter_too_much ]) @given(m=from_schema(MsgDelegateFeedConsent.__schema__)) def test_schema(self, m): assert_serdes_consistent(MsgDelegateFeedConsent, m) def test_matches_meta(self): assert MsgDelegateFeedConsent.type == "oracle/MsgDelegateFeedConsent" assert MsgDelegateFeedConsent.action == "delegatefeeder" @given(other=st.text()) def test_constructor_validates_addresses(self, acc_address, val_address, other): """MsgDelegateFeedConsent should validate `operator` to be ValAddress and `delegate` to be AccAddress. """ assume(not is_val_address(other) and not is_acc_address(other)) with pytest.raises(InvalidValAddress): MsgDelegateFeedConsent(operator=other, delegate=acc_address) with pytest.raises(InvalidAccAddress): MsgDelegateFeedConsent(operator=val_address, delegate=other) A = MsgDelegateFeedConsent(operator=val_address, delegate=acc_address) assert A.operator == val_address assert A.delegate == acc_address
class TestStdFeeSerdes: @pytest.mark.slow @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much]) @given(fee=from_schema(StdFee.__schema__)) def test_schema(self, fee): x = StdFee.deserialize(fee) y = StdFee.deserialize(json.loads(x.to_json())) assert x == y
def not_from_schema(draw: Callable, schema: Dict[str, Any]) -> Any: """Generate data that does NOT match the given schema.""" mutations = list(_mutate(schema)) if not mutations: raise Unsatisfiable mutation_strategies = st.sampled_from(mutations) mutated_strategy = draw(mutation_strategies) schema_strategy = from_schema(mutated_strategy) return draw(schema_strategy)
class TestMsgBeginRedelegate: def test_schema_valid(self, msg_examples): for m in msg_examples[MsgBeginRedelegate]: assert_serdes_consistent(MsgBeginRedelegate, m) assert_serdes_exact(MsgBeginRedelegate, m) @pytest.mark.serdes @pytest.mark.slow @settings(suppress_health_check=[ HealthCheck.too_slow, HealthCheck.filter_too_much ]) @given(m=from_schema(MsgBeginRedelegate.__schema__)) def test_serdes_consistent(self, m): assert_serdes_consistent(MsgBeginRedelegate, m) def test_matches_meta(self): assert MsgBeginRedelegate.type == "staking/MsgBeginRedelegate" assert MsgBeginRedelegate.action == "begin_redelegate" @given(other=st.text()) def test_constructor_validates_addresses(self, acc_address, val_address, other): """MsgBeginRedelegate should validate `delegator` to be AccAddress, and both `validator_src_address` and `validator_dst_address` to be ValAddress. """ assume(not is_acc_address(other) and not is_val_address(other)) with pytest.raises(InvalidAccAddress): MsgBeginRedelegate( delegator_address=other, validator_src_address=val_address, validator_dst_address=val_address, amount=None, ) with pytest.raises(InvalidValAddress): MsgBeginRedelegate( delegator_address=acc_address, validator_src_address=other, validator_dst_address=val_address, amount=None, ) with pytest.raises(InvalidValAddress): MsgBeginRedelegate( delegator_address=acc_address, validator_src_address=val_address, validator_dst_address=other, amount=None, ) A = MsgBeginRedelegate( delegator_address=acc_address, validator_src_address=val_address, validator_dst_address=val_address, amount=None, ) assert A.delegator_address == acc_address assert A.validator_src_address == val_address assert A.validator_dst_address == val_address
def test_generated_data_matches_schema(schema_strategy, data): """Check that an object drawn from an arbitrary schema is valid.""" schema = data.draw(schema_strategy) try: value = data.draw(from_schema(schema), "value from schema") except InvalidArgument: reject() jsonschema.validate(value, schema) # This checks that our canonicalisation is semantically equivalent. jsonschema.validate(value, canonicalish(schema))
def test_generate_func_from_single_st(): """Checks that generate function from single strategy works""" # pylint: disable=blacklisted-name def foo(a): """A sample function""" type(a) schema = {"type": "array", "items": {"type": "number"}} strategy = from_schema(schema) function = generate.generate_func_from_single_st(foo, strategy) assert str(type(function)) == "<class 'function'>"
class TestRedelegationSerdes: def test_schema_valid(self, rdelgn_examples): for d in rdelgn_examples: assert_serdes_consistent(Redelegation, d) assert_serdes_exact(Redelegation, d) @pytest.mark.slow @settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much]) @given(d=from_schema(Redelegation.__schema__)) def test_schema(self, d): assert_serdes_consistent(Redelegation, d)
def make_positive_strategy(schema: Dict[str, Any], operation_name: str, location: str, media_type: Optional[str]) -> st.SearchStrategy: """Strategy for generating values that fit the schema.""" if is_header_location(location): # We try to enforce the right header values via "format" # This way, only allowed values will be used during data generation, which reduces the amount of filtering later # If a property schema contains `pattern` it leads to heavy filtering and worse performance - therefore, skip it for sub_schema in schema.get("properties", {}).values(): if list(sub_schema) == ["type"]: sub_schema.setdefault("format", HEADER_FORMAT) return from_schema(schema, custom_formats=STRING_FORMATS)
def get_examples(endpoint: Endpoint) -> Generator[Case, None, None]: for name in PARAMETERS: parameter = getattr(endpoint, name) if "example" in parameter: with handle_warnings(): strategies = { other: from_schema(getattr(endpoint, other)) for other in PARAMETERS - {name} } static_parameters = {name: parameter["example"]} yield _get_case_strategy(endpoint, static_parameters, strategies).example()
def prepare_strategy(parameter: str, value: Dict[str, Any], map_func: Optional[Callable]) -> st.SearchStrategy: """Create a strategy for a schema and add location-specific filters & maps.""" strategy = from_schema(value) if map_func is not None: strategy = strategy.map(map_func) if parameter == "path_parameters": strategy = strategy.filter(filter_path_parameters).map(quote_all) # type: ignore elif parameter in ("headers", "cookies"): strategy = strategy.filter(is_valid_header) # type: ignore elif parameter == "query": strategy = strategy.filter(is_valid_query) # type: ignore return strategy
class TestExchangeRatePrevoteSerdes: def test_schema_valid(self, examples): for x in examples: assert_serdes_consistent(ExchangeRatePrevote, x) assert_serdes_exact(ExchangeRatePrevote, x) @pytest.mark.serdes @pytest.mark.slow @settings(suppress_health_check=[HealthCheck.too_slow]) @given(x=from_schema(ExchangeRatePrevote.__schema__)) def test_serdes_consistent(self, x): assert_serdes_consistent(ExchangeRatePrevote, x)
def test_canonicalises_to_equivalent_fixpoint(schema_strategy, data): """Check that an object drawn from an arbitrary schema is valid.""" schema = data.draw(schema_strategy, label="schema") cc = canonicalish(schema) assert cc == canonicalish(cc) try: strat = from_schema(cc) except InvalidArgument: # e.g. array of unique {type: integers}, with too few allowed integers assume(False) instance = data.draw(JSON_STRATEGY | strat, label="instance") assert is_valid(instance, schema) == is_valid(instance, cc) jsonschema.validators.validator_for(schema).check_schema(schema)
def test_successful_mutations(data, mutation, schema): validate_schema(schema) validator = Draft4Validator(schema) schema = deepcopy(schema) # When mutation can be applied # Then it returns "success" assert mutation(MutationContext(schema, "body", "application/json"), data.draw, schema) == MutationResult.SUCCESS # And the mutated schema is a valid JSON Schema validate_schema(schema) # And instances valid for this schema are not valid for the original one new_instance = data.draw(from_schema(schema)) assert not validator.is_valid(new_instance)
class TestVestingAccountSerdes: def test_schema_valid(self, examples): for acc in examples: assert_serdes_consistent(LazyGradedVestingAccount, acc) assert_serdes_exact(LazyGradedVestingAccount, acc) @pytest.mark.slow @settings(suppress_health_check=[ HealthCheck.too_slow, HealthCheck.filter_too_much ]) @given(acc=from_schema(LazyGradedVestingAccount.__schema__)) def test_schema(self, acc): assert_serdes_consistent(LazyGradedVestingAccount, acc)