Skip to content

Commit

Permalink
fix: refactory tests a bit
Browse files Browse the repository at this point in the history
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
  • Loading branch information
CarstenLeue committed Feb 9, 2024
1 parent 0afedbd commit 51ed169
Show file tree
Hide file tree
Showing 20 changed files with 1,179 additions and 16 deletions.
2 changes: 1 addition & 1 deletion context/readerioeither/file/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
return func(w W) RIOE.ReaderIOEither[[]byte] {
return F.Pipe1(
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
RIOE.TryCatch(func(_ context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
_, err := w.Write(data)
return data, err
Expand Down
16 changes: 10 additions & 6 deletions context/readerioeither/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,21 @@ func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
return ReadJSON[A](client)
}

// ReadJSON sends a request, reads the response and parses the response as JSON
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
func readJSON(client Client) func(Requester) RIOE.ReaderIOEither[[]byte] {
return F.Flow3(
ReadFullResponse(client),
RIOE.ChainFirstEitherK(F.Flow2(
H.Response,
H.ValidateJSONResponse,
)),
RIOE.ChainEitherK(F.Flow2(
H.Body,
J.Unmarshal[A],
)),
RIOE.Map(H.Body),
)
}

// ReadJSON sends a request, reads the response and parses the response as JSON
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
return F.Flow2(
readJSON(client),
RIOE.ChainEitherK(J.Unmarshal[A]),
)
}
2 changes: 1 addition & 1 deletion di/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func eraseTuple[A, R any](f func(A) IOE.IOEither[error, R]) func(E.Either[error,
}

func eraseProviderFactory0[R any](f IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
return func(params ...any) IOE.IOEither[error, any] {
return func(_ ...any) IOE.IOEither[error, any] {
return F.Pipe1(
f,
IOE.Map[error](F.ToAny[R]),
Expand Down
2 changes: 1 addition & 1 deletion identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func Map[A, B any](f func(A) B) func(A) B {
return G.Map(f)
}

func MonadMapTo[A, B any](fa A, b B) B {
func MonadMapTo[A, B any](_ A, b B) B {
return b
}

Expand Down
131 changes: 131 additions & 0 deletions internal/applicative/testing/law.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ import (

E "github.com/IBM/fp-go/eq"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/applicative"
"github.com/IBM/fp-go/internal/apply"
L "github.com/IBM/fp-go/internal/apply/testing"
"github.com/IBM/fp-go/internal/functor"
"github.com/IBM/fp-go/internal/pointed"
"github.com/stretchr/testify/assert"
)

// Applicative identity law
//
// A.ap(A.of(a => a), fa) <-> fa
//
// Deprecated: use [ApplicativeAssertIdentity]
func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
eq E.Eq[HKTA],

Expand All @@ -46,9 +52,33 @@ func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
}
}

// Applicative identity law
//
// A.ap(A.of(a => a), fa) <-> fa
func ApplicativeAssertIdentity[HKTA, HKTFAA, A any](t *testing.T,
eq E.Eq[HKTA],

ap applicative.Applicative[A, A, HKTA, HKTA, HKTFAA],
paa pointed.Pointed[func(A) A, HKTFAA],

) func(fa HKTA) bool {
// mark as test helper
t.Helper()

return func(fa HKTA) bool {

left := ap.Ap(fa)(paa.Of(F.Identity[A]))
right := fa

return assert.True(t, eq.Equals(left, right), "Applicative identity")
}
}

// Applicative homomorphism law
//
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
//
// Deprecated: use [ApplicativeAssertHomomorphism]
func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
eq E.Eq[HKTB],

Expand All @@ -72,9 +102,35 @@ func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
}
}

// Applicative homomorphism law
//
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
func ApplicativeAssertHomomorphism[HKTA, HKTB, HKTFAB, A, B any](t *testing.T,
eq E.Eq[HKTB],

apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
pb pointed.Pointed[B, HKTB],
pfab pointed.Pointed[func(A) B, HKTFAB],

ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()

return func(a A) bool {

left := apab.Ap(apab.Of(a))(pfab.Of(ab))
right := pb.Of(ab(a))

return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
}
}

// Applicative interchange law
//
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
//
// Deprecated: use [ApplicativeAssertInterchange]
func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
eq E.Eq[HKTB],

Expand Down Expand Up @@ -103,7 +159,38 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
}
}

// Applicative interchange law
//
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
func ApplicativeAssertInterchange[HKTA, HKTB, HKTFAB, HKTABB, A, B any](t *testing.T,
eq E.Eq[HKTB],

apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
apabb applicative.Applicative[func(A) B, B, HKTFAB, HKTB, HKTABB],
pabb pointed.Pointed[func(func(A) B) B, HKTABB],

ab func(A) B,
) func(a A) bool {
// mark as test helper
t.Helper()

return func(a A) bool {

fab := apabb.Of(ab)

left := apab.Ap(apab.Of(a))(fab)

right := apabb.Ap(fab)(pabb.Of(func(ab func(A) B) B {
return ab(a)
}))

return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
}
}

// AssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
//
// Deprecated: use [ApplicativeAssertLaws] instead
func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqb E.Eq[HKTB],
Expand Down Expand Up @@ -150,3 +237,47 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
}
}

// ApplicativeAssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
func ApplicativeAssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqb E.Eq[HKTB],
eqc E.Eq[HKTC],

fofb pointed.Pointed[B, HKTB],

fofaa pointed.Pointed[func(A) A, HKTAA],
fofbc pointed.Pointed[func(B) C, HKTBC],

fofabb pointed.Pointed[func(func(A) B) B, HKTABB],

faa functor.Functor[A, A, HKTA, HKTA],

fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],

fapaa applicative.Applicative[A, A, HKTA, HKTA, HKTAA],
fapab applicative.Applicative[A, B, HKTA, HKTB, HKTAB],
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],

fapabb applicative.Applicative[func(A) B, B, HKTAB, HKTB, HKTABB],
fapabac applicative.Applicative[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],

ab func(A) B,
bc func(B) C,
) func(a A) bool {
// mark as test helper
t.Helper()

// apply laws
apply := L.ApplyAssertLaws(t, eqa, eqc, applicative.ToPointed(fapabac), fofbc, faa, fmap, applicative.ToApply(fapab), fapbc, fapac, applicative.ToApply(fapabac), ab, bc)
// applicative laws
identity := ApplicativeAssertIdentity(t, eqa, fapaa, fofaa)
homomorphism := ApplicativeAssertHomomorphism(t, eqb, fapab, fofb, applicative.ToPointed(fapabb), ab)
interchange := ApplicativeAssertInterchange(t, eqb, fapab, fapabb, fofabb, ab)

return func(a A) bool {
fa := fapaa.Of(a)
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
}
}
16 changes: 16 additions & 0 deletions internal/applicative/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,26 @@ package applicative

import (
"github.com/IBM/fp-go/internal/apply"
"github.com/IBM/fp-go/internal/functor"
"github.com/IBM/fp-go/internal/pointed"
)

type Applicative[A, B, HKTA, HKTB, HKTFAB any] interface {
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
pointed.Pointed[A, HKTA]
}

// ToFunctor converts from [Applicative] to [functor.Functor]
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
return ap
}

// ToApply converts from [Applicative] to [apply.Apply]
func ToApply[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) apply.Apply[A, B, HKTA, HKTB, HKTFAB] {
return ap
}

// ToPointed converts from [Applicative] to [pointed.Pointed]
func ToPointed[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) pointed.Pointed[A, HKTA] {
return ap
}
80 changes: 80 additions & 0 deletions internal/apply/testing/laws.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ import (
"testing"

E "github.com/IBM/fp-go/eq"
"github.com/IBM/fp-go/internal/apply"
"github.com/IBM/fp-go/internal/functor"
FCT "github.com/IBM/fp-go/internal/functor/testing"
"github.com/IBM/fp-go/internal/pointed"
"github.com/stretchr/testify/assert"
)

// Apply associative composition law
//
// F.ap(F.ap(F.map(fbc, bc => ab => a => bc(ab(a))), fab), fa) <-> F.ap(fbc, F.ap(fab, fa))
//
// Deprecated: use [ApplyAssertAssociativeComposition] instead
func AssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
eq E.Eq[HKTC],

Expand Down Expand Up @@ -63,7 +68,49 @@ func AssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC
}
}

// Apply associative composition law
//
// F.ap(F.ap(F.map(fbc, bc => ab => a => bc(ab(a))), fab), fa) <-> F.ap(fbc, F.ap(fab, fa))
func ApplyAssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
eq E.Eq[HKTC],

fofab pointed.Pointed[func(A) B, HKTAB],
fofbc pointed.Pointed[func(B) C, HKTBC],

fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],

fapab apply.Apply[A, B, HKTA, HKTB, HKTAB],
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],

fapabac apply.Apply[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],

ab func(A) B,
bc func(B) C,
) func(fa HKTA) bool {
t.Helper()
return func(fa HKTA) bool {

fab := fofab.Of(ab)
fbc := fofbc.Of(bc)

left := fapac.Ap(fa)(fapabac.Ap(fab)(fmap.Map(func(bc func(B) C) func(func(A) B) func(A) C {
return func(ab func(A) B) func(A) C {
return func(a A) C {
return bc(ab(a))
}
}
})(fbc)))

right := fapbc.Ap(fapab.Ap(fa)(fab))(fbc)

return assert.True(t, eq.Equals(left, right), "Apply associative composition")
}
}

// AssertLaws asserts the apply laws `identity`, `composition` and `associative composition`
//
// Deprecated: use [ApplyAssertLaws] instead
func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqc E.Eq[HKTC],
Expand Down Expand Up @@ -98,3 +145,36 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
return functor(fa) && composition(fa)
}
}

// ApplyAssertLaws asserts the apply laws `identity`, `composition` and `associative composition`
func ApplyAssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
eqa E.Eq[HKTA],
eqc E.Eq[HKTC],

fofab pointed.Pointed[func(A) B, HKTAB],
fofbc pointed.Pointed[func(B) C, HKTBC],

faa functor.Functor[A, A, HKTA, HKTA],

fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],

fapab apply.Apply[A, B, HKTA, HKTB, HKTAB],
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],

fapabac apply.Apply[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],

ab func(A) B,
bc func(B) C,
) func(fa HKTA) bool {
// mark as test helper
t.Helper()
// functor laws
functor := FCT.FunctorAssertLaws(t, eqa, eqc, faa, apply.ToFunctor(fapab), apply.ToFunctor(fapac), apply.ToFunctor(fapbc), ab, bc)
// associative composition laws
composition := ApplyAssertAssociativeComposition(t, eqc, fofab, fofbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)

return func(fa HKTA) bool {
return functor(fa) && composition(fa)
}
}
5 changes: 5 additions & 0 deletions internal/apply/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@ type Apply[A, B, HKTA, HKTB, HKTFAB any] interface {
functor.Functor[A, B, HKTA, HKTB]
Ap(HKTA) func(HKTFAB) HKTB
}

// ToFunctor converts from [Apply] to [functor.Functor]
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Apply[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
return ap
}

0 comments on commit 51ed169

Please sign in to comment.