Tue Nov 19 06:51:39 2019 UTC ()
pkgtools/pkglint: update to 19.3.9

Changes since 19.3.8:

Match man pages in ALTERNATIVES with their counterparts in PLIST. In
PLIST files, ${PKGMANDIR} may be abbreviated as a simple "man", but not
in ALTERNATIVES.


(rillig)
diff -r1.608 -r1.609 pkgsrc/pkgtools/pkglint/Makefile
diff -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/alternatives.go
diff -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/alternatives_test.go
diff -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/mktypes.go
diff -r1.40 -r1.41 pkgsrc/pkgtools/pkglint/files/pkgsrc.go
diff -r1.34 -r1.35 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/testnames_test.go
diff -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go
diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/intqa/testnames.go
diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go
diff -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go
diff -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go
diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go
diff -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go

cvs diff -r1.608 -r1.609 pkgsrc/pkgtools/pkglint/Makefile (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/Makefile 2019/11/17 02:06:01 1.608
+++ pkgsrc/pkgtools/pkglint/Makefile 2019/11/19 06:51:38 1.609
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1# $NetBSD: Makefile,v 1.608 2019/11/17 02:06:01 rillig Exp $ 1# $NetBSD: Makefile,v 1.609 2019/11/19 06:51:38 rillig Exp $
2 2
3PKGNAME= pkglint-19.3.8 3PKGNAME= pkglint-19.3.9
4CATEGORIES= pkgtools 4CATEGORIES= pkgtools
5DISTNAME= tools 5DISTNAME= tools
6MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/} 6MASTER_SITES= ${MASTER_SITE_GITHUB:=golang/}
7GITHUB_PROJECT= tools 7GITHUB_PROJECT= tools
8GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704 8GITHUB_TAG= 92d8274bd7b8a4c65f24bafe401a029e58392704
9 9
10MAINTAINER= rillig@NetBSD.org 10MAINTAINER= rillig@NetBSD.org
11HOMEPAGE= https://github.com/rillig/pkglint 11HOMEPAGE= https://github.com/rillig/pkglint
12COMMENT= Verifier for NetBSD packages 12COMMENT= Verifier for NetBSD packages
13LICENSE= 2-clause-bsd 13LICENSE= 2-clause-bsd
14CONFLICTS+= pkglint4-[0-9]* 14CONFLICTS+= pkglint4-[0-9]*
15 15
16USE_TOOLS+= pax 16USE_TOOLS+= pax

cvs diff -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/Attic/alternatives.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/alternatives.go 2019/11/17 01:26:25 1.15
+++ pkgsrc/pkgtools/pkglint/files/Attic/alternatives.go 2019/11/19 06:51:38 1.16
@@ -18,26 +18,29 @@ func CheckFileAlternatives(filename stri @@ -18,26 +18,29 @@ func CheckFileAlternatives(filename stri
18 18
19 checkPlistWrapper := func(line *Line, wrapper string) { 19 checkPlistWrapper := func(line *Line, wrapper string) {
20 if plist.Files[wrapper] != nil { 20 if plist.Files[wrapper] != nil {
21 line.Errorf("Alternative wrapper %q must not appear in the PLIST.", wrapper) 21 line.Errorf("Alternative wrapper %q must not appear in the PLIST.", wrapper)
22 } 22 }
23 } 23 }
24 24
25 checkPlistAlternative := func(line *Line, alternative string) { 25 checkPlistAlternative := func(line *Line, alternative string) {
26 relImplementation := strings.Replace(alternative, "@PREFIX@/", "", 1) 26 relImplementation := strings.Replace(alternative, "@PREFIX@/", "", 1)
27 plistName := replaceAll(relImplementation, `@(\w+)@`, "${$1}") 27 plistName := replaceAll(relImplementation, `@(\w+)@`, "${$1}")
28 if plist.Files[plistName] != nil || G.Pkg.vars.IsDefined("ALTERNATIVES_SRC") { 28 if plist.Files[plistName] != nil || G.Pkg.vars.IsDefined("ALTERNATIVES_SRC") {
29 return 29 return
30 } 30 }
 31 if plist.Files[strings.Replace(plistName, "${PKGMANDIR}", "man", 1)] != nil {
 32 return
 33 }
31 34
32 switch { 35 switch {
33 36
34 case hasPrefix(alternative, "/"): 37 case hasPrefix(alternative, "/"):
35 // It's possible but unusual to refer to a fixed absolute path. 38 // It's possible but unusual to refer to a fixed absolute path.
36 // These cannot be mentioned in the PLIST since they are not part of the package. 39 // These cannot be mentioned in the PLIST since they are not part of the package.
37 break 40 break
38 41
39 case plistName == alternative: 42 case plistName == alternative:
40 line.Errorf("Alternative implementation %q must appear in the PLIST.", alternative) 43 line.Errorf("Alternative implementation %q must appear in the PLIST.", alternative)
41 44
42 default: 45 default:
43 line.Errorf("Alternative implementation %q must appear in the PLIST as %q.", alternative, plistName) 46 line.Errorf("Alternative implementation %q must appear in the PLIST as %q.", alternative, plistName)

cvs diff -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/Attic/alternatives_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/alternatives_test.go 2019/07/14 21:25:47 1.16
+++ pkgsrc/pkgtools/pkglint/files/Attic/alternatives_test.go 2019/11/19 06:51:38 1.17
@@ -96,13 +96,35 @@ func (s *Suite) Test_CheckFileAlternativ @@ -96,13 +96,35 @@ func (s *Suite) Test_CheckFileAlternativ
96 // really had this case in mind when I initially wrote the code in 96 // really had this case in mind when I initially wrote the code in
97 // CheckFileAlternatives. 97 // CheckFileAlternatives.
98 t.SetUpPackage("category/package", 98 t.SetUpPackage("category/package",
99 "ALTERNATIVES_SRC=\talts") 99 "ALTERNATIVES_SRC=\talts")
100 t.CreateFileLines("category/package/ALTERNATIVES", 100 t.CreateFileLines("category/package/ALTERNATIVES",
101 "bin/pgm @PREFIX@/bin/gnu-program", 101 "bin/pgm @PREFIX@/bin/gnu-program",
102 "bin/pgm @PREFIX@/bin/nb-program") 102 "bin/pgm @PREFIX@/bin/nb-program")
103 t.FinishSetUp() 103 t.FinishSetUp()
104 104
105 G.Check(t.File("category/package")) 105 G.Check(t.File("category/package"))
106 106
107 t.CheckOutputEmpty() 107 t.CheckOutputEmpty()
108} 108}
 109
 110// When a man page is mentioned in the ALTERNATIVES file, it must use the
 111// PKGMANDIR variable. In the PLIST files though, there is some magic
 112// in the pkgsrc infrastructure that maps man/ to ${PKGMANDIR}, which
 113// leads to a bit less typing.
 114//
 115// Seen in graphics/py-blockdiag.
 116func (s *Suite) Test_CheckFileAlternatives__PLIST_man(c *check.C) {
 117 t := s.Init(c)
 118
 119 t.SetUpPackage("category/package")
 120 t.CreateFileLines("category/package/ALTERNATIVES",
 121 "@PKGMANDIR@/man1/blockdiag @PREFIX@/@PKGMANDIR@/man1/blockdiag-@PYVERSSUFFIX@.1")
 122 t.CreateFileLines("category/package/PLIST",
 123 PlistCvsID,
 124 "man/man1/blockdiag-${PYVERSSUFFIX}.1")
 125 t.FinishSetUp()
 126
 127 G.Check(t.File("category/package"))
 128
 129 t.CheckOutputEmpty()
 130}

cvs diff -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/Attic/mktypes.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/mktypes.go 2019/11/01 19:56:53 1.19
+++ pkgsrc/pkgtools/pkglint/files/Attic/mktypes.go 2019/11/19 06:51:38 1.20
@@ -100,27 +100,27 @@ func (m MkVarUseModifier) MatchMatch() ( @@ -100,27 +100,27 @@ func (m MkVarUseModifier) MatchMatch() (
100 exact := !strings.ContainsAny(m.Text[1:], "*?[\\$") 100 exact := !strings.ContainsAny(m.Text[1:], "*?[\\$")
101 return true, m.Text[0] == 'M', m.Text[1:], exact 101 return true, m.Text[0] == 'M', m.Text[1:], exact
102 } 102 }
103 return false, false, "", false 103 return false, false, "", false
104} 104}
105 105
106func (m MkVarUseModifier) IsToLower() bool { return m.Text == "tl" } 106func (m MkVarUseModifier) IsToLower() bool { return m.Text == "tl" }
107 107
108// ChangesWords returns true if applying this modifier to a list variable 108// ChangesWords returns true if applying this modifier to a list variable
109// may change the number of words in the list, or their boundaries. 109// may change the number of words in the list, or their boundaries.
110func (m MkVarUseModifier) ChangesWords() bool { 110func (m MkVarUseModifier) ChangesWords() bool {
111 text := m.Text 111 text := m.Text
112 112
113 // See MkParser.VarUseModifiers for the meaning of these modifiers. 113 // See MkParser.varUseModifier for the meaning of these modifiers.
114 switch text[0] { 114 switch text[0] {
115 115
116 case 'E', 'H', 'M', 'N', 'O', 'R', 'T': 116 case 'E', 'H', 'M', 'N', 'O', 'R', 'T':
117 return false 117 return false
118 118
119 case 'C', 'Q', 'S': 119 case 'C', 'Q', 'S':
120 // For the :C and :S modifiers, a more detailed analysis could reveal 120 // For the :C and :S modifiers, a more detailed analysis could reveal
121 // cases that don't change the structure, such as :S,a,b,g or 121 // cases that don't change the structure, such as :S,a,b,g or
122 // :C,[0-9A-Za-z_],.,g, but not :C,x,,g. 122 // :C,[0-9A-Za-z_],.,g, but not :C,x,,g.
123 return true 123 return true
124 } 124 }
125 125
126 switch text { 126 switch text {

cvs diff -r1.40 -r1.41 pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go 2019/11/17 02:55:56 1.40
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc.go 2019/11/19 06:51:38 1.41
@@ -209,27 +209,27 @@ func (src *Pkgsrc) loadDocChangesFromFil @@ -209,27 +209,27 @@ func (src *Pkgsrc) loadDocChangesFromFil
209 } 209 }
210 210
211 change := src.parseDocChange(line, warn) 211 change := src.parseDocChange(line, warn)
212 if change == nil { 212 if change == nil {
213 continue 213 continue
214 } 214 }
215 215
216 changes = append(changes, change) 216 changes = append(changes, change)
217 217
218 if !warn { 218 if !warn {
219 continue 219 continue
220 } 220 }
221 221
222 if year != "" && len(change.Date) >= 4 && change.Date[0:4] != year { 222 if year != "" && change.Date[0:4] != year {
223 line.Warnf("Year %q for %s does not match the filename %s.", 223 line.Warnf("Year %q for %s does not match the filename %s.",
224 change.Date[0:4], change.Pkgpath, filename) 224 change.Date[0:4], change.Pkgpath, filename)
225 } 225 }
226 226
227 if len(changes) >= 2 && year != "" { 227 if len(changes) >= 2 && year != "" {
228 if prev := changes[len(changes)-2]; change.Date < prev.Date { 228 if prev := changes[len(changes)-2]; change.Date < prev.Date {
229 line.Warnf("Date %q for %s is earlier than %q in %s.", 229 line.Warnf("Date %q for %s is earlier than %q in %s.",
230 change.Date, change.Pkgpath, prev.Date, line.RefToLocation(prev.Location)) 230 change.Date, change.Pkgpath, prev.Date, line.RefToLocation(prev.Location))
231 line.Explain( 231 line.Explain(
232 "The entries in doc/CHANGES should be in chronological order, and", 232 "The entries in doc/CHANGES should be in chronological order, and",
233 "all dates are assumed to be in the UTC timezone, to prevent time", 233 "all dates are assumed to be in the UTC timezone, to prevent time",
234 "warps.", 234 "warps.",
235 "", 235 "",

cvs diff -r1.34 -r1.35 pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc_test.go 2019/11/17 02:55:56 1.34
+++ pkgsrc/pkgtools/pkglint/files/Attic/pkgsrc_test.go 2019/11/19 06:51:38 1.35
@@ -358,96 +358,100 @@ func (s *Suite) Test_Pkgsrc_parseDocChan @@ -358,96 +358,100 @@ func (s *Suite) Test_Pkgsrc_parseDocChan
358 test("\tAdded something [author date]", 358 test("\tAdded something [author date]",
359 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 359 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
360 "\tAdded something [author date]") 360 "\tAdded something [author date]")
361 361
362 test("\tAdded category/package 1.0 [author 2019-11-17]", 362 test("\tAdded category/package 1.0 [author 2019-11-17]",
363 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 363 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
364 "\tAdded category/package 1.0 [author 2019-11-17]") 364 "\tAdded category/package 1.0 [author 2019-11-17]")
365 365
366 test("\t\tToo large indentation", 366 test("\t\tToo large indentation",
367 "WARN: doc/CHANGES-2019:123: Package changes should be indented using a single tab, not \"\\t\\t\".") 367 "WARN: doc/CHANGES-2019:123: Package changes should be indented using a single tab, not \"\\t\\t\".")
368 test("\t Too large indentation", 368 test("\t Too large indentation",
369 "WARN: doc/CHANGES-2019:123: Package changes should be indented using a single tab, not \"\\t \".") 369 "WARN: doc/CHANGES-2019:123: Package changes should be indented using a single tab, not \"\\t \".")
370 370
 371 test("\t",
 372 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t")
 373 test("\t1",
 374 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1")
371 test("\t1 2 3 4", 375 test("\t1 2 3 4",
372 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4") 376 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4")
373 test("\t1 2 3 4 5", 377 test("\t1 2 3 4 5",
374 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5") 378 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5")
375 test("\t1 2 3 4 5 6", 379 test("\t1 2 3 4 5 6",
376 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5 6") 380 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5 6")
377 test("\t1 2 3 4 5 6 7", 381 test("\t1 2 3 4 5 6 7",
378 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5 6 7") 382 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4 5 6 7")
379 test("\t1 2 [3 4", 383 test("\t1 2 [3 4",
380 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 [3 4") 384 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 [3 4")
381 test("\t1 2 [3 4]", 385 test("\t1 2 [3 4]",
382 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 [3 4]") 386 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 [3 4]")
383 test("\tAdded 2 [3 4]", 387 test("\tAdded 2 [3 4]",
384 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \tAdded 2 [3 4]") 388 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \tAdded 2 [3 4]")
385 389
386 test("\tAdded pkgpath version 1.0 [author 2019-01-01]", 390 test("\tAdded pkgpath version 1.0 [author 2019-01-01]",
387 nil...) 391 nil...)
388 392
389 // "to" is wrong 393 // "to" is wrong
390 test("\tAdded pkgpath to 1.0 [author date]", 394 test("\tAdded pkgpath to 1.0 [author 2019-01-01]",
391 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 395 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
392 "\tAdded pkgpath to 1.0 [author date]") 396 "\tAdded pkgpath to 1.0 [author 2019-01-01]")
393 397
394 test("\tUpdated pkgpath to 1.0 [author 2019-01-01]", 398 test("\tUpdated pkgpath to 1.0 [author 2019-01-01]",
395 nil...) 399 nil...)
396 400
397 // "from" is wrong 401 // "from" is wrong
398 test("\tUpdated pkgpath from 1.0 [author date]", 402 test("\tUpdated pkgpath from 1.0 [author 2019-01-01]",
399 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 403 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
400 "\tUpdated pkgpath from 1.0 [author date]") 404 "\tUpdated pkgpath from 1.0 [author 2019-01-01]")
401 405
402 test("\tDowngraded pkgpath to 1.0 [author 2019-01-01]", 406 test("\tDowngraded pkgpath to 1.0 [author 2019-01-01]",
403 nil...) 407 nil...)
404 408
405 // "from" is wrong 409 // "from" is wrong
406 test("\tDowngraded pkgpath from 1.0 [author date]", 410 test("\tDowngraded pkgpath from 1.0 [author 2019-01-01]",
407 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 411 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
408 "\tDowngraded pkgpath from 1.0 [author date]") 412 "\tDowngraded pkgpath from 1.0 [author 2019-01-01]")
409 413
410 test("\tRemoved pkgpath [author 2019-01-01]", 414 test("\tRemoved pkgpath [author 2019-01-01]",
411 nil...) 415 nil...)
412 416
413 test("\tRemoved pkgpath successor pkgpath [author 2019-01-01]", 417 test("\tRemoved pkgpath successor pkgpath [author 2019-01-01]",
414 nil...) 418 nil...)
415 419
416 // "and" is wrong 420 // "and" is wrong
417 test("\tRemoved pkgpath and pkgpath [author date]", 421 test("\tRemoved pkgpath and pkgpath [author 2019-01-01]",
418 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 422 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
419 "\tRemoved pkgpath and pkgpath [author date]") 423 "\tRemoved pkgpath and pkgpath [author 2019-01-01]")
420 424
421 test("\tRenamed pkgpath to other [author 2019-01-01]", 425 test("\tRenamed pkgpath to other [author 2019-01-01]",
422 nil...) 426 nil...)
423 427
424 // "from" is wrong 428 // "from" is wrong
425 test("\tRenamed pkgpath from previous [author date]", 429 test("\tRenamed pkgpath from previous [author 2019-01-01]",
426 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 430 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
427 "\tRenamed pkgpath from previous [author date]") 431 "\tRenamed pkgpath from previous [author 2019-01-01]")
428 432
429 test("\tMoved pkgpath to other [author 2019-01-01]", 433 test("\tMoved pkgpath to other [author 2019-01-01]",
430 nil...) 434 nil...)
431 435
432 // "from" is wrong 436 // "from" is wrong
433 test("\tMoved pkgpath from previous [author date]", 437 test("\tMoved pkgpath from previous [author 2019-01-01]",
434 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 438 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
435 "\tMoved pkgpath from previous [author date]") 439 "\tMoved pkgpath from previous [author 2019-01-01]")
436 440
437 // "Split" is wrong 441 // "Split" is wrong
438 test("\tSplit pkgpath into a and b [author date]", 442 test("\tSplit pkgpath into a and b [author 2019-01-01]",
439 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 443 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
440 "\tSplit pkgpath into a and b [author date]") 444 "\tSplit pkgpath into a and b [author 2019-01-01]")
441 445
442 // Entries ending in a colon are used for infrastructure changes. 446 // Entries ending in a colon are used for infrastructure changes.
443 test("\tmk: remove support for USE_CROSSBASE [author 2016-06-19]", 447 test("\tmk: remove support for USE_CROSSBASE [author 2016-06-19]",
444 nil...) 448 nil...)
445 449
446 test("\tAdded category/pkgpath version 1.0 [author-dash 2019-01-01]", 450 test("\tAdded category/pkgpath version 1.0 [author-dash 2019-01-01]",
447 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+ 451 "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
448 "\tAdded category/pkgpath version 1.0 [author-dash 2019-01-01]") 452 "\tAdded category/pkgpath version 1.0 [author-dash 2019-01-01]")
449} 453}
450 454
451func (s *Suite) Test_Pkgsrc_checkRemovedAfterLastFreeze(c *check.C) { 455func (s *Suite) Test_Pkgsrc_checkRemovedAfterLastFreeze(c *check.C) {
452 t := s.Init(c) 456 t := s.Init(c)
453 457

cvs diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/Attic/testnames_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/Attic/testnames_test.go 2019/11/17 01:26:25 1.7
+++ pkgsrc/pkgtools/pkglint/files/Attic/testnames_test.go 2019/11/19 06:51:38 1.8
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1package pkglint 1package pkglint
2 2
3import ( 3import (
4 "gopkg.in/check.v1" 4 "gopkg.in/check.v1"
5 "netbsd.org/pkglint/intqa" 5 "netbsd.org/pkglint/intqa"
6) 6)
7 7
8// Ensures that all test names follow a common naming scheme: 8// Ensures that all test names follow a common naming scheme:
9// 9//
10// Test_${Type}_${Method}__${description_using_underscores} 10// Test_${Type}_${Method}__${description_using_underscores}
11func (s *Suite) Test__test_names(c *check.C) { 11func (s *Suite) Test__test_names(c *check.C) {
12 ck := intqa.NewTestNameChecker(c.Errorf) 12 ck := intqa.NewTestNameChecker(c.Errorf)
13 ck.IgnoreFiles("*yacc.go") 13 ck.Configure("*", "*", "*", -intqa.EMissingTest)
14 ck.Enable(intqa.EAll, -intqa.EMissingTest) 14 ck.Configure("*yacc.go", "*", "*", intqa.ENone)
15 ck.Check() 15 ck.Check()
16} 16}

cvs diff -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/getopt/Attic/getopt_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/getopt/Attic/getopt_test.go 2019/11/17 01:26:26 1.11
+++ pkgsrc/pkgtools/pkglint/files/getopt/Attic/getopt_test.go 2019/11/19 06:51:38 1.12
@@ -401,16 +401,16 @@ func (s *Suite) Test_Options_Help__with_ @@ -401,16 +401,16 @@ func (s *Suite) Test_Options_Help__with_
401 " -W, --warnings=warning,... Print selected warnings\n"+ 401 " -W, --warnings=warning,... Print selected warnings\n"+
402 "\n"+ 402 "\n"+
403 " Flags for -W, --warnings:\n"+ 403 " Flags for -W, --warnings:\n"+
404 " all all of the following\n"+ 404 " all all of the following\n"+
405 " none none of the following\n"+ 405 " none none of the following\n"+
406 " basic Print basic warnings (enabled)\n"+ 406 " basic Print basic warnings (enabled)\n"+
407 " extra Print extra warnings (disabled)\n"+ 407 " extra Print extra warnings (disabled)\n"+
408 "\n"+ 408 "\n"+
409 " (Prefix a flag with \"no-\" to disable it.)\n") 409 " (Prefix a flag with \"no-\" to disable it.)\n")
410} 410}
411 411
412func (s *Suite) Test__test_names(c *check.C) { 412func (s *Suite) Test__test_names(c *check.C) {
413 ck := intqa.NewTestNameChecker(c.Errorf) 413 ck := intqa.NewTestNameChecker(c.Errorf)
414 ck.Enable(intqa.EAll, -intqa.EMissingTest) 414 ck.Configure("*", "*", "*", -intqa.EMissingTest)
415 ck.Check() 415 ck.Check()
416} 416}

cvs diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/histogram/Attic/histogram_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/histogram/Attic/histogram_test.go 2019/11/17 01:26:26 1.2
+++ pkgsrc/pkgtools/pkglint/files/histogram/Attic/histogram_test.go 2019/11/19 06:51:38 1.3
@@ -20,16 +20,16 @@ func (s *Suite) Test_Histogram(c *check. @@ -20,16 +20,16 @@ func (s *Suite) Test_Histogram(c *check.
20 hgr.Add("two", 2) 20 hgr.Add("two", 2)
21 hgr.Add("three", 3) 21 hgr.Add("three", 3)
22 22
23 var out strings.Builder 23 var out strings.Builder
24 hgr.PrintStats(&out, "caption", 2) 24 hgr.PrintStats(&out, "caption", 2)
25 25
26 c.Check(out.String(), check.Equals, ""+ 26 c.Check(out.String(), check.Equals, ""+
27 "caption 3 three\n"+ 27 "caption 3 three\n"+
28 "caption 2 two\n") 28 "caption 2 two\n")
29} 29}
30 30
31func (s *Suite) Test__test_names(c *check.C) { 31func (s *Suite) Test__test_names(c *check.C) {
32 ck := intqa.NewTestNameChecker(c.Errorf) 32 ck := intqa.NewTestNameChecker(c.Errorf)
33 ck.Enable(intqa.EAll, -intqa.EMissingTest) 33 ck.Configure("*", "*", "*", -intqa.EMissingTest)
34 ck.Check() 34 ck.Check()
35} 35}

cvs diff -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames.go 2019/11/17 01:26:26 1.5
+++ pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames.go 2019/11/19 06:51:38 1.6
@@ -1,33 +1,34 @@ @@ -1,33 +1,34 @@
1// Package intqa provides quality assurance for the pkglint code. 1// Package intqa provides quality assurance for the pkglint code.
2package intqa 2package intqa
3 3
4import ( 4import (
5 "fmt" 5 "fmt"
6 "go/ast" 6 "go/ast"
7 "go/parser" 7 "go/parser"
8 "go/token" 8 "go/token"
9 "io" 9 "io"
10 "os" 10 "os"
11 "path/filepath" 11 "path"
 12 "reflect"
12 "sort" 13 "sort"
13 "strings" 14 "strings"
14 "unicode" 15 "unicode"
15) 16)
16 17
17type Error int 18type Error int
18 19
19const ( 20const (
20 ENone Error = iota 21 ENone Error = iota + 1
21 EAll 22 EAll
22 23
23 // A function or method does not have a corresponding test. 24 // A function or method does not have a corresponding test.
24 EMissingTest 25 EMissingTest
25 26
26 // The name of a test function does not correspond to a program 27 // The name of a test function does not correspond to a program
27 // element to be tested. 28 // element to be tested.
28 EMissingTestee 29 EMissingTestee
29 30
30 // The tests are not in the same order as their corresponding 31 // The tests are not in the same order as their corresponding
31 // testees in the main code. 32 // testees in the main code.
32 EOrder 33 EOrder
33 34
@@ -35,368 +36,428 @@ const ( @@ -35,368 +36,428 @@ const (
35 EName 36 EName
36 37
37 // The file of the test method does not correspond to the 38 // The file of the test method does not correspond to the
38 // file of the testee. 39 // file of the testee.
39 EFile 40 EFile
40) 41)
41 42
42// TestNameChecker ensures that all test names follow a common naming scheme: 43// TestNameChecker ensures that all test names follow a common naming scheme:
43// Test_${Type}_${Method}__${description_using_underscores} 44// Test_${Type}_${Method}__${description_using_underscores}
44// Each of the variable parts may be omitted. 45// Each of the variable parts may be omitted.
45type TestNameChecker struct { 46type TestNameChecker struct {
46 errorf func(format string, args ...interface{}) 47 errorf func(format string, args ...interface{})
47 48
48 ignoredFiles []string 49 filters []filter
49 order int 50 order int
50 51
51 testees []*testee 52 testees []*testee
52 tests []*test 53 tests []*test
53 54
54 errorsMask uint64 55 errors []string
55 errors []string 56 out io.Writer
56 out io.Writer 
57} 57}
58 58
59// NewTestNameChecker creates a new checker. 59// NewTestNameChecker creates a new checker.
60// By default, all errors are disabled; call Enable to enable them. 60// By default, all errors are enabled;
 61// call Configure to disable them selectively.
61func NewTestNameChecker(errorf func(format string, args ...interface{})) *TestNameChecker { 62func NewTestNameChecker(errorf func(format string, args ...interface{})) *TestNameChecker {
62 return &TestNameChecker{errorf: errorf, out: os.Stderr} 63 ck := TestNameChecker{errorf: errorf, out: os.Stderr}
63} 
64 64
65func (ck *TestNameChecker) IgnoreFiles(fileGlob string) { 65 // For test fixtures from https://gopkg.in/check/v1.
66 ck.ignoredFiles = append(ck.ignoredFiles, fileGlob) 66 ck.Configure("*_test.go", "*", "SetUpTest", -EMissingTest)
67} 67 ck.Configure("*_test.go", "*", "TearDownTest", -EMissingTest)
68 68
69func (ck *TestNameChecker) Enable(errors ...Error) { 69 // See https://github.com/rillig/gobco.
70 for _, err := range errors { 70 ck.Configure("gobco_*.go", "gobco*", "*", -EMissingTest)
71 if err == ENone { 71 ck.Configure("gobco_*.go", "", "gobco*", -EMissingTest)
72 ck.errorsMask = 0 72
73 } else if err == EAll { 73 return &ck
74 ck.errorsMask = ^uint64(0) 74}
75 } else if err < 0 { 75
76 ck.errorsMask &= ^(uint64(1) << -uint(err)) 76// Configure sets the errors that are activated for the given code,
77 } else { 77// specified by shell patterns like in path.Match.
78 ck.errorsMask |= uint64(1) << uint(err) 78//
79 } 79// All rules are applied in order. Later rules overwrite earlier rules.
80 } 80//
 81// Individual errors can be enabled by giving their constant and disabled
 82// by negating them, such as -EMissingTestee. To reset everything, use
 83// either EAll or ENone.
 84func (ck *TestNameChecker) Configure(filenames, typeNames, funcNames string, errors ...Error) {
 85 ck.filters = append(ck.filters, filter{filenames, typeNames, funcNames, errors})
81} 86}
82 87
83func (ck *TestNameChecker) Check() { 88func (ck *TestNameChecker) Check() {
84 ck.load() 89 ck.load(".")
85 ck.checkTestees() 90 ck.checkTestees()
86 ck.checkTests() 91 ck.checkTests()
87 ck.checkOrder() 92 ck.checkOrder()
88 ck.print() 93 ck.print()
89} 94}
90 95
91// load loads all type, function and method names from the current package. 96// load loads all type, function and method names from the current package.
92func (ck *TestNameChecker) load() { 97func (ck *TestNameChecker) load(dir string) {
 98
93 fileSet := token.NewFileSet() 99 fileSet := token.NewFileSet()
94 pkgs, err := parser.ParseDir(fileSet, ".", nil, 0) 100 pkgs, err := parser.ParseDir(fileSet, dir, nil, 0)
95 if err != nil { 101 if err != nil {
96 panic(err) 102 panic(err)
97 } 103 }
98 104
99 var pkgnames []string 105 for _, pkgname := range sortedKeys(pkgs) {
100 for pkgname := range pkgs { 
101 pkgnames = append(pkgnames, pkgname) 
102 } 
103 sort.Strings(pkgnames) 
104 
105 for _, pkgname := range pkgnames { 
106 files := pkgs[pkgname].Files 106 files := pkgs[pkgname].Files
107 107
108 var filenames []string 108 for _, filename := range sortedKeys(files) {
109 for filename := range files { 
110 filenames = append(filenames, filename) 
111 } 
112 sort.Strings(filenames) 
113 
114 for _, filename := range filenames { 
115 file := files[filename] 109 file := files[filename]
116 for _, decl := range file.Decls { 110 for _, decl := range file.Decls {
117 ck.loadDecl(decl, filename) 111 ck.loadDecl(decl, filename)
118 } 112 }
119 } 113 }
120 } 114 }
121 115
122 ck.relate() 116 ck.relate()
123} 117}
124 118
125// loadDecl adds a single type or function declaration to the known elements. 119// loadDecl adds a single type or function declaration to the known elements.
126func (ck *TestNameChecker) loadDecl(decl ast.Decl, filename string) { 120func (ck *TestNameChecker) loadDecl(decl ast.Decl, filename string) {
127 switch decl := decl.(type) { 121 switch decl := decl.(type) {
128 122
129 case *ast.GenDecl: 123 case *ast.GenDecl:
130 for _, spec := range decl.Specs { 124 for _, spec := range decl.Specs {
131 switch spec := spec.(type) { 125 switch spec := spec.(type) {
132 case *ast.TypeSpec: 126 case *ast.TypeSpec:
133 typeName := spec.Name.Name 127 typeName := spec.Name.Name
134 ck.addCode(code{filename, typeName, "", ck.nextOrder()}) 128 ck.addCode(code{filename, typeName, "", 0})
135 } 129 }
136 } 130 }
137 131
138 case *ast.FuncDecl: 132 case *ast.FuncDecl:
139 typeName := "" 133 typeName := ""
140 if decl.Recv != nil { 134 if decl.Recv != nil {
141 typeExpr := decl.Recv.List[0].Type.(ast.Expr) 135 typeExpr := decl.Recv.List[0].Type.(ast.Expr)
142 if star, ok := typeExpr.(*ast.StarExpr); ok { 136 if star, ok := typeExpr.(*ast.StarExpr); ok {
143 typeName = star.X.(*ast.Ident).Name 137 typeName = star.X.(*ast.Ident).Name
144 } else { 138 } else {
145 typeName = typeExpr.(*ast.Ident).Name 139 typeName = typeExpr.(*ast.Ident).Name
146 } 140 }
147 } 141 }
148 ck.addCode(code{filename, typeName, decl.Name.Name, ck.nextOrder()}) 142 funcName := decl.Name.Name
 143 ck.addCode(code{filename, typeName, funcName, 0})
149 } 144 }
150} 145}
151 146
152func (ck *TestNameChecker) addCode(code code) { 147func (ck *TestNameChecker) addCode(code code) {
153 isTest := strings.HasSuffix(code.file, "_test.go") && 148 if code.isTestScope() && code.isFunc() && code.Func == "TestMain" {
154 code.Type != "" && 149 // This is not a test for Main, but a wrapper function of the test.
155 strings.HasPrefix(code.Func, "Test") 150 // Therefore it is completely ignored.
 151 // See https://golang.org/pkg/testing/#hdr-Main.
 152 //
 153 // Among others, this function is created by
 154 // https://github.com/rillig/gobco when measuring the branch
 155 // coverage of a package.
 156 return
 157 }
156 158
157 if isTest { 159 if !ck.isRelevant(code.file, code.Type, code.Func, EAll) {
 160 return
 161 }
 162
 163 if code.isTest() {
158 ck.addTest(code) 164 ck.addTest(code)
159 } else { 165 } else {
160 ck.addTestee(code) 166 ck.addTestee(code)
161 } 167 }
162} 168}
163 169
164func (ck *TestNameChecker) addTestee(code code) { 170func (ck *TestNameChecker) addTestee(code code) {
 171 code.order = ck.nextOrder()
165 ck.testees = append(ck.testees, &testee{code}) 172 ck.testees = append(ck.testees, &testee{code})
166} 173}
167 174
168func (ck *TestNameChecker) addTest(code code) { 175func (ck *TestNameChecker) addTest(code code) {
169 if !strings.HasPrefix(code.Func, "Test_") { 176 if !strings.HasPrefix(code.Func, "Test_") &&
 177 code.Func != "Test" &&
170 ck.addError( 178 ck.addError(
171 EName, 179 EName,
 180 code,
172 "Test %q must start with %q.", 181 "Test %q must start with %q.",
173 code.fullName(), "Test_") 182 code.fullName(), "Test_") {
 183
174 return 184 return
175 } 185 }
176 186
177 parts := strings.SplitN(code.Func, "__", 2) 187 parts := strings.SplitN(code.Func, "__", 2)
178 testeeName := strings.TrimPrefix(strings.TrimPrefix(parts[0], "Test"), "_") 188 testeeName := strings.TrimPrefix(strings.TrimPrefix(parts[0], "Test"), "_")
179 descr := "" 189 descr := ""
180 if len(parts) > 1 { 190 if len(parts) > 1 {
181 if parts[1] == "" { 191 if parts[1] == "" &&
182 ck.addError( 192 ck.addError(
183 EName, 193 EName,
184 "Test %q must not have a nonempty description.", 194 code,
185 code.fullName()) 195 "Test %q must have a nonempty description.",
 196 code.fullName()) {
186 return 197 return
187 } 198 }
188 descr = parts[1] 199 descr = parts[1]
189 } 200 }
190 201
 202 code.order = ck.nextOrder()
191 ck.tests = append(ck.tests, &test{code, testeeName, descr, nil}) 203 ck.tests = append(ck.tests, &test{code, testeeName, descr, nil})
192} 204}
193 205
194func (ck *TestNameChecker) nextOrder() int { 206func (ck *TestNameChecker) nextOrder() int {
195 id := ck.order 207 id := ck.order
196 ck.order++ 208 ck.order++
197 return id 209 return id
198} 210}
199 211
200// relate connects the tests to their testees. 212// relate connects the tests to their testees.
201func (ck *TestNameChecker) relate() { 213func (ck *TestNameChecker) relate() {
202 testeesByPrefix := make(map[string]*testee) 214 testeesByPrefix := make(map[string]*testee)
203 for _, testee := range ck.testees { 215 for _, testee := range ck.testees {
204 prefix := join(testee.Type, "_", testee.Func) 216 prefix := join(testee.Type, "_", testee.Func)
205 testeesByPrefix[prefix] = testee 217 testeesByPrefix[prefix] = testee
206 } 218 }
207 219
208 for _, test := range ck.tests { 220 for _, test := range ck.tests {
209 test.testee = testeesByPrefix[test.testeeName] 221 test.testee = testeesByPrefix[test.testeeName]
210 } 222 }
211} 223}
212 224
213func (ck *TestNameChecker) checkTests() { 225func (ck *TestNameChecker) checkTests() {
214 for _, test := range ck.tests { 226 for _, test := range ck.tests {
215 ck.checkTestFile(test) 227 ck.checkTestFile(test)
216 ck.checkTestName(test) 
217 ck.checkTestTestee(test) 228 ck.checkTestTestee(test)
 229 ck.checkTestDescr(test)
218 } 230 }
219} 231}
220 232
221func (ck *TestNameChecker) checkTestFile(test *test) { 233func (ck *TestNameChecker) checkTestFile(test *test) {
222 testee := test.testee 234 testee := test.testee
223 if testee == nil || testee.file == test.file { 235 if testee == nil || testee.file == test.file {
224 return 236 return
225 } 237 }
226 238
227 correctTestFile := strings.TrimSuffix(testee.file, ".go") + "_test.go" 239 correctTestFile := strings.TrimSuffix(testee.file, ".go") + "_test.go"
228 if correctTestFile != test.file { 240 if correctTestFile == test.file {
229 ck.addError( 241 return
230 EFile, 
231 "Test %q for %q must be in %s instead of %s.", 
232 test.fullName(), testee.fullName(), correctTestFile, test.file) 
233 } 242 }
 243
 244 ck.addError(
 245 EFile,
 246 test.code,
 247 "Test %q for %q must be in %s instead of %s.",
 248 test.fullName(), testee.fullName(), correctTestFile, test.file)
234} 249}
235 250
236func (ck *TestNameChecker) checkTestTestee(test *test) { 251func (ck *TestNameChecker) checkTestTestee(test *test) {
237 testee := test.testee 252 testee := test.testee
238 if testee != nil || test.testeeName == "" { 253 if testee != nil || test.testeeName == "" {
239 return 254 return
240 } 255 }
241 256
242 testeeName := strings.Replace(test.testeeName, "_", ".", -1) 257 testeeName := strings.Replace(test.testeeName, "_", ".", -1)
243 ck.addError( 258 ck.addError(
244 EMissingTestee, 259 EMissingTestee,
 260 test.code,
245 "Missing testee %q for test %q.", 261 "Missing testee %q for test %q.",
246 testeeName, test.fullName()) 262 testeeName, test.fullName())
247} 263}
248 264
249// checkTestName ensures that the method name does not accidentally 265// checkTestDescr ensures that the type or function name of the testee
250// end up in the description of the test. This could happen if there is a 266// does not accidentally end up in the description of the test. This could
251// double underscore instead of a single underscore. 267// happen if there is a double underscore instead of a single underscore.
252func (ck *TestNameChecker) checkTestName(test *test) { 268func (ck *TestNameChecker) checkTestDescr(test *test) {
253 testee := test.testee 269 testee := test.testee
254 if testee == nil { 270 if testee == nil || testee.isMethod() || !isCamelCase(test.descr) {
255 return 
256 } 
257 if testee.Type != "" && testee.Func != "" { 
258 return 
259 } 
260 if !isCamelCase(test.descr) { 
261 return 271 return
262 } 272 }
263 273
264 ck.addError( 274 ck.addError(
265 EName, 275 EName,
 276 testee.code,
266 "%s: Test description %q must not use CamelCase in the first word.", 277 "%s: Test description %q must not use CamelCase in the first word.",
267 test.fullName(), test.descr) 278 test.fullName(), test.descr)
268} 279}
269 280
270func (ck *TestNameChecker) checkTestees() { 281func (ck *TestNameChecker) checkTestees() {
271 tested := make(map[*testee]bool) 282 tested := make(map[*testee]bool)
272 for _, test := range ck.tests { 283 for _, test := range ck.tests {
273 tested[test.testee] = true 284 tested[test.testee] = true
274 } 285 }
275 286
276 for _, testee := range ck.testees { 287 for _, testee := range ck.testees {
277 if tested[testee] || testee.Func == "" { 288 ck.checkTesteeTest(testee, tested)
278 continue 289 }
279 } 290}
280 291
281 testName := "Test_" + join(testee.Type, "_", testee.Func) 292func (ck *TestNameChecker) checkTesteeTest(testee *testee, tested map[*testee]bool) {
282 ck.addError( 293 if tested[testee] || testee.isType() {
283 EMissingTest, 294 return
284 "Missing unit test %q for %q.", 
285 testName, testee.fullName()) 
286 } 295 }
 296
 297 testName := "Test_" + join(testee.Type, "_", testee.Func)
 298 ck.addError(
 299 EMissingTest,
 300 testee.code,
 301 "Missing unit test %q for %q.",
 302 testName, testee.fullName())
287} 303}
288 304
289func (ck *TestNameChecker) isIgnored(filename string) bool { 305// isRelevant checks whether the given error is enabled.
290 for _, mask := range ck.ignoredFiles { 306func (ck *TestNameChecker) isRelevant(filename, typeName, funcName string, e Error) bool {
291 ok, err := filepath.Match(mask, filename) 307 mask := ^uint64(0)
292 if err != nil { 308 for _, filter := range ck.filters {
293 panic(err) 309 if matches(filename, filter.filenames) &&
 310 matches(typeName, filter.typeNames) &&
 311 matches(funcName, filter.funcNames) {
 312 mask = ck.errorsMask(mask, filter.errors...)
294 } 313 }
295 if ok { 314 }
296 return true 315 return mask&ck.errorsMask(0, e) != 0
 316}
 317
 318func (ck *TestNameChecker) errorsMask(mask uint64, errors ...Error) uint64 {
 319 for _, err := range errors {
 320 if err == ENone {
 321 mask = 0
 322 } else if err == EAll {
 323 mask = ^uint64(0)
 324 } else if err < 0 {
 325 mask &= ^(uint64(1) << -uint(err))
 326 } else {
 327 mask |= uint64(1) << uint(err)
297 } 328 }
298 } 329 }
299 return false 330 return mask
300} 331}
301 332
302// checkOrder ensures that the tests appear in the same order as their 333// checkOrder ensures that the tests appear in the same order as their
303// counterparts in the main code. 334// counterparts in the main code.
304func (ck *TestNameChecker) checkOrder() { 335func (ck *TestNameChecker) checkOrder() {
305 maxOrderByFile := make(map[string]*test) 336 maxOrderByFile := make(map[string]*test)
306 337
307 for _, test := range ck.tests { 338 for _, test := range ck.tests {
308 testee := test.testee 339 testee := test.testee
309 if testee == nil { 340 if testee == nil {
310 continue 341 continue
311 } 342 }
312 343
313 maxOrder := maxOrderByFile[testee.file] 344 maxOrder := maxOrderByFile[testee.file]
314 if maxOrder == nil || testee.order > maxOrder.testee.order { 345 if maxOrder == nil || testee.order > maxOrder.testee.order {
315 maxOrderByFile[testee.file] = test 346 maxOrderByFile[testee.file] = test
316 } 347 }
317 348
318 if maxOrder != nil && testee.order < maxOrder.testee.order { 349 if maxOrder != nil && testee.order < maxOrder.testee.order {
319 insertBefore := maxOrder 350 insertBefore := maxOrder
320 for _, before := range ck.tests { 351 for _, before := range ck.tests {
321 if before.file == test.file && before.testee != nil && before.testee.order > testee.order { 352 if before.file == test.file && before.testee != nil && before.testee.order > testee.order {
322 insertBefore = before 353 insertBefore = before
323 break 354 break
324 } 355 }
325 } 356 }
 357
326 ck.addError( 358 ck.addError(
327 EOrder, 359 EOrder,
328 "Test %q should be ordered before %q.", 360 test.code,
 361 "Test %q must be ordered before %q.",
329 test.fullName(), insertBefore.fullName()) 362 test.fullName(), insertBefore.fullName())
330 } 363 }
331 } 364 }
332} 365}
333 366
334func (ck *TestNameChecker) addError(e Error, format string, args ...interface{}) { 367func (ck *TestNameChecker) addError(e Error, c code, format string, args ...interface{}) bool {
335 if ck.errorsMask&(uint64(1)<<uint(e)) != 0 { 368 relevant := ck.isRelevant(c.file, c.Type, c.Func, e)
 369 if relevant {
336 ck.errors = append(ck.errors, fmt.Sprintf(format, args...)) 370 ck.errors = append(ck.errors, fmt.Sprintf(format, args...))
337 } 371 }
 372 return relevant
338} 373}
339 374
340func (ck *TestNameChecker) print() { 375func (ck *TestNameChecker) print() {
341 for _, msg := range ck.errors { 376 for _, msg := range ck.errors {
342 _, _ = fmt.Fprintln(ck.out, msg) 377 _, _ = fmt.Fprintln(ck.out, msg)
343 } 378 }
344 379
345 errors := plural(len(ck.errors), "error", "errors") 380 n := len(ck.errors)
346 if len(ck.errors) > 0 { 381 if n > 1 {
347 ck.errorf("%s.", errors) 382 ck.errorf("%d errors.", n)
 383 } else if n == 1 {
 384 ck.errorf("%d error.", n)
348 } 385 }
349} 386}
350 387
351type code struct { 388type filter struct {
352 file string // The file containing the code 389 filenames string
353 Type string // The type, e.g. MkLine 390 typeNames string
354 Func string // The function or method name, e.g. Warnf 391 funcNames string
355 order int // The relative order in the file 392 errors []Error
356} 393}
357 394
358func (c *code) fullName() string { return join(c.Type, ".", c.Func) } 
359 
360// testee is an element of the source code that can be tested. 395// testee is an element of the source code that can be tested.
361// It is either a type, a function or a method. 
362type testee struct { 396type testee struct {
363 code 397 code
364} 398}
365 399
366type test struct { 400type test struct {
367 code 401 code
368 402
369 testeeName string // The method name without the "Test_" prefix and description 403 testeeName string // The method name without the "Test_" prefix and description
370 descr string // The part after the "__" in the method name 404 descr string // The part after the "__" in the method name
371 testee *testee 405 testee *testee
372} 406}
373 407
374func plural(n int, sg, pl string) string { 408// code is either a type, a function or a method.
375 if n == 0 { 409type code struct {
376 return "" 410 file string // the file containing the code
377 } 411 Type string // the type, e.g. MkLine
378 form := pl 412 Func string // the function or method name, e.g. Warnf
379 if n == 1 { 413 order int // the relative order in the file
380 form = sg 414}
381 } 415
382 return fmt.Sprintf("%d %s", n, form) 416func (c *code) fullName() string { return join(c.Type, ".", c.Func) }
 417func (c *code) isFunc() bool { return c.Type == "" }
 418func (c *code) isType() bool { return c.Func == "" }
 419func (c *code) isMethod() bool { return c.Type != "" && c.Func != "" }
 420
 421func (c *code) isTest() bool {
 422 return c.isTestScope() && strings.HasPrefix(c.Func, "Test")
 423}
 424func (c *code) isTestScope() bool {
 425 return strings.HasSuffix(c.file, "_test.go")
383} 426}
384 427
385func isCamelCase(str string) bool { 428func isCamelCase(str string) bool {
386 for i := 0; i+1 < len(str); i++ { 429 for i := 0; i+1 < len(str); i++ {
387 if str[i] == '_' { 430 if str[i] == '_' {
388 return false 431 return false
389 } 432 }
390 if unicode.IsLower(rune(str[i])) && unicode.IsUpper(rune(str[i+1])) { 433 if unicode.IsLower(rune(str[i])) && unicode.IsUpper(rune(str[i+1])) {
391 return true 434 return true
392 } 435 }
393 } 436 }
394 return false 437 return false
395} 438}
396 439
397func join(a, sep, b string) string { 440func join(a, sep, b string) string {
398 if a == "" || b == "" { 441 if a == "" || b == "" {
399 sep = "" 442 sep = ""
400 } 443 }
401 return a + sep + b 444 return a + sep + b
402} 445}
 446
 447func matches(subj string, pattern string) bool {
 448 ok, err := path.Match(pattern, subj)
 449 if err != nil {
 450 panic(err)
 451 }
 452 return ok
 453}
 454
 455// sortedKeys returns the sorted keys from an arbitrary map.
 456func sortedKeys(m interface{}) []string {
 457 var keys []string
 458 for _, key := range reflect.ValueOf(m).MapKeys() {
 459 keys = append(keys, key.Interface().(string))
 460 }
 461 sort.Strings(keys)
 462 return keys
 463}

cvs diff -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames_test.go 2019/11/17 02:06:01 1.2
+++ pkgsrc/pkgtools/pkglint/files/intqa/Attic/testnames_test.go 2019/11/19 06:51:38 1.3
@@ -1,125 +1,310 @@ @@ -1,125 +1,310 @@
1package intqa 1package intqa
2 2
3import ( 3import (
4 "bytes" 4 "bytes"
5 "fmt" 5 "fmt"
 6 "go/ast"
6 "gopkg.in/check.v1" 7 "gopkg.in/check.v1"
7 "io/ioutil" 8 "io/ioutil"
 9 "path"
8 "testing" 10 "testing"
9) 11)
10 12
11type Suite struct { 13type Suite struct {
12 c *check.C 14 c *check.C
13 ck *TestNameChecker 15 ck *TestNameChecker
14 summary string 16 summary string
15} 17}
16 18
17func Test(t *testing.T) { 19func Test(t *testing.T) {
18 check.Suite(&Suite{}) 20 check.Suite(&Suite{})
19 check.TestingT(t) 21 check.TestingT(t)
20} 22}
21 23
22func (s *Suite) Init(c *check.C) *TestNameChecker { 24func (s *Suite) Init(c *check.C) *TestNameChecker {
23 errorf := func(format string, args ...interface{}) { 25 errorf := func(format string, args ...interface{}) {
24 s.summary = fmt.Sprintf(format, args...) 26 s.summary = fmt.Sprintf(format, args...)
25 } 27 }
26 28
27 s.c = c 29 s.c = c
28 s.ck = NewTestNameChecker(errorf) 30 s.ck = NewTestNameChecker(errorf)
29 s.ck.Enable(EAll) 
30 s.ck.out = ioutil.Discard 31 s.ck.out = ioutil.Discard
31 return s.ck 32 return s.ck
32} 33}
33 34
34func (s *Suite) TearDownTest(c *check.C) { 35func (s *Suite) TearDownTest(c *check.C) {
35 s.c = c 36 s.c = c
36 s.CheckErrors(nil...) 37 s.CheckErrors(nil...)
37 s.CheckSummary("") 38 s.CheckSummary("")
38} 39}
39 40
 41func (s *Suite) CheckTestees(testees ...*testee) {
 42 s.c.Check(s.ck.testees, check.DeepEquals, testees)
 43 s.ck.testees = nil
 44}
 45
 46func (*Suite) newTestee(filename, typeName, funcName string, order int) *testee {
 47 return &testee{code{filename, typeName, funcName, order}}
 48}
 49
 50func (s *Suite) CheckTests(tests ...*test) {
 51 s.c.Check(s.ck.tests, check.DeepEquals, tests)
 52 s.ck.tests = nil
 53}
 54
 55func (*Suite) newTest(filename, typeName, funcName string, order int, testeeName, descr string, testee *testee) *test {
 56 c := code{filename, typeName, funcName, order}
 57 return &test{c, testeeName, descr, testee}
 58}
 59
40func (s *Suite) CheckErrors(errors ...string) { 60func (s *Suite) CheckErrors(errors ...string) {
41 s.c.Check(s.ck.errors, check.DeepEquals, errors) 61 s.c.Check(s.ck.errors, check.DeepEquals, errors)
42 s.ck.errors = nil 62 s.ck.errors = nil
43} 63}
44 64
45func (s *Suite) CheckSummary(summary string) { 65func (s *Suite) CheckSummary(summary string) {
46 s.c.Check(s.summary, check.Equals, summary) 66 s.c.Check(s.summary, check.Equals, summary)
47 s.summary = "" 67 s.summary = ""
48} 68}
49 69
50func (s *Suite) Test_TestNameChecker_Enable(c *check.C) { 70func (s *Suite) Test_NewTestNameChecker(c *check.C) {
 71 ck := s.Init(c)
 72
 73 c.Check(ck.isRelevant("*_test.go", "Suite", "SetUpTest", EAll), check.Equals, true)
 74 c.Check(ck.isRelevant("*_test.go", "Suite", "SetUpTest", EMissingTest), check.Equals, false)
 75
 76 c.Check(ck.isRelevant("*_test.go", "Suite", "TearDownTest", EAll), check.Equals, true)
 77 c.Check(ck.isRelevant("*_test.go", "Suite", "TearDownTest", EMissingTest), check.Equals, false)
 78}
 79
 80func (s *Suite) Test_TestNameChecker_Configure(c *check.C) {
51 ck := s.Init(c) 81 ck := s.Init(c)
52 82
53 ck.Enable(ENone) // overwrite initialization from Suite.Init 83 ck.Configure("*", "*", "*", ENone) // overwrite initialization from Suite.Init
 84
 85 c.Check(ck.isRelevant("", "", "", EAll), check.Equals, false)
 86 c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
 87 c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, false)
 88
 89 ck.Configure("*", "*", "*", EAll)
54 90
55 c.Check(ck.errorsMask, check.Equals, uint64(0)) 91 c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
 92 c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, true)
 93 c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
56 94
57 ck.Enable(EAll) 95 ck.Configure("*", "*", "*", -EMissingTestee)
58 96
59 c.Check(ck.errorsMask, check.Equals, ^uint64(0)) 97 c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
 98 c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
 99 c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
 100
 101 ck.Configure("*", "*", "*", ENone, EMissingTest)
 102
 103 c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
 104 c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
 105 c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
 106
 107 ck.Configure("*", "*", "*", EAll, -EMissingTest)
 108
 109 c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
 110 c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, true)
 111 c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, false)
 112}
60 113
61 ck.Enable(ENone, EMissingTest) 114func (s *Suite) Test_TestNameChecker_Configure__ignore_single_function(c *check.C) {
 115 ck := s.Init(c)
62 116
63 c.Check(ck.errorsMask, check.Equals, uint64(4)) 117 ck.Configure("*", "*", "*", EAll)
64 118
65 ck.Enable(EAll, -EMissingTest) 119 // The intention of this rule is that this particular function is ignored.
 120 // Everything else from that file is still processed.
 121 ck.Configure("*_test.go", "", "TestMain", ENone)
66 122
67 c.Check(ck.errorsMask, check.Equals, ^uint64(0)^4) 123 c.Check(ck.isRelevant("file_test.go", "", "", EAll), check.Equals, true)
 124 c.Check(ck.isRelevant("file_test.go", "*", "*", EAll), check.Equals, true)
 125 c.Check(ck.isRelevant("file_test.go", "*", "Other", EAll), check.Equals, true)
 126 c.Check(ck.isRelevant("file_test.go", "", "TestMain", EAll), check.Equals, false)
 127 c.Check(ck.isRelevant("file_test.go", "*", "TestMain", EAll), check.Equals, true)
68} 128}
69 129
70func (s *Suite) Test_TestNameChecker_Check(c *check.C) { 130func (s *Suite) Test_TestNameChecker_Check(c *check.C) {
71 ck := s.Init(c) 131 ck := s.Init(c)
72 132
 133 ck.Configure("*", "Suite", "*", -EMissingTest)
 134
73 ck.Check() 135 ck.Check()
74 136
75 s.CheckErrors( 137 s.CheckErrors(
76 "Missing unit test \"Test_NewTestNameChecker\" for \"NewTestNameChecker\".", 
77 "Missing unit test \"Test_TestNameChecker_IgnoreFiles\" for \"TestNameChecker.IgnoreFiles\".", 
78 "Missing unit test \"Test_TestNameChecker_load\" for \"TestNameChecker.load\".", 
79 "Missing unit test \"Test_TestNameChecker_loadDecl\" for \"TestNameChecker.loadDecl\".", 
80 "Missing unit test \"Test_TestNameChecker_addCode\" for \"TestNameChecker.addCode\".", 138 "Missing unit test \"Test_TestNameChecker_addCode\" for \"TestNameChecker.addCode\".",
81 "Missing unit test \"Test_TestNameChecker_addTestee\" for \"TestNameChecker.addTestee\".", 
82 "Missing unit test \"Test_TestNameChecker_nextOrder\" for \"TestNameChecker.nextOrder\".", 
83 "Missing unit test \"Test_TestNameChecker_relate\" for \"TestNameChecker.relate\".", 139 "Missing unit test \"Test_TestNameChecker_relate\" for \"TestNameChecker.relate\".",
84 "Missing unit test \"Test_TestNameChecker_checkTests\" for \"TestNameChecker.checkTests\".", 140 "Missing unit test \"Test_TestNameChecker_isRelevant\" for \"TestNameChecker.isRelevant\".")
85 "Missing unit test \"Test_TestNameChecker_checkTestees\" for \"TestNameChecker.checkTestees\".", 141 s.CheckSummary("3 errors.")
86 "Missing unit test \"Test_TestNameChecker_isIgnored\" for \"TestNameChecker.isIgnored\".", 142}
87 "Missing unit test \"Test_TestNameChecker_addError\" for \"TestNameChecker.addError\".", 143
88 "Missing unit test \"Test_Test\" for \"Test\".", 144func (s *Suite) Test_TestNameChecker_load__filtered_nothing(c *check.C) {
89 "Missing unit test \"Test_Suite_Init\" for \"Suite.Init\".", 145 ck := s.Init(c)
90 "Missing unit test \"Test_Suite_TearDownTest\" for \"Suite.TearDownTest\".", 146
91 "Missing unit test \"Test_Suite_CheckErrors\" for \"Suite.CheckErrors\".", 147 ck.Configure("*", "*", "*", ENone)
92 "Missing unit test \"Test_Suite_CheckSummary\" for \"Suite.CheckSummary\".", 148
93 "Missing unit test \"Test_Value_Method\" for \"Value.Method\".") 149 ck.load(".")
94 s.CheckSummary("18 errors.") 150
 151 c.Check(ck.testees, check.IsNil)
 152 c.Check(ck.tests, check.IsNil)
 153}
 154
 155func (s *Suite) Test_TestNameChecker_load__filtered_only_Value(c *check.C) {
 156 ck := s.Init(c)
 157
 158 ck.Configure("*", "*", "*", ENone)
 159 ck.Configure("*", "Value", "*", EAll)
 160
 161 ck.load(".")
 162
 163 c.Check(ck.testees, check.DeepEquals, []*testee{
 164 {code{"testnames_test.go", "Value", "", 0}},
 165 {code{"testnames_test.go", "Value", "Method", 1}}})
 166 c.Check(ck.tests, check.IsNil)
 167}
 168
 169func (s *Suite) Test_TestNameChecker_load__panic(c *check.C) {
 170 ck := s.Init(c)
 171
 172 c.Check(
 173 func() { ck.load("does-not-exist") },
 174 check.PanicMatches,
 175 `^open does-not-exist\b.*`)
 176}
 177
 178func (s *Suite) Test_TestNameChecker_loadDecl(c *check.C) {
 179 ck := s.Init(c)
 180
 181 typeDecl := func(name string) *ast.GenDecl {
 182 return &ast.GenDecl{Specs: []ast.Spec{&ast.TypeSpec{Name: &ast.Ident{Name: name}}}}
 183 }
 184 funcDecl := func(name string) *ast.FuncDecl {
 185 return &ast.FuncDecl{Name: &ast.Ident{Name: name}}
 186 }
 187 methodDecl := func(typeName, methodName string) *ast.FuncDecl {
 188 return &ast.FuncDecl{
 189 Name: &ast.Ident{Name: methodName},
 190 Recv: &ast.FieldList{List: []*ast.Field{{Type: &ast.Ident{Name: typeName}}}}}
 191 }
 192
 193 ck.loadDecl(typeDecl("TypeName"), "file_test.go")
 194
 195 s.CheckTestees(
 196 s.newTestee("file_test.go", "TypeName", "", 0))
 197
 198 // The freestanding TestMain function is ignored by a hardcoded rule,
 199 // independently of the configuration.
 200 ck.loadDecl(funcDecl("TestMain"), "file_test.go")
 201
 202 // The TestMain method on a type is relevant, but violates the naming rule.
 203 // Therefore it is ignored.
 204 ck.loadDecl(methodDecl("Suite", "TestMain"), "file_test.go")
 205
 206 s.CheckTests(
 207 nil...)
 208 s.CheckErrors(
 209 "Test \"Suite.TestMain\" must start with \"Test_\".")
 210
 211 // The above error can be disabled, and then the method is handled
 212 // like any other test method.
 213 ck.Configure("*", "Suite", "*", -EName)
 214 ck.loadDecl(methodDecl("Suite", "TestMain"), "file_test.go")
 215
 216 s.CheckTests(
 217 s.newTest("file_test.go", "Suite", "TestMain", 1, "Main", "", nil))
 218
 219 // There is no special handling for TestMain method with a description.
 220 ck.loadDecl(methodDecl("Suite", "TestMain__descr"), "file_test.go")
 221
 222 s.CheckTests(
 223 s.newTest("file_test.go", "Suite", "TestMain__descr", 2, "Main", "descr", nil))
 224}
 225
 226func (s *Suite) Test_TestNameChecker_addTestee(c *check.C) {
 227 ck := s.Init(c)
 228
 229 code := code{"filename.go", "Type", "Method", 0}
 230 ck.addTestee(code)
 231
 232 c.Check(ck.testees, check.DeepEquals, []*testee{{code}})
95} 233}
96 234
97func (s *Suite) Test_TestNameChecker_addTest(c *check.C) { 235func (s *Suite) Test_TestNameChecker_addTest(c *check.C) {
98 ck := s.Init(c) 236 ck := s.Init(c)
99 237
100 ck.addTest(code{"filename.go", "Type", "Method", 0}) 238 ck.addTest(code{"filename.go", "Type", "Method", 0})
101 239
 240 c.Check(ck.tests, check.IsNil)
102 s.CheckErrors( 241 s.CheckErrors(
103 "Test \"Type.Method\" must start with \"Test_\".") 242 "Test \"Type.Method\" must start with \"Test_\".")
104} 243}
105 244
106func (s *Suite) Test_TestNameChecker_addTest__empty_description(c *check.C) { 245func (s *Suite) Test_TestNameChecker_addTest__empty_description(c *check.C) {
107 ck := s.Init(c) 246 ck := s.Init(c)
108 247
109 ck.addTest(code{"filename.go", "Suite", "Test_Method__", 0}) 248 ck.addTest(code{"f_test.go", "Suite", "Test_Method__", 0})
 249
 250 s.CheckErrors(
 251 "Test \"Suite.Test_Method__\" must have a nonempty description.")
 252
 253 // The test is not registered and thus cannot complain about its missing
 254 // testee.
 255 ck.checkTests()
 256
 257 s.CheckErrors(
 258 nil...)
 259}
 260
 261func (s *Suite) Test_TestNameChecker_addTest__suppressed_empty_description(c *check.C) {
 262 ck := s.Init(c)
 263
 264 ck.Configure("*", "*", "*", -EName)
 265 ck.addTest(code{"f_test.go", "Suite", "Test_Method__", 0})
 266
 267 s.CheckErrors(
 268 nil...)
 269
 270 // Since there was no error above, the test is added normally
 271 // and can complain about its missing testee.
 272 ck.checkTests()
 273
 274 s.CheckErrors(
 275 "Missing testee \"Method\" for test \"Suite.Test_Method__\".")
 276}
 277
 278func (s *Suite) Test_TestNameChecker_nextOrder(c *check.C) {
 279 ck := s.Init(c)
 280
 281 c.Check(ck.nextOrder(), check.Equals, 0)
 282 c.Check(ck.nextOrder(), check.Equals, 1)
 283 c.Check(ck.nextOrder(), check.Equals, 2)
 284}
 285
 286func (s *Suite) Test_TestNameChecker_checkTests(c *check.C) {
 287 ck := s.Init(c)
 288
 289 ck.tests = append(ck.tests,
 290 s.newTest("wrong_test.go", "", "Test_Func", 0, "Func", "",
 291 s.newTestee("source.go", "", "Func", 1)))
 292
 293 ck.checkTests()
110 294
111 s.CheckErrors( 295 s.CheckErrors(
112 "Test \"Suite.Test_Method__\" must not have a nonempty description.") 296 "Test \"Test_Func\" for \"Func\" " +
 297 "must be in source_test.go instead of wrong_test.go.")
113} 298}
114 299
115func (s *Suite) Test_TestNameChecker_checkTestFile__global(c *check.C) { 300func (s *Suite) Test_TestNameChecker_checkTestFile__global(c *check.C) {
116 ck := s.Init(c) 301 ck := s.Init(c)
117 302
118 ck.checkTestFile(&test{ 303 ck.checkTestFile(&test{
119 code{"demo_test.go", "Suite", "Test__Global", 0}, 304 code{"demo_test.go", "Suite", "Test__Global", 0},
120 "", 305 "",
121 "", 306 "",
122 &testee{code{"other.go", "", "Global", 0}}}) 307 &testee{code{"other.go", "", "Global", 0}}})
123 308
124 s.CheckErrors( 309 s.CheckErrors(
125 "Test \"Suite.Test__Global\" for \"Global\" " + 310 "Test \"Suite.Test__Global\" for \"Global\" " +
@@ -155,126 +340,289 @@ func (s *Suite) Test_TestNameChecker_che @@ -155,126 +340,289 @@ func (s *Suite) Test_TestNameChecker_che
155func (s *Suite) Test_TestNameChecker_checkTestTestee__testee_exists(c *check.C) { 340func (s *Suite) Test_TestNameChecker_checkTestTestee__testee_exists(c *check.C) {
156 ck := s.Init(c) 341 ck := s.Init(c)
157 342
158 ck.checkTestTestee(&test{ 343 ck.checkTestTestee(&test{
159 code{"demo_test.go", "Suite", "Test_Missing", 0}, 344 code{"demo_test.go", "Suite", "Test_Missing", 0},
160 "Missing", 345 "Missing",
161 "", 346 "",
162 &testee{}}) 347 &testee{}})
163 348
164 s.CheckErrors( 349 s.CheckErrors(
165 nil...) 350 nil...)
166} 351}
167 352
168func (s *Suite) Test_TestNameChecker_checkTestName__camel_case(c *check.C) { 353func (s *Suite) Test_TestNameChecker_checkTestDescr__camel_case(c *check.C) {
169 ck := s.Init(c) 354 ck := s.Init(c)
170 355
171 ck.checkTestName(&test{ 356 ck.checkTestDescr(&test{
172 code{"demo_test.go", "Suite", "Test_Missing__CamelCase", 0}, 357 code{"demo_test.go", "Suite", "Test_Missing__CamelCase", 0},
173 "Missing", 358 "Missing",
174 "CamelCase", 359 "CamelCase",
175 &testee{}}) 360 &testee{}})
176 361
177 s.CheckErrors( 362 s.CheckErrors(
178 "Suite.Test_Missing__CamelCase: Test description \"CamelCase\" " + 363 "Suite.Test_Missing__CamelCase: Test description \"CamelCase\" " +
179 "must not use CamelCase in the first word.") 364 "must not use CamelCase in the first word.")
180} 365}
181 366
 367func (s *Suite) Test_TestNameChecker_checkTestees(c *check.C) {
 368 ck := s.Init(c)
 369
 370 ck.testees = []*testee{s.newTestee("s.go", "", "Func", 0)}
 371 ck.tests = nil // force an error
 372
 373 ck.checkTestees()
 374
 375 s.CheckErrors(
 376 "Missing unit test \"Test_Func\" for \"Func\".")
 377}
 378
 379func (s *Suite) Test_TestNameChecker_checkTesteeTest(c *check.C) {
 380 ck := s.Init(c)
 381
 382 ck.checkTesteeTest(
 383 &testee{code{"demo.go", "Type", "", 0}},
 384 nil)
 385 ck.checkTesteeTest(
 386 &testee{code{"demo.go", "", "Func", 0}},
 387 nil)
 388 ck.checkTesteeTest(
 389 &testee{code{"demo.go", "Type", "Method", 0}},
 390 nil)
 391
 392 s.CheckErrors(
 393 "Missing unit test \"Test_Func\" for \"Func\".",
 394 "Missing unit test \"Test_Type_Method\" for \"Type.Method\".")
 395}
 396
 397func (s *Suite) Test_TestNameChecker_errorsMask(c *check.C) {
 398 ck := s.Init(c)
 399
 400 c.Check(ck.errorsMask(0, EAll), check.Equals, ^uint64(0))
 401 c.Check(ck.errorsMask(12345, ENone), check.Equals, uint64(0))
 402 c.Check(ck.errorsMask(12345, ENone, EMissingTest), check.Equals, uint64(8))
 403 c.Check(ck.errorsMask(2, EMissingTest), check.Equals, uint64(10))
 404}
 405
182func (s *Suite) Test_TestNameChecker_checkOrder(c *check.C) { 406func (s *Suite) Test_TestNameChecker_checkOrder(c *check.C) {
183 ck := s.Init(c) 407 ck := s.Init(c)
184 408
185 ck.addTestee(code{"f.go", "T", "", 10}) 409 ck.addTestee(code{"f.go", "T", "", 10})
186 ck.addTestee(code{"f.go", "T", "M1", 11}) 410 ck.addTestee(code{"f.go", "T", "M1", 11})
187 ck.addTestee(code{"f.go", "T", "M2", 12}) 411 ck.addTestee(code{"f.go", "T", "M2", 12})
188 ck.addTestee(code{"f.go", "T", "M3", 13}) 412 ck.addTestee(code{"f.go", "T", "M3", 13})
 413 ck.addTest(code{"a_test.go", "S", "Test_A", 98}) // different file, is skipped
 414 ck.addTest(code{"f_test.go", "S", "Test_Missing", 99}) // missing testee, is skipped
189 ck.addTest(code{"f_test.go", "S", "Test_T_M1", 100}) // maxTestee = 11 415 ck.addTest(code{"f_test.go", "S", "Test_T_M1", 100}) // maxTestee = 11
190 ck.addTest(code{"f_test.go", "S", "Test_T_M2", 101}) // maxTestee = 12 416 ck.addTest(code{"f_test.go", "S", "Test_T_M2", 101}) // maxTestee = 12
191 ck.addTest(code{"f_test.go", "S", "Test_T", 102}) // testee 10 < maxTestee 12: insert before first [.testee > testee 10] == T_M1 417 ck.addTest(code{"f_test.go", "S", "Test_T", 102}) // testee 10 < maxTestee 12: insert before first [.testee > testee 10] == T_M1
192 ck.addTest(code{"f_test.go", "S", "Test_T_M3", 103}) // maxTestee = 13 418 ck.addTest(code{"f_test.go", "S", "Test_T_M3", 103}) // maxTestee = 13
193 ck.addTest(code{"f_test.go", "S", "Test_T__1", 104}) // testee < maxTestee: insert before first [testee > 10] 419 ck.addTest(code{"f_test.go", "S", "Test_T__1", 104}) // testee < maxTestee: insert before first [testee > 10]
194 ck.addTest(code{"f_test.go", "S", "Test_T__2", 105}) // testee < maxTestee: insert before first [testee > 10] 420 ck.addTest(code{"f_test.go", "S", "Test_T__2", 105}) // testee < maxTestee: insert before first [testee > 10]
195 ck.addTest(code{"f_test.go", "S", "Test_T_M2__1", 106}) // testee < maxTestee: insert before first [testee > 12] == T_M3 421 ck.addTest(code{"f_test.go", "S", "Test_T_M2__1", 106}) // testee < maxTestee: insert before first [testee > 12] == T_M3
196 ck.relate() 422 ck.relate()
197 423
198 ck.checkOrder() 424 ck.checkOrder()
199 425
200 s.CheckErrors( 426 s.CheckErrors(
201 "Test \"S.Test_T\" should be ordered before \"S.Test_T_M1\".", 427 "Test \"S.Test_T\" must be ordered before \"S.Test_T_M1\".",
202 "Test \"S.Test_T__1\" should be ordered before \"S.Test_T_M1\".", 428 "Test \"S.Test_T__1\" must be ordered before \"S.Test_T_M1\".",
203 "Test \"S.Test_T__2\" should be ordered before \"S.Test_T_M1\".", 429 "Test \"S.Test_T__2\" must be ordered before \"S.Test_T_M1\".",
204 "Test \"S.Test_T_M2__1\" should be ordered before \"S.Test_T_M3\".") 430 "Test \"S.Test_T_M2__1\" must be ordered before \"S.Test_T_M3\".")
 431}
 432
 433func (s *Suite) Test_TestNameChecker_addError(c *check.C) {
 434 ck := s.Init(c)
 435
 436 ck.Configure("ignored*", "*", "*", -EName)
 437 ok1 := ck.addError(EName, code{"ignored.go", "", "Func", 0}, "E1")
 438 ok2 := ck.addError(EName, code{"reported.go", "", "Func", 0}, "E2")
 439
 440 c.Check(ok1, check.Equals, false)
 441 c.Check(ok2, check.Equals, true)
 442 s.CheckErrors(
 443 "E2")
205} 444}
206 445
207func (s *Suite) Test_TestNameChecker_print__empty(c *check.C) { 446func (s *Suite) Test_TestNameChecker_print__empty(c *check.C) {
208 var out bytes.Buffer 447 var out bytes.Buffer
209 ck := s.Init(c) 448 ck := s.Init(c)
210 ck.out = &out 449 ck.out = &out
211 450
212 ck.print() 451 ck.print()
213 452
214 c.Check(out.String(), check.Equals, "") 453 c.Check(out.String(), check.Equals, "")
215} 454}
216 455
217func (s *Suite) Test_TestNameChecker_print__errors(c *check.C) { 456func (s *Suite) Test_TestNameChecker_print__1_error(c *check.C) {
218 var out bytes.Buffer 457 var out bytes.Buffer
219 ck := s.Init(c) 458 ck := s.Init(c)
220 ck.out = &out 459 ck.out = &out
 460 ck.addError(EName, code{}, "1")
221 461
222 ck.addError(EName, "1") 
223 ck.print() 462 ck.print()
224 463
225 c.Check(out.String(), check.Equals, "1\n") 464 c.Check(out.String(), check.Equals, "1\n")
226 s.CheckErrors("1") 465 s.CheckErrors("1")
227 s.CheckSummary("1 error.") 466 s.CheckSummary("1 error.")
228} 467}
229 468
 469func (s *Suite) Test_TestNameChecker_print__2_errors(c *check.C) {
 470 var out bytes.Buffer
 471 ck := s.Init(c)
 472 ck.out = &out
 473 ck.addError(EName, code{}, "1")
 474 ck.addError(EName, code{}, "2")
 475
 476 ck.print()
 477
 478 c.Check(out.String(), check.Equals, "1\n2\n")
 479 s.CheckErrors("1", "2")
 480 s.CheckSummary("2 errors.")
 481}
 482
230func (s *Suite) Test_code_fullName(c *check.C) { 483func (s *Suite) Test_code_fullName(c *check.C) {
231 _ = s.Init(c) 484 _ = s.Init(c)
232 485
233 test := func(typeName, funcName, fullName string) { 486 test := func(typeName, funcName, fullName string) {
234 code := code{"filename", typeName, funcName, 0} 487 code := code{"filename", typeName, funcName, 0}
235 c.Check(code.fullName(), check.Equals, fullName) 488 c.Check(code.fullName(), check.Equals, fullName)
236 } 489 }
237 490
238 test("Type", "", "Type") 491 test("Type", "", "Type")
239 test("", "Func", "Func") 492 test("", "Func", "Func")
240 test("Type", "Method", "Type.Method") 493 test("Type", "Method", "Type.Method")
241} 494}
242 495
243func (s *Suite) Test_plural(c *check.C) { 496func (s *Suite) Test_code_isFunc(c *check.C) {
244 _ = s.Init(c) 497 _ = s.Init(c)
245 498
246 c.Check(plural(0, "singular", "plural"), check.Equals, "") 499 test := func(typeName, funcName string, isFunc bool) {
247 c.Check(plural(1, "singular", "plural"), check.Equals, "1 singular") 500 code := code{"filename", typeName, funcName, 0}
248 c.Check(plural(2, "singular", "plural"), check.Equals, "2 plural") 501 c.Check(code.isFunc(), check.Equals, isFunc)
249 c.Check(plural(1000, "singular", "plural"), check.Equals, "1000 plural") 502 }
 503
 504 test("Type", "", false)
 505 test("", "Func", true)
 506 test("Type", "Method", false)
 507}
 508
 509func (s *Suite) Test_code_isType(c *check.C) {
 510 _ = s.Init(c)
 511
 512 test := func(typeName, funcName string, isType bool) {
 513 code := code{"filename", typeName, funcName, 0}
 514 c.Check(code.isType(), check.Equals, isType)
 515 }
 516
 517 test("Type", "", true)
 518 test("", "Func", false)
 519 test("Type", "Method", false)
 520}
 521
 522func (s *Suite) Test_code_isMethod(c *check.C) {
 523 _ = s.Init(c)
 524
 525 test := func(typeName, funcName string, isMethod bool) {
 526 code := code{"filename", typeName, funcName, 0}
 527 c.Check(code.isMethod(), check.Equals, isMethod)
 528 }
 529
 530 test("Type", "", false)
 531 test("", "Func", false)
 532 test("Type", "Method", true)
 533}
 534
 535func (s *Suite) Test_code_isTest(c *check.C) {
 536 _ = s.Init(c)
 537
 538 test := func(filename, typeName, funcName string, isTest bool) {
 539 code := code{filename, typeName, funcName, 0}
 540 c.Check(code.isTest(), check.Equals, isTest)
 541 }
 542
 543 test("f.go", "Type", "", false)
 544 test("f.go", "", "Func", false)
 545 test("f.go", "Type", "Method", false)
 546 test("f.go", "Type", "Test", false)
 547 test("f.go", "Type", "Test_Type_Method", false)
 548 test("f.go", "", "Test_Type_Method", false)
 549 test("f_test.go", "Type", "Test", true)
 550 test("f_test.go", "Type", "Test_Type_Method", true)
 551 test("f_test.go", "", "Test_Type_Method", true)
 552}
 553
 554func (s *Suite) Test_code_isTestScope(c *check.C) {
 555 _ = s.Init(c)
 556
 557 test := func(filename string, isTestScope bool) {
 558 code := code{filename, "", "", 0}
 559 c.Check(code.isTestScope(), check.Equals, isTestScope)
 560 }
 561
 562 test("f.go", false)
 563 test("test.go", false)
 564 test("_test.go", true)
 565 test("file_test.go", true)
 566 test("file_linux_test.go", true)
250} 567}
251 568
252func (s *Suite) Test_isCamelCase(c *check.C) { 569func (s *Suite) Test_isCamelCase(c *check.C) {
253 _ = s.Init(c) 570 _ = s.Init(c)
254 571
255 c.Check(isCamelCase(""), check.Equals, false) 572 c.Check(isCamelCase(""), check.Equals, false)
256 c.Check(isCamelCase("Word"), check.Equals, false) 573 c.Check(isCamelCase("Word"), check.Equals, false)
257 c.Check(isCamelCase("Ada_Case"), check.Equals, false) 574 c.Check(isCamelCase("Ada_Case"), check.Equals, false)
258 c.Check(isCamelCase("snake_case"), check.Equals, false) 575 c.Check(isCamelCase("snake_case"), check.Equals, false)
259 c.Check(isCamelCase("CamelCase"), check.Equals, true) 576 c.Check(isCamelCase("CamelCase"), check.Equals, true)
260 577
261 // After the first underscore of the description, any CamelCase 578 // After the first underscore of the description, any CamelCase
262 // is ignored because there is no danger of confusing the method 579 // is ignored because there is no danger of confusing the method
263 // name with the description. 580 // name with the description.
264 c.Check(isCamelCase("Word_CamelCase"), check.Equals, false) 581 c.Check(isCamelCase("Word_CamelCase"), check.Equals, false)
265} 582}
266 583
267func (s *Suite) Test_join(c *check.C) { 584func (s *Suite) Test_join(c *check.C) {
268 _ = s.Init(c) 585 _ = s.Init(c)
269 586
270 c.Check(join("", " and ", ""), check.Equals, "") 587 c.Check(join("", " and ", ""), check.Equals, "")
271 c.Check(join("one", " and ", ""), check.Equals, "one") 588 c.Check(join("one", " and ", ""), check.Equals, "one")
272 c.Check(join("", " and ", "two"), check.Equals, "two") 589 c.Check(join("", " and ", "two"), check.Equals, "two")
273 c.Check(join("one", " and ", "two"), check.Equals, "one and two") 590 c.Check(join("one", " and ", "two"), check.Equals, "one and two")
274} 591}
275 592
 593func (s *Suite) Test_matches(c *check.C) {
 594 _ = s.Init(c)
 595
 596 c.Check(matches("*", "*"), check.Equals, true)
 597 c.Check(matches("anything", "*"), check.Equals, true)
 598 c.Check(matches("*", "anything"), check.Equals, false)
 599 c.Check(func() { matches("any", "[") }, check.Panics, path.ErrBadPattern)
 600}
 601
 602func (s *Suite) Test_sortedKeys(c *check.C) {
 603 _ = s.Init(c)
 604
 605 m := make(map[string]uint8)
 606 m["first"] = 1
 607 m["second"] = 2
 608 m["third"] = 3
 609 m["fourth"] = 4
 610
 611 c.Check(
 612 sortedKeys(m),
 613 check.DeepEquals,
 614 []string{"first", "fourth", "second", "third"})
 615}
 616
 617func (s *Suite) Test_Value_Method(c *check.C) {
 618 _ = s.Init(c)
 619
 620 // Just for code coverage of checkTestFile, to have a piece of code
 621 // that lives in the same file as its test.
 622}
 623
276type Value struct{} 624type Value struct{}
277 625
278// Method has no star on the receiver, 626// Method has no star on the receiver,
279// for code coverage of TestNameChecker.loadDecl. 627// for code coverage of TestNameChecker.loadDecl.
280func (Value) Method() {} 628func (Value) Method() {}

cvs diff -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/licenses/Attic/licenses_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/licenses/Attic/licenses_test.go 2019/11/17 01:26:26 1.6
+++ pkgsrc/pkgtools/pkglint/files/licenses/Attic/licenses_test.go 2019/11/19 06:51:38 1.7
@@ -123,16 +123,16 @@ func NewOr(parts ...*Condition) *Conditi @@ -123,16 +123,16 @@ func NewOr(parts ...*Condition) *Conditi
123 123
124func toJSON(cond *Condition) string { 124func toJSON(cond *Condition) string {
125 jsonStr, _ := json.Marshal(cond) 125 jsonStr, _ := json.Marshal(cond)
126 return strings.Replace(string(jsonStr), "\"", "", -1) 126 return strings.Replace(string(jsonStr), "\"", "", -1)
127} 127}
128 128
129func Test(t *testing.T) { 129func Test(t *testing.T) {
130 check.Suite(new(Suite)) 130 check.Suite(new(Suite))
131 check.TestingT(t) 131 check.TestingT(t)
132} 132}
133 133
134func (s *Suite) Test__test_names(c *check.C) { 134func (s *Suite) Test__test_names(c *check.C) {
135 ck := intqa.NewTestNameChecker(c.Errorf) 135 ck := intqa.NewTestNameChecker(c.Errorf)
136 ck.Enable(intqa.EAll, -intqa.EMissingTest) 136 ck.Configure("*", "*", "*", -intqa.EMissingTest)
137 ck.Check() 137 ck.Check()
138} 138}

cvs diff -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/pkgver/Attic/vercmp_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/pkgver/Attic/vercmp_test.go 2019/11/17 01:26:26 1.6
+++ pkgsrc/pkgtools/pkglint/files/pkgver/Attic/vercmp_test.go 2019/11/19 06:51:38 1.7
@@ -85,16 +85,16 @@ func (s *Suite) Test_newVersion(c *check @@ -85,16 +85,16 @@ func (s *Suite) Test_newVersion(c *check
85 &version{nil, 1}) 85 &version{nil, 1})
86 c.Check(newVersion("1.0.1a"), check.DeepEquals, 86 c.Check(newVersion("1.0.1a"), check.DeepEquals,
87 &version{[]int{1, 0, 0, 0, 1, 1}, 0}) 87 &version{[]int{1, 0, 0, 0, 1, 1}, 0})
88 c.Check(newVersion("1.0.1z"), check.DeepEquals, 88 c.Check(newVersion("1.0.1z"), check.DeepEquals,
89 &version{[]int{1, 0, 0, 0, 1, 26}, 0}) 89 &version{[]int{1, 0, 0, 0, 1, 26}, 0})
90 c.Check(newVersion("0pre20160620"), check.DeepEquals, 90 c.Check(newVersion("0pre20160620"), check.DeepEquals,
91 &version{[]int{0, -1, 20160620}, 0}) 91 &version{[]int{0, -1, 20160620}, 0})
92 c.Check(newVersion("3.5.DEV1710"), check.DeepEquals, 92 c.Check(newVersion("3.5.DEV1710"), check.DeepEquals,
93 &version{[]int{3, 0, 5, 0, 4, 5, 22, 1710}, 0}) 93 &version{[]int{3, 0, 5, 0, 4, 5, 22, 1710}, 0})
94} 94}
95 95
96func (s *Suite) Test__test_names(c *check.C) { 96func (s *Suite) Test__test_names(c *check.C) {
97 ck := intqa.NewTestNameChecker(c.Errorf) 97 ck := intqa.NewTestNameChecker(c.Errorf)
98 ck.Enable(intqa.EAll, -intqa.EMissingTest) 98 ck.Configure("*", "*", "*", -intqa.EMissingTest)
99 ck.Check() 99 ck.Check()
100} 100}

cvs diff -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/textproc/Attic/lexer_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/textproc/Attic/lexer_test.go 2019/11/17 01:26:26 1.7
+++ pkgsrc/pkgtools/pkglint/files/textproc/Attic/lexer_test.go 2019/11/19 06:51:39 1.8
@@ -405,16 +405,16 @@ func (s *Suite) Test__Alpha(c *check.C)  @@ -405,16 +405,16 @@ func (s *Suite) Test__Alpha(c *check.C)
405 set := Alpha 405 set := Alpha
406 406
407 c.Check(set.Contains(0x00), equals, false) 407 c.Check(set.Contains(0x00), equals, false)
408 c.Check(set.Contains('@'), equals, false) 408 c.Check(set.Contains('@'), equals, false)
409 c.Check(set.Contains('A'), equals, true) 409 c.Check(set.Contains('A'), equals, true)
410 c.Check(set.Contains('Z'), equals, true) 410 c.Check(set.Contains('Z'), equals, true)
411 c.Check(set.Contains('`'), equals, false) 411 c.Check(set.Contains('`'), equals, false)
412 c.Check(set.Contains('a'), equals, true) 412 c.Check(set.Contains('a'), equals, true)
413 c.Check(set.Contains('z'), equals, true) 413 c.Check(set.Contains('z'), equals, true)
414} 414}
415 415
416func (s *Suite) Test__test_names(c *check.C) { 416func (s *Suite) Test__test_names(c *check.C) {
417 ck := intqa.NewTestNameChecker(c.Errorf) 417 ck := intqa.NewTestNameChecker(c.Errorf)
418 ck.Enable(intqa.EAll, -intqa.EMissingTest) 418 ck.Configure("*", "*", "*", -intqa.EMissingTest)
419 ck.Check() 419 ck.Check()
420} 420}

cvs diff -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/trace/Attic/tracing_test.go (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkglint/files/trace/Attic/tracing_test.go 2019/11/17 01:26:26 1.4
+++ pkgsrc/pkgtools/pkglint/files/trace/Attic/tracing_test.go 2019/11/19 06:51:39 1.5
@@ -135,16 +135,16 @@ func (s *Suite) captureTracingOutput(act @@ -135,16 +135,16 @@ func (s *Suite) captureTracingOutput(act
135 tracer.Tracing = false 135 tracer.Tracing = false
136 tracer.Out = nil 136 tracer.Out = nil
137 return out.String() 137 return out.String()
138} 138}
139 139
140type str struct{} 140type str struct{}
141 141
142func (str) String() string { 142func (str) String() string {
143 return "It's a string" 143 return "It's a string"
144} 144}
145 145
146func (s *Suite) Test__test_names(c *check.C) { 146func (s *Suite) Test__test_names(c *check.C) {
147 ck := intqa.NewTestNameChecker(c.Errorf) 147 ck := intqa.NewTestNameChecker(c.Errorf)
148 ck.Enable(intqa.EAll, -intqa.EMissingTest) 148 ck.Configure("*", "*", "*", -intqa.EMissingTest)
149 ck.Check() 149 ck.Check()
150} 150}