@@ -2,9 +2,11 @@ package main
2
2
3
3
import (
4
4
"bytes"
5
+ "errors"
5
6
"fmt"
6
7
"go/ast"
7
8
"go/build"
9
+ "go/doc"
8
10
"go/parser"
9
11
"go/scanner"
10
12
"go/token"
@@ -18,11 +20,14 @@ import (
18
20
"path"
19
21
"path/filepath"
20
22
"runtime"
23
+ // "sort"
21
24
"strconv"
22
25
"strings"
23
26
"syscall"
24
27
"text/template"
25
28
"time"
29
+ "unicode"
30
+ "unicode/utf8"
26
31
27
32
gbuild "github.com/gopherjs/gopherjs/build"
28
33
"github.com/gopherjs/gopherjs/compiler"
@@ -325,28 +330,25 @@ func main() {
325
330
fmt .Printf ("? \t %s\t [no test files]\n " , pkg .ImportPath )
326
331
continue
327
332
}
328
-
329
333
s := gbuild .NewSession (options )
334
+
330
335
tests := & testFuncs {Package : pkg .Package }
331
336
collectTests := func (testPkg * gbuild.PackageData , testPkgName string , needVar * bool ) error {
332
337
archive , err := s .BuildPackage (testPkg )
333
338
if err != nil {
334
339
return err
335
340
}
336
-
337
- for _ , decl := range archive .Declarations {
338
- switch {
339
- case decl .FullName == testPkg .ImportPath + ".TestMain" :
340
- if tests .TestMain != nil {
341
- return fmt .Errorf ("multiple definitions of TestMain" )
341
+ if testPkgName == "_test" {
342
+ for _ , file := range pkg .TestGoFiles {
343
+ if err := tests .load (filepath .Join (pkg .Package .Dir , file ), testPkgName , & tests .ImportTest , & tests .NeedTest ); err != nil {
344
+ return err
345
+ }
346
+ }
347
+ } else {
348
+ for _ , file := range pkg .XTestGoFiles {
349
+ if err := tests .load (filepath .Join (pkg .Package .Dir , file ), "_xtest" , & tests .ImportXtest , & tests .NeedXtest ); err != nil {
350
+ return err
342
351
}
343
- tests .TestMain = & testFunc {Package : testPkgName , Name : decl .FullName [len (testPkg .ImportPath )+ 1 :]}
344
- case strings .HasPrefix (decl .FullName , testPkg .ImportPath + ".Test" ):
345
- tests .Tests = append (tests .Tests , testFunc {Package : testPkgName , Name : decl .FullName [len (testPkg .ImportPath )+ 1 :]})
346
- * needVar = true
347
- case strings .HasPrefix (decl .FullName , testPkg .ImportPath + ".Benchmark" ):
348
- tests .Benchmarks = append (tests .Benchmarks , testFunc {Package : testPkgName , Name : decl .FullName [len (testPkg .ImportPath )+ 1 :]})
349
- * needVar = true
350
352
}
351
353
}
352
354
return nil
@@ -775,13 +777,15 @@ func runNode(script string, args []string, dir string, quiet bool) error {
775
777
}
776
778
777
779
type testFuncs struct {
778
- Tests []testFunc
779
- Benchmarks []testFunc
780
- Examples []testFunc
781
- TestMain * testFunc
782
- Package * build.Package
783
- NeedTest bool
784
- NeedXtest bool
780
+ Tests []testFunc
781
+ Benchmarks []testFunc
782
+ Examples []testFunc
783
+ TestMain * testFunc
784
+ Package * build.Package
785
+ ImportTest bool
786
+ NeedTest bool
787
+ ImportXtest bool
788
+ NeedXtest bool
785
789
}
786
790
787
791
type testFunc struct {
@@ -790,6 +794,96 @@ type testFunc struct {
790
794
Output string // output, for examples
791
795
}
792
796
797
+ var testFileSet = token .NewFileSet ()
798
+
799
+ func (t * testFuncs ) load (filename , pkg string , doImport , seen * bool ) error {
800
+ f , err := parser .ParseFile (testFileSet , filename , nil , parser .ParseComments )
801
+ if err != nil {
802
+ return err
803
+ }
804
+ for _ , d := range f .Decls {
805
+ n , ok := d .(* ast.FuncDecl )
806
+ if ! ok {
807
+ continue
808
+ }
809
+ if n .Recv != nil {
810
+ continue
811
+ }
812
+ name := n .Name .String ()
813
+ switch {
814
+ case isTestMain (n ):
815
+ if t .TestMain != nil {
816
+ return errors .New ("multiple definitions of TestMain" )
817
+ }
818
+ t .TestMain = & testFunc {pkg , name , "" }
819
+ * doImport , * seen = true , true
820
+ case isTest (name , "Test" ):
821
+ t .Tests = append (t .Tests , testFunc {pkg , name , "" })
822
+ * doImport , * seen = true , true
823
+ case isTest (name , "Benchmark" ):
824
+ t .Benchmarks = append (t .Benchmarks , testFunc {pkg , name , "" })
825
+ * doImport , * seen = true , true
826
+ }
827
+ }
828
+ // ex := doc.Examples(f)
829
+ // sort.Sort(byOrder(ex))
830
+ // for _, e := range ex {
831
+ // *doImport = true // import test file whether executed or not
832
+ // if e.Output == "" && !e.EmptyOutput {
833
+ // // Don't run examples with no output.
834
+ // continue
835
+ // }
836
+ // t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
837
+ // *seen = true
838
+ // }
839
+ return nil
840
+ }
841
+
842
+ type byOrder []* doc.Example
843
+
844
+ func (x byOrder ) Len () int { return len (x ) }
845
+ func (x byOrder ) Swap (i , j int ) { x [i ], x [j ] = x [j ], x [i ] }
846
+ func (x byOrder ) Less (i , j int ) bool { return x [i ].Order < x [j ].Order }
847
+
848
+ // isTestMain tells whether fn is a TestMain(m *testing.M) function.
849
+ func isTestMain (fn * ast.FuncDecl ) bool {
850
+ if fn .Name .String () != "TestMain" ||
851
+ fn .Type .Results != nil && len (fn .Type .Results .List ) > 0 ||
852
+ fn .Type .Params == nil ||
853
+ len (fn .Type .Params .List ) != 1 ||
854
+ len (fn .Type .Params .List [0 ].Names ) > 1 {
855
+ return false
856
+ }
857
+ ptr , ok := fn .Type .Params .List [0 ].Type .(* ast.StarExpr )
858
+ if ! ok {
859
+ return false
860
+ }
861
+ // We can't easily check that the type is *testing.M
862
+ // because we don't know how testing has been imported,
863
+ // but at least check that it's *M or *something.M.
864
+ if name , ok := ptr .X .(* ast.Ident ); ok && name .Name == "M" {
865
+ return true
866
+ }
867
+ if sel , ok := ptr .X .(* ast.SelectorExpr ); ok && sel .Sel .Name == "M" {
868
+ return true
869
+ }
870
+ return false
871
+ }
872
+
873
+ // isTest tells whether name looks like a test (or benchmark, according to prefix).
874
+ // It is a Test (say) if there is a character after Test that is not a lower-case letter.
875
+ // We don't want TesticularCancer.
876
+ func isTest (name , prefix string ) bool {
877
+ if ! strings .HasPrefix (name , prefix ) {
878
+ return false
879
+ }
880
+ if len (name ) == len (prefix ) { // "Test" is ok
881
+ return true
882
+ }
883
+ rune , _ := utf8 .DecodeRuneInString (name [len (prefix ):])
884
+ return ! unicode .IsLower (rune )
885
+ }
886
+
793
887
var testmainTmpl = template .Must (template .New ("main" ).Parse (`
794
888
package main
795
889
@@ -800,11 +894,11 @@ import (
800
894
"regexp"
801
895
"testing"
802
896
803
- {{if .NeedTest }}
804
- _test {{.Package.ImportPath | printf "%q"}}
897
+ {{if .ImportTest }}
898
+ {{if .NeedTest}} _test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
805
899
{{end}}
806
- {{if .NeedXtest }}
807
- _xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
900
+ {{if .ImportXtest }}
901
+ {{if .NeedXtest}} _xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
808
902
{{end}}
809
903
)
810
904
0 commit comments