Skip to content

Commit b95a706

Browse files
authored
Merge pull request bitfield#89 from gty929/small-updates
Bug fixes and improvements for corner cases
2 parents 7ad252b + 6189603 commit b95a706

File tree

6 files changed

+119
-4
lines changed

6 files changed

+119
-4
lines changed

filters.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"container/ring"
77
"crypto/sha256"
88
"encoding/hex"
9+
"errors"
910
"fmt"
1011
"io"
1112
"os"
@@ -41,7 +42,7 @@ func (p *Pipe) Basename() *Pipe {
4142
func (p *Pipe) Column(col int) *Pipe {
4243
return p.EachLine(func(line string, out *strings.Builder) {
4344
columns := strings.Fields(line)
44-
if col <= len(columns) {
45+
if col > 0 && col <= len(columns) {
4546
out.WriteString(columns[col-1])
4647
out.WriteRune('\n')
4748
}
@@ -176,7 +177,7 @@ func (p *Pipe) First(lines int) *Pipe {
176177
return p
177178
}
178179
defer p.Close()
179-
if lines == 0 {
180+
if lines <= 0 {
180181
return NewPipe()
181182
}
182183
scanner := bufio.NewScanner(p.Reader)
@@ -263,7 +264,7 @@ func (p *Pipe) Last(lines int) *Pipe {
263264
return p
264265
}
265266
defer p.Close()
266-
if lines == 0 {
267+
if lines <= 0 {
267268
return NewPipe()
268269
}
269270
scanner := bufio.NewScanner(p.Reader)
@@ -303,6 +304,9 @@ func (p *Pipe) Match(s string) *Pipe {
303304
// that match the specified compiled regular expression. If there is an error
304305
// reading the pipe, the pipe's error status is also set.
305306
func (p *Pipe) MatchRegexp(re *regexp.Regexp) *Pipe {
307+
if re == nil { // to prevent SIGSEGV
308+
return p.WithError(errors.New("nil regular expression"))
309+
}
306310
return p.EachLine(func(line string, out *strings.Builder) {
307311
if re.MatchString(line) {
308312
out.WriteString(line)
@@ -327,6 +331,9 @@ func (p *Pipe) Reject(s string) *Pipe {
327331
// lines that don't match the specified compiled regular expression. If there
328332
// is an error reading the pipe, the pipe's error status is also set.
329333
func (p *Pipe) RejectRegexp(re *regexp.Regexp) *Pipe {
334+
if re == nil { // to prevent SIGSEGV
335+
return p.WithError(errors.New("nil regular expression"))
336+
}
330337
return p.EachLine(func(line string, out *strings.Builder) {
331338
if !re.MatchString(line) {
332339
out.WriteString(line)
@@ -351,6 +358,9 @@ func (p *Pipe) Replace(search, replace string) *Pipe {
351358
// represents the text of the first submatch. If there is an error reading the
352359
// pipe, the pipe's error status is also set.
353360
func (p *Pipe) ReplaceRegexp(re *regexp.Regexp, replace string) *Pipe {
361+
if re == nil { // to prevent SIGSEGV
362+
return p.WithError(errors.New("nil regular expression"))
363+
}
354364
return p.EachLine(func(line string, out *strings.Builder) {
355365
out.WriteString(re.ReplaceAllString(line, replace))
356366
out.WriteRune('\n')

filters_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ func TestColumn(t *testing.T) {
5151
if !bytes.Equal(got, want) {
5252
t.Errorf("want %q, got %q", want, got)
5353
}
54+
got, err = script.File("testdata/column.input.txt").Column(0).Bytes()
55+
if err != nil {
56+
t.Error()
57+
}
58+
if !bytes.Equal(got, []byte{}) {
59+
t.Errorf("want %q, got %q", want, got)
60+
}
61+
got, err = script.File("testdata/column.input.txt").Column(-1).Bytes()
62+
if err != nil {
63+
t.Error()
64+
}
65+
if !bytes.Equal(got, []byte{}) {
66+
t.Errorf("want %q, got %q", want, got)
67+
}
68+
got, err = script.File("testdata/column.input.txt").Column(10).Bytes()
69+
if err != nil {
70+
t.Error()
71+
}
72+
if !bytes.Equal(got, []byte{}) {
73+
t.Errorf("want %q, got %q", want, got)
74+
}
5475
}
5576

5677
func TestConcat(t *testing.T) {
@@ -232,6 +253,18 @@ func TestFirst(t *testing.T) {
232253
if err == nil {
233254
t.Error("input not closed after reading")
234255
}
256+
input = script.File("testdata/first.input.txt")
257+
gotZero, err = input.First(-1).CountLines()
258+
if err != nil {
259+
t.Fatal(err)
260+
}
261+
if gotZero != 0 {
262+
t.Errorf("want 0 lines, got %d lines", gotZero)
263+
}
264+
_, err = ioutil.ReadAll(input.Reader)
265+
if err == nil {
266+
t.Error("input not closed after reading")
267+
}
235268
want, err = script.File("testdata/first.input.txt").Bytes()
236269
if err != nil {
237270
t.Fatal(err)
@@ -312,6 +345,18 @@ func TestLast(t *testing.T) {
312345
if err == nil {
313346
t.Error("input not closed after reading")
314347
}
348+
input = script.File("testdata/first.input.txt")
349+
gotZero, err = input.Last(-1).CountLines()
350+
if err != nil {
351+
t.Fatal(err)
352+
}
353+
if gotZero != 0 {
354+
t.Errorf("want 0 lines, got %d lines", gotZero)
355+
}
356+
_, err = ioutil.ReadAll(input.Reader)
357+
if err == nil {
358+
t.Error("input not closed after reading")
359+
}
315360
want, err = script.File("testdata/first.input.txt").Bytes()
316361
if err != nil {
317362
t.Fatal(err)
@@ -350,6 +395,16 @@ func TestMatch(t *testing.T) {
350395

351396
func TestMatchRegexp(t *testing.T) {
352397
t.Parallel()
398+
p := script.File("testdata/hello.txt")
399+
_, err := p.MatchRegexp(nil).String()
400+
if err == nil {
401+
t.Error("nil regex should cause an error")
402+
}
403+
_, err = ioutil.ReadAll(p.Reader)
404+
if err == nil {
405+
t.Error("input not closed after reading")
406+
}
407+
353408
testCases := []struct {
354409
testFileName string
355410
match string
@@ -397,6 +452,16 @@ func TestReplace(t *testing.T) {
397452

398453
func TestReplaceRegexp(t *testing.T) {
399454
t.Parallel()
455+
p := script.File("testdata/hello.txt")
456+
_, err := p.ReplaceRegexp(nil, "").String()
457+
if err == nil {
458+
t.Error("nil regex should cause an error")
459+
}
460+
_, err = ioutil.ReadAll(p.Reader)
461+
if err == nil {
462+
t.Error("input not closed after reading")
463+
}
464+
400465
testCases := []struct {
401466
testFileName string
402467
regexp string
@@ -444,6 +509,16 @@ func TestReject(t *testing.T) {
444509

445510
func TestRejectRegexp(t *testing.T) {
446511
t.Parallel()
512+
p := script.File("testdata/hello.txt")
513+
_, err := p.RejectRegexp(nil).String()
514+
if err == nil {
515+
t.Error("nil regex should cause an error")
516+
}
517+
_, err = ioutil.ReadAll(p.Reader)
518+
if err == nil {
519+
t.Error("input not closed after reading")
520+
}
521+
447522
testCases := []struct {
448523
testFileName string
449524
reject string

pipes.go

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ func (p *Pipe) Read(b []byte) (int, error) {
7575
// SetError sets the pipe's error status to the specified error.
7676
func (p *Pipe) SetError(err error) {
7777
if p != nil {
78+
if err != nil {
79+
p.Close()
80+
}
7881
p.err = err
7982
}
8083
}

pipes_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ func TestWithReader(t *testing.T) {
2626
}
2727
}
2828

29+
func TestWithError(t *testing.T) {
30+
t.Parallel()
31+
p := script.File("testdata/empty.txt")
32+
want := "fake error"
33+
_, gotErr := p.WithError(errors.New(want)).String()
34+
if gotErr.Error() != "fake error" {
35+
t.Errorf("want %q, got %q", want, gotErr.Error())
36+
}
37+
_, err := ioutil.ReadAll(p.Reader)
38+
if err == nil {
39+
t.Error("input not closed after reading")
40+
}
41+
p = script.File("testdata/empty.txt")
42+
_, gotErr = p.WithError(nil).String()
43+
if gotErr != nil {
44+
t.Errorf("got unexpected error: %q", gotErr.Error())
45+
}
46+
}
47+
2948
func TestWithStdout(t *testing.T) {
3049
t.Parallel()
3150
buf := &bytes.Buffer{}
@@ -126,6 +145,8 @@ func doMethodsOnPipe(t *testing.T, p *script.Pipe, kind string) {
126145
p.Error()
127146
action = "Exec()"
128147
p.Exec("bogus")
148+
action = "ExecForEach()"
149+
p.ExecForEach("bogus")
129150
action = "ExitStatus()"
130151
p.ExitStatus()
131152
action = "First()"
@@ -142,6 +163,10 @@ func doMethodsOnPipe(t *testing.T, p *script.Pipe, kind string) {
142163
p.MatchRegexp(regexp.MustCompile(".*"))
143164
action = "Read()"
144165
p.Read([]byte{})
166+
action = "Reject()"
167+
p.Reject("")
168+
action = "RejectRegexp"
169+
p.RejectRegexp(regexp.MustCompile(".*"))
145170
action = "Replace()"
146171
p.Replace("old", "new")
147172
action = "ReplaceRegexp()"

testdata/freq.golden.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
10 apple
22
4 banana
3-
2 orange
3+
4 orange
44
1 kumquat

testdata/freq.input.txt

+2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ apple
66
orange
77
kumquat
88
apple
9+
orange
910
apple
1011
banana
1112
banana
1213
apple
1314
apple
15+
orange
1416
apple
1517
apple
1618
apple

0 commit comments

Comments
 (0)