diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index 9c119420048..e6f972bc984 100644 --- a/bigtable/bttest/inmem.go +++ b/bigtable/bttest/inmem.go @@ -612,7 +612,10 @@ func filterRow(f *btpb.RowFilter, r *row) (bool, error) { offset -= len(cs) } } - return true, nil + // If we get here, we have to have consumed all of the cells, + // otherwise, we would have returned above. We're not generating + // a row, so false. + return false, nil case *btpb.RowFilter_RowSampleFilter: // The row sample filter "matches all cells from a row with probability // p, and matches no cells from the row with probability 1-p." diff --git a/bigtable/bttest/inmem_test.go b/bigtable/bttest/inmem_test.go index 3632346088b..6f450a785fb 100644 --- a/bigtable/bttest/inmem_test.go +++ b/bigtable/bttest/inmem_test.go @@ -2033,3 +2033,40 @@ func TestValueFilterRowWithAlternationInRegex(t *testing.T) { t.Fatalf("Response chunks mismatch: got: + want -\n%s", diff) } } + +func TestFilterRowCellsPerRowLimitFilterTruthiness(t *testing.T) { + row := &row{ + key: "row", + families: map[string]*family{ + "fam": { + name: "fam", + cells: map[string][]cell{ + "col1": {{ts: 1000, value: []byte("val2")}}, + "col2": { + {ts: 1000, value: []byte("val2")}, + {ts: 1000, value: []byte("val3")}, + }, + }, + colNames: []string{"col1", "col2"}, + }, + }, + } + for _, test := range []struct { + filter *btpb.RowFilter + want bool + }{ + // The regexp-based filters perform whole-string, case-sensitive matches. + {&btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{1}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{2}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{3}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{4}}, false}, + } { + got, err := filterRow(test.filter, row.copy()) + if err != nil { + t.Errorf("%s: got unexpected error: %v", proto.CompactTextString(test.filter), err) + } + if got != test.want { + t.Errorf("%s: got %t, want %t", proto.CompactTextString(test.filter), got, test.want) + } + } +}