github.com/tiagovtristao/plz@v13.4.0+incompatible/src/parse/parse_step_test.go (about)

     1  // Tests for general parse functions.
     2  
     3  package parse
     4  
     5  import (
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/thought-machine/please/src/core"
    11  )
    12  
    13  var empty = []string{}
    14  
    15  func TestAddDepSimple(t *testing.T) {
    16  	// Simple case with only one package parsed and one target added
    17  	state := makeState(true, false)
    18  	activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty)
    19  	assertPendingParses(t, state, "//package2:target1", "//package2:target1")
    20  	assertPendingBuilds(t, state) // None until package2 parses
    21  	assert.Equal(t, 5, state.NumActive())
    22  }
    23  
    24  func TestAddDepMultiple(t *testing.T) {
    25  	// Similar to above but doing all targets in that package
    26  	state := makeState(true, false)
    27  	activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty)
    28  	activateTarget(state, nil, buildLabel("//package1:target2"), core.OriginalTarget, false, empty, empty)
    29  	activateTarget(state, nil, buildLabel("//package1:target3"), core.OriginalTarget, false, empty, empty)
    30  	// We get an additional dep on target2, but not another on package2:target1 because target2
    31  	// is already activated since package1:target1 depends on it
    32  	assertPendingParses(t, state, "//package2:target1", "//package2:target1", "//package2:target2")
    33  	assertPendingBuilds(t, state) // None until package2 parses
    34  	assert.Equal(t, 7, state.NumActive())
    35  }
    36  
    37  func TestAddDepMultiplePackages(t *testing.T) {
    38  	// This time we already have package2 parsed
    39  	state := makeState(true, true)
    40  	activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty)
    41  	assertPendingBuilds(t, state, "//package2:target2") // This is the only candidate target
    42  	assertPendingParses(t, state)                       // None, we have both packages already
    43  	assert.Equal(t, 6, state.NumActive())
    44  }
    45  
    46  func TestAddDepNoBuild(t *testing.T) {
    47  	// Tag state as not needing build. We shouldn't get any pending builds at this point.
    48  	state := makeState(true, true)
    49  	state.NeedBuild = false
    50  	activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty)
    51  	assertPendingParses(t, state)         // None, we have both packages already
    52  	assertPendingBuilds(t, state)         // Nothing because we don't need to build.
    53  	assert.Equal(t, 1, state.NumActive()) // Parses only
    54  }
    55  
    56  func TestAddParseDep(t *testing.T) {
    57  	// Tag state as not needing build. Any target that needs to be built to complete parse
    58  	// should still get queued for build though. Recall that we indicate this with :all...
    59  	state := makeState(true, true)
    60  	state.NeedBuild = false
    61  	activateTarget(state, nil, buildLabel("//package2:target2"), buildLabel("//package3:all"), false, empty, empty)
    62  	assertPendingBuilds(t, state, "//package2:target2") // Queued because it's needed for parse
    63  	assertPendingParses(t, state)                       // None, we have both packages already
    64  	assert.Equal(t, 2, state.NumActive())
    65  }
    66  
    67  func TestAddDepRescan(t *testing.T) {
    68  	// Simulate a post-build function and rescan.
    69  	state := makeState(true, true)
    70  	activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty)
    71  	assertPendingBuilds(t, state, "//package2:target2") // This is the only candidate target
    72  	assertPendingParses(t, state)                       // None, we have both packages already
    73  	assert.Equal(t, 6, state.NumActive())
    74  
    75  	// Add new target & dep to target1
    76  	target4 := makeTarget("//package1:target4")
    77  	state.Graph.Package("package1", "").AddTarget(target4)
    78  	state.Graph.AddTarget(target4)
    79  	target1 := state.Graph.TargetOrDie(buildLabel("//package1:target1"))
    80  	target1.AddDependency(buildLabel("//package1:target4"))
    81  	state.Graph.AddDependency(buildLabel("//package1:target1"), buildLabel("//package1:target4"))
    82  
    83  	// Fake test: calling this now should have no effect because rescan is not true.
    84  	addDep(state, buildLabel("//package1:target1"), core.OriginalTarget, false, false)
    85  	assertPendingParses(t, state)
    86  	assertPendingBuilds(t, state) // Note that the earlier call to assertPendingBuilds cleared it.
    87  
    88  	// Now running this should activate it
    89  	rescanDeps(state, map[*core.BuildTarget]struct{}{target1: {}})
    90  	assertPendingBuilds(t, state, "//package1:target4")
    91  	assertPendingParses(t, state)
    92  	assert.True(t, state.Graph.AllDependenciesResolved(target1))
    93  }
    94  
    95  func TestAddParseDepDeferred(t *testing.T) {
    96  	// Similar to TestAddParseDep but where we scan the package once and come back later because
    97  	// something else asserts a dependency on it.
    98  	state := makeState(true, true)
    99  	state.NeedBuild = false
   100  	assert.Equal(t, 1, state.NumActive())
   101  	activateTarget(state, nil, buildLabel("//package2:target2"), core.OriginalTarget, false, empty, empty)
   102  	assertPendingParses(t, state)
   103  	assertPendingBuilds(t, state) // Not yet.
   104  
   105  	// Now the undefer kicks off...
   106  	activateTarget(state, nil, buildLabel("//package2:target2"), buildLabel("//package1:all"), false, empty, empty)
   107  	assertPendingBuilds(t, state, "//package2:target2") // This time!
   108  	assertPendingParses(t, state)
   109  	assert.Equal(t, 2, state.NumActive())
   110  }
   111  
   112  func makeTarget(label string, deps ...string) *core.BuildTarget {
   113  	target := core.NewBuildTarget(core.ParseBuildLabel(label, ""))
   114  	for _, dep := range deps {
   115  		target.AddDependency(core.ParseBuildLabel(dep, ""))
   116  	}
   117  	return target
   118  }
   119  
   120  // makeState creates a new build state with optionally one or two packages in it.
   121  // Used in various tests above.
   122  func makeState(withPackage1, withPackage2 bool) *core.BuildState {
   123  	state := core.NewBuildState(5, nil, 4, core.DefaultConfiguration())
   124  	if withPackage1 {
   125  		pkg := core.NewPackage("package1")
   126  		state.Graph.AddPackage(pkg)
   127  		pkg.AddTarget(makeTarget("//package1:target1", "//package1:target2", "//package2:target1"))
   128  		pkg.AddTarget(makeTarget("//package1:target2", "//package2:target1"))
   129  		pkg.AddTarget(makeTarget("//package1:target3", "//package2:target2"))
   130  		state.Graph.AddTarget(pkg.Target("target1"))
   131  		state.Graph.AddTarget(pkg.Target("target2"))
   132  		state.Graph.AddTarget(pkg.Target("target3"))
   133  		addDeps(state.Graph, pkg)
   134  	}
   135  	if withPackage2 {
   136  		pkg := core.NewPackage("package2")
   137  		state.Graph.AddPackage(pkg)
   138  		pkg.AddTarget(makeTarget("//package2:target1", "//package2:target2", "//package1:target3"))
   139  		pkg.AddTarget(makeTarget("//package2:target2"))
   140  		state.Graph.AddTarget(pkg.Target("target1"))
   141  		state.Graph.AddTarget(pkg.Target("target2"))
   142  		addDeps(state.Graph, pkg)
   143  	}
   144  	return state
   145  }
   146  
   147  func addDeps(graph *core.BuildGraph, pkg *core.Package) {
   148  	for _, target := range pkg.AllTargets() {
   149  		for _, dep := range target.DeclaredDependencies() {
   150  			graph.AddDependency(target.Label, dep)
   151  		}
   152  	}
   153  }
   154  
   155  func assertPendingParses(t *testing.T, state *core.BuildState, targets ...string) {
   156  	state.Stop(1)
   157  	pending := []core.BuildLabel{}
   158  	for {
   159  		label, _, typ := state.NextTask()
   160  		if typ == core.Stop {
   161  			break
   162  		} else if typ != core.Parse && typ != core.SubincludeParse {
   163  			t.Errorf("Unexpected non-parse task")
   164  		} else {
   165  			pending = append(pending, label)
   166  		}
   167  	}
   168  	expected := []core.BuildLabel{}
   169  	for _, target := range targets {
   170  		expected = append(expected, core.ParseBuildLabel(target, ""))
   171  	}
   172  	assert.Equal(t, expected, pending)
   173  }
   174  
   175  func assertPendingBuilds(t *testing.T, state *core.BuildState, targets ...string) {
   176  	state.Stop(1)
   177  	pending := []core.BuildLabel{}
   178  	for {
   179  		label, _, typ := state.NextTask()
   180  		if typ == core.Stop {
   181  			break
   182  		} else if typ != core.Build && typ != core.SubincludeBuild {
   183  			t.Errorf("Unexpected non-build task")
   184  		} else {
   185  			pending = append(pending, label)
   186  		}
   187  	}
   188  	expected := []core.BuildLabel{}
   189  	for _, target := range targets {
   190  		expected = append(expected, core.ParseBuildLabel(target, ""))
   191  	}
   192  	assert.Equal(t, expected, pending)
   193  }
   194  
   195  func buildLabel(bl string) core.BuildLabel {
   196  	return core.ParseBuildLabel(bl, "")
   197  }