github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/doc/doc_test.go (about) 1 // Copyright 2015 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 main 6 7 import ( 8 "bytes" 9 "flag" 10 "regexp" 11 "runtime" 12 "strings" 13 "testing" 14 ) 15 16 func maybeSkip(t *testing.T) { 17 if strings.HasPrefix(runtime.GOOS, "nacl") { 18 t.Skip("nacl does not have a full file tree") 19 } 20 if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") { 21 t.Skip("darwin/arm does not have a full file tree") 22 } 23 } 24 25 type test struct { 26 name string 27 args []string // Arguments to "[go] doc". 28 yes []string // Regular expressions that should match. 29 no []string // Regular expressions that should not match. 30 } 31 32 const p = "cmd/doc/testdata" 33 34 var tests = []test{ 35 // Sanity check. 36 { 37 "sanity check", 38 []string{p}, 39 []string{`type ExportedType struct`}, 40 nil, 41 }, 42 43 // Package dump includes import, package statement. 44 { 45 "package clause", 46 []string{p}, 47 []string{`package pkg.*cmd/doc/testdata`}, 48 nil, 49 }, 50 51 // Constants. 52 // Package dump 53 { 54 "full package", 55 []string{p}, 56 []string{ 57 `Package comment`, 58 `const ExportedConstant = 1`, // Simple constant. 59 `const ConstOne = 1`, // First entry in constant block. 60 `const ConstFive ...`, // From block starting with unexported constant. 61 `var ExportedVariable = 1`, // Simple variable. 62 `var VarOne = 1`, // First entry in variable block. 63 `func ExportedFunc\(a int\) bool`, // Function. 64 `type ExportedType struct { ... }`, // Exported type. 65 `const ExportedTypedConstant ExportedType = iota`, // Typed constant. 66 `const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type. 67 }, 68 []string{ 69 `const internalConstant = 2`, // No internal constants. 70 `var internalVariable = 2`, // No internal variables. 71 `func internalFunc(a int) bool`, // No internal functions. 72 `Comment about exported constant`, // No comment for single constant. 73 `Comment about exported variable`, // No comment for single variable. 74 `Comment about block of constants.`, // No comment for constant block. 75 `Comment about block of variables.`, // No comment for variable block. 76 `Comment before ConstOne`, // No comment for first entry in constant block. 77 `Comment before VarOne`, // No comment for first entry in variable block. 78 `ConstTwo = 2`, // No second entry in constant block. 79 `VarTwo = 2`, // No second entry in variable block. 80 `VarFive = 5`, // From block starting with unexported variable. 81 `type unexportedType`, // No unexported type. 82 `unexportedTypedConstant`, // No unexported typed constant. 83 `Field`, // No fields. 84 `Method`, // No methods. 85 }, 86 }, 87 // Package dump -u 88 { 89 "full package with u", 90 []string{`-u`, p}, 91 []string{ 92 `const ExportedConstant = 1`, // Simple constant. 93 `const internalConstant = 2`, // Internal constants. 94 `func internalFunc\(a int\) bool`, // Internal functions. 95 }, 96 []string{ 97 `Comment about exported constant`, // No comment for simple constant. 98 `Comment about block of constants`, // No comment for constant block. 99 `Comment about internal function`, // No comment for internal function. 100 }, 101 }, 102 103 // Single constant. 104 { 105 "single constant", 106 []string{p, `ExportedConstant`}, 107 []string{ 108 `Comment about exported constant`, // Include comment. 109 `const ExportedConstant = 1`, 110 }, 111 nil, 112 }, 113 // Single constant -u. 114 { 115 "single constant with -u", 116 []string{`-u`, p, `internalConstant`}, 117 []string{ 118 `Comment about internal constant`, // Include comment. 119 `const internalConstant = 2`, 120 }, 121 nil, 122 }, 123 // Block of constants. 124 { 125 "block of constants", 126 []string{p, `ConstTwo`}, 127 []string{ 128 `Comment before ConstOne.\n.*ConstOne = 1`, // First... 129 `ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up. 130 `Comment about block of constants`, // Comment does too. 131 }, 132 []string{ 133 `constThree`, // No unexported constant. 134 }, 135 }, 136 // Block of constants -u. 137 { 138 "block of constants with -u", 139 []string{"-u", p, `constThree`}, 140 []string{ 141 `constThree = 3.*Comment on line with constThree`, 142 }, 143 nil, 144 }, 145 146 // Single variable. 147 { 148 "single variable", 149 []string{p, `ExportedVariable`}, 150 []string{ 151 `ExportedVariable`, // Include comment. 152 `var ExportedVariable = 1`, 153 }, 154 nil, 155 }, 156 // Single variable -u. 157 { 158 "single variable with -u", 159 []string{`-u`, p, `internalVariable`}, 160 []string{ 161 `Comment about internal variable`, // Include comment. 162 `var internalVariable = 2`, 163 }, 164 nil, 165 }, 166 // Block of variables. 167 { 168 "block of variables", 169 []string{p, `VarTwo`}, 170 []string{ 171 `Comment before VarOne.\n.*VarOne = 1`, // First... 172 `VarTwo = 2.*Comment on line with VarTwo`, // And second show up. 173 `Comment about block of variables`, // Comment does too. 174 }, 175 []string{ 176 `varThree= 3`, // No unexported variable. 177 }, 178 }, 179 // Block of variables -u. 180 { 181 "block of variables with -u", 182 []string{"-u", p, `varThree`}, 183 []string{ 184 `varThree = 3.*Comment on line with varThree`, 185 }, 186 nil, 187 }, 188 189 // Function. 190 { 191 "function", 192 []string{p, `ExportedFunc`}, 193 []string{ 194 `Comment about exported function`, // Include comment. 195 `func ExportedFunc\(a int\) bool`, 196 }, 197 nil, 198 }, 199 // Function -u. 200 { 201 "function with -u", 202 []string{"-u", p, `internalFunc`}, 203 []string{ 204 `Comment about internal function`, // Include comment. 205 `func internalFunc\(a int\) bool`, 206 }, 207 nil, 208 }, 209 210 // Type. 211 { 212 "type", 213 []string{p, `ExportedType`}, 214 []string{ 215 `Comment about exported type`, // Include comment. 216 `type ExportedType struct`, // Type definition. 217 `Comment before exported field.*\n.*ExportedField +int` + 218 `.*Comment on line with exported field.`, 219 `ExportedEmbeddedType.*Comment on line with exported embedded field.`, 220 `Has unexported fields`, 221 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 222 `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. 223 `func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor. 224 }, 225 []string{ 226 `unexportedField`, // No unexported field. 227 `int.*embedded`, // No unexported embedded field. 228 `Comment about exported method.`, // No comment about exported method. 229 `unexportedMethod`, // No unexported method. 230 `unexportedTypedConstant`, // No unexported constant. 231 }, 232 }, 233 // Type -u with unexported fields. 234 { 235 "type with unexported fields and -u", 236 []string{"-u", p, `ExportedType`}, 237 []string{ 238 `Comment about exported type`, // Include comment. 239 `type ExportedType struct`, // Type definition. 240 `Comment before exported field.*\n.*ExportedField +int`, 241 `unexportedField.*int.*Comment on line with unexported field.`, 242 `ExportedEmbeddedType.*Comment on line with exported embedded field.`, 243 `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`, 244 `unexportedType.*Comment on line with unexported embedded field.`, 245 `\*unexportedType.*Comment on line with unexported embedded \*field.`, 246 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 247 `unexportedTypedConstant`, 248 }, 249 []string{ 250 `Has unexported fields`, 251 }, 252 }, 253 // Unexported type with -u. 254 { 255 "unexported type with -u", 256 []string{"-u", p, `unexportedType`}, 257 []string{ 258 `Comment about unexported type`, // Include comment. 259 `type unexportedType int`, // Type definition. 260 `func \(unexportedType\) ExportedMethod\(\) bool`, 261 `func \(unexportedType\) unexportedMethod\(\) bool`, 262 `ExportedTypedConstant_unexported unexportedType = iota`, 263 `const unexportedTypedConstant unexportedType = 1`, 264 }, 265 nil, 266 }, 267 268 // Interface. 269 { 270 "type", 271 []string{p, `ExportedInterface`}, 272 []string{ 273 `Comment about exported interface`, // Include comment. 274 `type ExportedInterface interface`, // Interface definition. 275 `Comment before exported method.*\n.*ExportedMethod\(\)` + 276 `.*Comment on line with exported method`, 277 `Has unexported methods`, 278 }, 279 []string{ 280 `unexportedField`, // No unexported field. 281 `Comment about exported method`, // No comment about exported method. 282 `unexportedMethod`, // No unexported method. 283 `unexportedTypedConstant`, // No unexported constant. 284 }, 285 }, 286 // Interface -u with unexported methods. 287 { 288 "type with unexported methods and -u", 289 []string{"-u", p, `ExportedInterface`}, 290 []string{ 291 `Comment about exported interface`, // Include comment. 292 `type ExportedInterface interface`, // Interface definition. 293 `Comment before exported method.*\n.*ExportedMethod\(\)` + 294 `.*Comment on line with exported method`, 295 `unexportedMethod\(\).*Comment on line with unexported method.`, 296 }, 297 []string{ 298 `Has unexported methods`, 299 }, 300 }, 301 302 // Method. 303 { 304 "method", 305 []string{p, `ExportedType.ExportedMethod`}, 306 []string{ 307 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 308 `Comment about exported method.`, 309 }, 310 nil, 311 }, 312 // Method with -u. 313 { 314 "method with -u", 315 []string{"-u", p, `ExportedType.unexportedMethod`}, 316 []string{ 317 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 318 `Comment about unexported method.`, 319 }, 320 nil, 321 }, 322 323 // Case matching off. 324 { 325 "case matching off", 326 []string{p, `casematch`}, 327 []string{ 328 `CaseMatch`, 329 `Casematch`, 330 }, 331 nil, 332 }, 333 334 // Case matching on. 335 { 336 "case matching on", 337 []string{"-c", p, `Casematch`}, 338 []string{ 339 `Casematch`, 340 }, 341 []string{ 342 `CaseMatch`, 343 }, 344 }, 345 } 346 347 func TestDoc(t *testing.T) { 348 maybeSkip(t) 349 for _, test := range tests { 350 var b bytes.Buffer 351 var flagSet flag.FlagSet 352 err := do(&b, &flagSet, test.args) 353 if err != nil { 354 t.Fatalf("%s: %s\n", test.name, err) 355 } 356 output := b.Bytes() 357 failed := false 358 for j, yes := range test.yes { 359 re, err := regexp.Compile(yes) 360 if err != nil { 361 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err) 362 } 363 if !re.Match(output) { 364 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes) 365 failed = true 366 } 367 } 368 for j, no := range test.no { 369 re, err := regexp.Compile(no) 370 if err != nil { 371 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err) 372 } 373 if re.Match(output) { 374 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no) 375 failed = true 376 } 377 } 378 if failed { 379 t.Logf("\n%s", output) 380 } 381 } 382 } 383 384 // Test the code to try multiple packages. Our test case is 385 // go doc rand.Float64 386 // This needs to find math/rand.Float64; however crypto/rand, which doesn't 387 // have the symbol, usually appears first in the directory listing. 388 func TestMultiplePackages(t *testing.T) { 389 if testing.Short() { 390 t.Skip("scanning file system takes too long") 391 } 392 maybeSkip(t) 393 var b bytes.Buffer // We don't care about the output. 394 // Make sure crypto/rand does not have the symbol. 395 { 396 var flagSet flag.FlagSet 397 err := do(&b, &flagSet, []string{"crypto/rand.float64"}) 398 if err == nil { 399 t.Errorf("expected error from crypto/rand.float64") 400 } else if !strings.Contains(err.Error(), "no symbol float64") { 401 t.Errorf("unexpected error %q from crypto/rand.float64", err) 402 } 403 } 404 // Make sure math/rand does have the symbol. 405 { 406 var flagSet flag.FlagSet 407 err := do(&b, &flagSet, []string{"math/rand.float64"}) 408 if err != nil { 409 t.Errorf("unexpected error %q from math/rand.float64", err) 410 } 411 } 412 // Try the shorthand. 413 { 414 var flagSet flag.FlagSet 415 err := do(&b, &flagSet, []string{"rand.float64"}) 416 if err != nil { 417 t.Errorf("unexpected error %q from rand.float64", err) 418 } 419 } 420 // Now try a missing symbol. We should see both packages in the error. 421 { 422 var flagSet flag.FlagSet 423 err := do(&b, &flagSet, []string{"rand.doesnotexit"}) 424 if err == nil { 425 t.Errorf("expected error from rand.doesnotexit") 426 } else { 427 errStr := err.Error() 428 if !strings.Contains(errStr, "no symbol") { 429 t.Errorf("error %q should contain 'no symbol", errStr) 430 } 431 if !strings.Contains(errStr, "crypto/rand") { 432 t.Errorf("error %q should contain crypto/rand", errStr) 433 } 434 if !strings.Contains(errStr, "math/rand") { 435 t.Errorf("error %q should contain math/rand", errStr) 436 } 437 } 438 } 439 } 440 441 type trimTest struct { 442 path string 443 prefix string 444 result string 445 ok bool 446 } 447 448 var trimTests = []trimTest{ 449 {"", "", "", true}, 450 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, 451 {"/usr/gopher/bar", "/usr/gopher", "bar", true}, 452 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false}, 453 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false}, 454 } 455 456 func TestTrim(t *testing.T) { 457 for _, test := range trimTests { 458 result, ok := trim(test.path, test.prefix) 459 if ok != test.ok { 460 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok) 461 continue 462 } 463 if result != test.result { 464 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result) 465 continue 466 } 467 } 468 }