// Copyright (c) 2023 IBM Corp. // All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testing import ( "testing" E "github.com/IBM/fp-go/eq" F "github.com/IBM/fp-go/function" "github.com/IBM/fp-go/internal/functor" "github.com/stretchr/testify/assert" ) // Functor identity law // // F.map(fa, a => a) <-> fa // // Deprecated: use [FunctorAssertIdentity] func AssertIdentity[HKTA, A any](t *testing.T, eq E.Eq[HKTA], fmap func(HKTA, func(A) A) HKTA) func(fa HKTA) bool { t.Helper() return func(fa HKTA) bool { return assert.True(t, eq.Equals(fa, fmap(fa, F.Identity[A])), "Functor identity law") } } // Functor identity law // // F.map(fa, a => a) <-> fa func FunctorAssertIdentity[HKTA, A any]( t *testing.T, eq E.Eq[HKTA], fca functor.Functor[A, A, HKTA, HKTA], ) func(fa HKTA) bool { t.Helper() return func(fa HKTA) bool { return assert.True(t, eq.Equals(fa, fca.Map(F.Identity[A])(fa)), "Functor identity law") } } // Functor composition law // // F.map(fa, a => bc(ab(a))) <-> F.map(F.map(fa, ab), bc) // // Deprecated: use [FunctorAssertComposition] instead func AssertComposition[HKTA, HKTB, HKTC, A, B, C any]( t *testing.T, eq E.Eq[HKTC], fab func(HKTA, func(A) B) HKTB, fac func(HKTA, func(A) C) HKTC, fbc func(HKTB, func(B) C) HKTC, ab func(A) B, bc func(B) C, ) func(fa HKTA) bool { t.Helper() return func(fa HKTA) bool { return assert.True(t, eq.Equals(fac(fa, F.Flow2(ab, bc)), fbc(fab(fa, ab), bc)), "Functor composition law") } } // Functor composition law // // F.map(fa, a => bc(ab(a))) <-> F.map(F.map(fa, ab), bc) func FunctorAssertComposition[HKTA, HKTB, HKTC, A, B, C any]( t *testing.T, eq E.Eq[HKTC], fab functor.Functor[A, B, HKTA, HKTB], fac functor.Functor[A, C, HKTA, HKTC], fbc functor.Functor[B, C, HKTB, HKTC], ab func(A) B, bc func(B) C, ) func(fa HKTA) bool { t.Helper() return func(fa HKTA) bool { return assert.True(t, eq.Equals(fac.Map(F.Flow2(ab, bc))(fa), fbc.Map(bc)(fab.Map(ab)(fa))), "Functor composition law") } } // AssertLaws asserts the functor laws `identity` and `composition` // // Deprecated: use [FunctorAssertLaws] instead func AssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T, eqa E.Eq[HKTA], eqc E.Eq[HKTC], faa func(HKTA, func(A) A) HKTA, fab func(HKTA, func(A) B) HKTB, fac func(HKTA, func(A) C) HKTC, fbc func(HKTB, func(B) C) HKTC, ab func(A) B, bc func(B) C, ) func(fa HKTA) bool { t.Helper() identity := AssertIdentity(t, eqa, faa) composition := AssertComposition(t, eqc, fab, fac, fbc, ab, bc) return func(fa HKTA) bool { return identity(fa) && composition(fa) } } // FunctorAssertLaws asserts the functor laws `identity` and `composition` func FunctorAssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T, eqa E.Eq[HKTA], eqc E.Eq[HKTC], faa functor.Functor[A, A, HKTA, HKTA], fab functor.Functor[A, B, HKTA, HKTB], fac functor.Functor[A, C, HKTA, HKTC], fbc functor.Functor[B, C, HKTB, HKTC], ab func(A) B, bc func(B) C, ) func(fa HKTA) bool { t.Helper() identity := FunctorAssertIdentity(t, eqa, faa) composition := FunctorAssertComposition(t, eqc, fab, fac, fbc, ab, bc) return func(fa HKTA) bool { return identity(fa) && composition(fa) } }