├── .credo.exs ├── .formatter.exs ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib ├── assert_value.ex └── assert_value │ ├── app.ex │ ├── diff.ex │ ├── ex_unit_formatter.ex │ ├── formatter.ex │ ├── parser.ex │ ├── server.ex │ └── string_tools.ex ├── mix.exs └── test ├── bad_arguments_test.exs ├── file_tracker_test.exs ├── integration ├── accept_all_test.exs.after ├── accept_all_test.exs.before ├── accept_all_test.exs.output ├── accept_all_with_error_test.exs.after ├── accept_all_with_error_test.exs.before ├── accept_all_with_error_test.exs.output ├── decline_all_test.exs.after ├── decline_all_test.exs.before ├── decline_all_test.exs.output ├── decline_all_test.exs.output.1.10 ├── diff_and_help_prompt_test.exs.after ├── diff_and_help_prompt_test.exs.before ├── diff_and_help_prompt_test.exs.output ├── diff_and_help_prompt_test.exs.output.1.10 ├── diff_test.exs.after ├── diff_test.exs.after.1.15 ├── diff_test.exs.before ├── diff_test.exs.output ├── diff_test.exs.output.1.15 ├── file_to_create.after ├── file_to_update.after ├── file_to_update.before ├── formatter_test.exs.after ├── formatter_test.exs.after.1.14 ├── formatter_test.exs.before ├── formatter_test.exs.output ├── formatter_test.exs.output.1.14 ├── misc_test.exs.after ├── misc_test.exs.before ├── misc_test.exs.output ├── misc_test.exs.output.1.10 ├── non_interactive_accept_test.exs.after ├── non_interactive_accept_test.exs.before ├── non_interactive_accept_test.exs.output ├── non_interactive_reject_test.exs.after ├── non_interactive_reject_test.exs.before ├── non_interactive_reject_test.exs.output ├── non_interactive_reject_test.exs.output.1.10 ├── parser_test.exs.after ├── parser_test.exs.after.1.13 ├── parser_test.exs.after.1.14 ├── parser_test.exs.after.1.15 ├── parser_test.exs.after.1.8 ├── parser_test.exs.before ├── parser_test.exs.output ├── parser_test.exs.output.1.10 ├── parser_test.exs.output.1.13 ├── parser_test.exs.output.1.14 ├── parser_test.exs.output.1.15 ├── parser_test.exs.output.1.8 ├── reformat_expected_test.exs.after ├── reformat_expected_test.exs.before └── reformat_expected_test.exs.output ├── integration_test.exs └── test_helper.exs /.credo.exs: -------------------------------------------------------------------------------- 1 | # Credo config to add/disable check rules. 2 | # On execution it is merged with default config in deps/credo/.config.exs 3 | %{ 4 | configs: [ 5 | %{ 6 | # All configs are named to be executed with 'mix credo -C ' 7 | # To merge with default config we should specify "default" name 8 | name: "default", 9 | strict: true, 10 | color: true, 11 | # 12 | # These are the files included in the analysis 13 | # We SHOULD specify them here 14 | # This key IS NOT merged with default config 15 | files: %{ 16 | included: ["lib/", "config/", "test/"], 17 | excluded: [~r"/_build/", ~r"/deps/"] 18 | }, 19 | # 20 | # If you create your own checks, you must specify the source files for 21 | # them here, so they can be loaded by Credo before running the analysis. 22 | requires: [], 23 | # 24 | # This key IS merged with default config 25 | # Add here only changes to default rules 26 | checks: [ 27 | {Credo.Check.Design.AliasUsage, false}, 28 | {Credo.Check.Readability.ModuleDoc, false}, 29 | {Credo.Check.Refactor.PipeChainStart, false}, 30 | {Credo.Check.Design.TagTODO, false}, 31 | # Turn off function complexity check. It always fail on 32 | # assert_value macro because it is complex. 33 | {Credo.Check.Refactor.CyclomaticComplexity, false}, 34 | # Same for function body nesting 35 | {Credo.Check.Refactor.Nesting, max_nesting: 3}, 36 | {Credo.Check.Refactor.FunctionArity, false}, 37 | # Long lines are not ok, Exit with status code 38 | {Credo.Check.Readability.MaxLineLength, 39 | ignore_strings: false, 40 | ignore_definitions: false, 41 | priority: :high, 42 | exit_status: 2}, 43 | # Do not suggest to write large numbers with underscore 44 | # We have GitHub data maps in tests with big ids and bytes sizes 45 | {Credo.Check.Readability.LargeNumbers, false}, 46 | # We have a lot of assert_value "foo" == "foo" in tests 47 | {Credo.Check.Warning.OperationOnSameValues, false} 48 | ] 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: ["*.exs", "lib/**/*.ex"], 3 | line_length: 80, 4 | locals_without_parens: [assert_value: :*], 5 | export: [ 6 | locals_without_parens: [assert_value: :*] 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Show all tests output diffs 2 | *.exs.output diff 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - '**' 8 | 9 | jobs: 10 | mix_test: 11 | name: mix test (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp}}) 12 | runs-on: ubuntu-22.04 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | include: 17 | # We run linter only for last Elixir version 18 | - elixir: 1.18.x 19 | otp: 27 20 | warnings_as_errors: true 21 | lint: true 22 | - elixir: 1.17.x 23 | otp: 27 24 | - elixir: 1.16.x 25 | otp: 26 26 | - elixir: 1.15.x 27 | otp: 26 28 | - elixir: 1.14.x 29 | otp: 25 30 | - elixir: 1.13.x 31 | otp: 24 32 | - elixir: 1.12.x 33 | otp: 24 34 | - elixir: 1.11.x 35 | otp: 24 36 | env: 37 | MIX_ENV: test 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: erlef/setup-beam@v1 41 | with: 42 | otp-version: ${{matrix.otp}} 43 | elixir-version: ${{matrix.elixir}} 44 | - name: Install Dependencies 45 | run: | 46 | mix local.hex --force 47 | mix local.rebar --force 48 | mix deps.get --only test 49 | - run: mix compile --warnings-as-errors 50 | if: matrix.warnings_as_errors 51 | - run: mix test 52 | - run: | 53 | mix deps.get --only dev 54 | MIX_ENV=dev mix credo --format=oneline 55 | mix format --check-formatted 56 | if: matrix.lint 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /cover 3 | /deps 4 | mix.lock 5 | erl_crash.dump 6 | *.ez 7 | *.swp 8 | .tool-versions 9 | 10 | # File used in development 11 | /test/dev_test.exs 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## v0.10.5 - May 14, 2025 3 | 4 | * Enhancements 5 | * Add support for Elixir 1.17, 1.18 6 | 7 | ## v0.10.4 - January 22, 2024 8 | 9 | * Enhancements 10 | * Add support for Elixir 1.16 11 | 12 | ## v0.10.3 - Oct 31, 2023 13 | 14 | * Enhancements 15 | * Full support for Elixir 1.15 16 | * Map keys are now sorted when creating new expected values to 17 | ensure predictable test results in Elixir 1.15/OTP 26 18 | 19 | ## v0.10.2 - Oct 30, 2023 20 | 21 | * Bugfixes 22 | * Fix crashes and subsequent test failures in umbrella apps at the end of 23 | test suite in Elixir 1.15/OTP 26 24 | * Fix rare cases of missing test results summaries in Elixir 1.15/OTP 26 25 | 26 | ## v0.10.1 - March 29, 2023 27 | 28 | * Enhancements 29 | * Add support for Elixir 1.14 30 | 31 | ## v0.10 - May 25, 2022 32 | 33 | * Enhancements 34 | * Add support for Elixir 1.13. Drop support for Elixir < 1.7 35 | * Improve formatter to work the same way as "mix format" 36 | in all known cases 37 | 38 | * Requirements 39 | * Elixir >= 1.7 40 | 41 | * Upgrade Instructions (optional) 42 | * Run `ASSERT_VALUE_ACCEPT_DIFFS=reformat mix test` to take advantage of 43 | improved formatter. This will avoid mixing actual test changes with 44 | formatting changes in the future. 45 | 46 | ## v0.9.5 - October 27, 2020 47 | 48 | * Enhancements 49 | * Do not run :iex app when running tests. 50 | Add "xref: [exclude: [{IEx.Info, :info, 1}]]" to project 51 | to avoid compilation warning 52 | 53 | ## v0.9.4 - October 22, 2020 54 | 55 | * Enhancements 56 | * Fix deprecation warnings in Elixir 1.10 and 1.11 57 | 58 | # Changelog 59 | ## v0.9.3 - June 12, 2019 60 | 61 | * Enhancements 62 | * Fix deprecation warnings in Elixir 1.8 63 | 64 | ## v0.9.2 - May 29, 2018 65 | 66 | * Bugfixes 67 | * Fix big data structure serialization using plain Macro.to_string() 68 | when running Elixir >= 1.6.5 69 | 70 | ## v0.9.1 - May 18, 2018 71 | 72 | * Bugfixes 73 | * Include .formatter.exs in the hex package 74 | 75 | ## v0.9.0 - May 10, 2018 76 | 77 | * Features 78 | * assert_value now uses Elixir Formatter to format values. This improves 79 | formatting of big data structures. Previously assert_value formatted 80 | expected values other than strings as one line making code unreadable 81 | when using big data structures like long arrays and nested maps. Now 82 | we use Elixir Formatter and it formats them correctly on multiple lines 83 | * Enhancements 84 | * assert_value now shows easier to understand diffs (more context) 85 | ``` 86 | # assert_value v0.8.5 87 | test/example_test.exs:7:"test expected" assert_value 2 + 2 failed 88 | - 89 | +4 90 | 91 | # assert_value v0.9.0 92 | test/example_test.exs:7:"test example" assert_value failed 93 | - assert_value 2 + 2 94 | + assert_value 2 + 2 == 4 95 | ``` 96 | * Requirements 97 | * Elixir >= 1.6 98 | * Upgrade Instructions 99 | * Add this to .formatter.exs: 100 | ```elixir 101 | [ 102 | # don't add parens around assert_value arguments 103 | import_deps: [:assert_value], 104 | # use this line length when updating expected value 105 | line_length: 98 # whatever you prefer, default is 98 106 | ] 107 | ``` 108 | * Run `ASSERT_VALUE_ACCEPT_DIFFS=reformat mix test` to take advantage of 109 | improved formatter 110 | 111 | ## v0.8.5 - April 30, 2018 112 | 113 | * Enhancements 114 | * Better error messages and README.md 115 | 116 | ## v0.8.4 - April 20, 2018 117 | 118 | * Features 119 | * Remove support for strict equality (===) 120 | 121 | ## v0.8.3 - April 20, 2018 122 | 123 | * Bugfixes 124 | * Fix long (>4096 symbols) binaries serialization 125 | * Features 126 | * Support strict equality operator: `assert_value 1 === 1.0` 127 | 128 | ## v0.8.2 - February 19, 2018 129 | 130 | * Bugfixes 131 | * Fix parser to correctly parse calls to functions without arguments 132 | * Enhancements 133 | * Better check and error message for not-serializable values 134 | 135 | ## v0.8.1 - February 8, 2018 136 | 137 | * Bugfixes 138 | * Fix parser for code producing AST with hygienic counters 139 | 140 | ## v0.8.0 - February 1, 2018 141 | 142 | * Upgrade Instructions 143 | * Run `mix test`. You may get diffs because assert_value no longer converts 144 | everything to a string 145 | * Run `ASSERT_VALUE_ACCEPT_DIFFS=reformat mix test` to take advantage of 146 | improved formatter 147 | * Add this to .formatter.exs to make Elixir formatter not to add parens to 148 | assert_value 149 | ```elixir 150 | [ 151 | import_deps: [:assert_value] 152 | ] 153 | ``` 154 | * Features 155 | * Support all argument types (e.g. Integer, List, Map) except not 156 | serializable (e.g. Function, PID, Reference) 157 | * Add ASSERT_VALUE_ACCEPT_DIFFS=reformat to automatically reformat all 158 | expected values 159 | * Enhancements 160 | * Better parser now supports any kind of formatting (expressions, 161 | parentheses, multi-line, etc.) 162 | * Better formatter (smarter formatting one-line and multi-line strings) 163 | * Better error reporting 164 | * Ensure compatibility with Elixir 1.6 165 | 166 | ## v0.7.1 - October 27, 2017 167 | 168 | * Enhancements 169 | * Better prompt (less options displayed for better readability) 170 | * Better README.md 171 | 172 | ## v0.7.0 - October 13, 2017 173 | 174 | * Initial release 175 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Pluron, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /lib/assert_value.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue do 2 | # Assertions with right argument like "assert_value actual == expected" 3 | defmacro assert_value({:==, _, [left, right]} = assertion) do 4 | {expected_type, expected_file} = 5 | case right do 6 | {{:., _, [{:__aliases__, _, [:File]}, :read!]}, _, [filename]} -> 7 | {:file, filename} 8 | 9 | str when is_binary(str) -> 10 | {:string, nil} 11 | 12 | _ -> 13 | {:other, nil} 14 | end 15 | 16 | expected_value = 17 | case expected_type do 18 | :string -> 19 | quote do 20 | unquote(right) 21 | |> String.replace(~r/\n\Z/, "", global: false) 22 | end 23 | 24 | # TODO: should deal with a no-bang File.read instead, may 25 | # want to deal with different errors differently 26 | :file -> 27 | quote do 28 | (File.exists?(unquote(expected_file)) && 29 | File.read!(unquote(expected_file))) || 30 | "" 31 | end 32 | 33 | :other -> 34 | right 35 | end 36 | 37 | quote do 38 | assertion_ast = unquote(Macro.escape(assertion)) 39 | actual_ast = unquote(Macro.escape(left)) 40 | actual_value = unquote(left) 41 | expected_type = unquote(expected_type) 42 | expected_file = unquote(expected_file) 43 | expected_ast = unquote(Macro.escape(right)) 44 | expected_value = unquote(expected_value) 45 | 46 | check_serializable(actual_value) 47 | check_string_and_file_read(actual_value, expected_type) 48 | # We need to check for reformat_expected? first to disable 49 | # "this check/guard will always yield the same result" warnings 50 | if AssertValue.Server.reformat_expected?() || 51 | actual_value != expected_value do 52 | decision = 53 | AssertValue.Server.ask_user_about_diff( 54 | caller: [ 55 | file: unquote(__CALLER__.file), 56 | line: unquote(__CALLER__.line), 57 | function: unquote(__CALLER__.function) 58 | ], 59 | assertion_ast: assertion_ast, 60 | actual_ast: actual_ast, 61 | actual_value: actual_value, 62 | expected_type: expected_type, 63 | expected_ast: expected_ast, 64 | expected_value: expected_value, 65 | expected_file: expected_file 66 | ) 67 | 68 | case decision do 69 | :ok -> 70 | true 71 | 72 | {:error, :ex_unit_assertion_error, error_attrs} -> 73 | raise ExUnit.AssertionError, error_attrs 74 | 75 | {:error, :parse_error} -> 76 | # raise ParseError in test instead of genserver 77 | # to show readable error message and stacktrace 78 | raise AssertValue.Parser.ParseError 79 | end 80 | else 81 | true 82 | end 83 | end 84 | end 85 | 86 | # Assertions without right argument like (assert_value "foo") 87 | defmacro assert_value(assertion) do 88 | quote do 89 | assertion_ast = unquote(Macro.escape(assertion)) 90 | actual_value = unquote(assertion) 91 | check_serializable(actual_value) 92 | 93 | decision = 94 | AssertValue.Server.ask_user_about_diff( 95 | caller: [ 96 | file: unquote(__CALLER__.file), 97 | line: unquote(__CALLER__.line), 98 | function: unquote(__CALLER__.function) 99 | ], 100 | assertion_ast: assertion_ast, 101 | # :_not_present_ is to show the difference between 102 | # nil and actually not present actual/expected 103 | actual_ast: :_not_present_, 104 | actual_value: actual_value, 105 | expected_type: :source, 106 | expected_ast: :_not_present_ 107 | ) 108 | 109 | case decision do 110 | :ok -> 111 | true 112 | 113 | {:error, :ex_unit_assertion_error, error_attrs} -> 114 | raise ExUnit.AssertionError, error_attrs 115 | 116 | {:error, :parse_error} -> 117 | # raise ParseError in test instead of genserver 118 | # to show readable error message and stacktrace 119 | raise AssertValue.Parser.ParseError 120 | end 121 | end 122 | end 123 | 124 | defmodule ArgumentError do 125 | defexception [:message] 126 | end 127 | 128 | def check_serializable(value) do 129 | # Some types like Function, PID, Decimal, etc don't have literal 130 | # representation and cannot be used as expected 131 | # 132 | # #Decimal<18.98> 133 | # 134 | # To check this we format actual value and try to parse it back with 135 | # Code.eval_string. If evaluated value is the same as it was before 136 | # formatting then value is serialized correctly 137 | {res, evaluated_value} = 138 | try do 139 | {evaluated_value, _} = 140 | value 141 | |> AssertValue.Formatter.new_expected_from_actual_value() 142 | |> Code.eval_string() 143 | 144 | evaluated_value = 145 | if is_binary(evaluated_value) do 146 | String.replace(evaluated_value, ~r/\n\Z/, "", global: false) 147 | else 148 | evaluated_value 149 | end 150 | 151 | {:ok, evaluated_value} 152 | rescue 153 | _ -> {:error, nil} 154 | end 155 | 156 | unless res == :ok and value == evaluated_value do 157 | raise AssertValue.ArgumentError, 158 | message: """ 159 | Unable to serialize #{inspect(value)} 160 | 161 | assert_value needs to be able to take actual value and update expected 162 | in source code so they are equal. To do this it needs to serialize 163 | Elixir value as valid Elixir source code. 164 | 165 | assert_value tried to serialize this expected value, and it did not 166 | work. 167 | 168 | Some types like Function, PID, Decimal don't have literal 169 | representation and cannot be serialized. Same goes for data 170 | structures that include these values. 171 | 172 | One way to fix this is to write your own serializer and convert 173 | this actual value to a string before passing it to assert_value. 174 | For example you can wrap actual value in Kernel.inspect/1 175 | """ 176 | end 177 | 178 | :ok 179 | end 180 | 181 | def check_string_and_file_read(actual_value, _expected_type = :file) 182 | when is_binary(actual_value), 183 | do: :ok 184 | 185 | def check_string_and_file_read(actual_value, _expected_type = :file) do 186 | raise AssertValue.ArgumentError, 187 | message: """ 188 | Unable to compare #{get_value_type(actual_value)} with File.read! 189 | 190 | File.read! always return binary result and requires left argument 191 | in assert_value to be binary. You might want to use to_string/1 or 192 | inspect/1 to compare other types with File.read! 193 | 194 | assert_value to_string(:foo) == File.read!("foo.log") 195 | assert_value inspect(:foo) == File.read!("foo.log") 196 | """ 197 | end 198 | 199 | def check_string_and_file_read(_, _), do: :ok 200 | 201 | defp get_value_type(arg) do 202 | [{"Data type", type} | _t] = IEx.Info.info(arg) 203 | type 204 | end 205 | end 206 | -------------------------------------------------------------------------------- /lib/assert_value/app.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.App do 2 | use Application 3 | 4 | def start(_type, _args) do 5 | import Supervisor.Spec, warn: false 6 | # We use custom formatter to temporarily capture and 7 | # suppress async tests output while interacting with user. 8 | # persistent: true is used because we may not have ExUnit 9 | # initialized before this application start. 10 | Application.put_env(:ex_unit, :formatters, [AssertValue.ExUnitFormatter], 11 | persistent: true 12 | ) 13 | 14 | children = [ 15 | AssertValue.Server 16 | ] 17 | 18 | opts = [strategy: :one_for_one] 19 | Supervisor.start_link(children, opts) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/assert_value/diff.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.Diff do 2 | @prefixes %{eq: " ", ins: "+", del: "-"} 3 | 4 | def diff(a, b) when is_binary(a) and is_binary(b) do 5 | a = AssertValue.StringTools.to_lines(a) 6 | b = AssertValue.StringTools.to_lines(b) 7 | 8 | List.myers_difference(a, b) 9 | |> format_diff 10 | end 11 | 12 | defp format_diff(diff) do 13 | diff 14 | |> Enum.map(fn {k, v} -> 15 | Enum.map(v, fn s -> 16 | @prefixes[k] <> s 17 | end) 18 | end) 19 | |> List.flatten() 20 | |> Enum.join("\n") 21 | |> Kernel.<>("\n") 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/assert_value/ex_unit_formatter.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.ExUnitFormatter do 2 | @moduledoc false 3 | 4 | # This module is used to flush all ExUnit's output collected by 5 | # other tests running in parallel before interacting with user so 6 | # their output will not mix on screen. 7 | 8 | # TODO: User may use custom formatter(s) that even don't write to stdout. 9 | # In the best case this module will do nothing, otherwise it may raise 10 | # unexpected errors 11 | 12 | use GenServer 13 | 14 | def init(opts) do 15 | {:ok, config} = ExUnit.CLIFormatter.init(opts) 16 | # Get ExUnit's Formatter io device pid and tell it to AssertValue.Server 17 | # We will use it to flush ExUnit's output before interactions with user 18 | {:ok, captured_ex_unit_io_pid} = StringIO.open("") 19 | AssertValue.Server.set_captured_ex_unit_io_pid(captured_ex_unit_io_pid) 20 | {:ok, config} 21 | end 22 | 23 | def handle_cast(request, state) do 24 | {:noreply, state} = ExUnit.CLIFormatter.handle_cast(request, state) 25 | 26 | # Do not flush ExUnit IO at the end of the suite 27 | # ExUnit may close StringIO faster then we try to call it 28 | case request do 29 | {:suite_finished, _} -> :ok 30 | _ -> AssertValue.Server.flush_ex_unit_io() 31 | end 32 | 33 | {:noreply, state} 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/assert_value/formatter.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.Formatter do 2 | import AssertValue.StringTools 3 | 4 | def new_expected_from_actual_value(actual) do 5 | if is_binary(actual) and length(to_lines(actual)) > 1 do 6 | format_as_heredoc(actual) 7 | else 8 | actual 9 | |> Kernel.inspect( 10 | limit: :infinity, 11 | printable_limit: :infinity, 12 | custom_options: [sort_maps: true] 13 | ) 14 | |> Code.format_string!() 15 | |> IO.iodata_to_binary() 16 | end 17 | end 18 | 19 | def format_with_indentation(code, indentation, formatter_opts) do 20 | # 98 is default Elixir line length 21 | line_length = Keyword.get(formatter_opts, :line_length, 98) 22 | # Reduce line length to indentation 23 | # Since we format only assert_value statement, formatter will unindent 24 | # it as it is the only statement in all code. When we add indentation 25 | # back, line length may exceed limits. 26 | line_length = line_length - String.length(indentation) 27 | formatter_opts = Keyword.put(formatter_opts, :line_length, line_length) 28 | 29 | code 30 | |> Code.format_string!(formatter_opts) 31 | |> IO.iodata_to_binary() 32 | |> to_lines 33 | |> Enum.map_join("\n", &indent_heredoc_line(&1, indentation)) 34 | end 35 | 36 | # Private 37 | 38 | defp format_as_heredoc(actual) do 39 | actual = 40 | actual 41 | |> add_noeol_if_needed 42 | |> to_lines 43 | |> Enum.map(&escape_heredoc_line/1) 44 | 45 | ([~s(""")] ++ actual ++ [~s(""")]) 46 | |> Enum.join("\n") 47 | end 48 | 49 | # Inspect protocol for String has the best implementation 50 | # of string escaping. Use it, but remove surrounding quotes 51 | # https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/inspect.ex 52 | defp escape_heredoc_line(s) do 53 | inspect(s, printable_limit: :infinity) 54 | |> String.replace(~r/(\A"|"\Z)/, "") 55 | end 56 | 57 | # "mix format" does not indent empty lines in heredocs 58 | defp indent_heredoc_line(s, indentation) do 59 | if(s == "", do: s, else: indentation <> s) 60 | end 61 | 62 | # to work as a heredoc a string must end with a newline. For 63 | # strings that don't we append a special token and a newline when 64 | # writing them to source file. This way we can look for this 65 | # special token when we read it back and strip it at that time. 66 | defp add_noeol_if_needed(arg) do 67 | if String.at(arg, -1) == "\n" do 68 | arg 69 | else 70 | arg <> "\n" 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/assert_value/parser.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.Parser do 2 | # This is internal parser error 3 | # In theory we parse any valid Elixir code and should not face it 4 | defmodule ParseError do 5 | defexception message: "Unable to parse assert_value arguments" 6 | end 7 | 8 | # Parse file with test code and returns {:ok, parsed} on success 9 | # where parsed is a map with keys: 10 | # 11 | # :prefix - code before line with assert_value 12 | # :assert_value - whole assert_value call with all arguments as it is 13 | # formatted in the code 14 | # :indentation - spaces from the beginning of the line to "assert_value" 15 | # :assert_value_prefix - everything in assert_value call before expected 16 | # as it is formatted in the code (including ==) 17 | # :expected - expected as it is formatted in the code (including quotes) 18 | # :assert_value_suffix - everything left in assert_value after expected 19 | # (closing parens, spaces, etc) 20 | # :suffix - code after last line of assert_value call (with all arguments) 21 | # 22 | # Example: 23 | # 24 | # defmodule AssertValue.DevTest do ----+ 25 | # use ExUnit.Case | 26 | # | :prefix 27 | # import AssertValue | 28 | # | 29 | # test "list" do ----+ 30 | # assert_value "foo" == "bar" :assert_value 31 | # end ----+ 32 | # | :suffix 33 | # end ----+ 34 | # 35 | # +---+-- :indentation +---+------ :expected 36 | # | | | | 37 | # assert_value "foo" == "bar" \n 38 | # | | | | 39 | # | | +--+-- :assert_value_suffix 40 | # | | 41 | # +--------------------+----------- :assert_value_prefix 42 | # 43 | # Returns {:error, :parse_error} on failure 44 | # 45 | def parse_assert_value( 46 | filename, 47 | line_num, 48 | assertion_ast, 49 | actual_ast, 50 | expected_ast 51 | ) do 52 | {prefix, suffix} = 53 | File.read!(filename) 54 | |> String.split("\n") 55 | |> Enum.split(line_num - 1) 56 | 57 | prefix = prefix |> Enum.join("\n") 58 | suffix = suffix |> Enum.join("\n") 59 | 60 | [_, indentation, assert_value, rest] = 61 | Regex.run(~r/(^\s*)(assert_value\s*)(.*)/s, suffix) 62 | 63 | prefix = prefix <> "\n" 64 | assert_value_prefix = indentation <> assert_value 65 | assert_value_suffix = "" 66 | 67 | # We enclose parsing in try/rescue because parser code is executed 68 | # inside genserver. Exceptions raised in genserver produce unreadable 69 | # Erlang error messages so it is better to pass theese exceptions outside 70 | # genserver and reraise them to show readable Elixir error messages 71 | try do 72 | {assertion, suffix} = find_ast_in_code(rest, assertion_ast) 73 | assert_value = assert_value_prefix <> assertion 74 | {assertion, left_parens, right_parens} = trim_parens(assertion) 75 | assert_value_prefix = assert_value_prefix <> left_parens 76 | assert_value_suffix = right_parens <> assert_value_suffix 77 | 78 | {assert_value_prefix, rest} = 79 | if actual_ast == :_not_present_ do 80 | {assert_value_prefix <> assertion, ""} 81 | else 82 | {actual, rest} = find_ast_in_code(assertion, actual_ast) 83 | {assert_value_prefix <> actual, rest} 84 | end 85 | 86 | {assert_value_prefix, expected, assert_value_suffix} = 87 | if expected_ast == :_not_present_ do 88 | { 89 | assert_value_prefix <> " == ", 90 | "", 91 | assert_value_suffix 92 | } 93 | else 94 | [_, operator, _, rest] = Regex.run(~r/((\)|\s)*==\s*)(.*)/s, rest) 95 | {expected, rest} = find_ast_in_code(rest, expected_ast) 96 | 97 | { 98 | assert_value_prefix <> operator, 99 | expected, 100 | rest <> assert_value_suffix 101 | } 102 | end 103 | 104 | {:ok, 105 | %{ 106 | prefix: prefix, 107 | suffix: suffix, 108 | assert_value: assert_value, 109 | assert_value_prefix: assert_value_prefix, 110 | assert_value_suffix: assert_value_suffix, 111 | expected: expected, 112 | indentation: indentation 113 | }} 114 | rescue 115 | AssertValue.Parser.ParseError -> 116 | {:error, :parse_error} 117 | end 118 | end 119 | 120 | # Private 121 | 122 | # Finds the part of the code with the same AST as second parameter 123 | # Return pair {accumulator, rest} 124 | # 125 | # iex(1) find_ast_in_code("(1 + 2) == 3", {:+, [], [1, 2]}) 126 | # #=> {"(1 + 2)", "== 3"} 127 | # 128 | # Recursively take one character from code, append it to accumulator, and 129 | # compare accumulator's AST with reference 130 | # 131 | # Corner Case: 132 | # 133 | # * floats with trailing zeros 134 | # AST for "42.00000" is 42.0 135 | # when we parse "42.00000" from code we will get mathing ast for "42.0" 136 | # and there wil be "0000" left in the code. 137 | # Since valid Elixir code cannot start with "0" we should check the 138 | # rest of the code and if it starts with "0" then we did not finish 139 | # and should continue parsing 140 | # 141 | # * function without arguments 142 | # For defined function with no args "foo" and "foo()" have the same AST 143 | # We shoul check that the rest of the code does not start with "()" 144 | # "()" without function name is invalid code in Elixir. It works but 145 | # emits "invalid expression" warning 146 | # 147 | defp find_ast_in_code(code, ast, accumulator \\ "") do 148 | if code_match_ast?(accumulator, ast) && !(code =~ ~r/^(0|\(\))/) do 149 | {accumulator, code} 150 | else 151 | case String.next_grapheme(code) do 152 | {first_grapheme, rest} -> 153 | find_ast_in_code(rest, ast, accumulator <> first_grapheme) 154 | 155 | nil -> 156 | # No more characters left and still not match? 157 | raise AssertValue.Parser.ParseError 158 | end 159 | end 160 | end 161 | 162 | # Returns true if code's AST match the second parameter 163 | # Empty code does not match anything 164 | defp code_match_ast?("", _ast), do: false 165 | 166 | defp code_match_ast?(code, ast) do 167 | case Code.string_to_quoted(code) do 168 | {:ok, quoted} -> 169 | quoted = 170 | if is_binary(quoted) do 171 | String.replace(quoted, "\\n", "") 172 | else 173 | quoted 174 | end 175 | 176 | ast_match?(quoted, ast) 177 | 178 | _ -> 179 | false 180 | end 181 | 182 | # Elixir 1.13 raises MatchError on some escape characters 183 | # https://github.com/elixir-lang/elixir/issues/11813 184 | rescue 185 | _ -> false 186 | end 187 | 188 | defp ast_match?(a, b) do 189 | # Use === to correctly match floats 190 | # In Elixir 1.0 == 1 so we should continue parsing until 1.0 === 1.0 191 | remove_ast_meta(a) === remove_ast_meta(b) 192 | end 193 | 194 | # recursively delete meta information about line numbers and 195 | # hygienic counters from AST 196 | # iex> remove_ast_meta({:foo, [line: 10, counter: 6], []}) 197 | # {:foo, [], []} 198 | defp remove_ast_meta(ast) do 199 | cleaner = &Keyword.drop(&1, [:line, :column, :counter]) 200 | Macro.prewalk(ast, &Macro.update_meta(&1, cleaner)) 201 | end 202 | 203 | # Try to trim parens and whitespaces around the code recursively 204 | # while code's AST remains the same 205 | # 206 | # Return {trimmed_code, left_parens_acc, right_parens_acc) 207 | # 208 | # trim_parens(" ( (foo ) ) ") 209 | # => {"foo", " ( (", " ) ) "} 210 | # 211 | defp trim_parens(code, left_parens_acc \\ "", right_parens_acc \\ "") do 212 | with [_, lp, trimmed, rp] <- 213 | Regex.run(~r/^(\s*\(\s*)(.*)(\s*\)\s*)$/s, code), 214 | {:ok, original_code_ast} <- Code.string_to_quoted(code), 215 | {:ok, trimmed_code_ast} <- Code.string_to_quoted(trimmed), 216 | true <- ast_match?(trimmed_code_ast, original_code_ast) do 217 | trim_parens(trimmed, left_parens_acc <> lp, rp <> right_parens_acc) 218 | else 219 | _ -> 220 | {code, left_parens_acc, right_parens_acc} 221 | end 222 | end 223 | end 224 | -------------------------------------------------------------------------------- /lib/assert_value/server.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.Server do 2 | use GenServer 3 | import AssertValue.StringTools 4 | 5 | def start_link(args) do 6 | GenServer.start_link(__MODULE__, args, name: __MODULE__) 7 | end 8 | 9 | def init(_) do 10 | env_var_name = "ASSERT_VALUE_ACCEPT_DIFFS" 11 | env_settings = System.get_env(env_var_name) 12 | # Clear environment variable for child processes 13 | System.delete_env(env_var_name) 14 | 15 | recurring_answer = 16 | cond do 17 | env_settings == "y" -> 18 | "Y" 19 | 20 | env_settings == "n" -> 21 | "N" 22 | 23 | env_settings == "reformat" -> 24 | # Store this recurring_answer as atom to make it impossible 25 | # for user to enter it on asking about diff 26 | :reformat 27 | 28 | env_settings == "ask" -> 29 | nil 30 | 31 | # ASSERT_VALUE_ACCEPT_DIFFS is set to unknown value 32 | is_binary(env_settings) -> 33 | raise """ 34 | Unknown ASSERT_VALUE_ACCEPT_DIFFS env variable value "#{env_settings}" 35 | Should be one of [y,n,ask,reformat] 36 | """ 37 | 38 | # Check that we are running in continuous integration environment 39 | # TravisCI and CircleCI have this variable 40 | System.get_env("CI") == "true" -> 41 | "N" 42 | 43 | # Elixir sets ansi_enabled env variable on start based on 44 | # "/usr/bin/test -t 1 -a -t 2" 45 | # This checks that STDOUT and STERR are terminals. If so we 46 | # can prompt user for answers. 47 | IO.ANSI.enabled?() -> 48 | nil 49 | 50 | true -> 51 | "N" 52 | end 53 | 54 | state = %{ 55 | captured_ex_unit_io_pid: nil, 56 | file_changes: %{}, 57 | recurring_answer: recurring_answer 58 | } 59 | 60 | {:ok, state} 61 | end 62 | 63 | def handle_cast({:set_captured_ex_unit_io_pid, pid}, state) do 64 | {:noreply, %{state | captured_ex_unit_io_pid: pid}} 65 | end 66 | 67 | def handle_cast({:flush_ex_unit_io}, state) do 68 | contents = StringIO.flush(state.captured_ex_unit_io_pid) 69 | if contents != "", do: IO.write(contents) 70 | {:noreply, state} 71 | end 72 | 73 | def handle_call({:reformat_expected?}, _from, state) do 74 | {:reply, state.recurring_answer == :reformat, state} 75 | end 76 | 77 | def handle_call({:ask_user_about_diff, opts}, _from, state) do 78 | # Hack: We try to wait until previous test asking about diff (and fail) will 79 | # output test results. Otherwise user will get previous failed test result 80 | # message right after the answer for current test. 81 | # TODO: Refactor to messaging 82 | Process.sleep(30) 83 | contents = StringIO.flush(state.captured_ex_unit_io_pid) 84 | if contents != "", do: IO.write(contents) 85 | 86 | case prepare_formatted_diff_and_new_code(opts, state) do 87 | {:ok, prepared} -> 88 | {answer, state} = prompt_for_action(prepared.diff, opts, state) 89 | 90 | if answer in ["y", "Y", :reformat] do 91 | file_changes = 92 | if opts[:expected_type] == :file do 93 | File.write!(opts[:expected_file], opts[:actual_value]) 94 | state.file_changes 95 | else 96 | File.write!(opts[:caller][:file], prepared.new_file_content) 97 | 98 | update_line_numbers( 99 | state.file_changes, 100 | opts[:caller][:file], 101 | opts[:caller][:line], 102 | prepared.old_assert_value, 103 | prepared.new_assert_value 104 | ) 105 | end 106 | 107 | {:reply, :ok, %{state | file_changes: file_changes}} 108 | else 109 | # Fail test. Pass exception up to the caller and throw it there 110 | {:reply, 111 | {:error, :ex_unit_assertion_error, 112 | [ 113 | left: opts[:actual_value], 114 | right: opts[:expected_value], 115 | expr: Macro.to_string(opts[:assertion_ast]), 116 | message: "AssertValue assertion failed" 117 | ]}, state} 118 | end 119 | 120 | {:error, :parse_error} -> 121 | {:reply, {:error, :parse_error}, state} 122 | end 123 | end 124 | 125 | def set_captured_ex_unit_io_pid(pid) do 126 | GenServer.cast(__MODULE__, {:set_captured_ex_unit_io_pid, pid}) 127 | end 128 | 129 | def flush_ex_unit_io do 130 | GenServer.cast(__MODULE__, {:flush_ex_unit_io}) 131 | end 132 | 133 | # All calls get :infinity timeout because GenServer may wait for user input 134 | 135 | def reformat_expected? do 136 | GenServer.call(__MODULE__, {:reformat_expected?}, :infinity) 137 | end 138 | 139 | def ask_user_about_diff(opts) do 140 | GenServer.call(__MODULE__, {:ask_user_about_diff, opts}, :infinity) 141 | end 142 | 143 | defp prepare_formatted_diff_and_new_code(opts, state) do 144 | if opts[:expected_type] == :file do 145 | {:ok, 146 | %{ 147 | diff: AssertValue.Diff.diff(opts[:expected_value], opts[:actual_value]) 148 | }} 149 | else 150 | current_line_number = 151 | current_line_number( 152 | state.file_changes, 153 | opts[:caller][:file], 154 | opts[:caller][:line] 155 | ) 156 | 157 | case AssertValue.Parser.parse_assert_value( 158 | opts[:caller][:file], 159 | current_line_number, 160 | opts[:assertion_ast], 161 | opts[:actual_ast], 162 | opts[:expected_ast] 163 | ) do 164 | {:ok, parsed} -> 165 | formatter_options = formatter_options_for_file(opts[:caller][:file]) 166 | 167 | new_expected = 168 | AssertValue.Formatter.new_expected_from_actual_value( 169 | opts[:actual_value] 170 | ) 171 | 172 | new_assert_value = 173 | parsed.assert_value_prefix <> 174 | new_expected <> 175 | parsed.assert_value_suffix 176 | 177 | # Format old assert value with formatter to diff it against 178 | # new assert_value. This way user will see only expected value 179 | # diff without mixing it with formatting diff 180 | old_assert_value = 181 | AssertValue.Formatter.format_with_indentation( 182 | parsed.assert_value, 183 | parsed.indentation, 184 | formatter_options 185 | ) 186 | 187 | new_assert_value = 188 | AssertValue.Formatter.format_with_indentation( 189 | new_assert_value, 190 | parsed.indentation, 191 | formatter_options 192 | ) 193 | 194 | diff = AssertValue.Diff.diff(old_assert_value, new_assert_value) 195 | 196 | new_file_content = parsed.prefix <> new_assert_value <> parsed.suffix 197 | 198 | {:ok, 199 | %{ 200 | diff: diff, 201 | new_file_content: new_file_content, 202 | old_assert_value: parsed.assert_value, 203 | new_assert_value: new_assert_value 204 | }} 205 | 206 | {:error, :parse_error} -> 207 | {:error, :parse_error} 208 | end 209 | end 210 | end 211 | 212 | defp prompt_for_action(diff, opts, state) do 213 | if state.recurring_answer do 214 | {state.recurring_answer, state} 215 | else 216 | print_diff_and_context(diff, opts) 217 | get_answer(diff, opts, state) 218 | end 219 | end 220 | 221 | defp print_diff_and_context(diff, opts) do 222 | file = 223 | opts[:caller][:file] 224 | # make it shorter 225 | |> Path.relative_to(File.cwd!()) 226 | 227 | line = opts[:caller][:line] 228 | # the prompt we print here should 229 | # * let user easily identify which assert failed 230 | # * work with editors's automatic go-to-error-line file:line: 231 | # format handling 232 | # * not be unreasonably long, so the user sees it on the screen 233 | # grouped with the diff 234 | {function, _} = opts[:caller][:function] 235 | # We don't need to print context when showing diff for assert_value 236 | # statement because all context is in diff. But we still need to print 237 | # context when showing diff for File.read! Because we show only diff 238 | # for file contents in that case. 239 | diff_context = 240 | if opts[:expected_type] == :file do 241 | code = opts[:assertion_ast] |> Macro.to_string() |> smart_truncate(40) 242 | "#{file}:#{line}:\"#{function}\" assert_value #{code} failed" 243 | else 244 | "#{file}:#{line}:\"#{function}\" assert_value failed" 245 | end 246 | 247 | diff_lines_count = String.split(diff, "\n") |> Enum.count() 248 | IO.puts("\n" <> diff_context <> "\n") 249 | IO.puts(diff) 250 | # If diff is too long diff context does not fit to screen 251 | # we need to repeat it 252 | if diff_lines_count > 37, do: IO.puts(diff_context) 253 | end 254 | 255 | defp get_answer(diff, opts, state) do 256 | answer = 257 | IO.gets("Accept new value? [y,n,?] ") 258 | |> String.trim_trailing("\n") 259 | 260 | case answer do 261 | "?" -> 262 | print_help() 263 | get_answer(diff, opts, state) 264 | 265 | "d" -> 266 | print_diff_and_context(diff, opts) 267 | get_answer(diff, opts, state) 268 | 269 | c when c in ["Y", "N"] -> 270 | # Save answer in state and use it in future 271 | {c, %{state | recurring_answer: c}} 272 | 273 | _ -> 274 | {answer, state} 275 | end 276 | end 277 | 278 | defp print_help do 279 | """ 280 | 281 | y - Accept new value as correct. Will update expected value. Test will pass 282 | n - Reject new value. Test will fail 283 | Y - Accept all. Will accept this and all following new values in this run 284 | N - Reject all. Will reject this and all following new values in this run 285 | d - Show diff between actual and expected values 286 | ? - This help 287 | """ 288 | # Indent all lines 289 | |> String.replace(~r/^/m, " ") 290 | |> IO.puts() 291 | end 292 | 293 | # Helpers to keep changes we make to files on updating expected values 294 | 295 | def current_line_number(file_changes, filename, original_line_number) do 296 | current_file_changes = file_changes[filename] || %{} 297 | 298 | cumulative_offset = 299 | Enum.reduce(current_file_changes, 0, fn {l, o}, total -> 300 | if original_line_number > l, do: total + o, else: total 301 | end) 302 | 303 | original_line_number + cumulative_offset 304 | end 305 | 306 | def update_line_numbers( 307 | file_changes, 308 | filename, 309 | original_line_number, 310 | old_expected, 311 | new_expected 312 | ) do 313 | offset = length(to_lines(new_expected)) - length(to_lines(old_expected)) 314 | 315 | current_file_changes = 316 | (file_changes[filename] || %{}) 317 | |> Map.put(original_line_number, offset) 318 | 319 | Map.put(file_changes, filename, current_file_changes) 320 | end 321 | 322 | # Use user's formatter options but force locals_without_parens 323 | # for assert_value 324 | defp formatter_options_for_file(file) do 325 | # Handle deprecation and maintain backward compatibility: 326 | # 327 | # * `formatter_for_file` was introduced in Elixir >= 1.13 328 | # * `formatter_opts_for_file` was deprecated in Elixir >= 1.17 329 | # 330 | # The code below calls `formatter_for_file` when available, and 331 | # falls back to `formatter_opts_for_file` in older versions 332 | # 333 | # `apply` keeps the compiler from emitting "deprecated” or 334 | # “undefined function” warnings 335 | # `apply` is considered unnecessary when the module and function names 336 | # are known, so we also suppress Credo that would normally flag it 337 | opts = 338 | if function_exported?(Mix.Tasks.Format, :formatter_for_file, 2) do 339 | # credo:disable-for-next-line 340 | {_, opts} = apply(Mix.Tasks.Format, :formatter_for_file, [file, []]) 341 | opts 342 | else 343 | # credo:disable-for-next-line 344 | apply(Mix.Tasks.Format, :formatter_opts_for_file, [file]) 345 | end 346 | 347 | # Force locals_without_parens for assert_value. We don't eval 348 | # formatter options from all user dependencies (including assert_value). 349 | # Also user may not add "import_deps: [:assert_value]" to .formatter.exs 350 | forced_options = MapSet.new(assert_value: :*) 351 | 352 | locals_without_parens = 353 | opts 354 | |> Keyword.get(:locals_without_parens, []) 355 | |> MapSet.new() 356 | |> MapSet.union(forced_options) 357 | |> MapSet.to_list() 358 | 359 | Keyword.put(opts, :locals_without_parens, locals_without_parens) 360 | end 361 | end 362 | -------------------------------------------------------------------------------- /lib/assert_value/string_tools.ex: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.StringTools do 2 | def to_lines(arg) do 3 | arg 4 | # remove trailing newline otherwise String.split will give us an 5 | # empty line at the end 6 | |> String.replace(~r/\n\Z/, "", global: false) 7 | |> String.split("\n") 8 | end 9 | 10 | def smart_truncate(s, length) when is_binary(s) and length > 0 do 11 | if String.length(s) <= length do 12 | s 13 | else 14 | s 15 | |> String.slice(0..(length - 1)) 16 | |> Kernel.<>("...") 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :assert_value, 7 | version: "0.10.5", 8 | elixir: "~> 1.7", 9 | build_embedded: Mix.env() == :prod, 10 | start_permanent: Mix.env() == :prod, 11 | description: description(), 12 | package: package(), 13 | deps: deps(), 14 | # Elixir 1.11 checks that all functions used by application belong 15 | # to modules listed in deps, applications, or extra_applications, 16 | # and emits warnings on compilation if they not. 17 | # Since IEx is a part of Elixir and always present we can skip 18 | # this check and suppress warning about IEx.Info.info/1 19 | xref: [exclude: [{IEx.Info, :info, 1}]] 20 | ] 21 | end 22 | 23 | # Configuration for the OTP application 24 | # 25 | # Type "mix help compile.app" for more information 26 | def application do 27 | [ 28 | applications: [], 29 | mod: {AssertValue.App, []} 30 | ] 31 | end 32 | 33 | # Dependencies can be Hex packages: 34 | # 35 | # {:mydep, "~> 0.3.0"} 36 | # 37 | # Or git/path repositories: 38 | # 39 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} 40 | # 41 | # Type "mix help deps" for more examples and options 42 | defp deps do 43 | [ 44 | {:credo, "~> 1.7", only: :dev, runtime: false}, 45 | {:ex_doc, ">= 0.0.0", only: :dev} 46 | ] 47 | end 48 | 49 | defp description do 50 | "ExUnit's assert on steroids that writes and updates tests for you" 51 | end 52 | 53 | defp package do 54 | [ 55 | files: [ 56 | "lib", 57 | ".formatter.exs", 58 | "mix.exs", 59 | "README.md", 60 | "CHANGELOG.md", 61 | "LICENSE" 62 | ], 63 | maintainers: ["Gleb Arshinov", "Serge Smetana"], 64 | licenses: ["MIT"], 65 | links: %{ 66 | "GitHub" => "https://github.com/assert-value/assert_value_elixir", 67 | "Changelog" => 68 | "https://github.com/assert-value/assert_value_elixir/blob/master/CHANGELOG.md" 69 | } 70 | ] 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /test/bad_arguments_test.exs: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.BadArgumentsTest do 2 | use ExUnit.Case, async: true 3 | 4 | defmodule User do 5 | defstruct name: "John", age: 27 6 | end 7 | 8 | import AssertValue 9 | 10 | test "bad actual and no expected" do 11 | f = fn -> true end 12 | 13 | assert_raise AssertValue.ArgumentError, fn -> 14 | assert_value f 15 | end 16 | 17 | task = Task.async(f) 18 | 19 | assert_raise AssertValue.ArgumentError, fn -> 20 | assert_value task.pid 21 | end 22 | 23 | assert_raise AssertValue.ArgumentError, fn -> 24 | assert_value task.ref 25 | end 26 | 27 | {:ok, port} = :gen_udp.open(0) 28 | 29 | assert_raise AssertValue.ArgumentError, fn -> 30 | assert_value port 31 | end 32 | 33 | Port.close(port) 34 | end 35 | 36 | test "bad actual" do 37 | f = fn -> true end 38 | g = fn -> true end 39 | 40 | assert_raise AssertValue.ArgumentError, fn -> 41 | assert_value f == g 42 | end 43 | 44 | task = Task.async(f) 45 | 46 | assert_raise AssertValue.ArgumentError, fn -> 47 | assert_value task.pid == :foo 48 | end 49 | 50 | assert_raise AssertValue.ArgumentError, fn -> 51 | assert_value task.ref == :foo 52 | end 53 | 54 | {:ok, port} = :gen_udp.open(0) 55 | 56 | assert_raise AssertValue.ArgumentError, fn -> 57 | assert_value port == :foo 58 | end 59 | 60 | Port.close(port) 61 | end 62 | 63 | test "left argument for File.read!" do 64 | assert_raise AssertValue.ArgumentError, fn -> 65 | assert_value nil == File.read!("file.txt") 66 | end 67 | 68 | assert_raise AssertValue.ArgumentError, fn -> 69 | assert_value true == File.read!("file.txt") 70 | end 71 | 72 | assert_raise AssertValue.ArgumentError, fn -> 73 | assert_value false == File.read!("file.txt") 74 | end 75 | 76 | assert_raise AssertValue.ArgumentError, fn -> 77 | assert_value :foo == File.read!("file.txt") 78 | end 79 | 80 | assert_raise AssertValue.ArgumentError, fn -> 81 | assert_value to_charlist("0") == File.read!("any.txt") 82 | end 83 | 84 | assert_raise AssertValue.ArgumentError, fn -> 85 | assert_value ~D[2018-01-01] == File.read!("any.txt") 86 | end 87 | 88 | assert_raise AssertValue.ArgumentError, fn -> 89 | assert_value 0.1 == File.read!("any.txt") 90 | end 91 | 92 | assert_raise AssertValue.ArgumentError, fn -> 93 | assert_value 1 == File.read!("any.txt") 94 | end 95 | 96 | assert_raise AssertValue.ArgumentError, fn -> 97 | assert_value [] == File.read!("any.txt") 98 | end 99 | 100 | assert_raise AssertValue.ArgumentError, fn -> 101 | assert_value %{} == File.read!("any.txt") 102 | end 103 | 104 | assert_raise AssertValue.ArgumentError, fn -> 105 | assert_value ~N[2018-01-01 21:01:50] == File.read!("any.txt") 106 | end 107 | 108 | assert_raise AssertValue.ArgumentError, fn -> 109 | assert_value ~T[23:00:07] == File.read!("any.txt") 110 | end 111 | 112 | assert_raise AssertValue.ArgumentError, fn -> 113 | assert_value {:ok} == File.read!("any.txt") 114 | end 115 | 116 | assert_raise AssertValue.ArgumentError, fn -> 117 | assert_value %User{} == File.read!("any.txt") 118 | end 119 | end 120 | 121 | test "nested not-serializable type" do 122 | f = fn -> true end 123 | g = fn -> true end 124 | 125 | assert_raise AssertValue.ArgumentError, fn -> 126 | assert_value %{f: f} 127 | end 128 | 129 | assert_raise AssertValue.ArgumentError, fn -> 130 | assert_value %{x: f} == %{x: g} 131 | end 132 | end 133 | 134 | test "big maps" do 135 | big_map = 136 | 1..64 137 | |> Enum.reduce(%{}, fn x, acc -> 138 | Map.put(acc, to_string(x), x) 139 | end) 140 | 141 | assert_value big_map == %{ 142 | "61" => 61, 143 | "58" => 58, 144 | "49" => 49, 145 | "10" => 10, 146 | "37" => 37, 147 | "24" => 24, 148 | "14" => 14, 149 | "12" => 12, 150 | "42" => 42, 151 | "36" => 36, 152 | "16" => 16, 153 | "4" => 4, 154 | "26" => 26, 155 | "64" => 64, 156 | "34" => 34, 157 | "32" => 32, 158 | "46" => 46, 159 | "8" => 8, 160 | "5" => 5, 161 | "3" => 3, 162 | "19" => 19, 163 | "9" => 9, 164 | "7" => 7, 165 | "50" => 50, 166 | "55" => 55, 167 | "13" => 13, 168 | "44" => 44, 169 | "52" => 52, 170 | "57" => 57, 171 | "2" => 2, 172 | "45" => 45, 173 | "11" => 11, 174 | "40" => 40, 175 | "15" => 15, 176 | "29" => 29, 177 | "17" => 17, 178 | "63" => 63, 179 | "25" => 25, 180 | "39" => 39, 181 | "28" => 28, 182 | "54" => 54, 183 | "59" => 59, 184 | "18" => 18, 185 | "27" => 27, 186 | "35" => 35, 187 | "23" => 23, 188 | "31" => 31, 189 | "43" => 43, 190 | "6" => 6, 191 | "41" => 41, 192 | "30" => 30, 193 | "20" => 20, 194 | "22" => 22, 195 | "21" => 21, 196 | "62" => 62, 197 | "56" => 56, 198 | "48" => 48, 199 | "38" => 38, 200 | "51" => 51, 201 | "47" => 47, 202 | "1" => 1, 203 | "60" => 60, 204 | "33" => 33, 205 | "53" => 53 206 | } 207 | end 208 | 209 | test "long bitstring" do 210 | bitstring = String.duplicate(<<1>>, 51) 211 | 212 | assert_value bitstring == 213 | <<1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 214 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 215 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1>> 216 | end 217 | end 218 | -------------------------------------------------------------------------------- /test/file_tracker_test.exs: -------------------------------------------------------------------------------- 1 | defmodule AssertValue.FileTrackerTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue.Server, 5 | only: [current_line_number: 3, update_line_numbers: 5] 6 | 7 | test "cumulative offsets" do 8 | file_changes = %{} 9 | assert current_line_number(file_changes, "~/test.exs", 2) == 2 10 | 11 | file_changes = 12 | update_line_numbers(file_changes, "~/test.exs", 5, "1\n2\n3", "1") 13 | 14 | assert current_line_number(file_changes, "~/test.exs", 2) == 2 15 | assert current_line_number(file_changes, "~/test.exs", 6) == 4 16 | 17 | file_changes = 18 | update_line_numbers( 19 | file_changes, 20 | "~/test.exs", 21 | 2, 22 | "1\n2", 23 | "1\n2\n3\n4\n5" 24 | ) 25 | 26 | assert current_line_number(file_changes, "~/test.exs", 6) == 7 27 | 28 | file_changes = 29 | update_line_numbers( 30 | file_changes, 31 | "~/test.exs", 32 | 10, 33 | "0\n1\n2\n3\n4", 34 | "0\n1\n2\n3\n4\n5\n6\n7\n8\n9" 35 | ) 36 | 37 | assert current_line_number(file_changes, "~/test.exs", 10) == 11 38 | assert current_line_number(file_changes, "~/test.exs", 11) == 17 39 | end 40 | 41 | test "different files" do 42 | file_changes = %{} 43 | assert current_line_number(file_changes, "~/first_test.exs", 2) == 2 44 | 45 | file_changes = 46 | file_changes 47 | |> update_line_numbers("~/first_test.exs", 5, "0\n1\n2", "0") 48 | |> update_line_numbers("~/first_test.exs", 7, "0", "0\n1\n2\n3") 49 | |> update_line_numbers("~/second_test.exs", 2, "0", "0\n1\n2\n3") 50 | |> update_line_numbers("~/second_test.exs", 5, "0", "0\n1") 51 | 52 | assert current_line_number(file_changes, "~/first_test.exs", 6) == 4 53 | assert current_line_number(file_changes, "~/first_test.exs", 7) == 5 54 | assert current_line_number(file_changes, "~/first_test.exs", 8) == 9 55 | assert current_line_number(file_changes, "~/second_test.exs", 1) == 1 56 | assert current_line_number(file_changes, "~/second_test.exs", 2) == 2 57 | assert current_line_number(file_changes, "~/second_test.exs", 3) == 6 58 | assert current_line_number(file_changes, "~/second_test.exs", 6) == 10 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /test/integration/accept_all_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule AcceptAllTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: Y 7 | 8 | test "all pass" do 9 | assert_value "foo\nbar" == """ 10 | foo 11 | bar 12 | """ 13 | assert_value "foo\nbaz" == """ 14 | foo 15 | baz 16 | """ 17 | end 18 | 19 | test "all pass again" do 20 | assert_value "foo\nfoo" == """ 21 | foo 22 | foo 23 | """ 24 | assert_value "bar\nbar" == """ 25 | bar 26 | bar 27 | """ 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/integration/accept_all_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule AcceptAllTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: Y 7 | 8 | test "all pass" do 9 | assert_value "foo\nbar" == """ 10 | bar 11 | """ 12 | assert_value "foo\nbaz" == """ 13 | baz 14 | """ 15 | end 16 | 17 | test "all pass again" do 18 | assert_value "foo\nfoo" == """ 19 | foo 20 | """ 21 | assert_value "bar\nbar" == """ 22 | baz 23 | """ 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /test/integration/accept_all_test.exs.output: -------------------------------------------------------------------------------- 1 | accept_all_test.exs:##:"test all pass" assert_value failed 2 | 3 | assert_value "foo\nbar" == """ 4 | + foo 5 | bar 6 | """ 7 | 8 | Accept new value? [y,n,?] .. 9 | 2 tests, 0 failures 10 | -------------------------------------------------------------------------------- /test/integration/accept_all_with_error_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule AcceptAllWithErrorTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: Y 7 | 8 | test "all pass" do 9 | assert_value "foo" == "foo" 10 | assert_value "foo\nbar" == """ 11 | foo 12 | bar 13 | """ 14 | assert_value "foo\nbaz" == """ 15 | foo 16 | baz 17 | """ 18 | end 19 | 20 | test "one fail with error" do 21 | assert_value "foo" == "foo" 22 | assert_value "foo" == "foo" 23 | assert_value "foo\nbaz" == """ 24 | foo 25 | baz 26 | """ 27 | raise "Error!" 28 | end 29 | 30 | test "all pass again" do 31 | assert_value "foo\nfoo" == """ 32 | foo 33 | foo 34 | """ 35 | assert_value "bar\nbar" == """ 36 | bar 37 | bar 38 | """ 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /test/integration/accept_all_with_error_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule AcceptAllWithErrorTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: Y 7 | 8 | test "all pass" do 9 | assert_value "foo" 10 | assert_value "foo\nbar" == """ 11 | bar 12 | """ 13 | assert_value "foo\nbaz" == """ 14 | baz 15 | """ 16 | end 17 | 18 | test "one fail with error" do 19 | assert_value "foo" 20 | assert_value "foo" == "bar" 21 | assert_value "foo\nbaz" == """ 22 | baz 23 | """ 24 | raise "Error!" 25 | end 26 | 27 | test "all pass again" do 28 | assert_value "foo\nfoo" == """ 29 | foo 30 | """ 31 | assert_value "bar\nbar" == """ 32 | bar 33 | """ 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /test/integration/accept_all_with_error_test.exs.output: -------------------------------------------------------------------------------- 1 | accept_all_with_error_test.exs:##:"test all pass" assert_value failed 2 | 3 | - assert_value "foo" 4 | + assert_value "foo" == "foo" 5 | 6 | Accept new value? [y,n,?] . 7 | 8 | 1) test one fail with error (AcceptAllWithErrorTest) 9 | accept_all_with_error_test.exs:## 10 | ** (RuntimeError) Error! 11 | stacktrace: 12 | accept_all_with_error_test.exs:##: (test) 13 | 14 | . 15 | 3 tests, 1 failure 16 | -------------------------------------------------------------------------------- /test/integration/decline_all_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule DeclineAllTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: N 7 | 8 | test "all fail" do 9 | assert_value "foo" == """ 10 | bar 11 | """ 12 | assert_value "foo" == """ 13 | baz 14 | """ 15 | end 16 | 17 | test "all pass" do 18 | assert_value "foo" == """ 19 | foo 20 | """ 21 | assert_value "foo" == """ 22 | foo 23 | """ 24 | end 25 | 26 | test "all fail again" do 27 | assert_value "foo" == """ 28 | bar 29 | """ 30 | assert_value "bar" == """ 31 | baz 32 | """ 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /test/integration/decline_all_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule DeclineAllTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | # prompt: N 7 | 8 | test "all fail" do 9 | assert_value "foo" == """ 10 | bar 11 | """ 12 | assert_value "foo" == """ 13 | baz 14 | """ 15 | end 16 | 17 | test "all pass" do 18 | assert_value "foo" == """ 19 | foo 20 | """ 21 | assert_value "foo" == """ 22 | foo 23 | """ 24 | end 25 | 26 | test "all fail again" do 27 | assert_value "foo" == """ 28 | bar 29 | """ 30 | assert_value "bar" == """ 31 | baz 32 | """ 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /test/integration/decline_all_test.exs.output: -------------------------------------------------------------------------------- 1 | decline_all_test.exs:##:"test all fail" assert_value failed 2 | 3 | - assert_value "foo" == """ 4 | - bar 5 | - """ 6 | + assert_value "foo" == "foo" 7 | 8 | Accept new value? [y,n,?] 9 | 10 | 1) test all fail (DeclineAllTest) 11 | decline_all_test.exs:## 12 | AssertValue assertion failed 13 | code: "foo" == "bar\n" 14 | left: "foo" 15 | right: "bar" 16 | stacktrace: 17 | decline_all_test.exs:##: (test) 18 | 19 | . 20 | 21 | 2) test all fail again (DeclineAllTest) 22 | decline_all_test.exs:## 23 | AssertValue assertion failed 24 | code: "foo" == "bar\n" 25 | left: "foo" 26 | right: "bar" 27 | stacktrace: 28 | decline_all_test.exs:##: (test) 29 | 3 tests, 2 failures 30 | -------------------------------------------------------------------------------- /test/integration/decline_all_test.exs.output.1.10: -------------------------------------------------------------------------------- 1 | decline_all_test.exs:##:"test all fail" assert_value failed 2 | 3 | - assert_value "foo" == """ 4 | - bar 5 | - """ 6 | + assert_value "foo" == "foo" 7 | 8 | Accept new value? [y,n,?] 9 | 10 | 1) test all fail (DeclineAllTest) 11 | decline_all_test.exs:## 12 | AssertValue assertion failed 13 | code: "\"foo\" == \"bar\\n\"" 14 | left: "foo" 15 | right: "bar" 16 | stacktrace: 17 | decline_all_test.exs:##: (test) 18 | 19 | . 20 | 21 | 2) test all fail again (DeclineAllTest) 22 | decline_all_test.exs:## 23 | AssertValue assertion failed 24 | code: "\"foo\" == \"bar\\n\"" 25 | left: "foo" 26 | right: "bar" 27 | stacktrace: 28 | decline_all_test.exs:##: (test) 29 | 3 tests, 2 failures 30 | -------------------------------------------------------------------------------- /test/integration/diff_and_help_prompt_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule DiffAndHelpPromptTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "promt help and accept" do 7 | # prompt: ? 8 | # prompt: y 9 | assert_value "foo" == "foo" 10 | end 11 | 12 | test "promt help then diff then fail" do 13 | # prompt: ? 14 | # prompt: d 15 | # prompt: n 16 | assert_value "foo" 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /test/integration/diff_and_help_prompt_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule DiffAndHelpPromptTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "promt help and accept" do 7 | # prompt: ? 8 | # prompt: y 9 | assert_value "foo" 10 | end 11 | 12 | test "promt help then diff then fail" do 13 | # prompt: ? 14 | # prompt: d 15 | # prompt: n 16 | assert_value "foo" 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /test/integration/diff_and_help_prompt_test.exs.output: -------------------------------------------------------------------------------- 1 | diff_and_help_prompt_test.exs:##:"test promt help and accept" assert_value failed 2 | 3 | - assert_value "foo" 4 | + assert_value "foo" == "foo" 5 | 6 | Accept new value? [y,n,?] 7 | y - Accept new value as correct. Will update expected value. Test will pass 8 | n - Reject new value. Test will fail 9 | Y - Accept all. Will accept this and all following new values in this run 10 | N - Reject all. Will reject this and all following new values in this run 11 | d - Show diff between actual and expected values 12 | ? - This help 13 | 14 | Accept new value? [y,n,?] . 15 | diff_and_help_prompt_test.exs:##:"test promt help then diff then fail" assert_value failed 16 | 17 | - assert_value "foo" 18 | + assert_value "foo" == "foo" 19 | 20 | Accept new value? [y,n,?] 21 | y - Accept new value as correct. Will update expected value. Test will pass 22 | n - Reject new value. Test will fail 23 | Y - Accept all. Will accept this and all following new values in this run 24 | N - Reject all. Will reject this and all following new values in this run 25 | d - Show diff between actual and expected values 26 | ? - This help 27 | 28 | Accept new value? [y,n,?] 29 | diff_and_help_prompt_test.exs:##:"test promt help then diff then fail" assert_value failed 30 | 31 | - assert_value "foo" 32 | + assert_value "foo" == "foo" 33 | 34 | Accept new value? [y,n,?] 35 | 36 | 1) test promt help then diff then fail (DiffAndHelpPromptTest) 37 | diff_and_help_prompt_test.exs:## 38 | AssertValue assertion failed 39 | code: "foo" 40 | left: "foo" 41 | right: nil 42 | stacktrace: 43 | diff_and_help_prompt_test.exs:##: (test) 44 | 2 tests, 1 failure 45 | -------------------------------------------------------------------------------- /test/integration/diff_and_help_prompt_test.exs.output.1.10: -------------------------------------------------------------------------------- 1 | diff_and_help_prompt_test.exs:##:"test promt help and accept" assert_value failed 2 | 3 | - assert_value "foo" 4 | + assert_value "foo" == "foo" 5 | 6 | Accept new value? [y,n,?] 7 | y - Accept new value as correct. Will update expected value. Test will pass 8 | n - Reject new value. Test will fail 9 | Y - Accept all. Will accept this and all following new values in this run 10 | N - Reject all. Will reject this and all following new values in this run 11 | d - Show diff between actual and expected values 12 | ? - This help 13 | 14 | Accept new value? [y,n,?] . 15 | diff_and_help_prompt_test.exs:##:"test promt help then diff then fail" assert_value failed 16 | 17 | - assert_value "foo" 18 | + assert_value "foo" == "foo" 19 | 20 | Accept new value? [y,n,?] 21 | y - Accept new value as correct. Will update expected value. Test will pass 22 | n - Reject new value. Test will fail 23 | Y - Accept all. Will accept this and all following new values in this run 24 | N - Reject all. Will reject this and all following new values in this run 25 | d - Show diff between actual and expected values 26 | ? - This help 27 | 28 | Accept new value? [y,n,?] 29 | diff_and_help_prompt_test.exs:##:"test promt help then diff then fail" assert_value failed 30 | 31 | - assert_value "foo" 32 | + assert_value "foo" == "foo" 33 | 34 | Accept new value? [y,n,?] 35 | 36 | 1) test promt help then diff then fail (DiffAndHelpPromptTest) 37 | diff_and_help_prompt_test.exs:## 38 | AssertValue assertion failed 39 | code: "\"foo\"" 40 | left: "foo" 41 | right: nil 42 | stacktrace: 43 | diff_and_help_prompt_test.exs:##: (test) 44 | 2 tests, 1 failure 45 | -------------------------------------------------------------------------------- /test/integration/diff_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule DiffTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | def f_nil() do 7 | # The way to dynamically generate nil, to avoid "type violation" warnings 8 | List.first([]) 9 | end 10 | 11 | def f_int() do 12 | 1 13 | end 14 | 15 | def f_str() do 16 | # Dynamic binary to avoid "type violation" warnings 17 | Enum.join(~w[aaa bbb ccc ddd eee fff] ++ [""], "\n") 18 | end 19 | 20 | test "empty string" do 21 | # prompt: y 22 | assert_value "" == "" 23 | end 24 | 25 | test "nil" do 26 | # prompt: y 27 | assert_value f_nil() == nil 28 | 29 | # prompt: y 30 | assert_value f_nil() == nil 31 | end 32 | 33 | test "integer and string" do 34 | # prompt: y 35 | assert_value f_int() == 1 36 | end 37 | 38 | 39 | test "diff" do 40 | a = """ 41 | aaa 42 | bbb 43 | ccc 44 | ddd 45 | eee 46 | fff 47 | """ 48 | b = """ 49 | aaa 50 | xxx 51 | ddd 52 | eee 53 | fff 54 | GGG 55 | """ 56 | 57 | # prompt: y 58 | assert_value a == """ 59 | aaa 60 | bbb 61 | ccc 62 | ddd 63 | eee 64 | fff 65 | """ 66 | 67 | # prompt: y 68 | assert_value f_nil() == nil 69 | 70 | # prompt: y 71 | assert_value f_str() == """ 72 | aaa 73 | bbb 74 | ccc 75 | ddd 76 | eee 77 | fff 78 | """ 79 | end 80 | 81 | test "char list diff" do 82 | # prompt: y 83 | assert_value ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" == 84 | 'aaa\nbbb\nccc\nddd\neee\nfff\n' 85 | end 86 | 87 | end 88 | -------------------------------------------------------------------------------- /test/integration/diff_test.exs.after.1.15: -------------------------------------------------------------------------------- 1 | defmodule DiffTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | def f_nil() do 7 | # The way to dynamically generate nil, to avoid "type violation" warnings 8 | List.first([]) 9 | end 10 | 11 | def f_int() do 12 | 1 13 | end 14 | 15 | def f_str() do 16 | # Dynamic binary to avoid "type violation" warnings 17 | Enum.join(~w[aaa bbb ccc ddd eee fff] ++ [""], "\n") 18 | end 19 | 20 | test "empty string" do 21 | # prompt: y 22 | assert_value "" == "" 23 | end 24 | 25 | test "nil" do 26 | # prompt: y 27 | assert_value f_nil() == nil 28 | 29 | # prompt: y 30 | assert_value f_nil() == nil 31 | end 32 | 33 | test "integer and string" do 34 | # prompt: y 35 | assert_value f_int() == 1 36 | end 37 | 38 | 39 | test "diff" do 40 | a = """ 41 | aaa 42 | bbb 43 | ccc 44 | ddd 45 | eee 46 | fff 47 | """ 48 | b = """ 49 | aaa 50 | xxx 51 | ddd 52 | eee 53 | fff 54 | GGG 55 | """ 56 | 57 | # prompt: y 58 | assert_value a == """ 59 | aaa 60 | bbb 61 | ccc 62 | ddd 63 | eee 64 | fff 65 | """ 66 | 67 | # prompt: y 68 | assert_value f_nil() == nil 69 | 70 | # prompt: y 71 | assert_value f_str() == """ 72 | aaa 73 | bbb 74 | ccc 75 | ddd 76 | eee 77 | fff 78 | """ 79 | end 80 | 81 | test "char list diff" do 82 | # prompt: y 83 | assert_value ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" == 84 | ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" 85 | end 86 | 87 | end 88 | -------------------------------------------------------------------------------- /test/integration/diff_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule DiffTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | def f_nil() do 7 | # The way to dynamically generate nil, to avoid "type violation" warnings 8 | List.first([]) 9 | end 10 | 11 | def f_int() do 12 | 1 13 | end 14 | 15 | def f_str() do 16 | # Dynamic binary to avoid "type violation" warnings 17 | Enum.join(~w[aaa bbb ccc ddd eee fff] ++ [""], "\n") 18 | end 19 | 20 | test "empty string" do 21 | # prompt: y 22 | assert_value "" 23 | end 24 | 25 | test "nil" do 26 | # prompt: y 27 | assert_value f_nil() == "" 28 | 29 | # prompt: y 30 | assert_value f_nil() == 1 31 | end 32 | 33 | test "integer and string" do 34 | # prompt: y 35 | assert_value f_int() == "1" 36 | end 37 | 38 | 39 | test "diff" do 40 | a = """ 41 | aaa 42 | bbb 43 | ccc 44 | ddd 45 | eee 46 | fff 47 | """ 48 | b = """ 49 | aaa 50 | xxx 51 | ddd 52 | eee 53 | fff 54 | GGG 55 | """ 56 | 57 | # prompt: y 58 | assert_value a == b 59 | 60 | # prompt: y 61 | assert_value f_nil() == b 62 | 63 | # prompt: y 64 | assert_value f_str() == nil 65 | end 66 | 67 | test "char list diff" do 68 | # prompt: y 69 | assert_value ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" == 70 | ~c"aaa\nxxx\nddd\neee\nfff\nGGG\n" 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /test/integration/diff_test.exs.output: -------------------------------------------------------------------------------- 1 | diff_test.exs:##:"test empty string" assert_value failed 2 | 3 | - assert_value "" 4 | + assert_value "" == "" 5 | 6 | Accept new value? [y,n,?] . 7 | diff_test.exs:##:"test nil" assert_value failed 8 | 9 | - assert_value f_nil() == "" 10 | + assert_value f_nil() == nil 11 | 12 | Accept new value? [y,n,?] 13 | diff_test.exs:##:"test nil" assert_value failed 14 | 15 | - assert_value f_nil() == 1 16 | + assert_value f_nil() == nil 17 | 18 | Accept new value? [y,n,?] . 19 | diff_test.exs:##:"test integer and string" assert_value failed 20 | 21 | - assert_value f_int() == "1" 22 | + assert_value f_int() == 1 23 | 24 | Accept new value? [y,n,?] . 25 | diff_test.exs:##:"test diff" assert_value failed 26 | 27 | - assert_value a == b 28 | + assert_value a == """ 29 | + aaa 30 | + bbb 31 | + ccc 32 | + ddd 33 | + eee 34 | + fff 35 | + """ 36 | 37 | Accept new value? [y,n,?] 38 | diff_test.exs:##:"test diff" assert_value failed 39 | 40 | - assert_value f_nil() == b 41 | + assert_value f_nil() == nil 42 | 43 | Accept new value? [y,n,?] 44 | diff_test.exs:##:"test diff" assert_value failed 45 | 46 | - assert_value f_str() == nil 47 | + assert_value f_str() == """ 48 | + aaa 49 | + bbb 50 | + ccc 51 | + ddd 52 | + eee 53 | + fff 54 | + """ 55 | 56 | Accept new value? [y,n,?] . 57 | diff_test.exs:##:"test char list diff" assert_value failed 58 | 59 | assert_value ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" == 60 | - ~c"aaa\nxxx\nddd\neee\nfff\nGGG\n" 61 | + 'aaa\nbbb\nccc\nddd\neee\nfff\n' 62 | 63 | Accept new value? [y,n,?] . 64 | 5 tests, 0 failures 65 | -------------------------------------------------------------------------------- /test/integration/diff_test.exs.output.1.15: -------------------------------------------------------------------------------- 1 | diff_test.exs:##:"test empty string" assert_value failed 2 | 3 | - assert_value "" 4 | + assert_value "" == "" 5 | 6 | Accept new value? [y,n,?] . 7 | diff_test.exs:##:"test nil" assert_value failed 8 | 9 | - assert_value f_nil() == "" 10 | + assert_value f_nil() == nil 11 | 12 | Accept new value? [y,n,?] 13 | diff_test.exs:##:"test nil" assert_value failed 14 | 15 | - assert_value f_nil() == 1 16 | + assert_value f_nil() == nil 17 | 18 | Accept new value? [y,n,?] . 19 | diff_test.exs:##:"test integer and string" assert_value failed 20 | 21 | - assert_value f_int() == "1" 22 | + assert_value f_int() == 1 23 | 24 | Accept new value? [y,n,?] . 25 | diff_test.exs:##:"test diff" assert_value failed 26 | 27 | - assert_value a == b 28 | + assert_value a == """ 29 | + aaa 30 | + bbb 31 | + ccc 32 | + ddd 33 | + eee 34 | + fff 35 | + """ 36 | 37 | Accept new value? [y,n,?] 38 | diff_test.exs:##:"test diff" assert_value failed 39 | 40 | - assert_value f_nil() == b 41 | + assert_value f_nil() == nil 42 | 43 | Accept new value? [y,n,?] 44 | diff_test.exs:##:"test diff" assert_value failed 45 | 46 | - assert_value f_str() == nil 47 | + assert_value f_str() == """ 48 | + aaa 49 | + bbb 50 | + ccc 51 | + ddd 52 | + eee 53 | + fff 54 | + """ 55 | 56 | Accept new value? [y,n,?] . 57 | diff_test.exs:##:"test char list diff" assert_value failed 58 | 59 | assert_value ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" == 60 | - ~c"aaa\nxxx\nddd\neee\nfff\nGGG\n" 61 | + ~c"aaa\nbbb\nccc\nddd\neee\nfff\n" 62 | 63 | Accept new value? [y,n,?] . 64 | 5 tests, 0 failures 65 | -------------------------------------------------------------------------------- /test/integration/file_to_create.after: -------------------------------------------------------------------------------- 1 | aaa 2 | bbb 3 | ccc 4 | -------------------------------------------------------------------------------- /test/integration/file_to_update.after: -------------------------------------------------------------------------------- 1 | aaa 2 | bbb 3 | ccc 4 | -------------------------------------------------------------------------------- /test/integration/file_to_update.before: -------------------------------------------------------------------------------- 1 | aaa 2 | bBb 3 | ccc 4 | -------------------------------------------------------------------------------- /test/integration/formatter_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule FormatterTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "integer variants" do 7 | # prompt: y 8 | assert_value 42_000_000 == 42_000_000 9 | 10 | # prompt: y 11 | assert_value 42.0e-5 == 4.2e-4 12 | 13 | # prompt: y 14 | assert_value 43.0e+5 == 4.3e6 15 | 16 | # prompt: y 17 | assert_value 42.0e15 == 4.2e16 18 | 19 | # prompt: y 20 | assert_value 0x2A == 42 21 | end 22 | 23 | test "multiline strings" do 24 | # prompt: y 25 | assert_value "foo\nbar" == """ 26 | foo 27 | bar 28 | """ 29 | end 30 | 31 | test "long arrays" do 32 | # prompt: y 33 | assert_value [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] == [ 34 | 0, 35 | 1, 36 | 2, 37 | 3, 38 | 4, 39 | 5, 40 | 6, 41 | 7, 42 | 8, 43 | 9, 44 | 10 45 | ] 46 | end 47 | 48 | test "long strings" do 49 | # prompt: y 50 | assert_value String.duplicate("a", 5000) == 51 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /test/integration/formatter_test.exs.after.1.14: -------------------------------------------------------------------------------- 1 | defmodule FormatterTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "integer variants" do 7 | # prompt: y 8 | assert_value 42_000_000 == 42_000_000 9 | 10 | # prompt: y 11 | assert_value 42.0e-5 == 4.2e-4 12 | 13 | # prompt: y 14 | assert_value 43.0e+5 == 4_300_000.0 15 | 16 | # prompt: y 17 | assert_value 42.0e15 == 4.2e16 18 | 19 | # prompt: y 20 | assert_value 0x2A == 42 21 | end 22 | 23 | test "multiline strings" do 24 | # prompt: y 25 | assert_value "foo\nbar" == """ 26 | foo 27 | bar 28 | """ 29 | end 30 | 31 | test "long arrays" do 32 | # prompt: y 33 | assert_value [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] == [ 34 | 0, 35 | 1, 36 | 2, 37 | 3, 38 | 4, 39 | 5, 40 | 6, 41 | 7, 42 | 8, 43 | 9, 44 | 10 45 | ] 46 | end 47 | 48 | test "long strings" do 49 | # prompt: y 50 | assert_value String.duplicate("a", 5000) == 51 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /test/integration/formatter_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule FormatterTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "integer variants" do 7 | # prompt: y 8 | assert_value 42_000_000 9 | 10 | # prompt: y 11 | assert_value 42.0e-5 12 | 13 | # prompt: y 14 | assert_value 43.0e+5 15 | 16 | # prompt: y 17 | assert_value 42.0e15 18 | 19 | # prompt: y 20 | assert_value 0x2A 21 | end 22 | 23 | test "multiline strings" do 24 | # prompt: y 25 | assert_value "foo\nbar" 26 | end 27 | 28 | test "long arrays" do 29 | # prompt: y 30 | assert_value [0,1,2,3,4,5,6,7,8,9,10] == [0,1,2,3,5,5,5,7,8,9,10] 31 | end 32 | 33 | test "long strings" do 34 | # prompt: y 35 | assert_value String.duplicate("a", 5000) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /test/integration/formatter_test.exs.output: -------------------------------------------------------------------------------- 1 | formatter_test.exs:##:"test integer variants" assert_value failed 2 | 3 | - assert_value 42_000_000 4 | + assert_value 42_000_000 == 42_000_000 5 | 6 | Accept new value? [y,n,?] 7 | formatter_test.exs:##:"test integer variants" assert_value failed 8 | 9 | - assert_value 42.0e-5 10 | + assert_value 42.0e-5 == 4.2e-4 11 | 12 | Accept new value? [y,n,?] 13 | formatter_test.exs:##:"test integer variants" assert_value failed 14 | 15 | - assert_value 43.0e+5 16 | + assert_value 43.0e+5 == 4.3e6 17 | 18 | Accept new value? [y,n,?] 19 | formatter_test.exs:##:"test integer variants" assert_value failed 20 | 21 | - assert_value 42.0e15 22 | + assert_value 42.0e15 == 4.2e16 23 | 24 | Accept new value? [y,n,?] 25 | formatter_test.exs:##:"test integer variants" assert_value failed 26 | 27 | - assert_value 0x2A 28 | + assert_value 0x2A == 42 29 | 30 | Accept new value? [y,n,?] . 31 | formatter_test.exs:##:"test multiline strings" assert_value failed 32 | 33 | - assert_value "foo\nbar" 34 | + assert_value "foo\nbar" == """ 35 | + foo 36 | + bar 37 | + """ 38 | 39 | Accept new value? [y,n,?] . 40 | formatter_test.exs:##:"test long arrays" assert_value failed 41 | 42 | assert_value [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] == [ 43 | 0, 44 | 1, 45 | 2, 46 | 3, 47 | + 4, 48 | 5, 49 | - 5, 50 | - 5, 51 | + 6, 52 | 7, 53 | 8, 54 | 9, 55 | 10 56 | ] 57 | 58 | Accept new value? [y,n,?] . 59 | formatter_test.exs:##:"test long strings" assert_value failed 60 | 61 | - assert_value String.duplicate("a", 5000) 62 | + assert_value String.duplicate("a", 5000) == 63 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 64 | 65 | Accept new value? [y,n,?] . 66 | 4 tests, 0 failures 67 | -------------------------------------------------------------------------------- /test/integration/formatter_test.exs.output.1.14: -------------------------------------------------------------------------------- 1 | formatter_test.exs:##:"test integer variants" assert_value failed 2 | 3 | - assert_value 42_000_000 4 | + assert_value 42_000_000 == 42_000_000 5 | 6 | Accept new value? [y,n,?] 7 | formatter_test.exs:##:"test integer variants" assert_value failed 8 | 9 | - assert_value 42.0e-5 10 | + assert_value 42.0e-5 == 4.2e-4 11 | 12 | Accept new value? [y,n,?] 13 | formatter_test.exs:##:"test integer variants" assert_value failed 14 | 15 | - assert_value 43.0e+5 16 | + assert_value 43.0e+5 == 4_300_000.0 17 | 18 | Accept new value? [y,n,?] 19 | formatter_test.exs:##:"test integer variants" assert_value failed 20 | 21 | - assert_value 42.0e15 22 | + assert_value 42.0e15 == 4.2e16 23 | 24 | Accept new value? [y,n,?] 25 | formatter_test.exs:##:"test integer variants" assert_value failed 26 | 27 | - assert_value 0x2A 28 | + assert_value 0x2A == 42 29 | 30 | Accept new value? [y,n,?] . 31 | formatter_test.exs:##:"test multiline strings" assert_value failed 32 | 33 | - assert_value "foo\nbar" 34 | + assert_value "foo\nbar" == """ 35 | + foo 36 | + bar 37 | + """ 38 | 39 | Accept new value? [y,n,?] . 40 | formatter_test.exs:##:"test long arrays" assert_value failed 41 | 42 | assert_value [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] == [ 43 | 0, 44 | 1, 45 | 2, 46 | 3, 47 | + 4, 48 | 5, 49 | - 5, 50 | - 5, 51 | + 6, 52 | 7, 53 | 8, 54 | 9, 55 | 10 56 | ] 57 | 58 | Accept new value? [y,n,?] . 59 | formatter_test.exs:##:"test long strings" assert_value failed 60 | 61 | - assert_value String.duplicate("a", 5000) 62 | + assert_value String.duplicate("a", 5000) == 63 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 64 | 65 | Accept new value? [y,n,?] . 66 | 4 tests, 0 failures 67 | -------------------------------------------------------------------------------- /test/integration/misc_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule MiscTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "simple pass" do 7 | assert_value 1 == 1 8 | end 9 | 10 | test "reprompt context" do 11 | actual = String.duplicate("line\n", 38) 12 | # prompt: y 13 | assert_value actual == """ 14 | line 15 | line 16 | line 17 | line 18 | line 19 | line 20 | line 21 | line 22 | line 23 | line 24 | line 25 | line 26 | line 27 | line 28 | line 29 | line 30 | line 31 | line 32 | line 33 | line 34 | line 35 | line 36 | line 37 | line 38 | line 39 | line 40 | line 41 | line 42 | line 43 | line 44 | line 45 | line 46 | line 47 | line 48 | line 49 | line 50 | line 51 | line 52 | """ 53 | end 54 | 55 | # tests with prompt answer n go below here 56 | 57 | test "simple fail" do 58 | actual = """ 59 | aaa 60 | bbb 61 | ccc 62 | """ 63 | # prompt: n 64 | assert_value actual == """ 65 | aaa 66 | bBb 67 | ccc 68 | """ 69 | end 70 | 71 | test "escaped string" do 72 | actual = ~s["foo"] 73 | # prompt: n 74 | assert_value actual == "\"bar\"" 75 | end 76 | 77 | end 78 | -------------------------------------------------------------------------------- /test/integration/misc_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule MiscTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "simple pass" do 7 | assert_value 1 == 1 8 | end 9 | 10 | test "reprompt context" do 11 | actual = String.duplicate("line\n", 38) 12 | # prompt: y 13 | assert_value actual 14 | end 15 | 16 | # tests with prompt answer n go below here 17 | 18 | test "simple fail" do 19 | actual = """ 20 | aaa 21 | bbb 22 | ccc 23 | """ 24 | # prompt: n 25 | assert_value actual == """ 26 | aaa 27 | bBb 28 | ccc 29 | """ 30 | end 31 | 32 | test "escaped string" do 33 | actual = ~s["foo"] 34 | # prompt: n 35 | assert_value actual == "\"bar\"" 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /test/integration/misc_test.exs.output: -------------------------------------------------------------------------------- 1 | . 2 | misc_test.exs:##:"test reprompt context" assert_value failed 3 | 4 | - assert_value actual 5 | + assert_value actual == """ 6 | + line 7 | + line 8 | + line 9 | + line 10 | + line 11 | + line 12 | + line 13 | + line 14 | + line 15 | + line 16 | + line 17 | + line 18 | + line 19 | + line 20 | + line 21 | + line 22 | + line 23 | + line 24 | + line 25 | + line 26 | + line 27 | + line 28 | + line 29 | + line 30 | + line 31 | + line 32 | + line 33 | + line 34 | + line 35 | + line 36 | + line 37 | + line 38 | + line 39 | + line 40 | + line 41 | + line 42 | + line 43 | + line 44 | + """ 45 | 46 | misc_test.exs:##:"test reprompt context" assert_value failed 47 | Accept new value? [y,n,?] . 48 | misc_test.exs:##:"test simple fail" assert_value failed 49 | 50 | assert_value actual == """ 51 | aaa 52 | - bBb 53 | + bbb 54 | ccc 55 | """ 56 | 57 | Accept new value? [y,n,?] 58 | 59 | 1) test simple fail (MiscTest) 60 | misc_test.exs:## 61 | AssertValue assertion failed 62 | code: actual == "aaa\nbBb\nccc\n" 63 | left: "aaa\nbbb\nccc\n" 64 | right: "aaa\nbBb\nccc\n" 65 | stacktrace: 66 | misc_test.exs:##: (test) 67 | 68 | 69 | misc_test.exs:##:"test escaped string" assert_value failed 70 | 71 | - assert_value actual == "\"bar\"" 72 | + assert_value actual == "\"foo\"" 73 | 74 | Accept new value? [y,n,?] 75 | 76 | 2) test escaped string (MiscTest) 77 | misc_test.exs:## 78 | AssertValue assertion failed 79 | code: actual == "\"bar\"" 80 | left: "\"foo\"" 81 | right: "\"bar\"" 82 | stacktrace: 83 | misc_test.exs:##: (test) 84 | 4 tests, 2 failures 85 | -------------------------------------------------------------------------------- /test/integration/misc_test.exs.output.1.10: -------------------------------------------------------------------------------- 1 | . 2 | misc_test.exs:##:"test reprompt context" assert_value failed 3 | 4 | - assert_value actual 5 | + assert_value actual == """ 6 | + line 7 | + line 8 | + line 9 | + line 10 | + line 11 | + line 12 | + line 13 | + line 14 | + line 15 | + line 16 | + line 17 | + line 18 | + line 19 | + line 20 | + line 21 | + line 22 | + line 23 | + line 24 | + line 25 | + line 26 | + line 27 | + line 28 | + line 29 | + line 30 | + line 31 | + line 32 | + line 33 | + line 34 | + line 35 | + line 36 | + line 37 | + line 38 | + line 39 | + line 40 | + line 41 | + line 42 | + line 43 | + line 44 | + """ 45 | 46 | misc_test.exs:##:"test reprompt context" assert_value failed 47 | Accept new value? [y,n,?] . 48 | misc_test.exs:##:"test simple fail" assert_value failed 49 | 50 | assert_value actual == """ 51 | aaa 52 | - bBb 53 | + bbb 54 | ccc 55 | """ 56 | 57 | Accept new value? [y,n,?] 58 | 59 | 1) test simple fail (MiscTest) 60 | misc_test.exs:## 61 | AssertValue assertion failed 62 | code: "actual == \"aaa\\nbBb\\nccc\\n\"" 63 | left: "aaa\nbbb\nccc\n" 64 | right: "aaa\nbBb\nccc\n" 65 | stacktrace: 66 | misc_test.exs:##: (test) 67 | 68 | 69 | misc_test.exs:##:"test escaped string" assert_value failed 70 | 71 | - assert_value actual == "\"bar\"" 72 | + assert_value actual == "\"foo\"" 73 | 74 | Accept new value? [y,n,?] 75 | 76 | 2) test escaped string (MiscTest) 77 | misc_test.exs:## 78 | AssertValue assertion failed 79 | code: "actual == \"\\\"bar\\\"\"" 80 | left: "\"foo\"" 81 | right: "\"bar\"" 82 | stacktrace: 83 | misc_test.exs:##: (test) 84 | 4 tests, 2 failures 85 | -------------------------------------------------------------------------------- /test/integration/non_interactive_accept_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule NonInteractiveAcceptTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "update" do 7 | assert_value "foo\nbar" == """ 8 | foo 9 | bar 10 | """ 11 | end 12 | 13 | test "update again" do 14 | assert_value "foo\nbaz" == """ 15 | foo 16 | baz 17 | """ 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /test/integration/non_interactive_accept_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule NonInteractiveAcceptTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "update" do 7 | assert_value "foo\nbar" == """ 8 | bar 9 | """ 10 | end 11 | 12 | test "update again" do 13 | assert_value "foo\nbaz" == """ 14 | baz 15 | """ 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/non_interactive_accept_test.exs.output: -------------------------------------------------------------------------------- 1 | .. 2 | 2 tests, 0 failures 3 | -------------------------------------------------------------------------------- /test/integration/non_interactive_reject_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule NonInteractiveRejectTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "fail" do 7 | assert_value "foo\nbar" == """ 8 | bar 9 | """ 10 | end 11 | 12 | test "fail again" do 13 | assert_value "foo\nbaz" == """ 14 | baz 15 | """ 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/non_interactive_reject_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule NonInteractiveRejectTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "fail" do 7 | assert_value "foo\nbar" == """ 8 | bar 9 | """ 10 | end 11 | 12 | test "fail again" do 13 | assert_value "foo\nbaz" == """ 14 | baz 15 | """ 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/non_interactive_reject_test.exs.output: -------------------------------------------------------------------------------- 1 | 1) test fail (NonInteractiveRejectTest) 2 | non_interactive_reject_test.exs:## 3 | AssertValue assertion failed 4 | code: "foo\nbar" == "bar\n" 5 | left: "foo\nbar" 6 | right: "bar" 7 | stacktrace: 8 | non_interactive_reject_test.exs:##: (test) 9 | 10 | 11 | 12 | 2) test fail again (NonInteractiveRejectTest) 13 | non_interactive_reject_test.exs:## 14 | AssertValue assertion failed 15 | code: "foo\nbaz" == "baz\n" 16 | left: "foo\nbaz" 17 | right: "baz" 18 | stacktrace: 19 | non_interactive_reject_test.exs:##: (test) 20 | 2 tests, 2 failures 21 | -------------------------------------------------------------------------------- /test/integration/non_interactive_reject_test.exs.output.1.10: -------------------------------------------------------------------------------- 1 | 1) test fail (NonInteractiveRejectTest) 2 | non_interactive_reject_test.exs:## 3 | AssertValue assertion failed 4 | code: "\"foo\\nbar\" == \"bar\\n\"" 5 | left: "foo\nbar" 6 | right: "bar" 7 | stacktrace: 8 | non_interactive_reject_test.exs:##: (test) 9 | 10 | 11 | 12 | 2) test fail again (NonInteractiveRejectTest) 13 | non_interactive_reject_test.exs:## 14 | AssertValue assertion failed 15 | code: "\"foo\\nbaz\" == \"baz\\n\"" 16 | left: "foo\nbaz" 17 | right: "baz" 18 | stacktrace: 19 | non_interactive_reject_test.exs:##: (test) 20 | 2 tests, 2 failures 21 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | import AssertValue 16 | 17 | # Literals 18 | 19 | test "actual literals" do 20 | # prompt: y 21 | assert_value nil == nil 22 | 23 | # prompt: y 24 | assert_value true == true 25 | 26 | # prompt: y 27 | assert_value false == false 28 | 29 | # prompt: y 30 | assert_value :foo == :foo 31 | 32 | # prompt: y 33 | assert_value "forty-two" == "forty-two" 34 | 35 | # prompt: y 36 | assert_value """ 37 | forty-two 38 | сорок два 39 | 四十二 40 | quarante deux 41 | cuarenta y dos 42 | zweiundvierzig 43 | """ == """ 44 | forty-two 45 | сорок два 46 | 四十二 47 | quarante deux 48 | cuarenta y dos 49 | zweiundvierzig 50 | """ 51 | 52 | # prompt: y 53 | assert_value ~S(forty-two) == "forty-two" 54 | 55 | # prompt: y 56 | assert_value ~s(forty-two) == "forty-two" 57 | 58 | # prompt: y 59 | assert_value <<65, 66, 67>> == "ABC" 60 | 61 | # prompt: y 62 | assert_value <<256::utf8>> == "Ā" 63 | 64 | # prompt: y 65 | assert_value 'forty-two' == 'forty-two' 66 | 67 | # prompt: y 68 | assert_value ''' 69 | forty-two 70 | сорок два 71 | ''' == [ 72 | 102, 73 | 111, 74 | 114, 75 | 116, 76 | 121, 77 | 45, 78 | 116, 79 | 119, 80 | 111, 81 | 10, 82 | 1089, 83 | 1086, 84 | 1088, 85 | 1086, 86 | 1082, 87 | 32, 88 | 1076, 89 | 1074, 90 | 1072, 91 | 10 92 | ] 93 | # prompt: y 94 | assert_value ~C(forty-two) == 'forty-two' 95 | 96 | # prompt: y 97 | assert_value ~c(forty-two) == 'forty-two' 98 | 99 | # prompt: y 100 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 101 | 102 | # prompt: y 103 | assert_value 0.42 == 0.42 104 | 105 | # prompt: y 106 | assert_value -0.42 == -0.42 107 | 108 | # prompt: y 109 | assert_value 42 == 42 110 | 111 | # prompt: y 112 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 113 | 114 | # prompt: y 115 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 116 | 117 | # prompt: y 118 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 119 | 120 | # prompt: y 121 | assert_value ~r/foo/ == ~r/foo/ 122 | 123 | # prompt: y 124 | assert_value ~T[23:00:07] == ~T[23:00:07] 125 | 126 | # prompt: y 127 | assert_value {:ok, 42} == {:ok, 42} 128 | 129 | # prompt: y 130 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 131 | 132 | # prompt: y 133 | assert_value %User{age: 43} == %ParserTest.User{age: 43, name: "John"} 134 | 135 | # prompt: y 136 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 137 | %ParserTest.User{age: 21, name: "Peter"} 138 | 139 | # prompt: y 140 | assert_value ~W(foo bar) == ["foo", "bar"] 141 | 142 | # prompt: y 143 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 144 | %{ 145 | a: 42, 146 | b: {:left, :light}, 147 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 148 | }, 149 | nil 150 | ] 151 | end 152 | 153 | test "actual and expected literals" do 154 | # prompt: y 155 | assert_value nil == nil 156 | 157 | # prompt: y 158 | assert_value true == true 159 | 160 | # prompt: y 161 | assert_value :foo == :foo 162 | 163 | # prompt: y 164 | assert_value "forty-two" == "forty-two" 165 | 166 | # prompt: y 167 | assert_value """ 168 | forty-two 169 | сорок два 170 | 四十二 171 | quarante deux 172 | cuarenta y dos 173 | zweiundvierzig 174 | """ == """ 175 | forty-two 176 | сорок два 177 | 四十二 178 | quarante deux 179 | cuarenta y dos 180 | zweiundvierzig 181 | """ 182 | 183 | # prompt: y 184 | assert_value ~S(forty-two) == "forty-two" 185 | 186 | # prompt: y 187 | assert_value ~s(forty-two) == "forty-two" 188 | 189 | # prompt: y 190 | assert_value <<65, 66, 67>> == "ABC" 191 | 192 | # prompt: y 193 | assert_value <<256::utf8>> == "Ā" 194 | 195 | # prompt: y 196 | assert_value 'forty-two' == 'forty-two' 197 | 198 | # prompt: y 199 | assert_value ''' 200 | forty-two 201 | сорок два 202 | ''' == [ 203 | 102, 204 | 111, 205 | 114, 206 | 116, 207 | 121, 208 | 45, 209 | 116, 210 | 119, 211 | 111, 212 | 10, 213 | 1089, 214 | 1086, 215 | 1088, 216 | 1086, 217 | 1082, 218 | 32, 219 | 1076, 220 | 1074, 221 | 1072, 222 | 10 223 | ] 224 | 225 | # prompt: y 226 | assert_value ~C(forty-two) == 'forty-two' 227 | 228 | # prompt: y 229 | assert_value ~c(forty-two) == 'forty-two' 230 | 231 | # prompt: y 232 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 233 | 234 | # prompt: y 235 | assert_value 0.42 == 0.42 236 | 237 | # prompt: y 238 | assert_value -0.42 == -0.42 239 | 240 | # prompt: y 241 | assert_value 42 == 42 242 | 243 | # prompt: y 244 | assert_value -42 == -42 245 | 246 | # prompt: y 247 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 248 | 249 | # prompt: y 250 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 251 | 252 | # prompt: y 253 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 254 | 255 | # prompt: y 256 | assert_value ~T[23:00:07] == ~T[23:00:07] 257 | 258 | # prompt: y 259 | assert_value {:ok, 42} == {:ok, 42} 260 | 261 | # prompt: y 262 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 263 | 264 | # prompt: y 265 | assert_value %User{age: 42} == %ParserTest.User{age: 42, name: "John"} 266 | 267 | # This should pass 268 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 269 | 270 | # prompt: y 271 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 272 | %ParserTest.User{age: 21, name: "Peter"} 273 | 274 | # prompt: y 275 | assert_value ~W(foo bar) == ["foo", "bar"] 276 | 277 | # prompt: y 278 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 279 | %{ 280 | a: 42, 281 | b: {:left, :light}, 282 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 283 | }, 284 | nil 285 | ] 286 | end 287 | 288 | test "expected literal" do 289 | # prompt: y 290 | assert_value "foo" == "foo" 291 | 292 | # prompt: y 293 | assert_value "foo" == "foo" 294 | 295 | # prompt: y 296 | assert_value "foo" == "foo" 297 | 298 | # prompt: y 299 | assert_value "foo" == "foo" 300 | 301 | # prompt: y 302 | assert_value "foo" == "foo" 303 | 304 | # prompt: y 305 | assert_value "foo" == "foo" 306 | 307 | # prompt: y 308 | assert_value "foo" == "foo" 309 | 310 | # prompt: y 311 | assert_value "foo" == "foo" 312 | 313 | # prompt: y 314 | assert_value "foo" == "foo" 315 | 316 | # prompt: y 317 | assert_value "foo" == "foo" 318 | 319 | # prompt: y 320 | assert_value "foo" == "foo" 321 | 322 | # prompt: y 323 | assert_value "foo" == "foo" 324 | 325 | # prompt: y 326 | assert_value "foo" == "foo" 327 | 328 | # prompt: y 329 | assert_value "foo" == "foo" 330 | 331 | # prompt: y 332 | assert_value "foo" == "foo" 333 | 334 | # prompt: y 335 | assert_value "foo" == "foo" 336 | 337 | # prompt: y 338 | assert_value "foo" == "foo" 339 | 340 | # prompt: y 341 | assert_value "foo" == "foo" 342 | 343 | # prompt: y 344 | assert_value "foo" == "foo" 345 | 346 | # prompt: y 347 | assert_value "foo" == "foo" 348 | 349 | # prompt: y 350 | assert_value "foo" == "foo" 351 | 352 | # prompt: y 353 | assert_value "foo" == "foo" 354 | 355 | # prompt: y 356 | assert_value "foo" == "foo" 357 | 358 | # prompt: y 359 | assert_value "foo" == "foo" 360 | 361 | # prompt: y 362 | assert_value "foo" == "foo" 363 | 364 | # prompt: y 365 | assert_value "foo" == "foo" 366 | 367 | # prompt: y 368 | assert_value "foo" == "foo" 369 | 370 | # prompt: y 371 | assert_value "foo" == "foo" 372 | 373 | # prompt: y 374 | assert_value "foo" == "foo" 375 | end 376 | 377 | test "create file" do 378 | # prompt: y 379 | assert_value """ 380 | aaa 381 | bbb 382 | ccc 383 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 384 | end 385 | 386 | test "update file" do 387 | # prompt: y 388 | assert_value """ 389 | aaa 390 | bbb 391 | ccc 392 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 393 | end 394 | 395 | # Corner cases 396 | 397 | test "spaces around equation" do 398 | # prompt: y 399 | assert_value "foo" == "foo" 400 | 401 | # prompt: y 402 | assert_value "foo" == "foo" 403 | 404 | # prompt: y 405 | assert_value "foo" == "foo" 406 | 407 | # prompt: y 408 | assert_value "foo" == "foo" 409 | 410 | # prompt: y 411 | assert_value "foo" == "foo" 412 | 413 | # prompt: y 414 | assert_value "foo" == "foo" 415 | end 416 | 417 | test "string escaping" do 418 | # prompt: y 419 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo\\nbar\" \" \t \r %{}" 420 | 421 | # prompt: y 422 | assert_value "foo" == "foo" 423 | end 424 | 425 | test "float trailing zeros" do 426 | # prompt: y 427 | assert_value 42.0001000 == 42.0001 428 | 429 | # prompt: y 430 | assert_value -42.0001000 == -42.0001 431 | end 432 | 433 | test "bitstring and string" do 434 | assert_value <<65>> == "A" 435 | # prompt: y 436 | assert_value <<66>> == "B" 437 | 438 | assert_value "A" == <<65>> 439 | # prompt: y 440 | assert_value "B" == "B" 441 | end 442 | 443 | # Expressions 444 | 445 | test "variable" do 446 | foo = "foo" 447 | bar = "bar" 448 | 449 | # prompt: y 450 | assert_value foo == "foo" 451 | 452 | # prompt: y 453 | assert_value foo == "foo" 454 | end 455 | 456 | test "module attributes" do 457 | # prompt: y 458 | assert_value @foo == "foo" 459 | 460 | # prompt: y 461 | assert_value @foo == "foo" 462 | 463 | # prompt: y 464 | assert_value "foo" == @foo 465 | end 466 | 467 | test "parens" do 468 | # prompt: y 469 | assert_value("foo" == "foo") 470 | 471 | # prompt: y 472 | assert_value "foo" == "foo" 473 | 474 | # prompt: y 475 | assert_value("foo" == "foo") 476 | 477 | # prompt: y 478 | assert_value "foo" == "foo" 479 | 480 | # prompt: y 481 | assert_value("foo" == "foo") 482 | 483 | # prompt: y 484 | assert_value "foo" == "foo" 485 | 486 | # prompt: y 487 | assert_value("foo" == "foo") 488 | 489 | # prompt: y 490 | assert_value "foo" == "foo" 491 | 492 | # prompt: y 493 | assert_value "foo" == "foo" 494 | 495 | # prompt: y 496 | assert_value "foo" == "foo" 497 | 498 | # prompt: y 499 | assert_value("foo" == "foo") 500 | 501 | # prompt: y 502 | assert_value "foo" == "foo" 503 | 504 | # prompt: y 505 | assert_value("foo" == "foo") 506 | end 507 | 508 | test "left/right expressions" do 509 | foo = "foo" 510 | bar = "bar" 511 | 512 | # prompt: y 513 | assert_value foo <> "bar" == "foobar" 514 | 515 | # prompt: y 516 | assert_value foo <> "bar" == "foobar" 517 | 518 | # prompt: y 519 | assert_value foo <> "bar" == "foobar" 520 | 521 | # prompt: y 522 | assert_value foo <> "bar" == "foobar" 523 | end 524 | 525 | test "functions" do 526 | hello = fn(x) -> 527 | "Hello " <> x <> "!" 528 | end 529 | 530 | # prompt: y 531 | assert_value String.upcase("foo") == "FOO" 532 | 533 | # prompt: y 534 | assert_value hello.("World") == "Hello World!" 535 | 536 | # prompt: y 537 | assert_value String.upcase("foo") == "FOO" 538 | 539 | # prompt: y 540 | assert_value hello.("World") == "Hello World!" 541 | 542 | # prompt: y 543 | assert_value String.upcase("foo") == "FOO" 544 | end 545 | 546 | test "pipes" do 547 | # prompt: y 548 | assert_value String.upcase("foo") |> String.reverse() == "OOF" 549 | 550 | # prompt: y 551 | assert_value String.upcase("foo") 552 | |> String.reverse() == "OOF" 553 | end 554 | 555 | test "repeatable expressions" do 556 | # prompt: y 557 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 558 | 559 | # prompt: y 560 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 561 | 562 | # prompt: y 563 | assert_value 5 == 5 564 | end 565 | 566 | test "AST cleanup" do 567 | # Macro.expand below produces AST with hygienic counter 568 | # Check that we can correctly parse it 569 | # Last String.replace is to produce the same result code 570 | # from different Elixirs. 1.6.0 has slightly different 571 | # "if" macro. 572 | 573 | assert_value quote(do: Kernel.||(1, false)) 574 | |> Macro.expand(__ENV__) 575 | |> Macro.to_string() 576 | |> String.replace( 577 | "when x in [false, nil]", 578 | "when Kernel.in(x, [false, nil])" 579 | ) == """ 580 | case(1) do 581 | x when Kernel.in(x, [false, nil]) -> 582 | false 583 | x -> 584 | x 585 | end 586 | """ 587 | end 588 | 589 | test "function without arguments" do 590 | # prompt: y 591 | assert_value Foo.foo() == "foo" 592 | 593 | # prompt: y 594 | assert_value Foo.foo() == "foo" 595 | end 596 | 597 | test "not-serializable expected" do 598 | # This should pass. We can successfully parse expected and replace 599 | # it with serialized value 600 | # prompt: y 601 | assert_value :foo == :foo 602 | end 603 | 604 | test "integer floats" do 605 | # prompt: y 606 | assert_value 2 == 2 607 | 608 | # prompt: y 609 | assert_value 1.0 == 1.0 610 | end 611 | 612 | end 613 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.after.1.13: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | def f_nil() do 16 | # The way to dynamically generate nil, to avoid "type violation" warnings 17 | List.first([]) 18 | end 19 | 20 | def f_false() do 21 | List.first([false]) 22 | end 23 | 24 | def f_true() do 25 | List.first([true]) 26 | end 27 | 28 | def f_atom_foo() do 29 | List.first([:foo]) 30 | end 31 | 32 | def f_atom_bar() do 33 | List.first([:bar]) 34 | end 35 | 36 | import AssertValue 37 | 38 | # Literals 39 | 40 | test "actual literals" do 41 | # prompt: y 42 | assert_value nil == nil 43 | 44 | # prompt: y 45 | assert_value true == true 46 | 47 | # prompt: y 48 | assert_value false == false 49 | 50 | # prompt: y 51 | assert_value :foo == :foo 52 | 53 | # prompt: y 54 | assert_value "forty-two" == "forty-two" 55 | 56 | # prompt: y 57 | assert_value """ 58 | forty-two 59 | сорок два 60 | 四十二 61 | quarante deux 62 | cuarenta y dos 63 | zweiundvierzig 64 | """ == """ 65 | forty-two 66 | сорок два 67 | 四十二 68 | quarante deux 69 | cuarenta y dos 70 | zweiundvierzig 71 | """ 72 | 73 | # prompt: y 74 | assert_value ~S(forty-two) == "forty-two" 75 | 76 | # prompt: y 77 | assert_value ~s(forty-two) == "forty-two" 78 | 79 | # prompt: y 80 | assert_value <<65, 66, 67>> == "ABC" 81 | 82 | # prompt: y 83 | assert_value <<256::utf8>> == "Ā" 84 | 85 | # prompt: y 86 | assert_value ~c"forty-two" == 'forty-two' 87 | 88 | # prompt: y 89 | assert_value ~c""" 90 | forty-two 91 | сорок два 92 | """ == [ 93 | 102, 94 | 111, 95 | 114, 96 | 116, 97 | 121, 98 | 45, 99 | 116, 100 | 119, 101 | 111, 102 | 10, 103 | 1089, 104 | 1086, 105 | 1088, 106 | 1086, 107 | 1082, 108 | 32, 109 | 1076, 110 | 1074, 111 | 1072, 112 | 10 113 | ] 114 | # prompt: y 115 | assert_value ~C(forty-two) == 'forty-two' 116 | 117 | # prompt: y 118 | assert_value ~c(forty-two) == 'forty-two' 119 | 120 | # prompt: y 121 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 122 | 123 | # prompt: y 124 | assert_value 0.42 == 0.42 125 | 126 | # prompt: y 127 | assert_value -0.42 == -0.42 128 | 129 | # prompt: y 130 | assert_value 42 == 42 131 | 132 | # prompt: y 133 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 134 | 135 | # prompt: y 136 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 137 | 138 | # prompt: y 139 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 140 | 141 | # prompt: y 142 | assert_value ~r/foo/ == ~r/foo/ 143 | 144 | # prompt: y 145 | assert_value ~T[23:00:07] == ~T[23:00:07] 146 | 147 | # prompt: y 148 | assert_value {:ok, 42} == {:ok, 42} 149 | 150 | # prompt: y 151 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 152 | 153 | # prompt: y 154 | assert_value %User{age: 43} == %ParserTest.User{age: 43, name: "John"} 155 | 156 | # prompt: y 157 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 158 | %ParserTest.User{age: 21, name: "Peter"} 159 | 160 | # prompt: y 161 | assert_value ~W(foo bar) == ["foo", "bar"] 162 | 163 | # prompt: y 164 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 165 | %{ 166 | a: 42, 167 | b: {:left, :light}, 168 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 169 | }, 170 | nil 171 | ] 172 | end 173 | 174 | test "actual and expected literals" do 175 | # prompt: y 176 | assert_value nil == nil 177 | 178 | # prompt: y 179 | assert_value true == true 180 | 181 | # prompt: y 182 | assert_value :foo == :foo 183 | 184 | # prompt: y 185 | assert_value "forty-two" == "forty-two" 186 | 187 | # prompt: y 188 | assert_value """ 189 | forty-two 190 | сорок два 191 | 四十二 192 | quarante deux 193 | cuarenta y dos 194 | zweiundvierzig 195 | """ == """ 196 | forty-two 197 | сорок два 198 | 四十二 199 | quarante deux 200 | cuarenta y dos 201 | zweiundvierzig 202 | """ 203 | 204 | # prompt: y 205 | assert_value ~S(forty-two) == "forty-two" 206 | 207 | # prompt: y 208 | assert_value ~s(forty-two) == "forty-two" 209 | 210 | # prompt: y 211 | assert_value <<65, 66, 67>> == "ABC" 212 | 213 | # prompt: y 214 | assert_value <<256::utf8>> == "Ā" 215 | 216 | # prompt: y 217 | assert_value ~c"forty-two" == 'forty-two' 218 | 219 | # prompt: y 220 | assert_value ~c""" 221 | forty-two 222 | сорок два 223 | """ == [ 224 | 102, 225 | 111, 226 | 114, 227 | 116, 228 | 121, 229 | 45, 230 | 116, 231 | 119, 232 | 111, 233 | 10, 234 | 1089, 235 | 1086, 236 | 1088, 237 | 1086, 238 | 1082, 239 | 32, 240 | 1076, 241 | 1074, 242 | 1072, 243 | 10 244 | ] 245 | 246 | # prompt: y 247 | assert_value ~C(forty-two) == 'forty-two' 248 | 249 | # prompt: y 250 | assert_value ~c(forty-two) == 'forty-two' 251 | 252 | # prompt: y 253 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 254 | 255 | # prompt: y 256 | assert_value 0.42 == 0.42 257 | 258 | # prompt: y 259 | assert_value -0.42 == -0.42 260 | 261 | # prompt: y 262 | assert_value 42 == 42 263 | 264 | # prompt: y 265 | assert_value -42 == -42 266 | 267 | # prompt: y 268 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 269 | 270 | # prompt: y 271 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 272 | 273 | # prompt: y 274 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 275 | 276 | # prompt: y 277 | assert_value ~T[23:00:07] == ~T[23:00:07] 278 | 279 | # prompt: y 280 | assert_value {:ok, 42} == {:ok, 42} 281 | 282 | # prompt: y 283 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 284 | 285 | # prompt: y 286 | assert_value %User{age: 42} == %ParserTest.User{age: 42, name: "John"} 287 | 288 | # This should pass 289 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 290 | 291 | # prompt: y 292 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 293 | %ParserTest.User{age: 21, name: "Peter"} 294 | 295 | # prompt: y 296 | assert_value ~W(foo bar) == ["foo", "bar"] 297 | 298 | # prompt: y 299 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 300 | %{ 301 | a: 42, 302 | b: {:left, :light}, 303 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 304 | }, 305 | nil 306 | ] 307 | end 308 | 309 | test "expected literal" do 310 | # prompt: y 311 | assert_value Foo.foo() == "foo" 312 | 313 | # prompt: y 314 | assert_value Foo.foo() == "foo" 315 | 316 | # prompt: y 317 | assert_value Foo.foo() == "foo" 318 | 319 | # prompt: y 320 | assert_value Foo.foo() == "foo" 321 | 322 | # prompt: y 323 | assert_value Foo.foo() == "foo" 324 | 325 | # prompt: y 326 | assert_value Foo.foo() == "foo" 327 | 328 | # prompt: y 329 | assert_value Foo.foo() == "foo" 330 | 331 | # prompt: y 332 | assert_value Foo.foo() == "foo" 333 | 334 | # prompt: y 335 | assert_value Foo.foo() == "foo" 336 | 337 | # prompt: y 338 | assert_value Foo.foo() == "foo" 339 | 340 | # prompt: y 341 | assert_value Foo.foo() == "foo" 342 | 343 | # prompt: y 344 | assert_value Foo.foo() == "foo" 345 | 346 | # prompt: y 347 | assert_value Foo.foo() == "foo" 348 | 349 | # prompt: y 350 | assert_value Foo.foo() == "foo" 351 | 352 | # prompt: y 353 | assert_value Foo.foo() == "foo" 354 | 355 | # prompt: y 356 | assert_value Foo.foo() == "foo" 357 | 358 | # prompt: y 359 | assert_value Foo.foo() == "foo" 360 | 361 | # prompt: y 362 | assert_value Foo.foo() == "foo" 363 | 364 | # prompt: y 365 | assert_value Foo.foo() == "foo" 366 | 367 | # prompt: y 368 | assert_value Foo.foo() == "foo" 369 | 370 | # prompt: y 371 | assert_value Foo.foo() == "foo" 372 | 373 | # prompt: y 374 | assert_value Foo.foo() == "foo" 375 | 376 | # prompt: y 377 | assert_value Foo.foo() == "foo" 378 | 379 | # prompt: y 380 | assert_value Foo.foo() == "foo" 381 | 382 | # prompt: y 383 | assert_value Foo.foo() == "foo" 384 | 385 | # prompt: y 386 | assert_value Foo.foo() == "foo" 387 | 388 | # prompt: y 389 | assert_value Foo.foo() == "foo" 390 | 391 | # prompt: y 392 | assert_value Foo.foo() == "foo" 393 | 394 | # prompt: y 395 | assert_value Foo.foo() == "foo" 396 | end 397 | 398 | test "create file" do 399 | # prompt: y 400 | assert_value """ 401 | aaa 402 | bbb 403 | ccc 404 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 405 | end 406 | 407 | test "update file" do 408 | # prompt: y 409 | assert_value """ 410 | aaa 411 | bbb 412 | ccc 413 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 414 | end 415 | 416 | # Corner cases 417 | 418 | test "spaces around equation" do 419 | # prompt: y 420 | assert_value "foo" == "foo" 421 | 422 | # prompt: y 423 | assert_value "foo" == "foo" 424 | 425 | # prompt: y 426 | assert_value "foo" == "foo" 427 | 428 | # prompt: y 429 | assert_value "foo" == "foo" 430 | 431 | # prompt: y 432 | assert_value "foo" == "foo" 433 | 434 | # prompt: y 435 | assert_value "foo" == "foo" 436 | end 437 | 438 | test "string escaping" do 439 | # prompt: y 440 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo\\nbar\" \" \t \r %{}" 441 | 442 | # prompt: y 443 | assert_value "foo" == "foo" 444 | end 445 | 446 | test "float trailing zeros" do 447 | # prompt: y 448 | assert_value 42.0001000 == 42.0001 449 | 450 | # prompt: y 451 | assert_value -42.0001000 == -42.0001 452 | end 453 | 454 | test "bitstring and string" do 455 | assert_value <<65>> == "A" 456 | # prompt: y 457 | assert_value <<66>> == "B" 458 | 459 | assert_value "A" == <<65>> 460 | # prompt: y 461 | assert_value "B" == "B" 462 | end 463 | 464 | # Expressions 465 | 466 | test "variable" do 467 | foo = "foo" 468 | bar = "bar" 469 | 470 | # prompt: y 471 | assert_value foo == "foo" 472 | 473 | # prompt: y 474 | assert_value foo == "foo" 475 | end 476 | 477 | test "module attributes" do 478 | # prompt: y 479 | assert_value @foo == "foo" 480 | 481 | # prompt: y 482 | assert_value @foo == "foo" 483 | 484 | # prompt: y 485 | assert_value "foo" == @foo 486 | end 487 | 488 | test "parens" do 489 | # prompt: y 490 | assert_value("foo" == "foo") 491 | 492 | # prompt: y 493 | assert_value "foo" == "foo" 494 | 495 | # prompt: y 496 | assert_value("foo" == "foo") 497 | 498 | # prompt: y 499 | assert_value "foo" == "foo" 500 | 501 | # prompt: y 502 | assert_value("foo" == "foo") 503 | 504 | # prompt: y 505 | assert_value "foo" == "foo" 506 | 507 | # prompt: y 508 | assert_value("foo" == "foo") 509 | 510 | # prompt: y 511 | assert_value "foo" == "foo" 512 | 513 | # prompt: y 514 | assert_value "foo" == "foo" 515 | 516 | # prompt: y 517 | assert_value "foo" == "foo" 518 | 519 | # prompt: y 520 | assert_value("foo" == "foo") 521 | 522 | # prompt: y 523 | assert_value "foo" == "foo" 524 | 525 | # prompt: y 526 | assert_value("foo" == "foo") 527 | end 528 | 529 | test "left/right expressions" do 530 | foo = "foo" 531 | bar = "bar" 532 | 533 | # prompt: y 534 | assert_value foo <> "bar" == "foobar" 535 | 536 | # prompt: y 537 | assert_value foo <> "bar" == "foobar" 538 | 539 | # prompt: y 540 | assert_value foo <> 541 | "bar" == "foobar" 542 | 543 | # prompt: y 544 | assert_value foo <> 545 | "bar" == 546 | "foobar" 547 | end 548 | 549 | test "functions" do 550 | hello = fn(x) -> 551 | "Hello " <> x <> "!" 552 | end 553 | 554 | # prompt: y 555 | assert_value String.upcase("foo") == "FOO" 556 | 557 | # prompt: y 558 | assert_value hello.("World") == "Hello World!" 559 | 560 | # prompt: y 561 | assert_value String.upcase("foo") == "FOO" 562 | 563 | # prompt: y 564 | assert_value hello.("World") == "Hello World!" 565 | 566 | # prompt: y 567 | assert_value String.upcase("foo") == "FOO" 568 | end 569 | 570 | test "pipes" do 571 | # prompt: y 572 | assert_value String.upcase("foo") |> String.reverse() == 573 | "OOF" 574 | 575 | # prompt: y 576 | assert_value String.upcase("foo") 577 | |> String.reverse() == 578 | "OOF" 579 | end 580 | 581 | test "repeatable expressions" do 582 | # prompt: y 583 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 584 | 585 | # prompt: y 586 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 587 | 588 | # prompt: y 589 | assert_value 5 == 5 590 | end 591 | 592 | test "AST cleanup" do 593 | # Macro.expand below produces AST with hygienic counter 594 | # Check that we can correctly parse it 595 | # Last String.replace is to produce the same result code 596 | # from different Elixirs. 1.6.0 has slightly different 597 | # "if" macro. 598 | 599 | assert_value quote(do: Kernel.||(1, false)) 600 | |> Macro.expand(__ENV__) 601 | |> Macro.to_string() 602 | |> String.replace( 603 | "when x in [false, nil]", 604 | "when Kernel.in(x, [false, nil])" 605 | ) == """ 606 | case 1 do 607 | x when Kernel.in(x, [false, nil]) -> false 608 | x -> x 609 | end 610 | """ 611 | end 612 | 613 | test "function without arguments" do 614 | # prompt: y 615 | assert_value Foo.foo() == "foo" 616 | 617 | # prompt: y 618 | assert_value Foo.foo() == "foo" 619 | end 620 | 621 | test "not-serializable expected" do 622 | # This should pass. We can successfully parse expected and replace 623 | # it with serialized value 624 | # prompt: y 625 | assert_value :foo == :foo 626 | end 627 | 628 | test "integer floats" do 629 | # prompt: y 630 | assert_value 2 == 2 631 | 632 | # prompt: y 633 | assert_value 1.0 == 1.0 634 | end 635 | 636 | end 637 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.after.1.14: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | def f_nil() do 16 | # The way to dynamically generate nil, to avoid "type violation" warnings 17 | List.first([]) 18 | end 19 | 20 | def f_false() do 21 | List.first([false]) 22 | end 23 | 24 | def f_true() do 25 | List.first([true]) 26 | end 27 | 28 | def f_atom_foo() do 29 | List.first([:foo]) 30 | end 31 | 32 | def f_atom_bar() do 33 | List.first([:bar]) 34 | end 35 | 36 | import AssertValue 37 | 38 | # Literals 39 | 40 | test "actual literals" do 41 | # prompt: y 42 | assert_value nil == nil 43 | 44 | # prompt: y 45 | assert_value true == true 46 | 47 | # prompt: y 48 | assert_value false == false 49 | 50 | # prompt: y 51 | assert_value :foo == :foo 52 | 53 | # prompt: y 54 | assert_value "forty-two" == "forty-two" 55 | 56 | # prompt: y 57 | assert_value """ 58 | forty-two 59 | сорок два 60 | 四十二 61 | quarante deux 62 | cuarenta y dos 63 | zweiundvierzig 64 | """ == """ 65 | forty-two 66 | сорок два 67 | 四十二 68 | quarante deux 69 | cuarenta y dos 70 | zweiundvierzig 71 | """ 72 | 73 | # prompt: y 74 | assert_value ~S(forty-two) == "forty-two" 75 | 76 | # prompt: y 77 | assert_value ~s(forty-two) == "forty-two" 78 | 79 | # prompt: y 80 | assert_value <<65, 66, 67>> == "ABC" 81 | 82 | # prompt: y 83 | assert_value <<256::utf8>> == "Ā" 84 | 85 | # prompt: y 86 | assert_value ~c"forty-two" == 'forty-two' 87 | 88 | # prompt: y 89 | assert_value ~c""" 90 | forty-two 91 | сорок два 92 | """ == [ 93 | 102, 94 | 111, 95 | 114, 96 | 116, 97 | 121, 98 | 45, 99 | 116, 100 | 119, 101 | 111, 102 | 10, 103 | 1089, 104 | 1086, 105 | 1088, 106 | 1086, 107 | 1082, 108 | 32, 109 | 1076, 110 | 1074, 111 | 1072, 112 | 10 113 | ] 114 | # prompt: y 115 | assert_value ~C(forty-two) == 'forty-two' 116 | 117 | # prompt: y 118 | assert_value ~c(forty-two) == 'forty-two' 119 | 120 | # prompt: y 121 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 122 | 123 | # prompt: y 124 | assert_value 0.42 == 0.42 125 | 126 | # prompt: y 127 | assert_value -0.42 == -0.42 128 | 129 | # prompt: y 130 | assert_value 42 == 42 131 | 132 | # prompt: y 133 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 134 | 135 | # prompt: y 136 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 137 | 138 | # prompt: y 139 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 140 | 141 | # prompt: y 142 | assert_value ~r/foo/ == ~r/foo/ 143 | 144 | # prompt: y 145 | assert_value ~T[23:00:07] == ~T[23:00:07] 146 | 147 | # prompt: y 148 | assert_value {:ok, 42} == {:ok, 42} 149 | 150 | # prompt: y 151 | assert_value %User{} == %ParserTest.User{name: "John", age: 27} 152 | 153 | # prompt: y 154 | assert_value %User{age: 43} == %ParserTest.User{name: "John", age: 43} 155 | 156 | # prompt: y 157 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 158 | %ParserTest.User{name: "Peter", age: 21} 159 | 160 | # prompt: y 161 | assert_value ~W(foo bar) == ["foo", "bar"] 162 | 163 | # prompt: y 164 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 165 | %{ 166 | a: 42, 167 | b: {:left, :light}, 168 | c: [%ParserTest.User{name: "John", age: 27}, 1] 169 | }, 170 | nil 171 | ] 172 | end 173 | 174 | test "actual and expected literals" do 175 | # prompt: y 176 | assert_value nil == nil 177 | 178 | # prompt: y 179 | assert_value true == true 180 | 181 | # prompt: y 182 | assert_value :foo == :foo 183 | 184 | # prompt: y 185 | assert_value "forty-two" == "forty-two" 186 | 187 | # prompt: y 188 | assert_value """ 189 | forty-two 190 | сорок два 191 | 四十二 192 | quarante deux 193 | cuarenta y dos 194 | zweiundvierzig 195 | """ == """ 196 | forty-two 197 | сорок два 198 | 四十二 199 | quarante deux 200 | cuarenta y dos 201 | zweiundvierzig 202 | """ 203 | 204 | # prompt: y 205 | assert_value ~S(forty-two) == "forty-two" 206 | 207 | # prompt: y 208 | assert_value ~s(forty-two) == "forty-two" 209 | 210 | # prompt: y 211 | assert_value <<65, 66, 67>> == "ABC" 212 | 213 | # prompt: y 214 | assert_value <<256::utf8>> == "Ā" 215 | 216 | # prompt: y 217 | assert_value ~c"forty-two" == 'forty-two' 218 | 219 | # prompt: y 220 | assert_value ~c""" 221 | forty-two 222 | сорок два 223 | """ == [ 224 | 102, 225 | 111, 226 | 114, 227 | 116, 228 | 121, 229 | 45, 230 | 116, 231 | 119, 232 | 111, 233 | 10, 234 | 1089, 235 | 1086, 236 | 1088, 237 | 1086, 238 | 1082, 239 | 32, 240 | 1076, 241 | 1074, 242 | 1072, 243 | 10 244 | ] 245 | 246 | # prompt: y 247 | assert_value ~C(forty-two) == 'forty-two' 248 | 249 | # prompt: y 250 | assert_value ~c(forty-two) == 'forty-two' 251 | 252 | # prompt: y 253 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 254 | 255 | # prompt: y 256 | assert_value 0.42 == 0.42 257 | 258 | # prompt: y 259 | assert_value -0.42 == -0.42 260 | 261 | # prompt: y 262 | assert_value 42 == 42 263 | 264 | # prompt: y 265 | assert_value -42 == -42 266 | 267 | # prompt: y 268 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 269 | 270 | # prompt: y 271 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 272 | 273 | # prompt: y 274 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 275 | 276 | # prompt: y 277 | assert_value ~T[23:00:07] == ~T[23:00:07] 278 | 279 | # prompt: y 280 | assert_value {:ok, 42} == {:ok, 42} 281 | 282 | # prompt: y 283 | assert_value %User{} == %ParserTest.User{name: "John", age: 27} 284 | 285 | # prompt: y 286 | assert_value %User{age: 42} == %ParserTest.User{name: "John", age: 42} 287 | 288 | # This should pass 289 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 290 | 291 | # prompt: y 292 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 293 | %ParserTest.User{name: "Peter", age: 21} 294 | 295 | # prompt: y 296 | assert_value ~W(foo bar) == ["foo", "bar"] 297 | 298 | # prompt: y 299 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 300 | %{ 301 | a: 42, 302 | b: {:left, :light}, 303 | c: [%ParserTest.User{name: "John", age: 27}, 1] 304 | }, 305 | nil 306 | ] 307 | end 308 | 309 | test "expected literal" do 310 | # prompt: y 311 | assert_value Foo.foo() == "foo" 312 | 313 | # prompt: y 314 | assert_value Foo.foo() == "foo" 315 | 316 | # prompt: y 317 | assert_value Foo.foo() == "foo" 318 | 319 | # prompt: y 320 | assert_value Foo.foo() == "foo" 321 | 322 | # prompt: y 323 | assert_value Foo.foo() == "foo" 324 | 325 | # prompt: y 326 | assert_value Foo.foo() == "foo" 327 | 328 | # prompt: y 329 | assert_value Foo.foo() == "foo" 330 | 331 | # prompt: y 332 | assert_value Foo.foo() == "foo" 333 | 334 | # prompt: y 335 | assert_value Foo.foo() == "foo" 336 | 337 | # prompt: y 338 | assert_value Foo.foo() == "foo" 339 | 340 | # prompt: y 341 | assert_value Foo.foo() == "foo" 342 | 343 | # prompt: y 344 | assert_value Foo.foo() == "foo" 345 | 346 | # prompt: y 347 | assert_value Foo.foo() == "foo" 348 | 349 | # prompt: y 350 | assert_value Foo.foo() == "foo" 351 | 352 | # prompt: y 353 | assert_value Foo.foo() == "foo" 354 | 355 | # prompt: y 356 | assert_value Foo.foo() == "foo" 357 | 358 | # prompt: y 359 | assert_value Foo.foo() == "foo" 360 | 361 | # prompt: y 362 | assert_value Foo.foo() == "foo" 363 | 364 | # prompt: y 365 | assert_value Foo.foo() == "foo" 366 | 367 | # prompt: y 368 | assert_value Foo.foo() == "foo" 369 | 370 | # prompt: y 371 | assert_value Foo.foo() == "foo" 372 | 373 | # prompt: y 374 | assert_value Foo.foo() == "foo" 375 | 376 | # prompt: y 377 | assert_value Foo.foo() == "foo" 378 | 379 | # prompt: y 380 | assert_value Foo.foo() == "foo" 381 | 382 | # prompt: y 383 | assert_value Foo.foo() == "foo" 384 | 385 | # prompt: y 386 | assert_value Foo.foo() == "foo" 387 | 388 | # prompt: y 389 | assert_value Foo.foo() == "foo" 390 | 391 | # prompt: y 392 | assert_value Foo.foo() == "foo" 393 | 394 | # prompt: y 395 | assert_value Foo.foo() == "foo" 396 | end 397 | 398 | test "create file" do 399 | # prompt: y 400 | assert_value """ 401 | aaa 402 | bbb 403 | ccc 404 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 405 | end 406 | 407 | test "update file" do 408 | # prompt: y 409 | assert_value """ 410 | aaa 411 | bbb 412 | ccc 413 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 414 | end 415 | 416 | # Corner cases 417 | 418 | test "spaces around equation" do 419 | # prompt: y 420 | assert_value "foo" == "foo" 421 | 422 | # prompt: y 423 | assert_value "foo" == "foo" 424 | 425 | # prompt: y 426 | assert_value "foo" == "foo" 427 | 428 | # prompt: y 429 | assert_value "foo" == "foo" 430 | 431 | # prompt: y 432 | assert_value "foo" == "foo" 433 | 434 | # prompt: y 435 | assert_value "foo" == "foo" 436 | end 437 | 438 | test "string escaping" do 439 | # prompt: y 440 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo\\nbar\" \" \t \r %{}" 441 | 442 | # prompt: y 443 | assert_value "foo" == "foo" 444 | end 445 | 446 | test "float trailing zeros" do 447 | # prompt: y 448 | assert_value 42.0001000 == 42.0001 449 | 450 | # prompt: y 451 | assert_value -42.0001000 == -42.0001 452 | end 453 | 454 | test "bitstring and string" do 455 | assert_value <<65>> == "A" 456 | # prompt: y 457 | assert_value <<66>> == "B" 458 | 459 | assert_value "A" == <<65>> 460 | # prompt: y 461 | assert_value "B" == "B" 462 | end 463 | 464 | # Expressions 465 | 466 | test "variable" do 467 | foo = "foo" 468 | bar = "bar" 469 | 470 | # prompt: y 471 | assert_value foo == "foo" 472 | 473 | # prompt: y 474 | assert_value foo == "foo" 475 | end 476 | 477 | test "module attributes" do 478 | # prompt: y 479 | assert_value @foo == "foo" 480 | 481 | # prompt: y 482 | assert_value @foo == "foo" 483 | 484 | # prompt: y 485 | assert_value "foo" == @foo 486 | end 487 | 488 | test "parens" do 489 | # prompt: y 490 | assert_value("foo" == "foo") 491 | 492 | # prompt: y 493 | assert_value "foo" == "foo" 494 | 495 | # prompt: y 496 | assert_value("foo" == "foo") 497 | 498 | # prompt: y 499 | assert_value "foo" == "foo" 500 | 501 | # prompt: y 502 | assert_value("foo" == "foo") 503 | 504 | # prompt: y 505 | assert_value "foo" == "foo" 506 | 507 | # prompt: y 508 | assert_value("foo" == "foo") 509 | 510 | # prompt: y 511 | assert_value "foo" == "foo" 512 | 513 | # prompt: y 514 | assert_value "foo" == "foo" 515 | 516 | # prompt: y 517 | assert_value "foo" == "foo" 518 | 519 | # prompt: y 520 | assert_value("foo" == "foo") 521 | 522 | # prompt: y 523 | assert_value "foo" == "foo" 524 | 525 | # prompt: y 526 | assert_value("foo" == "foo") 527 | end 528 | 529 | test "left/right expressions" do 530 | foo = "foo" 531 | bar = "bar" 532 | 533 | # prompt: y 534 | assert_value foo <> "bar" == "foobar" 535 | 536 | # prompt: y 537 | assert_value foo <> "bar" == "foobar" 538 | 539 | # prompt: y 540 | assert_value foo <> 541 | "bar" == "foobar" 542 | 543 | # prompt: y 544 | assert_value foo <> 545 | "bar" == 546 | "foobar" 547 | end 548 | 549 | test "functions" do 550 | hello = fn(x) -> 551 | "Hello " <> x <> "!" 552 | end 553 | 554 | # prompt: y 555 | assert_value String.upcase("foo") == "FOO" 556 | 557 | # prompt: y 558 | assert_value hello.("World") == "Hello World!" 559 | 560 | # prompt: y 561 | assert_value String.upcase("foo") == "FOO" 562 | 563 | # prompt: y 564 | assert_value hello.("World") == "Hello World!" 565 | 566 | # prompt: y 567 | assert_value String.upcase("foo") == "FOO" 568 | end 569 | 570 | test "pipes" do 571 | # prompt: y 572 | assert_value String.upcase("foo") |> String.reverse() == 573 | "OOF" 574 | 575 | # prompt: y 576 | assert_value String.upcase("foo") 577 | |> String.reverse() == 578 | "OOF" 579 | end 580 | 581 | test "repeatable expressions" do 582 | # prompt: y 583 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 584 | 585 | # prompt: y 586 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 587 | 588 | # prompt: y 589 | assert_value 5 == 5 590 | end 591 | 592 | test "AST cleanup" do 593 | # Macro.expand below produces AST with hygienic counter 594 | # Check that we can correctly parse it 595 | # Last String.replace is to produce the same result code 596 | # from different Elixirs. 1.6.0 has slightly different 597 | # "if" macro. 598 | 599 | assert_value quote(do: Kernel.||(1, false)) 600 | |> Macro.expand(__ENV__) 601 | |> Macro.to_string() 602 | |> String.replace( 603 | "when x in [false, nil]", 604 | "when Kernel.in(x, [false, nil])" 605 | ) == """ 606 | case 1 do 607 | x when Kernel.in(x, [false, nil]) -> false 608 | x -> x 609 | end 610 | """ 611 | end 612 | 613 | test "function without arguments" do 614 | # prompt: y 615 | assert_value Foo.foo() == "foo" 616 | 617 | # prompt: y 618 | assert_value Foo.foo() == "foo" 619 | end 620 | 621 | test "not-serializable expected" do 622 | # This should pass. We can successfully parse expected and replace 623 | # it with serialized value 624 | # prompt: y 625 | assert_value :foo == :foo 626 | end 627 | 628 | test "integer floats" do 629 | # prompt: y 630 | assert_value 2 == 2 631 | 632 | # prompt: y 633 | assert_value 1.0 == 1.0 634 | end 635 | 636 | end 637 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.after.1.15: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | def f_nil() do 16 | # The way to dynamically generate nil, to avoid "type violation" warnings 17 | List.first([]) 18 | end 19 | 20 | def f_false() do 21 | List.first([false]) 22 | end 23 | 24 | def f_true() do 25 | List.first([true]) 26 | end 27 | 28 | def f_atom_foo() do 29 | List.first([:foo]) 30 | end 31 | 32 | def f_atom_bar() do 33 | List.first([:bar]) 34 | end 35 | 36 | import AssertValue 37 | 38 | # Literals 39 | 40 | test "actual literals" do 41 | # prompt: y 42 | assert_value nil == nil 43 | 44 | # prompt: y 45 | assert_value true == true 46 | 47 | # prompt: y 48 | assert_value false == false 49 | 50 | # prompt: y 51 | assert_value :foo == :foo 52 | 53 | # prompt: y 54 | assert_value "forty-two" == "forty-two" 55 | 56 | # prompt: y 57 | assert_value """ 58 | forty-two 59 | сорок два 60 | 四十二 61 | quarante deux 62 | cuarenta y dos 63 | zweiundvierzig 64 | """ == """ 65 | forty-two 66 | сорок два 67 | 四十二 68 | quarante deux 69 | cuarenta y dos 70 | zweiundvierzig 71 | """ 72 | 73 | # prompt: y 74 | assert_value ~S(forty-two) == "forty-two" 75 | 76 | # prompt: y 77 | assert_value ~s(forty-two) == "forty-two" 78 | 79 | # prompt: y 80 | assert_value <<65, 66, 67>> == "ABC" 81 | 82 | # prompt: y 83 | assert_value <<256::utf8>> == "Ā" 84 | 85 | # prompt: y 86 | assert_value ~c"forty-two" == ~c"forty-two" 87 | 88 | # prompt: y 89 | assert_value ~c""" 90 | forty-two 91 | сорок два 92 | """ == [ 93 | 102, 94 | 111, 95 | 114, 96 | 116, 97 | 121, 98 | 45, 99 | 116, 100 | 119, 101 | 111, 102 | 10, 103 | 1089, 104 | 1086, 105 | 1088, 106 | 1086, 107 | 1082, 108 | 32, 109 | 1076, 110 | 1074, 111 | 1072, 112 | 10 113 | ] 114 | # prompt: y 115 | assert_value ~C(forty-two) == ~c"forty-two" 116 | 117 | # prompt: y 118 | assert_value ~c(forty-two) == ~c"forty-two" 119 | 120 | # prompt: y 121 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 122 | 123 | # prompt: y 124 | assert_value 0.42 == 0.42 125 | 126 | # prompt: y 127 | assert_value -0.42 == -0.42 128 | 129 | # prompt: y 130 | assert_value 42 == 42 131 | 132 | # prompt: y 133 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 134 | 135 | # prompt: y 136 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 137 | 138 | # prompt: y 139 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 140 | 141 | # prompt: y 142 | assert_value ~r/foo/ == ~r/foo/ 143 | 144 | # prompt: y 145 | assert_value ~T[23:00:07] == ~T[23:00:07] 146 | 147 | # prompt: y 148 | assert_value {:ok, 42} == {:ok, 42} 149 | 150 | # prompt: y 151 | assert_value %User{} == %ParserTest.User{name: "John", age: 27} 152 | 153 | # prompt: y 154 | assert_value %User{age: 43} == %ParserTest.User{name: "John", age: 43} 155 | 156 | # prompt: y 157 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 158 | %ParserTest.User{name: "Peter", age: 21} 159 | 160 | # prompt: y 161 | assert_value ~W(foo bar) == ["foo", "bar"] 162 | 163 | # prompt: y 164 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 165 | %{ 166 | a: 42, 167 | b: {:left, :light}, 168 | c: [%ParserTest.User{name: "John", age: 27}, 1] 169 | }, 170 | nil 171 | ] 172 | end 173 | 174 | test "actual and expected literals" do 175 | # prompt: y 176 | assert_value nil == nil 177 | 178 | # prompt: y 179 | assert_value true == true 180 | 181 | # prompt: y 182 | assert_value :foo == :foo 183 | 184 | # prompt: y 185 | assert_value "forty-two" == "forty-two" 186 | 187 | # prompt: y 188 | assert_value """ 189 | forty-two 190 | сорок два 191 | 四十二 192 | quarante deux 193 | cuarenta y dos 194 | zweiundvierzig 195 | """ == """ 196 | forty-two 197 | сорок два 198 | 四十二 199 | quarante deux 200 | cuarenta y dos 201 | zweiundvierzig 202 | """ 203 | 204 | # prompt: y 205 | assert_value ~S(forty-two) == "forty-two" 206 | 207 | # prompt: y 208 | assert_value ~s(forty-two) == "forty-two" 209 | 210 | # prompt: y 211 | assert_value <<65, 66, 67>> == "ABC" 212 | 213 | # prompt: y 214 | assert_value <<256::utf8>> == "Ā" 215 | 216 | # prompt: y 217 | assert_value ~c"forty-two" == ~c"forty-two" 218 | 219 | # prompt: y 220 | assert_value ~c""" 221 | forty-two 222 | сорок два 223 | """ == [ 224 | 102, 225 | 111, 226 | 114, 227 | 116, 228 | 121, 229 | 45, 230 | 116, 231 | 119, 232 | 111, 233 | 10, 234 | 1089, 235 | 1086, 236 | 1088, 237 | 1086, 238 | 1082, 239 | 32, 240 | 1076, 241 | 1074, 242 | 1072, 243 | 10 244 | ] 245 | 246 | # prompt: y 247 | assert_value ~C(forty-two) == ~c"forty-two" 248 | 249 | # prompt: y 250 | assert_value ~c(forty-two) == ~c"forty-two" 251 | 252 | # prompt: y 253 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 254 | 255 | # prompt: y 256 | assert_value 0.42 == 0.42 257 | 258 | # prompt: y 259 | assert_value -0.42 == -0.42 260 | 261 | # prompt: y 262 | assert_value 42 == 42 263 | 264 | # prompt: y 265 | assert_value -42 == -42 266 | 267 | # prompt: y 268 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 269 | 270 | # prompt: y 271 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 272 | 273 | # prompt: y 274 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 275 | 276 | # prompt: y 277 | assert_value ~T[23:00:07] == ~T[23:00:07] 278 | 279 | # prompt: y 280 | assert_value {:ok, 42} == {:ok, 42} 281 | 282 | # prompt: y 283 | assert_value %User{} == %ParserTest.User{name: "John", age: 27} 284 | 285 | # prompt: y 286 | assert_value %User{age: 42} == %ParserTest.User{name: "John", age: 42} 287 | 288 | # This should pass 289 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 290 | 291 | # prompt: y 292 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 293 | %ParserTest.User{name: "Peter", age: 21} 294 | 295 | # prompt: y 296 | assert_value ~W(foo bar) == ["foo", "bar"] 297 | 298 | # prompt: y 299 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 300 | %{ 301 | a: 42, 302 | b: {:left, :light}, 303 | c: [%ParserTest.User{name: "John", age: 27}, 1] 304 | }, 305 | nil 306 | ] 307 | end 308 | 309 | test "expected literal" do 310 | # prompt: y 311 | assert_value Foo.foo() == "foo" 312 | 313 | # prompt: y 314 | assert_value Foo.foo() == "foo" 315 | 316 | # prompt: y 317 | assert_value Foo.foo() == "foo" 318 | 319 | # prompt: y 320 | assert_value Foo.foo() == "foo" 321 | 322 | # prompt: y 323 | assert_value Foo.foo() == "foo" 324 | 325 | # prompt: y 326 | assert_value Foo.foo() == "foo" 327 | 328 | # prompt: y 329 | assert_value Foo.foo() == "foo" 330 | 331 | # prompt: y 332 | assert_value Foo.foo() == "foo" 333 | 334 | # prompt: y 335 | assert_value Foo.foo() == "foo" 336 | 337 | # prompt: y 338 | assert_value Foo.foo() == "foo" 339 | 340 | # prompt: y 341 | assert_value Foo.foo() == "foo" 342 | 343 | # prompt: y 344 | assert_value Foo.foo() == "foo" 345 | 346 | # prompt: y 347 | assert_value Foo.foo() == "foo" 348 | 349 | # prompt: y 350 | assert_value Foo.foo() == "foo" 351 | 352 | # prompt: y 353 | assert_value Foo.foo() == "foo" 354 | 355 | # prompt: y 356 | assert_value Foo.foo() == "foo" 357 | 358 | # prompt: y 359 | assert_value Foo.foo() == "foo" 360 | 361 | # prompt: y 362 | assert_value Foo.foo() == "foo" 363 | 364 | # prompt: y 365 | assert_value Foo.foo() == "foo" 366 | 367 | # prompt: y 368 | assert_value Foo.foo() == "foo" 369 | 370 | # prompt: y 371 | assert_value Foo.foo() == "foo" 372 | 373 | # prompt: y 374 | assert_value Foo.foo() == "foo" 375 | 376 | # prompt: y 377 | assert_value Foo.foo() == "foo" 378 | 379 | # prompt: y 380 | assert_value Foo.foo() == "foo" 381 | 382 | # prompt: y 383 | assert_value Foo.foo() == "foo" 384 | 385 | # prompt: y 386 | assert_value Foo.foo() == "foo" 387 | 388 | # prompt: y 389 | assert_value Foo.foo() == "foo" 390 | 391 | # prompt: y 392 | assert_value Foo.foo() == "foo" 393 | 394 | # prompt: y 395 | assert_value Foo.foo() == "foo" 396 | end 397 | 398 | test "create file" do 399 | # prompt: y 400 | assert_value """ 401 | aaa 402 | bbb 403 | ccc 404 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 405 | end 406 | 407 | test "update file" do 408 | # prompt: y 409 | assert_value """ 410 | aaa 411 | bbb 412 | ccc 413 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 414 | end 415 | 416 | # Corner cases 417 | 418 | test "spaces around equation" do 419 | # prompt: y 420 | assert_value "foo" == "foo" 421 | 422 | # prompt: y 423 | assert_value "foo" == "foo" 424 | 425 | # prompt: y 426 | assert_value "foo" == "foo" 427 | 428 | # prompt: y 429 | assert_value "foo" == "foo" 430 | 431 | # prompt: y 432 | assert_value "foo" == "foo" 433 | 434 | # prompt: y 435 | assert_value "foo" == "foo" 436 | end 437 | 438 | test "string escaping" do 439 | # prompt: y 440 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo\\nbar\" \" \t \r %{}" 441 | 442 | # prompt: y 443 | assert_value "foo" == "foo" 444 | end 445 | 446 | test "float trailing zeros" do 447 | # prompt: y 448 | assert_value 42.0001000 == 42.0001 449 | 450 | # prompt: y 451 | assert_value -42.0001000 == -42.0001 452 | end 453 | 454 | test "bitstring and string" do 455 | assert_value <<65>> == "A" 456 | # prompt: y 457 | assert_value <<66>> == "B" 458 | 459 | assert_value "A" == <<65>> 460 | # prompt: y 461 | assert_value "B" == "B" 462 | end 463 | 464 | # Expressions 465 | 466 | test "variable" do 467 | foo = "foo" 468 | bar = "bar" 469 | 470 | # prompt: y 471 | assert_value foo == "foo" 472 | 473 | # prompt: y 474 | assert_value foo == "foo" 475 | end 476 | 477 | test "module attributes" do 478 | # prompt: y 479 | assert_value @foo == "foo" 480 | 481 | # prompt: y 482 | assert_value @foo == "foo" 483 | 484 | # prompt: y 485 | assert_value "foo" == @foo 486 | end 487 | 488 | test "parens" do 489 | # prompt: y 490 | assert_value("foo" == "foo") 491 | 492 | # prompt: y 493 | assert_value "foo" == "foo" 494 | 495 | # prompt: y 496 | assert_value("foo" == "foo") 497 | 498 | # prompt: y 499 | assert_value "foo" == "foo" 500 | 501 | # prompt: y 502 | assert_value("foo" == "foo") 503 | 504 | # prompt: y 505 | assert_value "foo" == "foo" 506 | 507 | # prompt: y 508 | assert_value("foo" == "foo") 509 | 510 | # prompt: y 511 | assert_value "foo" == "foo" 512 | 513 | # prompt: y 514 | assert_value "foo" == "foo" 515 | 516 | # prompt: y 517 | assert_value "foo" == "foo" 518 | 519 | # prompt: y 520 | assert_value("foo" == "foo") 521 | 522 | # prompt: y 523 | assert_value "foo" == "foo" 524 | 525 | # prompt: y 526 | assert_value("foo" == "foo") 527 | end 528 | 529 | test "left/right expressions" do 530 | foo = "foo" 531 | bar = "bar" 532 | 533 | # prompt: y 534 | assert_value foo <> "bar" == "foobar" 535 | 536 | # prompt: y 537 | assert_value foo <> "bar" == "foobar" 538 | 539 | # prompt: y 540 | assert_value foo <> 541 | "bar" == "foobar" 542 | 543 | # prompt: y 544 | assert_value foo <> 545 | "bar" == 546 | "foobar" 547 | end 548 | 549 | test "functions" do 550 | hello = fn(x) -> 551 | "Hello " <> x <> "!" 552 | end 553 | 554 | # prompt: y 555 | assert_value String.upcase("foo") == "FOO" 556 | 557 | # prompt: y 558 | assert_value hello.("World") == "Hello World!" 559 | 560 | # prompt: y 561 | assert_value String.upcase("foo") == "FOO" 562 | 563 | # prompt: y 564 | assert_value hello.("World") == "Hello World!" 565 | 566 | # prompt: y 567 | assert_value String.upcase("foo") == "FOO" 568 | end 569 | 570 | test "pipes" do 571 | # prompt: y 572 | assert_value String.upcase("foo") |> String.reverse() == 573 | "OOF" 574 | 575 | # prompt: y 576 | assert_value String.upcase("foo") 577 | |> String.reverse() == 578 | "OOF" 579 | end 580 | 581 | test "repeatable expressions" do 582 | # prompt: y 583 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 584 | 585 | # prompt: y 586 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 587 | 588 | # prompt: y 589 | assert_value 5 == 5 590 | end 591 | 592 | test "AST cleanup" do 593 | # Macro.expand below produces AST with hygienic counter 594 | # Check that we can correctly parse it 595 | # Last String.replace is to produce the same result code 596 | # from different Elixirs. 1.6.0 has slightly different 597 | # "if" macro. 598 | 599 | assert_value quote(do: Kernel.||(1, false)) 600 | |> Macro.expand(__ENV__) 601 | |> Macro.to_string() 602 | |> String.replace( 603 | "when x in [false, nil]", 604 | "when Kernel.in(x, [false, nil])" 605 | ) == """ 606 | case 1 do 607 | x when Kernel.in(x, [false, nil]) -> false 608 | x -> x 609 | end 610 | """ 611 | end 612 | 613 | test "function without arguments" do 614 | # prompt: y 615 | assert_value Foo.foo() == "foo" 616 | 617 | # prompt: y 618 | assert_value Foo.foo() == "foo" 619 | end 620 | 621 | test "not-serializable expected" do 622 | # This should pass. We can successfully parse expected and replace 623 | # it with serialized value 624 | # prompt: y 625 | assert_value :foo == :foo 626 | end 627 | 628 | test "integer floats" do 629 | # prompt: y 630 | assert_value 2 == 2 631 | 632 | # prompt: y 633 | assert_value 1.0 == 1.0 634 | end 635 | 636 | end 637 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.after.1.8: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | def f_nil() do 16 | # The way to dynamically generate nil, to avoid "type violation" warnings 17 | List.first([]) 18 | end 19 | 20 | def f_false() do 21 | List.first([false]) 22 | end 23 | 24 | def f_true() do 25 | List.first([true]) 26 | end 27 | 28 | def f_atom_foo() do 29 | List.first([:foo]) 30 | end 31 | 32 | def f_atom_bar() do 33 | List.first([:bar]) 34 | end 35 | 36 | import AssertValue 37 | 38 | # Literals 39 | 40 | test "actual literals" do 41 | # prompt: y 42 | assert_value nil == nil 43 | 44 | # prompt: y 45 | assert_value true == true 46 | 47 | # prompt: y 48 | assert_value false == false 49 | 50 | # prompt: y 51 | assert_value :foo == :foo 52 | 53 | # prompt: y 54 | assert_value "forty-two" == "forty-two" 55 | 56 | # prompt: y 57 | assert_value """ 58 | forty-two 59 | сорок два 60 | 四十二 61 | quarante deux 62 | cuarenta y dos 63 | zweiundvierzig 64 | """ == """ 65 | forty-two 66 | сорок два 67 | 四十二 68 | quarante deux 69 | cuarenta y dos 70 | zweiundvierzig 71 | """ 72 | 73 | # prompt: y 74 | assert_value ~S(forty-two) == "forty-two" 75 | 76 | # prompt: y 77 | assert_value ~s(forty-two) == "forty-two" 78 | 79 | # prompt: y 80 | assert_value <<65, 66, 67>> == "ABC" 81 | 82 | # prompt: y 83 | assert_value <<256::utf8>> == "Ā" 84 | 85 | # prompt: y 86 | assert_value ~c"forty-two" == 'forty-two' 87 | 88 | # prompt: y 89 | assert_value ~c""" 90 | forty-two 91 | сорок два 92 | """ == [ 93 | 102, 94 | 111, 95 | 114, 96 | 116, 97 | 121, 98 | 45, 99 | 116, 100 | 119, 101 | 111, 102 | 10, 103 | 1089, 104 | 1086, 105 | 1088, 106 | 1086, 107 | 1082, 108 | 32, 109 | 1076, 110 | 1074, 111 | 1072, 112 | 10 113 | ] 114 | # prompt: y 115 | assert_value ~C(forty-two) == 'forty-two' 116 | 117 | # prompt: y 118 | assert_value ~c(forty-two) == 'forty-two' 119 | 120 | # prompt: y 121 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 122 | 123 | # prompt: y 124 | assert_value 0.42 == 0.42 125 | 126 | # prompt: y 127 | assert_value -0.42 == -0.42 128 | 129 | # prompt: y 130 | assert_value 42 == 42 131 | 132 | # prompt: y 133 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 134 | 135 | # prompt: y 136 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 137 | 138 | # prompt: y 139 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 140 | 141 | # prompt: y 142 | assert_value ~r/foo/ == ~r/foo/ 143 | 144 | # prompt: y 145 | assert_value ~T[23:00:07] == ~T[23:00:07] 146 | 147 | # prompt: y 148 | assert_value {:ok, 42} == {:ok, 42} 149 | 150 | # prompt: y 151 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 152 | 153 | # prompt: y 154 | assert_value %User{age: 43} == %ParserTest.User{age: 43, name: "John"} 155 | 156 | # prompt: y 157 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 158 | %ParserTest.User{age: 21, name: "Peter"} 159 | 160 | # prompt: y 161 | assert_value ~W(foo bar) == ["foo", "bar"] 162 | 163 | # prompt: y 164 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 165 | %{ 166 | a: 42, 167 | b: {:left, :light}, 168 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 169 | }, 170 | nil 171 | ] 172 | end 173 | 174 | test "actual and expected literals" do 175 | # prompt: y 176 | assert_value nil == nil 177 | 178 | # prompt: y 179 | assert_value true == true 180 | 181 | # prompt: y 182 | assert_value :foo == :foo 183 | 184 | # prompt: y 185 | assert_value "forty-two" == "forty-two" 186 | 187 | # prompt: y 188 | assert_value """ 189 | forty-two 190 | сорок два 191 | 四十二 192 | quarante deux 193 | cuarenta y dos 194 | zweiundvierzig 195 | """ == """ 196 | forty-two 197 | сорок два 198 | 四十二 199 | quarante deux 200 | cuarenta y dos 201 | zweiundvierzig 202 | """ 203 | 204 | # prompt: y 205 | assert_value ~S(forty-two) == "forty-two" 206 | 207 | # prompt: y 208 | assert_value ~s(forty-two) == "forty-two" 209 | 210 | # prompt: y 211 | assert_value <<65, 66, 67>> == "ABC" 212 | 213 | # prompt: y 214 | assert_value <<256::utf8>> == "Ā" 215 | 216 | # prompt: y 217 | assert_value ~c"forty-two" == 'forty-two' 218 | 219 | # prompt: y 220 | assert_value ~c""" 221 | forty-two 222 | сорок два 223 | """ == [ 224 | 102, 225 | 111, 226 | 114, 227 | 116, 228 | 121, 229 | 45, 230 | 116, 231 | 119, 232 | 111, 233 | 10, 234 | 1089, 235 | 1086, 236 | 1088, 237 | 1086, 238 | 1082, 239 | 32, 240 | 1076, 241 | 1074, 242 | 1072, 243 | 10 244 | ] 245 | 246 | # prompt: y 247 | assert_value ~C(forty-two) == 'forty-two' 248 | 249 | # prompt: y 250 | assert_value ~c(forty-two) == 'forty-two' 251 | 252 | # prompt: y 253 | assert_value ~D[2018-01-01] == ~D[2018-01-01] 254 | 255 | # prompt: y 256 | assert_value 0.42 == 0.42 257 | 258 | # prompt: y 259 | assert_value -0.42 == -0.42 260 | 261 | # prompt: y 262 | assert_value 42 == 42 263 | 264 | # prompt: y 265 | assert_value -42 == -42 266 | 267 | # prompt: y 268 | assert_value [4, 2, true, nil, "42"] == [4, 2, true, nil, "42"] 269 | 270 | # prompt: y 271 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: nil} 272 | 273 | # prompt: y 274 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-01 21:01:50] 275 | 276 | # prompt: y 277 | assert_value ~T[23:00:07] == ~T[23:00:07] 278 | 279 | # prompt: y 280 | assert_value {:ok, 42} == {:ok, 42} 281 | 282 | # prompt: y 283 | assert_value %User{} == %ParserTest.User{age: 27, name: "John"} 284 | 285 | # prompt: y 286 | assert_value %User{age: 42} == %ParserTest.User{age: 42, name: "John"} 287 | 288 | # This should pass 289 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 290 | 291 | # prompt: y 292 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == 293 | %ParserTest.User{age: 21, name: "Peter"} 294 | 295 | # prompt: y 296 | assert_value ~W(foo bar) == ["foo", "bar"] 297 | 298 | # prompt: y 299 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [ 300 | %{ 301 | a: 42, 302 | b: {:left, :light}, 303 | c: [%ParserTest.User{age: 27, name: "John"}, 1] 304 | }, 305 | nil 306 | ] 307 | end 308 | 309 | test "expected literal" do 310 | # prompt: y 311 | assert_value Foo.foo() == "foo" 312 | 313 | # prompt: y 314 | assert_value Foo.foo() == "foo" 315 | 316 | # prompt: y 317 | assert_value Foo.foo() == "foo" 318 | 319 | # prompt: y 320 | assert_value Foo.foo() == "foo" 321 | 322 | # prompt: y 323 | assert_value Foo.foo() == "foo" 324 | 325 | # prompt: y 326 | assert_value Foo.foo() == "foo" 327 | 328 | # prompt: y 329 | assert_value Foo.foo() == "foo" 330 | 331 | # prompt: y 332 | assert_value Foo.foo() == "foo" 333 | 334 | # prompt: y 335 | assert_value Foo.foo() == "foo" 336 | 337 | # prompt: y 338 | assert_value Foo.foo() == "foo" 339 | 340 | # prompt: y 341 | assert_value Foo.foo() == "foo" 342 | 343 | # prompt: y 344 | assert_value Foo.foo() == "foo" 345 | 346 | # prompt: y 347 | assert_value Foo.foo() == "foo" 348 | 349 | # prompt: y 350 | assert_value Foo.foo() == "foo" 351 | 352 | # prompt: y 353 | assert_value Foo.foo() == "foo" 354 | 355 | # prompt: y 356 | assert_value Foo.foo() == "foo" 357 | 358 | # prompt: y 359 | assert_value Foo.foo() == "foo" 360 | 361 | # prompt: y 362 | assert_value Foo.foo() == "foo" 363 | 364 | # prompt: y 365 | assert_value Foo.foo() == "foo" 366 | 367 | # prompt: y 368 | assert_value Foo.foo() == "foo" 369 | 370 | # prompt: y 371 | assert_value Foo.foo() == "foo" 372 | 373 | # prompt: y 374 | assert_value Foo.foo() == "foo" 375 | 376 | # prompt: y 377 | assert_value Foo.foo() == "foo" 378 | 379 | # prompt: y 380 | assert_value Foo.foo() == "foo" 381 | 382 | # prompt: y 383 | assert_value Foo.foo() == "foo" 384 | 385 | # prompt: y 386 | assert_value Foo.foo() == "foo" 387 | 388 | # prompt: y 389 | assert_value Foo.foo() == "foo" 390 | 391 | # prompt: y 392 | assert_value Foo.foo() == "foo" 393 | 394 | # prompt: y 395 | assert_value Foo.foo() == "foo" 396 | end 397 | 398 | test "create file" do 399 | # prompt: y 400 | assert_value """ 401 | aaa 402 | bbb 403 | ccc 404 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 405 | end 406 | 407 | test "update file" do 408 | # prompt: y 409 | assert_value """ 410 | aaa 411 | bbb 412 | ccc 413 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 414 | end 415 | 416 | # Corner cases 417 | 418 | test "spaces around equation" do 419 | # prompt: y 420 | assert_value "foo" == "foo" 421 | 422 | # prompt: y 423 | assert_value "foo" == "foo" 424 | 425 | # prompt: y 426 | assert_value "foo" == "foo" 427 | 428 | # prompt: y 429 | assert_value "foo" == "foo" 430 | 431 | # prompt: y 432 | assert_value "foo" == "foo" 433 | 434 | # prompt: y 435 | assert_value "foo" == "foo" 436 | end 437 | 438 | test "string escaping" do 439 | # prompt: y 440 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo\\nbar\" \" \t \r %{}" 441 | 442 | # prompt: y 443 | assert_value "foo" == "foo" 444 | end 445 | 446 | test "float trailing zeros" do 447 | # prompt: y 448 | assert_value 42.0001000 == 42.0001 449 | 450 | # prompt: y 451 | assert_value -42.0001000 == -42.0001 452 | end 453 | 454 | test "bitstring and string" do 455 | assert_value <<65>> == "A" 456 | # prompt: y 457 | assert_value <<66>> == "B" 458 | 459 | assert_value "A" == <<65>> 460 | # prompt: y 461 | assert_value "B" == "B" 462 | end 463 | 464 | # Expressions 465 | 466 | test "variable" do 467 | foo = "foo" 468 | bar = "bar" 469 | 470 | # prompt: y 471 | assert_value foo == "foo" 472 | 473 | # prompt: y 474 | assert_value foo == "foo" 475 | end 476 | 477 | test "module attributes" do 478 | # prompt: y 479 | assert_value @foo == "foo" 480 | 481 | # prompt: y 482 | assert_value @foo == "foo" 483 | 484 | # prompt: y 485 | assert_value "foo" == @foo 486 | end 487 | 488 | test "parens" do 489 | # prompt: y 490 | assert_value("foo" == "foo") 491 | 492 | # prompt: y 493 | assert_value "foo" == "foo" 494 | 495 | # prompt: y 496 | assert_value("foo" == "foo") 497 | 498 | # prompt: y 499 | assert_value "foo" == "foo" 500 | 501 | # prompt: y 502 | assert_value("foo" == "foo") 503 | 504 | # prompt: y 505 | assert_value "foo" == "foo" 506 | 507 | # prompt: y 508 | assert_value("foo" == "foo") 509 | 510 | # prompt: y 511 | assert_value "foo" == "foo" 512 | 513 | # prompt: y 514 | assert_value "foo" == "foo" 515 | 516 | # prompt: y 517 | assert_value "foo" == "foo" 518 | 519 | # prompt: y 520 | assert_value("foo" == "foo") 521 | 522 | # prompt: y 523 | assert_value "foo" == "foo" 524 | 525 | # prompt: y 526 | assert_value("foo" == "foo") 527 | end 528 | 529 | test "left/right expressions" do 530 | foo = "foo" 531 | bar = "bar" 532 | 533 | # prompt: y 534 | assert_value foo <> "bar" == "foobar" 535 | 536 | # prompt: y 537 | assert_value foo <> "bar" == "foobar" 538 | 539 | # prompt: y 540 | assert_value foo <> 541 | "bar" == "foobar" 542 | 543 | # prompt: y 544 | assert_value foo <> 545 | "bar" == 546 | "foobar" 547 | end 548 | 549 | test "functions" do 550 | hello = fn(x) -> 551 | "Hello " <> x <> "!" 552 | end 553 | 554 | # prompt: y 555 | assert_value String.upcase("foo") == "FOO" 556 | 557 | # prompt: y 558 | assert_value hello.("World") == "Hello World!" 559 | 560 | # prompt: y 561 | assert_value String.upcase("foo") == "FOO" 562 | 563 | # prompt: y 564 | assert_value hello.("World") == "Hello World!" 565 | 566 | # prompt: y 567 | assert_value String.upcase("foo") == "FOO" 568 | end 569 | 570 | test "pipes" do 571 | # prompt: y 572 | assert_value String.upcase("foo") |> String.reverse() == 573 | "OOF" 574 | 575 | # prompt: y 576 | assert_value String.upcase("foo") 577 | |> String.reverse() == 578 | "OOF" 579 | end 580 | 581 | test "repeatable expressions" do 582 | # prompt: y 583 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 584 | 585 | # prompt: y 586 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 4 587 | 588 | # prompt: y 589 | assert_value 5 == 5 590 | end 591 | 592 | test "AST cleanup" do 593 | # Macro.expand below produces AST with hygienic counter 594 | # Check that we can correctly parse it 595 | # Last String.replace is to produce the same result code 596 | # from different Elixirs. 1.6.0 has slightly different 597 | # "if" macro. 598 | 599 | assert_value quote(do: Kernel.||(1, false)) 600 | |> Macro.expand(__ENV__) 601 | |> Macro.to_string() 602 | |> String.replace( 603 | "when x in [false, nil]", 604 | "when Kernel.in(x, [false, nil])" 605 | ) == """ 606 | case(1) do 607 | x when Kernel.in(x, [false, nil]) -> 608 | false 609 | x -> 610 | x 611 | end 612 | """ 613 | end 614 | 615 | test "function without arguments" do 616 | # prompt: y 617 | assert_value Foo.foo() == "foo" 618 | 619 | # prompt: y 620 | assert_value Foo.foo() == "foo" 621 | end 622 | 623 | test "not-serializable expected" do 624 | # This should pass. We can successfully parse expected and replace 625 | # it with serialized value 626 | # prompt: y 627 | assert_value :foo == :foo 628 | end 629 | 630 | test "integer floats" do 631 | # prompt: y 632 | assert_value 2 == 2 633 | 634 | # prompt: y 635 | assert_value 1.0 == 1.0 636 | end 637 | 638 | end 639 | -------------------------------------------------------------------------------- /test/integration/parser_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule ParserTest do 2 | use ExUnit.Case, async: true 3 | 4 | @foo "foo" 5 | @bar "bar" 6 | 7 | defmodule User do 8 | defstruct name: "John", age: 27 9 | end 10 | 11 | defmodule Foo do 12 | def foo, do: "foo" 13 | end 14 | 15 | def f_nil() do 16 | # The way to dynamically generate nil, to avoid "type violation" warnings 17 | List.first([]) 18 | end 19 | 20 | def f_false() do 21 | List.first([false]) 22 | end 23 | 24 | def f_true() do 25 | List.first([true]) 26 | end 27 | 28 | def f_atom_foo() do 29 | List.first([:foo]) 30 | end 31 | 32 | def f_atom_bar() do 33 | List.first([:bar]) 34 | end 35 | 36 | import AssertValue 37 | 38 | # Literals 39 | 40 | test "actual literals" do 41 | # prompt: y 42 | assert_value nil 43 | 44 | # prompt: y 45 | assert_value true 46 | 47 | # prompt: y 48 | assert_value false 49 | 50 | # prompt: y 51 | assert_value :foo 52 | 53 | # prompt: y 54 | assert_value "forty-two" 55 | 56 | # prompt: y 57 | assert_value """ 58 | forty-two 59 | сорок два 60 | 四十二 61 | quarante deux 62 | cuarenta y dos 63 | zweiundvierzig 64 | """ 65 | 66 | # prompt: y 67 | assert_value ~S(forty-two) 68 | 69 | # prompt: y 70 | assert_value ~s(forty-two) 71 | 72 | # prompt: y 73 | assert_value <<65, 66, 67>> 74 | 75 | # prompt: y 76 | assert_value <<256 :: utf8>> 77 | 78 | # prompt: y 79 | assert_value ~c"forty-two" 80 | 81 | # prompt: y 82 | assert_value ~c""" 83 | forty-two 84 | сорок два 85 | """ 86 | # prompt: y 87 | assert_value ~C(forty-two) 88 | 89 | # prompt: y 90 | assert_value ~c(forty-two) 91 | 92 | # prompt: y 93 | assert_value ~D[2018-01-01] 94 | 95 | # prompt: y 96 | assert_value 0.42 97 | 98 | # prompt: y 99 | assert_value -0.42 100 | 101 | # prompt: y 102 | assert_value 42 103 | 104 | # prompt: y 105 | assert_value [4, 2, true, nil, "42"] 106 | 107 | # prompt: y 108 | assert_value %{a: "forty", b: 2, c: nil} 109 | 110 | # prompt: y 111 | assert_value ~N[2018-01-01 21:01:50] 112 | 113 | # prompt: y 114 | assert_value ~r/foo/ 115 | 116 | # prompt: y 117 | assert_value ~T[23:00:07] 118 | 119 | # prompt: y 120 | assert_value {:ok, 42} 121 | 122 | # prompt: y 123 | assert_value %User{} 124 | 125 | # prompt: y 126 | assert_value %User{age: 43} 127 | 128 | # prompt: y 129 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} 130 | 131 | # prompt: y 132 | assert_value ~W(foo bar) 133 | 134 | # prompt: y 135 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] 136 | end 137 | 138 | test "actual and expected literals" do 139 | # prompt: y 140 | assert_value nil == f_false() 141 | 142 | # prompt: y 143 | assert_value true == f_false() 144 | 145 | # prompt: y 146 | assert_value :foo == f_atom_bar() 147 | 148 | # prompt: y 149 | assert_value "forty-two" == "forty-three" 150 | 151 | # prompt: y 152 | assert_value """ 153 | forty-two 154 | сорок два 155 | 四十二 156 | quarante deux 157 | cuarenta y dos 158 | zweiundvierzig 159 | """ == """ 160 | forty-three 161 | сорок два 162 | quarante deux 163 | cuarenta y dos 164 | """ 165 | 166 | # prompt: y 167 | assert_value ~S(forty-two) == ~S(forty-three) 168 | 169 | # prompt: y 170 | assert_value ~s(forty-two) == ~s(forty-three) 171 | 172 | # prompt: y 173 | assert_value <<65, 66, 67>> == <<65, 66, 68>> 174 | 175 | # prompt: y 176 | assert_value <<256 :: utf8>> == <<267 :: utf8>> 177 | 178 | # prompt: y 179 | assert_value ~c"forty-two" == ~c"forty-three" 180 | 181 | # prompt: y 182 | assert_value ~c""" 183 | forty-two 184 | сорок два 185 | """ == ~c""" 186 | forty-three 187 | сорок три 188 | """ 189 | 190 | # prompt: y 191 | assert_value ~C(forty-two) == ~C(forty-three) 192 | 193 | # prompt: y 194 | assert_value ~c(forty-two) == ~c(forty-three) 195 | 196 | # prompt: y 197 | assert_value ~D[2018-01-01] == ~D[2018-01-02] 198 | 199 | # prompt: y 200 | assert_value 0.42 == 0.43 201 | 202 | # prompt: y 203 | assert_value -0.42 == -0.43 204 | 205 | # prompt: y 206 | assert_value 42 == 43 207 | 208 | # prompt: y 209 | assert_value -42 == 42 210 | 211 | # prompt: y 212 | assert_value [4, 2, true, nil, "42"] == [4, 3, true, nil, "42"] 213 | 214 | # prompt: y 215 | assert_value %{a: "forty", b: 2, c: nil} == %{a: "forty", b: 2, c: f_true()} 216 | 217 | # prompt: y 218 | assert_value ~N[2018-01-01 21:01:50] == ~N[2018-01-02 21:01:51] 219 | 220 | # prompt: y 221 | assert_value ~T[23:00:07] == ~T[23:00:07.001004] 222 | 223 | # prompt: y 224 | assert_value {:ok, 42} == {f_atom_bar(), 42} 225 | 226 | # prompt: y 227 | assert_value %User{} == %User{age: 42} 228 | 229 | # prompt: y 230 | assert_value %User{age: 42} == %User{age: 43} 231 | 232 | # This should pass 233 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %User{age: 21, name: "Peter"} 234 | 235 | # prompt: y 236 | assert_value %{__struct__: ParserTest.User, age: 21, name: "Peter"} == %{__struct__: ParserTest.User, age: 25, name: "James"} 237 | 238 | # prompt: y 239 | assert_value ~W(foo bar) == ~W(foo baz) 240 | 241 | # prompt: y 242 | assert_value [%{a: 42, b: {:left, :light}, c: [%User{}, 1]}, nil] == [%{a: 42, b: {:left, :light}, c: [%User{}, 2]}, nil] 243 | end 244 | 245 | test "expected literal" do 246 | # prompt: y 247 | assert_value Foo.foo() == nil 248 | 249 | # prompt: y 250 | assert_value Foo.foo() == true 251 | 252 | # prompt: y 253 | assert_value Foo.foo() == false 254 | 255 | # prompt: y 256 | assert_value Foo.foo() == :foo 257 | 258 | # prompt: y 259 | assert_value Foo.foo() == "forty-two" 260 | 261 | # prompt: y 262 | assert_value Foo.foo() == """ 263 | forty-three 264 | сорок два 265 | quarante deux 266 | cuarenta y dos 267 | """ 268 | 269 | # prompt: y 270 | assert_value Foo.foo() == ~S(forty-two) 271 | 272 | # prompt: y 273 | assert_value Foo.foo() == ~s(forty-two) 274 | 275 | # prompt: y 276 | assert_value Foo.foo() == <<65, 66, 67>> 277 | 278 | # prompt: y 279 | assert_value Foo.foo() == <<256 :: utf8>> 280 | 281 | # prompt: y 282 | assert_value Foo.foo() == ~c"forty-two" 283 | 284 | # prompt: y 285 | assert_value Foo.foo() == ~c""" 286 | forty-three 287 | сорок три 288 | """ 289 | 290 | # prompt: y 291 | assert_value Foo.foo() == ~C(forty-two) 292 | 293 | # prompt: y 294 | assert_value Foo.foo() == ~c(forty-two) 295 | 296 | # prompt: y 297 | assert_value Foo.foo() == ~D[2018-01-01] 298 | 299 | # prompt: y 300 | assert_value Foo.foo() == 0.42 301 | 302 | # prompt: y 303 | assert_value Foo.foo() == -0.42 304 | 305 | # prompt: y 306 | assert_value Foo.foo() == 42 307 | 308 | # prompt: y 309 | assert_value Foo.foo() == -42 310 | 311 | # prompt: y 312 | assert_value Foo.foo() == [4, 3, true, nil, "42"] 313 | 314 | # prompt: y 315 | assert_value Foo.foo() == %{a: "forty", b: 2, c: nil} 316 | 317 | # prompt: y 318 | assert_value Foo.foo() == ~N[2018-01-01 21:01:50] 319 | 320 | # prompt: y 321 | assert_value Foo.foo() == ~r/foo/ 322 | 323 | # prompt: y 324 | assert_value Foo.foo() == ~T[23:00:07] 325 | 326 | # prompt: y 327 | assert_value Foo.foo() == {:ok, 42} 328 | 329 | # prompt: y 330 | assert_value Foo.foo() == %User{} 331 | 332 | # prompt: y 333 | assert_value Foo.foo() == %User{age: 43} 334 | 335 | # prompt: y 336 | assert_value Foo.foo() == ~W(foo bar) 337 | 338 | # prompt: y 339 | assert_value Foo.foo() == [%{a: 42, b: {:left, :light}, c: [%User{}, 2]}, nil] 340 | end 341 | 342 | test "create file" do 343 | # prompt: y 344 | assert_value """ 345 | aaa 346 | bbb 347 | ccc 348 | """ == File.read!(Path.expand("file_to_create", __DIR__)) 349 | end 350 | 351 | test "update file" do 352 | # prompt: y 353 | assert_value """ 354 | aaa 355 | bbb 356 | ccc 357 | """ == File.read!(Path.expand("file_to_update", __DIR__)) 358 | end 359 | 360 | # Corner cases 361 | 362 | test "spaces around equation" do 363 | # prompt: y 364 | assert_value "foo"== "bar" 365 | 366 | # prompt: y 367 | assert_value "foo" =="bar" 368 | 369 | # prompt: y 370 | assert_value "foo"=="bar" 371 | 372 | # prompt: y 373 | assert_value "foo" == "bar" 374 | 375 | # prompt: y 376 | assert_value "foo" == "bar" 377 | 378 | # prompt: y 379 | assert_value "foo" == "bar" 380 | end 381 | 382 | test "string escaping" do 383 | # prompt: y 384 | assert_value "foo\\nbar\" \" \t \r %{}" == "foo" 385 | 386 | # prompt: y 387 | assert_value "foo" == "foo\\nbar\" \" \t \r %{}" 388 | end 389 | 390 | test "float trailing zeros" do 391 | # prompt: y 392 | assert_value 42.0001000 == 42.00020010 393 | 394 | # prompt: y 395 | assert_value -42.0001000 == -42.00020010 396 | end 397 | 398 | test "bitstring and string" do 399 | assert_value <<65>> == "A" 400 | # prompt: y 401 | assert_value <<66>> == "A" 402 | 403 | assert_value "A" == <<65>> 404 | # prompt: y 405 | assert_value "B" == <<65>> 406 | end 407 | 408 | # Expressions 409 | 410 | test "variable" do 411 | foo = "foo" 412 | bar = "bar" 413 | 414 | # prompt: y 415 | assert_value foo 416 | 417 | # prompt: y 418 | assert_value foo == bar 419 | end 420 | 421 | test "module attributes" do 422 | # prompt: y 423 | assert_value @foo 424 | 425 | # prompt: y 426 | assert_value @foo == @bar 427 | 428 | # prompt: y 429 | assert_value "foo" == @foo 430 | end 431 | 432 | test "parens" do 433 | # prompt: y 434 | assert_value("foo") 435 | 436 | # prompt: y 437 | assert_value ("foo") 438 | 439 | # prompt: y 440 | assert_value(("foo")) 441 | 442 | # prompt: y 443 | assert_value (("foo")) 444 | 445 | # prompt: y 446 | assert_value("foo" == "bar") 447 | 448 | # prompt: y 449 | assert_value ("foo" == "bar") 450 | 451 | # prompt: y 452 | assert_value(("foo" == "bar")) 453 | 454 | # prompt: y 455 | assert_value (("foo" == "bar")) 456 | 457 | # prompt: y 458 | assert_value ("foo") == ("bar") 459 | 460 | # prompt: y 461 | assert_value (("foo")) == (("bar")) 462 | 463 | # prompt: y 464 | assert_value((("foo")) == (("bar"))) 465 | 466 | # prompt: y 467 | assert_value ((("foo")) == (("bar"))) 468 | 469 | # prompt: y 470 | assert_value( 471 | ( 472 | ("foo") 473 | ) == ( 474 | ("bar") 475 | ) 476 | ) 477 | end 478 | 479 | test "left/right expressions" do 480 | foo = "foo" 481 | bar = "bar" 482 | 483 | # prompt: y 484 | assert_value foo <> "bar" 485 | 486 | # prompt: y 487 | assert_value foo <> "bar" == bar <> "baz" 488 | 489 | # prompt: y 490 | assert_value foo <> 491 | "bar" 492 | 493 | # prompt: y 494 | assert_value foo <> 495 | "bar" == 496 | bar 497 | <> "baz" 498 | end 499 | 500 | test "functions" do 501 | hello = fn(x) -> 502 | "Hello " <> x <> "!" 503 | end 504 | 505 | # prompt: y 506 | assert_value String.upcase("foo") 507 | 508 | # prompt: y 509 | assert_value hello.("World") 510 | 511 | # prompt: y 512 | assert_value String.upcase("foo") == String.upcase("bar") 513 | 514 | # prompt: y 515 | assert_value hello.("World") == hello.("Elixir") 516 | 517 | # prompt: y 518 | assert_value String.upcase( 519 | "foo" 520 | ) == String.upcase( 521 | "bar" 522 | ) 523 | end 524 | 525 | test "pipes" do 526 | # prompt: y 527 | assert_value String.upcase("foo") |> String.reverse == 528 | String.upcase("bar") |> String.reverse 529 | 530 | # prompt: y 531 | assert_value String.upcase("foo") 532 | |> String.reverse 533 | == 534 | String.upcase("bar") 535 | |> String.reverse 536 | end 537 | 538 | test "repeatable expressions" do 539 | # prompt: y 540 | assert_value 2 + 2 - 2 + 2 - 2 + 2 541 | 542 | # prompt: y 543 | assert_value 2 + 2 - 2 + 2 - 2 + 2 == 5 544 | 545 | # prompt: y 546 | assert_value 5 == 2 + 2 - 2 + 2 - 2 + 2 547 | end 548 | 549 | test "AST cleanup" do 550 | # Macro.expand below produces AST with hygienic counter 551 | # Check that we can correctly parse it 552 | # Last String.replace is to produce the same result code 553 | # from different Elixirs. 1.6.0 has slightly different 554 | # "if" macro. 555 | 556 | assert_value quote(do: Kernel.||(1, false)) 557 | |> Macro.expand(__ENV__) 558 | |> Macro.to_string 559 | |> String.replace( 560 | "when x in [false, nil]", 561 | "when Kernel.in(x, [false, nil])" 562 | ) 563 | end 564 | 565 | test "function without arguments" do 566 | # prompt: y 567 | assert_value Foo.foo 568 | 569 | # prompt: y 570 | assert_value Foo.foo() 571 | end 572 | 573 | test "not-serializable expected" do 574 | # This should pass. We can successfully parse expected and replace 575 | # it with serialized value 576 | # prompt: y 577 | assert_value :foo == Port.list() |> List.first 578 | end 579 | 580 | test "integer floats" do 581 | # prompt: y 582 | assert_value 2 == 1.0 583 | 584 | # prompt: y 585 | assert_value 1.0 == 2 586 | end 587 | 588 | end 589 | -------------------------------------------------------------------------------- /test/integration/reformat_expected_test.exs.after: -------------------------------------------------------------------------------- 1 | defmodule ReformatExpectedTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "regenerate" do 7 | assert_value "foo\nbar" == """ 8 | foo 9 | bar 10 | """ 11 | assert_value "foobar" == "foobar" 12 | 13 | assert_value "foo\nbar\n" == """ 14 | foo 15 | bar 16 | """ 17 | 18 | assert_value 2 + 2 == 4 19 | end 20 | 21 | test "reformat heredoc with empty lines" do 22 | # first line has leading spaces 23 | doc = """ 24 | 25 | bar 26 | 27 | baz 28 | """ 29 | 30 | # empty lines will not have leading spaces after reformatting 31 | assert_value doc == """ 32 | 33 | bar 34 | 35 | baz 36 | """ 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /test/integration/reformat_expected_test.exs.before: -------------------------------------------------------------------------------- 1 | defmodule ReformatExpectedTest do 2 | use ExUnit.Case, async: true 3 | 4 | import AssertValue 5 | 6 | test "regenerate" do 7 | assert_value "foo\nbar" == """ 8 | foo 9 | bar 10 | """ 11 | assert_value "foobar" == """ 12 | foobar 13 | """ 14 | 15 | assert_value "foo\nbar\n" == "foo\nbar\n" 16 | 17 | assert_value 2 + 2 == 4 18 | end 19 | 20 | test "reformat heredoc with empty lines" do 21 | # first line has leading spaces 22 | doc = """ 23 | 24 | bar 25 | 26 | baz 27 | """ 28 | 29 | # empty lines will not have leading spaces after reformatting 30 | assert_value doc == "\nbar\nbaz\n" 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /test/integration/reformat_expected_test.exs.output: -------------------------------------------------------------------------------- 1 | .. 2 | 2 tests, 0 failures 3 | -------------------------------------------------------------------------------- /test/integration_test.exs: -------------------------------------------------------------------------------- 1 | # Things to test: 2 | # 3 | # * Parser 4 | # * Formatter 5 | # * Diff 6 | # 7 | # The goal is to test everything with minimal number of tests. 8 | # 9 | # If we have parser test producing diff and updating expected we don't need to 10 | # add separate tests for diff and formatter because they are already covered 11 | # by parser test. 12 | # 13 | # For parser we need to test that parser can parse full assertion, actual, 14 | # and expected. So we can be sure that three tests 15 | # 16 | # ``` 17 | # assert_value :foo 18 | # assert_value :foo == :bar 19 | # assert_value "foo" == :foo 20 | # ``` 21 | # cover all parser tests for Atom literals. And we just need to repeat these 22 | # tests for all types and add tests for corner cases (see below) These tests 23 | # for parser also cover diff and formatter tests for all types. And we just 24 | # need corner cases tests in diff_test.exs and formatter_test.exs 25 | # 26 | # # Elixir Types 27 | # 28 | # * nil (Atom) 29 | # * true (Atom) 30 | # * false (Atom) 31 | # * Atom 32 | # * Binary 33 | # * String 34 | # * Heredoc 35 | # * ~S, ~s 36 | # * BitString 37 | # * Charlist 38 | # * Charllst 39 | # * Charlist Heredoc 40 | # * ~C, ~c 41 | # * Date 42 | # * Float 43 | # * Positive 44 | # * Negative 45 | # * Trailing Zeroes 46 | # * Integer 47 | # * Positive 48 | # * Negative 49 | # * Underscores 50 | # * List 51 | # * [] 52 | # * ~W 53 | # * ~w 54 | # * Map 55 | # * NaiveDateTime 56 | # * Regexp 57 | # * Time 58 | # * Tuple 59 | # * Module attributes @ 60 | # * Any (Struct) 61 | # 62 | # Not Serializable 63 | # 64 | # * Function 65 | # * PID 66 | # * Port 67 | # * Referencea 68 | # * Custom types (like Decimal) 69 | # 70 | # # Form 71 | # 72 | # * Not Present (Expected Only) 73 | # * Literal 74 | # * Expression 75 | # * File.read! (Expected Only) 76 | # 77 | # # Expressions 78 | # 79 | # * Variable 80 | # * Parens (including recursive) 81 | # * Match operator (=) 82 | # * Left, Right expressions 83 | # ** Comparison (===, <, >, >=, <=, !=, =~) 84 | # ** Other (++, <>, etc...) 85 | # * Functions calls (named and anonymous) 86 | # * Pipes 87 | # 88 | # * Expressions could be one-liners or multi-line 89 | # 90 | # We need to have two tests for each expression type 91 | # ``` 92 | # assert_value 93 | # assert_value == 94 | # ``` 95 | # then we are sure that we correctly these expressions type in actual 96 | # and expected. Plus of course corner cases like nested parens, etc... 97 | 98 | import AssertValue.IntegrationTest.Support, only: [build_test_module: 3] 99 | 100 | build_test_module(:ParserTest, "parser_test.exs", 101 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 102 | expected_exit_code: 0, 103 | expected_files: ["file_to_create", "file_to_update"] 104 | ) 105 | 106 | build_test_module(:FormatterTest, "formatter_test.exs", 107 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 108 | expected_exit_code: 0 109 | ) 110 | 111 | build_test_module(:DiffTest, "diff_test.exs", 112 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 113 | expected_exit_code: 0 114 | ) 115 | 116 | build_test_module(:DiffAndHelpPromtTest, "diff_and_help_prompt_test.exs", 117 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 118 | # There should be failed tests 119 | expected_exit_code: 1 120 | ) 121 | 122 | build_test_module(:MiscTest, "misc_test.exs", 123 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 124 | expected_exit_code: 1 125 | ) 126 | 127 | build_test_module(:AcceptAppTest, "accept_all_test.exs", 128 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 129 | # No failed tests 130 | expected_exit_code: 0 131 | ) 132 | 133 | build_test_module(:AcceptAllWithErrorsTest, "accept_all_with_error_test.exs", 134 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 135 | expected_exit_code: 1 136 | ) 137 | 138 | build_test_module(:DeclineAllTest, "decline_all_test.exs", 139 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "ask"}], 140 | expected_exit_code: 1 141 | ) 142 | 143 | build_test_module(:NonInteractiveAcceptTest, "non_interactive_accept_test.exs", 144 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "y"}], 145 | expected_exit_code: 0 146 | ) 147 | 148 | build_test_module(:NonInteractiveRejectTest, "non_interactive_reject_test.exs", 149 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "n"}], 150 | expected_exit_code: 1 151 | ) 152 | 153 | build_test_module(:ReformatExpectedTest, "reformat_expected_test.exs", 154 | env: [{"ASSERT_VALUE_ACCEPT_DIFFS", "reformat"}], 155 | expected_exit_code: 0 156 | ) 157 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start(timeout: :infinity) 2 | 3 | defmodule AssertValue.IntegrationTest.Support do 4 | # This helper is used to start external process, feed it with input, 5 | # and collect output. 6 | # 7 | # Inspired by Sasa Juric's post about running external programs with 8 | # Elixir's Port module: 9 | # http://theerlangelist.blogspot.com/2015/08/outside-elixir.html 10 | # 11 | # and Alexei Sholik's Porcelain basic driver 12 | # https://github.com/alco/porcelain/tree/master/lib/porcelain/drivers 13 | # 14 | # Usage example: 15 | # Run integration test session as external process, provide "yes" answers 16 | # for two prompts, and collect output and test results code: 17 | # 18 | # {output, exit_code} = AssertValue.System.exec("mix", 19 | # ["test", "--seed", "0", "/tmp/intergration_test.exs"], input: "y\ny\n") 20 | def exec(cmd, args, env, opts) do 21 | cmd = cmd |> System.find_executable() 22 | # A Port’s :env option expects {:env, [{k, v}, ...]} with k and v 23 | # as charlists. We specify them as binary because it is easier to 24 | # write "y", then ~c"y" and we have them a lot 25 | env = Enum.map(env, fn {k, v} -> 26 | {to_charlist(k), to_charlist(v)} 27 | end) 28 | 29 | port = 30 | Port.open( 31 | {:spawn_executable, cmd}, 32 | [{:args, args}, {:env, env}, :binary, :exit_status] 33 | ) 34 | 35 | Port.command(port, opts[:input]) 36 | handle_output(port, "") 37 | end 38 | 39 | # This function recursively collects data provided by external 40 | # process indentified with port until it get :exit_status message. 41 | defp handle_output(port, output) do 42 | receive do 43 | {^port, {:data, data}} -> 44 | handle_output(port, output <> data) 45 | 46 | {^port, {:exit_status, exit_code}} -> 47 | {output, exit_code} 48 | end 49 | end 50 | 51 | @integration_test_dir Path.expand("integration", __DIR__) 52 | 53 | def prepare_runnable_test(basename, runnable_test_dir) do 54 | before_path = Path.expand(basename <> ".before", @integration_test_dir) 55 | after_path = Path.expand(basename <> ".after", @integration_test_dir) 56 | output_path = Path.expand(basename <> ".output", @integration_test_dir) 57 | # Due to difference in formatter we may need different output 58 | # files for different Elixir versions 59 | after_path = latest_compatible_output_file(System.version(), after_path) 60 | output_path = latest_compatible_output_file(System.version(), output_path) 61 | # copy the test to a temp dir for running 62 | runnable_path = Path.expand(basename, runnable_test_dir) 63 | File.cp!(before_path, runnable_path) 64 | {runnable_path, after_path, output_path} 65 | end 66 | 67 | def latest_compatible_output_file(version, path) do 68 | versioned_paths = Path.wildcard("#{path}.*") 69 | 70 | if Enum.empty?(versioned_paths) do 71 | path 72 | else 73 | compatible_versions = 74 | versioned_paths 75 | # get version from filename "parser_test.exs.output.1.8" => "1.8" 76 | |> Enum.map(&String.replace(&1, "#{path}.", "")) 77 | # find compatible versions 78 | |> Enum.filter(&Version.match?(version, "~>#{&1}")) 79 | 80 | if Enum.empty?(compatible_versions) do 81 | path 82 | else 83 | latest_compatible_version = 84 | compatible_versions 85 | |> Enum.max_by(&Version.parse("#{&1}.0")) 86 | 87 | "#{path}.#{latest_compatible_version}" 88 | end 89 | end 90 | end 91 | 92 | def run_tests(filename, env \\ []) do 93 | # extract expected assert_value prompt responses from the test. 94 | # We look for lines like '# prompt: y' 95 | prompt_responses = 96 | Regex.scan(~r/#\s*prompt:\s*(.)/, File.read!(filename)) 97 | |> Enum.map_join("\n", fn [_, x] -> x end) 98 | |> Kernel.<>("\n") 99 | 100 | # Elixir 1.13 changed default failed testcase exit status to 2 101 | # and introduced --exit-status param 102 | exec_params = 103 | if Version.match?(System.version(), ">= 1.13.0") do 104 | ["test", "--seed", "0", "--exit-status", "1", filename] 105 | else 106 | ["test", "--seed", "0", filename] 107 | end 108 | 109 | # In Elixir 1.18, mix locks the _build directory on compile. 110 | # Even without actual compilation the lock is briefly acquired. 111 | # Running many 'mix test' subprocesses concurrently in integration 112 | # tests may produce many "Waiting for lock on the build directory" 113 | # messages. 114 | # 115 | # Spawned child tests don’t require compilation, so we disable 116 | # the _build lock to avoid it. 117 | env = 118 | if Version.match?(System.version(), ">= 1.18.0") do 119 | env ++ [{"MIX_OS_CONCURRENCY_LOCK", "false"}] 120 | else 121 | env 122 | end 123 | 124 | {output, exit_code} = 125 | AssertValue.IntegrationTest.Support.exec( 126 | "mix", 127 | exec_params, 128 | env, 129 | input: prompt_responses 130 | ) 131 | 132 | # Canonicalize output 133 | output = 134 | output 135 | |> String.replace(~r/Running ExUnit with seed.*\n+/m, "\n") 136 | |> String.replace(~r{\/tmp\/assert-value-\w+/}, "") 137 | |> String.replace(~r/\n+Finished in[^\n]+\n+/m, "\n") 138 | |> String.replace(~r/\n+(\d+ tests)/m, "\n\\1") 139 | |> String.replace(~r/\nRandomized with seed.*\n/m, "") 140 | # mask line numbers 141 | |> String.replace(~r/(_test.exs:)\d+/, "\\1##") 142 | # canonicalize ExUnit error formatting: 143 | # - remove fancy spacing 144 | |> String.replace(~r/\s{5}code:\s+actual/m, " code: actual") 145 | |> String.replace(~r/\s{5}(left):\s+"/m, " left: \"") 146 | |> String.replace(~r/\s{5}(right):\s+"/m, " right: \"") 147 | # canonicalize messages about raised exceptions 148 | # ExUnit in Elixir 1.5 has "code:" line in message: 149 | # 150 | # ** (RuntimeError) Error! 151 | # code: raise "Error!" 152 | # stacktrace: 153 | # integration_test.exs:82: (test) 154 | # 155 | # ExUnit in Elixir 1.4 does not 156 | # 157 | # ** (RuntimeError) Error! 158 | # stacktrace: 159 | # integration_test.exs:82: (test) 160 | # 161 | |> String.replace( 162 | ~r/(\*\* \(.*?Error\).*?)\n\s{5}code:.*?\n/, 163 | "\\1\n" 164 | ) 165 | |> String.trim("\n") 166 | |> Kernel.<>("\n") 167 | 168 | {output, exit_code} 169 | end 170 | 171 | def prepare_expected_files(filenames, runnable_test_dir) do 172 | Enum.map(filenames, fn filename -> 173 | before_path = Path.expand(filename <> ".before", @integration_test_dir) 174 | after_path = Path.expand(filename <> ".after", @integration_test_dir) 175 | runnable_path = Path.expand(filename, runnable_test_dir) 176 | 177 | if File.exists?(before_path) do 178 | File.cp!(before_path, runnable_path) 179 | end 180 | 181 | [runnable_path, after_path] 182 | end) 183 | end 184 | 185 | # Integration test flow: 186 | # * Copy integration_test.exs.before to runnable_test_dir 187 | # * launch a child `mix test integration_test.exs` 188 | # * accept or reject assert_value changes when prompted 189 | # * compare test source file itself after the run with a reference copy 190 | # * compare test output with a reference copy 191 | # 192 | # We build the integration test module instead of just test to run 193 | # integration tests async 194 | # 195 | # Usage: 196 | # 197 | # import AssertValue.IntegrationTest.Support, only: [build_test_module: 3] 198 | # build_test_module :ParserTest, "parser_test.exs", 199 | # env: [{'ASSERT_VALUE_ACCEPT_DIFFS', 'ask'}], 200 | # expected_exit_code: 0, 201 | # expected_files: ["file_to_create", "file_to_update"] 202 | # 203 | defmacro build_test_module(module_name, test_filename, opts \\ []) do 204 | expected_files = Keyword.get(opts, :expected_files, []) 205 | expected_exit_code = Keyword.get(opts, :expected_exit_code, 0) 206 | runnable_test_dir = make_temp_dir("assert-value") 207 | test_name = "running integration #{module_name}" 208 | 209 | quote do 210 | defmodule unquote(module_name) do 211 | use ExUnit.Case, async: true 212 | 213 | import AssertValue 214 | 215 | import AssertValue.IntegrationTest.Support, 216 | only: [ 217 | prepare_runnable_test: 2, 218 | prepare_expected_files: 2, 219 | run_tests: 2 220 | ] 221 | 222 | setup_all do 223 | # Make sure we delete temporary dir even if tests fail 224 | on_exit(fn -> 225 | File.rm_rf!(unquote(runnable_test_dir)) 226 | end) 227 | 228 | :ok 229 | end 230 | 231 | test unquote(test_name) do 232 | {runnable_path, after_path, output_path} = 233 | prepare_runnable_test( 234 | unquote(test_filename), 235 | unquote(runnable_test_dir) 236 | ) 237 | 238 | expected_files = 239 | prepare_expected_files( 240 | unquote(expected_files), 241 | unquote(runnable_test_dir) 242 | ) 243 | 244 | {output, exit_code} = run_tests(runnable_path, unquote(opts[:env])) 245 | assert exit_code == unquote(expected_exit_code) 246 | test_source_result = File.read!(runnable_path) 247 | # Make sure resulting test file is valid Elixir code 248 | # Will raise SyntaxError or TokenMissingError otherwise 249 | Code.string_to_quoted!(test_source_result) 250 | assert_value test_source_result == File.read!(after_path) 251 | assert_value output == File.read!(output_path) 252 | 253 | Enum.each(expected_files, fn [runnable_path, after_path] -> 254 | assert_value(File.read!(runnable_path) == File.read!(after_path)) 255 | end) 256 | end 257 | end 258 | end 259 | end 260 | 261 | def make_temp_dir(basename) do 262 | random_string = 263 | :rand.uniform(0x100000000) 264 | |> Integer.to_string(36) 265 | |> String.downcase() 266 | 267 | dirname = 268 | Path.expand( 269 | basename <> "-" <> random_string, 270 | System.tmp_dir!() 271 | ) 272 | 273 | File.mkdir!(dirname) 274 | System.at_exit(fn _status -> File.rm_rf(dirname) end) 275 | dirname 276 | end 277 | end 278 | --------------------------------------------------------------------------------