chore: import upstream snapshot with attribution
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,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")
|
||||
}
|
||||
Reference in New Issue
Block a user