aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/query/parser_test.go
blob: 5c837c0efb6ba8d4854505a1719c3bcdbeefc939 (plain) (blame)
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
package query_test

import (
	"errors"
	"slices"
	"testing"

	"github.com/jpappel/atlas/pkg/query"
)

const (
	CAT_UNKNOWN  = query.CAT_UNKNOWN
	CAT_TITLE    = query.CAT_TITLE
	CAT_AUTHOR   = query.CAT_AUTHOR
	CAT_DATE     = query.CAT_DATE
	CAT_FILETIME = query.CAT_FILETIME
	CAT_TAGS     = query.CAT_TAGS
	CAT_HEADINGS = query.CAT_HEADINGS
	CAT_LINKS    = query.CAT_LINKS
	CAT_META     = query.CAT_META

	OP_UNKNOWN = query.OP_UNKNOWN
	OP_EQ      = query.OP_EQ
	OP_AP      = query.OP_AP
	OP_NE      = query.OP_NE
	OP_LT      = query.OP_LT
	OP_LE      = query.OP_LE
	OP_GE      = query.OP_GE
	OP_GT      = query.OP_GT
	OP_RE      = query.OP_RE
)

func TestParse(t *testing.T) {
	tests := []struct {
		name    string
		tokens  []query.Token
		want    *query.Clause
		wantErr error
	}{{
		"empty clause",
		[]query.Token{
			{Type: TOK_CLAUSE_START}, {Type: TOK_CLAUSE_AND}, {Type: TOK_CLAUSE_END},
		},
		&query.Clause{Operator: query.COP_AND},
		nil,
	}, {
		"simple clause",
		[]query.Token{
			{Type: TOK_CLAUSE_START}, {Type: TOK_CLAUSE_AND},
			{TOK_CAT_AUTHOR, "a"}, {TOK_OP_AP, ":"}, {TOK_VAL_STR, "ken thompson"},
			{Type: TOK_CLAUSE_END},
		},
		&query.Clause{
			Operator: query.COP_AND,
			Statements: []query.Statement{
				{Category: CAT_AUTHOR, Operator: OP_AP, Value: query.StringValue{"ken thompson"}},
			},
		},
		nil,
	}, {
		"nested clause",
		[]query.Token{
			{Type: TOK_CLAUSE_START}, {Type: TOK_CLAUSE_AND},
			{TOK_CAT_AUTHOR, "a"}, {TOK_OP_AP, ":"}, {TOK_VAL_STR, "Alonzo Church"},
			{Type: TOK_CLAUSE_START}, {Type: TOK_CLAUSE_OR},
			{TOK_CAT_AUTHOR, "a"}, {TOK_OP_EQ, "="}, {TOK_VAL_STR, "Alan Turing"},
			{Type: TOK_CLAUSE_END},
			{Type: TOK_CLAUSE_END},
		},
		&query.Clause{
			Operator: query.COP_AND,
			Statements: []query.Statement{
				{Category: CAT_AUTHOR, Operator: OP_AP, Value: query.StringValue{"Alonzo Church"}},
			},
			Clauses: []*query.Clause{
				{
					Operator: query.COP_OR,
					Statements: []query.Statement{
						{Category: CAT_AUTHOR, Operator: OP_EQ, Value: query.StringValue{"Alan Turing"}},
					},
				},
			},
		},
		nil,
	}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotC, gotErr := query.Parse(tt.tokens)
			if !errors.Is(gotErr, tt.wantErr) {
				t.Fatalf("Different parse error than expected: got %v, want %v", gotErr, tt.wantErr)
			} else if gotErr != nil {
				return
			}

			got := slices.Collect(gotC.DFS())
			want := slices.Collect(tt.want.DFS())

			gotL, wantL := len(got), len(want)
			if gotL != wantL {
				t.Errorf("Different number of clauses than expected: got %d, want %d", gotL, wantL)
			}

			for i := range min(gotL, wantL) {
				gotC, wantC := got[i], want[i]

				if gotC.Operator != wantC.Operator {
					t.Error("Different clause operator than expected")
				} else if !slices.EqualFunc(gotC.Statements, wantC.Statements,
					func(s1, s2 query.Statement) bool {
						return s1.Negated == s2.Negated && s1.Category == s2.Category && s1.Operator == s2.Operator && s1.Value.Compare(s2.Value) == 0
					}) {
					t.Error("Different statements than expected")
				} else if len(gotC.Clauses) != len(wantC.Clauses) {
					t.Error("Different number of child clauses than expected")
				}

				if t.Failed() {
					t.Log("Got\n", gotC)
					t.Log("Want\n", wantC)
					break
				}
			}
		})
	}
}