1// Copyright 2018 The Bazel Authors. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package xml2 16 17import ( 18 "bufio" 19 "bytes" 20 "encoding/xml" 21 "io" 22 "strings" 23 "testing" 24) 25 26func TestEncoderEncodeToken(t *testing.T) { 27 tests := []struct { 28 name string 29 in string 30 want string 31 wantErr string 32 }{ 33 { 34 name: "xmlnsPrefixForElement", 35 in: "<foo:bar xmlns:foo=\"baz\"></foo:bar>", 36 want: "<foo:bar xmlns:foo=\"baz\"></foo:bar>", 37 }, 38 { 39 name: "xmlnsPrefixForAttribute", 40 in: "<foo bar:baz=\"qux\" xmlns:bar=\"quux\"></foo>", 41 want: "<foo bar:baz=\"qux\" xmlns:bar=\"quux\"></foo>", 42 }, 43 { 44 name: "defaultXmlnsAttribute", 45 in: "<foo xmlns=\"bar\"></foo>", 46 want: "<foo xmlns=\"bar\"></foo>", 47 }, 48 { 49 // The return value of Decoder.Token() makes it 50 // impossible for a decode then encode of an xml file 51 // be isomorphic. This is mainly due to the fact that 52 // xml.Name.Space contains the uri, and xml.Name does 53 // not store the prefix. Instead, make sure that the 54 // behavior remains consistent. 55 // 56 // That is, the last prefix defined for the space is the 57 // one applied when encoding the token. 58 name: "multipleDefsXmlnsPrefixesSameUri", 59 in: ` 60<foo xmlns:bar="bar"> 61 <bar:baz xmlns:qux="bar"> 62 <qux:quux></qux:quux> 63 </bar:baz> 64</foo>`, 65 want: ` 66<foo xmlns:bar="bar"> 67 <qux:baz xmlns:qux="bar"> 68 <qux:quux></qux:quux> 69 </qux:baz> 70</foo>`, 71 }, 72 { 73 name: "xmlnsPrefixUsedOnElementButNotDefined", 74 in: "<foo:bar></foo:bar>", 75 wantErr: "unknown namespace: foo", 76 }, 77 { 78 name: "xmlnsPrefixUsedOnAttrButNotDefined", 79 in: "<foo bar:baz=\"qux\"></foo>", 80 wantErr: "unknown namespace: bar", 81 }, 82 { 83 name: "xmlnsPrefixUsedOutsideOfDefiningTag", 84 in: ` 85<foo xmlns:bar="baz" bar:qux="quux">corge</foo> 86<grault bar:garply="waldo"></grault>`, 87 wantErr: "unknown namespace: bar", 88 }, 89 } 90 for _, test := range tests { 91 t.Run(test.name, func(t *testing.T) { 92 var b bytes.Buffer 93 e := NewEncoder(bufio.NewWriter(&b)) 94 d := xml.NewDecoder(strings.NewReader(test.in)) 95 for { 96 tkn, err := d.Token() 97 if err != nil { 98 if err == io.EOF { 99 break 100 } 101 t.Fatalf("Unexpected error got: %v while reading: %s", err, test.in) 102 } 103 if err := e.EncodeToken(tkn); err != nil { 104 if test.wantErr != "" && strings.Contains(err.Error(), test.wantErr) { 105 // Do nothing, error is expected. 106 } else { 107 t.Errorf("Unexpected error during encode: %v", err) 108 } 109 return 110 } 111 } 112 e.Flush() 113 if b.String() != test.want { 114 t.Errorf("got: <%s> expected: <%s>", b.String(), test.want) 115 } 116 }) 117 } 118} 119 120func TestChildEncoder(t *testing.T) { 121 // Setup the parent Encoder with the namespace "bar". 122 d := xml.NewDecoder(strings.NewReader("<foo xmlns:bar=\"bar\"><bar:baz>Hello World</bar:baz></foo>")) 123 tkn, err := d.Token() 124 if err != nil { 125 t.Fatalf("Error occurred during decoding, got: %v", err) 126 } 127 parentEnc := NewEncoder(&bytes.Buffer{}) 128 if err := parentEnc.EncodeToken(tkn); err != nil { 129 t.Fatalf("Error occurred while the parent encoder was encoding token %q got: %v", tkn, err) 130 } 131 132 // Without instantiating the Encoder as a child, the "bar" namespace will be unknown and cause an 133 // error to occur when trying to encode the "bar" namespaced element "<bar:baz>". 134 tkn, err = d.Token() 135 if err != nil { 136 t.Fatalf("Error occurred during decoding, got: %v", err) 137 } 138 b := &bytes.Buffer{} 139 childEnc := ChildEncoder(b, parentEnc) 140 if err := childEnc.EncodeToken(tkn); err != nil { 141 t.Fatalf("Error occurred while the child encoder was encoding token %q got: %v", tkn, err) 142 } 143 childEnc.Flush() 144 145 // Verify that the token is not mangled. 146 if want := "<bar:baz>"; b.String() != want { 147 t.Errorf("Error, got %q, wanted %q", b.String(), want) 148 } 149} 150