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 liteparse 16 17import ( 18 "bytes" 19 "context" 20 "reflect" 21 "strings" 22 "testing" 23 24 "src/tools/ak/res/res" 25 "src/tools/ak/res/respipe/respipe" 26 "src/tools/ak/res/resxml/resxml" 27) 28 29func TestResValuesParse(t *testing.T) { 30 tests := []struct { 31 doc string 32 wanted []string 33 wantedErr []string 34 }{ 35 { 36 doc: `<resources> 37 <integer name='two'>2</integer> 38 <string name='embedded_stuff'>hi <b>there</b></string> 39 </resources>`, 40 wanted: []string{ 41 "res-auto:integer/two", 42 "res-auto:string/embedded_stuff", 43 }, 44 }, 45 { 46 doc: `<resources> 47 <fraction name='frac'>12dp</fraction> 48 <item type='id' name='foo'/> 49 <id name='two'/> 50 <bool name='on'>true</bool> 51 </resources>`, 52 wanted: []string{ 53 "res-auto:fraction/frac", 54 "res-auto:id/foo", 55 "res-auto:id/two", 56 "res-auto:bool/on", 57 }, 58 }, 59 { 60 doc: `<resources> 61 <color name='red'>#fff</color> 62 <item name='hundred' type='dimen'>100%</item> 63 <attr name="custom"> 64 <enum name="cars" value="21"/> 65 <enum name="planes" value="42"/> 66 </attr> 67 <eat-comment/> 68 <!-- a comment --> 69 <attr name='textSize'/> 70 </resources>`, 71 wanted: []string{ 72 "res-auto:color/red", 73 "res-auto:dimen/hundred", 74 "res-auto:id/cars", 75 "res-auto:id/planes", 76 "res-auto:attr/custom", 77 "res-auto:attr/textSize", 78 }, 79 }, 80 { 81 doc: `<resources> 82 <attr name='touch'> 83 <flag name="tap" value="0"/> 84 <flag name="double_tap" value="2"/> 85 </attr> 86 <integer-array name='empty'> 87 </integer-array> 88 <integer-array name='five'> 89 <item>1</item> 90 <item>@integer/two</item> 91 </integer-array> 92 </resources>`, 93 94 wanted: []string{ 95 "res-auto:id/tap", 96 "res-auto:id/double_tap", 97 "res-auto:attr/touch", 98 "res-auto:array/empty", 99 "res-auto:array/five", 100 }, 101 }, 102 { 103 104 doc: `<resources> 105 <declare-styleable name='absPieChart'> 106 <attr name='android:gravity'/> 107 <attr name='local' format='string'/> 108 <attr name='overlay'> 109 <flag name="transparent" value="0"/> 110 <flag name="awesome" value="2"/> 111 </attr> 112 </declare-styleable> 113 </resources>`, 114 wanted: []string{ 115 "res-auto:attr/local", 116 "res-auto:id/transparent", 117 "res-auto:id/awesome", 118 "res-auto:attr/overlay", 119 "res-auto:styleable/absPieChart", 120 }, 121 }, 122 { 123 doc: `<resources><string>2</string></resources>`, 124 wantedErr: []string{"Expected to encounter name attribute"}, 125 }, 126 } 127 128 for _, tc := range tests { 129 ctx, cancel := context.WithCancel(context.Background()) 130 defer cancel() 131 xmlC, xmlErrC := resxml.StreamDoc(ctx, bytes.NewBufferString(tc.doc)) 132 resC, parseErrC := valuesParse(ctx, xmlC) 133 errC := respipe.MergeErrStreams(ctx, []<-chan error{xmlErrC, parseErrC}) 134 var parsedNames []string 135 var errStrs []string 136 for resC != nil || errC != nil { 137 select { 138 case r, ok := <-resC: 139 if !ok { 140 resC = nil 141 continue 142 } 143 pn, err := res.ParseName(r.GetName(), res.Type(r.ResourceType)) 144 if err != nil { 145 t.Errorf("res.ParseName(%s, %v) unexpected err: %v", r.GetName(), r.ResourceType, err) 146 } 147 parsedNames = append(parsedNames, pn.String()) 148 case e, ok := <-errC: 149 if !ok { 150 errC = nil 151 continue 152 } 153 errStrs = append(errStrs, e.Error()) 154 } 155 156 } 157 158 if !reflect.DeepEqual(parsedNames, tc.wanted) { 159 t.Errorf("valuesParse of: %s got: %s wanted: %s", tc.doc, parsedNames, tc.wanted) 160 } 161 if len(errStrs) != len(tc.wantedErr) { 162 t.Errorf("%s: unexpected amount of errs: %v wanted: %v", tc.doc, errStrs, tc.wantedErr) 163 continue 164 } 165 for i, e := range errStrs { 166 if !strings.Contains(e, tc.wantedErr[i]) { 167 t.Errorf("doc: %q got err: %s should contain: %s", tc.doc, e, tc.wantedErr[i]) 168 } 169 } 170 } 171} 172