github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/encoding/csv/reader_test.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package csv
     6  
     7  import (
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  var readTests = []struct {
    14  	Name               string
    15  	Input              string
    16  	Output             [][]string
    17  	UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
    18  
    19  	// These fields are copied into the Reader
    20  	Comma            rune
    21  	Comment          rune
    22  	FieldsPerRecord  int
    23  	LazyQuotes       bool
    24  	TrailingComma    bool
    25  	TrimLeadingSpace bool
    26  
    27  	Error  string
    28  	Line   int // Expected error line if != 0
    29  	Column int // Expected error column if line != 0
    30  }{
    31  	{
    32  		Name:   "Simple",
    33  		Input:  "a,b,c\n",
    34  		Output: [][]string{{"a", "b", "c"}},
    35  	},
    36  	{
    37  		Name:   "CRLF",
    38  		Input:  "a,b\r\nc,d\r\n",
    39  		Output: [][]string{{"a", "b"}, {"c", "d"}},
    40  	},
    41  	{
    42  		Name:   "BareCR",
    43  		Input:  "a,b\rc,d\r\n",
    44  		Output: [][]string{{"a", "b\rc", "d"}},
    45  	},
    46  	{
    47  		Name:               "RFC4180test",
    48  		UseFieldsPerRecord: true,
    49  		Input: `#field1,field2,field3
    50  "aaa","bb
    51  b","ccc"
    52  "a,a","b""bb","ccc"
    53  zzz,yyy,xxx
    54  `,
    55  		Output: [][]string{
    56  			{"#field1", "field2", "field3"},
    57  			{"aaa", "bb\nb", "ccc"},
    58  			{"a,a", `b"bb`, "ccc"},
    59  			{"zzz", "yyy", "xxx"},
    60  		},
    61  	},
    62  	{
    63  		Name:   "NoEOLTest",
    64  		Input:  "a,b,c",
    65  		Output: [][]string{{"a", "b", "c"}},
    66  	},
    67  	{
    68  		Name:   "Semicolon",
    69  		Comma:  ';',
    70  		Input:  "a;b;c\n",
    71  		Output: [][]string{{"a", "b", "c"}},
    72  	},
    73  	{
    74  		Name: "MultiLine",
    75  		Input: `"two
    76  line","one line","three
    77  line
    78  field"`,
    79  		Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
    80  	},
    81  	{
    82  		Name:  "BlankLine",
    83  		Input: "a,b,c\n\nd,e,f\n\n",
    84  		Output: [][]string{
    85  			{"a", "b", "c"},
    86  			{"d", "e", "f"},
    87  		},
    88  	},
    89  	{
    90  		Name:             "TrimSpace",
    91  		Input:            " a,  b,   c\n",
    92  		TrimLeadingSpace: true,
    93  		Output:           [][]string{{"a", "b", "c"}},
    94  	},
    95  	{
    96  		Name:   "LeadingSpace",
    97  		Input:  " a,  b,   c\n",
    98  		Output: [][]string{{" a", "  b", "   c"}},
    99  	},
   100  	{
   101  		Name:    "Comment",
   102  		Comment: '#',
   103  		Input:   "#1,2,3\na,b,c\n#comment",
   104  		Output:  [][]string{{"a", "b", "c"}},
   105  	},
   106  	{
   107  		Name:   "NoComment",
   108  		Input:  "#1,2,3\na,b,c",
   109  		Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
   110  	},
   111  	{
   112  		Name:       "LazyQuotes",
   113  		LazyQuotes: true,
   114  		Input:      `a "word","1"2",a","b`,
   115  		Output:     [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
   116  	},
   117  	{
   118  		Name:       "BareQuotes",
   119  		LazyQuotes: true,
   120  		Input:      `a "word","1"2",a"`,
   121  		Output:     [][]string{{`a "word"`, `1"2`, `a"`}},
   122  	},
   123  	{
   124  		Name:       "BareDoubleQuotes",
   125  		LazyQuotes: true,
   126  		Input:      `a""b,c`,
   127  		Output:     [][]string{{`a""b`, `c`}},
   128  	},
   129  	{
   130  		Name:  "BadDoubleQuotes",
   131  		Input: `a""b,c`,
   132  		Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
   133  	},
   134  	{
   135  		Name:             "TrimQuote",
   136  		Input:            ` "a"," b",c`,
   137  		TrimLeadingSpace: true,
   138  		Output:           [][]string{{"a", " b", "c"}},
   139  	},
   140  	{
   141  		Name:  "BadBareQuote",
   142  		Input: `a "word","b"`,
   143  		Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
   144  	},
   145  	{
   146  		Name:  "BadTrailingQuote",
   147  		Input: `"a word",b"`,
   148  		Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
   149  	},
   150  	{
   151  		Name:  "ExtraneousQuote",
   152  		Input: `"a "word","b"`,
   153  		Error: `extraneous " in field`, Line: 1, Column: 3,
   154  	},
   155  	{
   156  		Name:               "BadFieldCount",
   157  		UseFieldsPerRecord: true,
   158  		Input:              "a,b,c\nd,e",
   159  		Error:              "wrong number of fields", Line: 2,
   160  	},
   161  	{
   162  		Name:               "BadFieldCount1",
   163  		UseFieldsPerRecord: true,
   164  		FieldsPerRecord:    2,
   165  		Input:              `a,b,c`,
   166  		Error:              "wrong number of fields", Line: 1,
   167  	},
   168  	{
   169  		Name:   "FieldCount",
   170  		Input:  "a,b,c\nd,e",
   171  		Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
   172  	},
   173  	{
   174  		Name:  "BadTrailingCommaEOF",
   175  		Input: "a,b,c,",
   176  		Error: "extra delimiter at end of line", Line: 1, Column: 5,
   177  	},
   178  	{
   179  		Name:  "BadTrailingCommaEOL",
   180  		Input: "a,b,c,\n",
   181  		Error: "extra delimiter at end of line", Line: 1, Column: 5,
   182  	},
   183  	{
   184  		Name:             "BadTrailingCommaSpaceEOF",
   185  		TrimLeadingSpace: true,
   186  		Input:            "a,b,c, ",
   187  		Error:            "extra delimiter at end of line", Line: 1, Column: 5,
   188  	},
   189  	{
   190  		Name:             "BadTrailingCommaSpaceEOL",
   191  		TrimLeadingSpace: true,
   192  		Input:            "a,b,c, \n",
   193  		Error:            "extra delimiter at end of line", Line: 1, Column: 5,
   194  	},
   195  	{
   196  		Name:             "BadTrailingCommaLine3",
   197  		TrimLeadingSpace: true,
   198  		Input:            "a,b,c\nd,e,f\ng,hi,",
   199  		Error:            "extra delimiter at end of line", Line: 3, Column: 4,
   200  	},
   201  	{
   202  		Name:   "NotTrailingComma3",
   203  		Input:  "a,b,c, \n",
   204  		Output: [][]string{{"a", "b", "c", " "}},
   205  	},
   206  	{
   207  		Name:          "CommaFieldTest",
   208  		TrailingComma: true,
   209  		Input: `x,y,z,w
   210  x,y,z,
   211  x,y,,
   212  x,,,
   213  ,,,
   214  "x","y","z","w"
   215  "x","y","z",""
   216  "x","y","",""
   217  "x","","",""
   218  "","","",""
   219  `,
   220  		Output: [][]string{
   221  			{"x", "y", "z", "w"},
   222  			{"x", "y", "z", ""},
   223  			{"x", "y", "", ""},
   224  			{"x", "", "", ""},
   225  			{"", "", "", ""},
   226  			{"x", "y", "z", "w"},
   227  			{"x", "y", "z", ""},
   228  			{"x", "y", "", ""},
   229  			{"x", "", "", ""},
   230  			{"", "", "", ""},
   231  		},
   232  	},
   233  	{
   234  		Name:             "Issue 2366",
   235  		TrailingComma:    true,
   236  		TrimLeadingSpace: true,
   237  		Input:            "a,b,\nc,d,e",
   238  		Output: [][]string{
   239  			{"a", "b", ""},
   240  			{"c", "d", "e"},
   241  		},
   242  	},
   243  	{
   244  		Name:             "Issue 2366a",
   245  		TrailingComma:    false,
   246  		TrimLeadingSpace: true,
   247  		Input:            "a,b,\nc,d,e",
   248  		Error:            "extra delimiter at end of line",
   249  	},
   250  }
   251  
   252  func TestRead(t *testing.T) {
   253  	for _, tt := range readTests {
   254  		r := NewReader(strings.NewReader(tt.Input))
   255  		r.Comment = tt.Comment
   256  		if tt.UseFieldsPerRecord {
   257  			r.FieldsPerRecord = tt.FieldsPerRecord
   258  		} else {
   259  			r.FieldsPerRecord = -1
   260  		}
   261  		r.LazyQuotes = tt.LazyQuotes
   262  		r.TrailingComma = tt.TrailingComma
   263  		r.TrimLeadingSpace = tt.TrimLeadingSpace
   264  		if tt.Comma != 0 {
   265  			r.Comma = tt.Comma
   266  		}
   267  		out, err := r.ReadAll()
   268  		perr, _ := err.(*ParseError)
   269  		if tt.Error != "" {
   270  			if err == nil || !strings.Contains(err.Error(), tt.Error) {
   271  				t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
   272  			} else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
   273  				t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
   274  			}
   275  		} else if err != nil {
   276  			t.Errorf("%s: unexpected error %v", tt.Name, err)
   277  		} else if !reflect.DeepEqual(out, tt.Output) {
   278  			t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
   279  		}
   280  	}
   281  }