Skip to content

Commit

Permalink
test(rx): add factory connectable tests (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Apr 4, 2024
1 parent 647cd9e commit fe31256
Show file tree
Hide file tree
Showing 15 changed files with 525 additions and 82 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dupl",
"emirpasic",
"errcheck",
"errgroup",
"exportloopref",
"extendio",
"fieldalignment",
Expand All @@ -36,6 +37,7 @@
"goreleaser",
"gosec",
"gosimple",
"gotn",
"goveralls",
"govet",
"graffico",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ require (
github.com/teivah/onecontext v1.3.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
golang.org/x/net v0.20.0 // indirect
golang.org/x/sync v0.6.0
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
Expand Down
149 changes: 131 additions & 18 deletions rx/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,49 @@ type RxAssert[T any] interface { //nolint:revive // foo
itemsNoOrderedToBeChecked() (bool, []T)
noItemsToBeChecked() bool
someItemsToBeChecked() bool
numbersToBeChecked() (bool, []int)
numbersNoOrderedToBeChecked() (bool, []int)
noNumbersToBeChecked() bool
someNumbersToBeChecked() bool
raisedErrorToBeChecked() (bool, error)
raisedErrorsToBeChecked() (bool, []error)
raisedAnErrorToBeChecked() (bool, error)
notRaisedErrorToBeChecked() bool
itemToBeChecked() (bool, T)
noItemToBeChecked() (bool, T)
numberToBeChecked() (b bool, i int)
noNumberToBeChecked() (b bool, i int)
customPredicatesToBeChecked() (bool, []AssertPredicate[T])
}

type rxAssert[T any] struct {
f func(*rxAssert[T])
checkHasItems bool
checkHasNoItems bool
checkHasSomeItems bool
items []T
checkHasItemsNoOrder bool
itemsNoOrder []T
f func(*rxAssert[T])
checkHasItems bool
checkHasNoItems bool
checkHasSomeItems bool
items []T
checkHasItemsNoOrder bool
itemsNoOrder []T

checkHasNumbers bool
checkHasNoNumbers bool
checkHasSomeNumbers bool
numbers []int
checkHasNumbersNoOrder bool
numbersNoOrder []int

checkHasRaisedError bool
err error
checkHasRaisedErrors bool
errs []error
checkHasRaisedAnError bool
checkHasNotRaisedError bool
checkHasItem bool
checkHasNumber bool
item T
number int
checkHasNoItem bool
checkHasNoNumber bool
checkHasCustomPredicate bool
customPredicates []AssertPredicate[T]
}
Expand All @@ -67,6 +84,23 @@ func (ass *rxAssert[T]) noItemsToBeChecked() bool {
func (ass *rxAssert[T]) someItemsToBeChecked() bool {
return ass.checkHasSomeItems
}

func (ass *rxAssert[T]) numbersToBeChecked() (b bool, i []int) {
return ass.checkHasNumbers, ass.numbers
}

func (ass *rxAssert[T]) numbersNoOrderedToBeChecked() (b bool, i []int) {
return ass.checkHasNumbersNoOrder, ass.numbersNoOrder
}

func (ass *rxAssert[T]) noNumbersToBeChecked() bool {
return ass.checkHasNoNumbers
}

func (ass *rxAssert[T]) someNumbersToBeChecked() bool {
return ass.checkHasSomeNumbers
}

func (ass *rxAssert[T]) raisedErrorToBeChecked() (bool, error) {
return ass.checkHasRaisedError, ass.err
}
Expand All @@ -91,6 +125,14 @@ func (ass *rxAssert[T]) noItemToBeChecked() (b bool, i T) {
return ass.checkHasNoItem, ass.item
}

func (ass *rxAssert[T]) numberToBeChecked() (b bool, i int) {
return ass.checkHasNumber, ass.number
}

func (ass *rxAssert[T]) noNumberToBeChecked() (b bool, i int) {
return ass.checkHasNoNumber, ass.number
}

func (ass *rxAssert[T]) customPredicatesToBeChecked() (bool, []AssertPredicate[T]) {
return ass.checkHasCustomPredicate, ass.customPredicates
}
Expand All @@ -111,9 +153,12 @@ func parseAssertions[T any](assertions ...RxAssert[T]) RxAssert[T] {
return ass
}

func Assert[T any](ctx context.Context, iterable Iterable[T], assertions ...RxAssert[T]) {
func Assert[T any](ctx context.Context, iterable Iterable[T], assertions ...RxAssert[T]) { //nolint:gocyclo // to be fixed
// TODO(fix): cyclo complexity of this function is too high, needs a refactoring
//
ass := parseAssertions(assertions...)
got := make([]T, 0)
gotN := make([]int, 0)
errs := make([]error, 0)
observe := iterable.Observe()

Expand All @@ -127,19 +172,26 @@ loop:
break loop
}

// TODO: needs to accommodate item.N, ie the numeric aux value
// and also should be modified to support all the other
// new ways of interpreting an item (Ch, Tick, Tv), possibly
// with new assertions, ie: HasCh, HasTick, HasTv.
//
if item.IsError() {
switch {
case item.IsError():
errs = append(errs, item.E)
} else {

case item.IsNumeric():
gotN = append(gotN, item.N)

default:
got = append(got, item.V)
}
}
}

// TODO: I wonder if we can re-design this somewhat. The problem with this current
// implementation, is that it speculatively checks the conditions on the Assert
// object to determine wether or not to invoke the check. If we delegated the
// checking to the assertions and then iterate the assertions, that would
// surely be a better option. For now, there is quite a bit of cloned code
// just waiting to be cleaned up.

if checked, predicates := ass.customPredicatesToBeChecked(); checked {
for _, predicate := range predicates {
err := predicate(got)
Expand All @@ -153,6 +205,10 @@ loop:
Expect(got).To(ContainElements(expectedItems))
}

if checkHasNumbers, expectedItems := ass.numbersToBeChecked(); checkHasNumbers {
Expect(gotN).To(ContainElements(expectedItems))
}

if checkHasItemsNoOrder, itemsNoOrder := ass.itemsNoOrderedToBeChecked(); checkHasItemsNoOrder {
m := make(map[interface{}]interface{})
for _, v := range itemsNoOrder {
Expand All @@ -168,6 +224,21 @@ loop:
}
}

if checkHasNumbersNoOrder, numbersNoOrder := ass.numbersNoOrderedToBeChecked(); checkHasNumbersNoOrder {
m := make(map[int]int)
for _, v := range numbersNoOrder { // what is this loop doing?
m[v] = 0 // ?? nil
}

for _, v := range gotN {
delete(m, v)
}

if len(m) != 0 {
Fail(fmt.Sprintf("missing elements: '%v'", gotN))
}
}

if checkHasItem, value := ass.itemToBeChecked(); checkHasItem {
length := len(got)
if length != 1 {
Expand All @@ -179,14 +250,33 @@ loop:
}
}

if checkHasNumber, value := ass.numberToBeChecked(); checkHasNumber {
length := len(gotN)
if length != 1 {
Fail(fmt.Sprintf("wrong number of items, expected 1, got %d", length))
}

if length > 0 {
Expect(gotN[0]).To(Equal(value))
}
}

if ass.noItemsToBeChecked() {
Expect(got).To(BeEmpty())
}

if ass.noNumbersToBeChecked() {
Expect(gotN).To(BeEmpty())
}

if ass.someItemsToBeChecked() {
Expect(got).NotTo(BeEmpty())
}

if ass.someNumbersToBeChecked() {
Expect(gotN).NotTo(BeEmpty())
}

if checkHasRaisedError, expectedError := ass.raisedErrorToBeChecked(); checkHasRaisedError {
if expectedError == nil {
Expect(errs).To(BeEmpty())
Expand Down Expand Up @@ -231,11 +321,34 @@ func HasItem[T any](i T) RxAssert[T] {
})
}

func HasNumbers[T any](expectedNumbers []int) RxAssert[T] {
return newAssertion(func(ra *rxAssert[T]) {
ra.checkHasNumbers = true
ra.numbers = expectedNumbers
})
}

// HasItem checks if a single or optional single has a specific item.
func HasNumber[T any](i int) RxAssert[T] {
return newAssertion(func(a *rxAssert[T]) {
a.checkHasNumber = true
a.number = i
})
}

// HasItemsNoOrder checks that an observable produces the corresponding items regardless of the order.
func HasItemsNoOrder[T any](items ...T) RxAssert[T] {
func HasItemsNoOrder[T any](numbers ...T) RxAssert[T] {
return newAssertion(func(a *rxAssert[T]) {
a.checkHasItemsNoOrder = true
a.itemsNoOrder = items
a.itemsNoOrder = numbers
})
}

// HasNumbersNoOrder checks that an observable produces the corresponding items regardless of the order.
func HasNumbersNoOrder[T any](numbers ...int) RxAssert[T] {
return newAssertion(func(a *rxAssert[T]) {
a.checkHasNumbersNoOrder = true
a.numbersNoOrder = numbers
})
}

Expand All @@ -246,7 +359,7 @@ func IsNotEmpty[T any]() RxAssert[T] {
})
}

// IsEmpty checks that the observable has not produce any item.
// IsEmpty checks that the observable has not produced any items.
func IsEmpty[T any]() RxAssert[T] {
return newAssertion(func(a *rxAssert[T]) {
a.checkHasNoItems = true
Expand Down
Loading

0 comments on commit fe31256

Please sign in to comment.