Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ subprojects {
}
}

configure(subprojects.findAll {it.name != 'tests'}) {
configure(subprojects) {

apply plugin: "maven"
apply plugin: "signing"
Expand Down Expand Up @@ -146,4 +146,4 @@ task wrapper(type: Wrapper) {

task env << {
println System.getenv()
}
}
12 changes: 10 additions & 2 deletions tests/build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@

archivesBaseName = "${project.projectName}-${project.name}"

apply plugin: 'scala'

ext {
scalaVersion = "2.11.6"
scalacheckScalaVersion = "2.11"
scalacheckVersion = "1.12.2"
signModule = true
}

tasks.withType(ScalaCompile) {
Expand All @@ -14,11 +17,16 @@ tasks.withType(ScalaCompile) {
dependencies {
compile project(":core")
compile "org.scala-lang:scala-library:$scalaVersion"
compile "org.scalacheck:scalacheck_$scalacheckScalaVersion:$scalacheckVersion"

testCompile "org.scala-lang:scala-library:$scalaVersion"
testCompile "org.scalacheck:scalacheck_$scalacheckScalaVersion:$scalacheckVersion"
testCompile dependencyJunit
}

sourceCompatibility = "1.7"

performSigning(signingEnabled, signModule)
configureUpload(signingEnabled, signModule)

uploadArchives.enabled = true


32 changes: 32 additions & 0 deletions tests/src/main/scala/fj/data/optic/IsoLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fj
package data.optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import P.p1
import Function.identity

object IsoLaws {

def apply[S: Arbitrary, A: Arbitrary](iso: PIso[S, S, A, A])(implicit sEqual: Equal[S], aEqual: Equal[A]) = new Properties("Iso") {

property("get and reverseGet forms an Isomorphism") = forAll { (s: S, a: A) =>
sEqual.eq(iso.reverseGet(iso.get(s)), s)
aEqual.eq(iso.get(iso.reverseGet(a)), a)
}

property("set is a weaker version of reverseGet") = forAll { (s: S, a: A) =>
sEqual.eq(iso.set(a).f(s), iso.reverseGet(a))
}

property("modifyF with Id does not do anything") = forAll { s: S =>
sEqual.eq(iso.modifyP1F(p1()).f(s)._1(), s)
}

property("modify with id does not do anything") = forAll { s: S =>
sEqual.eq(iso.modify(identity()).f(s), s)
}

}

}
36 changes: 36 additions & 0 deletions tests/src/main/scala/fj/data/optic/LensLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package fj
package data.optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import P.p1
import Function.identity

object LensLaws {

def apply[S: Arbitrary, A: Arbitrary](lens: PLens[S, S, A, A])(implicit sEqual: Equal[S], aEqual: Equal[A]) = new Properties("Lens") {

property("setting what you get does not do anything") = forAll { s: S =>
sEqual.eq(lens.set(lens.get(s)).f(s), s)
}

property("you get what you set") = forAll { (s: S, a: A) =>
aEqual.eq(lens.get(lens.set(a).f(s)), a)
}

/** calling set twice is the same as calling set once */
property("set is idempotent") = forAll { (s: S, a: A) =>
sEqual.eq(lens.set(a).f(lens.set(a).f(s)), lens.set(a).f(s))
}

property("modifyF with Id does not do anything") = forAll { s: S =>
sEqual.eq(lens.modifyP1F(p1()).f(s)._1(), s)
}

property("modify with id does not do anything") = forAll { s: S =>
sEqual.eq(lens.modify(identity()).f(s), s)
}

}

}
47 changes: 47 additions & 0 deletions tests/src/main/scala/fj/data/optic/OptionalLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package fj
package data.optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import P.p1
import Function.{identity, constant}
import Equal.optionEqual

object OptionalLaws {

def apply[S: Arbitrary, A: Arbitrary](optional: POptional[S, S, A, A])(implicit sEqual: Equal[S], aEqual: Equal[A]) = new Properties("Optional") {

property("setting what you get does not do anything") = forAll { s: S =>
sEqual.eq(optional.getOrModify(s).either(identity(), {a:A => optional.set(a).f(s)}), s)
}

property("you get what you set") = forAll { (s: S, a: A) =>
optionEqual(aEqual).eq(optional.getOption(optional.set(a).f(s)), optional.getOption(s).map(constant(a)))
}

/** calling set twice is the same as calling set once */
property("set is idempotent") = forAll { (s: S, a: A) =>
sEqual.eq(optional.set(a).f(optional.set(a).f(s)), optional.set(a).f(s))
}

/** modifyF does not change the number of targets */
property("modifyF with Id does not do anything") = forAll { s: S =>
sEqual.eq(optional.modifyP1F(p1()).f(s)._1(), s)
}

/** modify does not change the number of targets */
property("modify with id does not do anything") = forAll { s: S =>
sEqual.eq(optional.modify(identity()).f(s), s)
}

property("setOption only succeeds when the Optional is matching") = forAll { (s: S, a: A) =>
optionEqual(sEqual).eq(optional.setOption(a).f(s), optional.getOption(s).map(Function.constant(optional.set(a).f(s))))
}

property("modifyOption with id is isomorphomic to isMatching") = forAll { s: S =>
optionEqual(sEqual).eq(optional.modifyOption(identity()).f(s), optional.getOption(s).map(constant(s)))
}

}

}
44 changes: 44 additions & 0 deletions tests/src/main/scala/fj/data/optic/PrismLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fj
package data
package optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import P.p1
import Function.{identity, constant}
import Equal.optionEqual
import Option.some

object PrismLaws {

def apply[S: Arbitrary, A: Arbitrary](prism: PPrism[S, S, A, A])(implicit sEqual: Equal[S], aEqual: Equal[A]) = new Properties("Prism") {

property("reverseGet produces a value") = forAll { a: A =>
optionEqual(aEqual).eq(prism.getOption(prism.reverseGet(a)), some(a))
}

property("if a Prism match you can always go back to the source") = forAll { s: S =>
sEqual.eq(prism.getOrModify(s).either(identity(), {a:A => prism.reverseGet(a)}), s)
}

/** modifyF does not change the number of targets */
property("modifyF with Id does not do anything") = forAll { s: S =>
sEqual.eq(prism.modifyP1F(p1()).f(s)._1(), s)
}

/** modify does not change the number of targets */
property("modify with id does not do anything") = forAll { s: S =>
sEqual.eq(prism.modify(identity()).f(s), s)
}

property("setOption only succeeds when the prism is matching") = forAll { (s: S, a: A) =>
optionEqual(sEqual).eq(prism.setOption(a).f(s), prism.getOption(s).map(constant(prism.set(a).f(s))))
}

property("modifyOption with id is isomorphomic to isMatching") = forAll { s: S =>
optionEqual(sEqual).eq(prism.modifyOption(identity()).f(s), prism.getOption(s).map(constant(s)))
}

}

}
25 changes: 25 additions & 0 deletions tests/src/main/scala/fj/data/optic/SetterLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fj
package data
package optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import Function.identity

object SetterLaws {

def apply[S: Arbitrary, A: Arbitrary](setter: PSetter[S, S, A, A])(implicit sEqual: Equal[S]) = new Properties("Setter") {

/** calling set twice is the same as calling set once */
property("set is idempotent") = forAll { (s: S, a: A) =>
sEqual.eq(setter.set(a).f(setter.set(a).f(s)), setter.set(a).f(s))
}

/** modify does not change the number of targets */
property("modify preserves the structure") = forAll { s: S =>
sEqual.eq(setter.modify(identity()).f(s), s)
}

}

}
42 changes: 42 additions & 0 deletions tests/src/main/scala/fj/data/optic/TraversalLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package fj
package data
package optic

import org.scalacheck.Prop._
import org.scalacheck.{ Arbitrary, Properties }
import P.p1
import Function.{identity, constant}
import Equal.{optionEqual, listEqual}
import Option.some

object TraversalLaws {

def apply[S: Arbitrary, A: Arbitrary](traversal: PTraversal[S, S, A, A])(implicit sEqual: Equal[S], aEqual: Equal[A]) = new Properties("Traversal") {

/** set does not change the number of targets */
property("you get what you set") = forAll { (s: S, a: A) =>
listEqual(aEqual).eq(traversal.getAll(traversal.set(a).f(s)), traversal.getAll(s).map(constant(a)))
}

/** calling set twice is the same as calling set once */
property("set is idempotent") = forAll { (s: S, a: A) =>
sEqual.eq(traversal.set(a).f(traversal.set(a).f(s)), traversal.set(a).f(s))
}

/** modifyF does not change the number of targets */
property("modifyF preserves the structure") = forAll { s: S =>
sEqual.eq(traversal.modifyP1F(p1()).f(s)._1(), s)
}

/** modify does not change the number of targets */
property("modify preserves the structure") = forAll { s: S =>
sEqual.eq(traversal.modify(identity()).f(s), s)
}

property("headMaybe returns the first element of getAll (if getAll is finite)") = forAll { s: S =>
optionEqual(aEqual).eq(traversal.headOption(s), traversal.getAll(s).toOption())
}

}

}