diff --git a/.eqc_ci b/.eqc_ci new file mode 100644 index 0000000..f8e94ad --- /dev/null +++ b/.eqc_ci @@ -0,0 +1,3 @@ +{build, "./rebar3 compile eqc"}. +{test_path, "./_build/eqc/lib/msgpack/ebin"}. +{test_path, "./_build/eqc/lib/msgpack"}. diff --git a/.gitignore b/.gitignore index dee7d67..75b64f6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ ebin/*.app deps *.so _build +.rebar3 diff --git a/.travis.yml b/.travis.yml index 055f73a..ec91c36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: erlang sudo: false +install: echo rebar3 script: make check-all notifications: email: false diff --git a/EQC_CI_LICENCE.txt b/EQC_CI_LICENCE.txt new file mode 100644 index 0000000..6d2a058 --- /dev/null +++ b/EQC_CI_LICENCE.txt @@ -0,0 +1,34 @@ +This file is an agreement between Quviq AB ("Quviq"), Sven Hultins +Gata 9, Gothenburg, Sweden, and the committers to the github +repository in which the file appears ("the owner"). By placing this +file in a github repository, the owner agrees to the terms below. + +The purpose of the agreement is to enable Quviq AB to provide a +continuous integration service to the owner, whereby the code in the +repository ("the source code") is tested using Quviq's test tools, and +the test results are made available on the web. The test results +include test output, generated test cases, and a copy of the source +code in the repository annotated with coverage information ("the test +results"). + +The owner agrees that Quviq may run the tests in the source code and +display the test results on the web, without obligation. + +The owner warrants that running the tests in the source code and +displaying the test results on the web violates no laws, licences or other +agreements. In the event of such a violation, the owner accepts full +responsibility. + +The owner warrants that the source code is not malicious, and will not +mount an attack on either Quviq's server or any other server--for +example by taking part in a denial of service attack, or by attempting +to send unsolicited emails. + +The owner warrants that the source code does not attempt to reverse +engineer Quviq's code. + +Quviq reserves the right to exclude repositories that break this +agreement from its continuous integration service. + +Any dispute arising from the use of Quviq's service will be resolved +under Swedish law. diff --git a/eqc/msgpack_eqc.erl b/eqc/msgpack_eqc.erl new file mode 100644 index 0000000..f82099c --- /dev/null +++ b/eqc/msgpack_eqc.erl @@ -0,0 +1,110 @@ +%% +%% MessagePack for Erlang +%% +%% Copyright (C) 2009-2014 UENISHI Kota +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% + +-module(msgpack_eqc). + + +-ifdef(TEST). +-ifdef(EQC). + +-compile(export_all). +-include_lib("eqc/include/eqc.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-define(NUMTESTS, 16). +-define(QC_OUT(P), + eqc:on_output(fun(Str, Args) -> + io:format(user, Str, Args) end, P)). +-define(_assertProp(S), + {timeout, ?NUMTESTS * 10, + ?_assert(quickcheck(numtests(?NUMTESTS, ?QC_OUT(S))))}). + +eqc_test_() -> + {inparallel, + [ + ?_assertProp(prop_msgpack()), + ?_assertProp(prop_msgpack([{format, jiffy}])), + ?_assertProp(prop_msgpack([{format, jsx}])) + ]}. + +prop_msgpack() -> + ?FORALL(Obj, msgpack_object(), + begin + {ok, Obj} =:= msgpack:unpack(msgpack:pack(Obj)) + end). + +prop_msgpack(Options) -> + ?FORALL(Obj, msgpack_object(), + begin + {ok, Obj} =:= msgpack:unpack(msgpack:pack(Obj, Options), Options) + end). + +msgpack_object() -> + oneof(container_types() ++ primitive_types()). + +container_types() -> + [ fix_array(), array16() ]. +%% TODO: add map + +primitive_types() -> + [null(), + positive_fixnum(), negative_fixnum(), + int8(), int16(), int32(), int64(), + uint8(), uint16(), uint32(), uint64(), + eqc_gen:real(), eqc_gen:bool(), + fix_raw(), raw16(), raw32() + ]. + %% fix_raw(), raw16(), raw32()]). + +positive_fixnum() -> choose(0, 127). +negative_fixnum() -> choose(-32, -1). + +int8() -> choose(-16#80, 16#7F). +int16() -> oneof([choose(-16#8000, -16#81), + choose(16#80, 16#7FFF)]). +int32() -> oneof([choose(-16#80000000, -16#8001), + choose(16#10000, 16#7FFFFFFF)]). +int64() -> oneof([choose(-16#8000000000000000, -16#80000001), + choose(16#100000000, 16#7FFFFFFFFFFFFFFF)]). + +uint8() -> choose(0, 16#FF). +uint16() -> choose(16#100, 16#FFFF). +uint32() -> choose(16#10000, 16#FFFFFFFF). +uint64() -> choose(16#100000000, 16#FFFFFFFFFFFFFFFF). + +null() -> null. + +fix_raw() -> + ?LET(Integer, choose(0, 31), + ?LET(Binary, binary(Integer), Binary)). + +raw16() -> + ?LET(Integer, uint16(), + ?LET(Binary, binary(Integer), Binary)). + +raw32() -> + ?LET(Binary, binary(65537), Binary). + +fix_array() -> + eqc_gen:resize(16, eqc_gen:list(oneof(primitive_types()))). + +array16() -> + eqc_gen:resize(128, eqc_gen:list(oneof(primitive_types()))). + +-endif. +-endif. diff --git a/rebar.config b/rebar.config index a59ebf4..cb62335 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,8 @@ {require_otp_vsn, "17|18"}. {erl_opts, [fail_on_warning, debug_info, warn_untyped_record]}. +%%, {parse_transform, eqc_cover}]}. + {xref_checks, [undefined_function_calls]}. {cover_enabled, true}. {cover_print_enabled, false}. @@ -11,6 +13,9 @@ "src/msgpack_ext.erl" ]}. +{plugins, [ + {rebar3_eqc, ".*", {git, "https://github.com/kellymclaughlin/rebar3-eqc-plugin.git", {tag, "0.0.8"}}} +]}. %% {port_sources, ["c_src/*.c"]}. %% {port_env, [