From 58690664baad4302c2ddc0ae55b165480ad7d30a Mon Sep 17 00:00:00 2001 From: Sonia Hamilton Date: Thu, 6 Dec 2018 00:32:44 +0000 Subject: [PATCH 1/2] failure on nil reader --- byline.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ byline_test.go | 9 +++++++++ 2 files changed, 63 insertions(+) diff --git a/byline.go b/byline.go index 9068e73..c3f830b 100644 --- a/byline.go +++ b/byline.go @@ -42,6 +42,9 @@ type AWKVars struct { // NewReader - get new line by line Reader func NewReader(reader io.Reader) *Reader { + if reader == nil { + return nil + } lr := &Reader{ scanner: bufio.NewScanner(reader), existsData: true, @@ -76,6 +79,9 @@ func (lr *Reader) scanLinesBySep(data []byte, atEOF bool) (advance int, token [] // Read - implement io.Reader interface func (lr *Reader) Read(p []byte) (n int, err error) { + if lr == nil { + return 0, errors.New("nil reader") + } var ( bufErr, filterErr error lineBytes []byte @@ -119,6 +125,9 @@ func (lr *Reader) Read(p []byte) (n int, err error) { // Map - set filter function for process each line func (lr *Reader) Map(filterFn func([]byte) []byte) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { return filterFn(line), nil }) @@ -126,12 +135,18 @@ func (lr *Reader) Map(filterFn func([]byte) []byte) *Reader { // MapErr - set filter function for process each line, returns error if needed (io.EOF for example) func (lr *Reader) MapErr(filterFn func([]byte) ([]byte, error)) *Reader { + if lr == nil { + return nil + } lr.filterFuncs = append(lr.filterFuncs, filterFn) return lr } // MapString - set filter function for process each line as string func (lr *Reader) MapString(filterFn func(string) string) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { return []byte(filterFn(string(line))), nil }) @@ -139,6 +154,9 @@ func (lr *Reader) MapString(filterFn func(string) string) *Reader { // MapStringErr - set filter function for process each line as string, returns error if needed (io.EOF for example) func (lr *Reader) MapStringErr(filterFn func(string) (string, error)) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { newString, err := filterFn(string(line)) return []byte(newString), err @@ -148,6 +166,9 @@ func (lr *Reader) MapStringErr(filterFn func(string) (string, error)) *Reader { // Each - processing each line. // Do not save the value of the byte slice, since it can change in the next filter-steps. func (lr *Reader) Each(filterFn func([]byte)) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { filterFn(line) return line, nil @@ -156,6 +177,9 @@ func (lr *Reader) Each(filterFn func([]byte)) *Reader { // EachString - processing each line as string func (lr *Reader) EachString(filterFn func(string)) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { filterFn(string(line)) return line, nil @@ -164,6 +188,9 @@ func (lr *Reader) EachString(filterFn func(string)) *Reader { // Grep - grep lines by func func (lr *Reader) Grep(filterFn func([]byte) bool) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { if filterFn(line) { return line, nil @@ -175,6 +202,9 @@ func (lr *Reader) Grep(filterFn func([]byte) bool) *Reader { // GrepString - grep lines as string by func func (lr *Reader) GrepString(filterFn func(string) bool) *Reader { + if lr == nil { + return nil + } return lr.Grep(func(line []byte) bool { return filterFn(string(line)) }) @@ -182,6 +212,9 @@ func (lr *Reader) GrepString(filterFn func(string) bool) *Reader { // GrepByRegexp - grep lines by regexp func (lr *Reader) GrepByRegexp(re *regexp.Regexp) *Reader { + if lr == nil { + return nil + } return lr.Grep(func(line []byte) bool { return re.Match(line) }) @@ -189,18 +222,27 @@ func (lr *Reader) GrepByRegexp(re *regexp.Regexp) *Reader { // SetRS - set lines (records) separator func (lr *Reader) SetRS(rs byte) *Reader { + if lr == nil { + return nil + } lr.awkVars.RS = rs return lr } // SetFS - set field separator for AWK mode func (lr *Reader) SetFS(fs *regexp.Regexp) *Reader { + if lr == nil { + return nil + } lr.awkVars.FS = fs return lr } // AWKMode - process lines with AWK like mode func (lr *Reader) AWKMode(filterFn func(line string, fields []string, vars AWKVars) (string, error)) *Reader { + if lr == nil { + return nil + } return lr.MapErr(func(line []byte) ([]byte, error) { addRS := false RS := []byte{lr.awkVars.RS} @@ -227,6 +269,9 @@ func (lr *Reader) AWKMode(filterFn func(line string, fields []string, vars AWKVa // Discard - read all content from Reader for side effect from filter functions func (lr *Reader) Discard() error { + if lr == nil { + return errors.New("nil reader") + } _, err := io.Copy(ioutil.Discard, lr) return err } @@ -244,11 +289,17 @@ func (lr *Reader) ReadAllSlice() ([][]byte, error) { // ReadAll - read all content from Reader to slice of bytes func (lr *Reader) ReadAll() ([]byte, error) { + if lr == nil { + return []byte{}, errors.New("nil reader") + } return ioutil.ReadAll(lr) } // ReadAllSliceString - read all content from Reader to string slice by lines func (lr *Reader) ReadAllSliceString() ([]string, error) { + if lr == nil { + return []string{}, errors.New("nil reader") + } result := []string{} err := lr.MapString(func(line string) string { result = append(result, line) @@ -260,6 +311,9 @@ func (lr *Reader) ReadAllSliceString() ([]string, error) { // ReadAllString - read all content from Reader to one string func (lr *Reader) ReadAllString() (string, error) { + if lr == nil { + return "", errors.New("nil reader") + } result, err := ioutil.ReadAll(lr) return string(result), err } diff --git a/byline_test.go b/byline_test.go index 7ac84c7..7cd2085 100644 --- a/byline_test.go +++ b/byline_test.go @@ -385,6 +385,15 @@ func TestAWKModeWithError(t *testing.T) { } func TestReadAll(t *testing.T) { + t.Run("ReadAllEmptyReader", func(t *testing.T) { + var reader io.Reader + _, err := byline.NewReader(reader). + SetRS('#'). + MapString(func(line string) string { return "<" + line }). + ReadAll() + require.Error(t, err) + }) + t.Run("ReadAll", func(t *testing.T) { reader := strings.NewReader(`1 name_one 12.3#2 error_row#3 three row 15.51#4 row#5 row end`) result, err := byline.NewReader(reader). From ed4d2df7aceaf27f102a2e262e70be9348151989 Mon Sep 17 00:00:00 2001 From: Sonia Hamilton Date: Thu, 6 Dec 2018 21:00:20 +1100 Subject: [PATCH 2/2] ErrNilReader --- byline.go | 13 ++++++++----- byline_test.go | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/byline.go b/byline.go index c3f830b..f097178 100644 --- a/byline.go +++ b/byline.go @@ -13,6 +13,9 @@ var ( // ErrOmitLine - error for Map*Err/AWKMode, for omitting current line ErrOmitLine = errors.New("ErrOmitLine") + // ErrNilReader - error for provided reader being nil + ErrNilReader = errors.New("nil reader") + // default field separator defaultFS = regexp.MustCompile(`\s+`) // default line separator @@ -80,7 +83,7 @@ func (lr *Reader) scanLinesBySep(data []byte, atEOF bool) (advance int, token [] // Read - implement io.Reader interface func (lr *Reader) Read(p []byte) (n int, err error) { if lr == nil { - return 0, errors.New("nil reader") + return 0, ErrNilReader } var ( bufErr, filterErr error @@ -270,7 +273,7 @@ func (lr *Reader) AWKMode(filterFn func(line string, fields []string, vars AWKVa // Discard - read all content from Reader for side effect from filter functions func (lr *Reader) Discard() error { if lr == nil { - return errors.New("nil reader") + return ErrNilReader } _, err := io.Copy(ioutil.Discard, lr) return err @@ -290,7 +293,7 @@ func (lr *Reader) ReadAllSlice() ([][]byte, error) { // ReadAll - read all content from Reader to slice of bytes func (lr *Reader) ReadAll() ([]byte, error) { if lr == nil { - return []byte{}, errors.New("nil reader") + return []byte{}, ErrNilReader } return ioutil.ReadAll(lr) } @@ -298,7 +301,7 @@ func (lr *Reader) ReadAll() ([]byte, error) { // ReadAllSliceString - read all content from Reader to string slice by lines func (lr *Reader) ReadAllSliceString() ([]string, error) { if lr == nil { - return []string{}, errors.New("nil reader") + return []string{}, ErrNilReader } result := []string{} err := lr.MapString(func(line string) string { @@ -312,7 +315,7 @@ func (lr *Reader) ReadAllSliceString() ([]string, error) { // ReadAllString - read all content from Reader to one string func (lr *Reader) ReadAllString() (string, error) { if lr == nil { - return "", errors.New("nil reader") + return "", ErrNilReader } result, err := ioutil.ReadAll(lr) return string(result), err diff --git a/byline_test.go b/byline_test.go index 7cd2085..6983bf6 100644 --- a/byline_test.go +++ b/byline_test.go @@ -385,13 +385,14 @@ func TestAWKModeWithError(t *testing.T) { } func TestReadAll(t *testing.T) { - t.Run("ReadAllEmptyReader", func(t *testing.T) { + t.Run("ReadAllNilReader", func(t *testing.T) { var reader io.Reader _, err := byline.NewReader(reader). SetRS('#'). MapString(func(line string) string { return "<" + line }). ReadAll() - require.Error(t, err) + require.Exactly(t, byline.ErrNilReader, err, "ReadAllNilReader") + }) t.Run("ReadAll", func(t *testing.T) {