1

Here is the code I am testing:

defmodule BracketParser do
    @spec parse_line(binary) :: binary
    def parse_line(line), do: parse_line_as_list(String.graphemes(line), false, [])
    defp parse_line_as_list([], true, _acc) do
        IO.puts("hello")
        raise SyntaxError
    end
    defp parse_line_as_list([], _collect, acc) do
        Enum.reverse(acc) |> IO.iodata_to_binary
    end
    defp parse_line_as_list(["{" | t], _collect, acc) do
        parse_line_as_list(t, true, acc)
    end
    defp parse_line_as_list(["}" | t], _collect, acc) do
        parse_line_as_list(t, false, acc)
    end
    defp parse_line_as_list([h | t], true, acc) do
        parse_line_as_list(t, true, [h | acc])
    end
    defp parse_line_as_list([_h | t], collect, acc) do
        parse_line_as_list(t, collect, acc)
    end
end

This is my test:

ExUnit.start

defmodule TestBracketParser do
    use ExUnit.Case

    test "should get the text inside a pair of brackets" do
        assert_raise SyntaxError, fn() -> BracketParser.parse_line("{bill") end
    end
end

The goal is to have a parser that collects text between {} symbols. I expect the code to raise a Syntax error if the list is empty and the collection flag is set to true. However, when I run this code I get this:

  1) test should get the text inside a pair of brackets (TestBracketParser)
     test_parse_brackets.exs:6
     Got exception SyntaxError but it failed to produce a message with:

     ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1
         (elixir) lib/io.ex:461: IO.chardata_to_string(nil)
         (elixir) lib/path.ex:312: Path.relative_to/2
         (elixir) lib/exception.ex:713: SyntaxError.message/1
         (ex_unit) lib/ex_unit/assertions.ex:658: ExUnit.Assertions.check_error_message/2
         (ex_unit) lib/ex_unit/assertions.ex:639: ExUnit.Assertions.assert_raise/2
         test_parse_brackets.exs:10: TestBracketParser."test should get the text inside a pair of brackets"/1
         (ex_unit) lib/ex_unit/runner.ex:306: ExUnit.Runner.exec_test/1
         (stdlib) timer.erl:166: :timer.tc/1
         (ex_unit) lib/ex_unit/runner.ex:245: anonymous fn/4 in ExUnit.Runner.spawn_test/3

I have no idea why there is a FunctionClauseError being thrown. I seem to have accounted for all patterns. What am I doing wrong?

dopatraman
  • 13,416
  • 29
  • 90
  • 154

1 Answers1

3

As the documentation for raise states,

If msg is an atom, it just calls raise/2 with the atom as the first argument and [] as the second argument.

raise/2 will call the exception/1 function on the argument.

In your case, you should either use raise "SyntaxError", or provide a module called SyntaxError that calls defexception/1.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
Justin Wood
  • 9,941
  • 2
  • 33
  • 46