Skip to content

Commit

Permalink
adding quickcheck code
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Vorreuter committed May 27, 2009
1 parent b6d36c1 commit 3d7b57a
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
VERSION=0.3
VERSION=0.3.0
PKGNAME=erlang_protobuffs

all:
Expand Down
2 changes: 1 addition & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ make interfacing with the Protocol Buffers protocol easy.

Encoding is simple.

1> erlang:iolist_to_binary(protobuffs:encode(1, 1, uint32)).
1> protobuffs:encode(1, 1, uint32).
<<8,1>>
2> erlang:iolist_to_binary([
protobuffs:encode(1, <<"Nick">>, string),
Expand Down
4 changes: 2 additions & 2 deletions src/pokemon_pb.erl
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ pack(_, optional, undefined, _, _) -> [];

pack(_, repeated, undefined, _, _) -> [];

pack(_, required, undefined, _, _) ->
exit(required_field_is_undefined);
pack(FNum, required, undefined, Type, _) ->
exit({error, {required_field_is_undefined, FNum, Type}});

pack(_, repeated, [], _, Acc) ->
lists:reverse(Acc);
Expand Down
14 changes: 13 additions & 1 deletion src/protobuffs_compile.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
%% OTHER DEALINGS IN THE SOFTWARE.
-module(protobuffs_compile).
-export([scan_file/1]).
-export([scan_file/1, output/2]).

scan_file(ProtoFile) when is_list(ProtoFile) ->
Basename = filename:basename(ProtoFile, ".proto") ++ "_pb",
Parsed = protobuffs_parser:parse_file(ProtoFile),
Messages = collect_full_messages(Parsed),
output(Basename, Messages).

output(Basename, Messages) ->
ok = write_header_include_file(Basename, Messages),
BeamFile = code:lib_dir(erlang_protobuffs) ++ "/ebin/pokemon_pb.beam",
{ok,{_,[{abstract_code,{_,Forms}}]}} = beam_lib:chunks(BeamFile, [abstract_code]),
Expand Down Expand Up @@ -133,6 +136,15 @@ filter_to_record_clause({MsgName, _}, {clause,L,[_Param1,Param2],Guards,[Fold]})
Fold1 = replace_atom(Fold, pikachu, atomize(MsgName)),
{clause,L,[{atom,L,atomize(MsgName)},Param2],Guards,[Fold1]}.

%% [{"Location",
%% [{2,required,"string","country",number,none},
%% {1,required,"string","region",number,none}]},
%% {"Person",
%% [{5,optional,"Location","location",number,none},
%% {4,required,"int32","age",number,none},
%% {3,required,"string","phone_number",number,none},
%% {2,required,"string","address",number,none},
%% {1,required,"string","name",number,none}]}]
collect_full_messages(Data) -> collect_full_messages(Data, []).
collect_full_messages([{message, Name, Fields} | Tail], Acc) ->
FieldsOut = lists:foldl(
Expand Down
128 changes: 115 additions & 13 deletions t/protobuffs_eqc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,119 @@ prop_encode_decode3() ->
(compare(Data1,Data2) orelse foreign_type(Type1,Data1,Data2)))
end, true, lists:seq(1, length(Sorted)))
end).


prop_encode_decode4() ->
?FORALL({ProtoName, Msgs}, protobuff_msgs(),
begin
code:delete(list_to_atom(ProtoName)),
code:purge(list_to_atom(ProtoName)),
protobuffs_compile:output(ProtoName, Msgs),
?FORALL(Set, protobuff_set(Defs),
begin
Record = build_record_from_defs(MsgName, Defs, Set),
case catch apply(list_to_atom(ProtoName), list_to_atom("encode_" ++ MsgName), [Record]) of
{'EXIT', {error, {required_field_is_undefined, FNum, _}}} ->
{value, {_, required, _, _, _, _}} = lists:keysearch(FNum, 1, Defs),
true;
Bin when is_binary(Bin) ->
Record1 = apply(list_to_atom(ProtoName), list_to_atom("decode_" ++ MsgName), [Bin]),
lists:foldl(
fun ({A,B}, true) ->
io:format("compare ~p and ~p~n", [A,B]),
compare(A,B);
(_, false) ->
false
end, true, lists:zip(tuple_to_list(Record), tuple_to_list(Record1)))
end
end)
end).

%% Data generators

protobuff_msgs() ->
{string(), list({msg_name(), protobuff_defs()})}.

protobuff_many() ->
list(protobuff_data()).

protobuff_set(Defs) ->
[begin
{FNum, Name, field_value(Tag, Type)}
end || {FNum, Tag, Type, Name, _, _Default} <- Defs].

protobuff_data() ->
fault({field_num(), int(80), oneof([int32,uint32,int64,uint64,sint32,sint64])},
oneof([
{field_num(), int(32),int32},
{field_num(), uint(32),uint32},
{field_num(), int(64),int64},
{field_num(), uint(64),uint64},
{field_num(), bool(),bool},
{field_num(), sint(32),sint32},
{field_num(), sint(64),sint64},
{field_num(), real(),float},
{field_num(), real(),double}
{field_num(), int(32), int32},
{field_num(), uint(32), uint32},
{field_num(), int(64), int64},
{field_num(), uint(64), uint64},
{field_num(), bool(), bool},
{field_num(), sint(32), sint32},
{field_num(), sint(64), sint64},
{field_num(), real(), float},
{field_num(), real(), double},
{field_num(), list(char()), string},
{field_num(), binary(), bytes}
])
).

protobuff_defs() ->
?SUCHTHAT(D,orderedlist(protobuff_def()),length(D) > 0).

protobuff_def() ->
oneof([
{field_num(), tag(), "int32", field_name(), number, oneof([none, int(32)])},
{field_num(), tag(), "uint32", field_name(), number, oneof([none, uint(32)])},
{field_num(), tag(), "int64", field_name(), number, oneof([none, int(64)])},
{field_num(), tag(), "uint64", field_name(), number, oneof([none, uint(64)])},
{field_num(), tag(), "bool", field_name(), number, oneof([none, bool()])},
{field_num(), tag(), "sint32", field_name(), number, oneof([none, sint(32)])},
{field_num(), tag(), "sint64", field_name(), number, oneof([none, sint(64)])},
{field_num(), tag(), "float", field_name(), number, oneof([none, real()])},
{field_num(), tag(), "double", field_name(), number, oneof([none, real()])},
{field_num(), tag(), "string", field_name(), number, oneof([none, list(char())])},
{field_num(), tag(), "bytes", field_name(), number, oneof([none, binary()])}
]).

field_value(repeated, "int32") -> oneof([undefined, list(int(32))]);
field_value(repeated, "uint32") -> oneof([undefined, list(uint(32))]);
field_value(repeated, "int64") -> oneof([undefined, list(int(64))]);
field_value(repeated, "uint64") -> oneof([undefined, list(uint(64))]);
field_value(repeated, "bool") -> oneof([undefined, list(bool())]);
field_value(repeated, "sint32") -> oneof([undefined, list(sint(32))]);
field_value(repeated, "sint64") -> oneof([undefined, list(sint(64))]);
field_value(repeated, "float") -> oneof([undefined, list(real())]);
field_value(repeated, "double") -> oneof([undefined, list(real())]);
field_value(repeated, "string") -> oneof([undefined, list(list(char()))]);
field_value(repeated, "bytes") -> oneof([undefined, list(binary())]);
field_value(_, "int32") -> oneof([undefined, int(32)]);
field_value(_, "uint32") -> oneof([undefined, uint(32)]);
field_value(_, "int64") -> oneof([undefined, int(64)]);
field_value(_, "uint64") -> oneof([undefined, uint(64)]);
field_value(_, "bool") -> oneof([undefined, bool()]);
field_value(_, "sint32") -> oneof([undefined, sint(32)]);
field_value(_, "sint64") -> oneof([undefined, sint(64)]);
field_value(_, "float") -> oneof([undefined, real()]);
field_value(_, "double") -> oneof([undefined, real()]);
field_value(_, "string") -> oneof([undefined, list(char())]);
field_value(_, "bytes") -> oneof([undefined, binary()]).

field_num() ->
?SUCHTHAT(N,nat(),N>0).

tag() ->
oneof([optional, required, repeated]).

field_name() ->
?SUCHTHAT(N,string(),length(N)>0).

msg_name() ->
?SUCHTHAT(N,string(),length(N)>0).

string() ->
list(oneof([choose(97,122), choose(65,90)])).

%% Internal Functions

foreign_type(bool,false,0) ->
Expand All @@ -104,13 +196,17 @@ prop_varint() ->
)
).

build_record_from_defs(MsgName, Defs, Set) ->
lists:foldl(
fun({FNum, _Tag, _Type, _Name, _, _Default}, Acc) ->
{value, {_,_,Value}} = lists:keysearch(FNum, 1, Set),
erlang:append_element(Acc, Value)
end, {list_to_atom(MsgName)}, Defs).

%% Bits are in reverse order: First bit should be zero, rest should be 1
right_bits([0|Rest]) ->
lists:all(fun(B) -> B==1 end,Rest).

field_num() ->
?SUCHTHAT(N,nat(),N>0).

int(Base) ->
?LET(I,uint(Base),
begin
Expand Down Expand Up @@ -156,13 +252,19 @@ in_range(Float,float) ->
fitbits(Float,32);
in_range(Float,double) ->
fitbits(Float,64);
in_range(_,string) ->
true;
in_range(_,bytes) ->
true;
in_range(false,bool) ->
true;
in_range(true,bool) ->
true.

compare(Float1, Float2) when is_float(Float1), is_float(Float2) ->
(abs(Float1 - Float2) =< ?Mach_Eps);
compare(String, Binary) when is_list(String), is_binary(Binary) ->
String =:= binary_to_list(Binary);
compare(A,A) -> true;
compare(_,_) -> false.

Expand Down

0 comments on commit 3d7b57a

Please sign in to comment.