a06f331eb8
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
77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package languages
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
func TestScalaExtractor_Fields(t *testing.T) {
|
|
const scala = `package com.app
|
|
|
|
class Account {
|
|
val balance: Int = 0
|
|
var pending: List[Transaction] = Nil
|
|
def deposit(amount: Int): Boolean = {
|
|
true
|
|
}
|
|
}
|
|
`
|
|
res, err := NewScalaExtractor().Extract("Account.scala", []byte(scala))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
byName := map[string]*graph.Node{}
|
|
for _, n := range res.Nodes {
|
|
byName[n.Name] = n
|
|
}
|
|
typedAs := map[string]string{} // field id -> referenced type
|
|
for _, e := range res.Edges {
|
|
if e.Kind == graph.EdgeTypedAs {
|
|
typedAs[e.From] = e.To
|
|
}
|
|
}
|
|
|
|
// val field keeps its base type in meta, but a primitive annotation
|
|
// (Int) deliberately emits no typed_as usage edge — those would just
|
|
// clutter the graph with unresolved::Int edges that never land.
|
|
balance := byName["balance"]
|
|
if balance == nil || balance.Kind != graph.KindField {
|
|
t.Fatalf("val 'balance' should be a field node, got %+v", balance)
|
|
}
|
|
if balance.Meta["field_type"] != "Int" {
|
|
t.Errorf("balance field_type = %v, want Int", balance.Meta["field_type"])
|
|
}
|
|
if _, ok := typedAs[balance.ID]; ok {
|
|
t.Errorf("primitive-typed balance should NOT have a typed_as edge, got %q", typedAs[balance.ID])
|
|
}
|
|
|
|
// A container generic surfaces its element type as a usage edge:
|
|
// `List[Transaction]` references Transaction.
|
|
if p := byName["pending"]; p != nil && typedAs[p.ID] != "unresolved::Transaction" {
|
|
t.Errorf("pending (List[Transaction]) should typed_as unresolved::Transaction, got %q", typedAs[p.ID])
|
|
}
|
|
|
|
// var field is flagged mutable; generic type reduced to its base.
|
|
pending := byName["pending"]
|
|
if pending == nil || pending.Kind != graph.KindField {
|
|
t.Fatalf("var 'pending' should be a field node, got %+v", pending)
|
|
}
|
|
if pending.Meta["mutable"] != true {
|
|
t.Errorf("var pending should be mutable: meta=%v", pending.Meta)
|
|
}
|
|
if pending.Meta["field_type"] != "List" {
|
|
t.Errorf("pending field_type = %v, want List (generic stripped)", pending.Meta["field_type"])
|
|
}
|
|
|
|
// function gains a return type.
|
|
deposit := byName["deposit"]
|
|
if deposit == nil {
|
|
t.Fatal("method 'deposit' was not extracted")
|
|
}
|
|
if deposit.Meta["return_type"] != "Boolean" {
|
|
t.Errorf("deposit return_type = %v, want Boolean", deposit.Meta["return_type"])
|
|
}
|
|
}
|