| // Copyright 2018 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package zoekt |
| |
| import ( |
| "reflect" |
| "testing" |
| |
| "github.com/google/zoekt/query" |
| ) |
| |
| func Test_breakOnNewlines(t *testing.T) { |
| type args struct { |
| cm *candidateMatch |
| text []byte |
| } |
| tests := []struct { |
| name string |
| args args |
| want []*candidateMatch |
| }{ |
| { |
| name: "trivial case", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 0, |
| }, |
| text: nil, |
| }, |
| want: nil, |
| }, |
| { |
| name: "no newlines", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 1, |
| }, |
| text: []byte("a"), |
| }, |
| want: []*candidateMatch{ |
| { |
| byteOffset: 0, |
| byteMatchSz: 1, |
| }, |
| }, |
| }, |
| { |
| name: "newline at start", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 2, |
| }, |
| text: []byte("\na"), |
| }, |
| want: []*candidateMatch{ |
| { |
| byteOffset: 1, |
| byteMatchSz: 1, |
| }, |
| }, |
| }, |
| { |
| name: "newline at end", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 2, |
| }, |
| text: []byte("a\n"), |
| }, |
| want: []*candidateMatch{ |
| { |
| byteOffset: 0, |
| byteMatchSz: 1, |
| }, |
| }, |
| }, |
| { |
| name: "newline in middle", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 3, |
| }, |
| text: []byte("a\nb"), |
| }, |
| want: []*candidateMatch{ |
| { |
| byteOffset: 0, |
| byteMatchSz: 1, |
| }, |
| { |
| byteOffset: 2, |
| byteMatchSz: 1, |
| }, |
| }, |
| }, |
| { |
| name: "two newlines", |
| args: args{ |
| cm: &candidateMatch{ |
| byteOffset: 0, |
| byteMatchSz: 5, |
| }, |
| text: []byte("a\nb\nc"), |
| }, |
| want: []*candidateMatch{ |
| { |
| byteOffset: 0, |
| byteMatchSz: 1, |
| }, |
| { |
| byteOffset: 2, |
| byteMatchSz: 1, |
| }, |
| { |
| byteOffset: 4, |
| byteMatchSz: 1, |
| }, |
| }, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| if got := breakOnNewlines(tt.args.cm, tt.args.text); !reflect.DeepEqual(got, tt.want) { |
| type PrintableCm struct { |
| byteOffset uint32 |
| byteMatchSz uint32 |
| } |
| var got2, want2 []PrintableCm |
| for _, g := range got { |
| got2 = append(got2, PrintableCm{byteOffset: g.byteOffset, byteMatchSz: g.byteMatchSz}) |
| } |
| for _, w := range tt.want { |
| want2 = append(want2, PrintableCm{byteOffset: w.byteOffset, byteMatchSz: w.byteMatchSz}) |
| } |
| t.Errorf("breakMatchOnNewlines() = %+v, want %+v", got2, want2) |
| } |
| }) |
| } |
| } |
| |
| func TestEquivalentQuerySkipRegexpTree(t *testing.T) { |
| tests := []struct { |
| query string |
| skip bool |
| }{ |
| {query: "^foo", skip: false}, |
| {query: "foo", skip: true}, |
| {query: "thread|needle|haystack", skip: true}, |
| {query: "contain(er|ing)", skip: false}, |
| {query: "thread (needle|haystack)", skip: true}, |
| {query: "thread (needle|)", skip: false}, |
| } |
| |
| for _, tt := range tests { |
| q, err := query.Parse(tt.query) |
| if err != nil { |
| t.Errorf("Error parsing query: %s", "sym:"+tt.query) |
| continue |
| } |
| |
| d := &indexData{} |
| mt, err := d.newMatchTree(q) |
| if err != nil { |
| t.Errorf("Error creating match tree from query: %s", q) |
| continue |
| } |
| |
| visitMatchTree(mt, func(m matchTree) { |
| if _, ok := m.(*regexpMatchTree); ok && tt.skip { |
| t.Errorf("Expected regexpMatchTree to be skipped for query: %s", q) |
| } |
| }) |
| } |
| } |