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