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 android
16
17import (
18	"errors"
19	"fmt"
20	"reflect"
21	"strings"
22	"testing"
23)
24
25type strsTestCase struct {
26	in  []string
27	out string
28	err []error
29}
30
31var commonValidatePathTestCases = []strsTestCase{
32	{
33		in:  []string{""},
34		out: "",
35	},
36	{
37		in:  []string{"a/b"},
38		out: "a/b",
39	},
40	{
41		in:  []string{"a/b", "c"},
42		out: "a/b/c",
43	},
44	{
45		in:  []string{"a/.."},
46		out: ".",
47	},
48	{
49		in:  []string{"."},
50		out: ".",
51	},
52	{
53		in:  []string{".."},
54		out: "",
55		err: []error{errors.New("Path is outside directory: ..")},
56	},
57	{
58		in:  []string{"../a"},
59		out: "",
60		err: []error{errors.New("Path is outside directory: ../a")},
61	},
62	{
63		in:  []string{"b/../../a"},
64		out: "",
65		err: []error{errors.New("Path is outside directory: ../a")},
66	},
67	{
68		in:  []string{"/a"},
69		out: "",
70		err: []error{errors.New("Path is outside directory: /a")},
71	},
72	{
73		in:  []string{"a", "../b"},
74		out: "",
75		err: []error{errors.New("Path is outside directory: ../b")},
76	},
77	{
78		in:  []string{"a", "b/../../c"},
79		out: "",
80		err: []error{errors.New("Path is outside directory: ../c")},
81	},
82	{
83		in:  []string{"a", "./.."},
84		out: "",
85		err: []error{errors.New("Path is outside directory: ..")},
86	},
87}
88
89var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
90	{
91		in:  []string{"$host/../$a"},
92		out: "$a",
93	},
94}...)
95
96var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
97	{
98		in:  []string{"$host/../$a"},
99		out: "",
100		err: []error{errors.New("Path contains invalid character($): $host/../$a")},
101	},
102	{
103		in:  []string{"$host/.."},
104		out: "",
105		err: []error{errors.New("Path contains invalid character($): $host/..")},
106	},
107}...)
108
109func TestValidateSafePath(t *testing.T) {
110	for _, testCase := range validateSafePathTestCases {
111		ctx := &configErrorWrapper{}
112		out := validateSafePath(ctx, testCase.in...)
113		check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
114	}
115}
116
117func TestValidatePath(t *testing.T) {
118	for _, testCase := range validatePathTestCases {
119		ctx := &configErrorWrapper{}
120		out := validatePath(ctx, testCase.in...)
121		check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
122	}
123}
124
125func TestOptionalPath(t *testing.T) {
126	var path OptionalPath
127	checkInvalidOptionalPath(t, path)
128
129	path = OptionalPathForPath(nil)
130	checkInvalidOptionalPath(t, path)
131}
132
133func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
134	if path.Valid() {
135		t.Errorf("Uninitialized OptionalPath should not be valid")
136	}
137	if path.String() != "" {
138		t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
139	}
140	defer func() {
141		if r := recover(); r == nil {
142			t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
143		}
144	}()
145	path.Path()
146}
147
148func check(t *testing.T, testType, testString string,
149	got interface{}, err []error,
150	expected interface{}, expectedErr []error) {
151
152	printedTestCase := false
153	e := func(s string, expected, got interface{}) {
154		if !printedTestCase {
155			t.Errorf("test case %s: %s", testType, testString)
156			printedTestCase = true
157		}
158		t.Errorf("incorrect %s", s)
159		t.Errorf("  expected: %s", p(expected))
160		t.Errorf("       got: %s", p(got))
161	}
162
163	if !reflect.DeepEqual(expectedErr, err) {
164		e("errors:", expectedErr, err)
165	}
166
167	if !reflect.DeepEqual(expected, got) {
168		e("output:", expected, got)
169	}
170}
171
172func p(in interface{}) string {
173	if v, ok := in.([]interface{}); ok {
174		s := make([]string, len(v))
175		for i := range v {
176			s[i] = fmt.Sprintf("%#v", v[i])
177		}
178		return "[" + strings.Join(s, ", ") + "]"
179	} else {
180		return fmt.Sprintf("%#v", in)
181	}
182}
183