github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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 `Has unexported fields`, 224 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 225 `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. 226 `func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor. 227 }, 228 []string{ 229 `unexportedField`, // No unexported field. 230 `Comment about exported method.`, // No comment about exported method. 231 `unexportedMethod`, // No unexported method. 232 `unexportedTypedConstant`, // No unexported constant. 233 }, 234 }, 235 // Type -u with unexported fields. 236 { 237 "type with unexported fields and -u", 238 []string{"-u", p, `ExportedType`}, 239 []string{ 240 `Comment about exported type`, // Include comment. 241 `type ExportedType struct`, // Type definition. 242 `Comment before exported field.*\n.*ExportedField +int`, 243 `unexportedField int.*Comment on line with unexported field.`, 244 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 245 `unexportedTypedConstant`, 246 }, 247 []string{ 248 `Has unexported fields`, 249 }, 250 }, 251 // Unexported type with -u. 252 { 253 "unexported type with -u", 254 []string{"-u", p, `unexportedType`}, 255 []string{ 256 `Comment about unexported type`, // Include comment. 257 `type unexportedType int`, // Type definition. 258 `func \(unexportedType\) ExportedMethod\(\) bool`, 259 `func \(unexportedType\) unexportedMethod\(\) bool`, 260 `ExportedTypedConstant_unexported unexportedType = iota`, 261 `const unexportedTypedConstant unexportedType = 1`, 262 }, 263 nil, 264 }, 265 266 // Method. 267 { 268 "method", 269 []string{p, `ExportedType.ExportedMethod`}, 270 []string{ 271 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 272 `Comment about exported method.`, 273 }, 274 nil, 275 }, 276 // Method with -u. 277 { 278 "method with -u", 279 []string{"-u", p, `ExportedType.unexportedMethod`}, 280 []string{ 281 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 282 `Comment about unexported method.`, 283 }, 284 nil, 285 }, 286 287 // Case matching off. 288 { 289 "case matching off", 290 []string{p, `casematch`}, 291 []string{ 292 `CaseMatch`, 293 `Casematch`, 294 }, 295 nil, 296 }, 297 298 // Case matching on. 299 { 300 "case matching on", 301 []string{"-c", p, `Casematch`}, 302 []string{ 303 `Casematch`, 304 }, 305 []string{ 306 `CaseMatch`, 307 }, 308 }, 309 } 310 311 func TestDoc(t *testing.T) { 312 maybeSkip(t) 313 for _, test := range tests { 314 var b bytes.Buffer 315 var flagSet flag.FlagSet 316 err := do(&b, &flagSet, test.args) 317 if err != nil { 318 t.Fatalf("%s: %s\n", test.name, err) 319 } 320 output := b.Bytes() 321 failed := false 322 for j, yes := range test.yes { 323 re, err := regexp.Compile(yes) 324 if err != nil { 325 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err) 326 } 327 if !re.Match(output) { 328 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes) 329 failed = true 330 } 331 } 332 for j, no := range test.no { 333 re, err := regexp.Compile(no) 334 if err != nil { 335 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err) 336 } 337 if re.Match(output) { 338 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no) 339 failed = true 340 } 341 } 342 if failed { 343 t.Logf("\n%s", output) 344 } 345 } 346 } 347 348 // Test the code to try multiple packages. Our test case is 349 // go doc rand.Float64 350 // This needs to find math/rand.Float64; however crypto/rand, which doesn't 351 // have the symbol, usually appears first in the directory listing. 352 func TestMultiplePackages(t *testing.T) { 353 if testing.Short() { 354 t.Skip("scanning file system takes too long") 355 } 356 maybeSkip(t) 357 var b bytes.Buffer // We don't care about the output. 358 // Make sure crypto/rand does not have the symbol. 359 { 360 var flagSet flag.FlagSet 361 err := do(&b, &flagSet, []string{"crypto/rand.float64"}) 362 if err == nil { 363 t.Errorf("expected error from crypto/rand.float64") 364 } else if !strings.Contains(err.Error(), "no symbol float64") { 365 t.Errorf("unexpected error %q from crypto/rand.float64", err) 366 } 367 } 368 // Make sure math/rand does have the symbol. 369 { 370 var flagSet flag.FlagSet 371 err := do(&b, &flagSet, []string{"math/rand.float64"}) 372 if err != nil { 373 t.Errorf("unexpected error %q from math/rand.float64", err) 374 } 375 } 376 // Try the shorthand. 377 { 378 var flagSet flag.FlagSet 379 err := do(&b, &flagSet, []string{"rand.float64"}) 380 if err != nil { 381 t.Errorf("unexpected error %q from rand.float64", err) 382 } 383 } 384 // Now try a missing symbol. We should see both packages in the error. 385 { 386 var flagSet flag.FlagSet 387 err := do(&b, &flagSet, []string{"rand.doesnotexit"}) 388 if err == nil { 389 t.Errorf("expected error from rand.doesnotexit") 390 } else { 391 errStr := err.Error() 392 if !strings.Contains(errStr, "no symbol") { 393 t.Errorf("error %q should contain 'no symbol", errStr) 394 } 395 if !strings.Contains(errStr, "crypto/rand") { 396 t.Errorf("error %q should contain crypto/rand", errStr) 397 } 398 if !strings.Contains(errStr, "math/rand") { 399 t.Errorf("error %q should contain math/rand", errStr) 400 } 401 } 402 } 403 } 404 405 type trimTest struct { 406 path string 407 prefix string 408 result string 409 ok bool 410 } 411 412 var trimTests = []trimTest{ 413 {"", "", "", true}, 414 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, 415 {"/usr/gopher/bar", "/usr/gopher", "bar", true}, 416 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, 417 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false}, 418 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false}, 419 } 420 421 func TestTrim(t *testing.T) { 422 for _, test := range trimTests { 423 result, ok := trim(test.path, test.prefix) 424 if ok != test.ok { 425 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok) 426 continue 427 } 428 if result != test.result { 429 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result) 430 continue 431 } 432 } 433 }