1 package modload
2
3 import (
4 "archive/zip"
5 "bytes"
6 "context"
7 "fmt"
8 "io"
9 "io/fs"
10 "path/filepath"
11 "strings"
12 "testing"
13
14 "cuelabs.dev/go/oci/ociregistry/ociclient"
15 "github.com/go-quicktest/qt"
16 "github.com/google/go-cmp/cmp"
17 "golang.org/x/tools/txtar"
18
19 "cuelang.org/go/internal/registrytest"
20 "cuelang.org/go/internal/txtarfs"
21 "cuelang.org/go/mod/modfile"
22 "cuelang.org/go/mod/modregistry"
23 "cuelang.org/go/mod/module"
24 )
25
26 func TestTidy(t *testing.T) {
27 files, err := filepath.Glob("testdata/tidy/*.txtar")
28 qt.Assert(t, qt.IsNil(err))
29 for _, f := range files {
30 t.Run(f, func(t *testing.T) {
31 ar, err := txtar.ParseFile(f)
32 qt.Assert(t, qt.IsNil(err))
33 tfs := txtarfs.FS(ar)
34 reg := newRegistry(t, tfs, "_registry")
35
36 want, err := fs.ReadFile(tfs, "want")
37 qt.Assert(t, qt.IsNil(err))
38
39 err = CheckTidy(context.Background(), tfs, ".", reg)
40 wantCheckTidyError := stringFromFile(tfs, "tidy-check-error")
41 if wantCheckTidyError == "" {
42 qt.Check(t, qt.IsNil(err))
43 } else {
44 qt.Check(t, qt.ErrorMatches(err, wantCheckTidyError))
45 }
46
47 var out strings.Builder
48 mf, err := Tidy(context.Background(), tfs, ".", reg, stringFromFile(tfs, "cue-version"))
49 if err != nil {
50 fmt.Fprintf(&out, "error: %v\n", err)
51 } else {
52 data, err := mf.Format()
53 qt.Assert(t, qt.IsNil(err))
54 out.Write(data)
55 }
56 if diff := cmp.Diff(string(want), out.String()); diff != "" {
57 t.Log("actual result:\n", out.String())
58 t.Fatalf("unexpected results (-want +got):\n%s", diff)
59 }
60 })
61 }
62 }
63
64 func stringFromFile(fsys fs.FS, file string) string {
65 data, _ := fs.ReadFile(fsys, file)
66 return strings.TrimSpace(string(data))
67 }
68
69 func newRegistry(t *testing.T, fsys fs.FS, root string) Registry {
70 fsys, err := fs.Sub(fsys, "_registry")
71 qt.Assert(t, qt.IsNil(err))
72 regSrv, err := registrytest.New(fsys, "")
73 qt.Assert(t, qt.IsNil(err))
74 t.Cleanup(regSrv.Close)
75 regOCI, err := ociclient.New(regSrv.Host(), &ociclient.Options{
76 Insecure: true,
77 })
78 qt.Assert(t, qt.IsNil(err))
79 return ®istryImpl{modregistry.NewClient(regOCI)}
80 }
81
82 type registryImpl struct {
83 reg *modregistry.Client
84 }
85
86 func (r *registryImpl) Requirements(ctx context.Context, mv module.Version) ([]module.Version, error) {
87 m, err := r.reg.GetModule(ctx, mv)
88 if err != nil {
89 return nil, err
90 }
91 data, err := m.ModuleFile(ctx)
92 if err != nil {
93 return nil, fmt.Errorf("cannot get module file from %v: %v", m, err)
94 }
95 mf, err := modfile.Parse(data, mv.String())
96 if err != nil {
97 return nil, fmt.Errorf("cannot parse module file from %v: %v", m, err)
98 }
99 return mf.DepVersions(), nil
100 }
101
102
103
104 func (c *registryImpl) Fetch(ctx context.Context, mv module.Version) (module.SourceLoc, error) {
105 m, err := c.reg.GetModule(ctx, mv)
106 if err != nil {
107 return module.SourceLoc{}, err
108 }
109 r, err := m.GetZip(ctx)
110 if err != nil {
111 return module.SourceLoc{}, err
112 }
113 defer r.Close()
114 zipData, err := io.ReadAll(r)
115 if err != nil {
116 return module.SourceLoc{}, err
117 }
118 zipr, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))
119 if err != nil {
120 return module.SourceLoc{}, err
121 }
122 return module.SourceLoc{
123 FS: zipr,
124 Dir: ".",
125 }, nil
126 }
127
128 func (r *registryImpl) ModuleVersions(ctx context.Context, mpath string) ([]string, error) {
129 versions, err := r.reg.ModuleVersions(ctx, mpath)
130 if err != nil {
131 return nil, fmt.Errorf("cannot obtain versions for module %q: %v", mpath, err)
132 }
133 return versions, nil
134 }
135
View as plain text