Skip to content

Commit f9aee45

Browse files
authored
Merge pull request #45 from fredbi/test/refact-collection
Test/refact collection
2 parents 07e033c + 27cba1b commit f9aee45

File tree

6 files changed

+1034
-1155
lines changed

6 files changed

+1034
-1155
lines changed

internal/assertions/collection.go

Lines changed: 120 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
//
1717
// Len also fails if the object has a type that len() does not accept.
1818
//
19-
// The asserted object can be a string, a slice, a map, an array or a channel.
19+
// The asserted object can be a string, a slice, a map, an array, pointer to array or a channel.
2020
//
2121
// See also [reflect.Len].
2222
//
@@ -301,12 +301,16 @@ func MapNotContainsT[Map ~map[K]V, K comparable, V any](t T, m Map, key K, msgAn
301301
return true
302302
}
303303

304+
const unsupportedCollectionType = "%q has an unsupported type %s"
305+
304306
// Subset asserts that the list (array, slice, or map) contains all elements
305307
// given in the subset (array, slice, or map).
306308
//
307309
// Map elements are key-value pairs unless compared with an array or slice where
308310
// only the map key is evaluated.
309311
//
312+
// nil values are considered as empty sets.
313+
//
310314
// # Usage
311315
//
312316
// assertions.Subset(t, []int{1, 2, 3}, []int{1, 2})
@@ -324,37 +328,46 @@ func Subset(t T, list, subset any, msgAndArgs ...any) (ok bool) {
324328
h.Helper()
325329
}
326330

327-
if subset == nil {
328-
return true // we consider nil to be equal to the nil set
329-
}
331+
subsetType := reflect.TypeOf(subset)
332+
listType := reflect.TypeOf(list)
330333

331-
listKind := reflect.TypeOf(list).Kind()
332-
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
333-
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
334+
if subsetType == nil {
335+
if listType == nil { // ∅ ⊂ ∅
336+
return true // we consider nil to be equal to the nil set
337+
}
338+
339+
listKind := listType.Kind()
340+
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
341+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, list, listKind), msgAndArgs...)
342+
}
343+
344+
return true
334345
}
335346

336-
subsetKind := reflect.TypeOf(subset).Kind()
347+
subsetKind := subsetType.Kind()
337348
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
338-
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
349+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, subset, subsetKind), msgAndArgs...)
350+
}
351+
352+
if listType == nil {
353+
subsetList := reflect.ValueOf(subset)
354+
if subsetList.Len() == 0 {
355+
return true
356+
}
357+
358+
return Fail(t, fmt.Sprintf("%q is not a subset of the empty set", subset), msgAndArgs...)
359+
}
360+
361+
listKind := listType.Kind()
362+
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
363+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, list, listKind), msgAndArgs...)
339364
}
340365

341366
if subsetKind == reflect.Map && listKind == reflect.Map {
342367
subsetMap := reflect.ValueOf(subset)
343368
actualMap := reflect.ValueOf(list)
344369

345-
for _, k := range subsetMap.MapKeys() {
346-
ev := subsetMap.MapIndex(k)
347-
av := actualMap.MapIndex(k)
348-
349-
if !av.IsValid() {
350-
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
351-
}
352-
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
353-
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
354-
}
355-
}
356-
357-
return true
370+
return isSubsetMap(t, list, subset, subsetMap, actualMap, msgAndArgs...)
358371
}
359372

360373
subsetList := reflect.ValueOf(subset)
@@ -366,18 +379,7 @@ func Subset(t T, list, subset any, msgAndArgs ...any) (ok bool) {
366379
subsetList = reflect.ValueOf(keys)
367380
}
368381

369-
for i := range subsetList.Len() {
370-
element := subsetList.Index(i).Interface()
371-
ok, found := containsElement(list, element)
372-
if !ok {
373-
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
374-
}
375-
if !found {
376-
return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...)
377-
}
378-
}
379-
380-
return true
382+
return isSubsetList(t, list, subsetList, msgAndArgs...)
381383
}
382384

383385
// SliceSubsetT asserts that a slice of comparable elements contains all the elements given in the subset.
@@ -426,37 +428,44 @@ func NotSubset(t T, list, subset any, msgAndArgs ...any) (ok bool) {
426428
if h, ok := t.(H); ok {
427429
h.Helper()
428430
}
429-
if subset == nil {
430-
return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...)
431+
const emptySetMessage = "nil is the empty set which is a subset of every set"
432+
433+
subsetType := reflect.TypeOf(subset)
434+
listType := reflect.TypeOf(list)
435+
436+
if subsetType == nil {
437+
return Fail(t, emptySetMessage, msgAndArgs...)
431438
}
432439

433-
listKind := reflect.TypeOf(list).Kind()
440+
if listType == nil {
441+
subsetKind := subsetType.Kind()
442+
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
443+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, subset, subsetKind), msgAndArgs...)
444+
}
445+
446+
subsetList := reflect.ValueOf(subset)
447+
if subsetList.Len() != 0 {
448+
return true
449+
}
450+
451+
return Fail(t, emptySetMessage, msgAndArgs...)
452+
}
453+
454+
listKind := listType.Kind()
434455
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
435-
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
456+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, list, listKind), msgAndArgs...)
436457
}
437458

438-
subsetKind := reflect.TypeOf(subset).Kind()
459+
subsetKind := subsetType.Kind()
439460
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
440-
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
461+
return Fail(t, fmt.Sprintf(unsupportedCollectionType, subset, subsetKind), msgAndArgs...)
441462
}
442463

443464
if subsetKind == reflect.Map && listKind == reflect.Map {
444465
subsetMap := reflect.ValueOf(subset)
445466
actualMap := reflect.ValueOf(list)
446467

447-
for _, k := range subsetMap.MapKeys() {
448-
ev := subsetMap.MapIndex(k)
449-
av := actualMap.MapIndex(k)
450-
451-
if !av.IsValid() {
452-
return true
453-
}
454-
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
455-
return true
456-
}
457-
}
458-
459-
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...)
468+
return isNotSubsetMap(t, list, subset, subsetMap, actualMap, msgAndArgs...)
460469
}
461470

462471
subsetList := reflect.ValueOf(subset)
@@ -468,18 +477,7 @@ func NotSubset(t T, list, subset any, msgAndArgs ...any) (ok bool) {
468477
subsetList = reflect.ValueOf(keys)
469478
}
470479

471-
for i := range subsetList.Len() {
472-
element := subsetList.Index(i).Interface()
473-
ok, found := containsElement(list, element)
474-
if !ok {
475-
return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...)
476-
}
477-
if !found {
478-
return true
479-
}
480-
}
481-
482-
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...)
480+
return isNotSubsetList(t, list, subset, subsetList, msgAndArgs...)
483481
}
484482

485483
// SliceNotSubsetT asserts that a slice of comparable elements does not contain all the elements given in the subset.
@@ -649,6 +647,63 @@ func NotElementsMatchT[E comparable](t T, listA, listB []E, msgAndArgs ...any) (
649647
return true
650648
}
651649

650+
func isSubsetMap(t T, list, subset any, subsetMap, actualMap reflect.Value, msgAndArgs ...any) bool {
651+
for _, k := range subsetMap.MapKeys() {
652+
ev := subsetMap.MapIndex(k)
653+
av := actualMap.MapIndex(k)
654+
655+
if !av.IsValid() {
656+
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
657+
}
658+
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
659+
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
660+
}
661+
}
662+
663+
return true
664+
}
665+
666+
func isNotSubsetMap(t T, list, subset any, subsetMap, actualMap reflect.Value, msgAndArgs ...any) bool {
667+
for _, k := range subsetMap.MapKeys() {
668+
ev := subsetMap.MapIndex(k)
669+
av := actualMap.MapIndex(k)
670+
671+
if !av.IsValid() {
672+
return true
673+
}
674+
675+
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
676+
return true
677+
}
678+
}
679+
680+
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...)
681+
}
682+
683+
func isSubsetList(t T, list any, subsetList reflect.Value, msgAndArgs ...any) bool {
684+
for i := range subsetList.Len() {
685+
element := subsetList.Index(i).Interface()
686+
_, found := containsElement(list, element) // containsElement will work for this type: no need to check the ok bool
687+
if !found {
688+
return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...)
689+
}
690+
}
691+
692+
return true
693+
}
694+
695+
func isNotSubsetList(t T, list, subset any, subsetList reflect.Value, msgAndArgs ...any) bool {
696+
for i := range subsetList.Len() {
697+
element := subsetList.Index(i).Interface()
698+
_, found := containsElement(list, element)
699+
if !found {
700+
return true
701+
}
702+
}
703+
704+
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%q", subset), truncatingFormat("%q", list)), msgAndArgs...)
705+
}
706+
652707
// containsElement tries to loop over the list check if the list includes the element.
653708
//
654709
// return (false, false) if impossible.

0 commit comments

Comments
 (0)