Skip to content

Commit c129963

Browse files
committed
Add more typespec tests
1 parent 81fe6a1 commit c129963

File tree

3 files changed

+206
-51
lines changed

3 files changed

+206
-51
lines changed

test/examples/Elixir.Typespec.beam

2.33 KB
Binary file not shown.

test/examples/typespec.ex

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,41 @@
11
defmodule Typespec do
22
@type mylist(t) :: [t]
33

4-
@spec missing_type() :: Unknown.atom()
5-
def missing_type, do: :ok
4+
defstruct name: "", age: 1
65

7-
@spec missing_type_arg() :: mylist(Unknown.atom())
8-
def missing_type_arg, do: [:ok]
6+
@spec spec_remote_type() :: Unknown.atom()
7+
def spec_remote_type, do: :ok
98

10-
@spec named_type(name :: Unknown.atom()) :: atom()
11-
def named_type(name), do: name
9+
@spec spec_user_type() :: mylist(:ok | atom())
10+
def spec_user_type, do: [:ok]
1211

13-
@spec atoms_type(:ok | :error) :: :ok | :error
14-
def atoms_type(name), do: name
12+
@spec spec_map_and_named_type(type :: Unknown.atom()) :: %{
13+
optional(:value) => integer(),
14+
required(:type) => Unknown.atom()
15+
}
16+
def spec_map_and_named_type(type), do: %{type: type}
1517

16-
@spec atoms_type2(:ok | :error) :: Unknown.atom(:ok | :error)
17-
def atoms_type2(name), do: name
18+
@spec spec_atom(:ok | nil | true | false) :: Unknown.atom(:ok | nil | true | false)
19+
def spec_atom(name), do: name
20+
21+
@spec spec_function() :: (atom(), %{name: String.t()} -> map())
22+
def spec_function(), do: fn id, %{name: name} -> %{id: id, name: name} end
23+
24+
@spec spec_struct(%Typespec{}) :: %Typespec{}
25+
def spec_struct(struct), do: struct
26+
27+
@spec spec_list([integer(), ...]) :: [...]
28+
def spec_list(list), do: list
29+
30+
@spec spec_range(1..10) :: [1..10]
31+
def spec_range(i), do: [i]
32+
33+
@spec spec_keyword(a: integer(), b: integer()) :: integer()
34+
def spec_keyword(a: a, b: b), do: a + b
35+
36+
@spec spec_tuple({:ok, integer()}) :: tuple()
37+
def spec_tuple({:ok, a}), do: {:ok, a + 1}
38+
39+
@spec spec_bitstring(<<_::48, _::_*8>>) :: <<>>
40+
def spec_bitstring(_), do: <<>>
1841
end

test/gradient/ast_specifier_test.exs

Lines changed: 173 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,75 +1369,201 @@ defmodule Gradient.AstSpecifierTest do
13691369
test "typespec" do
13701370
{tokens, ast} = load("/Elixir.Typespec.beam", "/typespec.ex")
13711371

1372-
[atoms_type2, atoms_type, named_type, missing_type_arg, missing_type | _] =
1372+
result =
13731373
AstSpecifier.run_mappers(ast, tokens)
13741374
|> filter_attributes(:spec)
1375-
|> Enum.reverse()
1375+
|> make_spec_map()
1376+
1377+
assert {:attribute, 6, :spec,
1378+
{{:spec_remote_type, 0},
1379+
[
1380+
{:type, 6, :fun,
1381+
[
1382+
{:type, 6, :product, []},
1383+
{:remote_type, 6, [{:atom, 6, Unknown}, {:atom, 6, :atom}, []]}
1384+
]}
1385+
]}} = result.spec_remote_type
1386+
1387+
assert {:attribute, 9, :spec,
1388+
{{:spec_user_type, 0},
1389+
[
1390+
{:type, 9, :fun,
1391+
[
1392+
{:type, 9, :product, []},
1393+
{:user_type, 9, :mylist,
1394+
[{:type, 9, :union, [{:atom, 9, :ok}, {:type, 9, :atom, []}]}]}
1395+
]}
1396+
]}} = result.spec_user_type
1397+
1398+
assert {:attribute, 12, :spec,
1399+
{{:spec_map_and_named_type, 1},
1400+
[
1401+
{:type, 12, :fun,
1402+
[
1403+
{:type, 12, :product,
1404+
[
1405+
{:ann_type, 12,
1406+
[
1407+
{:var, 12, :type},
1408+
{:remote_type, 12, [{:atom, 12, Unknown}, {:atom, 12, :atom}, []]}
1409+
]}
1410+
]},
1411+
{:type, 12, :map,
1412+
[
1413+
{:type, 13, :map_field_assoc,
1414+
[{:atom, 13, :value}, {:type, 13, :integer, []}]},
1415+
{:type, 14, :map_field_exact,
1416+
[
1417+
{:atom, 14, :type},
1418+
{:remote_type, 14, [{:atom, 14, Unknown}, {:atom, 14, :atom}, []]}
1419+
]}
1420+
]}
1421+
]}
1422+
]}} = result.spec_map_and_named_type
1423+
1424+
assert {:attribute, 18, :spec,
1425+
{{:spec_atom, 1},
1426+
[
1427+
{:type, 18, :fun,
1428+
[
1429+
{:type, 18, :product,
1430+
[
1431+
{:type, 18, :union,
1432+
[{:atom, 18, :ok}, {:atom, 18, nil}, {:atom, 18, true}, {:atom, 18, false}]}
1433+
]},
1434+
{:remote_type, 18,
1435+
[
1436+
{:atom, 18, Unknown},
1437+
{:atom, 18, :atom},
1438+
[
1439+
{:type, 18, :union,
1440+
[
1441+
{:atom, 18, :ok},
1442+
{:atom, 18, nil},
1443+
{:atom, 18, true},
1444+
{:atom, 18, false}
1445+
]}
1446+
]
1447+
]}
1448+
]}
1449+
]}} = result.spec_atom
1450+
1451+
assert {:attribute, 21, :spec,
1452+
{{:spec_function, 0},
1453+
[
1454+
{:type, 21, :fun,
1455+
[
1456+
{:type, 21, :product, []},
1457+
{:type, 21, :fun,
1458+
[
1459+
{:type, 21, :product,
1460+
[
1461+
{:type, 21, :atom, []},
1462+
{:type, 21, :map,
1463+
[
1464+
{:type, 21, :map_field_exact,
1465+
[
1466+
{:atom, 21, :name},
1467+
{:remote_type, 21, [{:atom, 21, String}, {:atom, 21, :t}, []]}
1468+
]}
1469+
]}
1470+
]},
1471+
{:type, 21, :map, :any}
1472+
]}
1473+
]}
1474+
]}} = result.spec_function
13761475

1377-
assert {:attribute, 17, :spec,
1378-
{{:atoms_type2, 1},
1476+
assert {:attribute, 24, :spec,
1477+
{{:spec_struct, 1},
13791478
[
1380-
{:type, 17, :fun,
1479+
{:type, 24, :fun,
13811480
[
1382-
{:type, 17, :product,
1383-
[{:type, 17, :union, [{:atom, 17, :ok}, {:atom, 17, :error}]}]},
1384-
{:remote_type, 17,
1481+
{:type, 24, :product,
13851482
[
1386-
{:atom, 17, Unknown},
1387-
{:atom, 17, :atom},
1388-
[{:type, 17, :union, [{:atom, 17, :ok}, {:atom, 17, :error}]}]
1483+
{:type, 24, :map,
1484+
[
1485+
{:type, 24, :map_field_exact,
1486+
[{:atom, 24, :__struct__}, {:atom, 24, Typespec}]},
1487+
{:type, 24, :map_field_exact,
1488+
[{:atom, 24, :age}, {:type, 24, :term, []}]},
1489+
{:type, 24, :map_field_exact,
1490+
[{:atom, 24, :name}, {:type, 24, :term, []}]}
1491+
]}
1492+
]},
1493+
{:type, 24, :map,
1494+
[
1495+
{:type, 24, :map_field_exact,
1496+
[{:atom, 24, :__struct__}, {:atom, 24, Typespec}]},
1497+
{:type, 24, :map_field_exact, [{:atom, 24, :age}, {:type, 24, :term, []}]},
1498+
{:type, 24, :map_field_exact, [{:atom, 24, :name}, {:type, 24, :term, []}]}
13891499
]}
13901500
]}
1391-
]}} = atoms_type2
1501+
]}} = result.spec_struct
1502+
1503+
assert {:attribute, 27, :spec,
1504+
{{:spec_list, 1},
1505+
[
1506+
{:type, 27, :fun,
1507+
[
1508+
{:type, 27, :product,
1509+
[{:type, 27, :nonempty_list, [{:type, 27, :integer, []}]}]},
1510+
{:type, 27, :nonempty_list, []}
1511+
]}
1512+
]}} = result.spec_list
13921513

1393-
assert {:attribute, 14, :spec,
1394-
{{:atoms_type, 1},
1514+
assert {:attribute, 30, :spec,
1515+
{{:spec_range, 1},
13951516
[
1396-
{:type, 14, :fun,
1517+
{:type, 30, :fun,
13971518
[
1398-
{:type, 14, :product,
1399-
[{:type, 14, :union, [{:atom, 14, :ok}, {:atom, 14, :error}]}]},
1400-
{:type, 14, :union, [{:atom, 14, :ok}, {:atom, 14, :error}]}
1519+
{:type, 30, :product,
1520+
[{:type, 30, :range, [{:integer, 30, 1}, {:integer, 30, 10}]}]},
1521+
{:type, 30, :list,
1522+
[{:type, 30, :range, [{:integer, 30, 1}, {:integer, 30, 10}]}]}
14011523
]}
1402-
]}} = atoms_type
1524+
]}} = result.spec_range
14031525

1404-
assert {:attribute, 11, :spec,
1405-
{{:named_type, 1},
1526+
assert {:attribute, 33, :spec,
1527+
{{:spec_keyword, 1},
14061528
[
1407-
{:type, 11, :fun,
1529+
{:type, 33, :fun,
14081530
[
1409-
{:type, 11, :product,
1531+
{:type, 33, :product,
14101532
[
1411-
{:ann_type, 11,
1533+
{:type, 33, :list,
14121534
[
1413-
{:var, 11, :name},
1414-
{:remote_type, 11, [{:atom, 11, Unknown}, {:atom, 11, :atom}, []]}
1535+
{:type, 33, :union,
1536+
[
1537+
{:type, 33, :tuple, [{:atom, 33, :a}, {:type, 33, :integer, []}]},
1538+
{:type, 33, :tuple, [{:atom, 33, :b}, {:type, 33, :integer, []}]}
1539+
]}
14151540
]}
14161541
]},
1417-
{:type, 11, :atom, []}
1542+
{:type, 33, :integer, []}
14181543
]}
1419-
]}} = named_type
1544+
]}} = result.spec_keyword
14201545

1421-
assert {:attribute, 8, :spec,
1422-
{{:missing_type_arg, 0},
1546+
assert {:attribute, 36, :spec,
1547+
{{:spec_tuple, 1},
14231548
[
1424-
{:type, 8, :fun,
1549+
{:type, 36, :fun,
14251550
[
1426-
{:type, 8, :product, []},
1427-
{:user_type, 8, :mylist,
1428-
[{:remote_type, 8, [{:atom, 8, Unknown}, {:atom, 8, :atom}, []]}]}
1551+
{:type, 36, :product,
1552+
[{:type, 36, :tuple, [{:atom, 36, :ok}, {:type, 36, :integer, []}]}]},
1553+
{:type, 36, :tuple, :any}
14291554
]}
1430-
]}} = missing_type_arg
1555+
]}} = result.spec_tuple
14311556

1432-
assert {:attribute, 5, :spec,
1433-
{{:missing_type, 0},
1557+
assert {:attribute, 39, :spec,
1558+
{{:spec_bitstring, 1},
14341559
[
1435-
{:type, 5, :fun,
1560+
{:type, 39, :fun,
14361561
[
1437-
{:type, 5, :product, []},
1438-
{:remote_type, 5, [{:atom, 5, Unknown}, {:atom, 5, :atom}, []]}
1562+
{:type, 39, :product,
1563+
[{:type, 39, :binary, [{:integer, 39, 48}, {:integer, 39, 8}]}]},
1564+
{:type, 39, :binary, [{:integer, 39, 0}, {:integer, 39, 0}]}
14391565
]}
1440-
]}} = missing_type
1566+
]}} = result.spec_bitstring
14411567
end
14421568

14431569
test "clauses without a line" do
@@ -1458,4 +1584,10 @@ defmodule Gradient.AstSpecifierTest do
14581584
def filter_attributes(ast, type) do
14591585
Enum.filter(ast, &match?({:attribute, _, ^type, _}, &1))
14601586
end
1587+
1588+
def make_spec_map(specs) do
1589+
specs
1590+
|> Enum.map(fn {:attribute, _, _, {{name, _arity}, _}} = attr -> {name, attr} end)
1591+
|> Enum.into(%{})
1592+
end
14611593
end

0 commit comments

Comments
 (0)