@@ -2,15 +2,11 @@ package examples_test
2
2
3
3
import (
4
4
"fmt"
5
- "io/fs"
6
- "os"
7
- pathlib "path"
8
5
"path/filepath"
9
6
"slices"
10
7
"strings"
11
8
"testing"
12
9
13
- "github.com/gnolang/gno/gnovm"
14
10
"github.com/gnolang/gno/gnovm/pkg/gnoenv"
15
11
"github.com/gnolang/gno/gnovm/pkg/packages"
16
12
"github.com/stretchr/testify/require"
@@ -20,29 +16,17 @@ var injectedTestingLibs = []string{"encoding/json", "fmt", "os", "internal/os_te
20
16
21
17
// TestNoCycles checks that there is no import cycles in stdlibs and non-draft examples
22
18
func TestNoCycles (t * testing.T ) {
23
- // find stdlibs
24
- gnoRoot := gnoenv .RootDir ()
25
- pkgs , err := listPkgs (packages.Pkg {
26
- Dir : filepath .Join (gnoRoot , "gnovm" , "stdlibs" ),
27
- Name : "" ,
28
- })
19
+ // find examples and stdlibs
20
+ cfg := & packages.LoadConfig {SelfContained : true , Deps : true }
21
+ pkgs , err := packages .Load (cfg , filepath .Join (gnoenv .RootDir (), "examples" , "..." ))
29
22
require .NoError (t , err )
30
23
31
- // find examples
32
- examples , err := packages .ListPkgs (filepath .Join (gnoRoot , "examples" ))
33
- require .NoError (t , err )
34
- for _ , example := range examples {
35
- if example .Draft {
36
- continue
37
- }
38
- examplePkgs , err := listPkgs (example )
39
- require .NoError (t , err )
40
- pkgs = append (pkgs , examplePkgs ... )
41
- }
42
-
43
24
// detect cycles
44
25
visited := make (map [string ]bool )
45
26
for _ , p := range pkgs {
27
+ if p .Draft {
28
+ continue
29
+ }
46
30
require .NoError (t , detectCycles (p , pkgs , visited ))
47
31
}
48
32
}
@@ -73,7 +57,7 @@ func TestNoCycles(t *testing.T) {
73
57
// - foo_pkg/foo.go imports bar_pkg
74
58
//
75
59
// - bar_pkg/bar_test.go imports foo_pkg
76
- func detectCycles (root testPkg , pkgs []testPkg , visited map [string ]bool ) error {
60
+ func detectCycles (root * packages. Package , pkgs []* packages. Package , visited map [string ]bool ) error {
77
61
// check cycles in package's sources
78
62
stack := []string {}
79
63
if err := visitPackage (root , pkgs , visited , stack ); err != nil {
@@ -86,8 +70,8 @@ func detectCycles(root testPkg, pkgs []testPkg, visited map[string]bool) error {
86
70
87
71
// check cycles in tests' imports by marking the current package as visited while visiting the tests' imports
88
72
// we also consider PackageSource imports here because tests can call package code
89
- visited = map [string ]bool {root .PkgPath : true }
90
- stack = []string {root .PkgPath }
73
+ visited = map [string ]bool {root .ImportPath : true }
74
+ stack = []string {root .ImportPath }
91
75
if err := visitImports ([]packages.FileKind {packages .FileKindPackageSource , packages .FileKindTest }, root , pkgs , visited , stack ); err != nil {
92
76
return fmt .Errorf ("test import: %w" , err )
93
77
}
@@ -96,14 +80,14 @@ func detectCycles(root testPkg, pkgs []testPkg, visited map[string]bool) error {
96
80
}
97
81
98
82
// visitImports resolves and visits imports by kinds
99
- func visitImports (kinds []packages.FileKind , root testPkg , pkgs []testPkg , visited map [string ]bool , stack []string ) error {
83
+ func visitImports (kinds []packages.FileKind , root * packages. Package , pkgs []* packages. Package , visited map [string ]bool , stack []string ) error {
100
84
for _ , imp := range root .Imports .Merge (kinds ... ) {
101
- if slices .Contains (injectedTestingLibs , imp . PkgPath ) {
85
+ if slices .Contains (injectedTestingLibs , imp ) {
102
86
continue
103
87
}
104
- idx := slices .IndexFunc (pkgs , func (p testPkg ) bool { return p .PkgPath == imp . PkgPath })
88
+ idx := slices .IndexFunc (pkgs , func (p * packages. Package ) bool { return p .ImportPath == imp })
105
89
if idx == - 1 {
106
- return fmt .Errorf ("import %q not found for %q tests" , imp . PkgPath , root .PkgPath )
90
+ return fmt .Errorf ("import %q not found for %q tests" , imp , root .ImportPath )
107
91
}
108
92
if err := visitPackage (pkgs [idx ], pkgs , visited , stack ); err != nil {
109
93
return fmt .Errorf ("test import error: %w" , err )
@@ -114,98 +98,20 @@ func visitImports(kinds []packages.FileKind, root testPkg, pkgs []testPkg, visit
114
98
}
115
99
116
100
// visitNode visits a package and its imports recursively. It only considers imports in PackageSource
117
- func visitPackage (pkg testPkg , pkgs []testPkg , visited map [string ]bool , stack []string ) error {
118
- if slices .Contains (stack , pkg .PkgPath ) {
119
- return fmt .Errorf ("cycle detected: %s -> %s" , strings .Join (stack , " -> " ), pkg .PkgPath )
101
+ func visitPackage (pkg * packages. Package , pkgs []* packages. Package , visited map [string ]bool , stack []string ) error {
102
+ if slices .Contains (stack , pkg .ImportPath ) {
103
+ return fmt .Errorf ("cycle detected: %s -> %s" , strings .Join (stack , " -> " ), pkg .ImportPath )
120
104
}
121
- if visited [pkg .PkgPath ] {
105
+ if visited [pkg .ImportPath ] {
122
106
return nil
123
107
}
124
108
125
- visited [pkg .PkgPath ] = true
126
- stack = append (stack , pkg .PkgPath )
109
+ visited [pkg .ImportPath ] = true
110
+ stack = append (stack , pkg .ImportPath )
127
111
128
112
if err := visitImports ([]packages.FileKind {packages .FileKindPackageSource }, pkg , pkgs , visited , stack ); err != nil {
129
113
return err
130
114
}
131
115
132
116
return nil
133
117
}
134
-
135
- type testPkg struct {
136
- Dir string
137
- PkgPath string
138
- Imports packages.ImportsMap
139
- }
140
-
141
- // listPkgs lists all packages in rootMod
142
- func listPkgs (rootMod packages.Pkg ) ([]testPkg , error ) {
143
- res := []testPkg {}
144
- rootDir := rootMod .Dir
145
- visited := map [string ]struct {}{}
146
- if err := fs .WalkDir (os .DirFS (rootDir ), "." , func (path string , d fs.DirEntry , err error ) error {
147
- if err != nil {
148
- return err
149
- }
150
- if d .IsDir () {
151
- return nil
152
- }
153
- if ! strings .HasSuffix (d .Name (), ".gno" ) {
154
- return nil
155
- }
156
- subPath := filepath .Dir (path )
157
- dir := filepath .Join (rootDir , subPath )
158
- if _ , ok := visited [dir ]; ok {
159
- return nil
160
- }
161
- visited [dir ] = struct {}{}
162
-
163
- subPkgPath := pathlib .Join (rootMod .Name , subPath )
164
-
165
- pkg := testPkg {
166
- Dir : dir ,
167
- PkgPath : subPkgPath ,
168
- }
169
-
170
- memPkg , err := readPkg (pkg .Dir , pkg .PkgPath )
171
- if err != nil {
172
- return fmt .Errorf ("read pkg %q: %w" , pkg .Dir , err )
173
- }
174
- pkg .Imports , err = packages .Imports (memPkg , nil )
175
- if err != nil {
176
- return fmt .Errorf ("list imports of %q: %w" , memPkg .Path , err )
177
- }
178
-
179
- res = append (res , pkg )
180
- return nil
181
- }); err != nil {
182
- return nil , fmt .Errorf ("walk dirs at %q: %w" , rootDir , err )
183
- }
184
- return res , nil
185
- }
186
-
187
- // readPkg reads the sources of a package. It includes all .gno files but ignores the package name
188
- func readPkg (dir string , pkgPath string ) (* gnovm.MemPackage , error ) {
189
- list , err := os .ReadDir (dir )
190
- if err != nil {
191
- return nil , err
192
- }
193
- memPkg := & gnovm.MemPackage {Path : pkgPath }
194
- for _ , entry := range list {
195
- fpath := filepath .Join (dir , entry .Name ())
196
- if ! strings .HasSuffix (fpath , ".gno" ) {
197
- continue
198
- }
199
- fname := filepath .Base (fpath )
200
- bz , err := os .ReadFile (fpath )
201
- if err != nil {
202
- return nil , err
203
- }
204
- memPkg .Files = append (memPkg .Files ,
205
- & gnovm.MemFile {
206
- Name : fname ,
207
- Body : string (bz ),
208
- })
209
- }
210
- return memPkg , nil
211
- }
0 commit comments