Search code examples
scalaunit-testingpeano-numbers

How to test Peano numbers


I'm going through the course Functional Programming Principles in Scala on Coursera. There is an example of implementation of the Peano numbers which goes like this:

abstract class Nat {
  def isZero: Boolean
  def predecessor: Nat
  def successor: Nat = new Succ(this)
  def +(that: Nat): Nat
  def -(that: Nat): Nat
}

object Zero extends Nat {
  def isZero = true
  def predecessor: Nat = throw new Error("0.predecessor")
  def +(that: Nat): Nat = that
  def -(that: Nat): Nat = if (that.isZero) this else throw new Error("negative number")
}

class Succ(n: Nat) extends Nat {
  def isZero: Boolean = false
  def predecessor: Nat = n
  def +(that: Nat): Nat = new Succ(n + that)
  def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor
}

I wrote couple of unit tests. Most of the pass, but the following ones - written in naive way - are failing from obvious reasons (comparison of different instances):

trait Fixture {
  val one = new Succ(Zero)
  val two = new Succ(one)
}

test("successor of zero is one") {
  new Fixture {
    assert(Zero.successor == one)
  }
}

test("successor of one is two") {
  new Fixture {
    assert(one.successor == two)
  }
}

test("one plus zero is one") {
  new Fixture {
    assert((one + Zero) === one)
  }
}

test("one plus one is two") {
  new Fixture {
    assert((one + one) === two)
  }
}

My question is: how a unit test should be implemented that successfully tests + and - operations on peano numbers?

Just in case, here you can find remaining unit tests.


Solution

  • Thanks to hint from Cyrille Corpet, it looks to me that it's elegant to use case class which "compares by structure, not by reference". All unit tests are passing now without any change.

    case class Succ(n: Nat) extends Nat {
      def isZero: Boolean = false
      def predecessor: Nat = n
      def +(that: Nat): Nat = new Succ(n + that)
      def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor
    }