Skip to content

Commit

Permalink
fix: noshrink response body (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
javiergarea authored Aug 29, 2023
1 parent fec725a commit 928cc38
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![restcheck ci](https://github.com/nomasystems/restcheck/actions/workflows/ci.yml/badge.svg)](https://github.com/nomasystems/restcheck/actions/workflows/ci.yml)
[![restcheck docs](https://github.com/nomasystems/restcheck/actions/workflows/docs.yml/badge.svg)](https://nomasystems.github.io/restcheck)

An automatic REST API contract testing tool based on property-based testing techniques.
A REST API fuzzing tool based on property-based testing techniques.

## Contributing

Expand Down
157 changes: 157 additions & 0 deletions examples/users/users.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"openapi": "3.0.0",
"info": {
"title": "Users REST API",
"version": "1.0.0",
"description": "A REST API for a simple user management service."
},
"paths": {
"/users": {
"post": {
"operationId": "createUser",
"summary": "Creates a User",
"requestBody": {
"description": "A user creation request",
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 3,
"maxLength": 9
},
"password": {
"type": "string",
"minLength": 6,
"maxLength": 12
}
},
"required": [
"username",
"password"
]
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/users/{userId}": {
"parameters": [
{
"$ref": "#/components/parameters/userId"
}
],
"get": {
"operationId": "getUser",
"summary": "Gets a User",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"operationId": "deleteUser",
"summary": "Deletes a User",
"responses": {
"204": {
"description": "No Content"
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
},
"components": {
"parameters": {
"userId": {
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
},
"schemas": {
"User": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 9
},
"password": {
"type": "string",
"minLength": 6,
"maxLength": 12
}
}
},
"Error": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
4 changes: 3 additions & 1 deletion src/restcheck.erl
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,10 @@ format_error({method_not_allowed, {_Path, _Method}}) ->
"Method not allowed";
format_error({server_error, _StatusCode}) ->
"Server error";
format_error({invalid_response_body, _RespondeBody}) ->
format_error({invalid_response_body, _ResponseBody}) ->
"Invalid response body";
format_error({invalid_response_status, _ResponseStatus}) ->
"Invalid response status";
format_error(Reason) ->
erlang:term_to_binary(Reason).

Expand Down
5 changes: 5 additions & 0 deletions src/restcheck_backend.erl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
ForAll :: restcheck_pbt:property().
%% Wraps a <code>forall</code> property.

-callback noshrink(Generator) -> NoShrinkGenerator when
Generator :: restcheck_pbt:generator(),
NoShrinkGenerator :: restcheck_pbt:generator().
%% Prevents a generator from shrinking.

-callback quickcheck(Property, NumTests, OutputFun) -> Result when
Property :: restcheck_pbt:property(),
NumTests :: restcheck_pbt:num_tests(),
Expand Down
8 changes: 6 additions & 2 deletions src/restcheck_schema.erl
Original file line number Diff line number Diff line change
Expand Up @@ -262,18 +262,22 @@ complement(#{<<"type">> := <<"object">>} = Schema) ->
true ->
undefined;
false ->
OldRequired = maps:get(<<"required">>, Schema, []),
PropertyName = new_property_name(maps:keys(Properties)),
Schema#{
<<"properties">> => Properties#{
PropertyName => #{}
}
},
<<"required">> => [PropertyName | OldRequired]
};
AdditionalSchema ->
OldRequired = maps:get(<<"required">>, Schema, []),
PropertyName = new_property_name(maps:keys(Properties)),
Schema#{
<<"properties">> => Properties#{
PropertyName => complement(AdditionalSchema)
}
},
<<"required">> => [PropertyName | OldRequired]
}
end,
Schemas = lists:filter(
Expand Down
19 changes: 16 additions & 3 deletions src/restcheck_suite.erl
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,17 @@ generate(API) ->
RequestBodySchema = schema_ast(maps:get(RequestBody, Schemas)),
RequestBodyGenerator = erl_syntax:application(
erl_syntax:atom(restcheck_pbt),
erl_syntax:atom(dto),
erl_syntax:atom(noshrink),
[
erl_syntax:variable('Backend'),
RequestBodySchema
erl_syntax:application(
erl_syntax:atom(restcheck_pbt),
erl_syntax:atom(dto),
[
erl_syntax:variable('Backend'),
RequestBodySchema
]
)
]
),
{Values, Generators} = {[RequestBodyValue | RawValues], [
Expand Down Expand Up @@ -315,7 +322,13 @@ prop_ast(RawPath, Method, Parameters, RequestBody, Responses) ->
DefaultResponse =
case maps:get('*', Responses, undefined) of
undefined ->
erl_syntax:atom(false);
erl_syntax:tuple([
erl_syntax:atom(false),
erl_syntax:tuple([
erl_syntax:atom(invalid_response_status),
erl_syntax:variable('ResponseStatus')
])
]);
Ref ->
erl_syntax:case_expr(
erl_syntax:application(
Expand Down
5 changes: 1 addition & 4 deletions src/restcheck_triq.erl
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,7 @@ string(Schema) ->
Length :: non_neg_integer(),
FormatGenerator :: restcheck_pbt:generator().
string_format(undefined, Length) ->
triq_dom:vector(
Length,
triq_dom:unicode_char()
);
triq_dom:unicode_binary(Length);
string_format(<<"base64">>, Length) ->
0 = (Length rem 4),
triq_dom:vector(
Expand Down

0 comments on commit 928cc38

Please sign in to comment.