%%% -*- erlang-indent-level: 2 -*- %%%------------------------------------------------------------------- %%% Author: Kostis Sagonas %%% %%% Contains tests for handling of BIFs in guards and body calls. %%%------------------------------------------------------------------- -module(basic_bifs). -export([test/0]). -define(BIG, 1398479237498374913984792374983749). test() -> ok = test_abs(), ok = test_binary_part(), ok = test_element(), ok = test_float(), ok = test_float_to_list(), ok = test_integer_to_list(), ok = test_list_to_float(), ok = test_list_to_integer(), ok = test_round(), ok = test_trunc(), ok. %%-------------------------------------------------------------------- test_abs() -> t_abs(5.5, 0.0, -100.0, 5, 0, -100, ?BIG). t_abs(F1, F2, F3, I1, I2, I3, BigNum) -> %% Floats. 5.5 = abs(F1), 0.0 = abs(F2), 100.0 = abs(F3), %% Integers. 5 = abs(I1), 0 = abs(I2), 100 = abs(I3), %% Bignums. BigNum = abs(BigNum), BigNum = abs(-BigNum), ok. %%-------------------------------------------------------------------- %% Checks that 2-ary and 3-ary BIFs can be compiled to native code. test_binary_part() -> Bin = <<1,2,3,4,5,6,7,8,9,10>>, BinPart = bp3(Bin), <<7,8>> = bp2(BinPart), ok. bp2(Bin) -> binary_part(Bin, {1, 2}). bp3(Bin) -> binary_part(Bin, byte_size(Bin), -5). %%-------------------------------------------------------------------- test_element() -> true = elem({a, b}), false = elem({a, c}), other = elem(gazonk), ok. elem(T) when element(1, T) == a -> element(2, T) == b; elem(_) -> other. %%-------------------------------------------------------------------- test_float() -> t_float(0, 42, -100, 2.5, 0.0, -100.42, ?BIG, -?BIG). t_float(I1, I2, I3, F1, F2, F3, B1, B2) -> 0.0 = float(I1), 2.5 = float(F1), 0.0 = float(F2), -100.42 = float(F3), 42.0 = float(I2), -100.0 = float(I3), %% Bignums. 1398479237498374913984792374983749.0 = float(B1), -1398479237498374913984792374983749.0 = float(B2), %% Extremly big bignums. Big = list_to_integer(duplicate(2000, $1)), {'EXIT', _} = (catch float(Big)), %% Invalid types and lists. {'EXIT', _} = (catch my_list_to_integer(atom)), {'EXIT', _} = (catch my_list_to_integer(123)), {'EXIT', _} = (catch my_list_to_integer([$1, [$2]])), {'EXIT', _} = (catch my_list_to_integer("1.2")), {'EXIT', _} = (catch my_list_to_integer("a")), {'EXIT', _} = (catch my_list_to_integer("")), ok. my_list_to_integer(X) -> list_to_integer(X). %%-------------------------------------------------------------------- test_float_to_list() -> test_ftl("0.0e+0", 0.0), test_ftl("2.5e+1", 25.0), test_ftl("2.5e+0", 2.5), test_ftl("2.5e-1", 0.25), test_ftl("-3.5e+17", -350.0e15), ok. test_ftl(Expect, Float) -> %% No \n on the next line -- we want the line number from t_float_to_list. Expect = remove_zeros(lists:reverse(float_to_list(Float)), []). %% Removes any non-significant zeros in a floating point number. %% Example: 2.500000e+01 -> 2.5e+1 remove_zeros([$+, $e|Rest], [$0, X|Result]) -> remove_zeros([$+, $e|Rest], [X|Result]); remove_zeros([$-, $e|Rest], [$0, X|Result]) -> remove_zeros([$-, $e|Rest], [X|Result]); remove_zeros([$0, $.|Rest], [$e|Result]) -> remove_zeros(Rest, [$., $0, $e|Result]); remove_zeros([$0|Rest], [$e|Result]) -> remove_zeros(Rest, [$e|Result]); remove_zeros([Char|Rest], Result) -> remove_zeros(Rest, [Char|Result]); remove_zeros([], Result) -> Result. %%-------------------------------------------------------------------- test_integer_to_list() -> t_integer_to_list(0, 42, 32768, 268435455, 123456932798748738738). t_integer_to_list(I1, I2, I3, I4, BIG) -> "0" = integer_to_list(I1), "42" = integer_to_list(I2), "-42" = integer_to_list(-I2), "-42" = integer_to_list(-I2), "32768" = integer_to_list(I3), "268435455" = integer_to_list(I4), "-268435455" = integer_to_list(-I4), "123456932798748738738" = integer_to_list(BIG), BigList = duplicate(2000, $1), Big = list_to_integer(BigList), BigList = integer_to_list(Big), ok. %%-------------------------------------------------------------------- test_list_to_float() -> ok = t_list_to_float_safe(), ok = t_list_to_float_risky(). t_list_to_float_safe() -> 0.0 = my_list_to_float("0.0"), 0.0 = my_list_to_float("-0.0"), 0.5 = my_list_to_float("0.5"), -0.5 = my_list_to_float("-0.5"), 100.0 = my_list_to_float("1.0e2"), 127.5 = my_list_to_float("127.5"), -199.5 = my_list_to_float("-199.5"), {'EXIT', _} = (catch my_list_to_float("0")), {'EXIT', _} = (catch my_list_to_float("0..0")), {'EXIT', _} = (catch my_list_to_float("0e12")), {'EXIT', _} = (catch my_list_to_float("--0.0")), ok. my_list_to_float(X) -> list_to_float(X). %% This might crash the emulator. (Used to crash Erlang 4.4.1 on Unix.) t_list_to_float_risky() -> Many_Ones = duplicate(25000, $1), ok = case list_to_float("2." ++ Many_Ones) of F when is_float(F), 0.0 < F, F =< 3.14 -> ok end, {'EXIT', _} = (catch list_to_float("2" ++ Many_Ones)), ok. %%-------------------------------------------------------------------- test_list_to_integer() -> ok = t_list_to_integer_small("0", "00", "-0", "1", "-1", "42", "-12", "32768", "268435455", "-268435455"), ok = t_list_to_integer_bignum("123456932798748738738666"), ok. t_list_to_integer_small(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10) -> 0 = list_to_integer(S1), 0 = list_to_integer(S2), 0 = list_to_integer(S3), 1 = list_to_integer(S4), -1 = list_to_integer(S5), 42 = list_to_integer(S6), -12 = list_to_integer(S7), 32768 = list_to_integer(S8), 268435455 = list_to_integer(S9), -268435455 = list_to_integer(S10), ok. t_list_to_integer_bignum(S) -> 123456932798748738738666 = list_to_integer(S), case list_to_integer(duplicate(2000, $1)) of I when is_integer(I), I > 123456932798748738738666 -> ok end. %%-------------------------------------------------------------------- test_round() -> ok = t_round_small(0.0, 0.4, 0.5, -0.4, -0.5, 255.3, 255.6, -1033.3, -1033.6), ok = t_round_big(4294967296.1, 4294967296.9), ok. t_round_small(F1, F2, F3, F4, F5, F6, F7, F8, F9) -> 0 = round(F1), 0 = round(F2), 1 = round(F3), 0 = round(F4), -1 = round(F5), 255 = round(F6), 256 = round(F7), -1033 = round(F8), -1034 = round(F9), ok. t_round_big(B1, B2) -> 4294967296 = round(B1), 4294967297 = round(B2), -4294967296 = round(-B1), -4294967297 = round(-B2), ok. %%-------------------------------------------------------------------- test_trunc() -> t_trunc(0.0, 5.3333, -10.978987, 4294967305.7). t_trunc(F1, F2, F3, B) -> 0 = trunc(F1), 5 = trunc(F2), -10 = trunc(F3), %% Bignums. 4294967305 = trunc(B), -4294967305 = trunc(-B), ok. %%-------------------------------------------------------------------- %% Auxiliary functions below duplicate(N, X) when is_integer(N), N >= 0 -> duplicate(N, X, []). duplicate(0, _, L) -> L; duplicate(N, X, L) -> duplicate(N-1, X, [X|L]).