...

Source file src/strconv/quote_test.go

Documentation: strconv

		 1  // Copyright 2009 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 strconv_test
		 6  
		 7  import (
		 8  	. "strconv"
		 9  	"strings"
		10  	"testing"
		11  	"unicode"
		12  )
		13  
		14  // Verify that our IsPrint agrees with unicode.IsPrint.
		15  func TestIsPrint(t *testing.T) {
		16  	n := 0
		17  	for r := rune(0); r <= unicode.MaxRune; r++ {
		18  		if IsPrint(r) != unicode.IsPrint(r) {
		19  			t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r))
		20  			n++
		21  			if n > 10 {
		22  				return
		23  			}
		24  		}
		25  	}
		26  }
		27  
		28  // Verify that our IsGraphic agrees with unicode.IsGraphic.
		29  func TestIsGraphic(t *testing.T) {
		30  	n := 0
		31  	for r := rune(0); r <= unicode.MaxRune; r++ {
		32  		if IsGraphic(r) != unicode.IsGraphic(r) {
		33  			t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r))
		34  			n++
		35  			if n > 10 {
		36  				return
		37  			}
		38  		}
		39  	}
		40  }
		41  
		42  type quoteTest struct {
		43  	in			string
		44  	out		 string
		45  	ascii	 string
		46  	graphic string
		47  }
		48  
		49  var quotetests = []quoteTest{
		50  	{"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
		51  	{"\\", `"\\"`, `"\\"`, `"\\"`},
		52  	{"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`},
		53  	{"\u263a", `"☺"`, `"\u263a"`, `"☺"`},
		54  	{"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`},
		55  	{"\x04", `"\x04"`, `"\x04"`, `"\x04"`},
		56  	// Some non-printable but graphic runes. Final column is double-quoted.
		57  	{"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""},
		58  }
		59  
		60  func TestQuote(t *testing.T) {
		61  	for _, tt := range quotetests {
		62  		if out := Quote(tt.in); out != tt.out {
		63  			t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
		64  		}
		65  		if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
		66  			t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
		67  		}
		68  	}
		69  }
		70  
		71  func TestQuoteToASCII(t *testing.T) {
		72  	for _, tt := range quotetests {
		73  		if out := QuoteToASCII(tt.in); out != tt.ascii {
		74  			t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
		75  		}
		76  		if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
		77  			t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
		78  		}
		79  	}
		80  }
		81  
		82  func TestQuoteToGraphic(t *testing.T) {
		83  	for _, tt := range quotetests {
		84  		if out := QuoteToGraphic(tt.in); out != tt.graphic {
		85  			t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic)
		86  		}
		87  		if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
		88  			t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
		89  		}
		90  	}
		91  }
		92  
		93  func BenchmarkQuote(b *testing.B) {
		94  	for i := 0; i < b.N; i++ {
		95  		Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
		96  	}
		97  }
		98  
		99  func BenchmarkQuoteRune(b *testing.B) {
	 100  	for i := 0; i < b.N; i++ {
	 101  		QuoteRune('\a')
	 102  	}
	 103  }
	 104  
	 105  var benchQuoteBuf []byte
	 106  
	 107  func BenchmarkAppendQuote(b *testing.B) {
	 108  	for i := 0; i < b.N; i++ {
	 109  		benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
	 110  	}
	 111  }
	 112  
	 113  var benchQuoteRuneBuf []byte
	 114  
	 115  func BenchmarkAppendQuoteRune(b *testing.B) {
	 116  	for i := 0; i < b.N; i++ {
	 117  		benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a')
	 118  	}
	 119  }
	 120  
	 121  type quoteRuneTest struct {
	 122  	in			rune
	 123  	out		 string
	 124  	ascii	 string
	 125  	graphic string
	 126  }
	 127  
	 128  var quoterunetests = []quoteRuneTest{
	 129  	{'a', `'a'`, `'a'`, `'a'`},
	 130  	{'\a', `'\a'`, `'\a'`, `'\a'`},
	 131  	{'\\', `'\\'`, `'\\'`, `'\\'`},
	 132  	{0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`},
	 133  	{0x263a, `'☺'`, `'\u263a'`, `'☺'`},
	 134  	{0xfffd, `'�'`, `'\ufffd'`, `'�'`},
	 135  	{0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`},
	 136  	{0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`},
	 137  	{0x04, `'\x04'`, `'\x04'`, `'\x04'`},
	 138  	// Some differences between graphic and printable. Note the last column is double-quoted.
	 139  	{'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"},
	 140  	{'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"},
	 141  	{'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"},
	 142  }
	 143  
	 144  func TestQuoteRune(t *testing.T) {
	 145  	for _, tt := range quoterunetests {
	 146  		if out := QuoteRune(tt.in); out != tt.out {
	 147  			t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
	 148  		}
	 149  		if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
	 150  			t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
	 151  		}
	 152  	}
	 153  }
	 154  
	 155  func TestQuoteRuneToASCII(t *testing.T) {
	 156  	for _, tt := range quoterunetests {
	 157  		if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
	 158  			t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
	 159  		}
	 160  		if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
	 161  			t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
	 162  		}
	 163  	}
	 164  }
	 165  
	 166  func TestQuoteRuneToGraphic(t *testing.T) {
	 167  	for _, tt := range quoterunetests {
	 168  		if out := QuoteRuneToGraphic(tt.in); out != tt.graphic {
	 169  			t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic)
	 170  		}
	 171  		if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
	 172  			t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
	 173  		}
	 174  	}
	 175  }
	 176  
	 177  type canBackquoteTest struct {
	 178  	in	string
	 179  	out bool
	 180  }
	 181  
	 182  var canbackquotetests = []canBackquoteTest{
	 183  	{"`", false},
	 184  	{string(rune(0)), false},
	 185  	{string(rune(1)), false},
	 186  	{string(rune(2)), false},
	 187  	{string(rune(3)), false},
	 188  	{string(rune(4)), false},
	 189  	{string(rune(5)), false},
	 190  	{string(rune(6)), false},
	 191  	{string(rune(7)), false},
	 192  	{string(rune(8)), false},
	 193  	{string(rune(9)), true}, // \t
	 194  	{string(rune(10)), false},
	 195  	{string(rune(11)), false},
	 196  	{string(rune(12)), false},
	 197  	{string(rune(13)), false},
	 198  	{string(rune(14)), false},
	 199  	{string(rune(15)), false},
	 200  	{string(rune(16)), false},
	 201  	{string(rune(17)), false},
	 202  	{string(rune(18)), false},
	 203  	{string(rune(19)), false},
	 204  	{string(rune(20)), false},
	 205  	{string(rune(21)), false},
	 206  	{string(rune(22)), false},
	 207  	{string(rune(23)), false},
	 208  	{string(rune(24)), false},
	 209  	{string(rune(25)), false},
	 210  	{string(rune(26)), false},
	 211  	{string(rune(27)), false},
	 212  	{string(rune(28)), false},
	 213  	{string(rune(29)), false},
	 214  	{string(rune(30)), false},
	 215  	{string(rune(31)), false},
	 216  	{string(rune(0x7F)), false},
	 217  	{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
	 218  	{`0123456789`, true},
	 219  	{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
	 220  	{`abcdefghijklmnopqrstuvwxyz`, true},
	 221  	{`☺`, true},
	 222  	{"\x80", false},
	 223  	{"a\xe0\xa0z", false},
	 224  	{"\ufeffabc", false},
	 225  	{"a\ufeffz", false},
	 226  }
	 227  
	 228  func TestCanBackquote(t *testing.T) {
	 229  	for _, tt := range canbackquotetests {
	 230  		if out := CanBackquote(tt.in); out != tt.out {
	 231  			t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
	 232  		}
	 233  	}
	 234  }
	 235  
	 236  type unQuoteTest struct {
	 237  	in	string
	 238  	out string
	 239  }
	 240  
	 241  var unquotetests = []unQuoteTest{
	 242  	{`""`, ""},
	 243  	{`"a"`, "a"},
	 244  	{`"abc"`, "abc"},
	 245  	{`"☺"`, "☺"},
	 246  	{`"hello world"`, "hello world"},
	 247  	{`"\xFF"`, "\xFF"},
	 248  	{`"\377"`, "\377"},
	 249  	{`"\u1234"`, "\u1234"},
	 250  	{`"\U00010111"`, "\U00010111"},
	 251  	{`"\U0001011111"`, "\U0001011111"},
	 252  	{`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
	 253  	{`"'"`, "'"},
	 254  
	 255  	{`'a'`, "a"},
	 256  	{`'☹'`, "☹"},
	 257  	{`'\a'`, "\a"},
	 258  	{`'\x10'`, "\x10"},
	 259  	{`'\377'`, "\377"},
	 260  	{`'\u1234'`, "\u1234"},
	 261  	{`'\U00010111'`, "\U00010111"},
	 262  	{`'\t'`, "\t"},
	 263  	{`' '`, " "},
	 264  	{`'\''`, "'"},
	 265  	{`'"'`, "\""},
	 266  
	 267  	{"``", ``},
	 268  	{"`a`", `a`},
	 269  	{"`abc`", `abc`},
	 270  	{"`☺`", `☺`},
	 271  	{"`hello world`", `hello world`},
	 272  	{"`\\xFF`", `\xFF`},
	 273  	{"`\\377`", `\377`},
	 274  	{"`\\`", `\`},
	 275  	{"`\n`", "\n"},
	 276  	{"`	`", `	`},
	 277  	{"` `", ` `},
	 278  	{"`a\rb`", "ab"},
	 279  }
	 280  
	 281  var misquoted = []string{
	 282  	``,
	 283  	`"`,
	 284  	`"a`,
	 285  	`"'`,
	 286  	`b"`,
	 287  	`"\"`,
	 288  	`"\9"`,
	 289  	`"\19"`,
	 290  	`"\129"`,
	 291  	`'\'`,
	 292  	`'\9'`,
	 293  	`'\19'`,
	 294  	`'\129'`,
	 295  	`'ab'`,
	 296  	`"\x1!"`,
	 297  	`"\U12345678"`,
	 298  	`"\z"`,
	 299  	"`",
	 300  	"`xxx",
	 301  	"``x\r",
	 302  	"`\"",
	 303  	`"\'"`,
	 304  	`'\"'`,
	 305  	"\"\n\"",
	 306  	"\"\\n\n\"",
	 307  	"'\n'",
	 308  }
	 309  
	 310  func TestUnquote(t *testing.T) {
	 311  	for _, tt := range unquotetests {
	 312  		testUnquote(t, tt.in, tt.out, nil)
	 313  	}
	 314  	for _, tt := range quotetests {
	 315  		testUnquote(t, tt.out, tt.in, nil)
	 316  	}
	 317  	for _, s := range misquoted {
	 318  		testUnquote(t, s, "", ErrSyntax)
	 319  	}
	 320  }
	 321  
	 322  // Issue 23685: invalid UTF-8 should not go through the fast path.
	 323  func TestUnquoteInvalidUTF8(t *testing.T) {
	 324  	tests := []struct {
	 325  		in string
	 326  
	 327  		// one of:
	 328  		want		string
	 329  		wantErr error
	 330  	}{
	 331  		{in: `"foo"`, want: "foo"},
	 332  		{in: `"foo`, wantErr: ErrSyntax},
	 333  		{in: `"` + "\xc0" + `"`, want: "\xef\xbf\xbd"},
	 334  		{in: `"a` + "\xc0" + `"`, want: "a\xef\xbf\xbd"},
	 335  		{in: `"\t` + "\xc0" + `"`, want: "\t\xef\xbf\xbd"},
	 336  	}
	 337  	for _, tt := range tests {
	 338  		testUnquote(t, tt.in, tt.want, tt.wantErr)
	 339  	}
	 340  }
	 341  
	 342  func testUnquote(t *testing.T, in, want string, wantErr error) {
	 343  	// Test Unquote.
	 344  	got, gotErr := Unquote(in)
	 345  	if got != want || gotErr != wantErr {
	 346  		t.Errorf("Unquote(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr)
	 347  	}
	 348  
	 349  	// Test QuotedPrefix.
	 350  	// Adding an arbitrary suffix should not change the result of QuotedPrefix
	 351  	// assume that the suffix doesn't accidentally terminate a truncated input.
	 352  	if gotErr == nil {
	 353  		want = in
	 354  	}
	 355  	suffix := "\n\r\\\"`'" // special characters for quoted strings
	 356  	if len(in) > 0 {
	 357  		suffix = strings.ReplaceAll(suffix, in[:1], "")
	 358  	}
	 359  	in += suffix
	 360  	got, gotErr = QuotedPrefix(in)
	 361  	if gotErr == nil && wantErr != nil {
	 362  		_, wantErr = Unquote(got) // original input had trailing junk, reparse with only valid prefix
	 363  		want = got
	 364  	}
	 365  	if got != want || gotErr != wantErr {
	 366  		t.Errorf("QuotedPrefix(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr)
	 367  	}
	 368  }
	 369  
	 370  func BenchmarkUnquoteEasy(b *testing.B) {
	 371  	for i := 0; i < b.N; i++ {
	 372  		Unquote(`"Give me a rock, paper and scissors and I will move the world."`)
	 373  	}
	 374  }
	 375  
	 376  func BenchmarkUnquoteHard(b *testing.B) {
	 377  	for i := 0; i < b.N; i++ {
	 378  		Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`)
	 379  	}
	 380  }
	 381  

View as plain text