Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
737ac62926 | ||
|
|
9dcc0e140b | ||
|
|
e4e5481ca1 | ||
|
|
c3df6806b3 | ||
|
|
6dc523074d | ||
|
|
5746cbf1e3 | ||
|
|
51966e92a7 | ||
|
|
498057c51b | ||
|
|
b3c26a8633 | ||
|
|
5e218e77bf | ||
|
|
56fbf2a399 | ||
|
|
c3582f9617 | ||
|
|
bd83a45215 | ||
|
|
52dc944cfb | ||
|
|
3d27c749e1 | ||
|
|
75d679cdc8 | ||
|
|
2c9f28ecc3 | ||
|
|
9decf4c78a | ||
|
|
e2463a5589 | ||
|
|
a825f5a0c8 | ||
|
|
3c0d26cb74 | ||
|
|
f7a31ac804 | ||
|
|
31aebcdc59 | ||
|
|
afbac81918 | ||
|
|
0b78f86f08 | ||
|
|
7180b98f47 | ||
|
|
021cca436d |
@@ -85,6 +85,33 @@ ask Mix to use Rebar 3 to compile it by passing the `manager: :rebar3` option.
|
||||
Once configured, Mix will prompt you to install Rebar 3 if it is not yet
|
||||
available.
|
||||
|
||||
## v1.2.3 (2016-02-21)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [Base] Add `:ignore` and `:padding` option to encoding/decoding functions
|
||||
* [Mix] Add `Mix.Projects.deps_paths` that returns the dependencies path as a map
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [ExUnit] Do not provide negative line numbers without generated annotation (for compatibility with Erlang 19)
|
||||
* [Mix] Reject non fullfilled optional dependencies later on in the convergence resolution for proper dependency sorting
|
||||
* [String] Fix incomplete data trimming on both `String.replace_trailing` and `String.rstrip`
|
||||
* [String] Attach debug_info back into Unicode modules for Dialyzer support
|
||||
|
||||
## v1.2.2 (2016-01-31)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
* [Kernel] Support `@compile {:autoload, false}` to disable automatic loading after compilation
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
* [ExUnit] Raise if trying to override reserved tag in `setup` blocks
|
||||
* [Mix] Ensure retrieve compile manifests do fail if some compilers are not yet available
|
||||
* [Mix] Automatically merge managers according to the mix > rebar3 > rebar > make order
|
||||
* [Mix] Force recompilation if dependency was recently fetched
|
||||
|
||||
## v1.2.1 (2016-01-14)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
REBAR ?= "$(CURDIR)/rebar"
|
||||
PREFIX ?= /usr/local
|
||||
DOCS := v1.2
|
||||
CANONICAL := stable
|
||||
ELIXIRC := bin/elixirc --verbose --ignore-module-conflict
|
||||
ERLC := erlc -I lib/elixir/include
|
||||
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
|
||||
@@ -128,7 +129,7 @@ clean_exbeam:
|
||||
|
||||
LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
|
||||
SOURCE_REF = $(shell head="$$(git rev-parse HEAD)" tag="$$(git tag --points-at $$head | tail -1)" ; echo "$${tag:-$$head}\c")
|
||||
COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" -m "$(3)" -u "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) -o doc/$(2) -p http://elixir-lang.org/docs.html $(4)
|
||||
COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" -m "$(3)" -u "https://github.com/elixir-lang/elixir" --source-ref "v$(VERSION)" $(call LOGO_PATH) -o doc/$(2) -a http://elixir-lang.org/docs/$(CANONICAL)/$(2)/ -p http://elixir-lang.org/docs.html $(4)
|
||||
|
||||
docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
|
||||
|
||||
|
||||
+244
-127
@@ -138,6 +138,15 @@ defmodule Base do
|
||||
defp from_mixed(char),
|
||||
do: char
|
||||
|
||||
defp maybe_pad(subject, false, _, _),
|
||||
do: subject
|
||||
defp maybe_pad(subject, _, group_size, pad) do
|
||||
case rem(byte_size(subject), group_size) do
|
||||
0 -> subject
|
||||
x -> subject <> String.duplicate(pad, group_size - x)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Encodes a binary string into a base 16 encoded string.
|
||||
|
||||
@@ -225,29 +234,56 @@ defmodule Base do
|
||||
@doc """
|
||||
Encodes a binary string into a base 64 encoded string.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.encode64("foobar")
|
||||
"Zm9vYmFy"
|
||||
|
||||
iex> Base.encode64("foob")
|
||||
"Zm9vYg=="
|
||||
|
||||
iex> Base.encode64("foob", padding: false)
|
||||
"Zm9vYg"
|
||||
|
||||
"""
|
||||
@spec encode64(binary) :: binary
|
||||
def encode64(data) when is_binary(data) do
|
||||
do_encode64(data)
|
||||
@spec encode64(binary, Keyword.t) :: binary
|
||||
def encode64(data, opts \\ []) when is_binary(data) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode64(data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Decodes a base 64 encoded string into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.decode64("Zm9vYmFy")
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode64("Zm9vYmFy\\n", ignore: :whitespace)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode64("Zm9vYg==")
|
||||
{:ok, "foob"}
|
||||
|
||||
iex> Base.decode64("Zm9vYg", padding: false)
|
||||
{:ok, "foob"}
|
||||
|
||||
"""
|
||||
@spec decode64(binary) :: {:ok, binary} | :error
|
||||
def decode64(string) when is_binary(string) do
|
||||
{:ok, decode64!(string)}
|
||||
@spec decode64(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
def decode64(string, opts \\ []) when is_binary(string) do
|
||||
{:ok, decode64!(string, opts)}
|
||||
rescue
|
||||
ArgumentError -> :error
|
||||
end
|
||||
@@ -255,7 +291,11 @@ defmodule Base do
|
||||
@doc """
|
||||
Decodes a base 64 encoded string into a binary string.
|
||||
|
||||
The following alphabet is used both for encoding and decoding:
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
@@ -265,44 +305,72 @@ defmodule Base do
|
||||
iex> Base.decode64!("Zm9vYmFy")
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode64!("Zm9vYmFy\\n", ignore: :whitespace)
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode64!("Zm9vYg==")
|
||||
"foob"
|
||||
|
||||
iex> Base.decode64!("Zm9vYg", padding: false)
|
||||
"foob"
|
||||
|
||||
"""
|
||||
@spec decode64!(binary) :: binary
|
||||
def decode64!(string) when is_binary(string) and rem(byte_size(string), 4) == 0 do
|
||||
do_decode64(string)
|
||||
end
|
||||
|
||||
def decode64!(string) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
@spec decode64!(binary, Keyword.t) :: binary
|
||||
def decode64!(string, opts \\ []) when is_binary(string) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
string |> filter_ignored(opts[:ignore]) |> do_decode64(pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Encodes a binary string into a base 64 encoded string with URL and filename
|
||||
safe alphabet.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.url_encode64(<<255, 127, 254, 252>>)
|
||||
"_3_-_A=="
|
||||
|
||||
iex> Base.url_encode64(<<255, 127, 254, 252>>, padding: false)
|
||||
"_3_-_A"
|
||||
|
||||
"""
|
||||
@spec url_encode64(binary) :: binary
|
||||
def url_encode64(data) when is_binary(data) do
|
||||
do_encode64url(data)
|
||||
@spec url_encode64(binary, Keyword.t) :: binary
|
||||
def url_encode64(data, opts \\ []) when is_binary(data) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode64url(data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Decodes a base 64 encoded string with URL and filename safe alphabet
|
||||
into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.url_decode64("_3_-_A==")
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
iex> Base.url_decode64("_3_-_A==\\n", ignore: :whitespace)
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
iex> Base.url_decode64("_3_-_A", padding: false)
|
||||
{:ok, <<255, 127, 254, 252>>}
|
||||
|
||||
"""
|
||||
@spec url_decode64(binary) :: {:ok, binary} | :error
|
||||
def url_decode64(string) when is_binary(string) do
|
||||
{:ok, url_decode64!(string)}
|
||||
@spec url_decode64(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
def url_decode64(string, opts \\ []) when is_binary(string) do
|
||||
{:ok, url_decode64!(string, opts)}
|
||||
rescue
|
||||
ArgumentError -> :error
|
||||
end
|
||||
@@ -311,6 +379,12 @@ defmodule Base do
|
||||
Decodes a base 64 encoded string with URL and filename safe alphabet
|
||||
into a binary string.
|
||||
|
||||
Accepts `ignore: :whitespace` option which will ignore all the
|
||||
whitespace characters in the input string.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -319,14 +393,18 @@ defmodule Base do
|
||||
iex> Base.url_decode64!("_3_-_A==")
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
iex> Base.url_decode64!("_3_-_A==\\n", ignore: :whitespace)
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
iex> Base.url_decode64!("_3_-_A", padding: false)
|
||||
<<255, 127, 254, 252>>
|
||||
|
||||
"""
|
||||
@spec url_decode64!(binary) :: binary
|
||||
def url_decode64!(string) when is_binary(string) and rem(byte_size(string), 4) == 0 do
|
||||
do_decode64url(string)
|
||||
end
|
||||
|
||||
def url_decode64!(string) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
@spec url_decode64!(binary, Keyword.t) :: binary
|
||||
def url_decode64!(string, opts \\ []) when is_binary(string) do
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
string |> filter_ignored(opts[:ignore]) |> do_decode64url(pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -335,6 +413,9 @@ defmodule Base do
|
||||
Accepts an atom `:upper` (default) for encoding to upper case characters or
|
||||
`:lower` for lower case characters.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.encode32("foobar")
|
||||
@@ -343,12 +424,16 @@ defmodule Base do
|
||||
iex> Base.encode32("foobar", case: :lower)
|
||||
"mzxw6ytboi======"
|
||||
|
||||
iex> Base.encode32("foobar", padding: false)
|
||||
"MZXW6YTBOI"
|
||||
|
||||
"""
|
||||
@spec encode32(binary) :: binary
|
||||
@spec encode32(binary, Keyword.t) :: binary
|
||||
def encode32(data, opts \\ []) when is_binary(data) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_encode32(case, data)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_encode32(case, data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -358,6 +443,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.decode32("MZXW6YTBOI======")
|
||||
@@ -369,6 +457,9 @@ defmodule Base do
|
||||
iex> Base.decode32("mzXW6ytBOi======", case: :mixed)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.decode32("MZXW6YTBOI", padding: false)
|
||||
{:ok, "foobar"}
|
||||
|
||||
"""
|
||||
@spec decode32(binary) :: {:ok, binary} | :error
|
||||
@spec decode32(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
@@ -385,6 +476,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -399,18 +493,16 @@ defmodule Base do
|
||||
iex> Base.decode32!("mzXW6ytBOi======", case: :mixed)
|
||||
"foobar"
|
||||
|
||||
iex> Base.decode32!("MZXW6YTBOI", padding: false)
|
||||
"foobar"
|
||||
|
||||
"""
|
||||
@spec decode32!(binary) :: binary
|
||||
@spec decode32!(binary, Keyword.t) :: binary
|
||||
def decode32!(string, opts \\ [])
|
||||
|
||||
def decode32!(string, opts) when is_binary(string) and rem(byte_size(string), 8) == 0 do
|
||||
def decode32!(string, opts \\ []) when is_binary(string) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_decode32(case, string)
|
||||
end
|
||||
|
||||
def decode32!(string, _opts) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_decode32(case, string, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -420,6 +512,9 @@ defmodule Base do
|
||||
Accepts an atom `:upper` (default) for encoding to upper case characters or
|
||||
`:lower` for lower case characters.
|
||||
|
||||
Accepts `padding: false` option which will omit padding from
|
||||
the output string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.hex_encode32("foobar")
|
||||
@@ -428,12 +523,16 @@ defmodule Base do
|
||||
iex> Base.hex_encode32("foobar", case: :lower)
|
||||
"cpnmuoj1e8======"
|
||||
|
||||
iex> Base.hex_encode32("foobar", padding: false)
|
||||
"CPNMUOJ1E8"
|
||||
|
||||
"""
|
||||
@spec hex_encode32(binary) :: binary
|
||||
@spec hex_encode32(binary, Keyword.t) :: binary
|
||||
def hex_encode32(data, opts \\ []) when is_binary(data) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_hex_encode32(case, data)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_hex_encode32(case, data, pad_flag)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -444,6 +543,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Base.hex_decode32("CPNMUOJ1E8======")
|
||||
@@ -455,6 +557,9 @@ defmodule Base do
|
||||
iex> Base.hex_decode32("cpnMuOJ1E8======", case: :mixed)
|
||||
{:ok, "foobar"}
|
||||
|
||||
iex> Base.hex_decode32("CPNMUOJ1E8", padding: false)
|
||||
{:ok, "foobar"}
|
||||
|
||||
"""
|
||||
@spec hex_decode32(binary) :: {:ok, binary} | :error
|
||||
@spec hex_decode32(binary, Keyword.t) :: {:ok, binary} | :error
|
||||
@@ -472,6 +577,9 @@ defmodule Base do
|
||||
`:lower` for lower case characters. `:mixed` can be given for mixed case
|
||||
characters.
|
||||
|
||||
Accepts `padding: false` option which will ignore padding from
|
||||
the input string.
|
||||
|
||||
An `ArgumentError` exception is raised if the padding is incorrect or
|
||||
a non-alphabet character is present in the string.
|
||||
|
||||
@@ -486,18 +594,21 @@ defmodule Base do
|
||||
iex> Base.hex_decode32!("cpnMuOJ1E8======", case: :mixed)
|
||||
"foobar"
|
||||
|
||||
iex> Base.hex_decode32!("CPNMUOJ1E8", padding: false)
|
||||
"foobar"
|
||||
|
||||
"""
|
||||
@spec hex_decode32!(binary) :: binary
|
||||
@spec hex_decode32!(binary, Keyword.t) :: binary
|
||||
def hex_decode32!(string, opts \\ [])
|
||||
|
||||
def hex_decode32!(string, opts) when is_binary(string) and rem(byte_size(string), 8) == 0 do
|
||||
def hex_decode32!(string, opts \\ []) when is_binary(string) do
|
||||
case = Keyword.get(opts, :case, :upper)
|
||||
do_hex_decode32(case, string)
|
||||
pad_flag = Keyword.get(opts, :padding, true)
|
||||
do_hex_decode32(case, string, pad_flag)
|
||||
end
|
||||
|
||||
def hex_decode32!(string, _opts) when is_binary(string) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
defp filter_ignored(string, nil), do: string
|
||||
defp filter_ignored(string, :whitespace) do
|
||||
for <<c::8 <- string>>, not c in '\s\t\r\n', into: <<>>, do: <<c::8>>
|
||||
end
|
||||
|
||||
defp do_encode16(_, <<>>), do: <<>>
|
||||
@@ -525,213 +636,219 @@ defmodule Base do
|
||||
end
|
||||
end
|
||||
|
||||
defp do_encode64(<<>>), do: <<>>
|
||||
defp do_encode64(data) do
|
||||
defp do_encode64(<<>>, _), do: <<>>
|
||||
defp do_encode64(data, pad_flag) do
|
||||
split = 3 * div(byte_size(data), 3)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::6 <- main>>, into: <<>>, do: <<enc64(c)::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::6, c2::6, c3::4>> ->
|
||||
<<main::binary, enc64(c1)::8, enc64(c2)::8, enc64(bsl(c3, 2))::8, ?=>>
|
||||
<<enc64(c1)::8, enc64(c2)::8, enc64(bsl(c3, 2))::8>>
|
||||
<<c1::6, c2::2>> ->
|
||||
<<main::binary, enc64(c1)::8, enc64(bsl(c2, 4))::8, ?=, ?=>>
|
||||
<<enc64(c1)::8, enc64(bsl(c2, 4))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 4, "=")
|
||||
end
|
||||
|
||||
defp do_decode64(<<>>), do: <<>>
|
||||
defp do_decode64(string) do
|
||||
defp do_decode64(<<>>, _), do: <<>>
|
||||
defp do_decode64(string, false) do
|
||||
maybe_pad(string, true, 4, "=") |> do_decode64(true)
|
||||
end
|
||||
defp do_decode64(string, _pad_flag) when rem(byte_size(string), 4) == 0 do
|
||||
split = byte_size(string) - 4
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec64(c)::6>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=>> ->
|
||||
<<main::binary, dec64(c1)::6, bsr(dec64(c2), 4)::2>>
|
||||
<<dec64(c1)::6, bsr(dec64(c2), 4)::2>>
|
||||
<<c1::8, c2::8, c3::8, ?=>> ->
|
||||
<<main::binary, dec64(c1)::6, dec64(c2)::6, bsr(dec64(c3), 2)::4>>
|
||||
<<dec64(c1)::6, dec64(c2)::6, bsr(dec64(c3), 2)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8>> ->
|
||||
<<main::binary, dec64(c1)::6, dec64(c2)::6, dec64(c3)::6, dec64(c4)::6>>
|
||||
<<dec64(c1)::6, dec64(c2)::6, dec64(c3)::6, dec64(c4)::6>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
defp do_decode64(_, _) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
defp do_encode64url(<<>>), do: <<>>
|
||||
defp do_encode64url(data) do
|
||||
defp do_encode64url(<<>>, _), do: <<>>
|
||||
defp do_encode64url(data, pad_flag) do
|
||||
split = 3 * div(byte_size(data), 3)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::6 <- main>>, into: <<>>, do: <<enc64url(c)::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::6, c2::6, c3::4>> ->
|
||||
<<main::binary, enc64url(c1)::8, enc64url(c2)::8, enc64url(bsl(c3, 2))::8, ?=>>
|
||||
<<enc64url(c1)::8, enc64url(c2)::8, enc64url(bsl(c3, 2))::8>>
|
||||
<<c1::6, c2::2>> ->
|
||||
<<main::binary, enc64url(c1)::8, enc64url(bsl(c2, 4))::8, ?=, ?=>>
|
||||
<<enc64url(c1)::8, enc64url(bsl(c2, 4))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 4, "=")
|
||||
end
|
||||
|
||||
defp do_decode64url(<<>>), do: <<>>
|
||||
defp do_decode64url(string) do
|
||||
defp do_decode64url(<<>>, _), do: <<>>
|
||||
defp do_decode64url(string, false) do
|
||||
maybe_pad(string, true, 4, "=") |> do_decode64url(true)
|
||||
end
|
||||
defp do_decode64url(string, _pad_flag) when rem(byte_size(string), 4) == 0 do
|
||||
split = byte_size(string) - 4
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec64url(c)::6>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=>> ->
|
||||
<<main::binary, dec64url(c1)::6, bsr(dec64url(c2), 4)::2>>
|
||||
<<dec64url(c1)::6, bsr(dec64url(c2), 4)::2>>
|
||||
<<c1::8, c2::8, c3::8, ?=>> ->
|
||||
<<main::binary, dec64url(c1)::6, dec64url(c2)::6, bsr(dec64url(c3), 2)::4>>
|
||||
<<dec64url(c1)::6, dec64url(c2)::6, bsr(dec64url(c3), 2)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8>> ->
|
||||
<<main::binary, dec64url(c1)::6, dec64url(c2)::6, dec64url(c3)::6, dec64url(c4)::6>>
|
||||
<<dec64url(c1)::6, dec64url(c2)::6, dec64url(c3)::6, dec64url(c4)::6>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
defp do_decode64url(_, _) do
|
||||
raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
|
||||
|
||||
defp do_encode32(_, <<>>), do: <<>>
|
||||
defp do_encode32(_, <<>>, _), do: <<>>
|
||||
|
||||
for {case, fun} <- [upper: :to_upper, lower: :to_lower] do
|
||||
defp do_encode32(unquote(case), data) do
|
||||
defp do_encode32(unquote(case), data, pad_flag) do
|
||||
split = 5 * div(byte_size(data), 5)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::5 <- main>>, into: <<>>, do: <<unquote(fun)(enc32(c))::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::5, c6::5, c7::2>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(c4))::8,
|
||||
unquote(fun)(enc32(c5))::8, unquote(fun)(enc32(c6))::8,
|
||||
unquote(fun)(enc32(bsl(c7, 3)))::8, ?=>>
|
||||
unquote(fun)(enc32(bsl(c7, 3)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::4>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(c4))::8,
|
||||
unquote(fun)(enc32(bsl(c5, 1)))::8, ?=, ?=, ?=>>
|
||||
unquote(fun)(enc32(bsl(c5, 1)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::1>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(bsl(c4, 4)))::8,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(c2))::8,
|
||||
unquote(fun)(enc32(c3))::8, unquote(fun)(enc32(bsl(c4, 4)))::8>>
|
||||
<<c1::5, c2::3>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(bsl(c2, 2)))::8, ?=, ?=,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32(c1))::8, unquote(fun)(enc32(bsl(c2, 2)))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 8, "=")
|
||||
end
|
||||
end
|
||||
|
||||
defp do_decode32(_, <<>>), do: <<>>
|
||||
defp do_decode32(_, <<>>, _), do: <<>>
|
||||
defp do_decode32(case, string, false),
|
||||
do: do_decode32(case, maybe_pad(string, true, 8, "="), true)
|
||||
|
||||
for {case, fun} <- [upper: :from_upper, lower: :from_lower, mixed: :from_mixed] do
|
||||
defp do_decode32(unquote(case), string) do
|
||||
defp do_decode32(unquote(case), string, _pad_flag) when rem(byte_size(string), 8) == 0 do
|
||||
split = byte_size(string) - 8
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec32(unquote(fun)(c))::5>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary, dec32(unquote(fun)(c1))::5,
|
||||
bsr(dec32(unquote(fun)(c2)), 2)::3>>
|
||||
<<dec32(unquote(fun)(c1))::5, bsr(dec32(unquote(fun)(c2)), 2)::3>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, bsr(dec32(unquote(fun)(c4)), 4)::1>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
bsr(dec32(unquote(fun)(c5)), 1)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
dec32(unquote(fun)(c5))::5, dec32(unquote(fun)(c6))::5,
|
||||
bsr(dec32(unquote(fun)(c7)), 3)::2>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->
|
||||
<<main::binary,
|
||||
dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
<<dec32(unquote(fun)(c1))::5, dec32(unquote(fun)(c2))::5,
|
||||
dec32(unquote(fun)(c3))::5, dec32(unquote(fun)(c4))::5,
|
||||
dec32(unquote(fun)(c5))::5, dec32(unquote(fun)(c6))::5,
|
||||
dec32(unquote(fun)(c7))::5, dec32(unquote(fun)(c8))::5>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_encode32(_, <<>>), do: <<>>
|
||||
defp do_decode32(_, _, _),
|
||||
do: raise ArgumentError, "incorrect padding"
|
||||
|
||||
defp do_hex_encode32(_, <<>>, _), do: <<>>
|
||||
|
||||
for {case, fun} <- [upper: :to_upper, lower: :to_lower] do
|
||||
defp do_hex_encode32(unquote(case), data) do
|
||||
defp do_hex_encode32(unquote(case), data, pad_flag) do
|
||||
split = 5 * div(byte_size(data), 5)
|
||||
<<main::size(split)-binary, rest::binary>> = data
|
||||
main = for <<c::5 <- main>>, into: <<>>, do: <<unquote(fun)(enc32hex(c))::8>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::5, c6::5, c7::2>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(c4))::8,
|
||||
unquote(fun)(enc32hex(c5))::8, unquote(fun)(enc32hex(c6))::8,
|
||||
unquote(fun)(enc32hex(bsl(c7, 3)))::8, ?=>>
|
||||
unquote(fun)(enc32hex(bsl(c7, 3)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::5, c5::4>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(c4))::8,
|
||||
unquote(fun)(enc32hex(bsl(c5, 1)))::8, ?=, ?=, ?=>>
|
||||
unquote(fun)(enc32hex(bsl(c5, 1)))::8>>
|
||||
<<c1::5, c2::5, c3::5, c4::1>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(bsl(c4, 4)))::8,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(c2))::8,
|
||||
unquote(fun)(enc32hex(c3))::8, unquote(fun)(enc32hex(bsl(c4, 4)))::8>>
|
||||
<<c1::5, c2::3>> ->
|
||||
<<main::binary,
|
||||
unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(bsl(c2, 2)))::8, ?=, ?=,
|
||||
?=, ?=, ?=, ?=>>
|
||||
<<unquote(fun)(enc32hex(c1))::8, unquote(fun)(enc32hex(bsl(c2, 2)))::8>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> maybe_pad(tail, pad_flag, 8, "=")
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_decode32(_, <<>>), do: <<>>
|
||||
defp do_hex_decode32(_, <<>>, _), do: <<>>
|
||||
defp do_hex_decode32(case, string, false),
|
||||
do: do_hex_decode32(case, maybe_pad(string, true, 8, "="), true)
|
||||
|
||||
for {case, fun} <- [upper: :from_upper, lower: :from_lower, mixed: :from_mixed] do
|
||||
defp do_hex_decode32(unquote(case), string) do
|
||||
defp do_hex_decode32(unquote(case), string, _pad_flag) when rem(byte_size(string), 8) == 0 do
|
||||
split = byte_size(string) - 8
|
||||
<<main::size(split)-binary, rest::binary>> = string
|
||||
main = for <<c::8 <- main>>, into: <<>>, do: <<dec32hex(unquote(fun)(c))::5>>
|
||||
case rest do
|
||||
tail = case rest do
|
||||
<<c1::8, c2::8, ?=, ?=, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary, dec32hex(unquote(fun)(c1))::5,
|
||||
bsr(dec32hex(unquote(fun)(c2)), 2)::3>>
|
||||
<<dec32hex(unquote(fun)(c1))::5, bsr(dec32hex(unquote(fun)(c2)), 2)::3>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, ?=, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, bsr(dec32hex(unquote(fun)(c4)), 4)::1>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, ?=, ?=, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
bsr(dec32hex(unquote(fun)(c5)), 1)::4>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, ?=>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
dec32hex(unquote(fun)(c5))::5, dec32hex(unquote(fun)(c6))::5,
|
||||
bsr(dec32hex(unquote(fun)(c7)), 3)::2>>
|
||||
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8>> ->
|
||||
<<main::binary,
|
||||
dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
<<dec32hex(unquote(fun)(c1))::5, dec32hex(unquote(fun)(c2))::5,
|
||||
dec32hex(unquote(fun)(c3))::5, dec32hex(unquote(fun)(c4))::5,
|
||||
dec32hex(unquote(fun)(c5))::5, dec32hex(unquote(fun)(c6))::5,
|
||||
dec32hex(unquote(fun)(c7))::5, dec32hex(unquote(fun)(c8))::5>>
|
||||
<<>> ->
|
||||
main
|
||||
<<>>
|
||||
end
|
||||
main <> tail
|
||||
end
|
||||
end
|
||||
|
||||
defp do_hex_decode32(_, _, _),
|
||||
do: raise ArgumentError, "incorrect padding"
|
||||
end
|
||||
|
||||
@@ -661,7 +661,7 @@ defmodule String do
|
||||
replace_trailing(string, match, replacement, prefix_size, suffix_size, "")
|
||||
end
|
||||
|
||||
defp replace_trailing(string, match, replacement, prefix_size, suffix_size, acc) when prefix_size > 0 do
|
||||
defp replace_trailing(string, match, replacement, prefix_size, suffix_size, acc) when prefix_size >= 0 do
|
||||
case string do
|
||||
<<prefix::size(prefix_size)-binary, suffix::size(suffix_size)-binary>> when suffix == match ->
|
||||
replace_trailing(prefix, match, replacement, prefix_size - suffix_size, suffix_size, acc <> replacement)
|
||||
|
||||
@@ -100,8 +100,8 @@ Built-in type | Defined as
|
||||
`list()` | `[any()]`
|
||||
`maybe_improper_list()` | `maybe_improper_list(any(), any())`
|
||||
`nonempty_list()` | `nonempty_list(any())`
|
||||
`iolist()` | `maybe_improper_list(byte() \| binary() \| iolist(), binary() \| [])`
|
||||
`iodata()` | `iolist()` \| `binary()`
|
||||
`iolist()` | `maybe_improper_list(byte()` \| `binary()` \| `iolist(), binary()` \| `[])`
|
||||
`module()` | `atom()` \| `tuple()`
|
||||
`arity()` | `0..255`
|
||||
`mfa()` | `{atom(), atom(), arity()}`
|
||||
|
||||
@@ -78,9 +78,8 @@ code_loading_compilation(Forms, Vars, #{line := Line} = E) ->
|
||||
|
||||
%% Pass {native, false} to speed up bootstrap
|
||||
%% process when native is set to true
|
||||
AllOpts = options(),
|
||||
FinalOpts = AllOpts -- [native, warn_missing_spec],
|
||||
inner_module(Form, FinalOpts, true, E, fun(_, Binary) ->
|
||||
ErlOpts = options() -- [native, warn_missing_spec],
|
||||
inner_module(Form, ErlOpts, [{bootstrap, true}], E, fun(_, Binary) ->
|
||||
%% If we have labeled locals, anonymous functions
|
||||
%% were created and therefore we cannot ditch the
|
||||
%% module
|
||||
@@ -169,22 +168,32 @@ allows_fast_compilation(_) -> false.
|
||||
%% executes the callback in case of success. This automatically
|
||||
%% handles errors and warnings. Used by this module and elixir_module.
|
||||
module(Forms, Opts, E, Callback) ->
|
||||
Final =
|
||||
case (get_opt(debug_info) == true) orelse
|
||||
lists:member(debug_info, Opts) of
|
||||
true -> [debug_info] ++ options();
|
||||
false -> options()
|
||||
ErlOpts =
|
||||
case proplists:get_value(debug_info, Opts) of
|
||||
true -> [debug_info];
|
||||
false -> [];
|
||||
undefined ->
|
||||
case get_opt(debug_info) of
|
||||
true -> [debug_info];
|
||||
false -> []
|
||||
end
|
||||
end,
|
||||
inner_module(Forms, Final, false, E, Callback).
|
||||
inner_module(Forms, ErlOpts ++ options(), Opts, E, Callback).
|
||||
|
||||
inner_module(Forms, Options, Bootstrap, #{file := File} = E, Callback) when
|
||||
is_list(Forms), is_list(Options), is_boolean(Bootstrap), is_function(Callback) ->
|
||||
inner_module(Forms, ErlOpts, ExOpts, #{file := File} = E, Callback) when
|
||||
is_list(Forms), is_list(ErlOpts), is_list(ExOpts), is_function(Callback) ->
|
||||
Source = elixir_utils:characters_to_list(File),
|
||||
Autoload = proplists:get_value(autoload, ExOpts, true),
|
||||
Bootstrap = proplists:get_value(bootstrap, ExOpts, false),
|
||||
|
||||
case compile:noenv_forms([no_auto_import()|Forms], [return, {source, Source}|Options]) of
|
||||
case compile:noenv_forms([no_auto_import()|Forms], [return, {source, Source}|ErlOpts]) of
|
||||
{ok, Module, Binary, Warnings} ->
|
||||
format_warnings(Bootstrap, Warnings),
|
||||
{module, Module} = code:load_binary(Module, beam_location(E), Binary),
|
||||
{module, Module} =
|
||||
case Autoload of
|
||||
true -> code:load_binary(Module, beam_location(E), Binary);
|
||||
false -> {module, Module}
|
||||
end,
|
||||
Callback(Module, Binary);
|
||||
{error, Errors, Warnings} ->
|
||||
format_warnings(Bootstrap, Warnings),
|
||||
|
||||
@@ -331,7 +331,7 @@ spec_for_macro(Else) -> Else.
|
||||
|
||||
compile_opts(Module) ->
|
||||
case ets:lookup(data_table(Module), compile) of
|
||||
[{compile, Opts}] when is_list(Opts) -> Opts;
|
||||
[{compile, Opts}] when is_list(Opts) -> lists:flatten(Opts);
|
||||
[] -> []
|
||||
end.
|
||||
|
||||
|
||||
@@ -93,6 +93,18 @@ defmodule BaseTest do
|
||||
assert "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" == encode64(<<"0123456789!@#0^&*();:<>,. []{}">>)
|
||||
end
|
||||
|
||||
test "encode64 omit padding one pad" do
|
||||
assert "SGVsbG8gV29ybGQ" == encode64("Hello World", padding: false)
|
||||
end
|
||||
|
||||
test "encode64 omit padding two pads" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2FtZQ" == encode64("Aladdin:open sesame", padding: false)
|
||||
end
|
||||
|
||||
test "encode64 omit padding no pad" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2Ft" == encode64("Aladdin:open sesam", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 empty" do
|
||||
assert {:ok, ""} == decode64("")
|
||||
end
|
||||
@@ -135,6 +147,18 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode64 whitespace" do
|
||||
assert :error == decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
assert {:ok, "Aladdin:open sesam"} == decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "decode64! whitespace" do
|
||||
assert_raise ArgumentError, "non-alphabet digit found: \"\\n\" (byte 10)", fn ->
|
||||
decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
end
|
||||
assert "Aladdin:open sesam" == decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "decode64 incorrect padding" do
|
||||
assert :error == decode64("SGVsbG8gV29ybGQ")
|
||||
end
|
||||
@@ -145,6 +169,38 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode64 ignore padding two pads" do
|
||||
assert {:ok, "Aladdin:open sesame"} == decode64("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding two pads" do
|
||||
assert "Aladdin:open sesame" == decode64!("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding one pad" do
|
||||
assert {:ok, "Hello World"} == decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding one pad" do
|
||||
assert "Hello World" == decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding no pad" do
|
||||
assert {:ok, "Aladdin:open sesam"} == decode64("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding no pad" do
|
||||
assert "Aladdin:open sesam" == decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "decode64 ignore padding incorrect padding" do
|
||||
assert {:ok, "Hello World"} == decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode64! ignore padding incorrect padding" do
|
||||
assert "Hello World" == decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 empty" do
|
||||
assert "" == url_encode64("")
|
||||
end
|
||||
@@ -162,6 +218,18 @@ defmodule BaseTest do
|
||||
assert "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" == url_encode64(<<"0123456789!@#0^&*();:<>,. []{}">>)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding two pads" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2FtZQ" == url_encode64("Aladdin:open sesame", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding one pad" do
|
||||
assert "SGVsbG8gV29ybGQ" == url_encode64("Hello World", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 omit padding no pad" do
|
||||
assert "QWxhZGRpbjpvcGVuIHNlc2Ft" == url_encode64("Aladdin:open sesam", padding: false)
|
||||
end
|
||||
|
||||
test "url_encode64 no URL unsafe characters" do
|
||||
refute "/3/+/A==" == url_encode64(<<255, 127, 254, 252>>)
|
||||
assert "_3_-_A==" == url_encode64(<<255, 127, 254, 252>>)
|
||||
@@ -199,6 +267,18 @@ defmodule BaseTest do
|
||||
assert "Aladdin:open sesam" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft")
|
||||
end
|
||||
|
||||
test "url_decode64 whitespace" do
|
||||
assert :error == url_decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
assert {:ok, "Aladdin:open sesam"} == url_decode64("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "url_decode64! whitespace" do
|
||||
assert_raise ArgumentError, "non-alphabet digit found: \"\\n\" (byte 10)", fn ->
|
||||
url_decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t")
|
||||
end
|
||||
assert "Aladdin:open sesam" == url_decode64!("\nQWxhZGRp bjpvcGVu\sIHNlc2Ft\t", ignore: :whitespace)
|
||||
end
|
||||
|
||||
test "url_decode64 non-alphabet digit" do
|
||||
assert :error == url_decode64("Zm9)")
|
||||
end
|
||||
@@ -219,6 +299,38 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding two pads" do
|
||||
assert {:ok, "Aladdin:open sesame"} == url_decode64("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding two pads" do
|
||||
assert "Aladdin:open sesame" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2FtZQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding one pad" do
|
||||
assert {:ok, "Hello World"} == url_decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding one pad" do
|
||||
assert "Hello World" == url_decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding no pad" do
|
||||
assert {:ok, "Aladdin:open sesam"} == url_decode64("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding no pad" do
|
||||
assert "Aladdin:open sesam" == url_decode64!("QWxhZGRpbjpvcGVuIHNlc2Ft", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64 ignore padding incorrect padding" do
|
||||
assert {:ok, "Hello World"} == url_decode64("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "url_decode64! ignore padding incorrect padding" do
|
||||
assert "Hello World" == url_decode64!("SGVsbG8gV29ybGQ", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 empty" do
|
||||
assert "" == encode32("")
|
||||
end
|
||||
@@ -244,6 +356,26 @@ defmodule BaseTest do
|
||||
assert "MZXW6YTB" == encode32("fooba")
|
||||
end
|
||||
|
||||
test "encode32 omit padding one pad" do
|
||||
assert "MZXW6YQ" == encode32("foob", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding three pads" do
|
||||
assert "MZXW6" == encode32("foo", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding four pads" do
|
||||
assert "MZXQ" == encode32("fo", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding six pads" do
|
||||
assert "MZXW6YTBOI" == encode32("foobar", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 omit padding no pads" do
|
||||
assert "MZXW6YTB" == encode32("fooba", padding: false)
|
||||
end
|
||||
|
||||
test "encode32 lowercase" do
|
||||
assert "mzxw6ytb" == encode32("fooba", case: :lower)
|
||||
end
|
||||
@@ -342,6 +474,70 @@ defmodule BaseTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "decode32 ignore padding one pad" do
|
||||
assert {:ok, "foob"} == decode32("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding one pad" do
|
||||
assert "foob" == decode32!("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding three pads" do
|
||||
assert {:ok, "foo"} == decode32("MZXW6", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding three pads" do
|
||||
assert "foo" == decode32!("MZXW6", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding four pads" do
|
||||
assert {:ok, "fo"} == decode32("MZXQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding four pads" do
|
||||
assert "fo" == decode32!("MZXQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding lowercase" do
|
||||
assert {:ok, "fo"} == decode32("mzxq", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding lowercase" do
|
||||
assert "fo" == decode32!("mzxq", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding mixed case" do
|
||||
assert {:ok, "fo"} == decode32("mZXq", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding mixed case" do
|
||||
assert "fo" == decode32!("mZXq", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding six pads" do
|
||||
assert {:ok, "foobar"} == decode32("MZXW6YTBOI", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding six pads" do
|
||||
assert "foobar" == decode32!("MZXW6YTBOI", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding no pads" do
|
||||
assert {:ok, "fooba"} == decode32("MZXW6YTB", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding no pads" do
|
||||
assert "fooba" == decode32!("MZXW6YTB", padding: false)
|
||||
end
|
||||
|
||||
test "decode32 ignore padding incorrect padding" do
|
||||
assert {:ok, "foob"} == decode32("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "decode32! ignore padding incorrect padding" do
|
||||
"foob" = decode32!("MZXW6YQ", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 empty" do
|
||||
assert "" == hex_encode32("")
|
||||
end
|
||||
@@ -367,6 +563,26 @@ defmodule BaseTest do
|
||||
assert "CPNMUOJ1" == hex_encode32("fooba")
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding one pad" do
|
||||
assert "CPNMUOG" == hex_encode32("foob", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding three pads" do
|
||||
assert "CPNMU" == hex_encode32("foo", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding four pads" do
|
||||
assert "CPNG" == hex_encode32("fo", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding six pads" do
|
||||
assert "CPNMUOJ1E8" == hex_encode32("foobar", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 omit padding no pads" do
|
||||
assert "CPNMUOJ1" == hex_encode32("fooba", padding: false)
|
||||
end
|
||||
|
||||
test "hex_encode32 lowercase" do
|
||||
assert "cpnmuoj1" == hex_encode32("fooba", case: :lower)
|
||||
end
|
||||
@@ -470,4 +686,68 @@ defmodule BaseTest do
|
||||
decode16!("012" <> <<0>>)
|
||||
end
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding one pad" do
|
||||
assert {:ok, "foob"} == hex_decode32("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding one pad" do
|
||||
assert "foob" == hex_decode32!("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding three pads" do
|
||||
assert {:ok, "foo"} == hex_decode32("CPNMU", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding three pads" do
|
||||
assert "foo" == hex_decode32!("CPNMU", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding four pads" do
|
||||
assert {:ok, "fo"} == hex_decode32("CPNG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding four pads" do
|
||||
assert "fo" == hex_decode32!("CPNG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding six pads" do
|
||||
assert {:ok, "foobar"} == hex_decode32("CPNMUOJ1E8", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding six pads" do
|
||||
assert "foobar" == hex_decode32!("CPNMUOJ1E8", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding no pads" do
|
||||
assert {:ok, "fooba"} == hex_decode32("CPNMUOJ1", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding no pads" do
|
||||
assert "fooba" == hex_decode32!("CPNMUOJ1", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding incorrect padding" do
|
||||
assert {:ok, "foob"} == hex_decode32("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding incorrect padding" do
|
||||
"foob" = hex_decode32!("CPNMUOG", padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignoring padding lowercase" do
|
||||
assert {:ok, "fo"} == hex_decode32("cpng", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding lowercase" do
|
||||
assert "fo" == hex_decode32!("cpng", case: :lower, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32 ignore padding mixed case" do
|
||||
assert {:ok, "fo"} == hex_decode32("cPNg====", case: :mixed, padding: false)
|
||||
end
|
||||
|
||||
test "hex_decode32! ignore padding mixed case" do
|
||||
assert "fo" == hex_decode32!("cPNg", case: :mixed, padding: false)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,6 +144,13 @@ defmodule ModuleTest do
|
||||
assert [3, 2, 1] = @other_attribute
|
||||
end
|
||||
|
||||
test "@compile autoload attribute" do
|
||||
defmodule NoAutoload do
|
||||
@compile {:autoload, false}
|
||||
end
|
||||
refute :code.is_loaded(NoAutoload)
|
||||
end
|
||||
|
||||
## Naming
|
||||
|
||||
test "concat" do
|
||||
|
||||
@@ -160,6 +160,17 @@ defmodule StringTest do
|
||||
assert String.capitalize("fin") == "Fin"
|
||||
end
|
||||
|
||||
test "replace_trailing" do
|
||||
assert String.replace_trailing(" abc aa", "a", "") == " abc "
|
||||
assert String.replace_trailing(" abc __", "_", "") == " abc "
|
||||
assert String.replace_trailing(" aaaaaaaaa", "a", "") == " "
|
||||
assert String.replace_trailing("aaaaaaaaaa", "a", "") == ""
|
||||
assert String.replace_trailing("]]]]]]]]]]", "]", "") == ""
|
||||
assert String.replace_trailing(" cat 猫猫", "猫", "") == " cat "
|
||||
assert String.replace_trailing("test", "t", "") == "tes"
|
||||
assert String.replace_trailing("t", "t", "") == ""
|
||||
end
|
||||
|
||||
test "rstrip" do
|
||||
assert String.rstrip("") == ""
|
||||
assert String.rstrip("1\n") == "1"
|
||||
@@ -172,6 +183,9 @@ defmodule StringTest do
|
||||
assert String.rstrip("a abc a" <> <<194, 133>>) == "a abc a"
|
||||
assert String.rstrip(" abc aa", ?a) == " abc "
|
||||
assert String.rstrip(" abc __", ?_) == " abc "
|
||||
assert String.rstrip(" aaaaaaaaa", ?a) == " "
|
||||
assert String.rstrip("aaaaaaaaaa", ?a) == ""
|
||||
assert String.rstrip("]]]]]]]]]]", ?]) == ""
|
||||
assert String.rstrip(" cat 猫猫", ?猫) == " cat "
|
||||
end
|
||||
|
||||
|
||||
@@ -103,12 +103,13 @@ defmodule ExUnit.Assertions do
|
||||
# to avoid silly warnings though.
|
||||
return =
|
||||
no_warning(quote do
|
||||
if right do
|
||||
right
|
||||
else
|
||||
raise ExUnit.AssertionError,
|
||||
expr: expr,
|
||||
message: "Expected truthy, got #{inspect right}"
|
||||
case right do
|
||||
x when x in [nil, false] ->
|
||||
raise ExUnit.AssertionError,
|
||||
expr: expr,
|
||||
message: "Expected truthy, got #{inspect right}"
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -416,8 +417,11 @@ defmodule ExUnit.Assertions do
|
||||
|> elem(1)
|
||||
end
|
||||
|
||||
defp no_warning({name, meta, args}) do
|
||||
{name, [line: -1] ++ meta, args}
|
||||
defp no_warning({name, meta, [expr, [do: clauses]]}) do
|
||||
clauses = Enum.map clauses, fn {:->, meta, args} ->
|
||||
{:->, [generated: true] ++ Keyword.put(meta, :line, -1), args}
|
||||
end
|
||||
{name, meta, [expr, [do: clauses]]}
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
@@ -146,6 +146,8 @@ defmodule ExUnit.Callbacks do
|
||||
|
||||
## Helpers
|
||||
|
||||
@reserved ~w(case test line file)a
|
||||
|
||||
@doc false
|
||||
def __merge__(_mod, context, :ok) do
|
||||
{:ok, context}
|
||||
@@ -163,12 +165,16 @@ defmodule ExUnit.Callbacks do
|
||||
raise_merge_failed!(mod, data)
|
||||
end
|
||||
|
||||
defp context_merge(_mod, context, %{} = data) do
|
||||
Map.merge(context, data)
|
||||
defp context_merge(mod, context, %{} = data) do
|
||||
Map.merge(context, data, fn
|
||||
_, v, v -> v
|
||||
k, _, v when k in @reserved -> raise_merge_reserved!(mod, k, v)
|
||||
_, _, v -> v
|
||||
end)
|
||||
end
|
||||
|
||||
defp context_merge(_mod, context, data) when is_list(data) do
|
||||
Enum.into(data, context)
|
||||
defp context_merge(mod, context, data) when is_list(data) do
|
||||
context_merge(mod, context, Map.new(data))
|
||||
end
|
||||
|
||||
defp context_merge(mod, _context, data) do
|
||||
@@ -177,7 +183,12 @@ defmodule ExUnit.Callbacks do
|
||||
|
||||
defp raise_merge_failed!(mod, data) do
|
||||
raise "expected ExUnit callback in #{inspect mod} to return :ok " <>
|
||||
" or {:ok, keyword | map}, got #{inspect data} instead"
|
||||
"or {:ok, keyword | map}, got #{inspect data} instead"
|
||||
end
|
||||
|
||||
defp raise_merge_reserved!(mod, key, value) do
|
||||
raise "expected ExUnit callback in #{inspect mod} is trying to set " <>
|
||||
"reserved field #{inspect key} to #{inspect value}"
|
||||
end
|
||||
|
||||
defp escape(contents) do
|
||||
|
||||
@@ -114,10 +114,11 @@ defmodule ExUnit.Case do
|
||||
The following tags are set automatically by ExUnit and are
|
||||
therefore reserved:
|
||||
|
||||
* `:case` - the test case module
|
||||
* `:test` - the test name
|
||||
* `:line` - the line on which the test was defined
|
||||
* `:file` - the file on which the test was defined
|
||||
* `:case` - the test case module
|
||||
* `:test` - the test name
|
||||
* `:line` - the line on which the test was defined
|
||||
* `:file` - the file on which the test was defined
|
||||
* `:async` - if the test case is in async mode
|
||||
|
||||
The following tags customize how tests behaves:
|
||||
|
||||
@@ -174,7 +175,7 @@ defmodule ExUnit.Case do
|
||||
|
||||
This default can be overriden by `@tag capture_log: false` or `@moduletag capture_log: false`.
|
||||
|
||||
Since `setup_all` blocks don't belong to a specific test, log messages generated in them (or
|
||||
Since `setup_all` blocks don't belong to a specific test, log messages generated in them (or
|
||||
between tests) are never captured. If you want to suppress these messages as well, remove the
|
||||
console backend globally:
|
||||
|
||||
@@ -193,20 +194,16 @@ defmodule ExUnit.Case do
|
||||
end
|
||||
|
||||
quote do
|
||||
async = !!unquote(async)
|
||||
|
||||
unless Module.get_attribute(__MODULE__, :ex_unit_tests) do
|
||||
Enum.each [:ex_unit_tests, :tag, :moduletag],
|
||||
&Module.register_attribute(__MODULE__, &1, accumulate: true)
|
||||
|
||||
if unquote(async) do
|
||||
@moduletag async: true
|
||||
ExUnit.Server.add_async_case(__MODULE__)
|
||||
else
|
||||
@moduletag async: false
|
||||
ExUnit.Server.add_sync_case(__MODULE__)
|
||||
end
|
||||
|
||||
@moduletag async: async
|
||||
@before_compile ExUnit.Case
|
||||
@ex_unit_test_names %{}
|
||||
@ex_unit_async async
|
||||
use ExUnit.Callbacks
|
||||
end
|
||||
|
||||
@@ -254,7 +251,7 @@ defmodule ExUnit.Case do
|
||||
|
||||
quote bind_quoted: binding do
|
||||
test = :"test #{message}"
|
||||
ExUnit.Case.__on_definition__(__ENV__, test)
|
||||
ExUnit.Case.__on_definition__(__ENV__, test, [])
|
||||
def unquote(test)(unquote(var)), do: unquote(contents)
|
||||
end
|
||||
end
|
||||
@@ -284,6 +281,12 @@ defmodule ExUnit.Case do
|
||||
@doc false
|
||||
defmacro __before_compile__(_) do
|
||||
quote do
|
||||
if @ex_unit_async do
|
||||
ExUnit.Server.add_async_case(__MODULE__)
|
||||
else
|
||||
ExUnit.Server.add_sync_case(__MODULE__)
|
||||
end
|
||||
|
||||
def __ex_unit__(:case) do
|
||||
%ExUnit.TestCase{name: __MODULE__, tests: @ex_unit_tests}
|
||||
end
|
||||
@@ -291,8 +294,7 @@ defmodule ExUnit.Case do
|
||||
end
|
||||
|
||||
@doc false
|
||||
def __on_definition__(env, name, tags \\ []) do
|
||||
mod = env.module
|
||||
def __on_definition__(%{module: mod, file: file, line: line}, name, tags) do
|
||||
moduletag = Module.get_attribute(mod, :moduletag)
|
||||
|
||||
unless moduletag do
|
||||
@@ -304,7 +306,7 @@ defmodule ExUnit.Case do
|
||||
(tags ++ Module.get_attribute(mod, :tag) ++ moduletag)
|
||||
|> normalize_tags
|
||||
|> validate_tags
|
||||
|> Map.merge(%{line: env.line, file: env.file})
|
||||
|> Map.merge(%{line: line, file: file})
|
||||
|
||||
test = %ExUnit.Test{name: name, case: mod, tags: tags}
|
||||
test_names = Module.get_attribute(mod, :ex_unit_test_names)
|
||||
|
||||
@@ -152,7 +152,7 @@ defmodule ExUnitTest do
|
||||
refute output =~ "[debug] four"
|
||||
end
|
||||
|
||||
test "it supports multi errors" do
|
||||
test "supports multi errors" do
|
||||
capture_io :stderr, fn ->
|
||||
defmodule MultiTest do
|
||||
use ExUnit.Case
|
||||
@@ -187,7 +187,7 @@ defmodule ExUnitTest do
|
||||
assert output =~ "Failure #2"
|
||||
end
|
||||
|
||||
test "it registers only the first test with any given name" do
|
||||
test "registers only the first test with any given name" do
|
||||
capture_io :stderr, fn ->
|
||||
defmodule TestWithSameNames do
|
||||
use ExUnit.Case
|
||||
@@ -207,7 +207,7 @@ defmodule ExUnitTest do
|
||||
end) =~ "1 test, 0 failure"
|
||||
end
|
||||
|
||||
test "it produces error on not implemented tests" do
|
||||
test "produces error on not implemented tests" do
|
||||
defmodule TestNotImplemented do
|
||||
use ExUnit.Case
|
||||
|
||||
@@ -227,7 +227,7 @@ defmodule ExUnitTest do
|
||||
assert output =~ "1 test, 1 failure"
|
||||
end
|
||||
|
||||
test "it skips tagged test with skip" do
|
||||
test "skips tagged test with skip" do
|
||||
defmodule TestSkipped do
|
||||
use ExUnit.Case
|
||||
|
||||
@@ -250,6 +250,55 @@ defmodule ExUnitTest do
|
||||
assert output =~ "2 tests, 0 failures, 2 skipped"
|
||||
end
|
||||
|
||||
test "raises on reserved tag in module" do
|
||||
assert_raise RuntimeError, "cannot set tag :file because it is reserved by ExUnit", fn ->
|
||||
defmodule ReservedTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
@tag file: "oops"
|
||||
test "sample", do: :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "raises on reserved tag in setup" do
|
||||
defmodule ReservedSetupTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
test "sample", do: :ok
|
||||
end
|
||||
|
||||
output = capture_io(fn ->
|
||||
assert ExUnit.run == %{failures: 1, skipped: 0, total: 1}
|
||||
end)
|
||||
|
||||
assert output =~ "trying to set reserved field :file"
|
||||
end
|
||||
|
||||
test "does not raise on reserved tag in setup_all (lower priority)" do
|
||||
defmodule ReservedSetupAllTag do
|
||||
use ExUnit.Case
|
||||
|
||||
setup_all do
|
||||
{:ok, file: :foo}
|
||||
end
|
||||
|
||||
test "sample", do: :ok
|
||||
end
|
||||
|
||||
capture_io(fn ->
|
||||
assert ExUnit.run == %{failures: 0, skipped: 0, total: 1}
|
||||
end)
|
||||
end
|
||||
|
||||
defp run_with_filter(filters, {async, sync, load_us}) do
|
||||
opts = Keyword.merge(ExUnit.configuration, filters)
|
||||
output = capture_io fn ->
|
||||
|
||||
@@ -27,9 +27,9 @@ defmodule IEx.Helpers do
|
||||
* `cd/1` - changes the current directory
|
||||
* `clear/0` - clears the screen
|
||||
* `flush/0` - flushes all messages sent to the shell
|
||||
* `i/1` - prints information about the given data type
|
||||
* `h/0` - prints this help message
|
||||
* `h/1` - prints help for the given module, function or macro
|
||||
* `i/1` - prints information about the given data type
|
||||
* `import_file/1` - evaluates the given file in the shell's context
|
||||
* `l/1` - loads the given module's beam code
|
||||
* `ls/0` - lists the contents of the current directory
|
||||
@@ -42,7 +42,6 @@ defmodule IEx.Helpers do
|
||||
* `t/1` — prints type information
|
||||
* `v/0` — retrieves the last value from the history
|
||||
* `v/1` — retrieves the nth value from the history
|
||||
* `import_file/1` — evaluates the given file in the shell's context
|
||||
|
||||
Help for all of those functions can be consulted directly from
|
||||
the command line using the `h` helper itself. Try:
|
||||
|
||||
@@ -137,29 +137,26 @@ defmodule Mix.Compilers.Elixir do
|
||||
|> List.delete(module)
|
||||
|> Enum.reject(&match?("elixir_" <> _, Atom.to_string(&1)))
|
||||
|
||||
attributes = module.__info__(:attributes)
|
||||
|
||||
kind = detect_kind(attributes)
|
||||
kind = detect_kind(module)
|
||||
source = Path.relative_to(source, cwd)
|
||||
files = get_external_resources(attributes, cwd)
|
||||
files = get_external_resources(module, cwd)
|
||||
tuple = {beam, module, kind, source, compile, runtime, files, binary}
|
||||
Agent.cast pid, &:lists.keystore(beam, 1, &1, tuple)
|
||||
end
|
||||
|
||||
defp detect_kind(attributes) do
|
||||
defp detect_kind(module) do
|
||||
cond do
|
||||
impl = attributes[:impl] ->
|
||||
impl = Module.get_attribute(module, :impl) ->
|
||||
{:impl, impl[:protocol]}
|
||||
attributes[:protocol] ->
|
||||
Module.get_attribute(module, :protocol) ->
|
||||
:protocol
|
||||
true ->
|
||||
:module
|
||||
end
|
||||
end
|
||||
|
||||
defp get_external_resources(attributes, cwd) do
|
||||
for {:external_resource, values} <- attributes,
|
||||
file <- values,
|
||||
defp get_external_resources(module, cwd) do
|
||||
for file <- Module.get_attribute(module, :external_resource),
|
||||
File.regular?(file),
|
||||
relative = Path.relative_to(file, cwd),
|
||||
Path.type(relative) == :relative,
|
||||
|
||||
@@ -92,15 +92,18 @@ defmodule Mix.Dep.Converger do
|
||||
# In case no lock was given, we will use the local lock
|
||||
# which is potentially stale. So remote.deps/2 needs to always
|
||||
# check if the data it finds in the lock is actually valid.
|
||||
all(main, apps, callback, rest, lock, env, fn dep ->
|
||||
if cached = deps[dep.app] do
|
||||
{:loaded, cached}
|
||||
else
|
||||
{:unloaded, dep, remote.deps(dep, lock)}
|
||||
end
|
||||
end)
|
||||
{deps, rest, lock} =
|
||||
all(main, apps, callback, rest, lock, env, fn dep ->
|
||||
if cached = deps[dep.app] do
|
||||
{:loaded, cached}
|
||||
else
|
||||
{:unloaded, dep, remote.deps(dep, lock)}
|
||||
end
|
||||
end)
|
||||
|
||||
{reject_non_fullfilled_optional(deps), rest, lock}
|
||||
else
|
||||
{deps, rest, lock}
|
||||
{reject_non_fullfilled_optional(deps), rest, lock}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -173,12 +176,12 @@ defmodule Mix.Dep.Converger do
|
||||
Mix.Dep.Loader.load(dep, children)
|
||||
end
|
||||
|
||||
dep = %{dep | deps: reject_non_fullfilled_optional(dep.deps, current_breadths)}
|
||||
{acc, rest, lock} =
|
||||
all(t, [dep|acc], upper_breadths, current_breadths, callback, rest, lock, env, cache)
|
||||
|
||||
new_breadths = Enum.map(dep.deps, &(&1.app)) ++ current_breadths
|
||||
all(dep.deps, acc, current_breadths, new_breadths, callback, rest, lock, env, cache)
|
||||
deps = reject_non_fullfilled_optional(dep.deps, current_breadths)
|
||||
new_breadths = Enum.map(deps, &(&1.app)) ++ current_breadths
|
||||
all(deps, acc, current_breadths, new_breadths, callback, rest, lock, env, cache)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -213,7 +216,8 @@ defmodule Mix.Dep.Converger do
|
||||
in_upper? && other_opts[:override] ->
|
||||
{other |> with_matching_only(dep, in_upper?), true}
|
||||
converge?(other, dep) ->
|
||||
{other |> with_matching_only(dep, in_upper?) |> with_matching_req(dep) |> merge_manager(dep), true}
|
||||
{other |> with_matching_only(dep, in_upper?)
|
||||
|> with_matching_req(dep) |> merge_manager(dep, in_upper?), true}
|
||||
true ->
|
||||
tag = if in_upper?, do: :overridden, else: :diverged
|
||||
{%{other | status: {tag, dep}}, true}
|
||||
@@ -276,32 +280,40 @@ defmodule Mix.Dep.Converger do
|
||||
end
|
||||
end
|
||||
|
||||
defp converge?(%Mix.Dep{scm: scm1, manager: manager1, opts: opts1},
|
||||
%Mix.Dep{scm: scm2, manager: manager2, opts: opts2}) do
|
||||
scm1 == scm2 and
|
||||
manager_equal?(manager1, manager2) and
|
||||
opts_equal?(opts1, opts2) and
|
||||
scm1.equal?(opts1, opts2)
|
||||
defp converge?(%Mix.Dep{scm: scm1, opts: opts1}, %Mix.Dep{scm: scm2, opts: opts2}) do
|
||||
scm1 == scm2 and opts_equal?(opts1, opts2) and scm1.equal?(opts1, opts2)
|
||||
end
|
||||
|
||||
defp manager_equal?(manager, manager), do: true
|
||||
defp manager_equal?(_, nil), do: true
|
||||
defp manager_equal?(nil, _), do: true
|
||||
defp manager_equal?(_, _), do: false
|
||||
|
||||
defp opts_equal?(opts1, opts2) do
|
||||
keys = ~w(app env compile)a
|
||||
Enum.all?(keys, &(Keyword.fetch(opts1, &1) == Keyword.fetch(opts2, &1)))
|
||||
end
|
||||
|
||||
defp reject_non_fullfilled_optional(deps) do
|
||||
apps = Enum.map(deps, & &1.app)
|
||||
for dep <- deps do
|
||||
update_in dep.deps, &reject_non_fullfilled_optional(&1, apps)
|
||||
end
|
||||
end
|
||||
|
||||
defp reject_non_fullfilled_optional(children, upper_breadths) do
|
||||
Enum.reject children, fn %Mix.Dep{app: app, opts: opts} ->
|
||||
opts[:optional] && not(app in upper_breadths)
|
||||
end
|
||||
end
|
||||
|
||||
defp merge_manager(other, dep) do
|
||||
%{other | manager: other.manager || dep.manager}
|
||||
defp merge_manager(%{manager: other_manager} = other, %{manager: manager}, in_upper?) do
|
||||
%{other | manager: sort_manager(other_manager, manager, in_upper?)}
|
||||
end
|
||||
|
||||
@managers [:mix, :rebar3, :rebar, :make]
|
||||
|
||||
defp sort_manager(other_manager, manager, true) do
|
||||
other_manager || manager
|
||||
end
|
||||
defp sort_manager(other_manager, manager, false) do
|
||||
priority = @managers -- (@managers -- (List.wrap(other_manager) ++ List.wrap(manager)))
|
||||
List.first(priority) || other_manager || manager
|
||||
end
|
||||
|
||||
defp with_matching_req(%Mix.Dep{} = other, %Mix.Dep{} = dep) do
|
||||
|
||||
@@ -96,9 +96,7 @@ defmodule Mix.Dep.Fetcher do
|
||||
# it for compilation too, this is our best to try to solve the
|
||||
# maximum we can at each deps.get and deps.update.
|
||||
if Enum.all?(all_deps, &available?/1) do
|
||||
deps = (with_depending(deps, all_deps) ++
|
||||
Enum.filter(all_deps, fn dep -> not ok?(dep) end))
|
||||
|> Enum.uniq(&(&1.app))
|
||||
deps = Enum.uniq_by(with_depending(deps, all_deps), &(&1.app))
|
||||
end
|
||||
|
||||
# Merge the new lock on top of the old to guarantee we don't
|
||||
|
||||
@@ -236,6 +236,22 @@ defmodule Mix.Project do
|
||||
Path.expand config[:deps_path]
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the full path of all dependencies as a map.
|
||||
|
||||
## Examples
|
||||
|
||||
Mix.Project.deps_paths
|
||||
#=> %{foo: "deps/foo", bar: "custom/path/dep"}
|
||||
|
||||
"""
|
||||
@spec deps_paths() :: %{atom => Path.t}
|
||||
def deps_paths do
|
||||
Enum.reduce Mix.Dep.loaded(env: Mix.env), %{}, fn
|
||||
%{app: app, opts: opts}, acc -> Map.put acc, app, opts[:dest]
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the build path for this project.
|
||||
|
||||
|
||||
@@ -127,8 +127,8 @@ defmodule Mix.Tasks.Compile do
|
||||
"""
|
||||
def manifests do
|
||||
Enum.flat_map(compilers(), fn(compiler) ->
|
||||
module = Mix.Task.get!("compile.#{compiler}")
|
||||
if function_exported?(module, :manifests, 0) do
|
||||
module = Mix.Task.get("compile.#{compiler}")
|
||||
if module && function_exported?(module, :manifests, 0) do
|
||||
module.manifests
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -25,7 +25,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
"""
|
||||
|
||||
import Mix.Dep, only: [loaded: 1, available?: 1, loaded_by_name: 2,
|
||||
format_dep: 1, make?: 1, mix?: 1, rebar?: 1]
|
||||
format_dep: 1, make?: 1, mix?: 1]
|
||||
|
||||
@spec run(OptionParser.argv) :: :ok
|
||||
def run(args) do
|
||||
@@ -100,6 +100,11 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
"but you are running on v#{System.version}"
|
||||
end
|
||||
|
||||
# Force recompilation on compile status
|
||||
if dep.status == :compile do
|
||||
Mix.Dep.Lock.touch_manifest
|
||||
end
|
||||
|
||||
try do
|
||||
res = Mix.Task.run("compile", ["--no-deps", "--no-elixir-version-check"])
|
||||
:ok in List.wrap(res)
|
||||
|
||||
@@ -53,6 +53,17 @@ defmodule Mix.DepTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "extracts all dependencies paths from the given project" do
|
||||
Mix.Project.push DepsApp
|
||||
|
||||
in_fixture "deps_status", fn ->
|
||||
paths = Mix.Project.deps_paths
|
||||
assert map_size(paths) == 6
|
||||
assert paths[:ok] =~ "deps/ok"
|
||||
assert paths[:uncloned] =~ "deps/uncloned"
|
||||
end
|
||||
end
|
||||
|
||||
test "fails on invalid dependencies" do
|
||||
assert_wrong_dependency [{:ok}]
|
||||
assert_wrong_dependency [{:ok, nil}]
|
||||
@@ -144,7 +155,22 @@ defmodule Mix.DepTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "nested deps convergence with optional dependencies" do
|
||||
test "nested deps with convergence and managers" do
|
||||
Process.put(:custom_deps_git_repo_opts, [manager: :make])
|
||||
|
||||
deps = [{:deps_repo, "0.1.0", path: "custom/deps_repo", manager: :rebar},
|
||||
{:git_repo, "0.2.0", git: MixTest.Case.fixture_path("git_repo")}]
|
||||
|
||||
with_deps deps, fn ->
|
||||
in_fixture "deps_status", fn ->
|
||||
[dep1, dep2] = Mix.Dep.loaded([])
|
||||
assert dep1.manager == nil
|
||||
assert dep2.manager == :rebar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "nested deps with convergence and optional dependencies" do
|
||||
deps = [{:deps_repo, "0.1.0", path: "custom/deps_repo"},
|
||||
{:git_repo, "0.2.0", git: MixTest.Case.fixture_path("git_repo")}]
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ defmodule Mix.Tasks.CompileTest do
|
||||
assert_received {:mix_shell, :info, ["\nEnabled compilers: elixir, app, custom, protocols"]}
|
||||
end
|
||||
|
||||
test "compile does not require all compilers available on manifest" do
|
||||
Mix.Project.push CustomCompilers
|
||||
assert Mix.Tasks.Compile.manifests |> Enum.map(&Path.basename/1) ==
|
||||
[".compile.elixir"]
|
||||
end
|
||||
|
||||
test "compile a project with mixfile" do
|
||||
in_fixture "no_mixfile", fn ->
|
||||
assert Mix.Tasks.Compile.run([]) == :ok
|
||||
|
||||
@@ -146,9 +146,6 @@ defmodule Mix.Tasks.DepsGitTest do
|
||||
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
|
||||
|
||||
# Clear up to prepare for the update
|
||||
File.rm("_build/dev/lib/git_repo/ebin/Elixir.GitRepo.beam")
|
||||
File.rm("_build/dev/lib/git_repo/.compile.elixir")
|
||||
File.rm("deps/git_repo/.fetch")
|
||||
Mix.Task.clear
|
||||
Mix.shell.flush
|
||||
purge [A, B, C, GitRepo]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{application, elixir,
|
||||
[{description, "elixir"},
|
||||
{vsn, "1.2.1"},
|
||||
{vsn, "1.2.3"},
|
||||
{modules, [
|
||||
elixir
|
||||
]},
|
||||
|
||||
Reference in New Issue
Block a user