@@ -21,8 +21,11 @@ import (
2121 "go/token"
2222 "go/types"
2323 "slices"
24+ "sync"
2425 "testing"
2526
27+ "github.com/stretchr/testify/assert"
28+
2629 "github.com/stretchr/testify/require"
2730)
2831
@@ -195,3 +198,90 @@ var f func() (*http.Request, error)`,
195198 })
196199 }
197200}
201+
202+ func resetGlobals () {
203+ // 重置包缓存
204+ stdlibCache = NewPackageCache (10000 )
205+ }
206+
207+ func Test_isSysPkg (t * testing.T ) {
208+ // 测试在 `go env GOROOT` 可以成功执行时的行为
209+ t .Run ("Group: Happy Path - GOROOT is found" , func (t * testing.T ) {
210+ resetGlobals ()
211+
212+ testCases := []struct {
213+ name string
214+ importPath string
215+ want bool
216+ }{
217+ {"standard library package" , "fmt" , true },
218+ {"nested standard library package" , "net/http" , true },
219+ {"third-party package" , "github.com/google/uuid" , false },
220+ {"extended library package" , "golang.org/x/sync/errgroup" , false },
221+ {"local-like package name" , "myproject/utils" , false },
222+ {"non-existent package" , "non/existent/package" , false },
223+ {"root-level package with dot" , "gopkg.in/yaml.v2" , false },
224+ }
225+
226+ for _ , tc := range testCases {
227+ t .Run (tc .name , func (t * testing.T ) {
228+ if got := isSysPkg (tc .importPath ); got != tc .want {
229+ t .Errorf ("isSysPkg(%q) = %v, want %v" , tc .importPath , got , tc .want )
230+ }
231+ })
232+ }
233+ })
234+
235+ // 测试并发调用时的行为
236+ t .Run ("Group: Concurrency Test" , func (t * testing.T ) {
237+ resetGlobals ()
238+ var wg sync.WaitGroup
239+ numGoroutines := 50
240+ numOpsPerGoroutine := 100
241+
242+ for i := 0 ; i < numGoroutines ; i ++ {
243+ wg .Add (1 )
244+ go func () {
245+ defer wg .Done ()
246+ for j := 0 ; j < numOpsPerGoroutine ; j ++ {
247+ isSysPkg ("fmt" )
248+ isSysPkg ("github.com/cloudwego/abcoder" )
249+ isSysPkg ("net/http" )
250+ isSysPkg ("a/b/c" )
251+ }
252+ }()
253+ }
254+ wg .Wait ()
255+ })
256+
257+ // 测试 LRU 缓存的驱逐策略
258+ t .Run ("Group: LRU Eviction Test" , func (t * testing.T ) {
259+ resetGlobals ()
260+ stdlibCache .lruCapacity = 2
261+
262+ // 1. 填满 Cache
263+ isSysPkg ("fmt" )
264+ isSysPkg ("os" )
265+ assert .Equal (t , 2 , stdlibCache .lru .Len (), "Cache should be full" )
266+
267+ // 2. 访问 "fmt" 使它最近被使用
268+ isSysPkg ("fmt" )
269+ assert .Equal (t , "fmt" , stdlibCache .lru .Front ().Value .(* cacheEntry ).key , "fmt should be the most recently used" )
270+
271+ // 3. 访问 "net" 使它最近被使用
272+ isSysPkg ("net" ) // "os" should be evicted
273+ assert .Equal (t , 2 , stdlibCache .lru .Len (), "Cache size should remain at capacity" )
274+
275+ // 4. "fmt" 应该在 Cache 中
276+ _ , foundFmt := stdlibCache .get ("fmt" )
277+ assert .True (t , foundFmt , "fmt should still be in the cache" )
278+
279+ // 5. "net" 应该在 Cache 中
280+ _ , foundNet := stdlibCache .get ("net" )
281+ assert .True (t , foundNet , "net should be in the cache" )
282+
283+ // 6. "os" 不应该在 Cache 中
284+ _ , foundOs := stdlibCache .get ("os" )
285+ assert .False (t , foundOs , "os should have been evicted from the cache" )
286+ })
287+ }
0 commit comments