diff --git a/test/range_test.exs b/test/range_test.exs index 6943eeb..c8492a0 100644 --- a/test/range_test.exs +++ b/test/range_test.exs @@ -2,6 +2,8 @@ defmodule SourcerorTest.RangeTest do use ExUnit.Case, async: true doctest Sourceror.Range + import SourcerorTest.RangeSupport, only: [decorate: 2] + alias SourcerorTest.Support.Corpus defp to_range(string, opts \\ []) do @@ -12,733 +14,1001 @@ defmodule SourcerorTest.RangeTest do describe "get_range/1" do test "with comments" do - assert to_range(~S""" - # Foo - :bar - """) == %{start: [line: 2, column: 1], end: [line: 2, column: 5]} + code = ~S""" + # Foo + :bar + """ - assert to_range( - ~S""" + assert decorate(code, to_range(code)) == + """ # Foo - :bar - """, - include_comments: true - ) == %{start: [line: 1, column: 1], end: [line: 2, column: 5]} - - assert to_range(~S""" - # Foo - # Bar - :baz - """) == %{start: [line: 3, column: 1], end: [line: 3, column: 5]} - - assert to_range( - ~S""" + «:bar» + """ + |> String.trim_trailing() + + assert decorate(code, to_range(code, include_comments: true)) == + """ + «# Foo + :bar» + """ + |> String.trim_trailing() + + code = ~S""" + # Foo + # Bar + :baz + """ + + assert decorate(code, to_range(code)) == + """ # Foo # Bar - :baz - """, - include_comments: true - ) == %{start: [line: 1, column: 1], end: [line: 3, column: 5]} + «:baz» + """ + |> String.trim_trailing() - assert to_range(~S""" - :baz # Foo - """) == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} + assert decorate(code, to_range(code, include_comments: true)) == + """ + «# Foo + # Bar + :baz» + """ + |> String.trim_trailing() - assert to_range( - ~S""" - :baz # Foo - """, - include_comments: true - ) == %{start: [line: 1, column: 1], end: [line: 1, column: 11]} + code = ~S""" + :baz # Foo + """ - assert to_range(~S""" - # Foo - :baz # Bar - """) == %{start: [line: 2, column: 1], end: [line: 2, column: 5]} + assert decorate(code, to_range(code)) == + """ + «:baz» # Foo + """ + |> String.trim_trailing() - assert to_range( - ~S""" + assert decorate(code, to_range(code, include_comments: true)) == + """ + «:baz # Foo» + """ + |> String.trim_trailing() + + code = ~S""" + # Foo + :baz # Bar + """ + + assert decorate(code, to_range(code)) == + """ # Foo - :baz # Bar - """, - include_comments: true - ) == %{start: [line: 1, column: 1], end: [line: 2, column: 11]} + «:baz» # Bar + """ + |> String.trim_trailing() + + assert decorate(code, to_range(code, include_comments: true)) == + """ + «# Foo + :baz # Bar» + """ + |> String.trim_trailing() end test "numbers" do - assert to_range("1") == %{start: [line: 1, column: 1], end: [line: 1, column: 2]} - assert to_range("100") == %{start: [line: 1, column: 1], end: [line: 1, column: 4]} - assert to_range("1_000") == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} - - assert to_range("1.0") == %{start: [line: 1, column: 1], end: [line: 1, column: 4]} - assert to_range("1.00") == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} - assert to_range("1_000.0") == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = "1" + assert decorate(code, to_range(code)) == "«1»" + code = "100" + assert decorate(code, to_range(code)) == "«100»" + code = "1_000" + assert decorate(code, to_range(code)) == "«1_000»" + + code = "1.0" + assert decorate(code, to_range(code)) == "«1.0»" + code = "1.00" + assert decorate(code, to_range(code)) == "«1.00»" + code = "1_000.0" + assert decorate(code, to_range(code)) == "«1_000.0»" end test "strings" do - assert to_range(~S/"foo"/) == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} - assert to_range(~S/"fo\no"/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} - - assert to_range(~S''' - """ - foo - - bar - """ - ''') == %{start: [line: 1, column: 1], end: [line: 5, column: 4]} - - assert to_range(~S''' - """ + code = ~S/"foo"/ + assert decorate(code, to_range(code)) == "«\"foo\"»" + code = ~S/"fo\no"/ + assert decorate(code, to_range(code)) == "«\"fo\\no\"»" + + code = ~S''' + """ + foo + + bar + """ + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «""" foo + bar - """ - ''') == %{start: [line: 1, column: 3], end: [line: 4, column: 6]} + """» + ''' + |> String.trim_trailing() + + code = ~S''' + """ + foo + bar + """ + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «""" + foo + bar + """» + ''' + |> String.trim_trailing() end test "strings with interpolations" do - assert to_range(~S/"foo#{2}bar"/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 13] - } - - assert to_range(~S''' - "foo#{ - 2 - }bar" - ''') == %{ - start: [line: 1, column: 1], - end: [line: 3, column: 8] - } - - assert to_range(~S''' - "foo#{ - 2 - } - bar" - ''') == %{ - start: [line: 1, column: 1], - end: [line: 4, column: 7] - } - - assert to_range(~S''' - "foo#{ - 2 - } - bar - " - ''') == %{ - start: [line: 1, column: 1], - end: [line: 5, column: 2] - } + code = ~S/"foo#{2}bar"/ + assert decorate(code, to_range(code)) == ~S/«"foo#{2}bar"»/ + + code = ~S''' + "foo#{ + 2 + }bar" + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «"foo#{ + 2 + }bar"» + ''' + |> String.trim_trailing() + + code = ~S''' + "foo#{ + 2 + } + bar" + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «"foo#{ + 2 + } + bar"» + ''' + |> String.trim_trailing() + + code = ~S''' + "foo#{ + 2 + } + bar + " + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «"foo#{ + 2 + } + bar + "» + ''' + |> String.trim_trailing() end test "charlists" do - assert to_range(~S/'foo'/) == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} - assert to_range(~S/'fo\no'/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S/'foo'/ + assert decorate(code, to_range(code)) == "«'foo'»" + code = ~S/'fo\no'/ + assert decorate(code, to_range(code)) == "«'fo\\no'»" - assert to_range(~S""" - ''' - foo + code = ~S""" + ''' + foo - bar - ''' - """) == %{start: [line: 1, column: 1], end: [line: 5, column: 4]} + bar + ''' + """ - assert to_range(~S""" - ''' + assert decorate(code, to_range(code)) == + ~S""" + «''' foo + bar - ''' - """) == %{start: [line: 1, column: 3], end: [line: 4, column: 6]} + '''» + """ + |> String.trim_trailing() + + code = ~S""" + ''' + foo + bar + ''' + """ + + assert decorate(code, to_range(code)) == + ~S""" + «''' + foo + bar + '''» + """ + |> String.trim_trailing() end test "charlists with interpolations" do - assert to_range(~S/'foo#{2}bar'/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 13] - } - - assert to_range(~S""" - 'foo#{ - 2 - }bar' - """) == %{ - start: [line: 1, column: 1], - end: [line: 3, column: 8] - } - - assert to_range(~S""" - 'foo#{ - 2 - } - bar' - """) == %{ - start: [line: 1, column: 1], - end: [line: 4, column: 7] - } - - assert to_range(~S""" - 'foo#{ - 2 - } - bar - ' - """) == %{ - start: [line: 1, column: 1], - end: [line: 5, column: 2] - } - end + code = ~S/'foo#{2}bar'/ + assert decorate(code, to_range(code)) == ~S/«'foo#{2}bar'»/ - test "atoms" do - assert to_range(~S/:foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} - assert to_range(~S/:"foo"/) == %{start: [line: 1, column: 1], end: [line: 1, column: 7]} - assert to_range(~S/:'foo'/) == %{start: [line: 1, column: 1], end: [line: 1, column: 7]} - assert to_range(~S/:"::"/) == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} + code = ~S""" + 'foo#{ + 2 + }bar' + """ + + assert decorate(code, to_range(code)) == + ~S""" + «'foo#{ + 2 + }bar'» + """ + |> String.trim_trailing() + + code = ~S""" + 'foo#{ + 2 + } + bar' + """ - assert to_range(~S''' - :"foo + assert decorate(code, to_range(code)) == + ~S""" + «'foo#{ + 2 + } + bar'» + """ + |> String.trim_trailing() + + code = ~S""" + 'foo#{ + 2 + } + bar + ' + """ - bar" - ''') == %{start: [line: 1, column: 1], end: [line: 3, column: 5]} + assert decorate(code, to_range(code)) == + ~S""" + «'foo#{ + 2 + } + bar + '» + """ + |> String.trim_trailing() + end + + test "atoms" do + code = ~S/:foo/ + assert decorate(code, to_range(code)) == "«:foo»" + code = ~S/:"foo"/ + assert decorate(code, to_range(code)) == "«:\"foo\"»" + code = ~S/:'foo'/ + assert decorate(code, to_range(code)) == "«:'foo'»" + code = ~S/:"::"/ + assert decorate(code, to_range(code)) == "«:\"::\"»" + + code = ~S''' + :"foo + + bar" + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «:"foo + + bar"» + ''' + |> String.trim_trailing() end test "atoms with interpolations" do - assert to_range(~S/:"foo#{2}bar"/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } - - assert to_range(~S''' - :"foo#{ - 2 - }bar" - ''') == %{ - start: [line: 1, column: 1], - end: [line: 3, column: 8] - } - - assert to_range(~S''' - :"foo#{ - 2 - } - bar" - ''') == %{ - start: [line: 1, column: 1], - end: [line: 4, column: 5] - } + code = ~S/:"foo#{2}bar"/ + assert decorate(code, to_range(code)) == ~S/«:"foo#{2}bar"»/ + + code = ~S''' + :"foo#{ + 2 + }bar" + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «:"foo#{ + 2 + }bar"» + ''' + |> String.trim_trailing() + + code = ~S''' + :"foo#{ + 2 + } + bar" + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «:"foo#{ + 2 + } + bar"» + ''' + |> String.trim_trailing() end test "variables" do - assert to_range(~S/foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 4]} + code = ~S/foo/ + assert decorate(code, to_range(code)) == "«foo»" end test "tuples" do - assert to_range(~S/{1, 2, 3}/) == %{start: [line: 1, column: 1], end: [line: 1, column: 10]} + code = ~S/{1, 2, 3}/ + assert decorate(code, to_range(code)) == "«{1, 2, 3}»" + + code = ~S""" + { + 1, + 2, + 3 + } + """ + + assert decorate(code, to_range(code)) == + """ + «{ + 1, + 2, + 3 + }» + """ + |> String.trim_trailing() - assert to_range(~S""" - { - 1, - 2, - 3 - } - """) == %{start: [line: 1, column: 1], end: [line: 5, column: 2]} + code = ~S""" + {1, + 2, + 3} + """ - assert to_range(~S""" - {1, - 2, - 3} - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 6]} + assert decorate(code, to_range(code)) == + """ + «{1, + 2, + 3}» + """ + |> String.trim_trailing() end test "2-tuples from keyword lists" do - {_, _, [[tuple]]} = Sourceror.parse_string!(~S/[foo: :bar]/) + code = ~S"[foo: :bar]" + {_, _, [[tuple]]} = Sourceror.parse_string!(code) - assert Sourceror.Range.get_range(tuple) == %{ - start: [line: 1, column: 2], - end: [line: 1, column: 11] - } + range = Sourceror.Range.get_range(tuple) + assert decorate(code, range) == ~S"[«foo: :bar»]" end test "2-tuples from partial keyword lists" do alias Sourceror.Zipper, as: Z + code = ~S""" + config :my_app, :some_key, + a: b + """ + value = - Sourceror.parse_string!(~S""" - config :my_app, :some_key, - a: b - """) + code + |> Sourceror.parse_string!() |> Z.zip() |> Z.down() |> Z.rightmost() |> Z.node() - assert Sourceror.Range.get_range(value) == %{ - start: [line: 2, column: 3], - end: [line: 2, column: 7] - } + range = Sourceror.Range.get_range(value) + + assert decorate(code, range) == + ~S""" + config :my_app, :some_key, + «a: b» + """ + |> String.trim_trailing() + + code = ~S""" + config :my_app, :some_key, + a: b, + c: + d + """ value = - Sourceror.parse_string!(~S""" - config :my_app, :some_key, - a: b, - c: - d - """) + code + |> Sourceror.parse_string!() |> Z.zip() |> Z.down() |> Z.rightmost() |> Z.node() - assert Sourceror.Range.get_range(value) == %{ - start: [line: 2, column: 3], - end: [line: 4, column: 6] - } + range = Sourceror.Range.get_range(value) + + assert decorate(code, range) == + ~S""" + config :my_app, :some_key, + «a: b, + c: + d» + """ + |> String.trim_trailing() end test "stabs" do alias Sourceror.Zipper, as: Z + code = ~S""" + case do + a -> b + c, d -> e + end + """ + [{_, stabs}] = - Sourceror.parse_string!(~S""" - case do - a -> b - c, d -> e - end - """) + code + |> Sourceror.parse_string!() |> Z.zip() |> Z.down() |> Z.node() - assert Sourceror.Range.get_range(stabs) == %{ - start: [line: 2, column: 3], - end: [line: 3, column: 12] - } + range = Sourceror.Range.get_range(stabs) + + assert decorate(code, range) == + ~S""" + case do + «a -> b + c, d -> e» + end + """ + |> String.trim_trailing() end test "stab without args" do - {:fn, _, [stab]} = Sourceror.parse_string!(~S"fn -> :ok end") + code = ~S"fn -> :ok end" + {:fn, _, [stab]} = Sourceror.parse_string!(code) + + range = Sourceror.Range.get_range(stab) + assert decorate(code, range) == "fn «-> :ok» end" - assert Sourceror.Range.get_range(stab) == %{ - start: [line: 1, column: 4], - end: [line: 1, column: 10] - } + code = ~S""" + fn -> + :ok + end + """ - {:fn, _, [stab]} = - Sourceror.parse_string!(~S""" - fn -> - :ok - end - """) + {:fn, _, [stab]} = Sourceror.parse_string!(code) - assert Sourceror.Range.get_range(stab) == %{ - start: [line: 1, column: 4], - end: [line: 2, column: 6] - } + range = Sourceror.Range.get_range(stab) + + assert decorate(code, range) == + """ + fn «-> + :ok» + end + """ + |> String.trim() end test "stab without body" do - {:fn, _, [stab]} = Sourceror.parse_string!(~S"fn -> end") + code = ~S"fn -> end" + {:fn, _, [stab]} = Sourceror.parse_string!(code) - assert Sourceror.Range.get_range(stab) == %{ - start: [line: 1, column: 4], - end: [line: 1, column: 6] - } + range = Sourceror.Range.get_range(stab) + assert decorate(code, range) == "fn «->» end" - {:fn, _, [stab]} = - Sourceror.parse_string!(~S""" - fn a -> - end - """) + code = ~S""" + fn a -> + end + """ - assert Sourceror.Range.get_range(stab) == %{ - start: [line: 1, column: 4], - end: [line: 1, column: 8] - } + {:fn, _, [stab]} = Sourceror.parse_string!(code) + + range = Sourceror.Range.get_range(stab) + + assert decorate(code, range) == + """ + fn «a ->» + end + """ + |> String.trim() end test "anonymous functions" do - assert to_range(~S"fn -> :ok end") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } + code = ~S"fn -> :ok end" + assert decorate(code, to_range(code)) == "«fn -> :ok end»" - assert to_range(~S""" - fn -> - :ok - end - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 4]} + code = ~S""" + fn -> + :ok + end + """ - assert to_range(~S""" - fn -> end - """) == %{start: [line: 1, column: 1], end: [line: 1, column: 10]} + assert decorate(code, to_range(code)) == + """ + «fn -> + :ok + end» + """ + |> String.trim() + + code = ~S""" + fn -> end + """ + + assert decorate(code, to_range(code)) == + """ + «fn -> end» + """ + |> String.trim() - assert to_range(~S""" - fn -> - end - """) == %{start: [line: 1, column: 1], end: [line: 2, column: 4]} + code = ~S""" + fn -> + end + """ + + assert decorate(code, to_range(code)) == + """ + «fn -> + end» + """ + |> String.trim() end test "qualified tuples" do - assert to_range(~S/Foo.{Bar, Baz}/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } - - assert to_range(~S""" - Foo.{ - Bar, - Bar, - Qux - } - """) == %{start: [line: 1, column: 1], end: [line: 5, column: 2]} - - assert to_range(~S""" - Foo.{Bar, - Baz, - Qux} - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 8]} + code = ~S/Foo.{Bar, Baz}/ + assert decorate(code, to_range(code)) == "«Foo.{Bar, Baz}»" + + code = ~S""" + Foo.{ + Bar, + Bar, + Qux + } + """ + + assert decorate(code, to_range(code)) == + """ + «Foo.{ + Bar, + Bar, + Qux + }» + """ + |> String.trim_trailing() + + code = ~S""" + Foo.{Bar, + Baz, + Qux} + """ + + assert decorate(code, to_range(code)) == + """ + «Foo.{Bar, + Baz, + Qux}» + """ + |> String.trim_trailing() end test "lists" do - assert to_range(~S/[1, 2, 3]/) == %{start: [line: 1, column: 1], end: [line: 1, column: 10]} + code = ~S/[1, 2, 3]/ + assert decorate(code, to_range(code)) == "«[1, 2, 3]»" + + code = ~S""" + [ + 1, + 2, + 3 + ] + """ + + assert decorate(code, to_range(code)) == + """ + «[ + 1, + 2, + 3 + ]» + """ + |> String.trim_trailing() - assert to_range(~S""" - [ - 1, - 2, - 3 - ] - """) == %{start: [line: 1, column: 1], end: [line: 5, column: 2]} + code = ~S""" + [1, + 2, + 3] + """ - assert to_range(~S""" - [1, - 2, - 3] - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 6]} + assert decorate(code, to_range(code)) == + """ + «[1, + 2, + 3]» + """ + |> String.trim_trailing() end test "keyword blocks" do - assert to_range(~S/foo do :ok end/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~S/foo do :ok end/ + assert decorate(code, to_range(code)) == "«foo do :ok end»" - assert to_range(~S""" - foo do - :ok - end - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 4]} + code = ~S""" + foo do + :ok + end + """ + + assert decorate(code, to_range(code)) == + """ + «foo do + :ok + end» + """ + |> String.trim() end test "blocks with parens" do - assert to_range(~S/(1; 2; 3)/) == %{start: [line: 1, column: 1], end: [line: 1, column: 10]} + code = ~S/(1; 2; 3)/ + assert decorate(code, to_range(code)) == "«(1; 2; 3)»" + + code = ~S""" + (1; + 2; + 3) + """ + + assert decorate(code, to_range(code)) == + """ + «(1; + 2; + 3)» + """ + |> String.trim_trailing() - assert to_range(~S""" - (1; - 2; - 3) - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 5]} + code = ~S""" + (1; + 2; + 3 + ) + """ - assert to_range(~S""" - (1; - 2; - 3 - ) - """) == %{start: [line: 1, column: 1], end: [line: 4, column: 2]} + assert decorate(code, to_range(code)) == + """ + «(1; + 2; + 3 + )» + """ + |> String.trim_trailing() end test "qualified calls" do - assert to_range(~S/foo.bar/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} - assert to_range(~S/foo.bar()/) == %{start: [line: 1, column: 1], end: [line: 1, column: 10]} - assert to_range(~S/foo.()/) == %{start: [line: 1, column: 1], end: [line: 1, column: 7]} - - assert to_range(~S/foo.bar.()/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 11] - } - - assert to_range(~s/foo.bar(\n)/) == %{ - start: [line: 1, column: 1], - end: [line: 2, column: 2] - } - - assert to_range(~s/foo.bar.(\n)/) == %{ - start: [line: 1, column: 1], - end: [line: 2, column: 2] - } - - assert to_range(~S/a.b.c/) == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} - - assert to_range(~S/foo.bar(baz)/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 13] - } - - assert to_range(~S/foo.bar.(baz)/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } - - assert to_range(~s/foo.bar.(\nbaz)/) == %{ - start: [line: 1, column: 1], - end: [line: 2, column: 5] - } - - assert to_range(~S/foo.bar("baz#{2}qux")/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 22] - } - - assert to_range(~S/foo.bar("baz#{2}qux", [])/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 26] - } - - assert to_range(~S/foo."b-a-r"/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 12] - } - - assert to_range(~S/foo."b-a-r"()/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } - - assert to_range(~S/foo."b-a-r"(1)/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~S/foo.bar/ + assert decorate(code, to_range(code)) == "«foo.bar»" + + code = ~S/foo.bar()/ + assert decorate(code, to_range(code)) == "«foo.bar()»" + + code = ~S/foo.()/ + assert decorate(code, to_range(code)) == "«foo.()»" + + code = ~S/foo.bar.()/ + assert decorate(code, to_range(code)) == "«foo.bar.()»" + + code = ~s/foo.bar(\n)/ + assert decorate(code, to_range(code)) == "«foo.bar(\n)»" + + code = ~s/foo.bar.(\n)/ + assert decorate(code, to_range(code)) == "«foo.bar.(\n)»" + + code = ~S/a.b.c/ + assert decorate(code, to_range(code)) == "«a.b.c»" + + code = ~S/foo.bar(baz)/ + assert decorate(code, to_range(code)) == "«foo.bar(baz)»" + + code = ~S/foo.bar.(baz)/ + assert decorate(code, to_range(code)) == "«foo.bar.(baz)»" + + code = ~s/foo.bar.(\nbaz)/ + assert decorate(code, to_range(code)) == "«foo.bar.(\nbaz)»" + + code = ~S/foo.bar("baz#{2}qux")/ + assert decorate(code, to_range(code)) == ~S"«foo.bar(\"baz#{2}qux\")»" + + code = ~S/foo.bar("baz#{2}qux", [])/ + assert decorate(code, to_range(code)) == ~S"«foo.bar(\"baz#{2}qux\", [])»" + + code = ~S/foo."b-a-r"/ + assert decorate(code, to_range(code)) == "«foo.\"b-a-r\"»" + + code = ~S/foo."b-a-r"()/ + assert decorate(code, to_range(code)) == "«foo.\"b-a-r\"()»" + + code = ~S/foo."b-a-r"(1)/ + assert decorate(code, to_range(code)) == "«foo.\"b-a-r\"(1)»" end test "qualified calls without parens" do - assert to_range(~S/foo.bar baz/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 12] - } + code = ~S/foo.bar baz/ + assert decorate(code, to_range(code)) == "«foo.bar baz»" - assert to_range(~S/foo.bar baz, qux/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 17] - } + code = ~S/foo.bar baz, qux/ + assert decorate(code, to_range(code)) == "«foo.bar baz, qux»" - assert to_range(~S/foo."b-a-r" baz/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 16] - } + code = ~S/foo."b-a-r" baz/ + assert decorate(code, to_range(code)) == "«foo.\"b-a-r\" baz»" end test "unqualified calls" do - assert to_range(~S/foo(bar)/) == %{start: [line: 1, column: 1], end: [line: 1, column: 9]} + code = ~S/foo(bar)/ + assert decorate(code, to_range(code)) == "«foo(bar)»" - assert to_range(~S""" - foo( - bar - ) - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 4]} + code = ~S""" + foo( + bar + ) + """ + + assert decorate(code, to_range(code)) == + """ + «foo( + bar + )» + """ + |> String.trim_trailing() end test "unqualified calls without parens" do - assert to_range(~S/foo bar/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S/foo bar/ + assert decorate(code, to_range(code)) == "«foo bar»" + + code = ~S/foo bar baz/ + assert decorate(code, to_range(code)) == "«foo bar baz»" - assert to_range(~S/foo bar baz/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 12] - } + code = ~s/foo\n bar/ + assert decorate(code, to_range(code)) == "«foo\n bar»" - assert to_range(~s/foo\n bar/) == %{start: [line: 1, column: 1], end: [line: 2, column: 6]} - assert to_range(~S/Foo.bar/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S/Foo.bar/ + assert decorate(code, to_range(code)) == "«Foo.bar»" - assert to_range(~s/Foo.\n bar/) == %{ - start: [line: 1, column: 1], - end: [line: 2, column: 6] - } + code = ~s/Foo.\n bar/ + assert decorate(code, to_range(code)) == "«Foo.\n bar»" end test "unqualified double calls" do - assert to_range(~S/unquote(foo)()/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~S/unquote(foo)()/ + assert decorate(code, to_range(code)) == "«unquote(foo)()»" end test "module aliases" do - assert to_range(~S/Foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 4]} - assert to_range(~S/Foo.Bar/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S/Foo/ + assert decorate(code, to_range(code)) == "«Foo»" - assert to_range(~s/Foo.\n Bar/) == %{ - start: [line: 1, column: 1], - end: [line: 2, column: 6] - } + code = ~S/Foo.Bar/ + assert decorate(code, to_range(code)) == "«Foo.Bar»" - assert to_range(~s/__MODULE__/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 11] - } + code = ~s/Foo.\n Bar/ + assert decorate(code, to_range(code)) == "«Foo.\n Bar»" - assert to_range(~s/__MODULE__.Bar/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~s/__MODULE__/ + assert decorate(code, to_range(code)) == "«__MODULE__»" - assert to_range(~s/@foo.Bar/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 9] - } + code = ~s/__MODULE__.Bar/ + assert decorate(code, to_range(code)) == "«__MODULE__.Bar»" - assert to_range(~s/foo().Bar/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 10] - } + code = ~s/@foo.Bar/ + assert decorate(code, to_range(code)) == "«@foo.Bar»" - assert to_range(~s/foo.bar.().Baz/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~s/foo().Bar/ + assert decorate(code, to_range(code)) == "«foo().Bar»" + + code = ~s/foo.bar.().Baz/ + assert decorate(code, to_range(code)) == "«foo.bar.().Baz»" end test "unary operators" do - assert to_range(~S/!foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} - assert to_range(~S/! foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} - assert to_range(~S/not foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 9]} - assert to_range(~S/@foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} - assert to_range(~S/@ foo/) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S/!foo/ + assert decorate(code, to_range(code)) == "«!foo»" + + code = ~S/! foo/ + assert decorate(code, to_range(code)) == "«! foo»" + + code = ~S/not foo/ + assert decorate(code, to_range(code)) == "«not foo»" + + code = ~S/@foo/ + assert decorate(code, to_range(code)) == "«@foo»" + + code = ~S/@ foo/ + assert decorate(code, to_range(code)) == "«@ foo»" end test "binary operators" do - assert to_range(~S/1 + 1/) == %{start: [line: 1, column: 1], end: [line: 1, column: 6]} + code = ~S/1 + 1/ + assert decorate(code, to_range(code)) == "«1 + 1»" - assert to_range(~S/foo when bar/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 13] - } + code = ~S/foo when bar/ + assert decorate(code, to_range(code)) == "«foo when bar»" - assert to_range(~S""" - 5 + - 10 - """) == %{start: [line: 1, column: 2], end: [line: 2, column: 7]} + code = ~S""" + 5 + + 10 + """ - assert to_range(~S/foo |> bar/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 11] - } + assert decorate(code, to_range(code)) == + """ + «5 + + 10» + """ + |> String.trim_trailing() + + code = ~S/foo |> bar/ + assert decorate(code, to_range(code)) == "«foo |> bar»" + + code = ~S""" + foo + |> bar + """ + + assert decorate(code, to_range(code)) == + """ + «foo + |> bar» + """ + |> String.trim_trailing() - assert to_range(~S""" - foo - |> bar - """) == %{start: [line: 1, column: 1], end: [line: 2, column: 7]} + code = ~S""" + foo + |> + bar + """ - assert to_range(~S""" - foo - |> - bar - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 4]} + assert decorate(code, to_range(code)) == + """ + «foo + |> + bar» + """ + |> String.trim_trailing() end test "ranges" do - assert to_range(~S[1..2]) == %{start: [line: 1, column: 1], end: [line: 1, column: 5]} - assert to_range(~S[1..2//3]) == %{start: [line: 1, column: 1], end: [line: 1, column: 8]} + code = ~S[1..2] + assert decorate(code, to_range(code)) == "«1..2»" + + code = ~S[1..2//3] + assert decorate(code, to_range(code)) == "«1..2//3»" - assert to_range(~S[foo..bar//baz]) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } + code = ~S[foo..bar//baz] + assert decorate(code, to_range(code)) == "«foo..bar//baz»" end test "bitstrings" do - assert to_range(~S[<<1, 2, foo>>]) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 14] - } + code = ~S[<<1, 2, foo>>] + assert decorate(code, to_range(code)) == "«<<1, 2, foo>>»" - assert to_range(~S""" - <<1, 2, + code = ~S""" + <<1, 2, - foo>> - """) == %{start: [line: 1, column: 1], end: [line: 3, column: 7]} + foo>> + """ + + assert decorate(code, to_range(code)) == + """ + «<<1, 2, + + foo>>» + """ + |> String.trim_trailing() end test "sigils" do - assert to_range(~S/~s[foo bar]/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 12] - } - - assert to_range(~S''' - ~s""" - foo - bar - """ - ''') == %{ - start: [line: 1, column: 1], - end: [line: 4, column: 4] - } + code = ~S/~s[foo bar]/ + assert decorate(code, to_range(code)) == "«~s[foo bar]»" + + code = ~S''' + ~s""" + foo + bar + """ + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «~s""" + foo + bar + """» + ''' + |> String.trim_trailing() end test "sigils with interpolations" do - assert to_range(~S/~s[foo#{2}bar]/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } - - assert to_range(~S/~s[foo#{2}bar]abc/) == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 18] - } - - assert to_range(~S''' - ~s""" - foo#{10 - } - bar - """ - ''') == %{ - start: [line: 1, column: 1], - end: [line: 5, column: 4] - } - - assert to_range(~S''' - ~s""" - foo#{10 - }bar - """abc - ''') == %{ - start: [line: 1, column: 1], - end: [line: 4, column: 7] - } + code = ~S/~s[foo#{2}bar]/ + assert decorate(code, to_range(code)) == ~S/«~s[foo#{2}bar]»/ + + code = ~S/~s[foo#{2}bar]abc/ + assert decorate(code, to_range(code)) == ~S/«~s[foo#{2}bar]abc»/ + + code = ~S''' + ~s""" + foo#{10 + } + bar + """ + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «~s""" + foo#{10 + } + bar + """» + ''' + |> String.trim_trailing() + + code = ~S''' + ~s""" + foo#{10 + }bar + """abc + ''' + + assert decorate(code, to_range(code)) == + ~S''' + «~s""" + foo#{10 + }bar + """abc» + ''' + |> String.trim_trailing() end test "captures" do - assert to_range(~S"&foo/1") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 7] - } + code = ~S"&foo/1" + assert decorate(code, to_range(code)) == "«&foo/1»" - assert to_range(~S"&Foo.bar/1") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 11] - } + code = ~S"&Foo.bar/1" + assert decorate(code, to_range(code)) == "«&Foo.bar/1»" - assert to_range(~S"&__MODULE__.Foo.bar/1") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 22] - } + code = ~S"&__MODULE__.Foo.bar/1" + assert decorate(code, to_range(code)) == "«&__MODULE__.Foo.bar/1»" end test "captures with arguments" do - assert to_range(~S"&foo(&1, :bar)") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 15] - } + code = ~S"&foo(&1, :bar)" + assert decorate(code, to_range(code)) == "«&foo(&1, :bar)»" - assert to_range(~S"& &1.foo") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 9] - } + code = ~S"& &1.foo" + assert decorate(code, to_range(code)) == "«& &1.foo»" - assert to_range(~S"& &1") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 5] - } + code = ~S"& &1" + assert decorate(code, to_range(code)) == "«& &1»" # This range currently ends on column 5, though it should be column 6, # and appears to be a limitation of the parser, which does not include @@ -753,26 +1023,22 @@ defmodule SourcerorTest.RangeTest do end test "arguments in captures" do - {:&, _, [{:&, _, _} = arg]} = Sourceror.parse_string!(~S"& &1") + code = ~S"& &1" + {:&, _, [{:&, _, _} = arg]} = Sourceror.parse_string!(code) - assert Sourceror.Range.get_range(arg) == %{ - start: [line: 1, column: 3], - end: [line: 1, column: 5] - } + range = Sourceror.Range.get_range(arg) + assert decorate(code, range) == "& «&1»" end test "Access syntax" do - assert to_range(~S"foo[bar]") == %{ - start: [line: 1, column: 1], - end: [line: 1, column: 9] - } + code = ~S"foo[bar]" + assert decorate(code, to_range(code)) == "«foo[bar]»" - {{:., _, [Access, :get]} = access, _, _} = Sourceror.parse_string!(~S"foo[bar]") + code = ~S"foo[bar]" + {{:., _, [Access, :get]} = access, _, _} = Sourceror.parse_string!(code) - assert Sourceror.Range.get_range(access) == %{ - start: [line: 1, column: 4], - end: [line: 1, column: 9] - } + range = Sourceror.Range.get_range(access) + assert decorate(code, range) == "foo«[bar]»" end test "should never raise" do diff --git a/test/support/range_support.ex b/test/support/range_support.ex new file mode 100644 index 0000000..1377d40 --- /dev/null +++ b/test/support/range_support.ex @@ -0,0 +1,9 @@ +defmodule SourcerorTest.RangeSupport do + @moduledoc false + + def decorate(code, range) do + code + |> Sourceror.patch_string([%{range: range, change: &"«#{&1}»"}]) + |> String.trim_trailing() + end +end