this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue: fix path representation for shared nodes

In some cases, paths referred to the shared
nodes, rather than the original. This was
caused by storing a too-early dereferenced
node in structValue. We now store the original
value, so that linkParent can correctly detect
when a node is shared.

Fixes #3922

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Iea2bde18ce6c0879fb1254a2bb03da2eedcb28a3
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1215511
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>

+140 -2
+138
cue/path_test.go
··· 16 16 17 17 import ( 18 18 "fmt" 19 + "reflect" 19 20 "testing" 20 21 21 22 "cuelang.org/go/cue" 23 + "cuelang.org/go/cue/cuecontext" 22 24 "cuelang.org/go/internal/cuetdtest" 23 25 ) 24 26 ··· 130 132 path: cue.ParsePath("pkg.y"), 131 133 out: `"hello"`, 132 134 str: "pkg.y", // show original path, not structure shared path. 135 + }, { 136 + // Issue 3922 137 + path: cue.ParsePath("out.name"), 138 + out: `"one"`, 139 + str: "out.name", 133 140 }} 134 141 135 142 cuetdtest.Run(t, testCases, func(t *cuetdtest.T, tc *testCase) { ··· 151 158 // Issue 3577 152 159 pkg: z 153 160 z: y: "hello" 161 + 162 + // Issue 3922 163 + out: #Output 164 + #Output: name: _data.name 165 + _data: name: "one" 154 166 `) 155 167 156 168 t.Equal(tc.path.Err() != nil, tc.err) ··· 165 177 166 178 t.Equal(w.Path().String(), tc.str) 167 179 }) 180 + } 181 + 182 + // TestWalkPath is a more comprehensive table-driven test. 183 + func TestWalkPath(t *testing.T) { 184 + ctx := cuecontext.New() 185 + 186 + testCases := []struct { 187 + name string 188 + cueInput string 189 + wantPaths []string 190 + }{ 191 + { 192 + name: "issue 3922", 193 + cueInput: ` 194 + out: #Output 195 + #Output: name: _data.name 196 + _data: name: "one" 197 + `, 198 + wantPaths: []string{ 199 + "", // root 200 + "out", 201 + "out.name", 202 + }, 203 + }, 204 + { 205 + name: "simple struct", 206 + cueInput: ` 207 + b: { 208 + d: 3 209 + c: 2 210 + } 211 + a: 1 212 + `, 213 + wantPaths: []string{ 214 + "", // root 215 + "b", 216 + "b.d", 217 + "b.c", 218 + "a", 219 + }, 220 + }, 221 + { 222 + name: "struct with list", 223 + cueInput: ` 224 + l: [10, {y: 30, x: 20}] 225 + `, 226 + wantPaths: []string{ 227 + "", // root 228 + "l", 229 + "l[0]", 230 + "l[1]", 231 + "l[1].y", 232 + "l[1].x", 233 + }, 234 + }, 235 + { 236 + name: "root list", 237 + cueInput: `[10, {x: 20}]`, 238 + wantPaths: []string{ 239 + "", // root 240 + "[0]", 241 + "[1]", 242 + "[1].x", 243 + }, 244 + }, 245 + { 246 + name: "root literal string", 247 + cueInput: `"hello"`, 248 + wantPaths: []string{ 249 + "", // root 250 + }, 251 + }, 252 + { 253 + name: "root literal int", 254 + cueInput: `123`, 255 + wantPaths: []string{ 256 + "", // root 257 + }, 258 + }, 259 + { 260 + name: "empty struct", 261 + cueInput: `{}`, 262 + wantPaths: []string{ 263 + "", // root 264 + }, 265 + }, 266 + { 267 + name: "struct with various field types", 268 + cueInput: ` 269 + c: _h 270 + _h: #D 271 + #D: b: c: 3 272 + a: _g 273 + _g: #B 274 + #B: x: "definition B" 275 + `, 276 + // Order: regular (a, c), definitions (#B, #D), hidden (_g, _h) 277 + wantPaths: []string{ 278 + "", // root 279 + "c", 280 + "c.b", 281 + "c.b.c", 282 + "a", 283 + "a.x", 284 + }, 285 + }, 286 + } 287 + 288 + for _, tc := range testCases { 289 + t.Run(tc.name, func(t *testing.T) { 290 + v := ctx.CompileString(tc.cueInput) 291 + if err := v.Err(); err != nil { 292 + t.Fatalf("CompileString failed for input\n%s\nError: %v", tc.cueInput, err) 293 + } 294 + 295 + var gotPaths []string 296 + v.Walk(func(val cue.Value) bool { 297 + gotPaths = append(gotPaths, val.Path().String()) 298 + return true 299 + }, nil) 300 + 301 + if !reflect.DeepEqual(gotPaths, tc.wantPaths) { 302 + t.Errorf("Walk() paths mismatch for input\n%s\ngot: %#v\nwant: %#v", tc.cueInput, gotPaths, tc.wantPaths) 303 + } 304 + }) 305 + } 168 306 } 169 307 170 308 var selectorTests = []struct {
+2 -2
cue/types.go
··· 605 605 606 606 func newChildValue(o *structValue, i int) Value { 607 607 arc := o.at(i) 608 - // TODO: fix linkage to parent. 609 608 return makeValue(o.v.idx, arc, linkParent(o.v.parent_, o.v.v, arc)) 610 609 } 611 610 ··· 1249 1248 1250 1249 // structVal returns an structVal or an error if v is not a struct. 1251 1250 func (v Value) structValOpts(ctx *adt.OpContext, o options) (s structValue, err *adt.Bottom) { 1251 + orig := v 1252 1252 v, _ = v.Default() 1253 1253 1254 1254 obj := v.v ··· 1305 1305 } 1306 1306 arcs = append(arcs, arc) 1307 1307 } 1308 - return structValue{ctx, v, obj, arcs}, nil 1308 + return structValue{ctx, orig, obj, arcs}, nil 1309 1309 } 1310 1310 1311 1311 // Struct returns the underlying struct of a value or an error if the value