alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (range.scala)

This example Scala source code file (range.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

counter, counter, inclusiverangetest, int, int, option, properties, range, range, rangetest, rangetest, test, too, toolargerange

The Scala range.scala source code

import org.scalacheck._
import Prop._
import Gen._
import Arbitrary._

class Counter(r: Range) {
  var cnt = 0L
  var last: Option[Int] = None
  val str = "Range["+r.start+", "+r.end+", "+r.step+(if (r.isInclusive) "]" else ")")
  def apply(x: Int) = {
    cnt += 1L
    if (cnt % 500000000L == 0L) {
      println("Working: %s %d %d" format (str, cnt, x))
    }
    if (cnt > (Int.MaxValue.toLong + 1) * 2)
      error("Count exceeds maximum possible for an Int Range")
    if ((r.step > 0 && last.exists(_ > x)) || (r.step < 0 && last.exists(_ < x)))
      error("Range wrapped: %d %s" format (x, last.toString))
    last = Some(x)
  }
}
  
abstract class RangeTest(kind: String) extends Properties("Range "+kind) {
  def myGen: Gen[Range]

  val genRange = for {
    start <- arbitrary[Int]
    end <- arbitrary[Int]
    step <- Gen.choose(1, (start - end).abs + 1)
  } yield if (start < end) Range(start, end, step) else Range(start, end, -step)
  
  val genReasonableSizeRange = for {
    start <- choose(-Int.MinValue, Int.MaxValue)
    end <- choose(-Int.MinValue, Int.MaxValue)
    step <- choose(-Int.MaxValue, Int.MaxValue)
  } yield Range(start, end, if (step == 0) 100 else step)
  
  val genSmallRange = for {
    start <- choose(-100, 100)
    end <- choose(-100, 100)
    step <- choose(1, 1)
  } yield if (start < end) Range(start, end, step) else Range(start, end, -step)
  
  val genRangeByOne = for {
    start <- arbitrary[Int]
    end <- arbitrary[Int]
    if (end.toLong - start.toLong).abs <= 10000000L 
  } yield if (start < end) Range(start, end) else Range(end, start)
  
  def str(r: Range) = "Range["+r.start+", "+r.end+", "+r.step+(if (r.isInclusive) "]" else ")")
  
  def expectedSize(r: Range): Long = if (r.isInclusive) {
    (r.end.toLong - r.start.toLong < 0, r.step < 0) match {
      case (true, true) | (false, false) => (r.end.toLong - r.start.toLong).abs / r.step.abs.toLong + 1L
      case _ => if (r.start == r.end) 1L else 0L
    }
  } else {
    (r.end.toLong - r.start.toLong < 0, r.step < 0) match {
      case (true, true) | (false, false) => (
        (r.end.toLong - r.start.toLong).abs / r.step.abs.toLong 
        + (if ((r.end.toLong - r.start.toLong).abs % r.step.abs.toLong > 0L) 1L else 0L)
      )
      case _ => 0L
    }
  }
  
  def within(r: Range, x: Int) = if (r.step > 0)
    r.start <= x && (if (r.isInclusive) x <= r.end else x < r.end)
  else
    r.start >= x && (if (r.isInclusive) x >= r.end else x > r.end)
    
  def multiple(r: Range, x: Int) = (x.toLong - r.start) % r.step == 0 
  
  property("foreach.step") = forAll(myGen) { r => 
    var allValid = true
    val cnt = new Counter(r)
//    println("--------------------")
//    println(r)
    r foreach { x => cnt(x)
//      println(x + ", " + (x - r.start) + ", " + (x.toLong - r.start) + ", " + ((x.toLong - r.start) % r.step))
      allValid &&= multiple(r, x)
    }
    allValid :| str(r)
  }

  property("foreach.inside.range") = forAll(myGen) { r => 
    var allValid = true
    var last: Option[Int] = None
    val cnt = new Counter(r)
    r foreach { x => cnt(x)
      allValid &&= within(r, x)
    }
    allValid :| str(r)
  }

  property("foreach.visited.size") = forAll(myGen) { r => 
    var visited = 0L
    val cnt = new Counter(r)
    r foreach { x => cnt(x)
      visited += 1L
    }
//    println("----------")
//    println(str(r))
//    println("size: " + r.size)
//    println("expected: " + expectedSize(r))
//    println("visited: " + visited)
    (visited == expectedSize(r)) :| str(r)
  }
  
  property("length") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r =>
    (r.length == expectedSize(r)) :| str(r)
  }

  property("isEmpty") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r =>
    (r.isEmpty == (expectedSize(r) == 0L)) :| str(r)
  }
  
  property("contains") = forAll(myGen, arbInt.arbitrary) { (r, x) =>
//    println("----------------")
//    println(str(r))
//    println(x)
//    println("within: " + within(r, x))
//    println("multiple: " + multiple(r, x))
//    println("contains: " + r.contains(x))
    ((within(r, x) && multiple(r, x)) == r.contains(x)) :| str(r)+": "+x
  }
  
  property("take") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r)), arbInt.arbitrary) { (r, x) =>
    val t = r take x
    (t.size == (0 max x min r.size) && t.start == r.start && t.step == r.step) :| str(r)+" / "+str(t)+": "+x
  }
  
  property("init") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r =>
    (r.size == 0) || {
      val t = r.init
      (t.size + 1 == r.size) && (t.isEmpty || t.head == r.head)
    }
  }
  
  property("takeWhile") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r)), arbInt.arbitrary) { (r, x) =>
    val t = (if (r.step > 0) r takeWhile (_ <= x) else r takeWhile(_ >= x))
    if (r.size == 0) {
      (t.size == 0) :| str(r)+" / "+str(t)+": "+x
    } else {
      val t2 = (if (r.step > 0) Range(r.start, x min r.last, r.step).inclusive else Range(r.start, x max r.last, r.step).inclusive)
      (t.start == r.start && t.size == t2.size && t.step == r.step) :| str(r)+" / "+str(t)+" / "+str(t2)+": "+x
    }
  }
  
  property("reverse.toSet.equal") = forAll(myGen) { r =>
    val reversed = r.reverse
    val aresame = r.toSet == reversed.toSet
    if (!aresame) {
      println(str(r))
      println(r)
      println(reversed)
      println(r.toSet)
      println(reversed.toSet)
    }
    aresame
  }
}

object NormalRangeTest extends RangeTest("normal") {
  override def myGen = genReasonableSizeRange
  def genOne = for {
    start <- arbitrary[Int]
    end <- arbitrary[Int]
    if (start.toLong - end.toLong).abs < Int.MaxValue.toLong
  } yield Range(start, end, if (start < end) 1 else - 1)
  property("by 1.size + 1 == inclusive.size") = forAll(genOne) { r =>
    (r.size + 1 == r.inclusive.size) :| str(r)  
  }
}

object InclusiveRangeTest extends RangeTest("inclusive") {
  override def myGen = for (r <- genReasonableSizeRange) yield r.inclusive
}

object ByOneRangeTest extends RangeTest("byOne") {
  override def myGen = genSmallRange
}

object InclusiveByOneRangeTest extends RangeTest("inclusiveByOne") {
  override def myGen = for (r <- genSmallRange) yield r.inclusive
}

object SmallValuesRange extends RangeTest("smallValues") {
  override def myGen = genSmallRange
}

object TooLargeRange extends Properties("Too Large Range") {
  val genTooLargeStart = for {
    start <- choose(-Int.MinValue, 0)
  } yield start
  
  property("Too large range throws exception") = forAll(genTooLargeStart) { start =>
    try   { 
      val r = Range.inclusive(start, Int.MaxValue, 1)
      println("how here? r = " + r.toString)
      false
    }
    catch { case _: IllegalArgumentException => true }
  }
}

object Test extends Properties("Range") {
  import org.scalacheck.{ Test => STest }
  
  List(NormalRangeTest, InclusiveRangeTest, ByOneRangeTest, InclusiveByOneRangeTest, TooLargeRange) foreach { ps =>
    STest.checkProperties(STest.Params(testCallback = ConsoleReporter(0)), ps)
  }
}

/* Mini-benchmark
def testRange(i: Int, j: Int, k: Int) = {
  var count = 0
  for {
    vi <- 0 to i
    vj <- 0 to j
    vk <- 0 to k
  } { count += 1 }
}

testRange(10, 1000, 10000)
testRange(10000, 1000, 10)
*/

Other Scala examples (source code examples)

Here is a short list of links related to this Scala range.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.