github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/buildtools/stack/stack_test.go (about)

     1  package stack_test
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  
     9  	"github.com/fossas/fossa-cli/buildtools/stack"
    10  	"github.com/fossas/fossa-cli/pkg"
    11  )
    12  
    13  func TestDepFromCanonical(t *testing.T) {
    14  	t.Run("it should form an isomorphism with DepToCanonical", func(t *testing.T) {
    15  		dep := stack.Dep{Name: "package-one", Version: "0.0.1.0"}
    16  		assert.Equal(t, stack.DepFromCanonical(stack.DepToCanonical(dep)), dep)
    17  	})
    18  }
    19  
    20  func TestDepToCanonical(t *testing.T) {
    21  	t.Run("it should form an isomorphism with DepFromCanonical", func(t *testing.T) {
    22  		dep := stack.Canonical{Identifier: "package-one-0.0.1.0"}
    23  		assert.Equal(t, stack.DepToCanonical(stack.DepFromCanonical(dep)), dep)
    24  	})
    25  }
    26  
    27  func TestDepToPkgId(t *testing.T) {
    28  	dep := stack.Dep{Name: "package-one", Version: "0.0.1.0"}
    29  	result := stack.DepToPkgId(dep)
    30  
    31  	assert.Equal(t, result.Name, dep.Name)
    32  	assert.Equal(t, result.Revision, dep.Version)
    33  	assert.Equal(t, result.Type, pkg.Haskell)
    34  }
    35  
    36  func TestParseStackDependencies(t *testing.T) {
    37  	packageOne := stack.Dep{Name: "package-one", Version: "0.0.1.0"}
    38  	packageTwo := stack.Dep{Name: "package-two", Version: "0.0.1.0"}
    39  	const packageOneRaw = "package-one 0.0.1.0"
    40  	const packageTwoRaw = "package-two 0.0.1.0"
    41  
    42  	joinLines := func(deps ...string) string {
    43  		return strings.Join(deps, "\n")
    44  	}
    45  
    46  	t.Run("it should parse a single package", func(t *testing.T) {
    47  		deps := stack.ParseStackDependencies(packageOneRaw)
    48  		assert.ElementsMatch(t, []stack.Dep{packageOne}, deps)
    49  	})
    50  	t.Run("it should parse many packages", func(t *testing.T) {
    51  		deps := stack.ParseStackDependencies(joinLines(packageOneRaw, packageTwoRaw))
    52  		assert.Equal(t, []stack.Dep{packageOne, packageTwo}, deps)
    53  	})
    54  	t.Run("it should ignore empty or invalid lines", func(t *testing.T) {
    55  		deps := stack.ParseStackDependencies("notvalid\n\n")
    56  		assert.Len(t, deps, 0)
    57  	})
    58  }
    59  
    60  func TestParseGhcPkgDepMap(t *testing.T) {
    61  	packageOne := stack.Canonical{Identifier: "package-one-0.0.1.0"}
    62  	packageTwo := stack.Canonical{Identifier: "package-two-0.0.1.0"}
    63  	packageThree := stack.Canonical{Identifier: "package-three-0.0.1.0"}
    64  	packageFour := stack.Canonical{Identifier: "package-four-0.0.1.0"}
    65  	const (
    66  		packageOneRaw   = "\"package-one-0.0.1.0\""
    67  		packageTwoRaw   = "\"package-two-0.0.1.0\""
    68  		packageThreeRaw = "\"package-three-0.0.1.0\""
    69  		packageFourRaw  = "\"package-four-0.0.1.0\""
    70  	)
    71  
    72  	createDep := func(from string, to string) string {
    73  		return from + " -> " + to
    74  	}
    75  
    76  	joinLines := func(deps ...string) string {
    77  		return strings.Join(deps, "\n")
    78  	}
    79  
    80  	t.Run("it should parse a single dependency", func(t *testing.T) {
    81  		deps := stack.ParseGhcPkgDepMap(createDep(packageOneRaw, packageTwoRaw))
    82  		assert.Equal(t, deps, map[stack.Canonical][]stack.Canonical{
    83  			packageOne: {packageTwo},
    84  		})
    85  	})
    86  	t.Run("it should parse many dependencies", func(t *testing.T) {
    87  		deps := stack.ParseGhcPkgDepMap(joinLines(createDep(packageOneRaw, packageTwoRaw), createDep(packageThreeRaw, packageFourRaw)))
    88  		assert.Equal(t, deps, map[stack.Canonical][]stack.Canonical{
    89  			packageOne:   {packageTwo},
    90  			packageThree: {packageFour},
    91  		})
    92  	})
    93  	t.Run("it should combine dependencies", func(t *testing.T) {
    94  		deps := stack.ParseGhcPkgDepMap(joinLines(createDep(packageOneRaw, packageTwoRaw), createDep(packageOneRaw, packageThreeRaw)))
    95  		assert.Equal(t, deps, map[stack.Canonical][]stack.Canonical{
    96  			packageOne: {packageTwo, packageThree},
    97  		})
    98  	})
    99  	t.Run("it should ignore empty or invalid lines", func(t *testing.T) {
   100  		deps := stack.ParseGhcPkgDepMap("notvalid\n\n")
   101  		assert.Len(t, deps, 0)
   102  	})
   103  }
   104  
   105  func TestAnalyzeStackPure(t *testing.T) {
   106  	stackImmediateDeps := []stack.Dep{
   107  		{
   108  			Name:    "package-three",
   109  			Version: "0.0.1.0",
   110  		},
   111  		{
   112  			Name:    "package-four",
   113  			Version: "0.0.1.0",
   114  		},
   115  	}
   116  
   117  	stackAllDeps := append(stackImmediateDeps,
   118  		stack.Dep{
   119  			Name:    "package-one",
   120  			Version: "0.0.1.0",
   121  		},
   122  		stack.Dep{
   123  			Name:    "package-two",
   124  			Version: "0.0.1.0",
   125  		},
   126  	)
   127  
   128  	depMap := map[stack.Canonical][]stack.Canonical{
   129  		{Identifier: "package-one-0.0.1.0"}: {
   130  			{Identifier: "package-two-0.0.1.0"},
   131  		},
   132  		{Identifier: "package-two-0.0.1.0"}: {
   133  			{Identifier: "package-three-0.0.1.0"},
   134  			{Identifier: "package-four-0.0.1.0"},
   135  		},
   136  		{Identifier: "package-three-0.0.1.0"}: {
   137  			{Identifier: "package-four-0.0.1.0"},
   138  		},
   139  	}
   140  
   141  	// Shared model example -- when modifying this, also modify in cabal_test.go
   142  	deps := stack.GetDepsPure(stackAllDeps, stackImmediateDeps, depMap)
   143  
   144  	packageOne := pkg.ID{
   145  		Type:     pkg.Haskell,
   146  		Name:     "package-one",
   147  		Revision: "0.0.1.0",
   148  	}
   149  	packageTwo := pkg.ID{
   150  		Type:     pkg.Haskell,
   151  		Name:     "package-two",
   152  		Revision: "0.0.1.0",
   153  	}
   154  	packageThree := pkg.ID{
   155  		Type:     pkg.Haskell,
   156  		Name:     "package-three",
   157  		Revision: "0.0.1.0",
   158  	}
   159  	packageFour := pkg.ID{
   160  		Type:     pkg.Haskell,
   161  		Name:     "package-four",
   162  		Revision: "0.0.1.0",
   163  	}
   164  
   165  	assert.Len(t, deps.Direct, 2)
   166  	assert.Contains(t, deps.Direct, pkg.Import{Resolved: packageThree})
   167  	assert.Contains(t, deps.Direct, pkg.Import{Resolved: packageFour})
   168  
   169  	assert.Len(t, deps.Transitive, 4)
   170  
   171  	assert.Contains(t, deps.Transitive, packageOne)
   172  	assert.Len(t, deps.Transitive[packageOne].Imports, 1)
   173  	assert.Contains(t, deps.Transitive[packageOne].Imports, pkg.Import{Resolved: packageTwo})
   174  
   175  	assert.Contains(t, deps.Transitive, packageTwo)
   176  	assert.Len(t, deps.Transitive[packageTwo].Imports, 2)
   177  	assert.Contains(t, deps.Transitive[packageTwo].Imports, pkg.Import{Resolved: packageThree})
   178  	assert.Contains(t, deps.Transitive[packageTwo].Imports, pkg.Import{Resolved: packageFour})
   179  
   180  	assert.Contains(t, deps.Transitive, packageThree)
   181  	assert.Len(t, deps.Transitive[packageThree].Imports, 1)
   182  	assert.Contains(t, deps.Transitive[packageThree].Imports, pkg.Import{Resolved: packageFour})
   183  
   184  	assert.Contains(t, deps.Transitive, packageFour)
   185  	assert.Len(t, deps.Transitive[packageFour].Imports, 0)
   186  }