diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json new file mode 100644 index 0000000..962d98b --- /dev/null +++ b/Godeps/Godeps.json @@ -0,0 +1,25 @@ +{ + "ImportPath": "github.com/jimeh/kotaku-uk-rss", + "GoVersion": "go1.3", + "Deps": [ + { + "ImportPath": "code.google.com/p/cascadia", + "Comment": "null-30", + "Rev": "4f03c71bc42ba0015a68bea86422f0ecbb71bf70" + }, + { + "ImportPath": "code.google.com/p/go.net/html", + "Comment": "null-144", + "Rev": "ad01a6fcc8a19d3a4478c836895ffe883bd2ceab" + }, + { + "ImportPath": "github.com/PuerkitoBio/goquery", + "Comment": "v0.3.2-27-g1e5417b", + "Rev": "1e5417b3dbc2ca68de909fb56d9095daa680a166" + }, + { + "ImportPath": "github.com/gorilla/feeds", + "Rev": "2e133eb352fab1ff3569ee169e9a3a94f69c9081" + } + ] +} diff --git a/Godeps/Readme b/Godeps/Readme new file mode 100644 index 0000000..4cdaa53 --- /dev/null +++ b/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore new file mode 100644 index 0000000..f037d68 --- /dev/null +++ b/Godeps/_workspace/.gitignore @@ -0,0 +1,2 @@ +/pkg +/bin diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/.hgignore b/Godeps/_workspace/src/code.google.com/p/cascadia/.hgignore new file mode 100644 index 0000000..f97c559 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/.hgignore @@ -0,0 +1,6 @@ +^_ +^\. +\.out$ +\.6$ +~$ +\.orig$ diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/LICENSE b/Godeps/_workspace/src/code.google.com/p/cascadia/LICENSE new file mode 100644 index 0000000..ee5ad35 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2011 Andy Balholm. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/Makefile b/Godeps/_workspace/src/code.google.com/p/cascadia/Makefile new file mode 100644 index 0000000..c7d7a2b --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/Makefile @@ -0,0 +1,12 @@ +include $(GOROOT)/src/Make.inc + +TARG=cascadia + +GOFILES= \ + parser.go \ + selector.go \ + +include $(GOROOT)/src/Make.pkg + +format: + gofmt -w ${GOFILES} *_test.go diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/benchmark_test.go b/Godeps/_workspace/src/code.google.com/p/cascadia/benchmark_test.go new file mode 100644 index 0000000..cdd6eb2 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/benchmark_test.go @@ -0,0 +1,52 @@ +package cascadia + +import ( + "code.google.com/p/go.net/html" + "strings" + "testing" +) + +func MustParseHTML(doc string) *html.Node { + dom, err := html.Parse(strings.NewReader(doc)) + if err != nil { + panic(err) + } + return dom +} + +var selector = MustCompile(`div.matched`) +var doc = ` + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +` +var dom = MustParseHTML(doc) + +func BenchmarkMatchAll(b *testing.B) { + var matches []*html.Node + for i := 0; i < b.N; i++ { + matches = selector.MatchAll(dom) + } + _ = matches +} diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/parser.go b/Godeps/_workspace/src/code.google.com/p/cascadia/parser.go new file mode 100644 index 0000000..94f3d86 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/parser.go @@ -0,0 +1,812 @@ +// The cascadia package is an implementation of CSS selectors. +package cascadia + +import ( + "code.google.com/p/go.net/html" + "errors" + "fmt" + "regexp" + "strconv" + "strings" +) + +// a parser for CSS selectors +type parser struct { + s string // the source text + i int // the current position +} + +// parseEscape parses a backslash escape. +func (p *parser) parseEscape() (result string, err error) { + if len(p.s) < p.i+2 || p.s[p.i] != '\\' { + return "", errors.New("invalid escape sequence") + } + + start := p.i + 1 + c := p.s[start] + switch { + case c == '\r' || c == '\n' || c == '\f': + return "", errors.New("escaped line ending outside string") + case hexDigit(c): + // unicode escape (hex) + var i int + for i = start; i < p.i+6 && i < len(p.s) && hexDigit(p.s[i]); i++ { + // empty + } + v, _ := strconv.ParseUint(p.s[start:i], 16, 21) + if len(p.s) > i { + switch p.s[i] { + case '\r': + i++ + if len(p.s) > i && p.s[i] == '\n' { + i++ + } + case ' ', '\t', '\n', '\f': + i++ + } + } + p.i = i + return string(rune(v)), nil + } + + // Return the literal character after the backslash. + result = p.s[start : start+1] + p.i += 2 + return result, nil +} + +func hexDigit(c byte) bool { + return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' +} + +// nameStart returns whether c can be the first character of an identifier +// (not counting an initial hyphen, or an escape sequence). +func nameStart(c byte) bool { + return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127 +} + +// nameChar returns whether c can be a character within an identifier +// (not counting an escape sequence). +func nameChar(c byte) bool { + return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127 || + c == '-' || '0' <= c && c <= '9' +} + +// parseIdentifier parses an identifier. +func (p *parser) parseIdentifier() (result string, err error) { + startingDash := false + if len(p.s) > p.i && p.s[p.i] == '-' { + startingDash = true + p.i++ + } + + if len(p.s) <= p.i { + return "", errors.New("expected identifier, found EOF instead") + } + + if c := p.s[p.i]; !(nameStart(c) || c == '\\') { + return "", fmt.Errorf("expected identifier, found %c instead", c) + } + + result, err = p.parseName() + if startingDash && err == nil { + result = "-" + result + } + return +} + +// parseName parses a name (which is like an identifier, but doesn't have +// extra restrictions on the first character). +func (p *parser) parseName() (result string, err error) { + i := p.i +loop: + for i < len(p.s) { + c := p.s[i] + switch { + case nameChar(c): + start := i + for i < len(p.s) && nameChar(p.s[i]) { + i++ + } + result += p.s[start:i] + case c == '\\': + p.i = i + val, err := p.parseEscape() + if err != nil { + return "", err + } + i = p.i + result += val + default: + break loop + } + } + + if result == "" { + return "", errors.New("expected name, found EOF instead") + } + + p.i = i + return result, nil +} + +// parseString parses a single- or double-quoted string. +func (p *parser) parseString() (result string, err error) { + i := p.i + if len(p.s) < i+2 { + return "", errors.New("expected string, found EOF instead") + } + + quote := p.s[i] + i++ + +loop: + for i < len(p.s) { + switch p.s[i] { + case '\\': + if len(p.s) > i+1 { + switch c := p.s[i+1]; c { + case '\r': + if len(p.s) > i+2 && p.s[i+2] == '\n' { + i += 3 + continue loop + } + fallthrough + case '\n', '\f': + i += 2 + continue loop + } + } + p.i = i + val, err := p.parseEscape() + if err != nil { + return "", err + } + i = p.i + result += val + case quote: + break loop + case '\r', '\n', '\f': + return "", errors.New("unexpected end of line in string") + default: + start := i + for i < len(p.s) { + if c := p.s[i]; c == quote || c == '\\' || c == '\r' || c == '\n' || c == '\f' { + break + } + i++ + } + result += p.s[start:i] + } + } + + if i >= len(p.s) { + return "", errors.New("EOF in string") + } + + // Consume the final quote. + i++ + + p.i = i + return result, nil +} + +// parseRegex parses a regular expression; the end is defined by encountering an +// unmatched closing ')' or ']' which is not consumed +func (p *parser) parseRegex() (rx *regexp.Regexp, err error) { + i := p.i + if len(p.s) < i+2 { + return nil, errors.New("expected regular expression, found EOF instead") + } + + // number of open parens or brackets; + // when it becomes negative, finished parsing regex + open := 0 + +loop: + for i < len(p.s) { + switch p.s[i] { + case '(', '[': + open++ + case ')', ']': + open-- + if open < 0 { + break loop + } + } + i++ + } + + if i >= len(p.s) { + return nil, errors.New("EOF in regular expression") + } + rx, err = regexp.Compile(p.s[p.i:i]) + p.i = i + return rx, err +} + +// skipWhitespace consumes whitespace characters and comments. +// It returns true if there was actually anything to skip. +func (p *parser) skipWhitespace() bool { + i := p.i + for i < len(p.s) { + switch p.s[i] { + case ' ', '\t', '\r', '\n', '\f': + i++ + continue + case '/': + if strings.HasPrefix(p.s[i:], "/*") { + end := strings.Index(p.s[i+len("/*"):], "*/") + if end != -1 { + i += end + len("/**/") + continue + } + } + } + break + } + + if i > p.i { + p.i = i + return true + } + + return false +} + +// consumeParenthesis consumes an opening parenthesis and any following +// whitespace. It returns true if there was actually a parenthesis to skip. +func (p *parser) consumeParenthesis() bool { + if p.i < len(p.s) && p.s[p.i] == '(' { + p.i++ + p.skipWhitespace() + return true + } + return false +} + +// consumeClosingParenthesis consumes a closing parenthesis and any preceding +// whitespace. It returns true if there was actually a parenthesis to skip. +func (p *parser) consumeClosingParenthesis() bool { + i := p.i + p.skipWhitespace() + if p.i < len(p.s) && p.s[p.i] == ')' { + p.i++ + return true + } + p.i = i + return false +} + +// parseTypeSelector parses a type selector (one that matches by tag name). +func (p *parser) parseTypeSelector() (result Selector, err error) { + tag, err := p.parseIdentifier() + if err != nil { + return nil, err + } + + return typeSelector(tag), nil +} + +// parseIDSelector parses a selector that matches by id attribute. +func (p *parser) parseIDSelector() (Selector, error) { + if p.i >= len(p.s) { + return nil, fmt.Errorf("expected id selector (#id), found EOF instead") + } + if p.s[p.i] != '#' { + return nil, fmt.Errorf("expected id selector (#id), found '%c' instead", p.s[p.i]) + } + + p.i++ + id, err := p.parseName() + if err != nil { + return nil, err + } + + return attributeEqualsSelector("id", id), nil +} + +// parseClassSelector parses a selector that matches by class attribute. +func (p *parser) parseClassSelector() (Selector, error) { + if p.i >= len(p.s) { + return nil, fmt.Errorf("expected class selector (.class), found EOF instead") + } + if p.s[p.i] != '.' { + return nil, fmt.Errorf("expected class selector (.class), found '%c' instead", p.s[p.i]) + } + + p.i++ + class, err := p.parseIdentifier() + if err != nil { + return nil, err + } + + return attributeIncludesSelector("class", class), nil +} + +// parseAttributeSelector parses a selector that matches by attribute value. +func (p *parser) parseAttributeSelector() (Selector, error) { + if p.i >= len(p.s) { + return nil, fmt.Errorf("expected attribute selector ([attribute]), found EOF instead") + } + if p.s[p.i] != '[' { + return nil, fmt.Errorf("expected attribute selector ([attribute]), found '%c' instead", p.s[p.i]) + } + + p.i++ + p.skipWhitespace() + key, err := p.parseIdentifier() + if err != nil { + return nil, err + } + + p.skipWhitespace() + if p.i >= len(p.s) { + return nil, errors.New("unexpected EOF in attribute selector") + } + + if p.s[p.i] == ']' { + p.i++ + return attributeExistsSelector(key), nil + } + + if p.i+2 >= len(p.s) { + return nil, errors.New("unexpected EOF in attribute selector") + } + + op := p.s[p.i : p.i+2] + if op[0] == '=' { + op = "=" + } else if op[1] != '=' { + return nil, fmt.Errorf(`expected equality operator, found "%s" instead`, op) + } + p.i += len(op) + + p.skipWhitespace() + if p.i >= len(p.s) { + return nil, errors.New("unexpected EOF in attribute selector") + } + var val string + var rx *regexp.Regexp + if op == "#=" { + rx, err = p.parseRegex() + } else { + switch p.s[p.i] { + case '\'', '"': + val, err = p.parseString() + default: + val, err = p.parseIdentifier() + } + } + if err != nil { + return nil, err + } + + p.skipWhitespace() + if p.i >= len(p.s) { + return nil, errors.New("unexpected EOF in attribute selector") + } + if p.s[p.i] != ']' { + return nil, fmt.Errorf("expected ']', found '%c' instead", p.s[p.i]) + } + p.i++ + + switch op { + case "=": + return attributeEqualsSelector(key, val), nil + case "~=": + return attributeIncludesSelector(key, val), nil + case "|=": + return attributeDashmatchSelector(key, val), nil + case "^=": + return attributePrefixSelector(key, val), nil + case "$=": + return attributeSuffixSelector(key, val), nil + case "*=": + return attributeSubstringSelector(key, val), nil + case "#=": + return attributeRegexSelector(key, rx), nil + } + + return nil, fmt.Errorf("attribute operator %q is not supported", op) +} + +var expectedParenthesis = errors.New("expected '(' but didn't find it") +var expectedClosingParenthesis = errors.New("expected ')' but didn't find it") + +// parsePseudoclassSelector parses a pseudoclass selector like :not(p). +func (p *parser) parsePseudoclassSelector() (Selector, error) { + if p.i >= len(p.s) { + return nil, fmt.Errorf("expected pseudoclass selector (:pseudoclass), found EOF instead") + } + if p.s[p.i] != ':' { + return nil, fmt.Errorf("expected attribute selector (:pseudoclass), found '%c' instead", p.s[p.i]) + } + + p.i++ + name, err := p.parseIdentifier() + if err != nil { + return nil, err + } + name = toLowerASCII(name) + + switch name { + case "not", "has", "haschild": + if !p.consumeParenthesis() { + return nil, expectedParenthesis + } + sel, err := p.parseSelectorGroup() + if err != nil { + return nil, err + } + if !p.consumeClosingParenthesis() { + return nil, expectedClosingParenthesis + } + + switch name { + case "not": + return negatedSelector(sel), nil + case "has": + return hasDescendantSelector(sel), nil + case "haschild": + return hasChildSelector(sel), nil + } + + case "contains", "containsown": + if !p.consumeParenthesis() { + return nil, expectedParenthesis + } + var val string + switch p.s[p.i] { + case '\'', '"': + val, err = p.parseString() + default: + val, err = p.parseIdentifier() + } + if err != nil { + return nil, err + } + val = strings.ToLower(val) + p.skipWhitespace() + if p.i >= len(p.s) { + return nil, errors.New("unexpected EOF in pseudo selector") + } + if !p.consumeClosingParenthesis() { + return nil, expectedClosingParenthesis + } + + switch name { + case "contains": + return textSubstrSelector(val), nil + case "containsown": + return ownTextSubstrSelector(val), nil + } + + case "matches", "matchesown": + if !p.consumeParenthesis() { + return nil, expectedParenthesis + } + rx, err := p.parseRegex() + if err != nil { + return nil, err + } + if p.i >= len(p.s) { + return nil, errors.New("unexpected EOF in pseudo selector") + } + if !p.consumeClosingParenthesis() { + return nil, expectedClosingParenthesis + } + + switch name { + case "matches": + return textRegexSelector(rx), nil + case "matchesown": + return ownTextRegexSelector(rx), nil + } + + case "nth-child", "nth-last-child", "nth-of-type", "nth-last-of-type": + if !p.consumeParenthesis() { + return nil, expectedParenthesis + } + a, b, err := p.parseNth() + if err != nil { + return nil, err + } + if !p.consumeClosingParenthesis() { + return nil, expectedClosingParenthesis + } + return nthChildSelector(a, b, + name == "nth-last-child" || name == "nth-last-of-type", + name == "nth-of-type" || name == "nth-last-of-type"), + nil + + case "first-child": + return nthChildSelector(0, 1, false, false), nil + case "last-child": + return nthChildSelector(0, 1, true, false), nil + case "first-of-type": + return nthChildSelector(0, 1, false, true), nil + case "last-of-type": + return nthChildSelector(0, 1, true, true), nil + case "only-child": + return onlyChildSelector(false), nil + case "only-of-type": + return onlyChildSelector(true), nil + case "empty": + return emptyElementSelector, nil + } + + return nil, fmt.Errorf("unknown pseudoclass :%s", name) +} + +// parseInteger parses a decimal integer. +func (p *parser) parseInteger() (int, error) { + i := p.i + start := i + for i < len(p.s) && '0' <= p.s[i] && p.s[i] <= '9' { + i++ + } + if i == start { + return 0, errors.New("expected integer, but didn't find it.") + } + p.i = i + + val, err := strconv.Atoi(p.s[start:i]) + if err != nil { + return 0, err + } + + return val, nil +} + +// parseNth parses the argument for :nth-child (normally of the form an+b). +func (p *parser) parseNth() (a, b int, err error) { + // initial state + if p.i >= len(p.s) { + goto eof + } + switch p.s[p.i] { + case '-': + p.i++ + goto negativeA + case '+': + p.i++ + goto positiveA + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + goto positiveA + case 'n', 'N': + a = 1 + p.i++ + goto readN + case 'o', 'O', 'e', 'E': + id, err := p.parseName() + if err != nil { + return 0, 0, err + } + id = toLowerASCII(id) + if id == "odd" { + return 2, 1, nil + } + if id == "even" { + return 2, 0, nil + } + return 0, 0, fmt.Errorf("expected 'odd' or 'even', but found '%s' instead", id) + default: + goto invalid + } + +positiveA: + if p.i >= len(p.s) { + goto eof + } + switch p.s[p.i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + a, err = p.parseInteger() + if err != nil { + return 0, 0, err + } + goto readA + case 'n', 'N': + a = 1 + p.i++ + goto readN + default: + goto invalid + } + +negativeA: + if p.i >= len(p.s) { + goto eof + } + switch p.s[p.i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + a, err = p.parseInteger() + if err != nil { + return 0, 0, err + } + a = -a + goto readA + case 'n', 'N': + a = -1 + p.i++ + goto readN + default: + goto invalid + } + +readA: + if p.i >= len(p.s) { + goto eof + } + switch p.s[p.i] { + case 'n', 'N': + p.i++ + goto readN + default: + // The number we read as a is actually b. + return 0, a, nil + } + +readN: + p.skipWhitespace() + if p.i >= len(p.s) { + goto eof + } + switch p.s[p.i] { + case '+': + p.i++ + p.skipWhitespace() + b, err = p.parseInteger() + if err != nil { + return 0, 0, err + } + return a, b, nil + case '-': + p.i++ + p.skipWhitespace() + b, err = p.parseInteger() + if err != nil { + return 0, 0, err + } + return a, -b, nil + default: + return a, 0, nil + } + +eof: + return 0, 0, errors.New("unexpected EOF while attempting to parse expression of form an+b") + +invalid: + return 0, 0, errors.New("unexpected character while attempting to parse expression of form an+b") +} + +// parseSimpleSelectorSequence parses a selector sequence that applies to +// a single element. +func (p *parser) parseSimpleSelectorSequence() (Selector, error) { + var result Selector + + if p.i >= len(p.s) { + return nil, errors.New("expected selector, found EOF instead") + } + + switch p.s[p.i] { + case '*': + // It's the universal selector. Just skip over it, since it doesn't affect the meaning. + p.i++ + case '#', '.', '[', ':': + // There's no type selector. Wait to process the other till the main loop. + default: + r, err := p.parseTypeSelector() + if err != nil { + return nil, err + } + result = r + } + +loop: + for p.i < len(p.s) { + var ns Selector + var err error + switch p.s[p.i] { + case '#': + ns, err = p.parseIDSelector() + case '.': + ns, err = p.parseClassSelector() + case '[': + ns, err = p.parseAttributeSelector() + case ':': + ns, err = p.parsePseudoclassSelector() + default: + break loop + } + if err != nil { + return nil, err + } + if result == nil { + result = ns + } else { + result = intersectionSelector(result, ns) + } + } + + if result == nil { + result = func(n *html.Node) bool { + return true + } + } + + return result, nil +} + +// parseSelector parses a selector that may include combinators. +func (p *parser) parseSelector() (result Selector, err error) { + p.skipWhitespace() + result, err = p.parseSimpleSelectorSequence() + if err != nil { + return + } + + for { + var combinator byte + if p.skipWhitespace() { + combinator = ' ' + } + if p.i >= len(p.s) { + return + } + + switch p.s[p.i] { + case '+', '>', '~': + combinator = p.s[p.i] + p.i++ + p.skipWhitespace() + case ',', ')': + // These characters can't begin a selector, but they can legally occur after one. + return + } + + if combinator == 0 { + return + } + + c, err := p.parseSimpleSelectorSequence() + if err != nil { + return nil, err + } + + switch combinator { + case ' ': + result = descendantSelector(result, c) + case '>': + result = childSelector(result, c) + case '+': + result = siblingSelector(result, c, true) + case '~': + result = siblingSelector(result, c, false) + } + } + + panic("unreachable") +} + +// parseSelectorGroup parses a group of selectors, separated by commas. +func (p *parser) parseSelectorGroup() (result Selector, err error) { + result, err = p.parseSelector() + if err != nil { + return + } + + for p.i < len(p.s) { + if p.s[p.i] != ',' { + return result, nil + } + p.i++ + c, err := p.parseSelector() + if err != nil { + return nil, err + } + result = unionSelector(result, c) + } + + return +} diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/parser_test.go b/Godeps/_workspace/src/code.google.com/p/cascadia/parser_test.go new file mode 100644 index 0000000..47dd4a6 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/parser_test.go @@ -0,0 +1,86 @@ +package cascadia + +import ( + "testing" +) + +var identifierTests = map[string]string{ + "x": "x", + "96": "", + "-x": "-x", + `r\e9 sumé`: "résumé", + `a\"b`: `a"b`, +} + +func TestParseIdentifier(t *testing.T) { + for source, want := range identifierTests { + p := &parser{s: source} + got, err := p.parseIdentifier() + + if err != nil { + if want == "" { + // It was supposed to be an error. + continue + } + t.Errorf("parsing %q: got error (%s), want %q", source, err, want) + continue + } + + if want == "" { + if err == nil { + t.Errorf("parsing %q: got %q, want error", source, got) + } + continue + } + + if p.i < len(source) { + t.Errorf("parsing %q: %d bytes left over", source, len(source)-p.i) + continue + } + + if got != want { + t.Errorf("parsing %q: got %q, want %q", source, got, want) + } + } +} + +var stringTests = map[string]string{ + `"x"`: "x", + `'x'`: "x", + `'x`: "", + "'x\\\r\nx'": "xx", + `"r\e9 sumé"`: "résumé", + `"a\"b"`: `a"b`, +} + +func TestParseString(t *testing.T) { + for source, want := range stringTests { + p := &parser{s: source} + got, err := p.parseString() + + if err != nil { + if want == "" { + // It was supposed to be an error. + continue + } + t.Errorf("parsing %q: got error (%s), want %q", source, err, want) + continue + } + + if want == "" { + if err == nil { + t.Errorf("parsing %q: got %q, want error", source, got) + } + continue + } + + if p.i < len(source) { + t.Errorf("parsing %q: %d bytes left over", source, len(source)-p.i) + continue + } + + if got != want { + t.Errorf("parsing %q: got %q, want %q", source, got, want) + } + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/selector.go b/Godeps/_workspace/src/code.google.com/p/cascadia/selector.go new file mode 100644 index 0000000..febd7ee --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/selector.go @@ -0,0 +1,502 @@ +package cascadia + +import ( + "bytes" + "code.google.com/p/go.net/html" + "fmt" + "regexp" + "strings" +) + +// the Selector type, and functions for creating them + +// A Selector is a function which tells whether a node matches or not. +type Selector func(*html.Node) bool + +// hasChildMatch returns whether n has any child that matches a. +func hasChildMatch(n *html.Node, a Selector) bool { + for c := n.FirstChild; c != nil; c = c.NextSibling { + if a(c) { + return true + } + } + return false +} + +// hasDescendantMatch performs a depth-first search of n's descendants, +// testing whether any of them match a. It returns true as soon as a match is +// found, or false if no match is found. +func hasDescendantMatch(n *html.Node, a Selector) bool { + for c := n.FirstChild; c != nil; c = c.NextSibling { + if a(c) || (c.Type == html.ElementNode && hasDescendantMatch(c, a)) { + return true + } + } + return false +} + +// Compile parses a selector and returns, if successful, a Selector object +// that can be used to match against html.Node objects. +func Compile(sel string) (Selector, error) { + p := &parser{s: sel} + compiled, err := p.parseSelectorGroup() + if err != nil { + return nil, err + } + + if p.i < len(sel) { + return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i) + } + + return compiled, nil +} + +// MustCompile is like Compile, but panics instead of returning an error. +func MustCompile(sel string) Selector { + compiled, err := Compile(sel) + if err != nil { + panic(err) + } + return compiled +} + +// MatchAll returns a slice of the nodes that match the selector, +// from n and its children. +func (s Selector) MatchAll(n *html.Node) []*html.Node { + return s.matchAllInto(n, nil) +} + +func (s Selector) matchAllInto(n *html.Node, storage []*html.Node) []*html.Node { + if s(n) { + storage = append(storage, n) + } + + for child := n.FirstChild; child != nil; child = child.NextSibling { + storage = s.matchAllInto(child, storage) + } + + return storage +} + +// Match returns true if the node matches the selector. +func (s Selector) Match(n *html.Node) bool { + return s(n) +} + +// MatchFirst returns the first node that matches s, from n and its children. +func (s Selector) MatchFirst(n *html.Node) *html.Node { + if s.Match(n) { + return n + } + + for c := n.FirstChild; c != nil; c = c.NextSibling { + m := s.MatchFirst(c) + if m != nil { + return m + } + } + return nil +} + +// Filter returns the nodes in nodes that match the selector. +func (s Selector) Filter(nodes []*html.Node) (result []*html.Node) { + for _, n := range nodes { + if s(n) { + result = append(result, n) + } + } + return result +} + +// typeSelector returns a Selector that matches elements with a given tag name. +func typeSelector(tag string) Selector { + tag = toLowerASCII(tag) + return func(n *html.Node) bool { + return n.Type == html.ElementNode && n.Data == tag + } +} + +// toLowerASCII returns s with all ASCII capital letters lowercased. +func toLowerASCII(s string) string { + var b []byte + for i := 0; i < len(s); i++ { + if c := s[i]; 'A' <= c && c <= 'Z' { + if b == nil { + b = make([]byte, len(s)) + copy(b, s) + } + b[i] = s[i] + ('a' - 'A') + } + } + + if b == nil { + return s + } + + return string(b) +} + +// attributeSelector returns a Selector that matches elements +// where the attribute named key satisifes the function f. +func attributeSelector(key string, f func(string) bool) Selector { + key = toLowerASCII(key) + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + for _, a := range n.Attr { + if a.Key == key && f(a.Val) { + return true + } + } + return false + } +} + +// attributeExistsSelector returns a Selector that matches elements that have +// an attribute named key. +func attributeExistsSelector(key string) Selector { + return attributeSelector(key, func(string) bool { return true }) +} + +// attributeEqualsSelector returns a Selector that matches elements where +// the attribute named key has the value val. +func attributeEqualsSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + return s == val + }) +} + +// attributeIncludesSelector returns a Selector that matches elements where +// the attribute named key is a whitespace-separated list that includes val. +func attributeIncludesSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + for s != "" { + i := strings.IndexAny(s, " \t\r\n\f") + if i == -1 { + return s == val + } + if s[:i] == val { + return true + } + s = s[i+1:] + } + return false + }) +} + +// attributeDashmatchSelector returns a Selector that matches elements where +// the attribute named key equals val or starts with val plus a hyphen. +func attributeDashmatchSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + if s == val { + return true + } + if len(s) <= len(val) { + return false + } + if s[:len(val)] == val && s[len(val)] == '-' { + return true + } + return false + }) +} + +// attributePrefixSelector returns a Selector that matches elements where +// the attribute named key starts with val. +func attributePrefixSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + return strings.HasPrefix(s, val) + }) +} + +// attributeSuffixSelector returns a Selector that matches elements where +// the attribute named key ends with val. +func attributeSuffixSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + return strings.HasSuffix(s, val) + }) +} + +// attributeSubstringSelector returns a Selector that matches nodes where +// the attribute named key contains val. +func attributeSubstringSelector(key, val string) Selector { + return attributeSelector(key, + func(s string) bool { + return strings.Contains(s, val) + }) +} + +// attributeRegexSelector returns a Selector that matches nodes where +// the attribute named key matches the regular expression rx +func attributeRegexSelector(key string, rx *regexp.Regexp) Selector { + return attributeSelector(key, + func(s string) bool { + return rx.MatchString(s) + }) +} + +// intersectionSelector returns a selector that matches nodes that match +// both a and b. +func intersectionSelector(a, b Selector) Selector { + return func(n *html.Node) bool { + return a(n) && b(n) + } +} + +// unionSelector returns a selector that matches elements that match +// either a or b. +func unionSelector(a, b Selector) Selector { + return func(n *html.Node) bool { + return a(n) || b(n) + } +} + +// negatedSelector returns a selector that matches elements that do not match a. +func negatedSelector(a Selector) Selector { + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + return !a(n) + } +} + +// writeNodeText writes the text contained in n and its descendants to b. +func writeNodeText(n *html.Node, b *bytes.Buffer) { + switch n.Type { + case html.TextNode: + b.WriteString(n.Data) + case html.ElementNode: + for c := n.FirstChild; c != nil; c = c.NextSibling { + writeNodeText(c, b) + } + } +} + +// nodeText returns the text contained in n and its descendants. +func nodeText(n *html.Node) string { + var b bytes.Buffer + writeNodeText(n, &b) + return b.String() +} + +// nodeOwnText returns the contents of the text nodes that are direct +// children of n. +func nodeOwnText(n *html.Node) string { + var b bytes.Buffer + for c := n.FirstChild; c != nil; c = c.NextSibling { + if c.Type == html.TextNode { + b.WriteString(c.Data) + } + } + return b.String() +} + +// textSubstrSelector returns a selector that matches nodes that +// contain the given text. +func textSubstrSelector(val string) Selector { + return func(n *html.Node) bool { + text := strings.ToLower(nodeText(n)) + return strings.Contains(text, val) + } +} + +// ownTextSubstrSelector returns a selector that matches nodes that +// directly contain the given text +func ownTextSubstrSelector(val string) Selector { + return func(n *html.Node) bool { + text := strings.ToLower(nodeOwnText(n)) + return strings.Contains(text, val) + } +} + +// textRegexSelector returns a selector that matches nodes whose text matches +// the specified regular expression +func textRegexSelector(rx *regexp.Regexp) Selector { + return func(n *html.Node) bool { + return rx.MatchString(nodeText(n)) + } +} + +// ownTextRegexSelector returns a selector that matches nodes whose text +// directly matches the specified regular expression +func ownTextRegexSelector(rx *regexp.Regexp) Selector { + return func(n *html.Node) bool { + return rx.MatchString(nodeOwnText(n)) + } +} + +// hasChildSelector returns a selector that matches elements +// with a child that matches a. +func hasChildSelector(a Selector) Selector { + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + return hasChildMatch(n, a) + } +} + +// hasDescendantSelector returns a selector that matches elements +// with any descendant that matches a. +func hasDescendantSelector(a Selector) Selector { + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + return hasDescendantMatch(n, a) + } +} + +// nthChildSelector returns a selector that implements :nth-child(an+b). +// If last is true, implements :nth-last-child instead. +// If ofType is true, implements :nth-of-type instead. +func nthChildSelector(a, b int, last, ofType bool) Selector { + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + + parent := n.Parent + if parent == nil { + return false + } + + i := -1 + count := 0 + for c := parent.FirstChild; c != nil; c = c.NextSibling { + if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) { + continue + } + count++ + if c == n { + i = count + if !last { + break + } + } + } + + if i == -1 { + // This shouldn't happen, since n should always be one of its parent's children. + return false + } + + if last { + i = count - i + 1 + } + + i -= b + if a == 0 { + return i == 0 + } + + return i%a == 0 && i/a >= 0 + } +} + +// onlyChildSelector returns a selector that implements :only-child. +// If ofType is true, it implements :only-of-type instead. +func onlyChildSelector(ofType bool) Selector { + return func(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + + parent := n.Parent + if parent == nil { + return false + } + + count := 0 + for c := parent.FirstChild; c != nil; c = c.NextSibling { + if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) { + continue + } + count++ + if count > 1 { + return false + } + } + + return count == 1 + } +} + +// emptyElementSelector is a Selector that matches empty elements. +func emptyElementSelector(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + + for c := n.FirstChild; c != nil; c = c.NextSibling { + switch c.Type { + case html.ElementNode, html.TextNode: + return false + } + } + + return true +} + +// descendantSelector returns a Selector that matches an element if +// it matches d and has an ancestor that matches a. +func descendantSelector(a, d Selector) Selector { + return func(n *html.Node) bool { + if !d(n) { + return false + } + + for p := n.Parent; p != nil; p = p.Parent { + if a(p) { + return true + } + } + + return false + } +} + +// childSelector returns a Selector that matches an element if +// it matches d and its parent matches a. +func childSelector(a, d Selector) Selector { + return func(n *html.Node) bool { + return d(n) && n.Parent != nil && a(n.Parent) + } +} + +// siblingSelector returns a Selector that matches an element +// if it matches s2 and in is preceded by an element that matches s1. +// If adjacent is true, the sibling must be immediately before the element. +func siblingSelector(s1, s2 Selector, adjacent bool) Selector { + return func(n *html.Node) bool { + if !s2(n) { + return false + } + + if adjacent { + for n = n.PrevSibling; n != nil; n = n.PrevSibling { + if n.Type == html.TextNode || n.Type == html.CommentNode { + continue + } + return s1(n) + } + return false + } + + // Walk backwards looking for element that matches s1 + for c := n.PrevSibling; c != nil; c = c.PrevSibling { + if s1(c) { + return true + } + } + + return false + } +} diff --git a/Godeps/_workspace/src/code.google.com/p/cascadia/selector_test.go b/Godeps/_workspace/src/code.google.com/p/cascadia/selector_test.go new file mode 100644 index 0000000..3d252ba --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/cascadia/selector_test.go @@ -0,0 +1,536 @@ +package cascadia + +import ( + "code.google.com/p/go.net/html" + "strings" + "testing" +) + +type selectorTest struct { + HTML, selector string + results []string +} + +func nodeString(n *html.Node) string { + switch n.Type { + case html.TextNode: + return n.Data + case html.ElementNode: + return html.Token{ + Type: html.StartTagToken, + Data: n.Data, + Attr: n.Attr, + }.String() + } + return "" +} + +var selectorTests = []selectorTest{ + { + `
This address...
`, + "address", + []string{ + "
", + }, + }, + { + ``, + "*", + []string{ + "", + "", + "", + "", + }, + }, + { + `

`, + "#foo", + []string{ + `

`, + }, + }, + { + `

+#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode. +Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode. +Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode. +Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode. +Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode. +Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode. +Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode. +Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode. +Line: 1 Col: 58 Unexpected end tag (blink). Ignored. +Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode. +Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode. +Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag. +Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode. +Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode. +Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode. +Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode. +Line: 1 Col: 99 Unexpected end tag (select). Ignored. +Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode. +Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag. +Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode. +Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag. +Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode. +Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag. +Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode. +Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag. +Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode. +Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag. +Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode. +Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag. +Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored. +Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode. +Line: 1 Col: 141 Unexpected end tag (br). Treated as br element. +Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode. +Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode. +Line: 1 Col: 151 This element (img) has no end tag. +Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode. +Line: 1 Col: 159 Unexpected end tag (title). Ignored. +Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode. +Line: 1 Col: 166 Unexpected end tag (span). Ignored. +Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode. +Line: 1 Col: 174 Unexpected end tag (style). Ignored. +Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode. +Line: 1 Col: 183 Unexpected end tag (script). Ignored. +Line: 1 Col: 196 Unexpected end tag (th). Ignored. +Line: 1 Col: 201 Unexpected end tag (td). Ignored. +Line: 1 Col: 206 Unexpected end tag (tr). Ignored. +Line: 1 Col: 214 This element (frame) has no end tag. +Line: 1 Col: 221 This element (area) has no end tag. +Line: 1 Col: 228 Unexpected end tag (link). Ignored. +Line: 1 Col: 236 This element (param) has no end tag. +Line: 1 Col: 241 This element (hr) has no end tag. +Line: 1 Col: 249 This element (input) has no end tag. +Line: 1 Col: 255 Unexpected end tag (col). Ignored. +Line: 1 Col: 262 Unexpected end tag (base). Ignored. +Line: 1 Col: 269 Unexpected end tag (meta). Ignored. +Line: 1 Col: 280 This element (basefont) has no end tag. +Line: 1 Col: 290 This element (bgsound) has no end tag. +Line: 1 Col: 298 This element (embed) has no end tag. +Line: 1 Col: 307 This element (spacer) has no end tag. +Line: 1 Col: 311 Unexpected end tag (p). Ignored. +Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag. +Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag. +Line: 1 Col: 331 Unexpected end tag (caption). Ignored. +Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 350 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 366 Unexpected end tag (thead). Ignored. +Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag. +Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag. +Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag. +Line: 1 Col: 404 Unexpected end tag (dir). Ignored. +Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag. +Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag. +Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag. +Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag. +Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag. +Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag. +Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag. +Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 471 This element (wbr) has no end tag. +Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag. +Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag. +Line: 1 Col: 524 Unexpected end tag (html). Ignored. +Line: 1 Col: 524 Unexpected end tag (frameset). Ignored. +Line: 1 Col: 531 Unexpected end tag (head). Ignored. +Line: 1 Col: 540 Unexpected end tag (iframe). Ignored. +Line: 1 Col: 548 This element (image) has no end tag. +Line: 1 Col: 558 This element (isindex) has no end tag. +Line: 1 Col: 568 Unexpected end tag (noembed). Ignored. +Line: 1 Col: 579 Unexpected end tag (noframes). Ignored. +Line: 1 Col: 590 Unexpected end tag (noscript). Ignored. +Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored. +Line: 1 Col: 610 Unexpected end tag (option). Ignored. +Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored. +Line: 1 Col: 633 Unexpected end tag (textarea). Ignored. +#document +| +| +| +|
+| +| +| +|

+ +#data + +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 10 Expected closing tag. Unexpected end of file. +#document +| +| +| diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests10.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests10.dat new file mode 100644 index 0000000..4f8df86 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests10.dat @@ -0,0 +1,799 @@ +#data + +#errors +#document +| +| +| +| +| + +#data +a +#errors +29: Bogus comment +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +35: Stray “svg” start tag. +42: Stray end tag “svg” +#document +| +| +| +| +| +#errors +43: Stray “svg” start tag. +50: Stray end tag “svg” +#document +| +| +| +| +|

+#errors +34: Start tag “svg” seen in “table”. +41: Stray end tag “svg”. +#document +| +| +| +| +| +| + +#data +
foo
+#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +53: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| + +#data +
foobar
+#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +58: Stray end tag “g”. +65: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| + +#data +
foobar
+#errors +41: Start tag “svg” seen in “table”. +53: Stray end tag “g”. +65: Stray end tag “g”. +72: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| + +#data +
foobar
+#errors +45: Start tag “svg” seen in “table”. +57: Stray end tag “g”. +69: Stray end tag “g”. +76: Stray end tag “svg”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +| +| +| + +#data +
foobar
+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" + +#data +
foobar

baz

+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +
foobar

baz

+#errors +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +
foobar

baz

quux +#errors +70: HTML start tag “p” in a foreign namespace context. +81: “table” closed but “caption” was still open. +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +|

+| "baz" +|

+| "quux" + +#data +
foobarbaz

quux +#errors +78: “table” closed but “caption” was still open. +78: Unclosed elements on stack. +#document +| +| +| +| +| +|
+| +| +| "foo" +| +| "bar" +| "baz" +|

+| "quux" + +#data +foobar

baz

quux +#errors +44: Start tag “svg” seen in “table”. +56: Stray end tag “g”. +68: Stray end tag “g”. +71: HTML start tag “p” in a foreign namespace context. +71: Start tag “p” seen in “table”. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" +| +| +|

+| "quux" + +#data +

quux +#errors +50: Stray “svg” start tag. +54: Stray “g” start tag. +62: Stray end tag “g” +66: Stray “g” start tag. +74: Stray end tag “g” +77: Stray “p” start tag. +88: “table” end tag with “select” open. +#document +| +| +| +| +| +| +| +|
+|

quux +#errors +36: Start tag “select” seen in “table”. +42: Stray “svg” start tag. +46: Stray “g” start tag. +54: Stray end tag “g” +58: Stray “g” start tag. +66: Stray end tag “g” +69: Stray “p” start tag. +80: “table” end tag with “select” open. +#document +| +| +| +| +| +|

+| "quux" + +#data +foobar

baz +#errors +41: Stray “svg” start tag. +68: HTML start tag “p” in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +foobar

baz +#errors +34: Stray “svg” start tag. +61: HTML start tag “p” in a foreign namespace context. +#document +| +| +| +| +| +| +| "foo" +| +| "bar" +|

+| "baz" + +#data +

+#errors +31: Stray “svg” start tag. +35: Stray “g” start tag. +40: Stray end tag “g” +44: Stray “g” start tag. +49: Stray end tag “g” +52: Stray “p” start tag. +58: Stray “span” start tag. +58: End of file seen and there were open elements. +#document +| +| +| +| + +#data +

+#errors +42: Stray “svg” start tag. +46: Stray “g” start tag. +51: Stray end tag “g” +55: Stray “g” start tag. +60: Stray end tag “g” +63: Stray “p” start tag. +69: Stray “span” start tag. +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| +| xlink href="foo" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data + +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" + +#data +bar +#errors +#document +| +| +| +| +| xlink:href="foo" +| xml:lang="en" +| +| +| xlink href="foo" +| xml lang="en" +| "bar" + +#data + +#errors +#document +| +| +| +| + +#data +

a +#errors +#document +| +| +| +|
+| +| "a" + +#data +
a +#errors +#document +| +| +| +|
+| +| +| "a" + +#data +
+#errors +#document +| +| +| +|
+| +| +| + +#data +
a +#errors +#document +| +| +| +|
+| +| +| +| +| "a" + +#data +

a +#errors +#document +| +| +| +|

+| +| +| +|

+| "a" + +#data +
    a +#errors +40: HTML start tag “ul” in a foreign namespace context. +41: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +|
    +| +|
      +| "a" + +#data +
        a +#errors +35: HTML start tag “ul” in a foreign namespace context. +36: End of file in a foreign namespace context. +#document +| +| +| +| +| +| +| +|
          +| "a" + +#data +

          +#errors +#document +| +| +| +| +|

          +| +| +|

          + +#data +

          +#errors +#document +| +| +| +| +|

          +| +| +|

          + +#data +

          +#errors +#document +| +| +| +|

          +| +| +| +|

          +|

          + +#data +
          +#errors +#document +| +| +| +| +| +|
          +| +|
          +| +| + +#data +
          +#errors +#document +| +| +| +| +| +| +| +|
          +|
          +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data +

+#errors +#document +| +| +| +| +|
+| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| + +#data +
+#errors +#document +| +| +| +| +| +| +| +|
+| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests11.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests11.dat new file mode 100644 index 0000000..638cde4 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests11.dat @@ -0,0 +1,482 @@ +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data + +#errors +#document +| +| +| +| +| +| attributename="" +| attributetype="" +| basefrequency="" +| baseprofile="" +| calcmode="" +| clippathunits="" +| contentscripttype="" +| contentstyletype="" +| diffuseconstant="" +| edgemode="" +| externalresourcesrequired="" +| filterres="" +| filterunits="" +| glyphref="" +| gradienttransform="" +| gradientunits="" +| kernelmatrix="" +| kernelunitlength="" +| keypoints="" +| keysplines="" +| keytimes="" +| lengthadjust="" +| limitingconeangle="" +| markerheight="" +| markerunits="" +| markerwidth="" +| maskcontentunits="" +| maskunits="" +| numoctaves="" +| pathlength="" +| patterncontentunits="" +| patterntransform="" +| patternunits="" +| pointsatx="" +| pointsaty="" +| pointsatz="" +| preservealpha="" +| preserveaspectratio="" +| primitiveunits="" +| refx="" +| refy="" +| repeatcount="" +| repeatdur="" +| requiredextensions="" +| requiredfeatures="" +| specularconstant="" +| specularexponent="" +| spreadmethod="" +| startoffset="" +| stddeviation="" +| stitchtiles="" +| surfacescale="" +| systemlanguage="" +| tablevalues="" +| targetx="" +| targety="" +| textlength="" +| viewbox="" +| viewtarget="" +| xchannelselector="" +| ychannelselector="" +| zoomandpan="" + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests12.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests12.dat new file mode 100644 index 0000000..63107d2 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests12.dat @@ -0,0 +1,62 @@ +#data +

foobazeggs

spam

quuxbar +#errors +#document +| +| +| +| +|

+| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

+| "spam" +| +| +| +|
+| +| +| "quux" +| "bar" + +#data +foobazeggs

spam
quuxbar +#errors +#document +| +| +| +| +| "foo" +| +| +| +| "baz" +| +| +| +| +| "eggs" +| +| +|

+| "spam" +| +| +| +|
+| +| +| "quux" +| "bar" diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests14.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests14.dat new file mode 100644 index 0000000..b8713f8 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests14.dat @@ -0,0 +1,74 @@ +#data + +#errors +#document +| +| +| +| +| + +#data + +#errors +#document +| +| +| +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| abc:def="gh" +| +| +| + +#data + +#errors +15: Unexpected start tag html +#document +| +| +| xml:lang="bar" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| +| + +#data + +#errors +#document +| +| +| 123="456" +| 789="012" +| +| + +#data + +#errors +#document +| +| +| +| +| 789="012" diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests15.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests15.dat new file mode 100644 index 0000000..6ce1c0d --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests15.dat @@ -0,0 +1,208 @@ +#data +

X +#errors +Line: 1 Col: 31 Unexpected end tag (p). Ignored. +Line: 1 Col: 36 Expected closing tag. Unexpected end of file. +#document +| +| +| +| +|

+| +| +| +| +| +| +| " " +|

+| "X" + +#data +

+

X +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end tag (p). Ignored. +Line: 2 Col: 4 Expected closing tag. Unexpected end of file. +#document +| +| +| +|

+| +| +| +| +| +| +| " +" +|

+| "X" + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| +| " " + +#data + +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| + +#data + +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element. +#document +| +| +| +| + +#data +X +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| +| +| +| +| +| "X" + +#data +<!doctype html><table> X<meta></table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " X" +| <meta> +| <table> + +#data +<!doctype html><table> x</table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> + +#data +<!doctype html><table> x </table> +#errors +Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x " +| <table> + +#data +<!doctype html><table><tr> x</table> +#errors +Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table>X<style> <tr>x </style> </table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <style> +| " <tr>x " +| " " + +#data +<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div> +#errors +Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <a> +| "foo" +| <table> +| " " +| <tbody> +| <tr> +| <td> +| "bar" +| " " + +#data +<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes> +#errors +6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +13: Stray start tag “frame”. +21: Stray end tag “frame”. +29: Stray end tag “frame”. +39: “frameset” start tag after “body” already open. +105: End of file seen inside an [R]CDATA element. +105: End of file seen and there were open elements. +XXX: These errors are wrong, please fix me! +#document +| <html> +| <head> +| <frameset> +| <frame> +| <frameset> +| <frame> +| <noframes> +| "</frameset><noframes>" + +#data +<!DOCTYPE html><object></html> +#errors +1: Expected closing tag. Unexpected end of file +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests16.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests16.dat new file mode 100644 index 0000000..c8ef66f --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests16.dat @@ -0,0 +1,2299 @@ +#data +<!doctype html><script> +#errors +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script>a +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<!doctype html><script>< +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<!doctype html><script></ +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<!doctype html><script></S +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<!doctype html><script></SC +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<!doctype html><script></SCR +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<!doctype html><script></SCRI +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<!doctype html><script></SCRIP +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script></s +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<!doctype html><script></sc +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<!doctype html><script></scr +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<!doctype html><script></scri +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<!doctype html><script></scrip +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script><! +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<!doctype html><script><!a +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<!doctype html><script><!- +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<!doctype html><script><!-a +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<!doctype html><script><!-- +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--a +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<!doctype html><script><!--< +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<!doctype html><script><!--<a +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<!doctype html><script><!--</ +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--<s +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<!doctype html><script><!--<script < +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<!doctype html><script><!--<script <a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<!doctype html><script><!--<script </ +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<!doctype html><script><!--<script </s +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 43 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<!doctype html><script><!--<script </scripta +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script> +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<!doctype html><script><!--<script </script/ +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<!doctype html><script><!--<script </script < +#errors +Line: 1 Col: 45 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<!doctype html><script><!--<script </script <a +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<!doctype html><script><!--<script </script </ +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script/ +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script - +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<!doctype html><script><!--<script -a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<!doctype html><script><!--<script -< +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -<" +| <body> + +#data +<!doctype html><script><!--<script -- +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<!doctype html><script><!--<script --a +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<!doctype html><script><!--<script --< +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --<" +| <body> + +#data +<!doctype html><script><!--<script --> +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script -->< +#errors +Line: 1 Col: 39 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<!doctype html><script><!--<script --></ +#errors +Line: 1 Col: 40 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script/ +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script><\/script>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<!doctype html><script><!--<script></scr'+'ipt>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>--><!--</script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-- ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- -></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- - ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<!doctype html><script><!--<script>--!></script>X +#errors +Line: 1 Col: 49 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<!doctype html><script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 59 Unexpected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<!doctype html><script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 57 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<!doctype html><style><!--<style></style>--></style> +#errors +Line: 1 Col: 52 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<!doctype html><style><!--</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<!doctype html><style><!--...</style>...--></style> +#errors +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<!doctype html><style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 66 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<!doctype html><style><!--...</style><!-- --><style>@import ...</style> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<!doctype html><style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 63 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<!doctype html><style>...<!--[if IE]><style>...</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<!doctype html><title><!--<title>--> +#errors +Line: 1 Col: 52 Unexpected end tag (title). +#document +| +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<!doctype html><title></title> +#errors +#document +| +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (title). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<!doctype html><noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 64 Unexpected end tag (noscript). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<!doctype html><noscript><!--</noscript>X<noscript>--></noscript> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<!doctype html><noscript><iframe></noscript>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<!doctype html><noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 64 Unexpected end tag (noframes). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<!doctype html><noframes><body><script><!--...</script></body></noframes></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<!doctype html><textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 64 Unexpected end tag (textarea). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<!doctype html><textarea></textarea></textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<!doctype html><textarea><</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<" + +#data +<!doctype html><textarea>a<b</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "a<b" + +#data +<!doctype html><iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 56 Unexpected end tag (iframe). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<!doctype html><iframe>...<!--X->...<!--/X->...</iframe> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<!doctype html><xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 44 Unexpected end tag (xmp). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<!doctype html><noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 60 Unexpected end tag (noembed). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script>a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<script>< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<script></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<script></S +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<script></SC +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<script></SCR +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<script></SCRI +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<script></SCRIP +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script></s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<script></sc +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<script></scr +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<script></scri +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<script></scrip +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script><! +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<script><!a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<script><!- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<script><!-a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<script><!-- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<script><!--< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<script><!--<a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<script><!--</ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--<s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<script><!--<script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<script><!--<script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<script><!--<script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<script><!--<script </s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<script><!--<script </scripta +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<script><!--<script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<script><!--<script </script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<script><!--<script </script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<script><!--<script </script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script - +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<script><!--<script -a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<script><!--<script -- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<script><!--<script --a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<script><!--<script --> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script -->< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<script><!--<script --></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script><\/script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<script><!--<script></scr'+'ipt>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<script><!--<script></script><script></script></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<script><!--<script></script><script></script>--><!--</script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<script><!--<script></script><script></script>-- ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<script><!--<script></script><script></script>- -></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<script><!--<script></script><script></script>- - ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<script><!--<script></script><script></script>-></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<script><!--<script>--!></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 44 Unexpected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 42 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<style><!--<style></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<style><!--</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<style><!--...</style>...--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 36 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<style><!--...</style><!-- --><style>@import ...</style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 48 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<style>...<!--[if IE]><style>...</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<title><!--<title>--> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (title). +#document +| +| +| +| "<!--<title>" +| <body> +| "-->" + +#data +<title></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| +| +| +| "" +| + +#data +foo/title><link></head><body>X +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noscript). +#document +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<noscript><!--</noscript>X<noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<noscript><iframe></noscript>X +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noframes). +#document +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<noframes><body><script><!--...</script></body></noframes></html> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +#document +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (textarea). +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<textarea></textarea></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +Line: 1 Col: 41 Unexpected end tag (iframe). +#document +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<iframe>...<!--X->...<!--/X->...</iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end tag (xmp). +#document +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE. +Line: 1 Col: 45 Unexpected end tag (noembed). +#document +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<!doctype html><table> + +#errors +Line 2 Col 0 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " +" + +#data +<!doctype html><table><td><span><font></span><span> +#errors +Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase. +Line 1 Col 45 Unexpected end tag (span). +Line 1 Col 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <span> +| <font> +| <font> +| <span> + +#data +<!doctype html><form><table></form><form></table></form> +#errors +35: Stray end tag “form”. +41: Start tag “form” seen in “table”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <table> +| <form> diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests17.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests17.dat new file mode 100644 index 0000000..7b555f8 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests17.dat @@ -0,0 +1,153 @@ +#data +<!doctype html><table><tbody><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tr><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<!doctype html><table><tr><td><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| <td> + +#data +<!doctype html><table><tr><th><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <th> +| <select> +| <td> + +#data +<!doctype html><table><caption><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <select> +| <tbody> +| <tr> + +#data +<!doctype html><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><th> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tbody> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><thead> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><caption> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><table><tr></table>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| "a" diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests18.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests18.dat new file mode 100644 index 0000000..680e1f0 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests18.dat @@ -0,0 +1,269 @@ +#data +<!doctype html><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> + +#data +<!doctype html><table><tbody><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><caption><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><tr><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <style> +| "</script>" + +#data +<!doctype html><table><tr><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <script> +| "</style>" + +#data +<!doctype html><table><caption><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><table><td><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" + +#data +<!doctype html><table><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> + +#data +<!doctype html><table><tr><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><frameset></frameset><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><frameset></frameset></html><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><table><tr></tbody><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <tfoot> + +#data +<!doctype html><table><td><svg></svg>abc<td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| "abc" +| <td> diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests19.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests19.dat new file mode 100644 index 0000000..0d62f5a --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests19.dat @@ -0,0 +1,1237 @@ +#data +<!doctype html><math><mn DefinitionUrl="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| definitionURL="foo" + +#data +<!doctype html><html></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <!-- foo --> +| <head> +| <body> + +#data +<!doctype html><head></head></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- foo --> +| <body> + +#data +<!doctype html><body><p><pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <pre> + +#data +<!doctype html><body><p><listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <listing> + +#data +<!doctype html><p><plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <plaintext> + +#data +<!doctype html><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <h1> + +#data +<!doctype html><form><isindex> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> + +#data +<!doctype html><isindex action="POST"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| action="POST" +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex prompt="this is isindex"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "this is isindex" +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex type="hidden"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| type="hidden" +| <hr> + +#data +<!doctype html><isindex name="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><ruby><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rp> + +#data +<!doctype html><ruby><div><span><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rp> + +#data +<!doctype html><ruby><div><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rp> + +#data +<!doctype html><ruby><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rt> + +#data +<!doctype html><ruby><div><span><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rt> + +#data +<!doctype html><ruby><div><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rt> + +#data +<!doctype html><math/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <foo> + +#data +<!doctype html><svg/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <foo> + +#data +<!doctype html><div></body><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <!-- foo --> + +#data +<!doctype html><h1><div><h3><span></h1>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h1> +| <div> +| <h3> +| <span> +| "foo" + +#data +<!doctype html><p></h3>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "foo" + +#data +<!doctype html><h3><li>abc</h2>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h3> +| <li> +| "abc" +| "foo" + +#data +<!doctype html><table>abc<!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <!-- foo --> + +#data +<!doctype html><table> <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <!-- foo --> + +#data +<!doctype html><table> b <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " b " +| <table> +| <!-- foo --> + +#data +<!doctype html><select><option><option> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><p><math><mi><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mi> +| <p> +| <h1> + +#data +<!doctype html><p><math><mo><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mo> +| <p> +| <h1> + +#data +<!doctype html><p><math><mn><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <p> +| <h1> + +#data +<!doctype html><p><math><ms><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math ms> +| <p> +| <h1> + +#data +<!doctype html><p><math><mtext><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mtext> +| <p> +| <h1> + +#data +<!doctype html><frameset></noframes> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html c=d><body></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><html c=d><frameset></frameset></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <!-- foo --> + +#data +<!doctype html><html><frameset></frameset></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| " " + +#data +<!doctype html><html><frameset></frameset></html>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html></p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<html><frameset></frameset></html><!doctype html> +#errors +#document +| <html> +| <head> +| <frameset> + +#data +<!doctype html><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html><p><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><p>a<frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "a" + +#data +<!doctype html><p> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><pre><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> + +#data +<!doctype html><listing><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <listing> + +#data +<!doctype html><li><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <li> + +#data +<!doctype html><dd><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dd> + +#data +<!doctype html><dt><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> + +#data +<!doctype html><button><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <button> + +#data +<!doctype html><applet><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <applet> + +#data +<!doctype html><marquee><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <marquee> + +#data +<!doctype html><object><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> + +#data +<!doctype html><table><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> + +#data +<!doctype html><area><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <area> + +#data +<!doctype html><basefont><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <basefont> +| <frameset> + +#data +<!doctype html><bgsound><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <bgsound> +| <frameset> + +#data +<!doctype html><br><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <br> + +#data +<!doctype html><embed><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <embed> + +#data +<!doctype html><img><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html><input><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> + +#data +<!doctype html><keygen><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <keygen> + +#data +<!doctype html><wbr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <wbr> + +#data +<!doctype html><hr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <hr> + +#data +<!doctype html><textarea></textarea><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> + +#data +<!doctype html><xmp></xmp><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> + +#data +<!doctype html><iframe></iframe><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> + +#data +<!doctype html><select></select><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><svg></svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><math></math><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg><foreignObject><div> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg>a</svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| "a" + +#data +<!doctype html><svg> </svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<html>aaa<frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "aaa" + +#data +<html> a <frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "a " + +#data +<!doctype html><div><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><div><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> + +#data +<!doctype html><p><math></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| "a" + +#data +<!doctype html><p><math><mn><span></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <span> +| <p> +| "a" + +#data +<!doctype html><math></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!doctype html><meta charset="ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| charset="ascii" +| <body> + +#data +<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| content="text/html;charset=ascii" +| http-equiv="content-type" +| <body> + +#data +<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> +| <meta> +| charset="utf8" +| <body> + +#data +<!doctype html><html a=b><head></head><html c=d> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><image/> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html>a<i>b<table>c<b>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "a" +| <i> +| "bc" +| <b> +| "de" +| "f" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" + +#data +<!doctype html><table><i>a<b>b<div>c</i> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <i> +| "c" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><table><i>a<div>b<tr>c<b>d</i>e +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <div> +| "b" +| <i> +| "c" +| <b> +| "d" +| <b> +| "e" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><table><i>a<div>b<b>c</i>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <i> +| "a" +| <div> +| <i> +| "b" +| <b> +| "c" +| <b> +| "d" +| <table> + +#data +<!doctype html><body><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <bgsound> + +#data +<!doctype html><body><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <basefont> + +#data +<!doctype html><a><b></a><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <basefont> + +#data +<!doctype html><a><b></a><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <bgsound> + +#data +<!doctype html><figcaption><article></figcaption>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <figcaption> +| <article> +| "a" + +#data +<!doctype html><summary><article></summary>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <summary> +| <article> +| "a" + +#data +<!doctype html><p><a><plaintext>b +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <a> +| <plaintext> +| <a> +| "b" + +#data +<!DOCTYPE html><div>a<a></div>b<p>c</p>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| "a" +| <a> +| <a> +| "b" +| <p> +| "c" +| "d" diff --git a/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests2.dat b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests2.dat new file mode 100644 index 0000000..60d8592 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/go.net/html/testdata/webkit/tests2.dat @@ -0,0 +1,763 @@ +#data +<!DOCTYPE html>Test +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Test" + +#data +<textarea>test</div>test +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 24 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <textarea> +| "test</div>test" + +#data +<table><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 11 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><td>test</tbody></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "test" + +#data +<frame>test +#errors +Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected start tag frame. Ignored. +#document +| <html> +| <head> +| <body> +| "test" + +#data +<!DOCTYPE html><frameset>test +#errors +Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset><!DOCTYPE html> +#errors +Line: 1 Col: 40 Unexpected DOCTYPE. Ignored. +Line: 1 Col: 40 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><font><p><b>test</font> +#errors +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <p> +| <font> +| <b> +| "test" + +#data +<!DOCTYPE html><dt><div><dd> +#errors +Line: 1 Col: 28 Missing end tag (div, dt). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> +| <div> +| <dd> + +#data +<script></x +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</x" +| <body> + +#data +<table><plaintext><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode. +Line: 1 Col: 22 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "<td>" +| <table> + +#data +<plaintext></plaintext> +#errors +Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!DOCTYPE html><table><tr>TEST +#errors +Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "TEST" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4> +#errors +Line: 1 Col: 37 Unexpected start tag (body). +Line: 1 Col: 53 Unexpected start tag (body). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| t1="1" +| t2="2" +| t3="3" +| t4="4" + +#data +</b test +#errors +Line: 1 Col: 8 Unexpected end of file in attribute name. +Line: 1 Col: 8 End tag contains unexpected attributes. +Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html></b test<b &=&>X +#errors +Line: 1 Col: 32 Named entity didn't end with ';'. +Line: 1 Col: 33 End tag contains unexpected attributes. +Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" + +#data +<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 54 Unexpected end of file in the tag name. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| type="text/x-foobar;baz" +| "X</SCRipt" +| <body> + +#data +& +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&# +#errors +Line: 1 Col: 1 Numeric entity expected. Got end of file instead. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#" + +#data +&#X +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#X" + +#data +&#x +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#x" + +#data +- +#errors +Line: 1 Col: 4 Numeric entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "-" + +#data +&x-test +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&x-test" + +#data +<!doctypehtml><p><li> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <li> + +#data +<!doctypehtml><p><dt> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dt> + +#data +<!doctypehtml><p><dd> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dd> + +#data +<!doctypehtml><p><form> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <form> + +#data +<!DOCTYPE html><p></P>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "X" + +#data +& +#errors +Line: 1 Col: 4 Named entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&AMp; +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&AMp;" + +#data +<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY> +#errors +Line: 1 Col: 110 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly> + +#data +<!DOCTYPE html>X</body>X +#errors +Line: 1 Col: 24 Unexpected non-space characters in the after body phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "XX" + +#data +<!DOCTYPE html><!-- X +#errors +Line: 1 Col: 21 Unexpected end of file in comment. +#document +| <!DOCTYPE html> +| <!-- X --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><table><caption>test TEST</caption><td>test +#errors +Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 58 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| "test TEST" +| <tbody> +| <tr> +| <td> +| "test" + +#data +<!DOCTYPE html><select><option><optgroup> +#errors +Line: 1 Col: 41 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option> +#errors +Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 76 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <option> +| <option> + +#data +<!DOCTYPE html><select><optgroup><option><optgroup> +#errors +Line: 1 Col: 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><datalist><option>foo</datalist>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <datalist> +| <option> +| "foo" +| "bar" + +#data +<!DOCTYPE html><font><input><input></font> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <input> +| <input> + +#data +<!DOCTYPE html><!-- XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX +#errors +Line: 1 Col: 29 Unexpected end of file in comment (-) +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<isindex test=x name=x> +#errors +Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected start tag isindex. Don't use it! +#document +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| test="x" +| <hr> + +#data +test +test +#errors +Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "test +test" + +#data +<!DOCTYPE html><body><title>test</body> +#errors +#document +| +| +| +| +| +| "test</body>" + +#data +<!DOCTYPE html><body><title>X +#errors +#document +| +| +| +| +| +| "X" +| <meta> +| name="z" +| <link> +| rel="foo" +| <style> +| " +x { content:"</style" } " + +#data +<!DOCTYPE html><select><optgroup></optgroup></select> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> + +#data + + +#errors +Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html> <html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><script> +</script> <title>x +#errors +#document +| +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved. +#document +| +| +| +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +#document +| +| +| +| +| "x" +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (style). +#document +| +| +| --> x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +| x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| +| +|

+#errors +#document +| +| +| +| +| +| ddd +#errors +#document +| +| +| +#errors +#document +| +| +| +| +|
  • +| +| ", + " + + + + + + + + + +
    + + +
    +

    Package testing

    + + + + + + + + + + +
    +
    +
    import "testing"
    +
    +
    +
    Overview
    +
    Index
    + + +
    Subdirectories
    + +
    +
    + +
    + +
    +

    Overview ▾

    +

    +Package testing provides support for automated testing of Go packages. +It is intended to be used in concert with the “go test” command, which automates +execution of any function of the form +

    +
    func TestXxx(*testing.T)
    +
    +

    +where Xxx can be any alphanumeric string (but the first letter must not be in +[a-z]) and serves to identify the test routine. +These TestXxx routines should be declared within the package they are testing. +

    +

    +Functions of the form +

    +
    func BenchmarkXxx(*testing.B)
    +
    +

    +are considered benchmarks, and are executed by the "go test" command when +the -test.bench flag is provided. +

    +

    +A sample benchmark function looks like this: +

    +
    func BenchmarkHello(b *testing.B) {
    +    for i := 0; i < b.N; i++ {
    +        fmt.Sprintf("hello")
    +    }
    +}
    +
    +

    +The benchmark package will vary b.N until the benchmark function lasts +long enough to be timed reliably. The output +

    +
    testing.BenchmarkHello    10000000    282 ns/op
    +
    +

    +means that the loop ran 10000000 times at a speed of 282 ns per loop. +

    +

    +If a benchmark needs some expensive setup before running, the timer +may be stopped: +

    +
    func BenchmarkBigLen(b *testing.B) {
    +    b.StopTimer()
    +    big := NewBig()
    +    b.StartTimer()
    +    for i := 0; i < b.N; i++ {
    +        big.Len()
    +    }
    +}
    +
    +

    +The package also runs and verifies example code. Example functions may +include a concluding comment that begins with "Output:" and is compared with +the standard output of the function when the tests are run, as in these +examples of an example: +

    +
    func ExampleHello() {
    +        fmt.Println("hello")
    +        // Output: hello
    +}
    +
    +func ExampleSalutations() {
    +        fmt.Println("hello, and")
    +        fmt.Println("goodbye")
    +        // Output:
    +        // hello, and
    +        // goodbye
    +}
    +
    +

    +Example functions without output comments are compiled but not executed. +

    +

    +The naming convention to declare examples for a function F, a type T and +method M on type T are: +

    +
    func ExampleF() { ... }
    +func ExampleT() { ... }
    +func ExampleT_M() { ... }
    +
    +

    +Multiple example functions for a type/function/method may be provided by +appending a distinct suffix to the name. The suffix must start with a +lower-case letter. +

    +
    func ExampleF_suffix() { ... }
    +func ExampleT_suffix() { ... }
    +func ExampleT_M_suffix() { ... }
    +
    +

    +The entire test file is presented as the example when it contains a single +example function, at least one other function, type, variable, or constant +declaration, and no test or benchmark functions. +

    + +
    +
    + + +

    Index

    + +
    +
    + + + + +
    func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
    + + +
    func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
    + + +
    func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool)
    + + +
    func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
    + + +
    func Short() bool
    + + + +
    type B
    + + + +
        func (c *B) Error(args ...interface{})
    + + +
        func (c *B) Errorf(format string, args ...interface{})
    + + +
        func (c *B) Fail()
    + + +
        func (c *B) FailNow()
    + + +
        func (c *B) Failed() bool
    + + +
        func (c *B) Fatal(args ...interface{})
    + + +
        func (c *B) Fatalf(format string, args ...interface{})
    + + +
        func (c *B) Log(args ...interface{})
    + + +
        func (c *B) Logf(format string, args ...interface{})
    + + +
        func (b *B) ResetTimer()
    + + +
        func (b *B) SetBytes(n int64)
    + + +
        func (b *B) StartTimer()
    + + +
        func (b *B) StopTimer()
    + + + +
    type BenchmarkResult
    + + +
        func Benchmark(f func(b *B)) BenchmarkResult
    + + + +
        func (r BenchmarkResult) NsPerOp() int64
    + + +
        func (r BenchmarkResult) String() string
    + + + +
    type InternalBenchmark
    + + + + +
    type InternalExample
    + + + + +
    type InternalTest
    + + + + +
    type T
    + + + +
        func (c *T) Error(args ...interface{})
    + + +
        func (c *T) Errorf(format string, args ...interface{})
    + + +
        func (c *T) Fail()
    + + +
        func (c *T) FailNow()
    + + +
        func (c *T) Failed() bool
    + + +
        func (c *T) Fatal(args ...interface{})
    + + +
        func (c *T) Fatalf(format string, args ...interface{})
    + + +
        func (c *T) Log(args ...interface{})
    + + +
        func (c *T) Logf(format string, args ...interface{})
    + + +
        func (t *T) Parallel()
    + + + +
    + + + + +

    Package files

    +

    + + + benchmark.go + + example.go + + testing.go + + +

    + + + + + + + +

    func Main

    +
    func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
    +

    +An internal function but exported because it is cross-package; part of the implementation +of the "go test" command. +

    + + + + + +

    func RunBenchmarks

    +
    func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
    +

    +An internal function but exported because it is cross-package; part of the implementation +of the "go test" command. +

    + + + + + +

    func RunExamples

    +
    func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool)
    + + + + + +

    func RunTests

    +
    func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
    + + + + + +

    func Short

    +
    func Short() bool
    +

    +Short reports whether the -test.short flag is set. +

    + + + + + + +

    type B

    +
    type B struct {
    +    N int
    +    // contains filtered or unexported fields
    +}
    +

    +B is a type passed to Benchmark functions to manage benchmark +timing and to specify the number of iterations to run. +

    + + + + + + + + + + + + +

    func (*B) Error

    +
    func (c *B) Error(args ...interface{})
    +

    +Error is equivalent to Log() followed by Fail(). +

    + + + + + +

    func (*B) Errorf

    +
    func (c *B) Errorf(format string, args ...interface{})
    +

    +Errorf is equivalent to Logf() followed by Fail(). +

    + + + + + +

    func (*B) Fail

    +
    func (c *B) Fail()
    +

    +Fail marks the function as having failed but continues execution. +

    + + + + + +

    func (*B) FailNow

    +
    func (c *B) FailNow()
    +

    +FailNow marks the function as having failed and stops its execution. +Execution will continue at the next test or benchmark. +

    + + + + + +

    func (*B) Failed

    +
    func (c *B) Failed() bool
    +

    +Failed returns whether the function has failed. +

    + + + + + +

    func (*B) Fatal

    +
    func (c *B) Fatal(args ...interface{})
    +

    +Fatal is equivalent to Log() followed by FailNow(). +

    + + + + + +

    func (*B) Fatalf

    +
    func (c *B) Fatalf(format string, args ...interface{})
    +

    +Fatalf is equivalent to Logf() followed by FailNow(). +

    + + + + + +

    func (*B) Log

    +
    func (c *B) Log(args ...interface{})
    +

    +Log formats its arguments using default formatting, analogous to Println(), +and records the text in the error log. +

    + + + + + +

    func (*B) Logf

    +
    func (c *B) Logf(format string, args ...interface{})
    +

    +Logf formats its arguments according to the format, analogous to Printf(), +and records the text in the error log. +

    + + + + + +

    func (*B) ResetTimer

    +
    func (b *B) ResetTimer()
    +

    +ResetTimer sets the elapsed benchmark time to zero. +It does not affect whether the timer is running. +

    + + + + + +

    func (*B) SetBytes

    +
    func (b *B) SetBytes(n int64)
    +

    +SetBytes records the number of bytes processed in a single operation. +If this is called, the benchmark will report ns/op and MB/s. +

    + + + + + +

    func (*B) StartTimer

    +
    func (b *B) StartTimer()
    +

    +StartTimer starts timing a test. This function is called automatically +before a benchmark starts, but it can also used to resume timing after +a call to StopTimer. +

    + + + + + +

    func (*B) StopTimer

    +
    func (b *B) StopTimer()
    +

    +StopTimer stops timing a test. This can be used to pause the timer +while performing complex initialization that you don't +want to measure. +

    + + + + + + + +

    type BenchmarkResult

    +
    type BenchmarkResult struct {
    +    N     int           // The number of iterations.
    +    T     time.Duration // The total time taken.
    +    Bytes int64         // Bytes processed in one iteration.
    +}
    +

    +The results of a benchmark run. +

    + + + + + + + + + + +

    func Benchmark

    +
    func Benchmark(f func(b *B)) BenchmarkResult
    +

    +Benchmark benchmarks a single function. Useful for creating +custom benchmarks that do not use the "go test" command. +

    + + + + + + +

    func (BenchmarkResult) NsPerOp

    +
    func (r BenchmarkResult) NsPerOp() int64
    + + + + + +

    func (BenchmarkResult) String

    +
    func (r BenchmarkResult) String() string
    + + + + + + + +

    type InternalBenchmark

    +
    type InternalBenchmark struct {
    +    Name string
    +    F    func(b *B)
    +}
    +

    +An internal type but exported because it is cross-package; part of the implementation +of the "go test" command. +

    + + + + + + + + + + + + + + +

    type InternalExample

    +
    type InternalExample struct {
    +    Name   string
    +    F      func()
    +    Output string
    +}
    + + + + + + + + + + + + + + +

    type InternalTest

    +
    type InternalTest struct {
    +    Name string
    +    F    func(*T)
    +}
    +

    +An internal type but exported because it is cross-package; part of the implementation +of the "go test" command. +

    + + + + + + + + + + + + + + +

    type T

    +
    type T struct {
    +    // contains filtered or unexported fields
    +}
    +

    +T is a type passed to Test functions to manage test state and support formatted test logs. +Logs are accumulated during execution and dumped to standard error when done. +

    + + + + + + + + + + + + +

    func (*T) Error

    +
    func (c *T) Error(args ...interface{})
    +

    +Error is equivalent to Log() followed by Fail(). +

    + + + + + +

    func (*T) Errorf

    +
    func (c *T) Errorf(format string, args ...interface{})
    +

    +Errorf is equivalent to Logf() followed by Fail(). +

    + + + + + +

    func (*T) Fail

    +
    func (c *T) Fail()
    +

    +Fail marks the function as having failed but continues execution. +

    + + + + + +

    func (*T) FailNow

    +
    func (c *T) FailNow()
    +

    +FailNow marks the function as having failed and stops its execution. +Execution will continue at the next test or benchmark. +

    + + + + + +

    func (*T) Failed

    +
    func (c *T) Failed() bool
    +

    +Failed returns whether the function has failed. +

    + + + + + +

    func (*T) Fatal

    +
    func (c *T) Fatal(args ...interface{})
    +

    +Fatal is equivalent to Log() followed by FailNow(). +

    + + + + + +

    func (*T) Fatalf

    +
    func (c *T) Fatalf(format string, args ...interface{})
    +

    +Fatalf is equivalent to Logf() followed by FailNow(). +

    + + + + + +

    func (*T) Log

    +
    func (c *T) Log(args ...interface{})
    +

    +Log formats its arguments using default formatting, analogous to Println(), +and records the text in the error log. +

    + + + + + +

    func (*T) Logf

    +
    func (c *T) Logf(format string, args ...interface{})
    +

    +Logf formats its arguments according to the format, analogous to Printf(), +and records the text in the error log. +

    + + + + + +

    func (*T) Parallel

    +
    func (t *T) Parallel()
    +

    +Parallel signals that this test is to be run in parallel with (and only with) +other parallel tests in this CPU group. +

    + + + + + +
    + + + + + + + + + + + + +

    Subdirectories

    + +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name    Synopsis
    ..
    iotest    Package iotest implements Readers and Writers useful mainly for testing.
    quick    Package quick implements utility functions to help with black box testing.
    + + + + + + +

    + + + + + + diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/gowiki.html b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/gowiki.html new file mode 100644 index 0000000..2ed6bb7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/gowiki.html @@ -0,0 +1,1214 @@ + + + +Go (programming language) - Wikipedia, the free encyclopedia + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + + +
    + + +

    Go (programming language)

    + + +
    + +
    From Wikipedia, the free encyclopedia
    + + +
      (Redirected from Golang)
    + + +
    + Jump to: navigation, search +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Go
    Golang.png
    Paradigm(s)compiled, concurrent, imperative, structured
    Appeared in2009
    Designed byRobert Griesemer
    +Rob Pike
    +Ken Thompson
    DeveloperGoogle Inc.
    Stable releaseversion 1.0.2[1] (14 June 2012; 2 months ago (2012-06-14))
    Typing disciplinestrong, static
    Major implementationsgc (8g, 6g, 5g), gccgo
    Influenced byC, Limbo, Modula, Newsqueak, Oberon, Pascal,[2] Python
    OSLinux, Mac OS X, FreeBSD, OpenBSD, MS Windows, Plan 9[3]
    LicenseBSD-style[4] + Patent grant[5]
    Usual filename extensions.go
    Websitegolang.org
    +

    Go is a compiled, garbage-collected, concurrent programming language developed by Google Inc.[6]

    +

    The initial design of Go was started in September 2007 by Robert Griesemer, Rob Pike, and Ken Thompson.[2] Go was officially announced in November 2009. In May 2010, Rob Pike publicly stated that Go was being used "for real stuff" at Google.[7] Go's "gc" compiler targets the Linux, Mac OS X, FreeBSD, OpenBSD, Plan 9, and Microsoft Windows operating systems and the i386, amd64, and ARM processor architectures.[8]

    + + + + +
    +
    +

    Contents

    +
    + +
    +

    [edit] Goals

    +

    Go aims to provide the efficiency of a statically typed compiled language with the ease of programming of a dynamic language.[9] Other goals include:

    +
      +
    • Safety: Type-safe and memory-safe.
    • +
    • Good support for concurrency and communication.
    • +
    • Efficient, latency-free garbage collection.
    • +
    • High-speed compilation.
    • +
    +

    [edit] Description

    +

    The syntax of Go is broadly similar to that of C: blocks of code are surrounded with curly braces; common control flow structures include for, switch, and if. Unlike C, line-ending semicolons are optional, variable declarations are written differently and are usually optional, type conversions must be made explicit, and new go and select control keywords have been introduced to support concurrent programming. New built-in types include maps, Unicode strings, array slices, and channels for inter-thread communication.

    +

    Go is designed for exceptionally fast compiling times, even on modest hardware.[10] The language requires garbage collection. Certain concurrency-related structural conventions of Go (channels and alternative channel inputs) are borrowed from Tony Hoare's CSP. Unlike previous concurrent programming languages such as occam or Limbo, Go does not provide any built-in notion of safe or verifiable concurrency.[11]

    +

    Of features found in C++ or Java, Go does not include type inheritance, generic programming, assertions, method overloading, or pointer arithmetic.[2] Of these, the Go authors express an openness to generic programming, explicitly argue against assertions and pointer arithmetic, while defending the choice to omit type inheritance as giving a more useful language, encouraging heavy use of interfaces instead.[2] Initially, the language did not include exception handling, but in March 2010 a mechanism known as panic/recover was implemented to handle exceptional errors while avoiding some of the problems the Go authors find with exceptions.[12][13]

    +

    [edit] Type system

    +

    Go allows a programmer to write functions that can operate on inputs of arbitrary type, provided that the type implements the functions defined by a given interface.

    +

    Unlike Java, the interfaces a type supports do not need to be specified at the point at which the type is defined, and Go interfaces do not participate in a type hierarchy. A Go interface is best described as a set of methods, each identified by a name and signature. A type is considered to implement an interface if all the required methods have been defined for that type. An interface can be declared to "embed" other interfaces, meaning the declared interface includes the methods defined in the other interfaces.[11]

    +

    Unlike Java, the in-memory representation of an object does not contain a pointer to a virtual method table. Instead a value of interface type is implemented as a pair of a pointer to the object, and a pointer to a dictionary containing implementations of the interface methods for that type.

    +

    Consider the following example:

    +
    +
    +
    +type Sequence []int
    + 
    +func (s Sequence) Len() int {
    +    return len(s)
    +}
    + 
    +type HasLength interface {
    +    Len() int
    +}
    + 
    +func Foo (o HasLength) {
    +    ...
    +}
    +
    +
    +

    These four definitions could have been placed in separate files, in different parts of the program. Notably, the programmer who defined the Sequence type did not need to declare that the type implemented HasLength, and the person who implemented the Len method for Sequence did not need to specify that this method was part of HasLength.

    +

    [edit] Name visibility

    +

    Visibility of structures, structure fields, variables, constants, methods, top-level types and functions outside their defining package is defined implicitly according to the capitalization of their identifier.[14]

    +

    [edit] Concurrency

    +

    Go provides goroutines, small lightweight threads; the name alludes to coroutines. Goroutines are created with the go statement from anonymous or named functions.

    +

    Goroutines are executed in parallel with other goroutines, including their caller. They do not necessarily run in separate threads, but a group of goroutines are multiplexed onto multiple threads — execution control is moved between them by blocking them when sending or receiving messages over channels.

    +

    [edit] Implementations

    +

    There are currently two Go compilers:

    +
      +
    • 6g/8g/5g (the compilers for AMD64, x86, and ARM respectively) with their supporting tools (collectively known as "gc") based on Ken's previous work on Plan 9's C toolchain.
    • +
    • gccgo, a GCC frontend written in C++,[15] and now officially supported as of version 4.6, albeit not part of the standard binary for gcc.[16]
    • +
    +

    Both compilers work on Unix-like systems, and a port to Microsoft Windows of the gc compiler and runtime have been integrated in the main distribution. Most of the standard libraries also work on Windows.

    +

    There is also an unmaintained "tiny" runtime environment that allows Go programs to run on bare hardware.[17]

    +

    [edit] Examples

    +

    [edit] Hello world

    +

    The following is a Hello world program in Go:

    +
    +
    +
    +package main
    + 
    +import "fmt"
    + 
    +func main() {
    +        fmt.Println("Hello, World")
    +}
    +
    +
    +

    Go's automatic semicolon insertion feature requires that opening braces not be placed on their own lines, and this is thus the preferred brace style; the examples shown comply with this style.[18]

    +

    [edit] Echo

    +

    Example illustrating how to write a program like the Unix echo command in Go:[19]

    +
    +
    +
    +package main
    + 
    +import (
    +        "os"
    +        "flag"  // command line option parser
    +)
    + 
    +var omitNewline = flag.Bool("n", false, "don't print final newline")
    + 
    +const (
    +        Space = " "
    +        Newline = "\n"
    +)
    + 
    +func main() {
    +        flag.Parse()   // Scans the arg list and sets up flags
    +        var s string
    +        for i := 0; i < flag.NArg(); i++ {
    +                if i > 0 {
    +                        s += Space
    +                }
    +                s += flag.Arg(i)
    +        }
    +        if !*omitNewline {
    +                s += Newline
    +        }
    +        os.Stdout.WriteString(s)
    +}
    +
    +
    +

    [edit] Reception

    +

    Go's initial release led to much discussion.

    +

    Michele Simionato wrote in an article for artima.com:[20]

    +
    +
    Here I just wanted to point out the design choices about interfaces and inheritance. Such ideas are not new and it is a shame that no popular language has followed such particular route in the design space. I hope Go will become popular; if not, I hope such ideas will finally enter in a popular language, we are already 10 or 20 years too late :-(
    +
    +

    Dave Astels at Engine Yard wrote:[21]

    +
    +
    Go is extremely easy to dive into. There are a minimal number of fundamental language concepts and the syntax is clean and designed to be clear and unambiguous. Go is still experimental and still a little rough around the edges.
    +
    +

    Ars Technica interviewed Rob Pike, one of the authors of Go, and asked why a new language was needed. He replied that:[22]

    +
    +
    It wasn't enough to just add features to existing programming languages, because sometimes you can get more in the long run by taking things away. They wanted to start from scratch and rethink everything. ... [But they did not want] to deviate too much from what developers already knew because they wanted to avoid alienating Go's target audience.
    +
    +

    Go was in 15th place on the TIOBE Programming Community Index of programming language popularity in its first year, 2009,[citation needed] surpassing established languages like Pascal. As of March 2012, it ranked 66th in the index.[23]

    +

    Bruce Eckel stated:[24]

    +
    +
    The complexity of C++ (even more complexity has been added in the new C++), and the resulting impact on productivity, is no longer justified. All the hoops that the C++ programmer had to jump through in order to use a C-compatible language make no sense anymore -- they're just a waste of time and effort. Now, Go makes much more sense for the class of problems that C++ was originally intended to solve.
    +
    +

    [edit] Naming dispute

    +

    On the day of the general release of the language, Francis McCabe, developer of the Go! programming language (note the exclamation point), requested a name change of Google's language to prevent confusion with his language.[25] The issue was closed by a Google developer on 12 October 2010 with the custom status "Unfortunate", with a comment that "there are many computing products and services named Go. In the 11 months since our release, there has been minimal confusion of the two languages."[26]

    +

    [edit] See also

    + +

    [edit] References

    + +
    +
      +
    1. ^ "golang-announce: go1.0.2 released". https://groups.google.com/forum/#!msg/golang-announce/9-f_fnXNDzw/MiM3tk0iyjYJ. Retrieved 14 June 2012. 
    2. +
    3. ^ a b c d "Language Design FAQ". golang.org. 16 January 2010. http://golang.org/doc/go_faq.html. Retrieved 27 February 2010. 
    4. +
    5. ^ "Go Porting Efforts". Go Language Resources. cat-v. 12 January 2010. http://go-lang.cat-v.org/os-ports. Retrieved 18 January 2010. 
    6. +
    7. ^ "Text file LICENSE". http://golang.org/LICENSE. Retrieved 27 January 2011. 
    8. +
    9. ^ "Additional IP Rights Grant". http://code.google.com/p/go/source/browse/PATENTS. Retrieved 26 July 2012. 
    10. +
    11. ^ Kincaid, Jason (10 November 2009). "Google’s Go: A New Programming Language That’s Python Meets C++". TechCrunch. http://www.techcrunch.com/2009/11/10/google-go-language/. Retrieved 18 January 2010. 
    12. +
    13. ^ Metz, Cade (20 May 2010). "Google programming Frankenstein is a Go". The Register. http://www.theregister.co.uk/2010/05/20/go_in_production_at_google/. 
    14. +
    15. ^ "Installing Go". golang.org. The Go Authors. 11 June 2010. http://golang.org/doc/install.html#tmp_33. Retrieved 11 June 2010. 
    16. +
    17. ^ Pike, Rob. "The Go Programming Language". YouTube. http://www.youtube.com/watch?v=rKnDgT73v8s&feature=related. Retrieved 1 Jul 2011. 
    18. +
    19. ^ Rob Pike (10 November 2009) (flv). The Go Programming Language (Tech talk). Google. Event occurs at 8:53. http://www.youtube.com/watch?v=rKnDgT73v8s#t=8m53. 
    20. +
    21. ^ a b "The Go Memory Model". Google. http://golang.org/doc/go_mem.html. Retrieved 5 January 2011. 
    22. +
    23. ^ Release notes, 30 March 2010
    24. +
    25. ^ "Proposal for an exception-like mechanism". golang-nuts. 25 March 2010. http://groups.google.com/group/golang-nuts/browse_thread/thread/1ce5cd050bb973e4. Retrieved 25 March 2010. 
    26. +
    27. ^ "A Tutorial for the Go Programming Language". The Go Programming Language. Google. http://golang.org/doc/go_tutorial.html. Retrieved 10 March 2010. "In Go the rule about visibility of information is simple: if a name (of a top-level type, function, method, constant or variable, or of a structure field or method) is capitalized, users of the package may see it. Otherwise, the name and hence the thing being named is visible only inside the package in which it is declared." 
    28. +
    29. ^ "FAQ: Implementation". golang.org. 16 January 2010. http://golang.org/doc/go_faq.html#Implementation. Retrieved 18 January 2010. 
    30. +
    31. ^ "Installing GCC: Configuration". http://gcc.gnu.org/install/configure.html. Retrieved 3 December 2011. "Ada, Go and Objective-C++ are not default languages" 
    32. +
    33. ^ Gerrand, Andrew (1 February 2011). "release.2011-02-01". golang-nuts. Google. http://groups.google.com/group/golang-nuts/browse_thread/thread/b877e34723b543a7. Retrieved 5 February 2011. 
    34. +
    35. ^ "A Tutorial for the Go Programming Language". The Go Programming Language. Google. http://golang.org/doc/go_tutorial.html. Retrieved 10 March 2010. "The one surprise is that it's important to put the opening brace of a construct such as an if statement on the same line as the if; however, if you don't, there are situations that may not compile or may give the wrong result. The language forces the brace style to some extent." 
    36. +
    37. ^ "A Tutorial for the Go Programming Language". golang.org. 16 January 2010. http://golang.org/doc/go_tutorial.html. Retrieved 18 January 2010. 
    38. +
    39. ^ Simionato, Michele (15 November 2009). "Interfaces vs Inheritance (or, watch out for Go!)". artima. http://www.artima.com/weblogs/viewpost.jsp?thread=274019. Retrieved 15 November 2009. 
    40. +
    41. ^ Astels, Dave (9 November 2009). "Ready, Set, Go!". engineyard. http://www.engineyard.com/blog/2009/ready-set-go/. Retrieved 9 November 2009. 
    42. +
    43. ^ Paul, Ryan (10 November 2009). "Go: new open source programming language from Google". Ars Technica. http://arstechnica.com/open-source/news/2009/11/go-new-open-source-programming-language-from-google.ars. Retrieved 13 November 2009. 
    44. +
    45. ^ "TIOBE Programming Community Index for March 2012". TIOBE Software. March 2012. http://es.scribd.com/doc/89569304/TIOBE-Programming-Community-Index-for-March-2012. Retrieved 28 April 2012. 
    46. +
    47. ^ Bruce Eckel (27). "Calling Go from Python via JSON-RPC". http://www.artima.com/weblogs/viewpost.jsp?thread=333589. Retrieved 29 August 2011. 
    48. +
    49. ^ Claburn, Thomas (11 November 2009). "Google 'Go' Name Brings Accusations Of Evil'". InformationWeek. http://www.informationweek.com/news/software/web_services/showArticle.jhtml?articleID=221601351. Retrieved 18 January 2010. 
    50. +
    51. ^ "Issue 9 - go - I have already used the name for *MY* programming language". Google Code. Google Inc.. http://code.google.com/p/go/issues/detail?id=9. Retrieved 12 October 2010. 
    52. +
    +
    +

    [edit] Further reading

    + +

    [edit] External links

    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + + +
    + +
    + + +
    + + +
    +
    Personal tools
    + +
    + + +
    + + +
    +
    Namespaces
    + +
    + + + + +
    +

    +

    +
    Variants
    + +
    + + +
    +
    + + +
    +
    Views
    + +
    + + + + +
    +
    Actions
    + +
    + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/metalreview.html b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/metalreview.html new file mode 100644 index 0000000..fc4a38f --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/metalreview.html @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + Metal Reviews, News, Blogs, Interviews and Community | Metal Review + + + + + + + + + + +
    +
    + + + +
    + + + + +
    +
    + + + + +
    +
    +
    + +
    +
    +
    +
    + + + + + +
    +

    Reviews

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
      + +
    • +

      + Serpentine Path - Serpentine Path + Serpentine Path
      + Serpentine Path
      + +

      +
    • + +
    • +

      + Hunter + Hunter's Ground
      + No God But the Wild
      + +

      +
    • + +
    • +

      + Blut Aus Nord - 777 - Cosmosophy + Blut Aus Nord
      + 777 - Cosmosophy
      + Black +

      +
    • + +
    • +

      + Ufomammut - Oro: Opus Alter + Ufomammut
      + Oro: Opus Alter
      + Doom +

      +
    • + +
    • +

      + Resurgency - False Enlightenment + Resurgency
      + False Enlightenment
      + Death +

      +
    • + +
    • +

      + Morgoth - Cursed to Live + Morgoth
      + Cursed to Live
      + DeathLive +

      +
    • + +
    • +

      + Krallice - Years Past Matter + Krallice
      + Years Past Matter
      + Black +

      +
    • + +
    • +

      + Murder Construct - Results + Murder Construct
      + Results
      + Grindcore +

      +
    • + +
    • +

      + Grave - Endless Procession of Souls + Grave
      + Endless Procession of Souls
      + Death +

      +
    • + +
    • +

      + Master - The New Elite + Master
      + The New Elite
      + Death +

      +
    • + +
    +
    +
    +
    +
    +
    +
    + Serpentine Path - Serpentine PathHunter's Ground - No God But the WildBlut Aus Nord - 777 - CosmosophyUfomammut - Oro: Opus AlterResurgency - False EnlightenmentMorgoth - Cursed to LiveKrallice - Years Past MatterMurder Construct - ResultsGrave - Endless Procession of SoulsMaster - The New Elite +
    +
    +
    +
    + + + + + + + +
    +
    +
    +
    +
    + + + + +
    Goto Next Group
    +
    Goto Previous Group
    + + + + + +
    + +
    + + + + + + + +
    +

    Lashes

    +
    NEW Katatonia - Dead End Kings
    45 minutes ago by Chaosjunkie
    +
    Katatonia - Dead End Kings
    1 hour ago by Harry Dick Rotten
    +
    Resurgency - False Enlightenment
    3 hours ago by Anonymous
    +
    Witchcraft - The Alchemist
    5 hours ago by Luke_22
    +
    Katatonia - Dead End Kings
    9 hours ago by chaosjunkie
    +
    Katatonia - Dead End Kings
    10 hours ago by Compeller
    +
    Manetheren - Time
    10 hours ago by xpmule
    +
    Ufomammut - Oro: Opus Alter
    16 hours ago by Anonymous
    +
    Ufomammut - Oro: Opus Alter
    17 hours ago by Harry Dick Rotten
    +
    Katatonia - Dead End Kings
    yesterday by Chaosjunkie
    +
    Katatonia - Dead End Kings
    yesterday by Anonymous
    +
    Katatonia - Dead End Kings
    yesterday by Anonymous
    +
    Katatonia - Dead End Kings
    yesterday by Anonymous
    +
    Katatonia - Dead End Kings
    yesterday by frantic
    +
    Blut Aus Nord - 777 - Cosmosophy
    yesterday by Dimensional Bleedthrough
    + +
    + +
    +
    +
    + + + +
    +
    + + + + + + + + + + + diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page.html b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page.html new file mode 100644 index 0000000..92ec74e --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page.html @@ -0,0 +1,102 @@ + + + + + + + Provok.in + + + + + + + + + +
    +
    +
    +   +
    +
    +
    +
    +
    +
    +

    + Provok.in +

    +

    + Prove your point. +

    +
    +
    +
    +
    + Beta Version. Things may change. Or disappear. Or fail miserably. If it's the latter, please file an issue. +
    +
    + +
    + Welcome, {{getUserName()}} ( logout ) +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    +
    +
    +
    +
    + × +

    + {{ title }} +

    +

    + {{ message }} +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +   +
    +
    +
    +
    +   +
    +
    + +
    +
    +   +
    +
    +
    + + \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page2.html b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page2.html new file mode 100644 index 0000000..249209b --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/testdata/page2.html @@ -0,0 +1,24 @@ + + + + Tests for siblings + + +
    +
    +
    +
    +
    +
    +
    +
    + + + diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal.go b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal.go new file mode 100644 index 0000000..8fbeddf --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal.go @@ -0,0 +1,535 @@ +package goquery + +import ( + "code.google.com/p/cascadia" + "code.google.com/p/go.net/html" +) + +type siblingType int + +// Sibling type, used internally when iterating over children at the same +// level (siblings) to specify which nodes are requested. +const ( + siblingPrevUntil siblingType = iota - 3 + siblingPrevAll + siblingPrev + siblingAll + siblingNext + siblingNextAll + siblingNextUntil + siblingAllIncludingNonElements +) + +// Find gets the descendants of each element in the current set of matched +// elements, filtered by a selector. It returns a new Selection object +// containing these matched elements. +func (s *Selection) Find(selector string) *Selection { + return pushStack(s, findWithSelector(s.Nodes, selector)) +} + +// FindSelection gets the descendants of each element in the current +// Selection, filtered by a Selection. It returns a new Selection object +// containing these matched elements. +func (s *Selection) FindSelection(sel *Selection) *Selection { + if sel == nil { + return pushStack(s, nil) + } + return s.FindNodes(sel.Nodes...) +} + +// FindNodes gets the descendants of each element in the current +// Selection, filtered by some nodes. It returns a new Selection object +// containing these matched elements. +func (s *Selection) FindNodes(nodes ...*html.Node) *Selection { + return pushStack(s, mapNodes(nodes, func(i int, n *html.Node) []*html.Node { + if sliceContains(s.Nodes, n) { + return []*html.Node{n} + } + return nil + })) +} + +// Contents gets the children of each element in the Selection, +// including text and comment nodes. It returns a new Selection object +// containing these elements. +func (s *Selection) Contents() *Selection { + return pushStack(s, getChildrenNodes(s.Nodes, siblingAllIncludingNonElements)) +} + +// ContentsFiltered gets the children of each element in the Selection, +// filtered by the specified selector. It returns a new Selection +// object containing these elements. Since selectors only act on Element nodes, +// this function is an alias to ChildrenFiltered unless the selector is empty, +// in which case it is an alias to Contents. +func (s *Selection) ContentsFiltered(selector string) *Selection { + if selector != "" { + return s.ChildrenFiltered(selector) + } + return s.Contents() +} + +// Children gets the child elements of each element in the Selection. +// It returns a new Selection object containing these elements. +func (s *Selection) Children() *Selection { + return pushStack(s, getChildrenNodes(s.Nodes, siblingAll)) +} + +// ChildrenFiltered gets the child elements of each element in the Selection, +// filtered by the specified selector. It returns a new +// Selection object containing these elements. +func (s *Selection) ChildrenFiltered(selector string) *Selection { + return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), selector) +} + +// Parent gets the parent of each element in the Selection. It returns a +// new Selection object containing the matched elements. +func (s *Selection) Parent() *Selection { + return pushStack(s, getParentNodes(s.Nodes)) +} + +// ParentFiltered gets the parent of each element in the Selection filtered by a +// selector. It returns a new Selection object containing the matched elements. +func (s *Selection) ParentFiltered(selector string) *Selection { + return filterAndPush(s, getParentNodes(s.Nodes), selector) +} + +// Closest gets the first element that matches the selector by testing the +// element itself and traversing up through its ancestors in the DOM tree. +func (s *Selection) Closest(selector string) *Selection { + cs := cascadia.MustCompile(selector) + + return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node { + // For each node in the selection, test the node itself, then each parent + // until a match is found. + for ; n != nil; n = n.Parent { + if cs.Match(n) { + return []*html.Node{n} + } + } + return nil + })) +} + +// ClosestNodes gets the first element that matches one of the nodes by testing the +// element itself and traversing up through its ancestors in the DOM tree. +func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection { + return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node { + // For each node in the selection, test the node itself, then each parent + // until a match is found. + for ; n != nil; n = n.Parent { + if isInSlice(nodes, n) { + return []*html.Node{n} + } + } + return nil + })) +} + +// ClosestSelection gets the first element that matches one of the nodes in the +// Selection by testing the element itself and traversing up through its ancestors +// in the DOM tree. +func (s *Selection) ClosestSelection(sel *Selection) *Selection { + if sel == nil { + return pushStack(s, nil) + } + return s.ClosestNodes(sel.Nodes...) +} + +// Parents gets the ancestors of each element in the current Selection. It +// returns a new Selection object with the matched elements. +func (s *Selection) Parents() *Selection { + return pushStack(s, getParentsNodes(s.Nodes, "", nil)) +} + +// ParentsFiltered gets the ancestors of each element in the current +// Selection. It returns a new Selection object with the matched elements. +func (s *Selection) ParentsFiltered(selector string) *Selection { + return filterAndPush(s, getParentsNodes(s.Nodes, "", nil), selector) +} + +// ParentsUntil gets the ancestors of each element in the Selection, up to but +// not including the element matched by the selector. It returns a new Selection +// object containing the matched elements. +func (s *Selection) ParentsUntil(selector string) *Selection { + return pushStack(s, getParentsNodes(s.Nodes, selector, nil)) +} + +// ParentsUntilSelection gets the ancestors of each element in the Selection, +// up to but not including the elements in the specified Selection. It returns a +// new Selection object containing the matched elements. +func (s *Selection) ParentsUntilSelection(sel *Selection) *Selection { + if sel == nil { + return s.Parents() + } + return s.ParentsUntilNodes(sel.Nodes...) +} + +// ParentsUntilNodes gets the ancestors of each element in the Selection, +// up to but not including the specified nodes. It returns a +// new Selection object containing the matched elements. +func (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection { + return pushStack(s, getParentsNodes(s.Nodes, "", nodes)) +} + +// ParentsFilteredUntil is like ParentsUntil, with the option to filter the +// results based on a selector string. It returns a new Selection +// object containing the matched elements. +func (s *Selection) ParentsFilteredUntil(filterSelector string, untilSelector string) *Selection { + return filterAndPush(s, getParentsNodes(s.Nodes, untilSelector, nil), filterSelector) +} + +// ParentsFilteredUntilSelection is like ParentsUntilSelection, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { + if sel == nil { + return s.ParentsFiltered(filterSelector) + } + return s.ParentsFilteredUntilNodes(filterSelector, sel.Nodes...) +} + +// ParentsFilteredUntilNodes is like ParentsUntilNodes, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { + return filterAndPush(s, getParentsNodes(s.Nodes, "", nodes), filterSelector) +} + +// Siblings gets the siblings of each element in the Selection. It returns +// a new Selection object containing the matched elements. +func (s *Selection) Siblings() *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingAll, "", nil)) +} + +// SiblingsFiltered gets the siblings of each element in the Selection +// filtered by a selector. It returns a new Selection object containing the +// matched elements. +func (s *Selection) SiblingsFiltered(selector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, "", nil), selector) +} + +// Next gets the immediately following sibling of each element in the +// Selection. It returns a new Selection object containing the matched elements. +func (s *Selection) Next() *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingNext, "", nil)) +} + +// NextFiltered gets the immediately following sibling of each element in the +// Selection filtered by a selector. It returns a new Selection object +// containing the matched elements. +func (s *Selection) NextFiltered(selector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, "", nil), selector) +} + +// NextAll gets all the following siblings of each element in the +// Selection. It returns a new Selection object containing the matched elements. +func (s *Selection) NextAll() *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingNextAll, "", nil)) +} + +// NextAllFiltered gets all the following siblings of each element in the +// Selection filtered by a selector. It returns a new Selection object +// containing the matched elements. +func (s *Selection) NextAllFiltered(selector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, "", nil), selector) +} + +// Prev gets the immediately preceding sibling of each element in the +// Selection. It returns a new Selection object containing the matched elements. +func (s *Selection) Prev() *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingPrev, "", nil)) +} + +// PrevFiltered gets the immediately preceding sibling of each element in the +// Selection filtered by a selector. It returns a new Selection object +// containing the matched elements. +func (s *Selection) PrevFiltered(selector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, "", nil), selector) +} + +// PrevAll gets all the preceding siblings of each element in the +// Selection. It returns a new Selection object containing the matched elements. +func (s *Selection) PrevAll() *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevAll, "", nil)) +} + +// PrevAllFiltered gets all the preceding siblings of each element in the +// Selection filtered by a selector. It returns a new Selection object +// containing the matched elements. +func (s *Selection) PrevAllFiltered(selector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, "", nil), selector) +} + +// NextUntil gets all following siblings of each element up to but not +// including the element matched by the selector. It returns a new Selection +// object containing the matched elements. +func (s *Selection) NextUntil(selector string) *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil, + selector, nil)) +} + +// NextUntilSelection gets all following siblings of each element up to but not +// including the element matched by the Selection. It returns a new Selection +// object containing the matched elements. +func (s *Selection) NextUntilSelection(sel *Selection) *Selection { + if sel == nil { + return s.NextAll() + } + return s.NextUntilNodes(sel.Nodes...) +} + +// NextUntilNodes gets all following siblings of each element up to but not +// including the element matched by the nodes. It returns a new Selection +// object containing the matched elements. +func (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil, + "", nodes)) +} + +// PrevUntil gets all preceding siblings of each element up to but not +// including the element matched by the selector. It returns a new Selection +// object containing the matched elements. +func (s *Selection) PrevUntil(selector string) *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil, + selector, nil)) +} + +// PrevUntilSelection gets all preceding siblings of each element up to but not +// including the element matched by the Selection. It returns a new Selection +// object containing the matched elements. +func (s *Selection) PrevUntilSelection(sel *Selection) *Selection { + if sel == nil { + return s.PrevAll() + } + return s.PrevUntilNodes(sel.Nodes...) +} + +// PrevUntilNodes gets all preceding siblings of each element up to but not +// including the element matched by the nodes. It returns a new Selection +// object containing the matched elements. +func (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection { + return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil, + "", nodes)) +} + +// NextFilteredUntil is like NextUntil, with the option to filter +// the results based on a selector string. +// It returns a new Selection object containing the matched elements. +func (s *Selection) NextFilteredUntil(filterSelector string, untilSelector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, + untilSelector, nil), filterSelector) +} + +// NextFilteredUntilSelection is like NextUntilSelection, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { + if sel == nil { + return s.NextFiltered(filterSelector) + } + return s.NextFilteredUntilNodes(filterSelector, sel.Nodes...) +} + +// NextFilteredUntilNodes is like NextUntilNodes, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, + "", nodes), filterSelector) +} + +// PrevFilteredUntil is like PrevUntil, with the option to filter +// the results based on a selector string. +// It returns a new Selection object containing the matched elements. +func (s *Selection) PrevFilteredUntil(filterSelector string, untilSelector string) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, + untilSelector, nil), filterSelector) +} + +// PrevFilteredUntilSelection is like PrevUntilSelection, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { + if sel == nil { + return s.PrevFiltered(filterSelector) + } + return s.PrevFilteredUntilNodes(filterSelector, sel.Nodes...) +} + +// PrevFilteredUntilNodes is like PrevUntilNodes, with the +// option to filter the results based on a selector string. It returns a new +// Selection object containing the matched elements. +func (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { + return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, + "", nodes), filterSelector) +} + +// Filter and push filters the nodes based on a selector, and pushes the results +// on the stack, with the srcSel as previous selection. +func filterAndPush(srcSel *Selection, nodes []*html.Node, selector string) *Selection { + // Create a temporary Selection with the specified nodes to filter using winnow + sel := &Selection{nodes, srcSel.document, nil} + // Filter based on selector and push on stack + return pushStack(srcSel, winnow(sel, selector, true)) +} + +// Internal implementation of Find that return raw nodes. +func findWithSelector(nodes []*html.Node, selector string) []*html.Node { + // Compile the selector once + sel := cascadia.MustCompile(selector) + // Map nodes to find the matches within the children of each node + return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) { + // Go down one level, becausejQuery's Find selects only within descendants + for c := n.FirstChild; c != nil; c = c.NextSibling { + if c.Type == html.ElementNode { + result = append(result, sel.MatchAll(c)...) + } + } + return + }) +} + +// Internal implementation to get all parent nodes, stopping at the specified +// node (or nil if no stop). +func getParentsNodes(nodes []*html.Node, stopSelector string, stopNodes []*html.Node) []*html.Node { + return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) { + for p := n.Parent; p != nil; p = p.Parent { + sel := newSingleSelection(p, nil) + if stopSelector != "" { + if sel.Is(stopSelector) { + break + } + } else if len(stopNodes) > 0 { + if sel.IsNodes(stopNodes...) { + break + } + } + if p.Type == html.ElementNode { + result = append(result, p) + } + } + return + }) +} + +// Internal implementation of sibling nodes that return a raw slice of matches. +func getSiblingNodes(nodes []*html.Node, st siblingType, untilSelector string, untilNodes []*html.Node) []*html.Node { + var f func(*html.Node) bool + + // If the requested siblings are ...Until, create the test function to + // determine if the until condition is reached (returns true if it is) + if st == siblingNextUntil || st == siblingPrevUntil { + f = func(n *html.Node) bool { + if untilSelector != "" { + // Selector-based condition + sel := newSingleSelection(n, nil) + return sel.Is(untilSelector) + } else if len(untilNodes) > 0 { + // Nodes-based condition + sel := newSingleSelection(n, nil) + return sel.IsNodes(untilNodes...) + } + return false + } + } + + return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { + return getChildrenWithSiblingType(n.Parent, st, n, f) + }) +} + +// Gets the children nodes of each node in the specified slice of nodes, +// based on the sibling type request. +func getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node { + return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { + return getChildrenWithSiblingType(n, st, nil, nil) + }) +} + +// Gets the children of the specified parent, based on the requested sibling +// type, skipping a specified node if required. +func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node, + untilFunc func(*html.Node) bool) (result []*html.Node) { + + // Create the iterator function + var iter = func(cur *html.Node) (ret *html.Node) { + // Based on the sibling type requested, iterate the right way + for { + switch st { + case siblingAll, siblingAllIncludingNonElements: + if cur == nil { + // First iteration, start with first child of parent + // Skip node if required + if ret = parent.FirstChild; ret == skipNode && skipNode != nil { + ret = skipNode.NextSibling + } + } else { + // Skip node if required + if ret = cur.NextSibling; ret == skipNode && skipNode != nil { + ret = skipNode.NextSibling + } + } + case siblingPrev, siblingPrevAll, siblingPrevUntil: + if cur == nil { + // Start with previous sibling of the skip node + ret = skipNode.PrevSibling + } else { + ret = cur.PrevSibling + } + case siblingNext, siblingNextAll, siblingNextUntil: + if cur == nil { + // Start with next sibling of the skip node + ret = skipNode.NextSibling + } else { + ret = cur.NextSibling + } + default: + panic("Invalid sibling type.") + } + if ret == nil || ret.Type == html.ElementNode || st == siblingAllIncludingNonElements { + return + } + // Not a valid node, try again from this one + cur = ret + } + } + + for c := iter(nil); c != nil; c = iter(c) { + // If this is an ...Until case, test before append (returns true + // if the until condition is reached) + if st == siblingNextUntil || st == siblingPrevUntil { + if untilFunc(c) { + return + } + } + result = append(result, c) + if st == siblingNext || st == siblingPrev { + // Only one node was requested (immediate next or previous), so exit + return + } + } + return +} + +// Internal implementation of parent nodes that return a raw slice of Nodes. +func getParentNodes(nodes []*html.Node) []*html.Node { + return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { + if n.Parent != nil && n.Parent.Type == html.ElementNode { + return []*html.Node{n.Parent} + } + return nil + }) +} + +// Internal map function used by many traversing methods. Takes the source nodes +// to iterate on and the mapping function that returns an array of nodes. +// Returns an array of nodes mapped by calling the callback function once for +// each node in the source nodes. +func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) { + for i, n := range nodes { + if vals := f(i, n); len(vals) > 0 { + result = appendWithoutDuplicates(result, vals) + } + } + return +} diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal_test.go b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal_test.go new file mode 100644 index 0000000..d881cd8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/traversal_test.go @@ -0,0 +1,697 @@ +package goquery + +import ( + "strings" + "testing" +) + +func TestFind(t *testing.T) { + sel := Doc().Find("div.row-fluid") + AssertLength(t, sel.Nodes, 9) +} + +func TestFindRollback(t *testing.T) { + sel := Doc().Find("div.row-fluid") + sel2 := sel.Find("a").End() + AssertEqual(t, sel, sel2) +} + +func TestFindNotSelf(t *testing.T) { + sel := Doc().Find("h1").Find("h1") + AssertLength(t, sel.Nodes, 0) +} + +func TestFindInvalidSelector(t *testing.T) { + defer AssertPanic(t) + Doc().Find(":+ ^") +} + +func TestChainedFind(t *testing.T) { + sel := Doc().Find("div.hero-unit").Find(".row-fluid") + AssertLength(t, sel.Nodes, 4) +} + +func TestChildren(t *testing.T) { + sel := Doc().Find(".pvk-content").Children() + AssertLength(t, sel.Nodes, 5) +} + +func TestChildrenRollback(t *testing.T) { + sel := Doc().Find(".pvk-content") + sel2 := sel.Children().End() + AssertEqual(t, sel, sel2) +} + +func TestContents(t *testing.T) { + sel := Doc().Find(".pvk-content").Contents() + AssertLength(t, sel.Nodes, 13) +} + +func TestContentsRollback(t *testing.T) { + sel := Doc().Find(".pvk-content") + sel2 := sel.Contents().End() + AssertEqual(t, sel, sel2) +} + +func TestChildrenFiltered(t *testing.T) { + sel := Doc().Find(".pvk-content").ChildrenFiltered(".hero-unit") + AssertLength(t, sel.Nodes, 1) +} + +func TestChildrenFilteredRollback(t *testing.T) { + sel := Doc().Find(".pvk-content") + sel2 := sel.ChildrenFiltered(".hero-unit").End() + AssertEqual(t, sel, sel2) +} + +func TestContentsFiltered(t *testing.T) { + sel := Doc().Find(".pvk-content").ContentsFiltered(".hero-unit") + AssertLength(t, sel.Nodes, 1) +} + +func TestContentsFilteredRollback(t *testing.T) { + sel := Doc().Find(".pvk-content") + sel2 := sel.ContentsFiltered(".hero-unit").End() + AssertEqual(t, sel, sel2) +} + +func TestChildrenFilteredNone(t *testing.T) { + sel := Doc().Find(".pvk-content").ChildrenFiltered("a.btn") + AssertLength(t, sel.Nodes, 0) +} + +func TestParent(t *testing.T) { + sel := Doc().Find(".container-fluid").Parent() + AssertLength(t, sel.Nodes, 3) +} + +func TestParentRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.Parent().End() + AssertEqual(t, sel, sel2) +} + +func TestParentBody(t *testing.T) { + sel := Doc().Find("body").Parent() + AssertLength(t, sel.Nodes, 1) +} + +func TestParentFiltered(t *testing.T) { + sel := Doc().Find(".container-fluid").ParentFiltered(".hero-unit") + AssertLength(t, sel.Nodes, 1) + AssertClass(t, sel, "hero-unit") +} + +func TestParentFilteredRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ParentFiltered(".hero-unit").End() + AssertEqual(t, sel, sel2) +} + +func TestParents(t *testing.T) { + sel := Doc().Find(".container-fluid").Parents() + AssertLength(t, sel.Nodes, 8) +} + +func TestParentsOrder(t *testing.T) { + sel := Doc().Find("#cf2").Parents() + AssertLength(t, sel.Nodes, 6) + AssertSelectionIs(t, sel, ".hero-unit", ".pvk-content", "div.row-fluid", "#cf1", "body", "html") +} + +func TestParentsRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.Parents().End() + AssertEqual(t, sel, sel2) +} + +func TestParentsFiltered(t *testing.T) { + sel := Doc().Find(".container-fluid").ParentsFiltered("body") + AssertLength(t, sel.Nodes, 1) +} + +func TestParentsFilteredRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ParentsFiltered("body").End() + AssertEqual(t, sel, sel2) +} + +func TestParentsUntil(t *testing.T) { + sel := Doc().Find(".container-fluid").ParentsUntil("body") + AssertLength(t, sel.Nodes, 6) +} + +func TestParentsUntilRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ParentsUntil("body").End() + AssertEqual(t, sel, sel2) +} + +func TestParentsUntilSelection(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".pvk-content") + sel = sel.ParentsUntilSelection(sel2) + AssertLength(t, sel.Nodes, 3) +} + +func TestParentsUntilSelectionRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".pvk-content") + sel2 = sel.ParentsUntilSelection(sel2).End() + AssertEqual(t, sel, sel2) +} + +func TestParentsUntilNodes(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".pvk-content, .hero-unit") + sel = sel.ParentsUntilNodes(sel2.Nodes...) + AssertLength(t, sel.Nodes, 2) +} + +func TestParentsUntilNodesRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".pvk-content, .hero-unit") + sel2 = sel.ParentsUntilNodes(sel2.Nodes...).End() + AssertEqual(t, sel, sel2) +} + +func TestParentsFilteredUntil(t *testing.T) { + sel := Doc().Find(".container-fluid").ParentsFilteredUntil(".pvk-content", "body") + AssertLength(t, sel.Nodes, 2) +} + +func TestParentsFilteredUntilRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ParentsFilteredUntil(".pvk-content", "body").End() + AssertEqual(t, sel, sel2) +} + +func TestParentsFilteredUntilSelection(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".row-fluid") + sel = sel.ParentsFilteredUntilSelection("div", sel2) + AssertLength(t, sel.Nodes, 3) +} + +func TestParentsFilteredUntilSelectionRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".row-fluid") + sel2 = sel.ParentsFilteredUntilSelection("div", sel2).End() + AssertEqual(t, sel, sel2) +} + +func TestParentsFilteredUntilNodes(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".row-fluid") + sel = sel.ParentsFilteredUntilNodes("body", sel2.Nodes...) + AssertLength(t, sel.Nodes, 1) +} + +func TestParentsFilteredUntilNodesRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := Doc().Find(".row-fluid") + sel2 = sel.ParentsFilteredUntilNodes("body", sel2.Nodes...).End() + AssertEqual(t, sel, sel2) +} + +func TestSiblings(t *testing.T) { + sel := Doc().Find("h1").Siblings() + AssertLength(t, sel.Nodes, 1) +} + +func TestSiblingsRollback(t *testing.T) { + sel := Doc().Find("h1") + sel2 := sel.Siblings().End() + AssertEqual(t, sel, sel2) +} + +func TestSiblings2(t *testing.T) { + sel := Doc().Find(".pvk-gutter").Siblings() + AssertLength(t, sel.Nodes, 9) +} + +func TestSiblings3(t *testing.T) { + sel := Doc().Find("body>.container-fluid").Siblings() + AssertLength(t, sel.Nodes, 0) +} + +func TestSiblingsFiltered(t *testing.T) { + sel := Doc().Find(".pvk-gutter").SiblingsFiltered(".pvk-content") + AssertLength(t, sel.Nodes, 3) +} + +func TestSiblingsFilteredRollback(t *testing.T) { + sel := Doc().Find(".pvk-gutter") + sel2 := sel.SiblingsFiltered(".pvk-content").End() + AssertEqual(t, sel, sel2) +} + +func TestNext(t *testing.T) { + sel := Doc().Find("h1").Next() + AssertLength(t, sel.Nodes, 1) +} + +func TestNextRollback(t *testing.T) { + sel := Doc().Find("h1") + sel2 := sel.Next().End() + AssertEqual(t, sel, sel2) +} + +func TestNext2(t *testing.T) { + sel := Doc().Find(".close").Next() + AssertLength(t, sel.Nodes, 1) +} + +func TestNextNone(t *testing.T) { + sel := Doc().Find("small").Next() + AssertLength(t, sel.Nodes, 0) +} + +func TestNextFiltered(t *testing.T) { + sel := Doc().Find(".container-fluid").NextFiltered("div") + AssertLength(t, sel.Nodes, 2) +} + +func TestNextFilteredRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.NextFiltered("div").End() + AssertEqual(t, sel, sel2) +} + +func TestNextFiltered2(t *testing.T) { + sel := Doc().Find(".container-fluid").NextFiltered("[ng-view]") + AssertLength(t, sel.Nodes, 1) +} + +func TestPrev(t *testing.T) { + sel := Doc().Find(".red").Prev() + AssertLength(t, sel.Nodes, 1) + AssertClass(t, sel, "green") +} + +func TestPrevRollback(t *testing.T) { + sel := Doc().Find(".red") + sel2 := sel.Prev().End() + AssertEqual(t, sel, sel2) +} + +func TestPrev2(t *testing.T) { + sel := Doc().Find(".row-fluid").Prev() + AssertLength(t, sel.Nodes, 5) +} + +func TestPrevNone(t *testing.T) { + sel := Doc().Find("h2").Prev() + AssertLength(t, sel.Nodes, 0) +} + +func TestPrevFiltered(t *testing.T) { + sel := Doc().Find(".row-fluid").PrevFiltered(".row-fluid") + AssertLength(t, sel.Nodes, 5) +} + +func TestPrevFilteredRollback(t *testing.T) { + sel := Doc().Find(".row-fluid") + sel2 := sel.PrevFiltered(".row-fluid").End() + AssertEqual(t, sel, sel2) +} + +func TestNextAll(t *testing.T) { + sel := Doc().Find("#cf2 div:nth-child(1)").NextAll() + AssertLength(t, sel.Nodes, 3) +} + +func TestNextAllRollback(t *testing.T) { + sel := Doc().Find("#cf2 div:nth-child(1)") + sel2 := sel.NextAll().End() + AssertEqual(t, sel, sel2) +} + +func TestNextAll2(t *testing.T) { + sel := Doc().Find("div[ng-cloak]").NextAll() + AssertLength(t, sel.Nodes, 1) +} + +func TestNextAllNone(t *testing.T) { + sel := Doc().Find(".footer").NextAll() + AssertLength(t, sel.Nodes, 0) +} + +func TestNextAllFiltered(t *testing.T) { + sel := Doc().Find("#cf2 .row-fluid").NextAllFiltered("[ng-cloak]") + AssertLength(t, sel.Nodes, 2) +} + +func TestNextAllFilteredRollback(t *testing.T) { + sel := Doc().Find("#cf2 .row-fluid") + sel2 := sel.NextAllFiltered("[ng-cloak]").End() + AssertEqual(t, sel, sel2) +} + +func TestNextAllFiltered2(t *testing.T) { + sel := Doc().Find(".close").NextAllFiltered("h4") + AssertLength(t, sel.Nodes, 1) +} + +func TestPrevAll(t *testing.T) { + sel := Doc().Find("[ng-view]").PrevAll() + AssertLength(t, sel.Nodes, 2) +} + +func TestPrevAllOrder(t *testing.T) { + sel := Doc().Find("[ng-view]").PrevAll() + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#cf4", "#cf3") +} + +func TestPrevAllRollback(t *testing.T) { + sel := Doc().Find("[ng-view]") + sel2 := sel.PrevAll().End() + AssertEqual(t, sel, sel2) +} + +func TestPrevAll2(t *testing.T) { + sel := Doc().Find(".pvk-gutter").PrevAll() + AssertLength(t, sel.Nodes, 6) +} + +func TestPrevAllFiltered(t *testing.T) { + sel := Doc().Find(".pvk-gutter").PrevAllFiltered(".pvk-content") + AssertLength(t, sel.Nodes, 3) +} + +func TestPrevAllFilteredRollback(t *testing.T) { + sel := Doc().Find(".pvk-gutter") + sel2 := sel.PrevAllFiltered(".pvk-content").End() + AssertEqual(t, sel, sel2) +} + +func TestNextUntil(t *testing.T) { + sel := Doc().Find(".alert a").NextUntil("p") + AssertLength(t, sel.Nodes, 1) + AssertSelectionIs(t, sel, "h4") +} + +func TestNextUntil2(t *testing.T) { + sel := Doc().Find("#cf2-1").NextUntil("[ng-cloak]") + AssertLength(t, sel.Nodes, 1) + AssertSelectionIs(t, sel, "#cf2-2") +} + +func TestNextUntilOrder(t *testing.T) { + sel := Doc().Find("#cf2-1").NextUntil("#cf2-4") + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#cf2-2", "#cf2-3") +} + +func TestNextUntilRollback(t *testing.T) { + sel := Doc().Find("#cf2-1") + sel2 := sel.PrevUntil("#cf2-4").End() + AssertEqual(t, sel, sel2) +} + +func TestNextUntilSelection(t *testing.T) { + sel := Doc2().Find("#n2") + sel2 := Doc2().Find("#n4") + sel2 = sel.NextUntilSelection(sel2) + AssertLength(t, sel2.Nodes, 1) + AssertSelectionIs(t, sel2, "#n3") +} + +func TestNextUntilSelectionRollback(t *testing.T) { + sel := Doc2().Find("#n2") + sel2 := Doc2().Find("#n4") + sel2 = sel.NextUntilSelection(sel2).End() + AssertEqual(t, sel, sel2) +} + +func TestNextUntilNodes(t *testing.T) { + sel := Doc2().Find("#n2") + sel2 := Doc2().Find("#n5") + sel2 = sel.NextUntilNodes(sel2.Nodes...) + AssertLength(t, sel2.Nodes, 2) + AssertSelectionIs(t, sel2, "#n3", "#n4") +} + +func TestNextUntilNodesRollback(t *testing.T) { + sel := Doc2().Find("#n2") + sel2 := Doc2().Find("#n5") + sel2 = sel.NextUntilNodes(sel2.Nodes...).End() + AssertEqual(t, sel, sel2) +} + +func TestPrevUntil(t *testing.T) { + sel := Doc().Find(".alert p").PrevUntil("a") + AssertLength(t, sel.Nodes, 1) + AssertSelectionIs(t, sel, "h4") +} + +func TestPrevUntil2(t *testing.T) { + sel := Doc().Find("[ng-cloak]").PrevUntil(":not([ng-cloak])") + AssertLength(t, sel.Nodes, 1) + AssertSelectionIs(t, sel, "[ng-cloak]") +} + +func TestPrevUntilOrder(t *testing.T) { + sel := Doc().Find("#cf2-4").PrevUntil("#cf2-1") + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#cf2-3", "#cf2-2") +} + +func TestPrevUntilRollback(t *testing.T) { + sel := Doc().Find("#cf2-4") + sel2 := sel.PrevUntil("#cf2-1").End() + AssertEqual(t, sel, sel2) +} + +func TestPrevUntilSelection(t *testing.T) { + sel := Doc2().Find("#n4") + sel2 := Doc2().Find("#n2") + sel2 = sel.PrevUntilSelection(sel2) + AssertLength(t, sel2.Nodes, 1) + AssertSelectionIs(t, sel2, "#n3") +} + +func TestPrevUntilSelectionRollback(t *testing.T) { + sel := Doc2().Find("#n4") + sel2 := Doc2().Find("#n2") + sel2 = sel.PrevUntilSelection(sel2).End() + AssertEqual(t, sel, sel2) +} + +func TestPrevUntilNodes(t *testing.T) { + sel := Doc2().Find("#n5") + sel2 := Doc2().Find("#n2") + sel2 = sel.PrevUntilNodes(sel2.Nodes...) + AssertLength(t, sel2.Nodes, 2) + AssertSelectionIs(t, sel2, "#n4", "#n3") +} + +func TestPrevUntilNodesRollback(t *testing.T) { + sel := Doc2().Find("#n5") + sel2 := Doc2().Find("#n2") + sel2 = sel.PrevUntilNodes(sel2.Nodes...).End() + AssertEqual(t, sel, sel2) +} + +func TestNextFilteredUntil(t *testing.T) { + sel := Doc2().Find(".two").NextFilteredUntil(".even", ".six") + AssertLength(t, sel.Nodes, 4) + AssertSelectionIs(t, sel, "#n3", "#n5", "#nf3", "#nf5") +} + +func TestNextFilteredUntilRollback(t *testing.T) { + sel := Doc2().Find(".two") + sel2 := sel.NextFilteredUntil(".even", ".six").End() + AssertEqual(t, sel, sel2) +} + +func TestNextFilteredUntilSelection(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".five") + sel = sel.NextFilteredUntilSelection(".even", sel2) + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#n3", "#nf3") +} + +func TestNextFilteredUntilSelectionRollback(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".five") + sel3 := sel.NextFilteredUntilSelection(".even", sel2).End() + AssertEqual(t, sel, sel3) +} + +func TestNextFilteredUntilNodes(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".four") + sel = sel.NextFilteredUntilNodes(".odd", sel2.Nodes...) + AssertLength(t, sel.Nodes, 4) + AssertSelectionIs(t, sel, "#n2", "#n6", "#nf2", "#nf6") +} + +func TestNextFilteredUntilNodesRollback(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".four") + sel3 := sel.NextFilteredUntilNodes(".odd", sel2.Nodes...).End() + AssertEqual(t, sel, sel3) +} + +func TestPrevFilteredUntil(t *testing.T) { + sel := Doc2().Find(".five").PrevFilteredUntil(".odd", ".one") + AssertLength(t, sel.Nodes, 4) + AssertSelectionIs(t, sel, "#n4", "#n2", "#nf4", "#nf2") +} + +func TestPrevFilteredUntilRollback(t *testing.T) { + sel := Doc2().Find(".four") + sel2 := sel.PrevFilteredUntil(".odd", ".one").End() + AssertEqual(t, sel, sel2) +} + +func TestPrevFilteredUntilSelection(t *testing.T) { + sel := Doc2().Find(".odd") + sel2 := Doc2().Find(".two") + sel = sel.PrevFilteredUntilSelection(".odd", sel2) + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#n4", "#nf4") +} + +func TestPrevFilteredUntilSelectionRollback(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".five") + sel3 := sel.PrevFilteredUntilSelection(".even", sel2).End() + AssertEqual(t, sel, sel3) +} + +func TestPrevFilteredUntilNodes(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".four") + sel = sel.PrevFilteredUntilNodes(".odd", sel2.Nodes...) + AssertLength(t, sel.Nodes, 2) + AssertSelectionIs(t, sel, "#n2", "#nf2") +} + +func TestPrevFilteredUntilNodesRollback(t *testing.T) { + sel := Doc2().Find(".even") + sel2 := Doc2().Find(".four") + sel3 := sel.PrevFilteredUntilNodes(".odd", sel2.Nodes...).End() + AssertEqual(t, sel, sel3) +} + +func TestClosestItself(t *testing.T) { + sel := Doc2().Find(".three") + sel2 := sel.Closest(".row") + AssertLength(t, sel2.Nodes, sel.Length()) + AssertSelectionIs(t, sel2, "#n3", "#nf3") +} + +func TestClosestNoDupes(t *testing.T) { + sel := Doc().Find(".span12") + sel2 := sel.Closest(".pvk-content") + AssertLength(t, sel2.Nodes, 1) + AssertClass(t, sel2, "pvk-content") +} + +func TestClosestNone(t *testing.T) { + sel := Doc().Find("h4") + sel2 := sel.Closest("a") + AssertLength(t, sel2.Nodes, 0) +} + +func TestClosestMany(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.Closest(".pvk-content") + AssertLength(t, sel2.Nodes, 2) + AssertSelectionIs(t, sel2, "#pc1", "#pc2") +} + +func TestClosestRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.Closest(".pvk-content").End() + AssertEqual(t, sel, sel2) +} + +func TestClosestSelectionItself(t *testing.T) { + sel := Doc2().Find(".three") + sel2 := sel.ClosestSelection(Doc2().Find(".row")) + AssertLength(t, sel2.Nodes, sel.Length()) +} + +func TestClosestSelectionNoDupes(t *testing.T) { + sel := Doc().Find(".span12") + sel2 := sel.ClosestSelection(Doc().Find(".pvk-content")) + AssertLength(t, sel2.Nodes, 1) + AssertClass(t, sel2, "pvk-content") +} + +func TestClosestSelectionNone(t *testing.T) { + sel := Doc().Find("h4") + sel2 := sel.ClosestSelection(Doc().Find("a")) + AssertLength(t, sel2.Nodes, 0) +} + +func TestClosestSelectionMany(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ClosestSelection(Doc().Find(".pvk-content")) + AssertLength(t, sel2.Nodes, 2) + AssertSelectionIs(t, sel2, "#pc1", "#pc2") +} + +func TestClosestSelectionRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ClosestSelection(Doc().Find(".pvk-content")).End() + AssertEqual(t, sel, sel2) +} + +func TestClosestNodesItself(t *testing.T) { + sel := Doc2().Find(".three") + sel2 := sel.ClosestNodes(Doc2().Find(".row").Nodes...) + AssertLength(t, sel2.Nodes, sel.Length()) +} + +func TestClosestNodesNoDupes(t *testing.T) { + sel := Doc().Find(".span12") + sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...) + AssertLength(t, sel2.Nodes, 1) + AssertClass(t, sel2, "pvk-content") +} + +func TestClosestNodesNone(t *testing.T) { + sel := Doc().Find("h4") + sel2 := sel.ClosestNodes(Doc().Find("a").Nodes...) + AssertLength(t, sel2.Nodes, 0) +} + +func TestClosestNodesMany(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...) + AssertLength(t, sel2.Nodes, 2) + AssertSelectionIs(t, sel2, "#pc1", "#pc2") +} + +func TestClosestNodesRollback(t *testing.T) { + sel := Doc().Find(".container-fluid") + sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...).End() + AssertEqual(t, sel, sel2) +} + +func TestIssue26(t *testing.T) { + img1 := `150x150` + img2 := `150x150` + cases := []struct { + s string + l int + }{ + {s: img1 + img2, l: 2}, + {s: img1, l: 1}, + {s: img2, l: 1}, + } + for _, c := range cases { + doc, err := NewDocumentFromReader(strings.NewReader(c.s)) + if err != nil { + t.Fatal(err) + } + sel := doc.Find("img[src]") + AssertLength(t, sel.Nodes, c.l) + } +} diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type.go b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type.go new file mode 100644 index 0000000..e253a75 --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type.go @@ -0,0 +1,98 @@ +package goquery + +import ( + "code.google.com/p/go.net/html" + "errors" + "io" + "net/http" + "net/url" +) + +// Document represents an HTML document to be manipulated. Unlike jQuery, which +// is loaded as part of a DOM document, and thus acts upon its containing +// document, GoQuery doesn't know which HTML document to act upon. So it needs +// to be told, and that's what the Document class is for. It holds the root +// document node to manipulate, and can make selections on this document. +type Document struct { + *Selection + Url *url.URL + rootNode *html.Node +} + +// NewDocumentFromNode is a Document constructor that takes a root html Node +// as argument. +func NewDocumentFromNode(root *html.Node) *Document { + return newDocument(root, nil) +} + +// NewDocument is a Document constructor that takes a string URL as argument. +// It loads the specified document, parses it, and stores the root Document +// node, ready to be manipulated. +func NewDocument(url string) (*Document, error) { + // Load the URL + res, e := http.Get(url) + if e != nil { + return nil, e + } + return NewDocumentFromResponse(res) +} + +// NewDocumentFromReader returns a Document from a generic reader. +// It returns an error as second value if the reader's data cannot be parsed +// as html. It does *not* check if the reader is also an io.Closer, so the +// provided reader is never closed by this call, it is the responsibility +// of the caller to close it if required. +func NewDocumentFromReader(r io.Reader) (*Document, error) { + root, e := html.Parse(r) + if e != nil { + return nil, e + } + return newDocument(root, nil), nil +} + +// NewDocumentFromResponse is another Document constructor that takes an http resonse as argument. +// It loads the specified response's document, parses it, and stores the root Document +// node, ready to be manipulated. The response's body is closed on return. +func NewDocumentFromResponse(res *http.Response) (*Document, error) { + if res == nil { + return nil, errors.New("Response is nil pointer") + } + + defer res.Body.Close() + + // Parse the HTML into nodes + root, e := html.Parse(res.Body) + if e != nil { + return nil, e + } + + // Create and fill the document + return newDocument(root, res.Request.URL), nil +} + +// Private constructor, make sure all fields are correctly filled. +func newDocument(root *html.Node, url *url.URL) *Document { + // Create and fill the document + d := &Document{nil, url, root} + d.Selection = newSingleSelection(root, d) + return d +} + +// Selection represents a collection of nodes matching some criteria. The +// initial Selection can be created by using Document.Find, and then +// manipulated using the jQuery-like chainable syntax and methods. +type Selection struct { + Nodes []*html.Node + document *Document + prevSel *Selection +} + +// Helper constructor to create an empty selection +func newEmptySelection(doc *Document) *Selection { + return &Selection{nil, doc, nil} +} + +// Helper constructor to create a selection of only one node +func newSingleSelection(node *html.Node, doc *Document) *Selection { + return &Selection{[]*html.Node{node}, doc, nil} +} diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type_test.go b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type_test.go new file mode 100644 index 0000000..410a095 --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/type_test.go @@ -0,0 +1,160 @@ +package goquery + +import ( + "bytes" + "fmt" + "os" + "testing" + + "code.google.com/p/go.net/html" +) + +// Test helper functions and members +var doc *Document +var doc2 *Document +var docB *Document +var docW *Document + +func Doc() *Document { + if doc == nil { + doc = LoadDoc("page.html") + } + return doc +} +func Doc2() *Document { + if doc2 == nil { + doc2 = LoadDoc("page2.html") + } + return doc2 +} +func DocB() *Document { + if docB == nil { + docB = LoadDoc("gotesting.html") + } + return docB +} +func DocW() *Document { + if docW == nil { + docW = LoadDoc("gowiki.html") + } + return docW +} + +func AssertLength(t *testing.T, nodes []*html.Node, length int) { + if len(nodes) != length { + t.Errorf("Expected %d nodes, found %d.", length, len(nodes)) + for i, n := range nodes { + t.Logf("Node %d: %+v.", i, n) + } + } +} + +func AssertClass(t *testing.T, sel *Selection, class string) { + if !sel.HasClass(class) { + t.Errorf("Expected node to have class %s, found %+v.", class, sel.Get(0)) + } +} + +func AssertPanic(t *testing.T) { + if e := recover(); e == nil { + t.Error("Expected a panic.") + } +} + +func AssertEqual(t *testing.T, s1 *Selection, s2 *Selection) { + if s1 != s2 { + t.Error("Expected selection objects to be the same.") + } +} + +func AssertSelectionIs(t *testing.T, sel *Selection, is ...string) { + for i := 0; i < sel.Length(); i++ { + if !sel.Eq(i).Is(is[i]) { + t.Errorf("Expected node %d to be %s, found %+v", i, is[i], sel.Get(i)) + } + } +} + +func LoadDoc(page string) *Document { + var f *os.File + var e error + + if f, e = os.Open(fmt.Sprintf("./testdata/%s", page)); e != nil { + panic(e.Error()) + } + defer f.Close() + + var node *html.Node + if node, e = html.Parse(f); e != nil { + panic(e.Error()) + } + return NewDocumentFromNode(node) +} + +func TestNewDocument(t *testing.T) { + if f, e := os.Open("./testdata/page.html"); e != nil { + t.Error(e.Error()) + } else { + defer f.Close() + if node, e := html.Parse(f); e != nil { + t.Error(e.Error()) + } else { + doc = NewDocumentFromNode(node) + } + } +} + +func TestNewDocumentFromReader(t *testing.T) { + cases := []struct { + src string + err bool + sel string + cnt int + }{ + 0: { + src: ` + + +Test + +

    Hi

    + +`, + sel: "h1", + cnt: 1, + }, + 1: { + // Actually pretty hard to make html.Parse return an error + // based on content... + src: `>>qq>`, + }, + } + buf := bytes.NewBuffer(nil) + + for i, c := range cases { + buf.Reset() + buf.WriteString(c.src) + + d, e := NewDocumentFromReader(buf) + if (e != nil) != c.err { + if c.err { + t.Errorf("[%d] - expected error, got none", i) + } else { + t.Errorf("[%d] - expected no error, got %s", i, e) + } + } + if c.sel != "" { + s := d.Find(c.sel) + if s.Length() != c.cnt { + t.Errorf("[%d] - expected %d nodes, found %d", i, c.cnt, s.Length()) + } + } + } +} + +func TestNewDocumentFromResponseNil(t *testing.T) { + _, e := NewDocumentFromResponse(nil) + if e == nil { + t.Error("Expected error, got none") + } +} diff --git a/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/utilities.go b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/utilities.go new file mode 100644 index 0000000..c1b6f26 --- /dev/null +++ b/Godeps/_workspace/src/github.com/PuerkitoBio/goquery/utilities.go @@ -0,0 +1,84 @@ +package goquery + +import ( + "code.google.com/p/go.net/html" +) + +func getChildren(n *html.Node) (result []*html.Node) { + for c := n.FirstChild; c != nil; c = c.NextSibling { + result = append(result, c) + } + return result +} + +// Loop through all container nodes to search for the target node. +func sliceContains(container []*html.Node, contained *html.Node) bool { + for _, n := range container { + if nodeContains(n, contained) { + return true + } + } + + return false +} + +// Checks if the contained node is within the container node. +func nodeContains(container *html.Node, contained *html.Node) bool { + // Check if the parent of the contained node is the container node, traversing + // upward until the top is reached, or the container is found. + for contained = contained.Parent; contained != nil; contained = contained.Parent { + if container == contained { + return true + } + } + return false +} + +// Checks if the target node is in the slice of nodes. +func isInSlice(slice []*html.Node, node *html.Node) bool { + return indexInSlice(slice, node) > -1 +} + +// Returns the index of the target node in the slice, or -1. +func indexInSlice(slice []*html.Node, node *html.Node) int { + if node != nil { + for i, n := range slice { + if n == node { + return i + } + } + } + return -1 +} + +// Appends the new nodes to the target slice, making sure no duplicate is added. +// There is no check to the original state of the target slice, so it may still +// contain duplicates. The target slice is returned because append() may create +// a new underlying array. +func appendWithoutDuplicates(target []*html.Node, nodes []*html.Node) []*html.Node { + for _, n := range nodes { + if !isInSlice(target, n) { + target = append(target, n) + } + } + + return target +} + +// Loop through a selection, returning only those nodes that pass the predicate +// function. +func grep(sel *Selection, predicate func(i int, s *Selection) bool) (result []*html.Node) { + for i, n := range sel.Nodes { + if predicate(i, newSingleSelection(n, sel.document)) { + result = append(result, n) + } + } + return result +} + +// Creates a new Selection object based on the specified nodes, and keeps the +// source Selection object on the stack (linked list). +func pushStack(fromSel *Selection, nodes []*html.Node) *Selection { + result := &Selection{nodes, fromSel.document, fromSel} + return result +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/.travis.yml b/Godeps/_workspace/src/github.com/gorilla/feeds/.travis.yml new file mode 100644 index 0000000..8687342 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.1 + - 1.2 + - tip diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/LICENSE b/Godeps/_workspace/src/github.com/gorilla/feeds/LICENSE new file mode 100644 index 0000000..bb908df --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla Feeds Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/README.md b/Godeps/_workspace/src/github.com/gorilla/feeds/README.md new file mode 100644 index 0000000..ee9d269 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/README.md @@ -0,0 +1,130 @@ +## gorilla/feeds + +Web feed generator library. + +[![Build Status](https://travis-ci.org/gorilla/feeds.png?branch=master)](https://travis-ci.org/gorilla/feeds) + +### Goals + + * simple interface to create both Atom & RSS 2.0 feeds + * full support for Atom/RSS2.0 spec elements + * ability to modify particulars for each spec + +### Usage + +```go + +import ( + "fmt" + "time" + "github.com/gorilla/feeds" +) + +now := time.Now() +feed := &feeds.Feed{ + Title: "jmoiron.net blog", + Link: &feeds.Link{Href: "http://jmoiron.net/blog"}, + Description: "discussion about tech, footie, photos", + Author: &feeds.Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, +} + +feed.Items = []*feeds.Item{ + &feeds.Item{ + Title: "Limiting Concurrency in Go", + Link: &feeds.Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"}, + Description: "A discussion on controlled parallelism in golang", + Author: &feeds.Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, + }, + &feeds.Item{ + Title: "Logic-less Template Redux", + Link: &feeds.Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"}, + Description: "More thoughts on logicless templates", + Created: now, + }, + &feeds.Item{ + Title: "Idiomatic Code Reuse in Go", + Link: &feeds.Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"}, + Description: "How to use interfaces effectively", + Created: now, + }, +} + +atom, err := feed.ToAtom() +rss, err := feed.ToRss() + +fmt.Println(atom, "\n", rss) + +``` + +Outputs: + +```xml + + + jmoiron.net blog + + http://jmoiron.net/blog + 2013-01-16T03:26:01-05:00 + discussion about tech, footie, photos + + Limiting Concurrency in Go + + 2013-01-16T03:26:01-05:00 + tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/ + A discussion on controlled parallelism in golang + + Jason Moiron + jmoiron@jmoiron.net + + + + Logic-less Template Redux + + 2013-01-16T03:26:01-05:00 + tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/ + More thoughts on logicless templates + + + + Idiomatic Code Reuse in Go + + 2013-01-16T03:26:01-05:00 + tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/ + How to use interfaces <em>effectively</em> + + + + + + + + jmoiron.net blog + http://jmoiron.net/blog + discussion about tech, footie, photos + jmoiron@jmoiron.net (Jason Moiron) + 2013-01-16T03:22:24-05:00 + + Limiting Concurrency in Go + http://jmoiron.net/blog/limiting-concurrency-in-go/ + A discussion on controlled parallelism in golang + 2013-01-16T03:22:24-05:00 + + + Logic-less Template Redux + http://jmoiron.net/blog/logicless-template-redux/ + More thoughts on logicless templates + 2013-01-16T03:22:24-05:00 + + + Idiomatic Code Reuse in Go + http://jmoiron.net/blog/idiomatic-code-reuse-in-go/ + How to use interfaces <em>effectively</em> + 2013-01-16T03:22:24-05:00 + + + + +``` + diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/atom.go b/Godeps/_workspace/src/github.com/gorilla/feeds/atom.go new file mode 100644 index 0000000..1f2115f --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/atom.go @@ -0,0 +1,153 @@ +package feeds + +import ( + "encoding/xml" + "fmt" + "net/url" + "time" +) + +// Generates Atom feed as XML + +const ns = "http://www.w3.org/2005/Atom" + +type AtomPerson struct { + Name string `xml:"name,omitempty"` + Uri string `xml:"uri,omitempty"` + Email string `xml:"email,omitempty"` +} + +type AtomSummary struct { + XMLName xml.Name `xml:"summary"` + Content string `xml:",chardata"` + Type string `xml:"type,attr"` +} + +type AtomContent struct { + XMLName xml.Name `xml:"content"` + Content string `xml:",chardata"` + Type string `xml:"type,attr"` +} + +type AtomAuthor struct { + XMLName xml.Name `xml:"author"` + AtomPerson +} + +type AtomContributor struct { + XMLName xml.Name `xml:"contributor"` + AtomPerson +} + +type AtomEntry struct { + XMLName xml.Name `xml:"entry"` + Xmlns string `xml:"xmlns,attr,omitempty"` + Title string `xml:"title"` // required + Updated string `xml:"updated"` // required + Id string `xml:"id"` // required + Category string `xml:"category,omitempty"` + Content *AtomContent + Rights string `xml:"rights,omitempty"` + Source string `xml:"source,omitempty"` + Published string `xml:"published,omitempty"` + Contributor *AtomContributor + Link *AtomLink // required if no child 'content' elements + Summary *AtomSummary // required if content has src or content is base64 + Author *AtomAuthor // required if feed lacks an author +} + +type AtomLink struct { + XMLName xml.Name `xml:"link"` + Href string `xml:"href,attr"` + Rel string `xml:"rel,attr,omitempty"` +} + +type AtomFeed struct { + XMLName xml.Name `xml:"feed"` + Xmlns string `xml:"xmlns,attr"` + Title string `xml:"title"` // required + Id string `xml:"id"` // required + Updated string `xml:"updated"` // required + Category string `xml:"category,omitempty"` + Icon string `xml:"icon,omitempty"` + Logo string `xml:"logo,omitempty"` + Rights string `xml:"rights,omitempty"` // copyright used + Subtitle string `xml:"subtitle,omitempty"` + Link *AtomLink + Author *AtomAuthor // required + Contributor *AtomContributor + Entries []*AtomEntry +} + +type Atom struct { + *Feed +} + +func newAtomEntry(i *Item) *AtomEntry { + id := i.Id + // assume the description is html + c := &AtomContent{Content: i.Description, Type: "html"} + + if len(id) == 0 { + // if there's no id set, try to create one, either from data or just a uuid + if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { + dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created) + host, path := i.Link.Href, "/invalid.html" + if url, err := url.Parse(i.Link.Href); err == nil { + host, path = url.Host, url.Path + } + id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path) + } else { + id = "urn:uuid:" + NewUUID().String() + } + } + var name, email string + if i.Author != nil { + name, email = i.Author.Name, i.Author.Email + } + + x := &AtomEntry{ + Title: i.Title, + Link: &AtomLink{Href: i.Link.Href, Rel: i.Link.Rel}, + Content: c, + Id: id, + Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created), + } + if len(name) > 0 || len(email) > 0 { + x.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: name, Email: email}} + } + return x +} + +// create a new AtomFeed with a generic Feed struct's data +func (a *Atom) AtomFeed() *AtomFeed { + updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created) + feed := &AtomFeed{ + Xmlns: ns, + Title: a.Title, + Link: &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel}, + Subtitle: a.Description, + Id: a.Link.Href, + Updated: updated, + Rights: a.Copyright, + } + if a.Author != nil { + feed.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: a.Author.Name, Email: a.Author.Email}} + } else { + feed.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: "", Email: ""}} + } + for _, e := range a.Items { + feed.Entries = append(feed.Entries, newAtomEntry(e)) + } + return feed +} + +// return an XML-Ready object for an Atom object +func (a *Atom) FeedXml() interface{} { + return a.AtomFeed() +} + +// return an XML-ready object for an AtomFeed object +func (a *AtomFeed) FeedXml() interface{} { + return a +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/doc.go b/Godeps/_workspace/src/github.com/gorilla/feeds/doc.go new file mode 100644 index 0000000..385b45a --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/doc.go @@ -0,0 +1,70 @@ +/* +Syndication (feed) generator library for golang. + +Installing + + go get github.com/gorilla/feeds + +Syndicate provides a simple, generic Feed interface with a generic Item object as well as RSS and Atom specific RssFeed and AtomFeed objects which allow access to all of each spec's defined elements. + +Examples + +Create a Feed and some Items in that feed using the generic interfaces: + + import ( + "time" + . "github.com/gorilla/feeds + ) + + now = time.Now() + + feed := &Feed{ + Title: "jmoiron.net blog", + Link: &Link{Href: "http://jmoiron.net/blog"}, + Description: "discussion about tech, footie, photos", + Author: &Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, + Copyright: "This work is copyright © Benjamin Button", + } + + feed.Items = []*Item{ + &Item{ + Title: "Limiting Concurrency in Go", + Link: &Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"}, + Description: "A discussion on controlled parallelism in golang", + Author: &Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, + }, + &Item{ + Title: "Logic-less Template Redux", + Link: &Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"}, + Description: "More thoughts on logicless templates", + Created: now, + }, + &Item{ + Title: "Idiomatic Code Reuse in Go", + Link: &Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"}, + Description: "How to use interfaces effectively", + Created: now, + }, + } + +From here, you can output Atom or RSS versions of this feed easily + + atom, err := feed.ToAtom() + rss, err := feed.ToRss() + +You can also get access to the underlying objects that feeds uses to export its XML + + atomFeed := &Atom{feed}.AtomFeed() + rssFeed := &Rss{feed}.RssFeed() + +From here, you can modify or add each syndication's specific fields before outputting + + atomFeed.Subtitle = "plays the blues" + atom, err := ToXML(atomFeed) + rssFeed.Generator = "gorilla/feeds v1.0 (github.com/gorilla/feeds)" + rss, err := ToXML(rssFeed) + +*/ +package feeds diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/feed.go b/Godeps/_workspace/src/github.com/gorilla/feeds/feed.go new file mode 100644 index 0000000..7a6d133 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/feed.go @@ -0,0 +1,106 @@ +package feeds + +import ( + "encoding/xml" + "io" + "time" +) + +type Link struct { + Href, Rel string +} + +type Author struct { + Name, Email string +} + +type Item struct { + Title string + Link *Link + Author *Author + Description string // used as description in rss, summary in atom + Id string // used as guid in rss, id in atom + Updated time.Time + Created time.Time +} + +type Feed struct { + Title string + Link *Link + Description string + Author *Author + Updated time.Time + Created time.Time + Id string + Subtitle string + Items []*Item + Copyright string +} + +// add a new Item to a Feed +func (f *Feed) Add(item *Item) { + f.Items = append(f.Items, item) +} + +// returns the first non-zero time formatted as a string or "" +func anyTimeFormat(format string, times ...time.Time) string { + for _, t := range times { + if !t.IsZero() { + return t.Format(format) + } + } + return "" +} + +// interface used by ToXML to get a object suitable for exporting XML. +type XmlFeed interface { + FeedXml() interface{} +} + +// turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml +// returns an error if xml marshaling fails +func ToXML(feed XmlFeed) (string, error) { + x := feed.FeedXml() + data, err := xml.MarshalIndent(x, "", " ") + if err != nil { + return "", err + } + // strip empty line from default xml header + s := xml.Header[:len(xml.Header)-1] + string(data) + return s, nil +} + +// Write a feed object (either a Feed, AtomFeed, or RssFeed) as XML into +// the writer. Returns an error if XML marshaling fails. +func WriteXML(feed XmlFeed, w io.Writer) error { + x := feed.FeedXml() + // write default xml header, without the newline + if _, err := w.Write([]byte(xml.Header[:len(xml.Header)-1])); err != nil { + return err + } + e := xml.NewEncoder(w) + e.Indent("", " ") + return e.Encode(x) +} + +// creates an Atom representation of this feed +func (f *Feed) ToAtom() (string, error) { + a := &Atom{f} + return ToXML(a) +} + +// Writes an Atom representation of this feed to the writer. +func (f *Feed) WriteAtom(w io.Writer) error { + return WriteXML(&Atom{f}, w) +} + +// creates an Rss representation of this feed +func (f *Feed) ToRss() (string, error) { + r := &Rss{f} + return ToXML(r) +} + +// Writes an RSS representation of this feed to the writer. +func (f *Feed) WriteRss(w io.Writer) error { + return WriteXML(&Rss{f}, w) +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/feed_test.go b/Godeps/_workspace/src/github.com/gorilla/feeds/feed_test.go new file mode 100644 index 0000000..33b2752 --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/feed_test.go @@ -0,0 +1,145 @@ +package feeds + +import ( + "bytes" + "testing" + "time" +) + +var atomOutput = ` + jmoiron.net blog + http://jmoiron.net/blog + 2013-01-16T21:52:35-05:00 + This work is copyright © Benjamin Button + discussion about tech, footie, photos + + + Jason Moiron + jmoiron@jmoiron.net + + + Limiting Concurrency in Go + 2013-01-16T21:52:35-05:00 + tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/ + A discussion on controlled parallelism in golang + + + Jason Moiron + jmoiron@jmoiron.net + + + + Logic-less Template Redux + 2013-01-16T21:52:35-05:00 + tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/ + More thoughts on logicless templates + + + + Idiomatic Code Reuse in Go + 2013-01-16T21:52:35-05:00 + tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/ + How to use interfaces <em>effectively</em> + + +` + +var rssOutput = ` + + jmoiron.net blog + http://jmoiron.net/blog + discussion about tech, footie, photos + This work is copyright © Benjamin Button + jmoiron@jmoiron.net (Jason Moiron) + 16 Jan 13 21:52 EST + + Limiting Concurrency in Go + http://jmoiron.net/blog/limiting-concurrency-in-go/ + A discussion on controlled parallelism in golang + Jason Moiron + 16 Jan 13 21:52 EST + + + Logic-less Template Redux + http://jmoiron.net/blog/logicless-template-redux/ + More thoughts on logicless templates + 16 Jan 13 21:52 EST + + + Idiomatic Code Reuse in Go + http://jmoiron.net/blog/idiomatic-code-reuse-in-go/ + How to use interfaces <em>effectively</em> + 16 Jan 13 21:52 EST + + +` + +func TestFeed(t *testing.T) { + now, err := time.Parse(time.RFC3339, "2013-01-16T21:52:35-05:00") + if err != nil { + t.Error(err) + } + tz := time.FixedZone("EST", -5*60*60) + now = now.In(tz) + + feed := &Feed{ + Title: "jmoiron.net blog", + Link: &Link{Href: "http://jmoiron.net/blog"}, + Description: "discussion about tech, footie, photos", + Author: &Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, + Copyright: "This work is copyright © Benjamin Button", + } + + feed.Items = []*Item{ + &Item{ + Title: "Limiting Concurrency in Go", + Link: &Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"}, + Description: "A discussion on controlled parallelism in golang", + Author: &Author{"Jason Moiron", "jmoiron@jmoiron.net"}, + Created: now, + }, + &Item{ + Title: "Logic-less Template Redux", + Link: &Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"}, + Description: "More thoughts on logicless templates", + Created: now, + }, + &Item{ + Title: "Idiomatic Code Reuse in Go", + Link: &Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"}, + Description: "How to use interfaces effectively", + Created: now, + }, + } + + atom, err := feed.ToAtom() + if err != nil { + t.Error("unexpected error encoding Atom: %v", err) + } + if atom != atomOutput { + t.Errorf("Atom not what was expected. Got:\n%s\n\nExpected:\n%s\n", atom, atomOutput) + } + var buf bytes.Buffer + if err := feed.WriteAtom(&buf); err != nil { + t.Errorf("unexpected error writing Atom: %v", err) + } + if got := buf.String(); got != atomOutput { + t.Errorf("Atom not what was expected. Got:\n%s\n\nExpected:\n%s\n", got, rssOutput) + } + + rss, err := feed.ToRss() + if err != nil { + t.Errorf("unexpected error encoding RSS: %v", err) + } + if rss != rssOutput { + t.Errorf("Rss not what was expected. Got:\n%s\n\nExpected:\n%s\n", rss, rssOutput) + } + buf.Reset() + if err := feed.WriteRss(&buf); err != nil { + t.Errorf("unexpected error writing RSS: %v", err) + } + if got := buf.String(); got != rssOutput { + t.Errorf("Rss not what was expected. Got:\n%s\n\nExpected:\n%s\n", got, rssOutput) + } +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/rss.go b/Godeps/_workspace/src/github.com/gorilla/feeds/rss.go new file mode 100644 index 0000000..b1afcff --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/rss.go @@ -0,0 +1,138 @@ +package feeds + +// rss support +// validation done according to spec here: +// http://cyber.law.harvard.edu/rss/rss.html + +import ( + "encoding/xml" + "fmt" + "time" +) + +// private wrapper around the RssFeed which gives us the .. xml +type rssFeedXml struct { + XMLName xml.Name `xml:"rss"` + Version string `xml:"version,attr"` + Channel *RssFeed +} + +type RssImage struct { + XMLName xml.Name `xml:"image"` + Url string `xml:"url"` + Title string `xml:"title"` + Link string `xml:"link"` + Width int `xml:"width,omitempty"` + Height int `xml:"height,omitempty"` +} + +type RssTextInput struct { + XMLName xml.Name `xml:"textInput"` + Title string `xml:"title"` + Description string `xml:"description"` + Name string `xml:"name"` + Link string `xml:"link"` +} + +type RssFeed struct { + XMLName xml.Name `xml:"channel"` + Title string `xml:"title"` // required + Link string `xml:"link"` // required + Description string `xml:"description"` // required + Language string `xml:"language,omitempty"` + Copyright string `xml:"copyright,omitempty"` + ManagingEditor string `xml:"managingEditor,omitempty"` // Author used + WebMaster string `xml:"webMaster,omitempty"` + PubDate string `xml:"pubDate,omitempty"` // created or updated + LastBuildDate string `xml:"lastBuildDate,omitempty"` // updated used + Category string `xml:"category,omitempty"` + Generator string `xml:"generator,omitempty"` + Docs string `xml:"docs,omitempty"` + Cloud string `xml:"cloud,omitempty"` + Ttl int `xml:"ttl,omitempty"` + Rating string `xml:"rating,omitempty"` + SkipHours string `xml:"skipHours,omitempty"` + SkipDays string `xml:"skipDays,omitempty"` + Image *RssImage + TextInput *RssTextInput + Items []*RssItem +} + +type RssItem struct { + XMLName xml.Name `xml:"item"` + Title string `xml:"title"` // required + Link string `xml:"link"` // required + Description string `xml:"description"` // required + Author string `xml:"author,omitempty"` + Category string `xml:"category,omitempty"` + Comments string `xml:"comments,omitempty"` + Enclosure *RssEnclosure + Guid string `xml:"guid,omitempty"` // Id used + PubDate string `xml:"pubDate,omitempty"` // created or updated + Source string `xml:"source,omitempty"` +} + +type RssEnclosure struct { + XMLName xml.Name `xml:"enclosure"` + Url string `xml:"url,attr"` + Length string `xml:"length,attr"` + Type string `xml:"type,attr"` +} + +type Rss struct { + *Feed +} + +// create a new RssItem with a generic Item struct's data +func newRssItem(i *Item) *RssItem { + item := &RssItem{ + Title: i.Title, + Link: i.Link.Href, + Description: i.Description, + Guid: i.Id, + PubDate: anyTimeFormat(time.RFC822, i.Created, i.Updated), + } + if i.Author != nil { + item.Author = i.Author.Name + } + return item +} + +// create a new RssFeed with a generic Feed struct's data +func (r *Rss) RssFeed() *RssFeed { + pub := anyTimeFormat(time.RFC822, r.Created, r.Updated) + build := anyTimeFormat(time.RFC822, r.Updated) + author := "" + if r.Author != nil { + author = r.Author.Email + if len(r.Author.Name) > 0 { + author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name) + } + } + + channel := &RssFeed{ + Title: r.Title, + Link: r.Link.Href, + Description: r.Description, + ManagingEditor: author, + PubDate: pub, + LastBuildDate: build, + Copyright: r.Copyright, + } + for _, i := range r.Items { + channel.Items = append(channel.Items, newRssItem(i)) + } + return channel +} + +// return an XML-Ready object for an Rss object +func (r *Rss) FeedXml() interface{} { + // only generate version 2.0 feeds for now + return r.RssFeed().FeedXml() + +} + +// return an XML-ready object for an RssFeed object +func (r *RssFeed) FeedXml() interface{} { + return &rssFeedXml{Version: "2.0", Channel: r} +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/uuid.go b/Godeps/_workspace/src/github.com/gorilla/feeds/uuid.go new file mode 100644 index 0000000..51bbafe --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/uuid.go @@ -0,0 +1,27 @@ +package feeds + +// relevant bits from https://github.com/abneptis/GoUUID/blob/master/uuid.go + +import ( + "crypto/rand" + "fmt" +) + +type UUID [16]byte + +// create a new uuid v4 +func NewUUID() *UUID { + u := &UUID{} + _, err := rand.Read(u[:16]) + if err != nil { + panic(err) + } + + u[8] = (u[8] | 0x80) & 0xBf + u[6] = (u[6] | 0x40) & 0x4f + return u +} + +func (u *UUID) String() string { + return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/Godeps/_workspace/src/github.com/gorilla/feeds/uuid_test.go b/Godeps/_workspace/src/github.com/gorilla/feeds/uuid_test.go new file mode 100644 index 0000000..140fbfd --- /dev/null +++ b/Godeps/_workspace/src/github.com/gorilla/feeds/uuid_test.go @@ -0,0 +1,19 @@ +package feeds + +import ( + "testing" +) + +func TestUUID(t *testing.T) { + s := NewUUID() + s2 := NewUUID() + if len(s) != 16 { + t.Errorf("Expecting len of 16, got %d\n", len(s)) + } + if len(s.String()) != 36 { + t.Errorf("Expecting uuid hex string len of 36, got %d\n", len(s.String())) + } + if s == s2 { + t.Errorf("Expecting different UUIDs to be different, but they are the same.\n") + } +}