Home | History | Annotate | Download | only in blueprint
      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package blueprint
     16 
     17 import (
     18 	"bytes"
     19 	"testing"
     20 )
     21 
     22 type Walker interface {
     23 	Walk() bool
     24 }
     25 
     26 type fooModule struct {
     27 	SimpleName
     28 	properties struct {
     29 		Deps []string
     30 		Foo  string
     31 	}
     32 }
     33 
     34 func newFooModule() (Module, []interface{}) {
     35 	m := &fooModule{}
     36 	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
     37 }
     38 
     39 func (f *fooModule) GenerateBuildActions(ModuleContext) {
     40 }
     41 
     42 func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
     43 	return f.properties.Deps
     44 }
     45 
     46 func (f *fooModule) Foo() string {
     47 	return f.properties.Foo
     48 }
     49 
     50 func (f *fooModule) Walk() bool {
     51 	return true
     52 }
     53 
     54 type barModule struct {
     55 	SimpleName
     56 	properties struct {
     57 		Deps []string
     58 		Bar  bool
     59 	}
     60 }
     61 
     62 func newBarModule() (Module, []interface{}) {
     63 	m := &barModule{}
     64 	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
     65 }
     66 
     67 func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
     68 	return b.properties.Deps
     69 }
     70 
     71 func (b *barModule) GenerateBuildActions(ModuleContext) {
     72 }
     73 
     74 func (b *barModule) Bar() bool {
     75 	return b.properties.Bar
     76 }
     77 
     78 func (b *barModule) Walk() bool {
     79 	return false
     80 }
     81 
     82 func TestContextParse(t *testing.T) {
     83 	ctx := NewContext()
     84 	ctx.RegisterModuleType("foo_module", newFooModule)
     85 	ctx.RegisterModuleType("bar_module", newBarModule)
     86 
     87 	r := bytes.NewBufferString(`
     88 		foo_module {
     89 	        name: "MyFooModule",
     90 			deps: ["MyBarModule"],
     91 		}
     92 
     93 		bar_module {
     94 	        name: "MyBarModule",
     95 		}
     96 	`)
     97 
     98 	_, _, errs := ctx.parse(".", "Blueprint", r, nil)
     99 	if len(errs) > 0 {
    100 		t.Errorf("unexpected parse errors:")
    101 		for _, err := range errs {
    102 			t.Errorf("  %s", err)
    103 		}
    104 		t.FailNow()
    105 	}
    106 
    107 	errs = ctx.ResolveDependencies(nil)
    108 	if len(errs) > 0 {
    109 		t.Errorf("unexpected dep errors:")
    110 		for _, err := range errs {
    111 			t.Errorf("  %s", err)
    112 		}
    113 		t.FailNow()
    114 	}
    115 }
    116 
    117 // |---B===D       - represents a non-walkable edge
    118 // A               = represents a walkable edge
    119 // |===C---E===G
    120 //     |       |   A should not be visited because it's the root node.
    121 //     |===F===|   B, D and E should not be walked.
    122 func TestWalkDeps(t *testing.T) {
    123 	ctx := NewContext()
    124 	ctx.MockFileSystem(map[string][]byte{
    125 		"Blueprints": []byte(`
    126 			foo_module {
    127 			    name: "A",
    128 			    deps: ["B", "C"],
    129 			}
    130 			
    131 			bar_module {
    132 			    name: "B",
    133 			    deps: ["D"],
    134 			}
    135 			
    136 			foo_module {
    137 			    name: "C",
    138 			    deps: ["E", "F"],
    139 			}
    140 			
    141 			foo_module {
    142 			    name: "D",
    143 			}
    144 			
    145 			bar_module {
    146 			    name: "E",
    147 			    deps: ["G"],
    148 			}
    149 			
    150 			foo_module {
    151 			    name: "F",
    152 			    deps: ["G"],
    153 			}
    154 			
    155 			foo_module {
    156 			    name: "G",
    157 			}
    158 		`),
    159 	})
    160 
    161 	ctx.RegisterModuleType("foo_module", newFooModule)
    162 	ctx.RegisterModuleType("bar_module", newBarModule)
    163 	_, errs := ctx.ParseBlueprintsFiles("Blueprints")
    164 	if len(errs) > 0 {
    165 		t.Errorf("unexpected parse errors:")
    166 		for _, err := range errs {
    167 			t.Errorf("  %s", err)
    168 		}
    169 		t.FailNow()
    170 	}
    171 
    172 	errs = ctx.ResolveDependencies(nil)
    173 	if len(errs) > 0 {
    174 		t.Errorf("unexpected dep errors:")
    175 		for _, err := range errs {
    176 			t.Errorf("  %s", err)
    177 		}
    178 		t.FailNow()
    179 	}
    180 
    181 	var outputDown string
    182 	var outputUp string
    183 	topModule := ctx.modulesFromName("A")[0]
    184 	ctx.walkDeps(topModule,
    185 		func(dep depInfo, parent *moduleInfo) bool {
    186 			if dep.module.logicModule.(Walker).Walk() {
    187 				outputDown += ctx.ModuleName(dep.module.logicModule)
    188 				return true
    189 			}
    190 			return false
    191 		},
    192 		func(dep depInfo, parent *moduleInfo) {
    193 			if dep.module.logicModule.(Walker).Walk() {
    194 				outputUp += ctx.ModuleName(dep.module.logicModule)
    195 			}
    196 		})
    197 	if outputDown != "CFG" {
    198 		t.Fatalf("unexpected walkDeps behaviour: %s\ndown should be: CFG", outputDown)
    199 	}
    200 	if outputUp != "GFC" {
    201 		t.Fatalf("unexpected walkDeps behaviour: %s\nup should be: GFC", outputUp)
    202 	}
    203 }
    204