1// Copyright 2015 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
15package blueprint
16
17import (
18	"reflect"
19	"testing"
20)
21
22var (
23	testModuleA = &moduleInfo{variantName: "testModuleA"}
24	testModuleB = &moduleInfo{variantName: "testModuleB"}
25	testModuleC = &moduleInfo{variantName: "testModuleC"}
26	testModuleD = &moduleInfo{variantName: "testModuleD"}
27	testModuleE = &moduleInfo{variantName: "testModuleE"}
28	testModuleF = &moduleInfo{variantName: "testModuleF"}
29)
30
31var spliceModulesTestCases = []struct {
32	in         []*moduleInfo
33	at         int
34	with       []*moduleInfo
35	out        []*moduleInfo
36	outAt      int
37	reallocate bool
38}{
39	{
40		// Insert at the beginning
41		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC},
42		at:         0,
43		with:       []*moduleInfo{testModuleD, testModuleE},
44		out:        []*moduleInfo{testModuleD, testModuleE, testModuleB, testModuleC},
45		outAt:      1,
46		reallocate: true,
47	},
48	{
49		// Insert in the middle
50		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC},
51		at:         1,
52		with:       []*moduleInfo{testModuleD, testModuleE},
53		out:        []*moduleInfo{testModuleA, testModuleD, testModuleE, testModuleC},
54		outAt:      2,
55		reallocate: true,
56	},
57	{
58		// Insert at the end
59		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC},
60		at:         2,
61		with:       []*moduleInfo{testModuleD, testModuleE},
62		out:        []*moduleInfo{testModuleA, testModuleB, testModuleD, testModuleE},
63		outAt:      3,
64		reallocate: true,
65	},
66	{
67		// Insert over a single element
68		in:         []*moduleInfo{testModuleA},
69		at:         0,
70		with:       []*moduleInfo{testModuleD, testModuleE},
71		out:        []*moduleInfo{testModuleD, testModuleE},
72		outAt:      1,
73		reallocate: true,
74	},
75	{
76		// Insert at the beginning without reallocating
77		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC, nil}[0:3],
78		at:         0,
79		with:       []*moduleInfo{testModuleD, testModuleE},
80		out:        []*moduleInfo{testModuleD, testModuleE, testModuleB, testModuleC},
81		outAt:      1,
82		reallocate: false,
83	},
84	{
85		// Insert in the middle without reallocating
86		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC, nil}[0:3],
87		at:         1,
88		with:       []*moduleInfo{testModuleD, testModuleE},
89		out:        []*moduleInfo{testModuleA, testModuleD, testModuleE, testModuleC},
90		outAt:      2,
91		reallocate: false,
92	},
93	{
94		// Insert at the end without reallocating
95		in:         []*moduleInfo{testModuleA, testModuleB, testModuleC, nil}[0:3],
96		at:         2,
97		with:       []*moduleInfo{testModuleD, testModuleE},
98		out:        []*moduleInfo{testModuleA, testModuleB, testModuleD, testModuleE},
99		outAt:      3,
100		reallocate: false,
101	},
102	{
103		// Insert over a single element without reallocating
104		in:         []*moduleInfo{testModuleA, nil}[0:1],
105		at:         0,
106		with:       []*moduleInfo{testModuleD, testModuleE},
107		out:        []*moduleInfo{testModuleD, testModuleE},
108		outAt:      1,
109		reallocate: false,
110	},
111}
112
113func TestSpliceModules(t *testing.T) {
114	for _, testCase := range spliceModulesTestCases {
115		in := make([]*moduleInfo, len(testCase.in), cap(testCase.in))
116		copy(in, testCase.in)
117		origIn := in
118		got, gotAt := spliceModules(in, testCase.at, testCase.with)
119		if !reflect.DeepEqual(got, testCase.out) {
120			t.Errorf("test case: %v, %v -> %v", testCase.in, testCase.at, testCase.with)
121			t.Errorf("incorrect output:")
122			t.Errorf("  expected: %v", testCase.out)
123			t.Errorf("       got: %v", got)
124		}
125		if gotAt != testCase.outAt {
126			t.Errorf("test case: %v, %v -> %v", testCase.in, testCase.at, testCase.with)
127			t.Errorf("incorrect index:")
128			t.Errorf("  expected: %d", testCase.outAt)
129			t.Errorf("       got: %d", gotAt)
130		}
131		if sameArray(origIn, got) != !testCase.reallocate {
132			t.Errorf("test case: %v, %v -> %v", testCase.in, testCase.at, testCase.with)
133			not := ""
134			if !testCase.reallocate {
135				not = " not"
136			}
137			t.Errorf("  expected to%s reallocate", not)
138		}
139	}
140}
141
142func sameArray(a, b []*moduleInfo) bool {
143	return &a[0:cap(a)][cap(a)-1] == &b[0:cap(b)][cap(b)-1]
144}
145