-
Notifications
You must be signed in to change notification settings - Fork 107
Expand file tree
/
Copy pathelixir_test.go
More file actions
168 lines (143 loc) · 4.42 KB
/
Copy pathelixir_test.go
File metadata and controls
168 lines (143 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package languages
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
func TestExExtractor_Module(t *testing.T) {
src := []byte(`defmodule MyApp.UserService do
def find_user(id) do
Repo.get(User, id)
end
defp validate(user) do
# private function
end
end
`)
e := NewElixirExtractor()
result, err := e.Extract("user_service.ex", src)
require.NoError(t, err)
// Module should be a type.
types := nodesOfKind(result.Nodes, graph.KindType)
assert.GreaterOrEqual(t, len(types), 1)
// Functions inside module should be methods.
methods := nodesOfKind(result.Nodes, graph.KindMethod)
if len(methods) == 0 {
// Fallback: may be extracted as functions.
funcs := nodesOfKind(result.Nodes, graph.KindFunction)
assert.GreaterOrEqual(t, len(funcs), 1)
}
}
func TestExExtractor_Imports(t *testing.T) {
src := []byte(`import Ecto.Query
alias MyApp.Repo
use GenServer
`)
e := NewElixirExtractor()
result, err := e.Extract("app.ex", src)
require.NoError(t, err)
imports := edgesOfKind(result.Edges, graph.EdgeImports)
assert.GreaterOrEqual(t, len(imports), 1)
}
func TestExExtractor_ModuleWithMethods(t *testing.T) {
src := []byte(`defmodule Calculator do
def add(a, b) do
a + b
end
def subtract(a, b) do
a - b
end
defp internal_helper(x) do
x * 2
end
end
`)
e := NewElixirExtractor()
result, err := e.Extract("calc.ex", src)
require.NoError(t, err)
// Module node.
types := nodesOfKind(result.Nodes, graph.KindType)
require.GreaterOrEqual(t, len(types), 1)
assert.Equal(t, "Calculator", types[0].Name)
// Methods inside module.
methods := nodesOfKind(result.Nodes, graph.KindMethod)
require.GreaterOrEqual(t, len(methods), 2, "expected at least 2 methods (add, subtract)")
// MemberOf edges.
memberEdges := edgesOfKind(result.Edges, graph.EdgeMemberOf)
assert.GreaterOrEqual(t, len(memberEdges), 2)
for _, edge := range memberEdges {
assert.Equal(t, "calc.ex::Calculator", edge.To)
}
}
func TestExExtractor_TopLevelFunction(t *testing.T) {
src := []byte(`def hello(name) do
IO.puts("Hello #{name}")
end
`)
e := NewElixirExtractor()
result, err := e.Extract("script.exs", src)
require.NoError(t, err)
funcs := nodesOfKind(result.Nodes, graph.KindFunction)
if len(funcs) > 0 {
assert.Equal(t, "hello", funcs[0].Name)
}
}
func TestExExtractor_FileNode(t *testing.T) {
src := []byte(`defmodule Foo do
end
`)
e := NewElixirExtractor()
result, err := e.Extract("foo.ex", src)
require.NoError(t, err)
files := nodesOfKind(result.Nodes, graph.KindFile)
require.Len(t, files, 1)
assert.Equal(t, "foo.ex", files[0].ID)
assert.Equal(t, "elixir", files[0].Language)
}
func TestExExtractor_LanguageAndExtensions(t *testing.T) {
e := NewElixirExtractor()
assert.Equal(t, "elixir", e.Language())
assert.Equal(t, []string{".ex", ".exs"}, e.Extensions())
}
func TestExExtractor_PhoenixPlugDispatch(t *testing.T) {
// `plug :name` in a defmodule binds the named plug to every
// action function. `plug :name when action in [...]` binds only
// to the listed atoms. Both produce EdgeCalls edges from each
// matching action to the plug function.
src := []byte(`defmodule MyAppWeb.UserController do
plug :authenticate
plug :load_user when action in [:show, :update]
def index(conn, _params), do: conn
def show(conn, _params), do: conn
def update(conn, _params), do: conn
def authenticate(conn, _), do: conn
def load_user(conn, _), do: conn
end
`)
e := NewElixirExtractor()
result, err := e.Extract("user_controller.ex", src)
require.NoError(t, err)
authActions := map[string]bool{}
loadActions := map[string]bool{}
for _, ed := range edgesOfKind(result.Edges, graph.EdgeCalls) {
if ed.Meta == nil {
continue
}
plug, _ := ed.Meta["phoenix_plug"].(string)
switch plug {
case "authenticate":
authActions[ed.From] = true
case "load_user":
loadActions[ed.From] = true
}
}
// authenticate (no filter) guards every action — index, show, update.
assert.Len(t, authActions, 3)
assert.Contains(t, authActions, "user_controller.ex::MyAppWeb.UserController.index")
// load_user is filtered to :show and :update.
assert.Len(t, loadActions, 2)
assert.Contains(t, loadActions, "user_controller.ex::MyAppWeb.UserController.show")
assert.Contains(t, loadActions, "user_controller.ex::MyAppWeb.UserController.update")
assert.NotContains(t, loadActions, "user_controller.ex::MyAppWeb.UserController.index")
}