1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package webdav
6
7import (
8	"reflect"
9	"strings"
10	"testing"
11)
12
13func TestParseIfHeader(t *testing.T) {
14	// The "section x.y.z" test cases come from section x.y.z of the spec at
15	// http://www.webdav.org/specs/rfc4918.html
16	testCases := []struct {
17		desc  string
18		input string
19		want  ifHeader
20	}{{
21		"bad: empty",
22		``,
23		ifHeader{},
24	}, {
25		"bad: no parens",
26		`foobar`,
27		ifHeader{},
28	}, {
29		"bad: empty list #1",
30		`()`,
31		ifHeader{},
32	}, {
33		"bad: empty list #2",
34		`(a) (b c) () (d)`,
35		ifHeader{},
36	}, {
37		"bad: no list after resource #1",
38		`<foo>`,
39		ifHeader{},
40	}, {
41		"bad: no list after resource #2",
42		`<foo> <bar> (a)`,
43		ifHeader{},
44	}, {
45		"bad: no list after resource #3",
46		`<foo> (a) (b) <bar>`,
47		ifHeader{},
48	}, {
49		"bad: no-tag-list followed by tagged-list",
50		`(a) (b) <foo> (c)`,
51		ifHeader{},
52	}, {
53		"bad: unfinished list",
54		`(a`,
55		ifHeader{},
56	}, {
57		"bad: unfinished ETag",
58		`([b`,
59		ifHeader{},
60	}, {
61		"bad: unfinished Notted list",
62		`(Not a`,
63		ifHeader{},
64	}, {
65		"bad: double Not",
66		`(Not Not a)`,
67		ifHeader{},
68	}, {
69		"good: one list with a Token",
70		`(a)`,
71		ifHeader{
72			lists: []ifList{{
73				conditions: []Condition{{
74					Token: `a`,
75				}},
76			}},
77		},
78	}, {
79		"good: one list with an ETag",
80		`([a])`,
81		ifHeader{
82			lists: []ifList{{
83				conditions: []Condition{{
84					ETag: `a`,
85				}},
86			}},
87		},
88	}, {
89		"good: one list with three Nots",
90		`(Not a Not b Not [d])`,
91		ifHeader{
92			lists: []ifList{{
93				conditions: []Condition{{
94					Not:   true,
95					Token: `a`,
96				}, {
97					Not:   true,
98					Token: `b`,
99				}, {
100					Not:  true,
101					ETag: `d`,
102				}},
103			}},
104		},
105	}, {
106		"good: two lists",
107		`(a) (b)`,
108		ifHeader{
109			lists: []ifList{{
110				conditions: []Condition{{
111					Token: `a`,
112				}},
113			}, {
114				conditions: []Condition{{
115					Token: `b`,
116				}},
117			}},
118		},
119	}, {
120		"good: two Notted lists",
121		`(Not a) (Not b)`,
122		ifHeader{
123			lists: []ifList{{
124				conditions: []Condition{{
125					Not:   true,
126					Token: `a`,
127				}},
128			}, {
129				conditions: []Condition{{
130					Not:   true,
131					Token: `b`,
132				}},
133			}},
134		},
135	}, {
136		"section 7.5.1",
137		`<http://www.example.com/users/f/fielding/index.html>
138			(<urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6>)`,
139		ifHeader{
140			lists: []ifList{{
141				resourceTag: `http://www.example.com/users/f/fielding/index.html`,
142				conditions: []Condition{{
143					Token: `urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6`,
144				}},
145			}},
146		},
147	}, {
148		"section 7.5.2 #1",
149		`(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
150		ifHeader{
151			lists: []ifList{{
152				conditions: []Condition{{
153					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
154				}},
155			}},
156		},
157	}, {
158		"section 7.5.2 #2",
159		`<http://example.com/locked/>
160			(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
161		ifHeader{
162			lists: []ifList{{
163				resourceTag: `http://example.com/locked/`,
164				conditions: []Condition{{
165					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
166				}},
167			}},
168		},
169	}, {
170		"section 7.5.2 #3",
171		`<http://example.com/locked/member>
172			(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
173		ifHeader{
174			lists: []ifList{{
175				resourceTag: `http://example.com/locked/member`,
176				conditions: []Condition{{
177					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
178				}},
179			}},
180		},
181	}, {
182		"section 9.9.6",
183		`(<urn:uuid:fe184f2e-6eec-41d0-c765-01adc56e6bb4>)
184			(<urn:uuid:e454f3f3-acdc-452a-56c7-00a5c91e4b77>)`,
185		ifHeader{
186			lists: []ifList{{
187				conditions: []Condition{{
188					Token: `urn:uuid:fe184f2e-6eec-41d0-c765-01adc56e6bb4`,
189				}},
190			}, {
191				conditions: []Condition{{
192					Token: `urn:uuid:e454f3f3-acdc-452a-56c7-00a5c91e4b77`,
193				}},
194			}},
195		},
196	}, {
197		"section 9.10.8",
198		`(<urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>)`,
199		ifHeader{
200			lists: []ifList{{
201				conditions: []Condition{{
202					Token: `urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4`,
203				}},
204			}},
205		},
206	}, {
207		"section 10.4.6",
208		`(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
209			["I am an ETag"])
210			(["I am another ETag"])`,
211		ifHeader{
212			lists: []ifList{{
213				conditions: []Condition{{
214					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
215				}, {
216					ETag: `"I am an ETag"`,
217				}},
218			}, {
219				conditions: []Condition{{
220					ETag: `"I am another ETag"`,
221				}},
222			}},
223		},
224	}, {
225		"section 10.4.7",
226		`(Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
227			<urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)`,
228		ifHeader{
229			lists: []ifList{{
230				conditions: []Condition{{
231					Not:   true,
232					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
233				}, {
234					Token: `urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092`,
235				}},
236			}},
237		},
238	}, {
239		"section 10.4.8",
240		`(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>)
241			(Not <DAV:no-lock>)`,
242		ifHeader{
243			lists: []ifList{{
244				conditions: []Condition{{
245					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
246				}},
247			}, {
248				conditions: []Condition{{
249					Not:   true,
250					Token: `DAV:no-lock`,
251				}},
252			}},
253		},
254	}, {
255		"section 10.4.9",
256		`</resource1>
257			(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
258			[W/"A weak ETag"]) (["strong ETag"])`,
259		ifHeader{
260			lists: []ifList{{
261				resourceTag: `/resource1`,
262				conditions: []Condition{{
263					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
264				}, {
265					ETag: `W/"A weak ETag"`,
266				}},
267			}, {
268				resourceTag: `/resource1`,
269				conditions: []Condition{{
270					ETag: `"strong ETag"`,
271				}},
272			}},
273		},
274	}, {
275		"section 10.4.10",
276		`<http://www.example.com/specs/>
277			(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>)`,
278		ifHeader{
279			lists: []ifList{{
280				resourceTag: `http://www.example.com/specs/`,
281				conditions: []Condition{{
282					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
283				}},
284			}},
285		},
286	}, {
287		"section 10.4.11 #1",
288		`</specs/rfc2518.doc> (["4217"])`,
289		ifHeader{
290			lists: []ifList{{
291				resourceTag: `/specs/rfc2518.doc`,
292				conditions: []Condition{{
293					ETag: `"4217"`,
294				}},
295			}},
296		},
297	}, {
298		"section 10.4.11 #2",
299		`</specs/rfc2518.doc> (Not ["4217"])`,
300		ifHeader{
301			lists: []ifList{{
302				resourceTag: `/specs/rfc2518.doc`,
303				conditions: []Condition{{
304					Not:  true,
305					ETag: `"4217"`,
306				}},
307			}},
308		},
309	}}
310
311	for _, tc := range testCases {
312		got, ok := parseIfHeader(strings.Replace(tc.input, "\n", "", -1))
313		if gotEmpty := reflect.DeepEqual(got, ifHeader{}); gotEmpty == ok {
314			t.Errorf("%s: should be different: empty header == %t, ok == %t", tc.desc, gotEmpty, ok)
315			continue
316		}
317		if !reflect.DeepEqual(got, tc.want) {
318			t.Errorf("%s:\ngot  %v\nwant %v", tc.desc, got, tc.want)
319			continue
320		}
321	}
322}
323