this repo has no description
at master 471 lines 7.1 kB view raw
1// Copyright 2019 CUE Authors 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 diff 16 17import ( 18 "bytes" 19 "testing" 20 21 "cuelang.org/go/cue" 22 "cuelang.org/go/cue/cuecontext" 23 "cuelang.org/go/internal/cuetdtest" 24) 25 26func TestDiff(t *testing.T) { 27 testCases := []struct { 28 name string 29 x, y string 30 kind Kind 31 diff string 32 profile *Profile 33 }{{ 34 name: "identity struct", 35 x: `{ 36 a: { 37 b: 1 38 c: 2 39 } 40 l: { 41 d: 1 42 } 43 }`, 44 y: `{ 45 a: { 46 c: 2 47 b: 1 48 } 49 l: { 50 d: 1 51 } 52 }`, 53 }, { 54 name: "identity list", 55 x: `[1, 2, 3]`, 56 y: `[1, 2, 3]`, 57 }, { 58 name: "identity value", 59 x: `"foo"`, 60 y: `"foo"`, 61 }, { 62 name: "modified value", 63 x: `"foo"`, 64 y: `"bar"`, 65 kind: Modified, 66 diff: `- "foo", 67+ "bar", 68`, 69 }, { 70 name: "basics", 71 x: `{ 72 a: int 73 b: 2 74 s: 4 75 d: 1 76 e: null 77 } 78 `, 79 y: ` 80 { 81 a: string 82 c: 3 83 s: 4 84 d: int 85 e: null 86 } 87 `, 88 kind: Modified, 89 diff: ` { 90- a: int 91+ a: string 92- b: 2 93+ c: 3 94 s: 4 95- d: 1 96+ d: int 97 e: null 98 } 99`, 100 }, { 101 name: "basics 2", 102 x: `{ 103 ls: [2, 3, 4] 104 "foo-bar": 2 105 s: 4 106 lm1: [2, 3, 5] 107 lm2: [6] 108 } 109 `, 110 y: ` 111 { 112 ls: [2, 3, 4] 113 "foo-bar": 3 114 s: 4 115 lm1: [2, 3, 4, 6] 116 lm2: [] 117 la: [2, 3, 4] 118 } 119 `, 120 kind: Modified, 121 diff: ` { 122 ls: [2, 3, 4] 123- "foo-bar": 2 124+ "foo-bar": 3 125 s: 4 126 lm1: [ 127 2, 128 3, 129- 5, 130+ 4, 131+ 6, 132 ] 133 lm2: [ 134- 6, 135 ] 136+ la: [2, 3, 4] 137 } 138`, 139 }, { 140 name: "interupted run 1", 141 x: `{ 142 a: 1 143 b: 2 144 c: 3 145 d: 4 146 e: 10 147 f: 6 148 g: 7 149 h: 8 150 i: 9 151 j: 10 152} 153`, 154 y: ` 155{ 156 a: 1 157 b: 2 158 c: 3 159 d: 4 160 e: 5 161 f: 6 162 g: 7 163 h: 8 164 i: 9 165 j: 10 166} 167`, 168 kind: Modified, 169 diff: ` { 170 ... // 2 identical elements 171 c: 3 172 d: 4 173- e: 10 174+ e: 5 175 f: 6 176 g: 7 177 ... // 3 identical elements 178 } 179`, 180 }, { 181 name: "interupted run 2", 182 x: `{ 183 a: -1 184 b: 2 185 c: 3 186 d: 4 187 e: 5 188 f: 6 189 g: 7 190 h: 8 191 i: 9 192 j: -10 193 }`, 194 y: `{ 195 a: 1 196 b: 2 197 c: 3 198 d: 4 199 e: 5 200 f: 6 201 g: 7 202 h: 8 203 i: 9 204 j: 10 205 } 206 `, 207 kind: Modified, 208 diff: ` { 209- a: -1 210+ a: 1 211 b: 2 212 c: 3 213 ... // 4 identical elements 214 h: 8 215 i: 9 216- j: -10 217+ j: 10 218 } 219`, 220 }, { 221 name: "recursion", 222 x: `{ 223 s: { 224 a: 1 225 b: 3 226 d: 4 227 } 228 l: [ 229 [3, 4] 230 ] 231 }`, 232 y: `{ 233 s: { 234 a: 2 235 b: 3 236 c: 4 237 } 238 l: [ 239 [3, 5, 6] 240 ] 241 } 242 `, 243 kind: Modified, 244 diff: ` { 245 s: { 246- a: 1 247+ a: 2 248 b: 3 249- d: 4 250+ c: 4 251 } 252 l: [ 253 [ 254 3, 255- 4, 256+ 5, 257+ 6, 258 ] 259 ] 260 } 261`, 262 }, { 263 name: "optional and definitions", 264 x: `{ 265 #s: { 266 #a: 1 267 b: 2 268 } 269 o?: 3 270 #od?: 1 271 oc?: 5 272}`, 273 y: `{ 274 #s: { 275 a: 2 276 #b: 2 277 } 278 o?: 4 279 #od: 1 280 #oc?: 5 281} 282`, 283 kind: Modified, 284 diff: ` { 285 #s: { 286- #a: 1 287- b: 2 288+ a: 2 289+ #b: 2 290 } 291- o?: 3 292+ o?: 4 293- #od?: 1 294- oc?: 5 295+ #od: 1 296+ #oc?: 5 297 } 298`, 299 }, { 300 name: "bulk optional", 301 x: `{[_]: x: "hello"} 302 303a: x: "hello" 304 `, 305 y: `[_]: x: "hello" 306 307 `, 308 kind: Modified, 309 diff: ` { 310- a: { 311- x: "hello" 312- } 313 } 314`, 315 }, { 316 x: ` 317 #Directory: { 318 { 319 // Directory from another directory (e.g. subdirectory) 320 from: #Directory 321 } | { 322 // Reference to remote directory 323 ref: string 324 } | { 325 // Use a local directory 326 local: string 327 } 328 path: string | *"/" 329 } 330 `, 331 y: ` 332 #Directory: { 333 { 334 // Directory from another directory (e.g. subdirectory) 335 from: #Directory 336 } | { 337 // Reference to remote directory 338 ref: string 339 } | { 340 // Use a local directory 341 local: string 342 } 343 path: string | *"/" 344 } 345 `, 346 profile: Final, 347 }, { 348 x: ` 349 #Directory: { 350 { 351 // Directory from another directory (e.g. subdirectory) 352 from: #Directory 353 } | { 354 // Reference to remote directory 355 ref: string 356 } | { 357 // Use a local directory 358 local: string 359 } 360 path: string | *"/" 361 } 362 `, 363 y: ` 364 #Directory: { 365 { 366 // Directory from another directory (e.g. subdirectory) 367 from: #Directory 368 } | { 369 // Reference to remote directory 370 ref: string 371 } | { 372 // Use a local directory 373 local: string 374 } 375 path: string | *"/" 376 } 377`, 378 }, { 379 name: "hidden fields", 380 x: `{a: 1, _hidden1: 1, _hidden: 1}`, 381 y: `{a: 1, _hidden2: 1, _hidden: 2}`, 382 diff: ` { 383 a: 1 384- _hidden1: 1 385+ _hidden2: 1 386- _hidden: 1 387+ _hidden: 2 388 } 389`, 390 kind: Modified, 391 }, { 392 name: "ignore hidden fields in schema", 393 x: `{a: 1, _hidden1: 1, _hidden: 1}`, 394 y: `{a: 1, _hidden2: 1, _hidden: 2}`, 395 profile: &Profile{SkipHidden: true}, 396 }, { 397 name: "ignore hidden fields in data", 398 x: `{a: 1, _hidden1: 1, _hidden: 1}`, 399 y: `{a: 1, _hidden2: 1, _hidden: 2}`, 400 profile: &Profile{SkipHidden: true, Concrete: true}, 401 }, { 402 name: "all errors are equal", 403 x: `1 & 3`, 404 y: `1 & 4`, 405 }} 406 for _, tc := range testCases { 407 cuetdtest.FullMatrix.Run(t, tc.name, func(t *testing.T, m *cuetdtest.M) { 408 ctx := m.CueContext() 409 // it is not fatal if x or y contain errors: some test cases 410 // rely on interacting with such errors. 411 x := ctx.CompileString(tc.x, cue.Filename("x")) 412 y := ctx.CompileString(tc.y, cue.Filename("y")) 413 p := tc.profile 414 if p == nil { 415 p = Schema 416 } 417 kind, script := p.Diff(x, y) 418 if kind != tc.kind { 419 t.Fatalf("got %d; want %d", kind, tc.kind) 420 } 421 if script != nil { 422 w := &bytes.Buffer{} 423 err := Print(w, script) 424 if err != nil { 425 t.Fatal(err) 426 } 427 if got := w.String(); got != tc.diff { 428 t.Errorf("\ngot\n%s;\nwant\n%s", got, tc.diff) 429 } 430 } 431 }) 432 } 433} 434 435func TestX(t *testing.T) { 436 t.Skip() 437 438 tc := struct { 439 x, y string 440 kind Kind 441 diff string 442 }{ 443 x: `{ 444 } 445 `, 446 y: ` 447 { 448 } 449 `, 450 kind: Modified, 451 diff: ``, 452 } 453 ctx := cuecontext.New() 454 // it is not fatal if x or y contain errors: some test cases 455 // rely on interacting with such errors. 456 x := ctx.CompileString(tc.x, cue.Filename("x")) 457 y := ctx.CompileString(tc.y, cue.Filename("y")) 458 459 kind, script := Diff(x, y) 460 if kind != tc.kind { 461 t.Fatalf("got %d; want %d", kind, tc.kind) 462 } 463 w := &bytes.Buffer{} 464 err := Print(w, script) 465 if err != nil { 466 t.Fatal(err) 467 } 468 if got := w.String(); got != tc.diff { 469 t.Errorf("got\n%s;\nwant\n%s", got, tc.diff) 470 } 471}