@@ -130,6 +130,99 @@ func TestAnalysisSyntaxTokensReturnsDefensiveCopy(t *testing.T) {
130130 }
131131}
132132
133+ func TestSyntaxWordsReturnCanonicalCategorizedDefensiveMetadata (t * testing.T ) {
134+ words := SyntaxWords ()
135+ if got , want := len (words ), int (SyntaxWordWith ); got != want {
136+ t .Fatalf ("SyntaxWords length = %d, want %d" , got , want )
137+ }
138+
139+ seen := make (map [SyntaxWord ]SyntaxWordInfo , len (words ))
140+ previous := ""
141+
142+ for _ , word := range words {
143+ if word .Word == SyntaxWordUnknown {
144+ t .Fatalf ("SyntaxWords contains unknown word: %+v" , word )
145+ }
146+
147+ if _ , ok := seen [word .Word ]; ok {
148+ t .Fatalf ("SyntaxWords contains duplicate identity %d" , word .Word )
149+ }
150+
151+ if word .Spelling != strings .ToUpper (word .Spelling ) {
152+ t .Fatalf ("SyntaxWords spelling %q is not canonical uppercase" , word .Spelling )
153+ }
154+
155+ if previous != "" && previous >= word .Spelling {
156+ t .Fatalf ("SyntaxWords are not in spelling order: %q before %q" , previous , word .Spelling )
157+ }
158+
159+ seen [word .Word ] = word
160+ previous = word .Spelling
161+ }
162+
163+ for word := SyntaxWord (1 ); word <= SyntaxWordWith ; word ++ {
164+ if _ , ok := seen [word ]; ! ok {
165+ t .Errorf ("SyntaxWords omits identity %d" , word )
166+ }
167+ }
168+
169+ wantCategories := map [SyntaxWord ]SyntaxWordCategory {
170+ SyntaxWordLet : SyntaxWordCategoryKeyword ,
171+ SyntaxWordAnd : SyntaxWordCategoryOperator ,
172+ SyntaxWordTrue : SyntaxWordCategoryLiteral ,
173+ SyntaxWordRetry : SyntaxWordCategoryContextual ,
174+ }
175+
176+ for word , want := range wantCategories {
177+ if got := seen [word ].Category ; got != want {
178+ t .Errorf ("SyntaxWords category for %q = %d, want %d" , seen [word ].Spelling , got , want )
179+ }
180+ }
181+
182+ words [0 ] = SyntaxWordInfo {}
183+ if next := SyntaxWords (); len (next ) == 0 || next [0 ] == (SyntaxWordInfo {}) {
184+ t .Fatal ("SyntaxWords exposed mutable metadata storage" )
185+ }
186+ }
187+
188+ func TestAnalyzeSyntaxTokensExposeCanonicalWordIdentity (t * testing.T ) {
189+ query := "let value = true\n RETURN value AND false ASC DESC && ! ON ERROR FAIL RETRY DELAY"
190+ analysis , _ := New ().Analyze (source .NewAnonymous (query ))
191+ if analysis == nil {
192+ t .Fatal ("Analyze returned no partial snapshot" )
193+ }
194+
195+ wantWords := map [string ]SyntaxWord {
196+ "let" : SyntaxWordLet ,
197+ "true" : SyntaxWordTrue ,
198+ "RETURN" : SyntaxWordReturn ,
199+ "AND" : SyntaxWordAnd ,
200+ "false" : SyntaxWordFalse ,
201+ "ASC" : SyntaxWordAsc ,
202+ "DESC" : SyntaxWordDesc ,
203+ "ON" : SyntaxWordOn ,
204+ "ERROR" : SyntaxWordError ,
205+ "FAIL" : SyntaxWordFail ,
206+ "RETRY" : SyntaxWordRetry ,
207+ "DELAY" : SyntaxWordDelay ,
208+ }
209+
210+ tokens := analysis .SyntaxTokens ()
211+ for text , want := range wantWords {
212+ token , ok := syntaxTokenWithText (tokens , query , text )
213+ if ! ok || token .Word != want {
214+ t .Errorf ("syntax word %q = %+v, %t, want identity %d" , text , token , ok , want )
215+ }
216+ }
217+
218+ for _ , text := range []string {"&&" , "!" } {
219+ token , ok := syntaxTokenWithText (tokens , query , text )
220+ if ! ok || token .Word != SyntaxWordUnknown {
221+ t .Errorf ("symbolic operator %q word = %+v, %t" , text , token , ok )
222+ }
223+ }
224+ }
225+
133226func hasSyntaxTokenKind (tokens []SyntaxToken , kind SyntaxTokenKind ) bool {
134227 for _ , token := range tokens {
135228 if token .Kind == kind {
0 commit comments