Files
graph/engine/engine_test.go
T
zeekay 6aeee65a92 Add CI/CD pipelines, unit tests, release workflow
CI:
- ci.yml: build, vet, unit tests, e2e (SQLite + in-memory), benchmarks
  on ubuntu + macos matrix
- release.yml: cross-compile binaries (linux/darwin x amd64/arm64),
  multi-platform Docker image to ghcr.io/luxfi/graph, GitHub Release

Tests:
- engine/engine_test.go: parser (fields, args, where filters, aliases,
  depth, paren matching, limit clamping)
- indexer/indexer_test.go: hex parsing, uint256 decoding, topic address
  extraction, event signature coverage
- storage/store_test.go: FilterResults (exact, gte, lt, empty, no-match),
  sortResults (numeric, asc, string fallback), compareValues (numeric
  strings, mixed types)
2026-04-11 14:25:57 -07:00

172 lines
4.2 KiB
Go

package engine
import (
"testing"
)
func TestParseTopFields_SingleField(t *testing.T) {
fields, err := parseTopFields(`{ tokens(first: 10) { id symbol } }`)
if err != nil {
t.Fatal(err)
}
if len(fields) != 1 {
t.Fatalf("expected 1 field, got %d", len(fields))
}
if fields[0].name != "tokens" {
t.Errorf("expected tokens, got %s", fields[0].name)
}
if fields[0].args["first"] != "10" {
t.Errorf("expected first=10, got %v", fields[0].args["first"])
}
}
func TestParseTopFields_MultipleFields(t *testing.T) {
fields, err := parseTopFields("{\n bundle(id: \"1\") { ethPriceUSD }\n factories(first: 1) { poolCount }\n}")
if err != nil {
t.Fatal(err)
}
if len(fields) != 2 {
t.Fatalf("expected 2 fields, got %d", len(fields))
}
if fields[0].name != "bundle" {
t.Errorf("expected bundle, got %s", fields[0].name)
}
if fields[1].name != "factories" {
t.Errorf("expected factories, got %s", fields[1].name)
}
}
func TestParseTopFields_Alias(t *testing.T) {
fields, err := parseTopFields("{\n myTokens: tokens(first: 5) { id }\n}")
if err != nil {
t.Fatal(err)
}
if len(fields) != 1 {
t.Fatalf("expected 1 field, got %d", len(fields))
}
if fields[0].alias != "myTokens" {
t.Errorf("expected alias myTokens, got %s", fields[0].alias)
}
if fields[0].name != "tokens" {
t.Errorf("expected name tokens, got %s", fields[0].name)
}
}
func TestParseArgs_WhereFilter(t *testing.T) {
args := parseArgs(`first: 200, orderBy: timestamp, orderDirection: desc, where: { pool: "0xabc", date_gte: 12345 }`)
if args["first"] != "200" {
t.Errorf("first: got %v", args["first"])
}
if args["orderBy"] != "timestamp" {
t.Errorf("orderBy: got %v", args["orderBy"])
}
if args["orderDirection"] != "desc" {
t.Errorf("orderDirection: got %v", args["orderDirection"])
}
where, ok := args["where"].(map[string]interface{})
if !ok {
t.Fatalf("where not a map: %T", args["where"])
}
if where["pool"] != "0xabc" {
t.Errorf("where.pool: got %v", where["pool"])
}
if where["date_gte"] != "12345" {
t.Errorf("where.date_gte: got %v", where["date_gte"])
}
}
func TestParseArgs_NestedBraces(t *testing.T) {
args := parseArgs(`where: { token: { id: "0x123" } }`)
where, ok := args["where"].(map[string]interface{})
if !ok {
t.Fatal("where not a map")
}
inner, ok := where["token"].(map[string]interface{})
if !ok {
t.Fatal("where.token not a map")
}
if inner["id"] != "0x123" {
t.Errorf("expected 0x123, got %v", inner["id"])
}
}
func TestParseArgs_QuotedString(t *testing.T) {
args := parseArgs(`id: "hello, world"`)
if args["id"] != "hello, world" {
t.Errorf("expected 'hello, world', got %v", args["id"])
}
}
func TestParseArgs_Empty(t *testing.T) {
args := parseArgs("")
if len(args) != 0 {
t.Errorf("expected empty, got %v", args)
}
}
func TestQueryDepth(t *testing.T) {
tests := []struct {
query string
depth int
}{
{`{ tokens { id } }`, 2},
{`{ tokens { id name } }`, 2},
{`{ pools { token0 { id } } }`, 3},
{`{ a { b { c { d } } } }`, 4},
{`{ factory(id: "1") { id } }`, 2},
{`{ tokens(first: 1) { id } "quoted { brace" }`, 2}, // quoted braces ignored
}
for _, tt := range tests {
got := queryDepth(tt.query)
if got != tt.depth {
t.Errorf("queryDepth(%q) = %d, want %d", tt.query, got, tt.depth)
}
}
}
func TestFindMatchingParen(t *testing.T) {
tests := []struct {
s string
pos int
end int
}{
{"(abc)", 0, 4},
{"(a, b: {c: 1})", 0, 13},
{`(id: "test (paren)")`, 0, 19},
{"(no close", 0, -1},
}
for _, tt := range tests {
got := findMatchingParen(tt.s, tt.pos)
if got != tt.end {
t.Errorf("findMatchingParen(%q, %d) = %d, want %d", tt.s, tt.pos, got, tt.end)
}
}
}
func TestParseListArgs_Clamping(t *testing.T) {
// Negative
args := map[string]interface{}{"first": "-5"}
limit, _, _, _ := parseListArgs(args, 100)
if limit < 1 {
t.Errorf("negative limit not clamped: %d", limit)
}
// Too large
args = map[string]interface{}{"first": "999999"}
limit, _, _, _ = parseListArgs(args, 100)
if limit > 1000 {
t.Errorf("large limit not clamped: %d", limit)
}
// Default
args = map[string]interface{}{}
limit, _, _, _ = parseListArgs(args, 50)
if limit != 50 {
t.Errorf("default not applied: %d", limit)
}
}