OLD | NEW |
1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
9 "strings" | 9 "strings" |
10 "testing" | 10 "testing" |
11 "time" | 11 "time" |
12 | 12 |
13 "github.com/luci/gae/service/blobstore" | 13 "github.com/luci/gae/service/blobstore" |
14 ds "github.com/luci/gae/service/datastore" | 14 ds "github.com/luci/gae/service/datastore" |
15 "github.com/luci/gae/service/info" | 15 "github.com/luci/gae/service/info" |
16 "golang.org/x/net/context" | 16 "golang.org/x/net/context" |
17 | 17 |
18 . "github.com/luci/luci-go/common/testing/assertions" | 18 . "github.com/luci/luci-go/common/testing/assertions" |
19 . "github.com/smartystreets/goconvey/convey" | 19 . "github.com/smartystreets/goconvey/convey" |
20 ) | 20 ) |
21 | 21 |
| 22 func mkKey(appID, namespace string, elems ...interface{}) *ds.Key { |
| 23 return ds.KeyContext{appID, namespace}.MakeKey(elems...) |
| 24 } |
| 25 |
22 type qExpect struct { | 26 type qExpect struct { |
23 q *ds.Query | 27 q *ds.Query |
24 inTxn bool | 28 inTxn bool |
25 | 29 |
26 get []ds.PropertyMap | 30 get []ds.PropertyMap |
27 keys []*ds.Key | 31 keys []*ds.Key |
28 count int | 32 count int |
29 } | 33 } |
30 | 34 |
31 type qExStage struct { | 35 type qExStage struct { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 "Extra", "hello", "waffle", | 82 "Extra", "hello", "waffle", |
79 ), | 83 ), |
80 pmap("$key", key("Kind", 3, "Kind", 2), Next, | 84 pmap("$key", key("Kind", 3, "Kind", 2), Next, |
81 "Val", 3, 4, Next, | 85 "Val", 3, 4, Next, |
82 "Extra", "hello", "waffle", | 86 "Extra", "hello", "waffle", |
83 ), | 87 ), |
84 pmap("$key", key("Kind", 3, "Kind", 3), Next, | 88 pmap("$key", key("Kind", 3, "Kind", 3), Next, |
85 "Val", 3, 4, 2, 1, Next, | 89 "Val", 3, 4, 2, 1, Next, |
86 "Extra", "nuts", | 90 "Extra", "nuts", |
87 ), | 91 ), |
88 » pmap("$key", ds.MakeKey("dev~app", "", "Kind", "id")), | 92 » pmap("$key", mkKey("dev~app", "", "Kind", "id")), |
89 » pmap("$key", ds.MakeKey("dev~app", "bob", "Kind", "id")), | 93 » pmap("$key", mkKey("dev~app", "bob", "Kind", "id")), |
90 } | 94 } |
91 | 95 |
92 var collapsedData = []ds.PropertyMap{ | 96 var collapsedData = []ds.PropertyMap{ |
93 // PTTime | 97 // PTTime |
94 pmap("$key", key("Kind", 1), Next, | 98 pmap("$key", key("Kind", 1), Next, |
95 "Date", time.Date(2000, time.January, 1, 1, 1, 1, 1, time.UTC),
Next, | 99 "Date", time.Date(2000, time.January, 1, 1, 1, 1, 1, time.UTC),
Next, |
96 ), | 100 ), |
97 pmap("$key", key("Kind", 2), Next, | 101 pmap("$key", key("Kind", 2), Next, |
98 "Date", time.Date(2000, time.March, 1, 1, 1, 1, 1, time.UTC), Ne
xt, | 102 "Date", time.Date(2000, time.March, 1, 1, 1, 1, 1, time.UTC), Ne
xt, |
99 ), | 103 ), |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 key("Kind", 3, "Child", "seven"), | 146 key("Kind", 3, "Child", "seven"), |
143 }}, | 147 }}, |
144 {q: nq("Child").Ancestor(key("Kind", 3)).Eventua
lConsistency(true), keys: []*ds.Key{}}, | 148 {q: nq("Child").Ancestor(key("Kind", 3)).Eventua
lConsistency(true), keys: []*ds.Key{}}, |
145 {q: nq("Child").Ancestor(key("Kind", 3)).Eventua
lConsistency(true), keys: []*ds.Key{ | 149 {q: nq("Child").Ancestor(key("Kind", 3)).Eventua
lConsistency(true), keys: []*ds.Key{ |
146 key("Kind", 3, "Child", "seven"), | 150 key("Kind", 3, "Child", "seven"), |
147 }, inTxn: true}, | 151 }, inTxn: true}, |
148 {q: nq("Child").Ancestor(key("Kind", 3)), keys:
[]*ds.Key{ | 152 {q: nq("Child").Ancestor(key("Kind", 3)), keys:
[]*ds.Key{ |
149 key("Kind", 3, "Child", "seven"), | 153 key("Kind", 3, "Child", "seven"), |
150 }, inTxn: true}, | 154 }, inTxn: true}, |
151 {q: nq("__namespace__"), get: []ds.PropertyMap{ | 155 {q: nq("__namespace__"), get: []ds.PropertyMap{ |
152 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "ns")), | 156 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "ns")), |
153 }}, | 157 }}, |
154 {q: nq("__namespace__").Offset(1), get: []ds.Pro
pertyMap{}}, | 158 {q: nq("__namespace__").Offset(1), get: []ds.Pro
pertyMap{}}, |
155 {q: nq("__namespace__").Offset(1).Limit(1), get:
[]ds.PropertyMap{}}, | 159 {q: nq("__namespace__").Offset(1).Limit(1), get:
[]ds.PropertyMap{}}, |
156 }, | 160 }, |
157 }, | 161 }, |
158 | 162 |
159 { | 163 { |
160 putEnts: stage2Data, | 164 putEnts: stage2Data, |
161 delEnts: []*ds.Key{key("Unique", 1)}, | 165 delEnts: []*ds.Key{key("Unique", 1)}, |
162 addIdxs: []*ds.IndexDefinition{ | 166 addIdxs: []*ds.IndexDefinition{ |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 "When", 996688461000000), | 348 "When", 996688461000000), |
345 }}, | 349 }}, |
346 | 350 |
347 // Original (complex) types are retained when ge
tting the full value. | 351 // Original (complex) types are retained when ge
tting the full value. |
348 {q: nq("Kind").Order("When"), get: []ds.Property
Map{ | 352 {q: nq("Kind").Order("When"), get: []ds.Property
Map{ |
349 stage1Data[1], | 353 stage1Data[1], |
350 stage1Data[3], | 354 stage1Data[3], |
351 stage1Data[2], | 355 stage1Data[2], |
352 }}, | 356 }}, |
353 {q: nq("__namespace__"), get: []ds.PropertyMap{ | 357 {q: nq("__namespace__"), get: []ds.PropertyMap{ |
354 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", 1)), | 358 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", 1)), |
355 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "bob")), | 359 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "bob")), |
356 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "ns")), | 360 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "ns")), |
357 }}, | 361 }}, |
358 {q: nq("__namespace__").Offset(1), get: []ds.Pro
pertyMap{ | 362 {q: nq("__namespace__").Offset(1), get: []ds.Pro
pertyMap{ |
359 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "bob")), | 363 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "bob")), |
360 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "ns")), | 364 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "ns")), |
361 }}, | 365 }}, |
362 {q: nq("__namespace__").Offset(1).Limit(1), get:
[]ds.PropertyMap{ | 366 {q: nq("__namespace__").Offset(1).Limit(1), get:
[]ds.PropertyMap{ |
363 » » » » » pmap("$key", ds.MakeKey("dev~app", "", "
__namespace__", "bob")), | 367 » » » » » pmap("$key", mkKey("dev~app", "", "__nam
espace__", "bob")), |
364 }}, | 368 }}, |
365 }, | 369 }, |
366 | 370 |
367 extraFns: []func(context.Context){ | 371 extraFns: []func(context.Context){ |
368 func(c context.Context) { | 372 func(c context.Context) { |
369 data := ds.Get(c) | |
370 curs := ds.Cursor(nil) | 373 curs := ds.Cursor(nil) |
371 | 374 |
372 q := nq("").Gt("__key__", key("Kind", 2)
) | 375 q := nq("").Gt("__key__", key("Kind", 2)
) |
373 | 376 |
374 » » » » » err := data.Run(q, func(pm ds.PropertyMa
p, gc ds.CursorCB) error { | 377 » » » » » err := ds.Run(c, q, func(pm ds.PropertyM
ap, gc ds.CursorCB) error { |
375 So(pm, ShouldResemble, pmap( | 378 So(pm, ShouldResemble, pmap( |
376 "$key", key("Kind", 2, "
__entity_group__", 1), Next, | 379 "$key", key("Kind", 2, "
__entity_group__", 1), Next, |
377 "__version__", 1)) | 380 "__version__", 1)) |
378 | 381 |
379 err := error(nil) | 382 err := error(nil) |
380 curs, err = gc() | 383 curs, err = gc() |
381 So(err, ShouldBeNil) | 384 So(err, ShouldBeNil) |
382 return ds.Stop | 385 return ds.Stop |
383 }) | 386 }) |
384 So(err, shouldBeSuccessful) | 387 So(err, shouldBeSuccessful) |
385 | 388 |
386 » » » » » err = data.Run(q.Start(curs), func(pm ds
.PropertyMap) error { | 389 » » » » » err = ds.Run(c, q.Start(curs), func(pm d
s.PropertyMap) error { |
387 So(pm, ShouldResemble, stage1Dat
a[2]) | 390 So(pm, ShouldResemble, stage1Dat
a[2]) |
388 return ds.Stop | 391 return ds.Stop |
389 }) | 392 }) |
390 So(err, shouldBeSuccessful) | 393 So(err, shouldBeSuccessful) |
391 }, | 394 }, |
392 | 395 |
393 func(c context.Context) { | 396 func(c context.Context) { |
394 data := ds.Get(c) | |
395 q := nq("Something").Eq("Does", 2).Order
("Not", "-Work") | 397 q := nq("Something").Eq("Does", 2).Order
("Not", "-Work") |
396 » » » » » So(data.Run(q, func(ds.Key) {}), ShouldE
rrLike, strings.Join([]string{ | 398 » » » » » So(ds.Run(c, q, func(ds.Key) {}), Should
ErrLike, strings.Join([]string{ |
397 "Consider adding:", | 399 "Consider adding:", |
398 "- kind: Something", | 400 "- kind: Something", |
399 " properties:", | 401 " properties:", |
400 " - name: Does", | 402 " - name: Does", |
401 " - name: Not", | 403 " - name: Not", |
402 " - name: Work", | 404 " - name: Work", |
403 " direction: desc", | 405 " direction: desc", |
404 }, "\n")) | 406 }, "\n")) |
405 }, | 407 }, |
406 | 408 |
407 func(c context.Context) { | 409 func(c context.Context) { |
408 data := ds.Get(c) | |
409 q := nq("Something").Ancestor(key("Kind"
, 3)).Order("Val") | 410 q := nq("Something").Ancestor(key("Kind"
, 3)).Order("Val") |
410 » » » » » So(data.Run(q, func(ds.Key) {}), ShouldE
rrLike, strings.Join([]string{ | 411 » » » » » So(ds.Run(c, q, func(ds.Key) {}), Should
ErrLike, strings.Join([]string{ |
411 "Consider adding:", | 412 "Consider adding:", |
412 "- kind: Something", | 413 "- kind: Something", |
413 " ancestor: yes", | 414 " ancestor: yes", |
414 " properties:", | 415 " properties:", |
415 " - name: Val", | 416 " - name: Val", |
416 }, "\n")) | 417 }, "\n")) |
417 }, | 418 }, |
418 }, | 419 }, |
419 }, | 420 }, |
420 | 421 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 }, | 482 }, |
482 }, | 483 }, |
483 }, | 484 }, |
484 }}, | 485 }}, |
485 } | 486 } |
486 | 487 |
487 func TestQueryExecution(t *testing.T) { | 488 func TestQueryExecution(t *testing.T) { |
488 t.Parallel() | 489 t.Parallel() |
489 | 490 |
490 Convey("Test query execution", t, func() { | 491 Convey("Test query execution", t, func() { |
491 » » c, err := info.Get(Use(context.Background())).Namespace("ns") | 492 » » c, err := info.Namespace(Use(context.Background()), "ns") |
492 if err != nil { | 493 if err != nil { |
493 panic(err) | 494 panic(err) |
494 } | 495 } |
495 | 496 |
496 » » So(info.Get(c).FullyQualifiedAppID(), ShouldEqual, "dev~app") | 497 » » So(info.FullyQualifiedAppID(c), ShouldEqual, "dev~app") |
497 » » ns, has := info.Get(c).GetNamespace() | 498 » » So(info.GetNamespace(c), ShouldEqual, "ns") |
498 » » So(ns, ShouldEqual, "ns") | |
499 » » So(has, ShouldBeTrue) | |
500 | 499 |
501 » » data := ds.Get(c) | 500 » » testing := ds.GetTestable(c) |
502 » » testing := data.Testable() | |
503 | 501 |
504 for _, tc := range queryExecutionTests { | 502 for _, tc := range queryExecutionTests { |
505 Convey(tc.name, func() { | 503 Convey(tc.name, func() { |
506 for i, stage := range tc.test { | 504 for i, stage := range tc.test { |
507 // outside of Convey, since these must a
lways happen | 505 // outside of Convey, since these must a
lways happen |
508 testing.CatchupIndexes() | 506 testing.CatchupIndexes() |
509 | 507 |
510 testing.AddIndexes(stage.addIdxs...) | 508 testing.AddIndexes(stage.addIdxs...) |
511 byNs := map[string][]ds.PropertyMap{} | 509 byNs := map[string][]ds.PropertyMap{} |
512 for _, ent := range stage.putEnts { | 510 for _, ent := range stage.putEnts { |
513 k := ds.GetMetaDefault(ent, "key
", nil).(*ds.Key) | 511 k := ds.GetMetaDefault(ent, "key
", nil).(*ds.Key) |
514 byNs[k.Namespace()] = append(byN
s[k.Namespace()], ent) | 512 byNs[k.Namespace()] = append(byN
s[k.Namespace()], ent) |
515 } | 513 } |
516 for ns, ents := range byNs { | 514 for ns, ents := range byNs { |
517 » » » » » » c := info.Get(c).MustNamespace(n
s) | 515 » » » » » » c := info.MustNamespace(c, ns) |
518 » » » » » » data := ds.Get(c) | 516 » » » » » » if err := ds.Put(c, ents); err !
= nil { |
519 » » » » » » if err := data.PutMulti(ents); e
rr != nil { | |
520 // prevent Convey from t
hinking this assertion should show up in | 517 // prevent Convey from t
hinking this assertion should show up in |
521 // every test loop. | 518 // every test loop. |
522 panic(err) | 519 panic(err) |
523 } | 520 } |
524 } | 521 } |
525 | 522 |
526 » » » » » if err := data.DeleteMulti(stage.delEnts
); err != nil { | 523 » » » » » if err := ds.Delete(c, stage.delEnts); e
rr != nil { |
527 panic(err) | 524 panic(err) |
528 } | 525 } |
529 | 526 |
530 Convey(fmt.Sprintf("stage %d", i), func(
) { | 527 Convey(fmt.Sprintf("stage %d", i), func(
) { |
531 for j, expect := range stage.exp
ect { | 528 for j, expect := range stage.exp
ect { |
532 » » » » » » » runner := func(f func(ic
context.Context) error, _ *ds.TransactionOptions) error { | 529 » » » » » » » runner := func(c context
.Context, f func(ic context.Context) error, _ *ds.TransactionOptions) error { |
533 return f(c) | 530 return f(c) |
534 } | 531 } |
535 if expect.inTxn { | 532 if expect.inTxn { |
536 » » » » » » » » runner = data.Ru
nInTransaction | 533 » » » » » » » » runner = ds.RunI
nTransaction |
537 } | 534 } |
538 | 535 |
539 if expect.count == 0 { | 536 if expect.count == 0 { |
540 if len(expect.ke
ys) > 0 { | 537 if len(expect.ke
ys) > 0 { |
541 expect.c
ount = len(expect.keys) | 538 expect.c
ount = len(expect.keys) |
542 } else { | 539 } else { |
543 expect.c
ount = len(expect.get) | 540 expect.c
ount = len(expect.get) |
544 } | 541 } |
545 } | 542 } |
546 | 543 |
547 if expect.keys != nil { | 544 if expect.keys != nil { |
548 Convey(fmt.Sprin
tf("expect %d (keys)", j), func() { | 545 Convey(fmt.Sprin
tf("expect %d (keys)", j), func() { |
549 » » » » » » » » » err := r
unner(func(c context.Context) error { | 546 » » » » » » » » » err := r
unner(c, func(c context.Context) error { |
550 » » » » » » » » » »
data := ds.Get(c) | 547 » » » » » » » » » »
count, err := ds.Count(c, expect.q) |
551 » » » » » » » » » »
count, err := data.Count(expect.q) | |
552
So(err, shouldBeSuccessful) | 548
So(err, shouldBeSuccessful) |
553
So(count, ShouldEqual, expect.count) | 549
So(count, ShouldEqual, expect.count) |
554 | 550 |
555
rslt := []*ds.Key(nil) | 551
rslt := []*ds.Key(nil) |
556 » » » » » » » » » »
So(data.GetAll(expect.q, &rslt), shouldBeSuccessful) | 552 » » » » » » » » » »
So(ds.GetAll(c, expect.q, &rslt), shouldBeSuccessful) |
557
So(len(rslt), ShouldEqual, len(expect.keys)) | 553
So(len(rslt), ShouldEqual, len(expect.keys)) |
558
for i, r := range rslt { | 554
for i, r := range rslt { |
559
So(r, ShouldResemble, expect.keys[i]) | 555
So(r, ShouldResemble, expect.keys[i]) |
560
} | 556
} |
561
return nil | 557
return nil |
562 }, &ds.T
ransactionOptions{XG: true}) | 558 }, &ds.T
ransactionOptions{XG: true}) |
563 So(err,
shouldBeSuccessful) | 559 So(err,
shouldBeSuccessful) |
564 }) | 560 }) |
565 } | 561 } |
566 | 562 |
567 if expect.get != nil { | 563 if expect.get != nil { |
568 Convey(fmt.Sprin
tf("expect %d (data)", j), func() { | 564 Convey(fmt.Sprin
tf("expect %d (data)", j), func() { |
569 » » » » » » » » » err := r
unner(func(c context.Context) error { | 565 » » » » » » » » » err := r
unner(c, func(c context.Context) error { |
570 » » » » » » » » » »
data := ds.Get(c) | 566 » » » » » » » » » »
count, err := ds.Count(c, expect.q) |
571 » » » » » » » » » »
count, err := data.Count(expect.q) | |
572
So(err, shouldBeSuccessful) | 567
So(err, shouldBeSuccessful) |
573
So(count, ShouldEqual, expect.count) | 568
So(count, ShouldEqual, expect.count) |
574 | 569 |
575
rslt := []ds.PropertyMap(nil) | 570
rslt := []ds.PropertyMap(nil) |
576 » » » » » » » » » »
So(data.GetAll(expect.q, &rslt), shouldBeSuccessful) | 571 » » » » » » » » » »
So(ds.GetAll(c, expect.q, &rslt), shouldBeSuccessful) |
577
So(len(rslt), ShouldEqual, len(expect.get)) | 572
So(len(rslt), ShouldEqual, len(expect.get)) |
578
for i, r := range rslt { | 573
for i, r := range rslt { |
579
So(r, ShouldResemble, expect.get[i]) | 574
So(r, ShouldResemble, expect.get[i]) |
580
} | 575
} |
581
return nil | 576
return nil |
582 }, &ds.T
ransactionOptions{XG: true}) | 577 }, &ds.T
ransactionOptions{XG: true}) |
583 So(err,
shouldBeSuccessful) | 578 So(err,
shouldBeSuccessful) |
584 }) | 579 }) |
585 } | 580 } |
586 } | 581 } |
587 | 582 |
588 for j, fn := range stage.extraFn
s { | 583 for j, fn := range stage.extraFn
s { |
589 Convey(fmt.Sprintf("extr
aFn %d", j), func() { | 584 Convey(fmt.Sprintf("extr
aFn %d", j), func() { |
590 fn(c) | 585 fn(c) |
591 }) | 586 }) |
592 } | 587 } |
593 }) | 588 }) |
594 } | 589 } |
595 }) | 590 }) |
596 } | 591 } |
597 }) | 592 }) |
598 | 593 |
599 Convey("Test AutoIndex", t, func() { | 594 Convey("Test AutoIndex", t, func() { |
600 » » c, err := info.Get(Use(context.Background())).Namespace("ns") | 595 » » c, err := info.Namespace(Use(context.Background()), "ns") |
601 if err != nil { | 596 if err != nil { |
602 panic(err) | 597 panic(err) |
603 } | 598 } |
604 | 599 |
605 » » data := ds.Get(c) | 600 » » testing := ds.GetTestable(c) |
606 » » testing := data.Testable() | |
607 testing.Consistent(true) | 601 testing.Consistent(true) |
608 | 602 |
609 » » So(data.Put(pmap("$key", key("Kind", 1), Next, | 603 » » So(ds.Put(c, pmap("$key", key("Kind", 1), Next, |
610 "Val", 1, 2, 3, Next, | 604 "Val", 1, 2, 3, Next, |
611 "Extra", "hello", | 605 "Extra", "hello", |
612 )), shouldBeSuccessful) | 606 )), shouldBeSuccessful) |
613 | 607 |
614 » » So(data.Put(pmap("$key", key("Kind", 2), Next, | 608 » » So(ds.Put(c, pmap("$key", key("Kind", 2), Next, |
615 "Val", 2, 3, 9, Next, | 609 "Val", 2, 3, 9, Next, |
616 "Extra", "ace", "hello", "there", | 610 "Extra", "ace", "hello", "there", |
617 )), shouldBeSuccessful) | 611 )), shouldBeSuccessful) |
618 | 612 |
619 q := nq("Kind").Gt("Val", 2).Order("Val", "Extra") | 613 q := nq("Kind").Gt("Val", 2).Order("Val", "Extra") |
620 | 614 |
621 » » count, err := data.Count(q) | 615 » » count, err := ds.Count(c, q) |
622 So(err, ShouldErrLike, "Insufficient indexes") | 616 So(err, ShouldErrLike, "Insufficient indexes") |
623 | 617 |
624 testing.AutoIndex(true) | 618 testing.AutoIndex(true) |
625 | 619 |
626 » » count, err = data.Count(q) | 620 » » count, err = ds.Count(c, q) |
627 So(err, shouldBeSuccessful) | 621 So(err, shouldBeSuccessful) |
628 So(count, ShouldEqual, 2) | 622 So(count, ShouldEqual, 2) |
629 }) | 623 }) |
630 } | 624 } |
631 | 625 |
632 func shouldBeSuccessful(actual interface{}, expected ...interface{}) string { | 626 func shouldBeSuccessful(actual interface{}, expected ...interface{}) string { |
633 if len(expected) != 0 { | 627 if len(expected) != 0 { |
634 return "no expected values permitted" | 628 return "no expected values permitted" |
635 } | 629 } |
636 if actual == nil { | 630 if actual == nil { |
637 return "" | 631 return "" |
638 } | 632 } |
639 | 633 |
640 v, ok := actual.(error) | 634 v, ok := actual.(error) |
641 if !ok { | 635 if !ok { |
642 return fmt.Sprintf("type of 'actual' must be error, not %T", act
ual) | 636 return fmt.Sprintf("type of 'actual' must be error, not %T", act
ual) |
643 } | 637 } |
644 if v == nil || v == ds.Stop { | 638 if v == nil || v == ds.Stop { |
645 return "" | 639 return "" |
646 } | 640 } |
647 return fmt.Sprintf("expected success value, not %v", v) | 641 return fmt.Sprintf("expected success value, not %v", v) |
648 } | 642 } |
OLD | NEW |