github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/pkg/gnomod/pkg_test.go (about)

     1  package gnomod
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/gnolang/gno/tm2/pkg/testutils"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestListAndNonDraftPkgs(t *testing.T) {
    14  	for _, tc := range []struct {
    15  		desc string
    16  		in   []struct{ name, modfile string }
    17  
    18  		outListPkgs     []string
    19  		outNonDraftPkgs []string
    20  	}{
    21  		{
    22  			desc: "no packages",
    23  		},
    24  		{
    25  			desc: "no package depends on another package",
    26  			in: []struct{ name, modfile string }{
    27  				{
    28  					"foo",
    29  					`module foo`,
    30  				},
    31  				{
    32  					"bar",
    33  					`module bar`,
    34  				},
    35  				{
    36  					"baz",
    37  					`module baz`,
    38  				},
    39  			},
    40  			outListPkgs:     []string{"foo", "bar", "baz"},
    41  			outNonDraftPkgs: []string{"foo", "bar", "baz"},
    42  		},
    43  		{
    44  			desc: "no package depends on draft package",
    45  			in: []struct{ name, modfile string }{
    46  				{
    47  					"foo",
    48  					`module foo`,
    49  				},
    50  				{
    51  					"bar",
    52  					`module bar
    53  
    54  					require foo v0.0.0`,
    55  				},
    56  				{
    57  					"baz",
    58  					`module baz`,
    59  				},
    60  				{
    61  					"qux",
    62  					`// Draft
    63  
    64  					module qux`,
    65  				},
    66  			},
    67  			outListPkgs:     []string{"foo", "bar", "baz", "qux"},
    68  			outNonDraftPkgs: []string{"foo", "bar", "baz"},
    69  		},
    70  		{
    71  			desc: "package directly depends on draft package",
    72  			in: []struct{ name, modfile string }{
    73  				{
    74  					"foo",
    75  					`// Draft
    76  
    77  					module foo`,
    78  				},
    79  				{
    80  					"bar",
    81  					`module bar
    82  					require foo v0.0.0`,
    83  				},
    84  				{
    85  					"baz",
    86  					`module baz`,
    87  				},
    88  			},
    89  			outListPkgs:     []string{"foo", "bar", "baz"},
    90  			outNonDraftPkgs: []string{"baz"},
    91  		},
    92  		{
    93  			desc: "package indirectly depends on draft package",
    94  			in: []struct{ name, modfile string }{
    95  				{
    96  					"foo",
    97  					`// Draft
    98  
    99  					module foo`,
   100  				},
   101  				{
   102  					"bar",
   103  					`module bar
   104  
   105  					require foo v0.0.0`,
   106  				},
   107  				{
   108  					"baz",
   109  					`module baz
   110  
   111  					require bar v0.0.0`,
   112  				},
   113  				{
   114  					"qux",
   115  					`module qux`,
   116  				},
   117  			},
   118  			outListPkgs:     []string{"foo", "bar", "baz", "qux"},
   119  			outNonDraftPkgs: []string{"qux"},
   120  		},
   121  		{
   122  			desc: "package indirectly depends on draft package (multiple levels - 1)",
   123  			in: []struct{ name, modfile string }{
   124  				{
   125  					"foo",
   126  					`// Draft
   127  
   128  					module foo`,
   129  				},
   130  				{
   131  					"bar",
   132  					`module bar
   133  
   134  					require foo v0.0.0`,
   135  				},
   136  				{
   137  					"baz",
   138  					`module baz
   139  
   140  					require bar v0.0.0`,
   141  				},
   142  				{
   143  					"qux",
   144  					`module qux
   145  
   146  					require baz v0.0.0`,
   147  				},
   148  			},
   149  			outListPkgs:     []string{"foo", "bar", "baz", "qux"},
   150  			outNonDraftPkgs: []string{},
   151  		},
   152  		{
   153  			desc: "package indirectly depends on draft package (multiple levels - 2)",
   154  			in: []struct{ name, modfile string }{
   155  				{
   156  					"foo",
   157  					`// Draft
   158  
   159  					module foo`,
   160  				},
   161  				{
   162  					"bar",
   163  					`module bar
   164  
   165  					require qux v0.0.0`,
   166  				},
   167  				{
   168  					"baz",
   169  					`module baz
   170  
   171  					require foo v0.0.0`,
   172  				},
   173  				{
   174  					"qux",
   175  					`module qux
   176  
   177  					require baz v0.0.0`,
   178  				},
   179  			},
   180  			outListPkgs:     []string{"foo", "bar", "baz", "qux"},
   181  			outNonDraftPkgs: []string{},
   182  		},
   183  	} {
   184  		t.Run(tc.desc, func(t *testing.T) {
   185  			// Create test dir
   186  			dirPath, cleanUpFn := testutils.NewTestCaseDir(t)
   187  			require.NotNil(t, dirPath)
   188  			defer cleanUpFn()
   189  
   190  			// Create packages
   191  			for _, p := range tc.in {
   192  				createGnoModPkg(t, dirPath, p.name, p.modfile)
   193  			}
   194  
   195  			// List packages
   196  			pkgs, err := ListPkgs(dirPath)
   197  			require.NoError(t, err)
   198  			assert.Equal(t, len(tc.outListPkgs), len(pkgs))
   199  			for _, p := range pkgs {
   200  				assert.Contains(t, tc.outListPkgs, p.Name)
   201  			}
   202  
   203  			// Sort packages
   204  			sorted, err := pkgs.Sort()
   205  			require.NoError(t, err)
   206  
   207  			// Non draft packages
   208  			nonDraft := sorted.GetNonDraftPkgs()
   209  			assert.Equal(t, len(tc.outNonDraftPkgs), len(nonDraft))
   210  			for _, p := range nonDraft {
   211  				assert.Contains(t, tc.outNonDraftPkgs, p.Name)
   212  			}
   213  		})
   214  	}
   215  }
   216  
   217  func createGnoModPkg(t *testing.T, dirPath, pkgName, modData string) {
   218  	t.Helper()
   219  
   220  	// Create package dir
   221  	pkgDirPath := filepath.Join(dirPath, pkgName)
   222  	err := os.MkdirAll(pkgDirPath, 0o755)
   223  	require.NoError(t, err)
   224  
   225  	// Create gno.mod
   226  	err = os.WriteFile(filepath.Join(pkgDirPath, "gno.mod"), []byte(modData), 0o644)
   227  }
   228  
   229  func TestSortPkgs(t *testing.T) {
   230  	for _, tc := range []struct {
   231  		desc      string
   232  		in        PkgList
   233  		expected  []string
   234  		shouldErr bool
   235  	}{
   236  		{
   237  			desc:     "empty_input",
   238  			in:       []Pkg{},
   239  			expected: make([]string, 0),
   240  		}, {
   241  			desc: "no_dependencies",
   242  			in: []Pkg{
   243  				{Name: "pkg1", Dir: "/path/to/pkg1", Requires: []string{}},
   244  				{Name: "pkg2", Dir: "/path/to/pkg2", Requires: []string{}},
   245  				{Name: "pkg3", Dir: "/path/to/pkg3", Requires: []string{}},
   246  			},
   247  			expected: []string{"pkg1", "pkg2", "pkg3"},
   248  		}, {
   249  			desc: "circular_dependencies",
   250  			in: []Pkg{
   251  				{Name: "pkg1", Dir: "/path/to/pkg1", Requires: []string{"pkg2"}},
   252  				{Name: "pkg2", Dir: "/path/to/pkg2", Requires: []string{"pkg1"}},
   253  			},
   254  			shouldErr: true,
   255  		}, {
   256  			desc: "missing_dependencies",
   257  			in: []Pkg{
   258  				{Name: "pkg1", Dir: "/path/to/pkg1", Requires: []string{"pkg2"}},
   259  			},
   260  			shouldErr: true,
   261  		}, {
   262  			desc: "valid_dependencies",
   263  			in: []Pkg{
   264  				{Name: "pkg1", Dir: "/path/to/pkg1", Requires: []string{"pkg2"}},
   265  				{Name: "pkg2", Dir: "/path/to/pkg2", Requires: []string{"pkg3"}},
   266  				{Name: "pkg3", Dir: "/path/to/pkg3", Requires: []string{}},
   267  			},
   268  			expected: []string{"pkg3", "pkg2", "pkg1"},
   269  		},
   270  	} {
   271  		t.Run(tc.desc, func(t *testing.T) {
   272  			sorted, err := tc.in.Sort()
   273  			if tc.shouldErr {
   274  				assert.Error(t, err)
   275  			} else {
   276  				require.NoError(t, err)
   277  				for i := range tc.expected {
   278  					assert.Equal(t, tc.expected[i], sorted[i].Name)
   279  				}
   280  			}
   281  		})
   282  	}
   283  }