From 2de97923ed20638ef810e13014d2bda22d723c16 Mon Sep 17 00:00:00 2001 From: Nick Vatamaniuc Date: Fri, 7 Jun 2024 19:58:40 -0400 Subject: [PATCH] Add GH Actions CI and fix tests on Erlang 27 Add CI for Windows, MacOS and Ubuntu Linux. For Linux, test both rebar2 and rebar3. Apparently due to `string:split/2` in `rebar.config.script` jiffy wasn't compatible with Erlang <20 for quite a now, and we didn't see any complaints, so make Erlang 20 the minimum supported version. Old jiffy releases are still available for anyone who needs them. In addition, only Erlang OTP docker images 20+ work with the latest (v4) checkout CI action, so that's another reason to make that the new cutoff. On Erlang 27 needed to make a few test updates: * The referenced binary length size computation changed so make sure to make the binaries large enough to avoid triggering the inconsistencies between <27 and 27+ version and needing to do an ifdef of some sort. * In Erlang 27 -0.0 =/= 0.0 so updated a few tests expecting exact comparison, to use numeric equality `=`. Jiffy doesn't round-trip -0.0s anyway, so it's only a test-side discrepancy. --- .github/workflows/ci.yml | 86 ++++++++++++++++++++++++++ .travis.yml | 13 ---- c_src/decoder.c | 6 -- c_src/encoder.c | 4 -- c_src/jiffy.h | 4 -- c_src/objects.cc | 7 --- rebar.config | 12 ---- rebar.config.script | 7 ++- src/jiffy.erl | 13 ---- src/jiffy_utf8.erl | 5 -- test/jiffy_03_number_tests.erl | 4 +- test/jiffy_11_property_tests.erl | 17 +---- test/jiffy_15_return_trailer_tests.erl | 4 -- test/jiffy_17_copy_strings_tests.erl | 8 +-- 14 files changed, 98 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e154e2d8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,86 @@ +name: ci + +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + linux: + name: ${{matrix.os}}-${{matrix.otp_version}}-${{matrix.rebar}} + runs-on: ${{matrix.os}} + + strategy: + fail-fast: false + matrix: + otp_version: [20,23,26,27] + os: [ubuntu-latest] + rebar: [rebar, rebar3] + + container: + image: erlang:${{matrix.otp_version}} + + steps: + - uses: actions/checkout@v4 + - name: ${{matrix.rebar}} make check + run: | + make REBAR=${{matrix.rebar}} check + + macos: + name: macos + runs-on: ${{matrix.os}} + + strategy: + fail-fast: false + matrix: + os: [macos-12, macos-14] + + steps: + - uses: actions/checkout@v4 + - name: install erlang + run: | + brew install erlang + - name: install rebar3 + run: | + brew install rebar3 + - name: make check + run: | + make check + + windows: + name: windows + runs-on: ${{matrix.os}} + + strategy: + fail-fast: false + matrix: + os: [windows-2019, windows-2022] + + steps: + - name: prevent git from messing up our json test files + run: | + git config --global core.autocrlf false + git config --global core.eol lf + - uses: actions/checkout@v4 + - name: install erlang + run: | + choco install erlang + - name: install rebar3 + run: | + choco install rebar3 + - name: make check + run: | + $path = vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -nologo -nocolor -property installationPath + if ($path) { + $path = join-path $path '\VC\Auxiliary\Build\vcvars64.bat' + if (test-path $path) { + cmd /s /c """$path"" $args && set" | where { $_ -match '(\w+)=(.*)' } | foreach { + $null = new-item -force -path "Env:\$($Matches[1])" -value $Matches[2] + } + } + } + make check diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 53bb22d9..00000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: erlang -notifications: - email: paul.joseph.davis@gmail.com -script: make check -otp_release: - - 23.0 - - 22.2.4 - - 21.3.8.1 - - 20.3.8.22 - - 19.3 - - 18.3 - - 17.5 - - R16B03-1 diff --git a/c_src/decoder.c b/c_src/decoder.c index 8f78117c..27d101a4 100644 --- a/c_src/decoder.c +++ b/c_src/decoder.c @@ -621,11 +621,9 @@ dec_number(Decoder* d, ERL_NIF_TERM* value) ERL_NIF_TERM make_empty_object(ErlNifEnv* env, int ret_map) { -#if MAP_TYPE_PRESENT if(ret_map) { return enif_make_new_map(env); } -#endif return enif_make_tuple1(env, enif_make_list(env, 0)); } @@ -680,11 +678,7 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } else if(get_bytes_per_red(env, val, &(d->bytes_per_red))) { continue; } else if(enif_is_identical(val, d->atoms->atom_return_maps)) { -#if MAP_TYPE_PRESENT d->return_maps = 1; -#else - return enif_make_badarg(env); -#endif } else if(enif_is_identical(val, d->atoms->atom_return_trailer)) { d->return_trailer = 1; } else if(enif_is_identical(val, d->atoms->atom_dedupe_keys)) { diff --git a/c_src/encoder.c b/c_src/encoder.c index 4cfb3533..03c5500f 100644 --- a/c_src/encoder.c +++ b/c_src/encoder.c @@ -595,7 +595,6 @@ enc_comma(Encoder* e) return 1; } -#if MAP_TYPE_PRESENT int enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out) { @@ -636,7 +635,6 @@ enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out) *out = enif_make_tuple1(env, list); return 1; } -#endif ERL_NIF_TERM encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -897,7 +895,6 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) termstack_push(&stack, curr); termstack_push(&stack, e->atoms->ref_object); termstack_push(&stack, tuple[1]); -#if MAP_TYPE_PRESENT } else if(enif_is_map(env, curr)) { if(!enc_map_to_ejson(env, curr, &curr)) { ret = enc_error(e, "internal_error"); @@ -905,7 +902,6 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } termstack_push(&stack, curr); -#endif } else if(enif_is_list(env, curr)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); diff --git a/c_src/jiffy.h b/c_src/jiffy.h index 9c97945d..db426116 100644 --- a/c_src/jiffy.h +++ b/c_src/jiffy.h @@ -9,10 +9,6 @@ #define DEFAULT_BYTES_PER_REDUCTION 20 #define DEFAULT_ERLANG_REDUCTION_COUNT 2000 -#define MAP_TYPE_PRESENT \ - ((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) \ - || (ERL_NIF_MAJOR_VERSION > 2)) - #define CONSUME_TIMESLICE_PRESENT \ ((ERL_NIF_MAJOR_VERSION >= 2 && ERL_NIF_MINOR_VERSION >= 4)) diff --git a/c_src/objects.cc b/c_src/objects.cc index 1a16699c..2a35b251 100644 --- a/c_src/objects.cc +++ b/c_src/objects.cc @@ -8,10 +8,6 @@ #include "erl_nif.h" -#define MAP_TYPE_PRESENT \ - ((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) \ - || (ERL_NIF_MAJOR_VERSION > 2)) - #define BEGIN_C extern "C" { #define END_C } @@ -27,8 +23,6 @@ make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, std::set seen; -#if MAP_TYPE_PRESENT - ERL_NIF_TERM old_val; if(ret_map) { @@ -46,7 +40,6 @@ make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, *out = ret; return 1; } -#endif ret = enif_make_list(env, 0); while(enif_get_list_cell(env, pairs, &val, &pairs)) { diff --git a/rebar.config b/rebar.config index 0ee14f41..15e69b61 100644 --- a/rebar.config +++ b/rebar.config @@ -21,21 +21,9 @@ {"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)", "LDFLAGS", "$LDFLAGS $FLTO_FLAG -lstdc++"}, - %% OS X Leopard flags for 64-bit - {"darwin9.*-64$", "CXXFLAGS", "-m64"}, - {"darwin9.*-64$", "LDFLAGS", "-arch x86_64"}, - - %% OS X Snow Leopard flags for 32-bit - {"darwin10.*-32$", "CXXFLAGS", "-m32"}, - {"darwin10.*-32$", "LDFLAGS", "-arch i386"}, - {"win32", "CXXFLAGS", "$CXXFLAGS /O2 /DNDEBUG"} ]}. -{erl_opts, [ - {platform_define, "R1(1|2|3|4|5|6)", 'JIFFY_NO_MAPS'} -]}. - {eunit_opts, [ verbose ]}. diff --git a/rebar.config.script b/rebar.config.script index 007e9b3e..c2f1689e 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -53,8 +53,11 @@ case IsRebar2 of Config2; false -> Config2 ++ [ - {plugins, [{pc, "~> 1.0"}]}, - {artifacts, ["priv/jiffy.so"]}, + {plugins, [{pc, "~> 1.15"}]}, + case os:type() of + {win32, _} -> {artifacts, ["priv/jiffy.dll"]}; + {_, _} -> {artifacts, ["priv/jiffy.so"]} + end, {provider_hooks, [ {post, [ {compile, {pc, compile}}, diff --git a/src/jiffy.erl b/src/jiffy.erl index 6af15b5f..b1f3b98a 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -22,17 +22,9 @@ -type json_string() :: atom() | binary(). -type json_number() :: integer() | float(). --ifdef(JIFFY_NO_MAPS). - --type json_object() :: {[{json_string(),json_value()}]}. - --else. - -type json_object() :: {[{json_string(),json_value()}]} | #{json_string() => json_value()}. --endif. - -type jiffy_decode_result() :: json_value() | {has_trailer, json_value(), binary()}. @@ -141,7 +133,6 @@ finish_decode({has_trailer, Value, Rest}) -> finish_decode(Val) -> maybe_map(Val). --ifndef(JIFFY_NO_MAPS). maybe_map(Obj) when is_map(Obj) -> maps:map(fun finish_decode_map/2, Obj); maybe_map(Val) -> @@ -149,10 +140,6 @@ maybe_map(Val) -> finish_decode_map(_, V) -> finish_decode(V). --else. -maybe_map(Val) -> - Val. --endif. finish_decode_obj([], Acc) -> {lists:reverse(Acc)}; diff --git a/src/jiffy_utf8.erl b/src/jiffy_utf8.erl index e79756f9..81346cbb 100644 --- a/src/jiffy_utf8.erl +++ b/src/jiffy_utf8.erl @@ -14,7 +14,6 @@ fix(Bin) when is_binary(Bin) -> fix(Val) -> maybe_map(Val). --ifndef(JIFFY_NO_MAPS). maybe_map(Obj) when is_map(Obj) -> maps:fold(fun fix_map/3, maps:new(), Obj); maybe_map(Val) -> @@ -22,10 +21,6 @@ maybe_map(Val) -> fix_map(K, V, Acc) -> maps:put(fix(K), fix(V), Acc). --else. -maybe_map(Val) -> - Val. --endif. fix_props([], Acc) -> {lists:reverse(Acc)}; diff --git a/test/jiffy_03_number_tests.erl b/test/jiffy_03_number_tests.erl index ad86a000..7ae8404c 100644 --- a/test/jiffy_03_number_tests.erl +++ b/test/jiffy_03_number_tests.erl @@ -36,8 +36,8 @@ gen(error, J) -> gen(floats, F) -> NegF = -1.0 * F, {msg("float round trip - ~p", [F]), [ - {"Pos", ?_assertEqual(F, dec(enc(F)))}, - {"Neg", ?_assertEqual(NegF, dec(enc(NegF)))} + {"Pos", ?_assert(F == dec(enc(F)))}, + {"Neg", ?_assert(NegF == dec(enc(NegF)))} ]}. diff --git a/test/jiffy_11_property_tests.erl b/test/jiffy_11_property_tests.erl index eb7cf934..b3f05a75 100644 --- a/test/jiffy_11_property_tests.erl +++ b/test/jiffy_11_property_tests.erl @@ -21,20 +21,9 @@ property_test_() -> run(prop_dec_trailer), run(prop_enc_no_crash), run(prop_dec_no_crash_bin), - run(prop_dec_no_crash_any) - ] ++ map_props(). - - --ifndef(JIFFY_NO_MAPS). -map_props() -> - [ + run(prop_dec_no_crash_any), run(prop_map_enc_dec) ]. --else. -map_props() -> - []. --endif. - prop_enc_dec() -> ?FORALL(Data, json(), begin @@ -63,7 +52,6 @@ prop_enc_dec_pretty() -> ). --ifndef(JIFFY_NO_MAPS). prop_map_enc_dec() -> ?FORALL(Data, json(), begin @@ -71,7 +59,6 @@ prop_map_enc_dec() -> MapData == jiffy:decode(jiffy:encode(MapData), [return_maps]) end ). --endif. prop_enc_no_crash() -> @@ -115,7 +102,6 @@ run(Name) -> ]}. --ifndef(JIFFY_NO_MAPS). to_map_ejson({Props}) -> NewProps = [{K, to_map_ejson(V)} || {K, V} <- Props], maps:from_list(NewProps); @@ -123,7 +109,6 @@ to_map_ejson(Vals) when is_list(Vals) -> [to_map_ejson(V) || V <- Vals]; to_map_ejson(Val) -> Val. --endif. % Random any term generation diff --git a/test/jiffy_15_return_trailer_tests.erl b/test/jiffy_15_return_trailer_tests.erl index 80937fa1..c8860c85 100644 --- a/test/jiffy_15_return_trailer_tests.erl +++ b/test/jiffy_15_return_trailer_tests.erl @@ -18,13 +18,9 @@ trailer_test_() -> ?_assertEqual(Result, jiffy:decode(Data, Opts)) end, Cases)}. --ifndef(JIFFY_NO_MAPS). - trailer_bignum_test() -> Opts = [return_maps, return_trailer], Data = <<"{\"amount\":-50000000000000000000}{}">>, Obj = #{<<"amount">> => -50000000000000000000}, Expect = {has_trailer, Obj, <<"{}">>}, ?assertEqual(Expect, jiffy:decode(Data, Opts)). - --endif. diff --git a/test/jiffy_17_copy_strings_tests.erl b/test/jiffy_17_copy_strings_tests.erl index 359b9971..5401c86d 100644 --- a/test/jiffy_17_copy_strings_tests.erl +++ b/test/jiffy_17_copy_strings_tests.erl @@ -24,10 +24,10 @@ check_binaries(_Bin) -> copy_strings_test_() -> Opts = [copy_strings], Cases = [ - <<"\"foo\"">>, - <<"[\"bar\"]">>, - <<"{\"foo\":\"bar\"}">>, - <<"{\"foo\":[\"bar\"]}">> + <<"\"xoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"">>, + <<"[\"yoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"]">>, + <<"{\"zoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\":\"woooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"}">>, + <<"{\"koooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\":[\"loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\"]}">> ], {"Test copy_strings", lists:map(fun(Json) -> EJson = jiffy:decode(Json, Opts),