...

Source file src/github.com/bazelbuild/buildtools/edit/edit_test.go

Documentation: github.com/bazelbuild/buildtools/edit

     1  /*
     2  Copyright 2016 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package edit
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"regexp"
    26  	"strings"
    27  	"testing"
    28  
    29  	"github.com/bazelbuild/buildtools/build"
    30  )
    31  
    32  var parseLabelTests = []struct {
    33  	in   string
    34  	repo string
    35  	pkg  string
    36  	rule string
    37  }{
    38  	{"//devtools/buildozer:rule", "", "devtools/buildozer", "rule"},
    39  	{"devtools/buildozer:rule", "", "devtools/buildozer", "rule"},
    40  	{"//devtools/buildozer", "", "devtools/buildozer", "buildozer"},
    41  	{"//base", "", "base", "base"},
    42  	{"//base:", "", "base", "base"},
    43  	{"@r//devtools/buildozer:rule", "r", "devtools/buildozer", "rule"},
    44  	{"@r//devtools/buildozer", "r", "devtools/buildozer", "buildozer"},
    45  	{"@r//base", "r", "base", "base"},
    46  	{"@r//base:", "r", "base", "base"},
    47  	{"@foo", "foo", "", "foo"},
    48  	{":label", "", "", "label"},
    49  	{"label", "", "", "label"},
    50  	{"/abs/path/to/WORKSPACE:rule", "", "/abs/path/to/WORKSPACE", "rule"},
    51  }
    52  
    53  func TestParseLabel(t *testing.T) {
    54  	for i, tt := range parseLabelTests {
    55  		repo, pkg, rule := ParseLabel(tt.in)
    56  		if repo != tt.repo || pkg != tt.pkg || rule != tt.rule {
    57  			t.Errorf("%d. ParseLabel(%q) => (%q, %q, %q), want (%q, %q, %q)",
    58  				i, tt.in, repo, pkg, rule, tt.repo, tt.pkg, tt.rule)
    59  		}
    60  	}
    61  }
    62  
    63  var shortenLabelTests = []struct {
    64  	in     string
    65  	pkg    string
    66  	result string
    67  }{
    68  	{"//devtools/buildozer:rule", "devtools/buildozer", ":rule"},
    69  	{"@//devtools/buildozer:rule", "devtools/buildozer", ":rule"},
    70  	{"//devtools/buildozer:rule", "devtools", "//devtools/buildozer:rule"},
    71  	{"//base:rule", "devtools", "//base:rule"},
    72  	{"//base:base", "devtools", "//base"},
    73  	{"//base", "base", ":base"},
    74  	{"//devtools/buildozer:buildozer", "", "//devtools/buildozer"},
    75  	{"@r//devtools/buildozer:buildozer", "devtools/buildozer", "@r//devtools/buildozer"},
    76  	{"@r//devtools/buildozer", "devtools/buildozer", "@r//devtools/buildozer"},
    77  	{"@r//devtools", "devtools", "@r//devtools"},
    78  	{"@r:rule", "", "@r:rule"},
    79  	{"@r", "", "@r"},
    80  	{"@foo//:foo", "", "@foo"},
    81  	{"@foo//devtools:foo", "", "@foo//devtools:foo"},
    82  	{"@foo//devtools:foo", "devtools", "@foo//devtools:foo"},
    83  	{"@foo//foo:foo", "", "@foo//foo"},
    84  	{":local", "", ":local"},
    85  	{"something else", "", "something else"},
    86  	{"/path/to/file", "path/to", "/path/to/file"},
    87  }
    88  
    89  func TestShortenLabel(t *testing.T) {
    90  	for i, tt := range shortenLabelTests {
    91  		result := ShortenLabel(tt.in, tt.pkg)
    92  		if result != tt.result {
    93  			t.Errorf("%d. ShortenLabel(%q, %q) => %q, want %q",
    94  				i, tt.in, tt.pkg, result, tt.result)
    95  		}
    96  	}
    97  }
    98  
    99  var labelsEqualTests = []struct {
   100  	label1   string
   101  	label2   string
   102  	pkg      string
   103  	expected bool
   104  }{
   105  	{"//devtools/buildozer:rule", "rule", "devtools/buildozer", true},
   106  	{"//devtools/buildozer:rule", "rule:jar", "devtools", false},
   107  }
   108  
   109  func TestLabelsEqual(t *testing.T) {
   110  	for i, tt := range labelsEqualTests {
   111  		if got := LabelsEqual(tt.label1, tt.label2, tt.pkg); got != tt.expected {
   112  			t.Errorf("%d. LabelsEqual(%q, %q, %q) => %v, want %v",
   113  				i, tt.label1, tt.label2, tt.pkg, got, tt.expected)
   114  		}
   115  	}
   116  }
   117  
   118  var splitOnSpacesTests = []struct {
   119  	in  string
   120  	out []string
   121  }{
   122  	{"a", []string{"a"}},
   123  	{"  abc def ", []string{"abc", "def"}},
   124  	{`  abc\ def `, []string{"abc def"}},
   125  	{"  abc def\nghi", []string{"abc", "def", "ghi"}},
   126  }
   127  
   128  func TestSplitOnSpaces(t *testing.T) {
   129  	for i, tt := range splitOnSpacesTests {
   130  		result := SplitOnSpaces(tt.in)
   131  		if !reflect.DeepEqual(result, tt.out) {
   132  			t.Errorf("%d. SplitOnSpaces(%q) => %q, want %q",
   133  				i, tt.in, result, tt.out)
   134  		}
   135  	}
   136  }
   137  
   138  func TestInsertLoad(t *testing.T) {
   139  	tests := []struct{ input, expected string }{
   140  		{``, `load("location", "symbol")`},
   141  		{`load("location", "symbol")`, `load("location", "symbol")`},
   142  		{`load("location", "other", "symbol")`, `load("location", "other", "symbol")`},
   143  		{`load("location", "other")`, `load("location", "other", "symbol")`},
   144  		{
   145  			`load("other loc", "symbol")`,
   146  			`load("location", "symbol")
   147  load("other loc", "symbol")`,
   148  		},
   149  	}
   150  
   151  	for _, tst := range tests {
   152  		bld, err := build.Parse("BUILD", []byte(tst.input))
   153  		if err != nil {
   154  			t.Error(err)
   155  			continue
   156  		}
   157  		bld.Stmt = InsertLoad(bld.Stmt, "location", []string{"symbol"}, []string{"symbol"})
   158  		got := strings.TrimSpace(string(build.Format(bld)))
   159  		if got != tst.expected {
   160  			t.Errorf("maybeInsertLoad(%s): got %s, expected %s", tst.input, got, tst.expected)
   161  		}
   162  	}
   163  }
   164  
   165  func TestReplaceLoad(t *testing.T) {
   166  	tests := []struct{ input, expected string }{
   167  		{
   168  			``,
   169  			`load("new_location", "symbol")`,
   170  		},
   171  		{
   172  			`load("location", "symbol")`,
   173  			`load("new_location", "symbol")`,
   174  		},
   175  		{
   176  			`load("location", "other", "symbol")`,
   177  			`load("location", "other")
   178  load("new_location", "symbol")`,
   179  		},
   180  		{
   181  			`load("location", symbol = "other")`,
   182  			`load("new_location", "symbol")`,
   183  		},
   184  		{
   185  			`load("other loc", "symbol")
   186  load("location", "symbol")`,
   187  			`load("new_location", "symbol")`,
   188  		},
   189  	}
   190  
   191  	for _, tst := range tests {
   192  		bld, err := build.Parse("BUILD", []byte(tst.input))
   193  		if err != nil {
   194  			t.Error(err)
   195  			continue
   196  		}
   197  		bld.Stmt = ReplaceLoad(bld.Stmt, "new_location", []string{"symbol"}, []string{"symbol"})
   198  		got := strings.TrimSpace(string(build.Format(bld)))
   199  		if got != tst.expected {
   200  			t.Errorf("maybeReplaceLoad(%s): got %s, expected %s", tst.input, got, tst.expected)
   201  		}
   202  	}
   203  }
   204  
   205  func TestAddValueToListAttribute(t *testing.T) {
   206  	tests := []struct{ input, expected string }{
   207  		{`rule(name="rule")`, `rule(name="rule", attr=["foo"])`},
   208  		{`rule(name="rule", attr=["foo"])`, `rule(name="rule", attr=["foo"])`},
   209  		{`rule(name="rule", attr=IDENT)`, `rule(name="rule", attr=IDENT+["foo"])`},
   210  		{`rule(name="rule", attr=["foo"] + IDENT)`, `rule(name="rule", attr=["foo"] + IDENT)`},
   211  		{`rule(name="rule", attr=["bar"] + IDENT)`, `rule(name="rule", attr=["bar", "foo"] + IDENT)`},
   212  		{`rule(name="rule", attr=IDENT + ["foo"])`, `rule(name="rule", attr=IDENT + ["foo"])`},
   213  		{`rule(name="rule", attr=IDENT + ["bar"])`, `rule(name="rule", attr=IDENT + ["bar", "foo"])`},
   214  	}
   215  
   216  	for _, tst := range tests {
   217  		bld, err := build.Parse("BUILD", []byte(tst.input))
   218  		if err != nil {
   219  			t.Error(err)
   220  			continue
   221  		}
   222  		rule := bld.RuleAt(1)
   223  		AddValueToListAttribute(rule, "attr", "", &build.StringExpr{Value: "foo"}, nil)
   224  		got := strings.TrimSpace(string(build.Format(bld)))
   225  
   226  		wantBld, err := build.Parse("BUILD", []byte(tst.expected))
   227  		if err != nil {
   228  			t.Error(err)
   229  			continue
   230  		}
   231  		want := strings.TrimSpace(string(build.Format(wantBld)))
   232  		if got != want {
   233  			t.Errorf("AddValueToListAttribute(%s): got %s, expected %s", tst.input, got, want)
   234  		}
   235  	}
   236  }
   237  
   238  func TestSelectListsIntersection(t *testing.T) {
   239  	tests := []struct {
   240  		input    string
   241  		expected []build.Expr
   242  	}{
   243  		{`rule(
   244  			name = "rule",
   245  			attr = select()
   246  		)`, nil},
   247  		{`rule(
   248  			name = "rule",
   249  			attr = select({})
   250  		)`, nil},
   251  		{`rule(
   252  			name = "rule",
   253  			attr = select(CONFIGS)
   254  		)`, nil},
   255  		{`rule(
   256  			name = "rule",
   257  			attr = select({
   258  				"config": "string",
   259  				"DEFAULT": "default"
   260  			})
   261  		)`, nil},
   262  		{`rule(
   263  			name = "rule",
   264  			attr = select({
   265  				"config": LIST,
   266  				"DEFAULT": DEFAULT
   267  			})
   268  		)`, nil},
   269  		{`rule(
   270  			name = "rule",
   271  			attr = select({
   272  				"config": ":1 :2 :3".split(" "),
   273  				"DEFAULT": ":2 :3".split(" ")
   274  			})
   275  		)`, nil},
   276  		{`rule(
   277  			name = "rule",
   278  			attr = select({
   279  				"config1": [":1"],
   280  				"config2": [":2"],
   281  				"DEFAULT": []
   282  			})
   283  		)`, []build.Expr{}},
   284  		{`rule(
   285  			name = "rule",
   286  			attr = select({
   287  				"config1": [],
   288  				"config2": [":1"],
   289  				"DEFAULT": [":1"]
   290  			})
   291  		)`, []build.Expr{}},
   292  		{`rule(
   293  			name = "rule",
   294  			attr = select({
   295  				"config1": [":1", ":2", ":3"],
   296  				"config2": [":2"],
   297  				"config3": [":2", ":3"],
   298  				"DEFAULT": [":1", ":2"]
   299  			})
   300  		)`, []build.Expr{&build.StringExpr{Value: ":2"}}},
   301  		{`rule(
   302  			name = "rule",
   303  			attr = select({
   304  				"config1": [":4", ":3", ":1", ":5", ":2", ":6"],
   305  				"config2": [":5", ":2", ":6", ":1"],
   306  				"config3": [":1", ":2", ":3", ":4", ":5", ":6"],
   307  				"config4": [":2", ":1"],
   308  				"DEFAULT": [":3", ":4", ":1", ":2"]
   309  			})
   310  		)`, []build.Expr{&build.StringExpr{Value: ":1"}, &build.StringExpr{Value: ":2"}}},
   311  	}
   312  
   313  	for _, tst := range tests {
   314  		bld, err := build.Parse("BUILD", []byte(tst.input))
   315  		if err != nil {
   316  			t.Error(err)
   317  			continue
   318  		}
   319  		rule := bld.RuleAt(1)
   320  
   321  		got := SelectListsIntersection(rule.Attr("attr").(*build.CallExpr), "")
   322  		errStr := fmt.Sprintf("TestSelectListsIntersection(%s): got %s, expected %s", tst.input, got, tst.expected)
   323  
   324  		if len(got) != len(tst.expected) {
   325  			t.Error(errStr)
   326  		}
   327  
   328  		for i := range got {
   329  			if got[i].(*build.StringExpr).Value != tst.expected[i].(*build.StringExpr).Value {
   330  				t.Error(errStr)
   331  			}
   332  		}
   333  	}
   334  }
   335  
   336  func TestRemoveEmptySelectsAndConcatLists(t *testing.T) {
   337  	tests := []struct{ input, expected string }{
   338  		{`rule(
   339  			name = "rule",
   340  			attr = select({
   341  				"config1": [],
   342  				"config2": [],
   343  				"DEFAULT": []
   344  			})
   345  		)`, `rule(
   346  			name = "rule",
   347  			attr = []
   348  		)`},
   349  		{`rule(
   350  			name = "rule",
   351  			attr = select({}) + select() + select({
   352  				"config1": [],
   353  				"config2": [],
   354  				"DEFAULT": []
   355  			})
   356  		)`, `rule(
   357  			name = "rule",
   358  			attr = []
   359  		)`},
   360  		{`rule(
   361  			name = "rule",
   362  			attr = select({
   363  				"config1": [],
   364  				"config2": [],
   365  				"DEFAULT": []
   366  			}) + select(CONFIGS)
   367  		)`, `rule(
   368  			name = "rule",
   369  			attr = select(CONFIGS)
   370  		)`},
   371  		{`rule(
   372  			name = "rule",
   373  			attr = [":1"] + select({
   374  				"config1": [],
   375  				"config2": [],
   376  				"DEFAULT": []
   377  			}) + [":2"]
   378  		)`, `rule(
   379  			name = "rule",
   380  			attr = [":1", ":2"]
   381  		)`},
   382  		{`rule(
   383  			name = "rule",
   384  			attr = [":1"] + select({
   385  				"config1": [],
   386  				"config2": [],
   387  				"DEFAULT": []
   388  			}) + LIST + [":2"]
   389  		)`, `rule(
   390  			name = "rule",
   391  			attr = [":1"] + LIST + [":2"]
   392  		)`},
   393  		{`rule(
   394  			name = "rule",
   395  			attr = [":1"] + [":2", ":3"] + select({
   396  				"config1": [":4"],
   397  				"config2": [],
   398  				"DEFAULT": []
   399  			}) + []
   400  		)`, `rule(
   401  			name = "rule",
   402  			attr = [":1", ":2", ":3"] + select({
   403  				"config1": [":4"],
   404  				"config2": [],
   405  				"DEFAULT": []
   406  			})
   407  		)`},
   408  		{`rule(
   409  			name = "rule",
   410  			attr = [":1"] + [":2", ":3"] + select({
   411  				"config1": [":4"],
   412  				"config2": [],
   413  				"DEFAULT": []
   414  			}) + [] + select({
   415  				"config": LIST,
   416  				"DEFAULT": DEFAULT,
   417  			})
   418  		)`, `rule(
   419  			name = "rule",
   420  			attr = [":1", ":2", ":3"] + select({
   421  				"config1": [":4"],
   422  				"config2": [],
   423  				"DEFAULT": []
   424  			}) + select({
   425  				"config": LIST,
   426  				"DEFAULT": DEFAULT,
   427  			})
   428  		)`},
   429  	}
   430  
   431  	for _, tst := range tests {
   432  		bld, err := build.Parse("BUILD", []byte(tst.input))
   433  		if err != nil {
   434  			t.Error(err)
   435  			continue
   436  		}
   437  		rule := bld.RuleAt(1)
   438  		rule.SetAttr("attr", RemoveEmptySelectsAndConcatLists(rule.Attr("attr")))
   439  		got := strings.TrimSpace(string(build.Format(bld)))
   440  
   441  		wantBld, err := build.Parse("BUILD", []byte(tst.expected))
   442  		if err != nil {
   443  			t.Error(err)
   444  			continue
   445  		}
   446  		want := strings.TrimSpace(string(build.Format(wantBld)))
   447  		if got != want {
   448  			t.Errorf("RemoveEmptySelectsAndConcatLists(%s):\n got: %s,\n expected: %s", tst.input, got, want)
   449  		}
   450  	}
   451  }
   452  
   453  func TestResolveAttr(t *testing.T) {
   454  	tests := []struct{ input, expected string }{
   455  		{`rule(
   456  			name = "rule",
   457  			attr = select({
   458  				"config1": [":1"],
   459  				"config2": [":1"],
   460  				"DEFAULT": [":1"]
   461  			})
   462  		)`, `rule(
   463  			name = "rule",
   464  			attr = [":1"]
   465  		)`},
   466  		{`rule(
   467  			name = "rule",
   468  			attr = select({
   469  				"config1": [":1"],
   470  				"config2": [":1"],
   471  				"DEFAULT": [":1"]
   472  			}) + select() + select({})
   473  		)`, `rule(
   474  			name = "rule",
   475  			attr = [":1"]
   476  		)`},
   477  		{`rule(
   478  			name = "rule",
   479  			attr = select({
   480  				"config1": [":1"],
   481  				"config2": [":1"],
   482  				"DEFAULT": [":1"]
   483  			}) + LIST
   484  		)`, `rule(
   485  			name = "rule",
   486  			attr = LIST + [":1"]
   487  		)`},
   488  		{`rule(
   489  			name = "rule",
   490  			attr = select({
   491  				"config1": [":1"],
   492  				"config2": [":1"],
   493  				"DEFAULT": [":1"]
   494  			}) + select({
   495  				"config": LIST,
   496  				"DEFAULT": DEFAULT
   497  			}) + select({
   498  				"config": ":2 :3".split(" "),
   499  				"DEFAULT": ":3".split(" ")
   500  			})
   501  		)`, `rule(
   502  			name = "rule",
   503  			attr = select({
   504  				"config": LIST,
   505  				"DEFAULT": DEFAULT
   506  			}) + select({
   507  				"config": ":2 :3".split(" "),
   508  				"DEFAULT": ":3".split(" ")
   509  			}) + [":1"]
   510  		)`},
   511  		{`rule(
   512  			name = "rule",
   513  			attr = [":1"] + select({
   514  				"config1": [":2"],
   515  				"config2": [":2"],
   516  				"DEFAULT": [":2"]
   517  			}) + [":3"] + select({
   518  				"config1": [":4", ":2"],
   519  				"DEFAULT": [":2"]
   520  			})
   521  		)`, `rule(
   522  			name = "rule",
   523  			attr = [":1", ":2", ":3"] + select({
   524  				"config1": [":4"],
   525  				"DEFAULT": []
   526  			})
   527  		)`},
   528  		{`rule(
   529  			name = "rule",
   530  			attr = [":1"] + select({
   531  				"config1": [":2"],
   532  				"config2": [":2"],
   533  				"DEFAULT": [":2"]
   534  			}) + [":3"] + select({
   535  				"config1": [":4", ":2"],
   536  				"DEFAULT": [":4", ":2"]
   537  			})
   538  		)`, `rule(
   539  			name = "rule",
   540  			attr = [":1", ":2", ":4", ":3"]
   541  		)`},
   542  	}
   543  
   544  	for _, tst := range tests {
   545  		bld, err := build.Parse("BUILD", []byte(tst.input))
   546  		if err != nil {
   547  			t.Error(err)
   548  			continue
   549  		}
   550  		rule := bld.RuleAt(1)
   551  		ResolveAttr(rule, "attr", "")
   552  		got := strings.TrimSpace(string(build.Format(bld)))
   553  
   554  		wantBld, err := build.Parse("BUILD", []byte(tst.expected))
   555  		if err != nil {
   556  			t.Error(err)
   557  			continue
   558  		}
   559  		want := strings.TrimSpace(string(build.Format(wantBld)))
   560  		if got != want {
   561  			t.Errorf("ResolveAttr(%s):\n got: %s\n expected: %s", tst.input, got, want)
   562  		}
   563  	}
   564  }
   565  
   566  func TestListSubstitute(t *testing.T) {
   567  	tests := []struct {
   568  		desc, input, oldPattern, newTemplate, want string
   569  	}{
   570  		{
   571  			desc:        "no_match",
   572  			input:       `["abc"]`,
   573  			oldPattern:  `!!`,
   574  			newTemplate: `xx`,
   575  			want:        `["abc"]`,
   576  		}, {
   577  			desc:        "full_match",
   578  			input:       `["abc"]`,
   579  			oldPattern:  `.*`,
   580  			newTemplate: `xx`,
   581  			want:        `["xx"]`,
   582  		}, {
   583  			desc:        "partial_match",
   584  			input:       `["abcde"]`,
   585  			oldPattern:  `bcd`,
   586  			newTemplate: `xyz`,
   587  			want:        `["axyze"]`,
   588  		}, {
   589  			desc:        "number_group",
   590  			input:       `["abcde"]`,
   591  			oldPattern:  `a(bcd)`,
   592  			newTemplate: `$1 $1`,
   593  			want:        `["bcd bcde"]`,
   594  		}, {
   595  			desc:        "name_group",
   596  			input:       `["abcde"]`,
   597  			oldPattern:  `a(?P<x>bcd)`,
   598  			newTemplate: `$x $x`,
   599  			want:        `["bcd bcde"]`,
   600  		},
   601  	}
   602  
   603  	for _, tst := range tests {
   604  		t.Run(tst.desc, func(t *testing.T) {
   605  			f, err := build.ParseBuild("BUILD", []byte(tst.input))
   606  			if err != nil {
   607  				t.Fatalf("parse error: %v", err)
   608  			}
   609  			lst := f.Stmt[0]
   610  			oldRegexp, err := regexp.Compile(tst.oldPattern)
   611  			if err != nil {
   612  				t.Fatalf("error compiling regexp %q: %v", tst.oldPattern, err)
   613  			}
   614  			ListSubstitute(lst, oldRegexp, tst.newTemplate)
   615  			if got := build.FormatString(lst); got != tst.want {
   616  				t.Errorf("ListSubstitute(%q, %q, %q) = %q ; want %q", tst.input, tst.oldPattern, tst.newTemplate, got, tst.want)
   617  			}
   618  		})
   619  	}
   620  }
   621  
   622  func compareKeyValue(a, b build.Expr) bool {
   623  	if a == nil && b == nil {
   624  		return true
   625  	}
   626  	if a == nil || b == nil {
   627  		return false
   628  	}
   629  	aKeyVal := a.(*build.KeyValueExpr)
   630  	bKeyVal := b.(*build.KeyValueExpr)
   631  	return aKeyVal.Key.(*build.StringExpr).Value == bKeyVal.Key.(*build.StringExpr).Value &&
   632  		aKeyVal.Value.(*build.StringExpr).Value == bKeyVal.Value.(*build.StringExpr).Value
   633  }
   634  
   635  func TestDictionaryDelete(t *testing.T) {
   636  	tests := []struct {
   637  		input, expected string
   638  		expectedReturn  build.Expr
   639  	}{
   640  		{
   641  			`rule(attr = {"deletekey": "value"})`,
   642  			`rule(attr = {})`,
   643  			&build.KeyValueExpr{
   644  				Key:   &build.StringExpr{Value: "deletekey"},
   645  				Value: &build.StringExpr{Value: "value"},
   646  			},
   647  		}, {
   648  			`rule(attr = {"nodeletekey": "value", "deletekey": "value"})`,
   649  			`rule(attr = {"nodeletekey": "value"})`,
   650  			&build.KeyValueExpr{
   651  				Key:   &build.StringExpr{Value: "deletekey"},
   652  				Value: &build.StringExpr{Value: "value"},
   653  			},
   654  		}, {
   655  			`rule(attr = {"nodeletekey": "value"})`,
   656  			`rule(attr = {"nodeletekey": "value"})`,
   657  			nil,
   658  		},
   659  	}
   660  
   661  	for _, tst := range tests {
   662  		bld, err := build.ParseBuild("BUILD", []byte(tst.input))
   663  		if err != nil {
   664  			t.Error(err)
   665  			continue
   666  		}
   667  		rule := bld.RuleAt(1)
   668  		dict := rule.Call.List[0].(*build.AssignExpr).RHS.(*build.DictExpr)
   669  		returnVal := DictionaryDelete(dict, "deletekey")
   670  		got := strings.TrimSpace(string(build.Format(bld)))
   671  		wantBld, err := build.Parse("BUILD", []byte(tst.expected))
   672  		if err != nil {
   673  			t.Error(err)
   674  			continue
   675  		}
   676  		want := strings.TrimSpace(string(build.Format(wantBld)))
   677  		if got != want {
   678  			t.Errorf("TestDictionaryDelete(%s): got %s, expected %s", tst.input, got, want)
   679  		}
   680  		if !compareKeyValue(returnVal, tst.expectedReturn) {
   681  			t.Errorf("TestDictionaryDelete(%s): returned %v, expected %v", tst.input, returnVal, tst.expectedReturn)
   682  		}
   683  	}
   684  }
   685  
   686  func TestPackageDeclaration(t *testing.T) {
   687  	tests := []struct{ input, expected string }{
   688  		{``, `package(attr = "val")`},
   689  		{`"""Docstring."""
   690  
   691  load(":path.bzl", "x")
   692  
   693  # package() comes here
   694  
   695  x = 2`,
   696  			`"""Docstring."""
   697  
   698  load(":path.bzl", "x")
   699  
   700  # package() comes here
   701  
   702  package(attr = "val")
   703  
   704  x = 2`,
   705  		},
   706  	}
   707  
   708  	for _, tst := range tests {
   709  		bld, err := build.Parse("BUILD", []byte(tst.input))
   710  		if err != nil {
   711  			t.Error(err)
   712  			continue
   713  		}
   714  		pkg := PackageDeclaration(bld)
   715  		pkg.SetAttr("attr", &build.StringExpr{Value: "val"})
   716  		got := strings.TrimSpace(string(build.Format(bld)))
   717  		want := strings.TrimSpace(tst.expected)
   718  
   719  		if got != want {
   720  			t.Errorf("TestPackageDeclaration: got:\n%s\nexpected:\n%s", got, want)
   721  		}
   722  	}
   723  }
   724  
   725  type testCase struct {
   726  	inputRoot, inputTarget                       string
   727  	expectedBuildFile, expectedPkg, expectedRule string
   728  }
   729  
   730  func runTestInterpretLabelForWorkspaceLocation(t *testing.T, buildFileName string) {
   731  	tmp, err := ioutil.TempDir("", "")
   732  	if err != nil {
   733  		t.Fatal(err)
   734  	}
   735  	defer os.RemoveAll(tmp)
   736  	if err := os.MkdirAll(filepath.Join(tmp, "a", "b"), 0755); err != nil {
   737  		t.Fatal(err)
   738  	}
   739  	if err := ioutil.WriteFile(filepath.Join(tmp, "WORKSPACE"), nil, 0755); err != nil {
   740  		t.Fatal(err)
   741  	}
   742  	if err := ioutil.WriteFile(filepath.Join(tmp, buildFileName), nil, 0755); err != nil {
   743  		t.Fatal(err)
   744  	}
   745  	if err := ioutil.WriteFile(filepath.Join(tmp, "a", buildFileName), nil, 0755); err != nil {
   746  		t.Fatal(err)
   747  	}
   748  	if err := ioutil.WriteFile(filepath.Join(tmp, "a", "b", buildFileName), nil, 0755); err != nil {
   749  		t.Fatal(err)
   750  	}
   751  
   752  	for _, tc := range []testCase{
   753  		{tmp, "//", filepath.Join(tmp, buildFileName), "", "."},
   754  		{tmp, "//a", filepath.Join(tmp, "a", buildFileName), "a", "a"},
   755  		{tmp, "//a:a", filepath.Join(tmp, "a", buildFileName), "a", "a"},
   756  		{tmp, "//a/b", filepath.Join(tmp, "a", "b", buildFileName), "a/b", "b"},
   757  		{tmp, "//a/b:b", filepath.Join(tmp, "a", "b", buildFileName), "a/b", "b"},
   758  	} {
   759  		buildFile, _, pkg, rule := InterpretLabelForWorkspaceLocation(tc.inputRoot, tc.inputTarget)
   760  		if buildFile != tc.expectedBuildFile || pkg != tc.expectedPkg || rule != tc.expectedRule {
   761  			t.Errorf("InterpretLabelForWorkspaceLocation(%q, %q) = %q, %q, %q; want %q, %q, %q", tc.inputRoot, tc.inputTarget, buildFile, pkg, rule, tc.expectedBuildFile, tc.expectedPkg, tc.expectedRule)
   762  		}
   763  	}
   764  }
   765  
   766  func TestInterpretLabelForWorkspaceLocation(t *testing.T) {
   767  	runTestInterpretLabelForWorkspaceLocation(t, "BUILD")
   768  	runTestInterpretLabelForWorkspaceLocation(t, "BUILD.bazel")
   769  }
   770  

View as plain text