cuelang.org/go@v0.10.1/internal/mod/modload/tidy_test.go (about)

     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/mod/modfile"
    21  	"cuelang.org/go/mod/modregistry"
    22  	"cuelang.org/go/mod/module"
    23  )
    24  
    25  func TestTidy(t *testing.T) {
    26  	files, err := filepath.Glob("testdata/tidy/*.txtar")
    27  	qt.Assert(t, qt.IsNil(err))
    28  	for _, f := range files {
    29  		t.Run(f, func(t *testing.T) {
    30  			ar, err := txtar.ParseFile(f)
    31  			qt.Assert(t, qt.IsNil(err))
    32  			tfs, err := txtar.FS(ar)
    33  			qt.Assert(t, qt.IsNil(err))
    34  			reg := newRegistry(t, tfs)
    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  			var tidyFile []byte
    49  			mf, err := Tidy(context.Background(), tfs, ".", reg)
    50  			if err != nil {
    51  				fmt.Fprintf(&out, "error: %v\n", err)
    52  			} else {
    53  				tidyFile, err = mf.Format()
    54  				qt.Assert(t, qt.IsNil(err))
    55  				out.Write(tidyFile)
    56  			}
    57  			if diff := cmp.Diff(string(want), out.String()); diff != "" {
    58  				t.Log("actual result:\n", out.String())
    59  				t.Fatalf("unexpected results (-want +got):\n%s", diff)
    60  			}
    61  
    62  			// Ensure that CheckTidy does not error after a successful Tidy.
    63  			// We make a new txtar FS given that an FS is read-only.
    64  			if len(tidyFile) > 0 {
    65  				for i := range ar.Files {
    66  					file := &ar.Files[i]
    67  					if file.Name == "cue.mod/module.cue" {
    68  						file.Data = []byte(out.String())
    69  					}
    70  				}
    71  				tfs, err := txtar.FS(ar)
    72  				qt.Assert(t, qt.IsNil(err))
    73  				err = CheckTidy(context.Background(), tfs, ".", reg)
    74  				qt.Check(t, qt.IsNil(err), qt.Commentf("CheckTidy after a successful Tidy should not fail"))
    75  			}
    76  		})
    77  	}
    78  }
    79  
    80  func stringFromFile(fsys fs.FS, file string) string {
    81  	data, _ := fs.ReadFile(fsys, file)
    82  	return strings.TrimSpace(string(data))
    83  }
    84  
    85  func newRegistry(t *testing.T, fsys fs.FS) Registry {
    86  	fsys, err := fs.Sub(fsys, "_registry")
    87  	qt.Assert(t, qt.IsNil(err))
    88  	regSrv, err := registrytest.New(fsys, "")
    89  	qt.Assert(t, qt.IsNil(err))
    90  	t.Cleanup(regSrv.Close)
    91  	regOCI, err := ociclient.New(regSrv.Host(), &ociclient.Options{
    92  		Insecure: true,
    93  	})
    94  	qt.Assert(t, qt.IsNil(err))
    95  	return &registryImpl{modregistry.NewClient(regOCI)}
    96  }
    97  
    98  type registryImpl struct {
    99  	reg *modregistry.Client
   100  }
   101  
   102  func (r *registryImpl) Requirements(ctx context.Context, mv module.Version) ([]module.Version, error) {
   103  	m, err := r.reg.GetModule(ctx, mv)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	data, err := m.ModuleFile(ctx)
   108  	if err != nil {
   109  		return nil, fmt.Errorf("cannot get module file from %v: %v", m, err)
   110  	}
   111  	mf, err := modfile.Parse(data, mv.String())
   112  	if err != nil {
   113  		return nil, fmt.Errorf("cannot parse module file from %v: %v", m, err)
   114  	}
   115  	return mf.DepVersions(), nil
   116  }
   117  
   118  // getModContents downloads the module with the given version
   119  // and returns the directory where it's stored.
   120  func (c *registryImpl) Fetch(ctx context.Context, mv module.Version) (module.SourceLoc, error) {
   121  	m, err := c.reg.GetModule(ctx, mv)
   122  	if err != nil {
   123  		return module.SourceLoc{}, err
   124  	}
   125  	r, err := m.GetZip(ctx)
   126  	if err != nil {
   127  		return module.SourceLoc{}, err
   128  	}
   129  	defer r.Close()
   130  	zipData, err := io.ReadAll(r)
   131  	if err != nil {
   132  		return module.SourceLoc{}, err
   133  	}
   134  	zipr, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))
   135  	if err != nil {
   136  		return module.SourceLoc{}, err
   137  	}
   138  	return module.SourceLoc{
   139  		FS:  zipr,
   140  		Dir: ".",
   141  	}, nil
   142  }
   143  
   144  func (r *registryImpl) ModuleVersions(ctx context.Context, mpath string) ([]string, error) {
   145  	versions, err := r.reg.ModuleVersions(ctx, mpath)
   146  	if err != nil {
   147  		return nil, fmt.Errorf("cannot obtain versions for module %q: %v", mpath, err)
   148  	}
   149  	return versions, nil
   150  }