diff --git a/README.md b/README.md index 1c6bc31..c6e35df 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Install from [Hex.pm](https://hex.pm/packages/xdr): ```elixir def deps do - [{:xdr, "~> 0.1.2"}] + [{:xdr, "~> 0.2.0"}] end ``` @@ -56,7 +56,8 @@ XDR.Type.Optional | Version | Change Summary | | ------- | -------------- | -| [v0.1.2](https://hex.pm/packages/xdr/0.1.2) | [negative integers in Enums](https://github.com/sunny-g/xdr/pull/11) +| [v0.2.0](https://hex.pm/packages/xdr/0.2.0) (in-progress) | [unify `__using__` API, upgrade to Elixir 1.6](https://github.com/sunny-g/xdr/pull/14) | +| [v0.1.2](https://hex.pm/packages/xdr/0.1.2) | [negative integers in Enums](https://github.com/sunny-g/xdr/pull/11) | | [v0.1.1](https://hex.pm/packages/xdr/0.1.1) | [minor bugfix](https://github.com/sunny-g/xdr/pull/6) | | [v0.1.0](https://hex.pm/packages/xdr/0.1.0) | initial release | diff --git a/lib/xdr/type/bool.ex b/lib/xdr/type/bool.ex index 46aa7b2..116f7cb 100644 --- a/lib/xdr/type/bool.ex +++ b/lib/xdr/type/bool.ex @@ -6,5 +6,7 @@ defmodule XDR.Type.Bool do @type t :: boolean @type xdr :: Enum.xdr() - use XDR.Type.Enum, false: 0, true: 1 + use XDR.Type.Enum, + false: 0, + true: 1 end diff --git a/lib/xdr/type/double_float.ex b/lib/xdr/type/double_float.ex index 583dc80..06235c2 100644 --- a/lib/xdr/type/double_float.ex +++ b/lib/xdr/type/double_float.ex @@ -4,7 +4,7 @@ defmodule XDR.Type.DoubleFloat do """ alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @behaviour XDR.Type.Base @@ -16,7 +16,8 @@ defmodule XDR.Type.DoubleFloat do @length 8 - defguard is_xdr_double(double) when is_float(double) or is_integer(double) + defguard is_xdr_double(double) + when is_float(double) or is_integer(double) @doc false def length, do: @length diff --git a/lib/xdr/type/enum.ex b/lib/xdr/type/enum.ex index 9364447..0973678 100644 --- a/lib/xdr/type/enum.ex +++ b/lib/xdr/type/enum.ex @@ -2,9 +2,7 @@ defmodule XDR.Type.Enum do @moduledoc """ RFC 4506, Section 4.3 - Enumeration """ - - require OK - import XDR.Util.Macros + import XDR.Util.Guards alias XDR.Type.{Base, Int} @typedoc """ @@ -16,13 +14,13 @@ defmodule XDR.Type.Enum do @type decode_error :: {:error, :invalid_xdr | :invalid_enum} @type encode_error :: {:error, :invalid | :invalid_name | :invalid_enum} - defmacro __using__(opts) do + defmacro __using__(spec) do # TODO: update this to statically compile spec into pattern-matched methods - if not Keyword.keyword?(opts) do + if not Keyword.keyword?(spec) do raise "Enum spec must be a keyword list" end - if Enum.any?(opts, fn + if Enum.any?(spec, fn {_, {:-, _, [v]}} -> not is_number(v) {_, v} -> not is_number(v) end) do @@ -33,10 +31,10 @@ defmodule XDR.Type.Enum do @behaviour XDR.Type.Base defdelegate length, to: unquote(__MODULE__) - def new(name), do: unquote(__MODULE__).new(name, unquote(opts)) - def valid?(name), do: unquote(__MODULE__).valid?(name, unquote(opts)) - def encode(name), do: unquote(__MODULE__).encode(name, unquote(opts)) - def decode(name), do: unquote(__MODULE__).decode(name, unquote(opts)) + def new(name), do: unquote(__MODULE__).new(name, unquote(spec)) + def valid?(name), do: unquote(__MODULE__).valid?(name, unquote(spec)) + def encode(name), do: unquote(__MODULE__).encode(name, unquote(spec)) + def decode(name), do: unquote(__MODULE__).decode(name, unquote(spec)) end end @@ -88,9 +86,7 @@ defmodule XDR.Type.Enum do def decode(_, enum) when not is_list(enum), do: {:error, :invalid_enum} def decode(xdr, enum) do - OK.with do - {val, rest} <- Int.decode(xdr) - + with {:ok, {val, rest}} <- Int.decode(xdr) do case Enum.find(enum, &Kernel.===(elem(&1, 1), val)) do {k, _} -> {:ok, {k, rest}} nil -> {:error, :invalid_enum} diff --git a/lib/xdr/type/fixed_array.ex b/lib/xdr/type/fixed_array.ex index cd00c80..4dd4472 100644 --- a/lib/xdr/type/fixed_array.ex +++ b/lib/xdr/type/fixed_array.ex @@ -4,7 +4,7 @@ defmodule XDR.Type.FixedArray do """ alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @typedoc """ A binary of any length @@ -14,7 +14,10 @@ defmodule XDR.Type.FixedArray do @type xdr :: Base.xdr() @type decode_error :: {:error, reason :: :invalid | :xdr_too_small} - defmacro __using__(len: len, type: type) do + defmacro __using__(spec) do + len = Keyword.get(spec, :len) + type = Keyword.get(spec, :type) + if not (is_integer(len) and len >= 0) do raise "invalid length" end diff --git a/lib/xdr/type/fixed_opaque.ex b/lib/xdr/type/fixed_opaque.ex index 7cb6bb9..4100913 100644 --- a/lib/xdr/type/fixed_opaque.ex +++ b/lib/xdr/type/fixed_opaque.ex @@ -5,7 +5,7 @@ defmodule XDR.Type.FixedOpaque do alias XDR.Type.Base alias XDR.Util - import XDR.Util.Macros + import XDR.Util.Guards @typedoc """ A binary of any length diff --git a/lib/xdr/type/float.ex b/lib/xdr/type/float.ex index a31789b..5ec0ba6 100644 --- a/lib/xdr/type/float.ex +++ b/lib/xdr/type/float.ex @@ -4,7 +4,7 @@ defmodule XDR.Type.Float do """ alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @behaviour XDR.Type.Base diff --git a/lib/xdr/type/hyper_int.ex b/lib/xdr/type/hyper_int.ex index 5f6341d..e3408d9 100644 --- a/lib/xdr/type/hyper_int.ex +++ b/lib/xdr/type/hyper_int.ex @@ -3,9 +3,8 @@ defmodule XDR.Type.HyperInt do RFC 4506, Section 4.5 - Hyper Integer """ - require Math alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @behaviour XDR.Type.Base @@ -15,8 +14,8 @@ defmodule XDR.Type.HyperInt do @type t :: -9_223_372_036_854_775_808..9_223_372_036_854_775_807 @type xdr :: <<_::_*64>> - @min_hyper_int -Math.pow(2, 63) - @max_hyper_int Math.pow(2, 63) - 1 + @min_hyper_int -9_223_372_036_854_775_808 + @max_hyper_int 9_223_372_036_854_775_807 @length 8 defguard is_hyper_int(int) diff --git a/lib/xdr/type/hyper_uint.ex b/lib/xdr/type/hyper_uint.ex index 28ef4a9..b5d8ea3 100644 --- a/lib/xdr/type/hyper_uint.ex +++ b/lib/xdr/type/hyper_uint.ex @@ -3,9 +3,8 @@ defmodule XDR.Type.HyperUint do RFC 4506, Section 4.5 - Unsigned Hyper Integer """ - require Math alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @behaviour XDR.Type.Base @@ -16,7 +15,7 @@ defmodule XDR.Type.HyperUint do @type xdr :: <<_::_*64>> @min_hyper_uint 0 - @max_hyper_uint Math.pow(2, 64) - 1 + @max_hyper_uint 18_446_744_073_709_551_615 @length 8 defguard is_hyper_uint(uint) diff --git a/lib/xdr/type/int.ex b/lib/xdr/type/int.ex index 53de3af..dc09aac 100644 --- a/lib/xdr/type/int.ex +++ b/lib/xdr/type/int.ex @@ -3,9 +3,8 @@ defmodule XDR.Type.Int do RFC 4506, Section 4.1 - Integer """ - require Math alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @behaviour XDR.Type.Base @@ -15,8 +14,8 @@ defmodule XDR.Type.Int do @type t :: -2_147_483_648..2_147_483_647 @type xdr :: Base.xdr() - @min_int -Math.pow(2, 31) - @max_int Math.pow(2, 31) - 1 + @min_int -2_147_483_648 + @max_int 2_147_483_647 @length 4 defguard is_int(int) diff --git a/lib/xdr/type/optional.ex b/lib/xdr/type/optional.ex index ccdf320..b99ed86 100644 --- a/lib/xdr/type/optional.ex +++ b/lib/xdr/type/optional.ex @@ -11,10 +11,12 @@ defmodule XDR.Type.Optional do } defmacro __using__(for: optional_type) do + required = quote do: require(unquote(optional_type)) + quote do - @behaviour XDR.Type.Base + unquote(required) - @type t :: nil | any + @type t :: nil | unquote(optional_type).t() @type type :: module @type xdr :: Base.xdr() diff --git a/lib/xdr/type/string.ex b/lib/xdr/type/string.ex index c72735f..00a0b25 100644 --- a/lib/xdr/type/string.ex +++ b/lib/xdr/type/string.ex @@ -3,7 +3,6 @@ defmodule XDR.Type.String do RFC 4506, Section 4.11 - String """ - require Math alias XDR.Type.Base alias XDR.Type.VariableOpaque @@ -15,14 +14,14 @@ defmodule XDR.Type.String do @type max :: VariableOpaque.max() @type decode_error :: VariableOpaque.decode_error() - @max_len Math.pow(2, 32) - 1 + @max_len 2_147_483_647 defguard is_xdr_string(string, max_len) when is_bitstring(string) and is_integer(max_len) and max_len <= @max_len and byte_size(string) <= max_len - defmacro __using__(opts \\ []) do - max_len = Keyword.get(opts, :max_len, @max_len) + defmacro __using__(spec) do + max_len = Keyword.get(spec, :max_len, @max_len) if max_len > @max_len do raise "max length too large" diff --git a/lib/xdr/type/struct.ex b/lib/xdr/type/struct.ex index f9fa805..25db8fd 100644 --- a/lib/xdr/type/struct.ex +++ b/lib/xdr/type/struct.ex @@ -3,14 +3,20 @@ defmodule XDR.Type.Struct do RFC 4506, Section 4.14 - Structure """ - require OK alias XDR.Type.Base defmacro __using__(spec) do keys = Keyword.keys(spec) + values = Keyword.values(spec) + + required = + for module <- values do + quote do: require(unquote(module)) + end quote do - import XDR.Util.Macros + import XDR.Util.Guards + unquote(required) @behaviour XDR.Type.Base @@ -75,21 +81,16 @@ defmodule XDR.Type.Struct do # HELPERS # ---------------------------------------------------------------------------# - def valid?(struct, {key, module}), - do: - struct - |> Map.get(key) - |> module.valid? + def valid?(struct, {key, module}) do + struct + |> Map.get(key) + |> module.valid? + end def encode(_struct, {_, _}, {:error, reason}), do: {:error, reason} def encode(struct, {key, module}, {:ok, curr_xdr}) do - OK.with do - xdr <- - struct - |> Map.get(key) - |> module.encode - + with {:ok, xdr} <- struct |> Map.get(key) |> module.encode do {:ok, curr_xdr <> xdr} end end @@ -97,8 +98,7 @@ defmodule XDR.Type.Struct do def decode({_, _}, {:error, reason}), do: {:error, reason} def decode({key, module}, {:ok, {struct, xdr}}) do - OK.with do - {val, rest} <- module.decode(xdr) + with {:ok, {val, rest}} <- module.decode(xdr) do {:ok, {Map.put(struct, key, val), rest}} end end diff --git a/lib/xdr/type/uint.ex b/lib/xdr/type/uint.ex index 707746d..538a865 100644 --- a/lib/xdr/type/uint.ex +++ b/lib/xdr/type/uint.ex @@ -5,9 +5,8 @@ defmodule XDR.Type.Uint do @behaviour XDR.Type.Base - require Math alias XDR.Type.Base - import XDR.Util.Macros + import XDR.Util.Guards @typedoc """ Integer between 0 and 2^32 - 1 @@ -16,7 +15,7 @@ defmodule XDR.Type.Uint do @type xdr :: Base.xdr() @min_uint 0 - @max_uint Math.pow(2, 32) - 1 + @max_uint 4_294_967_295 @length 4 defguard is_uint(uint) diff --git a/lib/xdr/type/union.ex b/lib/xdr/type/union.ex index 6a4dcb4..d81df7f 100644 --- a/lib/xdr/type/union.ex +++ b/lib/xdr/type/union.ex @@ -3,8 +3,6 @@ defmodule XDR.Type.Union do RFC 4506, Section 4.15 - Discriminated Union """ - require OK - import OK, only: [~>>: 2] import XDR.Util alias XDR.Type.{ @@ -30,7 +28,12 @@ defmodule XDR.Type.Union do @type attributes :: [{atom, switch}] defmacro __using__(spec) do + switch_module = get_switch(spec) + required = quote do: require(unquote(switch_module)) + quote do + unquote(required) + @behaviour XDR.Type.Base def length, do: :union @@ -96,10 +99,8 @@ defmodule XDR.Type.Union do attribute_module = get_attribute(discriminant, spec) if valid?({discriminant, val}, spec) do - OK.with do - switch <- switch_module.encode(discriminant) - arm <- attribute_module.encode(val) - + with {:ok, switch} <- switch_module.encode(discriminant), + {:ok, arm} <- attribute_module.encode(val) do {:ok, switch <> arm} end else @@ -123,13 +124,9 @@ defmodule XDR.Type.Union do end if valid?(discriminant, spec) and not is_nil(case_module) do - OK.with do - switch <- switch_module.encode(discriminant) - - arm <- - case_module.new() - ~>> case_module.encode() - + with {:ok, switch} <- switch_module.encode(discriminant), + {:ok, val} <- case_module.new(), + {:ok, arm} <- case_module.encode(val) do {:ok, switch <> arm} end else @@ -145,10 +142,8 @@ defmodule XDR.Type.Union do def decode(<>, spec) do switch_module = get_switch(spec) - OK.with do - {discriminant, _} <- switch_module.decode(discriminant_xdr) - {arm, rest} <- decode_arm(discriminant, arm_xdr, spec) - + with {:ok, {discriminant, _}} <- switch_module.decode(discriminant_xdr), + {:ok, {arm, rest}} <- decode_arm(discriminant, arm_xdr, spec) do if is_nil(arm) and arm_xdr === rest do {:ok, {discriminant, rest}} else diff --git a/lib/xdr/type/variable_array.ex b/lib/xdr/type/variable_array.ex index 8fc423d..b6bd93a 100644 --- a/lib/xdr/type/variable_array.ex +++ b/lib/xdr/type/variable_array.ex @@ -3,9 +3,7 @@ defmodule XDR.Type.VariableArray do RFC 4506, Section 4.13 - Variable-length Array """ - require Math - require OK - import XDR.Util.Macros + import XDR.Util.Guards alias XDR.Type.{ Base, @@ -22,11 +20,11 @@ defmodule XDR.Type.VariableArray do @type decode_error :: {:error, :invalid | :xdr_too_small} @len_size 32 - @max_len Math.pow(2, 32) - 1 + @max_len 4_294_967_295 - defmacro __using__(opts \\ []) do - max = Keyword.get(opts, :max_len, @max_len) - type = Keyword.get(opts, :type) + defmacro __using__(spec) do + max = Keyword.get(spec, :max_len, @max_len) + type = Keyword.get(spec, :type) if not (is_integer(max) and max >= 0 and max <= @max_len) do raise "invalid length" @@ -74,10 +72,9 @@ defmodule XDR.Type.VariableArray do def encode(array, type, max) do if valid?(array, type, max) do - OK.with do - len = length(array) - encoded <- FixedArray.encode(array, type, len) - encoded_len <- Uint.encode(len) + with len = length(array), + {:ok, encoded} <- FixedArray.encode(array, type, len), + {:ok, encoded_len} <- Uint.encode(len) do {:ok, encoded_len <> encoded} end else diff --git a/lib/xdr/type/variable_opaque.ex b/lib/xdr/type/variable_opaque.ex index ac56f6e..2340aa7 100644 --- a/lib/xdr/type/variable_opaque.ex +++ b/lib/xdr/type/variable_opaque.ex @@ -3,9 +3,7 @@ defmodule XDR.Type.VariableOpaque do RFC 4506, Section 4.10 - Variable-length Opaque Data """ - require Math - require OK - import XDR.Util.Macros + import XDR.Util.Guards alias XDR.Type.{Base, FixedOpaque, Uint} @typedoc """ @@ -23,7 +21,7 @@ defmodule XDR.Type.VariableOpaque do | :invalid_padding} @len_size 32 - @max Math.pow(2, 32) - 1 + @max 4_294_967_295 defguard is_valid_variable_opaque(opaque, max) when is_binary(opaque) and is_integer(max) and max <= @max and byte_size(opaque) <= max @@ -70,10 +68,9 @@ defmodule XDR.Type.VariableOpaque do def encode(opaque, max) when not is_valid_variable_opaque(opaque, max), do: {:error, :invalid} def encode(opaque, _) do - OK.with do - len = byte_size(opaque) - encoded <- FixedOpaque.encode(opaque, len) - encoded_len <- Uint.encode(len) + with len = byte_size(opaque), + {:ok, encoded} <- FixedOpaque.encode(opaque, len), + {:ok, encoded_len} <- Uint.encode(len) do {:ok, encoded_len <> encoded} end end diff --git a/lib/xdr/util.ex b/lib/xdr/util.ex index 384d8c9..933ed5f 100644 --- a/lib/xdr/util.ex +++ b/lib/xdr/util.ex @@ -1,6 +1,50 @@ -defmodule XDR.Util.Macros do +defmodule XDR.Util.Delegate do @moduledoc """ - XDR Macros (to be used in guard clauses) + Module to be `use`d for aliasing an XDR Type module + """ + + defmacro __using__(to: to_module) do + required = quote do: require(unquote(to_module)) + + quote do + unless unquote(__MODULE__).valid_xdr_type?(unquote(to_module)) do + raise "can only delegate to valid XDR Type modules" + end + + unquote(required) + + @behaviour XDR.Type.Base + + defdelegate length, to: unquote(to_module) + defdelegate valid?(native), to: unquote(to_module) + defdelegate encode(native), to: unquote(to_module) + defdelegate decode(native), to: unquote(to_module) + + if function_exported?(unquote(to_module), :new, 0) do + defdelegate new, to: unquote(to_module) + defdelegate new(native), to: unquote(to_module) + else + defdelegate new(native), to: unquote(to_module) + end + end + end + + @doc """ + Determines if the module is a valid XDR Type module (as defined by it's exported functions) + """ + def valid_xdr_type?(module) when is_atom(module) do + function_exported?(module, :length, 0) and + (function_exported?(module, :new, 0) or function_exported?(module, :new, 1)) and + function_exported?(module, :valid?, 1) and function_exported?(module, :encode, 1) and + function_exported?(module, :decode, 1) + end + + def valid_xdr_type?(_), do: false +end + +defmodule XDR.Util.Guards do + @moduledoc """ + XDR Guards """ defguard is_valid_xdr(binary) @@ -16,24 +60,13 @@ end defmodule XDR.Util do @moduledoc false - require XDR.Util.Macros + require XDR.Util.Guards - def required_padding(0), do: 0 - def required_padding(4), do: 0 + defdelegate valid_xdr_type?(module), to: XDR.Util.Delegate - def required_padding(len) when is_integer(len) do - 4 - XDR.Util.Macros.calculate_padding(len) - end + def required_padding(len) when XDR.Util.Guards.calculate_padding(len) == 0, do: 0 - @doc """ - Determines if the module is a valid XDR Type module (as defined by it's exported functions) - """ - def valid_xdr_type?(atom) when is_atom(atom) do - function_exported?(atom, :length, 0) and - (function_exported?(atom, :new, 0) or function_exported?(atom, :new, 1)) and - function_exported?(atom, :valid?, 1) and function_exported?(atom, :encode, 1) and - function_exported?(atom, :decode, 1) + def required_padding(len) when is_integer(len) do + 4 - XDR.Util.Guards.calculate_padding(len) end - - def valid_xdr_type?(_), do: false end diff --git a/mix.exs b/mix.exs index 91d0707..b168e5c 100644 --- a/mix.exs +++ b/mix.exs @@ -4,10 +4,7 @@ defmodule XDR.Mixfile do @name :xdr @version "0.2.0" - @deps [ - {:math, "~> 0.3.0"}, - {:ok, github: "sunny-g/ok"}, - ] + @deps [] @dev_deps [ {:credo, "~> 0.8", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 525673b..e09066e 100644 --- a/mix.lock +++ b/mix.lock @@ -7,8 +7,6 @@ "jason": {:hex, :jason, "1.1.1", "d3ccb840dfb06f2f90a6d335b536dd074db748b3e7f5b11ab61d239506585eb2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "math": {:hex, :math, "0.3.0", "e14e7291115201cb155a3567e66d196bf5088a6f55b030d598107d7ae934a11c", [:mix], [], "hexpm"}, "mix_test_watch": {:hex, :mix_test_watch, "0.8.0", "acf97da2abc66532e7dc1aa66a5d6c9fc4442d7992d5d7eb4faeaeb964c2580e", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"}, - "ok": {:git, "https://github.com/sunny-g/ok.git", "e9bd5108b054cc12d45358790c693d640e8df388", []}, } diff --git a/test/xdr/type/enum_test.exs b/test/xdr/type/enum_test.exs index 5e34fab..3965b94 100644 --- a/test/xdr/type/enum_test.exs +++ b/test/xdr/type/enum_test.exs @@ -5,21 +5,21 @@ defmodule XDR.Type.EnumTest do alias XDR.Type.Enum alias XDR.Type.Int - defmodule XDR.Type.EnumTest.DummyEnum do + defmodule DummyEnum do use Enum, red: 0, green: 1, evenMoreGreen: 3 end - defmodule XDR.Type.EnumTest.NegativeEnum do + defmodule NegativeEnum do use Enum, zero: 0, one: -1, two: -2 end - defmodule XDR.Type.EnumTest.InvalidSpec do + defmodule InvalidSpec do import CompileTimeAssertions assert_compile_time_raise(RuntimeError, "Enum spec must be a keyword list", fn -> @@ -27,7 +27,7 @@ defmodule XDR.Type.EnumTest do end) end - defmodule XDR.Type.EnumTest.ExceedMax do + defmodule ExceedMax do import CompileTimeAssertions assert_compile_time_raise(RuntimeError, "all Enum values must be numbers", fn -> @@ -35,8 +35,6 @@ defmodule XDR.Type.EnumTest do end) end - alias XDR.Type.EnumTest.{DummyEnum, NegativeEnum} - test "length" do assert DummyEnum.length() === 4 end diff --git a/test/xdr/type/hyper_int_test.exs b/test/xdr/type/hyper_int_test.exs index 0009e19..712efa3 100644 --- a/test/xdr/type/hyper_int_test.exs +++ b/test/xdr/type/hyper_int_test.exs @@ -2,11 +2,10 @@ defmodule XDR.Type.HyperIntTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.HyperInt - @min_hyper_int -Math.pow(2, 63) - @max_hyper_int Math.pow(2, 63) - 1 + @min_hyper_int -9_223_372_036_854_775_808 + @max_hyper_int 9_223_372_036_854_775_807 test "length" do assert HyperInt.length() === 8 diff --git a/test/xdr/type/hyper_uint_test.exs b/test/xdr/type/hyper_uint_test.exs index dbab40f..17b55c4 100644 --- a/test/xdr/type/hyper_uint_test.exs +++ b/test/xdr/type/hyper_uint_test.exs @@ -2,11 +2,10 @@ defmodule XDR.Type.HyperUintTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.HyperUint @min_hyper_uint 0 - @max_hyper_uint Math.pow(2, 64) - 1 + @max_hyper_uint 18_446_744_073_709_551_615 test "length" do assert HyperUint.length() === 8 diff --git a/test/xdr/type/int_test.exs b/test/xdr/type/int_test.exs index a5169d8..d7a914f 100644 --- a/test/xdr/type/int_test.exs +++ b/test/xdr/type/int_test.exs @@ -2,11 +2,10 @@ defmodule XDR.Type.IntTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.Int - @min_int -Math.pow(2, 31) - @max_int Math.pow(2, 31) - 1 + @min_int -2_147_483_648 + @max_int 2_147_483_647 test "length" do assert Int.length() === 4 diff --git a/test/xdr/type/string_test.exs b/test/xdr/type/string_test.exs index 5608659..dc20d1b 100644 --- a/test/xdr/type/string_test.exs +++ b/test/xdr/type/string_test.exs @@ -2,7 +2,6 @@ defmodule XDR.Type.StringTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.String defmodule XDR.Type.StringTest.Len1 do @@ -25,7 +24,7 @@ defmodule XDR.Type.StringTest do import CompileTimeAssertions assert_compile_time_raise(RuntimeError, "max length too large", fn -> - use XDR.Type.String, max_len: Math.pow(2, 32) + use XDR.Type.String, max_len: 4_294_967_296 end) end diff --git a/test/xdr/type/uint_test.exs b/test/xdr/type/uint_test.exs index 616a498..219629d 100644 --- a/test/xdr/type/uint_test.exs +++ b/test/xdr/type/uint_test.exs @@ -2,11 +2,10 @@ defmodule XDR.Type.UintTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.Uint @min_uint 0 - @max_uint Math.pow(2, 32) - 1 + @max_uint 4_294_967_295 test "length" do assert Uint.length() === 4 diff --git a/test/xdr/type/variable_opaque_test.exs b/test/xdr/type/variable_opaque_test.exs index f608fa5..9e77a66 100644 --- a/test/xdr/type/variable_opaque_test.exs +++ b/test/xdr/type/variable_opaque_test.exs @@ -2,7 +2,6 @@ defmodule XDR.Type.VariableOpaqueTest do @moduledoc false use ExUnit.Case, async: true - require Math alias XDR.Type.VariableOpaque defmodule XDR.Type.VariableOpaqueTest.Len1 do @@ -25,7 +24,7 @@ defmodule XDR.Type.VariableOpaqueTest do import CompileTimeAssertions assert_compile_time_raise(RuntimeError, "max length too large", fn -> - use XDR.Type.VariableOpaque, max_len: Math.pow(2, 32) + use XDR.Type.VariableOpaque, max_len: 4_294_967_296 end) end diff --git a/test/xdr/util_test.exs b/test/xdr/util_test.exs new file mode 100644 index 0000000..38c21d7 --- /dev/null +++ b/test/xdr/util_test.exs @@ -0,0 +1,80 @@ +defmodule XDR.Util.DelegateTest.Int32 do + use XDR.Util.Delegate, to: XDR.Type.Int +end + +defmodule XDR.Util.DelegateTest do + @moduledoc false + + use ExUnit.Case, async: true + alias XDR.Util.DelegateTest.Int32 + + @min_int -2_147_483_648 + @max_int 2_147_483_647 + + test "length" do + assert Int32.length() === 4 + end + + test "new" do + assert Int32.new() === {:ok, 0} + assert Int32.new(0) === {:ok, 0} + assert Int32.new(1) === {:ok, 1} + assert Int32.new(@min_int) === {:ok, @min_int} + assert Int32.new(@max_int) === {:ok, @max_int} + + assert Int32.new(@min_int - 1) === {:error, :invalid} + assert Int32.new(@max_int + 1) === {:error, :invalid} + assert Int32.new("0") === {:error, :invalid} + assert Int32.new(nil) === {:error, :invalid} + assert Int32.new(false) === {:error, :invalid} + assert Int32.new([]) === {:error, :invalid} + assert Int32.new({}) === {:error, :invalid} + end + + test "valid?" do + assert Int32.valid?(0) == true + assert Int32.valid?(1) == true + assert Int32.valid?(-1) == true + assert Int32.valid?(@min_int) == true + assert Int32.valid?(@max_int) == true + + assert Int32.valid?(0.0) == false + assert Int32.valid?(-0.1) == false + assert Int32.valid?(-:math.pow(2, 31)) == false + assert Int32.valid?(:math.pow(2, 31) - 1) == false + assert Int32.valid?(@min_int - 1) == false + assert Int32.valid?(@max_int + 1) == false + assert Int32.valid?(true) == false + assert Int32.valid?(false) == false + assert Int32.valid?(nil) == false + assert Int32.valid?("0") == false + assert Int32.valid?({}) == false + assert Int32.valid?([]) == false + assert Int32.valid?([0]) == false + end + + test "encode" do + assert Int32.encode(0) == {:ok, <<0, 0, 0, 0>>} + assert Int32.encode(1) == {:ok, <<0, 0, 0, 1>>} + assert Int32.encode(-1) == {:ok, <<255, 255, 255, 255>>} + assert Int32.encode(@min_int) == {:ok, <<128, 0, 0, 0>>} + assert Int32.encode(@max_int) == {:ok, <<127, 255, 255, 255>>} + + assert Int32.encode(0.1) == {:error, :invalid} + assert Int32.encode(@min_int - 1) == {:error, :out_of_bounds} + assert Int32.encode(@max_int + 1) == {:error, :out_of_bounds} + end + + test "decode" do + assert Int32.decode(<<0, 0, 0, 0>>) == {:ok, {0, <<>>}} + assert Int32.decode(<<0, 0, 0, 1>>) == {:ok, {1, <<>>}} + assert Int32.decode(<<0, 0, 0, 1, 0, 0, 0, 0>>) == {:ok, {1, <<0, 0, 0, 0>>}} + assert Int32.decode(<<255, 255, 255, 255>>) == {:ok, {-1, <<>>}} + assert Int32.decode(<<128, 0, 0, 0>>) == {:ok, {@min_int, <<>>}} + assert Int32.decode(<<127, 255, 255, 255>>) == {:ok, {@max_int, <<>>}} + + assert Int32.decode("0") == {:error, :invalid} + assert Int32.decode(<<0, 0, 0, 0, 0>>) == {:error, :invalid} + assert Int32.decode(<<127, 255, 255, 255, 255>>) == {:error, :invalid} + end +end