Elixir: Configure a mix project to always print charlists as lists?

老子叫甜甜 提交于 2021-01-29 11:27:30

问题


In testing my Phoenix app, I keep running into situations where I'm comparing lists of expected versus actual record IDs. Errors are tedious to interpret because Elixir keeps printing the integer lists as charlists, so my test output looks like:

     Assertion with == failed
     code:  assert H.sort(Enum.map(list1, &(&1.id()))) == H.sort(Enum.map(list2, &(&1.id())))
     left:  'stu'
     right: 'st'

This is nudging me to rewrite my tests to avoid comparing lists of integers, which is tolerable, but it's a shame to just shrug and look for a workaround in a language like this. So I'm wondering if there's a way to tell Elixir/Mix to always print integer lists as lists, rather than as charlists/charstrings. I write Ruby-styled Elixir and I almost never make use of charlists, to me they're mostly a gotcha to work around.

Thanks to this answer I know there's a way to configure IEx to always print integer lists as lists. Is there a way to do so in Mix, or globally in Elixir itself, so mix test will adopt that behavior?


回答1:


This is not configurable in ExUnit, it goes down to calling Inspect.Algebra.to_doc/2 with the Inspect.Opts hardcoded to %Inspect.Opts{width: width}.

In your own code, you always might pass the second argument in a call to inspect/2, like

IO.inspect('ABC', charlists: :as_list)
#⇒ [65, 66, 67]



回答2:


The "humanizing" of charlists is perhaps one of the most confusing gotchas in Elixir. As @Aleksei points out, this isn't configurable in ExUnit (although you can configure iex by adding IEx.configure(inspect: [charlists: :as_lists]) in your .iex.exs file).

However, you should not need to rewrite your tests. Keep in mind that the way that values are printed is only a view on the data. It does not affect how the data are stored.

Your example assertion failed because 'stu' is not equal to 'st' just as [115, 116, 117] is not equal to [115, 116].

Look at the following code:

iex> [115, 116, 117] === 'stu'
true

The left and right sides are 100% exactly equivalent. The single-quotes merely allow humans to enter data more easily.

In your particular case, you might want to take a look at MapSet, especially if your list of IDs are unique. Then you can avoid the awkward/brittle sorting prior to comparison. With MapSet, you can just compare the two sets for equality. For example:

expected_ids = MapSet.new([115, 116, 117])
actual_ids = MapSet.new(some_function_output)

assert MapSet.equal?(actual_ids, expected_ids)

This might help avoid the tedious tracking down of errors caused by the charlists. Another option in your case might be to convert the integers to strings during the mapping, e.g. Enum.map(list1, fn x -> to_string(x.id) end)



来源:https://stackoverflow.com/questions/65087836/elixir-configure-a-mix-project-to-always-print-charlists-as-lists

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!