// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package webdav

import (
	"reflect"
	"strings"
	"testing"
)

func TestParseIfHeader(t *testing.T) {
	// The "section x.y.z" test cases come from section x.y.z of the spec at
	// http://www.webdav.org/specs/rfc4918.html
	testCases := []struct {
		desc  string
		input string
		want  ifHeader
	}{{
		"bad: empty",
		``,
		ifHeader{},
	}, {
		"bad: no parens",
		`foobar`,
		ifHeader{},
	}, {
		"bad: empty list #1",
		`()`,
		ifHeader{},
	}, {
		"bad: empty list #2",
		`(a) (b c) () (d)`,
		ifHeader{},
	}, {
		"bad: no list after resource #1",
		`<foo>`,
		ifHeader{},
	}, {
		"bad: no list after resource #2",
		`<foo> <bar> (a)`,
		ifHeader{},
	}, {
		"bad: no list after resource #3",
		`<foo> (a) (b) <bar>`,
		ifHeader{},
	}, {
		"bad: no-tag-list followed by tagged-list",
		`(a) (b) <foo> (c)`,
		ifHeader{},
	}, {
		"bad: unfinished list",
		`(a`,
		ifHeader{},
	}, {
		"bad: unfinished ETag",
		`([b`,
		ifHeader{},
	}, {
		"bad: unfinished Notted list",
		`(Not a`,
		ifHeader{},
	}, {
		"bad: double Not",
		`(Not Not a)`,
		ifHeader{},
	}, {
		"good: one list with a Token",
		`(a)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `a`,
				}},
			}},
		},
	}, {
		"good: one list with an ETag",
		`([a])`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					ETag: `a`,
				}},
			}},
		},
	}, {
		"good: one list with three Nots",
		`(Not a Not b Not [d])`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Not:   true,
					Token: `a`,
				}, {
					Not:   true,
					Token: `b`,
				}, {
					Not:  true,
					ETag: `d`,
				}},
			}},
		},
	}, {
		"good: two lists",
		`(a) (b)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `a`,
				}},
			}, {
				conditions: []Condition{{
					Token: `b`,
				}},
			}},
		},
	}, {
		"good: two Notted lists",
		`(Not a) (Not b)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Not:   true,
					Token: `a`,
				}},
			}, {
				conditions: []Condition{{
					Not:   true,
					Token: `b`,
				}},
			}},
		},
	}, {
		"section 7.5.1",
		`<http://www.example.com/users/f/fielding/index.html>
			(<urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6>)`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `http://www.example.com/users/f/fielding/index.html`,
				conditions: []Condition{{
					Token: `urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6`,
				}},
			}},
		},
	}, {
		"section 7.5.2 #1",
		`(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
				}},
			}},
		},
	}, {
		"section 7.5.2 #2",
		`<http://example.com/locked/>
			(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `http://example.com/locked/`,
				conditions: []Condition{{
					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
				}},
			}},
		},
	}, {
		"section 7.5.2 #3",
		`<http://example.com/locked/member>
			(<urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf>)`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `http://example.com/locked/member`,
				conditions: []Condition{{
					Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`,
				}},
			}},
		},
	}, {
		"section 9.9.6",
		`(<urn:uuid:fe184f2e-6eec-41d0-c765-01adc56e6bb4>)
			(<urn:uuid:e454f3f3-acdc-452a-56c7-00a5c91e4b77>)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `urn:uuid:fe184f2e-6eec-41d0-c765-01adc56e6bb4`,
				}},
			}, {
				conditions: []Condition{{
					Token: `urn:uuid:e454f3f3-acdc-452a-56c7-00a5c91e4b77`,
				}},
			}},
		},
	}, {
		"section 9.10.8",
		`(<urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4`,
				}},
			}},
		},
	}, {
		"section 10.4.6",
		`(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
			["I am an ETag"])
			(["I am another ETag"])`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
				}, {
					ETag: `"I am an ETag"`,
				}},
			}, {
				conditions: []Condition{{
					ETag: `"I am another ETag"`,
				}},
			}},
		},
	}, {
		"section 10.4.7",
		`(Not <urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
			<urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092>)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Not:   true,
					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
				}, {
					Token: `urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092`,
				}},
			}},
		},
	}, {
		"section 10.4.8",
		`(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>)
			(Not <DAV:no-lock>)`,
		ifHeader{
			lists: []ifList{{
				conditions: []Condition{{
					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
				}},
			}, {
				conditions: []Condition{{
					Not:   true,
					Token: `DAV:no-lock`,
				}},
			}},
		},
	}, {
		"section 10.4.9",
		`</resource1>
			(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>
			[W/"A weak ETag"]) (["strong ETag"])`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `/resource1`,
				conditions: []Condition{{
					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
				}, {
					ETag: `W/"A weak ETag"`,
				}},
			}, {
				resourceTag: `/resource1`,
				conditions: []Condition{{
					ETag: `"strong ETag"`,
				}},
			}},
		},
	}, {
		"section 10.4.10",
		`<http://www.example.com/specs/>
			(<urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>)`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `http://www.example.com/specs/`,
				conditions: []Condition{{
					Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`,
				}},
			}},
		},
	}, {
		"section 10.4.11 #1",
		`</specs/rfc2518.doc> (["4217"])`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `/specs/rfc2518.doc`,
				conditions: []Condition{{
					ETag: `"4217"`,
				}},
			}},
		},
	}, {
		"section 10.4.11 #2",
		`</specs/rfc2518.doc> (Not ["4217"])`,
		ifHeader{
			lists: []ifList{{
				resourceTag: `/specs/rfc2518.doc`,
				conditions: []Condition{{
					Not:  true,
					ETag: `"4217"`,
				}},
			}},
		},
	}}

	for _, tc := range testCases {
		got, ok := parseIfHeader(strings.Replace(tc.input, "\n", "", -1))
		if gotEmpty := reflect.DeepEqual(got, ifHeader{}); gotEmpty == ok {
			t.Errorf("%s: should be different: empty header == %t, ok == %t", tc.desc, gotEmpty, ok)
			continue
		}
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("%s:\ngot  %v\nwant %v", tc.desc, got, tc.want)
			continue
		}
	}
}
