diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..525446d --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/README.md b/README.md index f697e28..4321e6e 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,102 @@ -# elixir-base58-encode -[![Hex pm](http://img.shields.io/hexpm/v/b58.svg?style=flat)](https://hex.pm/packages/b58) -[![Build Status](https://travis-ci.org/dwyl/base58encode.svg?branch=master)](https://travis-ci.org/dwyl/base58encode) -[![codecov](https://codecov.io/gh/dwyl/base58encode/branch/master/graph/badge.svg)](https://codecov.io/gh/dwyl/base58encode) +
-This module provides the `Base58Encode.encode/1` function which takes an **Elixir binary** and returns its base58 String representation. +# `b58` - _Minimalist_ Elixir Base58 Encoding/Decoding Library + +[![Build Status](https://img.shields.io/travis/dwyl/base58/master.svg?style=flat-square)](https://travis-ci.org/dwyl/base58) +[![codecov.io](https://img.shields.io/codecov/c/github/dwyl/base58/master.svg?style=flat-square)](http://codecov.io/github/dwyl/base58?branch=master) +[![Hex.pm](https://img.shields.io/hexpm/v/base58?color=brightgreen&style=flat-square)](https://hex.pm/packages/base58) +[![Libraries.io dependency status](https://img.shields.io/librariesio/release/hex/base58?logoColor=brightgreen&style=flat-square)](https://libraries.io/hex/base58) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/base58/issues) +[![HitCount](http://hits.dwyl.io/dwyl/base58.svg)](http://hits.dwyl.io/dwyl/base58) + + +![base58-encode-hero-image](https://user-images.githubusercontent.com/194400/80292242-1d2de500-874d-11ea-8514-91a8fdfabfde.jpg) + + +
+ +`Base58` provides two functions to +work with Base58 encoded strings: `Base58.encode/1` and `Base58.decode/1`
+`encode/1` takes an **Elixir binary** (_String, Number, etc._) +and returns a Base58 encoded String.
+`decode/1` receives a Base58 encoded String and returns a binary. See the section [What is an Elixir binary?](#what-is-an-elixir-binary) for more information about the binary type in Elixir. -## How to use the module +## How to use the module? + +### 1. Add the package to you dependencies + +Open your `mix.exs` file and add the following line to your `deps`: + +```elixir +defp deps do + [ + {:b58, "~> 1.0"}, + ] +end +``` + +and run `mix deps.get` + +### 2. Invoke the `encode/1` function with a binary as parameter: + +```elixir +Base58.encode("foo") +"bQbp" +``` + +### 3. Invoke the `decode/1` function with a `base58` encoded string: + +```elixir +Base58.encode("hello") |> Base58.decode() +"hello" +``` + +
+ + +See `example/example.exs` file +for a simple example of how to use the module.
+You can also run this example with `mix run example/example.exs` + -1. Add the package to you dependencies +### Note: `Integer` Values are Converted to `String` + +When encoding an `Integer` +the value is converted to a `String` before encoding +so when it is decoded it will be a string e.g: + +```elixir +Base58.encode(42) |> Base58.decode() +"42" +``` + +This isn't ideal if you _expected_ an `Integer` +but there is no way to encode the **`type`** of the data. +So if you _know_ that you need it to be an `int`, +convert it back to a numeric value with `Base58.decode_to_int/1`: + +```elixir +iex(1)> Base58.encode(42) |> Base58.decode_to_int() +42 +``` - ``` - defp deps do - [b58: "~> 0.1.0"] - end - ``` - and run `mix deps.get` -2. Call the `encode` function with a binary as parameter: +

- ``` - Base58Encode.encode("foo") - "bQbp" - ``` +## Why? - if the parameter is not an Elixir binary the function will return `:error`. In - this example 42 is an Integer and not a binary (`is_binary(42)` will return `false`) - ``` - Base58Encode.encode(42) - :error - ``` - See `example/example.exs` file for a simple example on how to use the module. - You can also run this example with `mix run example/example.exs` -## What is base58? +## What is Base58? A *base* is a set of characters used for representing numbers. +https://en.wikipedia.org/wiki/Base58 For example - The base 2 (binary system) represents numbers with the digits ` 0 1` diff --git a/example/example.exs b/example/example.exs index 38d5a3e..77b944c 100644 --- a/example/example.exs +++ b/example/example.exs @@ -1,8 +1,10 @@ defmodule Example do hello = "hello" - helloBase58 = Base58Encode.encode(hello) + helloBase58 = Base58.encode(hello) + helloBase58Decode = Base58.decode(helloBase58) IO.puts("the \"#{hello}\" binary is represented as \"#{helloBase58}\" in base58") + IO.puts("the \"#{helloBase58Decode}\" decoded is #{hello})") end diff --git a/lib/base58.ex b/lib/base58.ex new file mode 100644 index 0000000..ec791b8 --- /dev/null +++ b/lib/base58.ex @@ -0,0 +1,114 @@ +defmodule Base58 do + @moduledoc """ + `Base58` provides two functions: `encode/1` and `decode/1`. + `encode/1` takes an **Elixir binary** (_String, Number, etc._) + and returns a Base58 encoded String. + `decode/1` receives a Base58 encoded String and returns a binary. + """ + + @doc """ + ## Examples + + iex> Base58.encode("hello") + "Cn8eVZg" + + iex> Base58.encode(42) + "4yP" + """ + def encode(""), do: "" + def encode(binary) when is_binary(binary) do + # see https://github.com/dwyl/base58/pull/3#discussion_r252291127 + decimal = :binary.decode_unsigned(binary) + + if decimal == 0 do + # see https://github.com/dwyl/base58/issues/5#issuecomment-459088540 + leading_zeros(binary, "") + else + codes = get_codes(decimal, []) + leading_zeros(binary, "") <> codes_to_string(codes) + end + end + + # If the parameter is not a binary convert it to binary before encode. + def encode(int) when is_integer(int) do + int + |> Integer.to_string() + |> encode() + end + + def encode(val) when is_float(val) do + val + |> Float.to_string() + |> encode() + end + + def encode(atom) when is_atom(atom) do + atom + |> Atom.to_string() + |> encode() + end + + # return a list of codes (codepoint of base58) + defp get_codes(int, codes) do + rest = div(int, 58) + code = rem(int, 58) + + if rest == 0 do + [code | codes] + else + get_codes(rest, [code | codes]) + end + end + + defp alphanum do + [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] + end + + # match codepoints to the alphabet of base58 + defp codes_to_string(codes) do + codes + |> Enum.map(&Enum.at(alphanum(), &1)) + |> Enum.join() + end + + # convert leading zeros to "1" + defp leading_zeros(<<0, rest::binary>>, acc) do + leading_zeros(rest, acc <> "1") + end + + defp leading_zeros(_bin, acc) do + acc + end + + @doc """ + `decode/1` decodes the given Base58 string back to binary. + ## Examples + + iex> Base58.encode("hello") |> Base58.decode() + "hello" + """ + @alnum ~c(123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz) + + def decode(""), do: "" # return empty string unmodified + def decode("\0"), do: "" # treat null values as empty + def decode(encoded), do: recurse(encoded |> to_charlist, 0) + defp recurse([], acc), do: acc |> :binary.encode_unsigned() + defp recurse([head | tail], acc) do + recurse(tail, (acc * 58) + Enum.find_index(@alnum, &(&1 == head))) + end + + @doc """ + `decode_to_int/1` decodes the given Base58 string back to an Integer. + ## Examples + + iex> Base58.encode(42) |> Base58.decode_to_int() + 42 + """ + def decode_to_int(encoded) do + decode(encoded) + |> String.to_integer() + end +end diff --git a/lib/base58encode.ex b/lib/base58encode.ex deleted file mode 100644 index 060f110..0000000 --- a/lib/base58encode.ex +++ /dev/null @@ -1,70 +0,0 @@ -defmodule Base58Encode do - @moduledoc """ - Provides the encode function which takes a binary and return it's - reprentation in base58 - """ - - @doc """ - ## Examples - - iex> Base58Encode.encode("hello") - "Cn8eVZg" - - iex> Base58Encode.encode(42) - :error - """ - - def encode(""), do: "" - - def encode(binary) when is_binary(binary) do - # see https://github.com/dwyl/base58encode/pull/3#discussion_r252291127 - decimal = :binary.decode_unsigned(binary) - if decimal == 0 do - # see https://github.com/dwyl/base58encode/issues/5#issuecomment-459088540 - leading_zeros(binary, "") - else - codes = get_codes(decimal, []) - leading_zeros(binary, "") <> codes_to_string(codes) - end - end - - - # If the parameter is not a binary, return an error - def encode(_), do: :error - - -# return a list of codes (codepoint of base58) - defp get_codes(int, codes) do - rest = div(int, 58) - code = rem(int, 58) - if rest == 0 do - [code | codes] - else - get_codes(rest, [code | codes]) - end - end - - # match codepoints to the alphabet of base58 - defp codes_to_string(codes) do - alphabet = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', - 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', - 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', - 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] - - codes - |> Enum.map(&(Enum.at(alphabet, &1))) - |> Enum.join() - end - - # convert leading zeros to "1" - defp leading_zeros(<<0, rest::binary>>, acc) do - leading_zeros(rest, acc <> "1") - end - - defp leading_zeros(_bin, acc) do - acc - end - -end diff --git a/mix.exs b/mix.exs index 28a2001..4bef7b7 100644 --- a/mix.exs +++ b/mix.exs @@ -1,13 +1,13 @@ -defmodule Base58Encode.MixProject do +defmodule Base58.MixProject do use Mix.Project def project do [ - app: :b58, + app: :B58, name: "b58", description: description(), package: package(), - version: "0.1.1", + version: "1.0.0", elixir: "~> 1.7", start_permanent: Mix.env() == :prod, deps: deps(), @@ -16,7 +16,7 @@ defmodule Base58Encode.MixProject do coveralls: :test, "coveralls.json": :test ], - source_url: "https://github.com/dwyl/base58encode" + source_url: "https://github.com/dwyl/base58" ] end @@ -29,15 +29,16 @@ defmodule Base58Encode.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do - [ {:excoveralls, "~> 0.10", only: :test}, + [ + {:excoveralls, "~> 0.12.3", only: :test}, {:basefiftyeight, "~> 0.1.0", only: :test}, - {:stream_data, "~> 0.1", only: :test}, - {:ex_doc, "~> 0.19.3", only: :dev} + {:stream_data, "~> 0.4.3", only: :test}, + {:ex_doc, "~> 0.21.3", only: :dev} ] end defp description() do - "Encode an Elixir binary to its base58 representation" + "B58 lets you encode an Elixir binary to base58 and decode a base58 string." end defp package() do @@ -45,7 +46,7 @@ defmodule Base58Encode.MixProject do name: "b58", licenses: ["GNU GPL v2.0"], maintainers: ["dwyl"], - links: %{"GitHub" => "https://github.com/dwyl/base58encode"} + links: %{"GitHub" => "https://github.com/dwyl/base58"} ] end end diff --git a/mix.lock b/mix.lock index ba6ae34..56f17ed 100644 --- a/mix.lock +++ b/mix.lock @@ -1,19 +1,19 @@ %{ - "basefiftyeight": {:hex, :basefiftyeight, "0.1.0", "3d48544743bf9aab7ab02aed803ac42af77acf268c7d8c71d4f39e7fa85ee8d3", [:mix], [], "hexpm"}, - "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, - "earmark": {:hex, :earmark, "1.3.1", "73812f447f7a42358d3ba79283cfa3075a7580a3a2ed457616d6517ac3738cb9", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.19.3", "3c7b0f02851f5fc13b040e8e925051452e41248f685e40250d7e40b07b9f8c10", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "excoveralls": {:hex, :excoveralls, "0.10.4", "b86230f0978bbc630c139af5066af7cd74fd16536f71bc047d1037091f9f63a9", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.0", "287a5d2304d516f63e56c469511c42b016423bcb167e61b611f6bad47e3ca60e", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, - "stream_data": {:hex, :stream_data, "0.4.2", "fa86b78c88ec4eaa482c0891350fcc23f19a79059a687760ddcf8680aac2799b", [:mix], [], "hexpm"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, + "basefiftyeight": {:hex, :basefiftyeight, "0.1.0", "3d48544743bf9aab7ab02aed803ac42af77acf268c7d8c71d4f39e7fa85ee8d3", [:mix], [], "hexpm", "af12f551429528c711e98628c029ad48d1e5ba5a284f40b2d91029a65381837a"}, + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"}, + "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, + "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, + "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"}, + "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, + "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"}, + "makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"}, + "stream_data": {:hex, :stream_data, "0.4.3", "62aafd870caff0849a5057a7ec270fad0eb86889f4d433b937d996de99e3db25", [:mix], [], "hexpm", "7dafd5a801f0bc897f74fcd414651632b77ca367a7ae4568778191fc3bf3a19a"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, } diff --git a/test/base58_encode_test.exs b/test/base58_encode_test.exs deleted file mode 100644 index d1088cc..0000000 --- a/test/base58_encode_test.exs +++ /dev/null @@ -1,46 +0,0 @@ -defmodule Base58EncodeTest do - use ExUnit.Case - use ExUnitProperties - - doctest Base58Encode - - describe "Testing encode function" do - test "returns base58 for the string foo" do - assert "bQbp" == Base58Encode.encode("foo") - end - - test "returns error if parameter is not a binary" do - assert :error == Base58Encode.encode(23) - end - - test "returns z when binary is represented by 57" do - assert "z" == Base58Encode.encode(<<57>>) - end - - test "returns empty string when encoding an empty string" do - assert "" == Base58Encode.encode("") - end - - test "add leading zeros as \"1\"" do - assert "1112" == Base58Encode.encode(<<0, 0, 0, 1>>) - end - - test "encode empty string" do - assert "Z" == Base58Encode.encode(" ") - end - - test "encode <<0>> retuens 1" do - assert "1" == Base58Encode.encode(<<0>>) - end - - test "encode <<0, 0, 0, 0, 0>> retuens 11111" do - assert "11111" == Base58Encode.encode(<<0, 0, 0, 0, 0>>) - end - - property "Compare result with basefiftyeight package" do - check all bin <- binary() do - assert B58.encode58(bin) == Base58Encode.encode(bin) - end - end - end -end diff --git a/test/base58_test.exs b/test/base58_test.exs new file mode 100644 index 0000000..01db845 --- /dev/null +++ b/test/base58_test.exs @@ -0,0 +1,88 @@ +defmodule Base58Test do + use ExUnit.Case + use ExUnitProperties + + doctest Base58 + import Base58 + + describe "Testing encode function" do + test "returns empty string when encoding an empty string" do + assert "" == encode("") + end + + test "returns base58 for the string foo" do + assert "bQbp" == encode("foo") + end + + test "converts any value to binary and then Base58 encodes it" do + # Integer + assert "4pa" == encode(23) + assert "4pa" == encode("23") + # Float + assert "2JstGb" == encode(3.14) + assert "2JstGb" == encode("3.14") + # Atom + assert "Cn8eVZg" == encode(:hello) + assert "Cn8eVZg" == encode("hello") + end + + test "returns z when binary is represented by 57" do + assert "z" == encode(<<57>>) + end + + test "add leading zeros as \"1\"" do + assert "1112" == encode(<<0, 0, 0, 1>>) + end + + test "encode empty string" do + assert "Z" == encode(" ") + end + + test "encode <<0>> returns 1" do + assert "1" == encode(<<0>>) + end + + test "encode <<0, 0, 0, 0, 0>> returns 11111" do + assert "11111" == encode(<<0, 0, 0, 0, 0>>) + end + + test "decode(encode(str) == str)" do + assert B58.encode58("123") == encode("123") + assert decode(encode("123")) == "123" + end + + test "decode :atom" do + assert encode(:hello) |> decode() == "hello" + end + + test "decode_to_int(encode(int) == int)" do + int = 42 + decoded = Base58.encode(int) |> Base58.decode_to_int() + assert decoded == int + end + + property "Check a batch of int values can be decoded" do + check all(int <- integer()) do + assert decode_to_int(encode(int)) == int + end + end + + property "Compare result with Base58 package" do + check all(bin <- binary()) do + case bin == "" do + true -> # Base58.encode cannot handle an empty string + bin + false -> + assert Base58.encode(bin) == encode(bin) + end + end + end + + property "Check a bunch of binary values can be encoded and decoded" do + check all(bin <- binary()) do + bin = String.replace(bin, "\0", "") # strip null + assert decode(encode(bin)) == bin + end + end + end +end