diff --git a/.credo.exs b/.credo.exs new file mode 100644 index 0000000..3e3962f --- /dev/null +++ b/.credo.exs @@ -0,0 +1,100 @@ +# .credo.exs +%{ + configs: [ + %{ + name: "default", + files: %{ + included: ["lib/", "test/"], + excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"] + }, + plugins: [], + requires: [], + strict: false, + parse_timeout: 5000, + color: true, + checks: %{ + enabled: [ + # Design Checks + {Credo.Check.Design.AliasUsage, []}, + {Credo.Check.Design.TagFIXME, []}, + {Credo.Check.Design.TagTODO, exit_status: 0}, + + # Readability Checks + {Credo.Check.Readability.AliasOrder, []}, + {Credo.Check.Readability.FunctionNames, []}, + {Credo.Check.Readability.LargeNumbers, []}, + {Credo.Check.Readability.MaxLineLength, [max_length: 120]}, + {Credo.Check.Readability.ModuleAttributeNames, []}, + {Credo.Check.Readability.ModuleDoc, []}, + {Credo.Check.Readability.ModuleNames, []}, + {Credo.Check.Readability.ParenthesesInCondition, []}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, + {Credo.Check.Readability.PipeIntoAnonymousFunctions, []}, + {Credo.Check.Readability.PredicateFunctionNames, []}, + {Credo.Check.Readability.PreferImplicitTry, []}, + {Credo.Check.Readability.RedundantBlankLines, []}, + {Credo.Check.Readability.Semicolons, []}, + {Credo.Check.Readability.SpaceAfterCommas, []}, + {Credo.Check.Readability.StringSigils, []}, + {Credo.Check.Readability.TrailingBlankLine, []}, + {Credo.Check.Readability.TrailingWhiteSpace, []}, + {Credo.Check.Readability.UnnecessaryAliasExpansion, []}, + {Credo.Check.Readability.VariableNames, []}, + {Credo.Check.Readability.WithSingleClause, []}, + + # Refactoring Opportunities + {Credo.Check.Refactor.Apply, []}, + {Credo.Check.Refactor.CondStatements, []}, + {Credo.Check.Refactor.CyclomaticComplexity, []}, + {Credo.Check.Refactor.FunctionArity, []}, + {Credo.Check.Refactor.LongQuoteBlocks, []}, + {Credo.Check.Refactor.MatchInCondition, []}, + {Credo.Check.Refactor.MapJoin, []}, + {Credo.Check.Refactor.NegatedConditionsInUnless, []}, + {Credo.Check.Refactor.NegatedConditionsWithElse, []}, + {Credo.Check.Refactor.Nesting, []}, + {Credo.Check.Refactor.UnlessWithElse, []}, + {Credo.Check.Refactor.WithClauses, []}, + + # Warnings + {Credo.Check.Warning.ApplicationConfigInModuleAttribute, []}, + {Credo.Check.Warning.BoolOperationOnSameValues, []}, + {Credo.Check.Warning.Dbg, []}, + {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, + {Credo.Check.Warning.IExPry, []}, + {Credo.Check.Warning.IoInspect, []}, + {Credo.Check.Warning.OperationOnSameValues, []}, + {Credo.Check.Warning.OperationWithConstantResult, []}, + {Credo.Check.Warning.RaiseInsideRescue, []}, + {Credo.Check.Warning.SpecWithStruct, []}, + {Credo.Check.Warning.UnusedEnumOperation, []}, + {Credo.Check.Warning.UnusedFileOperation, []}, + {Credo.Check.Warning.UnusedKeywordOperation, []}, + {Credo.Check.Warning.UnusedListOperation, []}, + {Credo.Check.Warning.UnusedPathOperation, []}, + {Credo.Check.Warning.UnusedRegexOperation, []}, + {Credo.Check.Warning.UnusedStringOperation, []}, + {Credo.Check.Warning.UnusedTupleOperation, []}, + {Credo.Check.Warning.WrongTestFileExtension, []} + ], + disabled: [ + # Disabled checks + {Credo.Check.Readability.MultiAlias, []}, + {Credo.Check.Readability.Specs, []}, + {Credo.Check.Refactor.ABCSize, []}, + {Credo.Check.Refactor.AppendSingleItem, []}, + {Credo.Check.Refactor.DoubleBooleanNegation, []}, + {Credo.Check.Refactor.ModuleDependencies, []}, + {Credo.Check.Refactor.NegatedIsNil, []}, + {Credo.Check.Refactor.PipeChainStart, []}, + {Credo.Check.Refactor.VariableRebinding, []}, + {Credo.Check.Warning.LazyLogging, []}, + {Credo.Check.Warning.LeakyEnvironment, []}, + {Credo.Check.Warning.MapGetUnsafePass, []}, + {Credo.Check.Warning.MixEnv, []}, + {Credo.Check.Warning.UnsafeToAtom, []} + ] + } + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6ab32cd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + branches: [ master, main ] + pull_request: + branches: [ master, main ] + +jobs: + test: + name: Test on Elixir ${{matrix.elixir}} / OTP ${{matrix.otp}} + runs-on: ubuntu-latest + strategy: + matrix: + elixir: ['1.14', '1.15', '1.16'] + otp: ['25', '26'] + + steps: + - uses: actions/checkout@v3 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{matrix.elixir}} + otp-version: ${{matrix.otp}} + + - name: Restore dependencies cache + uses: actions/cache@v3 + with: + path: deps + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + + - name: Install dependencies + run: mix deps.get + + - name: Compile with warnings as errors + run: mix compile --warnings-as-errors + + - name: Run tests + run: mix test + + - name: Run Credo + run: mix credo --strict + + - name: Run Sobelow + run: mix sobelow --exit Low + diff --git a/.gitignore b/.gitignore index f0084a6..3d87b42 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,14 @@ erl_crash.dump # Ignore package tarball (built via "mix hex.build"). smile-*.tar +smile_ex-*.tar # Temporary files, for example, from tests. /tmp/ + +# Dialyzer +/priv/plts/ + +# Coverage reports +coveralls.html +.coveralls.yml diff --git a/.hexignore b/.hexignore new file mode 100644 index 0000000..0c467a2 --- /dev/null +++ b/.hexignore @@ -0,0 +1,35 @@ +# Ignore build artifacts +/_build +/cover +/doc +/deps + +# Ignore test files +/test + +# Ignore git files +/.git +/.github +/.gitignore + +# Ignore development files +/.elixir_ls +/.vscode +/.idea + +# Ignore examples +/examples + +# Ignore temporary files +*.swp +*.swo +*~ +.DS_Store + +# Ignore CI files +/.travis.yml +/.github + +# Ignore summary +/SUMMARY.md + diff --git a/.sobelow-conf b/.sobelow-conf new file mode 100644 index 0000000..da1a60f --- /dev/null +++ b/.sobelow-conf @@ -0,0 +1,13 @@ +[ + verbose: false, + private: false, + skip: false, + router: "", + exit: "false", + format: "txt", + out: "", + threshold: "low", + ignore: [], + ignore_files: [] +] + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cbdfe90..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: elixir -sudo: required - -services: - - couchdb - -elixir: - - 1.5.1 -otp_release: - - 20.0 - - 19.3 - - 19.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dbfc98..e47f614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Initial release of Smile binary format encoder/decoder for Elixir +- Initial release of SmileEx binary format encoder/decoder for Elixir - Complete implementation of Smile format specification v1.0 - Support for all JSON-compatible data types (null, boolean, integer, float, string, array, object) - Encoding with back-references for field names and string values @@ -30,5 +30,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Typically 20-40% size reduction compared to JSON - Faster encoding and decoding than text-based JSON -[0.1.0]: https://github.com/thanos/smile/releases/tag/v0.1.0 +[0.1.0]: https://github.com/thanos/smile_ex/releases/tag/v0.1.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4efbded --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Smile Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md index 881c173..033be90 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# Smile +# SmileEx + -[![Hex.pm](https://img.shields.io/hexpm/v/smile.svg)](https://hex.pm/packages/smile) -[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/smile/) -[![Hex.pm](https://img.shields.io/hexpm/dt/smile.svg)](https://hex.pm/packages/smile) +[![Hex.pm](https://img.shields.io/hexpm/v/smile_ex.svg)](https://hex.pm/packages/smile_ex) +[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/smile_ex/) +[![Hex.pm](https://img.shields.io/hexpm/dt/smile_ex.svg)](https://hex.pm/packages/smile_ex) @@ -21,12 +22,12 @@ Smile is a computer data interchange format based on JSON. It can be considered ## Installation -Add `smile` to your list of dependencies in `mix.exs`: +Add `smile_ex` to your list of dependencies in `mix.exs`: ```elixir def deps do [ - {:smile, "~> 0.1.0"} + {:smile_ex, "~> 0.1.0"} ] end ``` @@ -187,18 +188,33 @@ json = Jason.encode!(data) # Plus: faster to encode/decode ``` -## Testing +## Development -Run the test suite: +### Testing ```bash +# Run tests mix test + +# Run tests with coverage +mix test --cover + +# Generate HTML coverage report +mix coveralls.html +open cover/excoveralls.html ``` -Run tests with coverage: +### Code Quality ```bash -mix test --cover +# Static code analysis +mix credo + +# Security analysis +mix sobelow + +# Type checking (first run takes a while) +mix dialyzer ``` ## Specification @@ -211,7 +227,14 @@ For more details about the format, see: ## Contributing -Contributions are welcome! Please feel free to submit a Pull Request. +Contributions are welcome! Please ensure: + +1. All tests pass: `mix test` +2. Code passes static analysis: `mix credo` +3. No security issues: `mix sobelow` +4. Code is formatted: `mix format` + +Then submit a Pull Request. ## License @@ -219,7 +242,7 @@ This project is licensed under the MIT License. ## API Documentation -The complete API documentation is available on [HexDocs](https://hexdocs.pm/smile/). +The complete API documentation is available on [HexDocs](https://hexdocs.pm/smile_ex/). You can also generate documentation locally: diff --git a/coveralls.json b/coveralls.json new file mode 100644 index 0000000..a6b330b --- /dev/null +++ b/coveralls.json @@ -0,0 +1,12 @@ +{ + "coverage_options": { + "minimum_coverage": 70, + "treat_no_relevant_lines_as_covered": true, + "output_dir": "cover/" + }, + "skip_files": [ + "test/", + "deps/" + ] +} + diff --git a/lib/constants.ex b/lib/constants.ex index 95b9603..a9763c1 100644 --- a/lib/constants.ex +++ b/lib/constants.ex @@ -50,17 +50,21 @@ defmodule Smile.Constants do def max_shared_names, do: 1024 def max_shared_string_values, do: 1024 def max_shared_string_length_bytes, do: 65 - def min_buffer_for_possible_short_string, do: 1 + (3 * 65) + def min_buffer_for_possible_short_string, do: 1 + 3 * 65 # Byte markers def byte_marker_end_of_string, do: 0xFC def byte_marker_end_of_content, do: 0xFF # Format header - def header_byte_1, do: 0x3A # ':' - def header_byte_2, do: 0x29 # ')' - def header_byte_3, do: 0x0A # '\n' - def header_byte_4, do: 0x00 # version 0 + # ':' + def header_byte_1, do: 0x3A + # ')' + def header_byte_2, do: 0x29 + # '\n' + def header_byte_3, do: 0x0A + # version 0 + def header_byte_4, do: 0x00 # Header bits def header_bit_has_shared_names, do: 0x01 diff --git a/lib/smile/decoder.ex b/lib/smile/decoder.ex index 599c23a..770591c 100644 --- a/lib/smile/decoder.ex +++ b/lib/smile/decoder.ex @@ -482,7 +482,7 @@ defmodule Smile.Decoder do end defp decode_vint_bytes(<>, acc, shift) do - value = acc ||| ((byte &&& 0x7F) <<< shift) + value = acc ||| (byte &&& 0x7F) <<< shift if (byte &&& 0x80) == 0 do {:ok, value, rest} diff --git a/lib/smile/encoder.ex b/lib/smile/encoder.ex index 44c8fcd..3427e24 100644 --- a/lib/smile/encoder.ex +++ b/lib/smile/encoder.ex @@ -215,7 +215,9 @@ defmodule Smile.Encoder do # Long ASCII ascii?(bytes) -> - {:ok, <> <> encode_vint(byte_len) <> bytes <> <>, state} + {:ok, + <> <> + encode_vint(byte_len) <> bytes <> <>, state} # Tiny Unicode (2-33 bytes) byte_len >= 2 and byte_len <= 33 -> @@ -229,7 +231,9 @@ defmodule Smile.Encoder do # Long Unicode true -> - {:ok, <> <> encode_vint(byte_len) <> bytes <> <>, state} + {:ok, + <> <> + encode_vint(byte_len) <> bytes <> <>, state} end end @@ -244,7 +248,8 @@ defmodule Smile.Encoder do <> <> bytes ascii?(bytes) -> - <> <> encode_vint(byte_len) <> bytes <> <> + <> <> + encode_vint(byte_len) <> bytes <> <> byte_len >= 2 and byte_len <= 33 -> token = C.token_prefix_tiny_unicode() + (byte_len - 2) @@ -255,7 +260,8 @@ defmodule Smile.Encoder do <> <> bytes true -> - <> <> encode_vint(byte_len) <> bytes <> <> + <> <> + encode_vint(byte_len) <> bytes <> <> end end @@ -270,8 +276,13 @@ defmodule Smile.Encoder do end) case items_data do - {:error, reason} -> {:error, reason} - _ -> {:ok, <> <> items_data <> <>, final_state} + {:error, reason} -> + {:error, reason} + + _ -> + {:ok, + <> <> items_data <> <>, + final_state} end end @@ -290,8 +301,13 @@ defmodule Smile.Encoder do end) case items_data do - {:error, reason} -> {:error, reason} - _ -> {:ok, <> <> items_data <> <>, final_state} + {:error, reason} -> + {:error, reason} + + _ -> + {:ok, + <> <> + items_data <> <>, final_state} end end @@ -340,7 +356,8 @@ defmodule Smile.Encoder do # Long string (with length prefix) true -> - <> <> encode_vint(byte_len) <> bytes <> <> + <> <> + encode_vint(byte_len) <> bytes <> <> end end @@ -349,9 +366,10 @@ defmodule Smile.Encoder do index = length(state.name_list) if index < C.max_shared_names() do - %{state | - name_refs: Map.put(state.name_refs, name, index), - name_list: state.name_list ++ [name] + %{ + state + | name_refs: Map.put(state.name_refs, name, index), + name_list: state.name_list ++ [name] } else state @@ -363,10 +381,12 @@ defmodule Smile.Encoder do index = length(state.value_list) if index < C.max_shared_string_values() do - new_state = %{state | - value_refs: Map.put(state.value_refs, value, index), - value_list: state.value_list ++ [value] + new_state = %{ + state + | value_refs: Map.put(state.value_refs, value, index), + value_list: state.value_list ++ [value] } + {<<>>, new_state} else {<<>>, state} @@ -382,7 +402,7 @@ defmodule Smile.Encoder do defp encode_shared_string_reference(index) do # Long reference: 2 bytes - <> + <> end # Variable-length integer encoding diff --git a/mix.exs b/mix.exs index 6b5e0e3..1ce3c05 100644 --- a/mix.exs +++ b/mix.exs @@ -1,12 +1,12 @@ -defmodule Smile.MixProject do +defmodule SmileEx.MixProject do use Mix.Project @version "0.1.0" - @source_url "https://github.com/thanos/smile" + @source_url "https://github.com/thanos/smile_ex" def project do [ - app: :smile, + app: :smile_ex, version: @version, elixir: "~> 1.5", start_permanent: Mix.env() == :prod, @@ -14,9 +14,18 @@ defmodule Smile.MixProject do description: description(), package: package(), docs: docs(), - name: "Smile", + name: "SmileEx", source_url: @source_url, - homepage_url: @source_url + homepage_url: @source_url, + test_coverage: [tool: ExCoveralls], + preferred_cli_env: [ + coveralls: :test, + "coveralls.html": :test + ], + dialyzer: [ + plt_file: {:no_warn, "priv/plts/dialyzer.plt"}, + flags: [:error_handling, :underspecs] + ] ] end @@ -28,7 +37,14 @@ defmodule Smile.MixProject do defp deps do [ - {:ex_doc, "~> 0.24", only: :dev, runtime: false} + # Documentation + {:ex_doc, "~> 0.24", only: :dev, runtime: false}, + + # Code quality and testing + {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, + {:excoveralls, "~> 0.18", only: :test}, + {:sobelow, "~> 0.13", only: [:dev, :test], runtime: false}, + {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false} ] end @@ -42,7 +58,7 @@ defmodule Smile.MixProject do defp package do [ - name: "smile", + name: "smile_ex", files: ["lib", "mix.exs", "README.md", "LICENSE", "CHANGELOG.md"], maintainers: ["Thanos Vassilakis"], licenses: ["MIT"], @@ -63,7 +79,7 @@ defmodule Smile.MixProject do groups_for_modules: [ "Core API": [Smile], "Encoding & Decoding": [Smile.Encoder, Smile.Decoder], - "Constants": [Smile.Constants] + Constants: [Smile.Constants] ] ] end diff --git a/mix.lock b/mix.lock index 489f3ff..fb3f980 100644 --- a/mix.lock +++ b/mix.lock @@ -1,8 +1,16 @@ %{ + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"}, + "dialyxir": {:hex, :dialyxir, "1.4.6", "7cca478334bf8307e968664343cbdb432ee95b4b68a9cba95bdabb0ad5bdfd9a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "8cf5615c5cd4c2da6c501faae642839c8405b49f8aa057ad4ae401cb808ef64d"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, + "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ex_doc": {:hex, :ex_doc, "0.39.1", "e19d356a1ba1e8f8cfc79ce1c3f83884b6abfcb79329d435d4bbb3e97ccc286e", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "8abf0ed3e3ca87c0847dfc4168ceab5bedfe881692f1b7c45f4a11b232806865"}, + "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, + "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, + "sobelow": {:hex, :sobelow, "0.14.1", "2f81e8632f15574cba2402bcddff5497b413c01e6f094bc0ab94e83c2f74db81", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8fac9a2bd90fdc4b15d6fca6e1608efb7f7c600fa75800813b794ee9364c87f2"}, } diff --git a/test/smile_test.exs b/test/smile_test.exs index 7e25ca6..ebb180d 100644 --- a/test/smile_test.exs +++ b/test/smile_test.exs @@ -28,13 +28,15 @@ defmodule SmileTest do # Small int range: -16 to +15 assert {:ok, binary} = Smile.encode(5) assert <<0x3A, 0x29, 0x0A, _flags::8, token::8>> = binary - assert (token &&& 0xE0) == 0xC0 # Small int prefix + # Small int prefix + assert (token &&& 0xE0) == 0xC0 end test "encodes small negative integers" do assert {:ok, binary} = Smile.encode(-5) assert <<0x3A, 0x29, 0x0A, _flags::8, token::8>> = binary - assert (token &&& 0xE0) == 0xC0 # Small int prefix + # Small int prefix + assert (token &&& 0xE0) == 0xC0 end test "encodes 32-bit integers" do @@ -284,7 +286,7 @@ defmodule SmileTest do "count" => 2, "metadata" => %{ "version" => "1.0", - "timestamp" => 1234567890 + "timestamp" => 1_234_567_890 } }