package pl.edu.pw.mini.jk.sg.uct.utils

import org.scalamock.scalatest.MockFactory
import org.scalatest._

class StepLimitQueueSpec extends WordSpec with Matchers with MockFactory {
  "StepLimitQueue" when {

    "empty queue" should {
      "two empty queues should equal" in {
        (new EmptyStepLimitQueue(2)) should equal(new EmptyStepLimitQueue(2))
      }

      "not evaluate function in foreach" in {
        val fun = mockFunction[Any, Unit]

        (new EmptyStepLimitQueue(2)).foreach(fun)
      }
    }

    "with many elements from single timestep" should {
      val queue = (new EmptyStepLimitQueue(2)).append(1, 1)
        .append(1,3).append(1,2).append(1,4).append(1,8)

      "foreach visit all values" in {
        val fun = mockFunction[Int, Unit]

        fun.expects(1)
        fun.expects(3)
        fun.expects(2)
        fun.expects(4)
        fun.expects(8)

        queue.foreach(fun)
      }

      "not equal empty queue" in {
        queue should not equal(new EmptyStepLimitQueue(2))
      }

      "not equal queue with order number of elements" in {
        val queue2 = (new EmptyStepLimitQueue(2)).append(1, 3)
          .append(1,1).append(1,2).append(1,4).append(1,8)
        queue should not equal(queue2)
      }

      "equal queue with the same elements" in {
        val queue2 = (new EmptyStepLimitQueue(2)).append(1, 1)
          .append(1,3).append(1,2).append(1,4).append(1,8)
        queue should equal(queue2)
      }

      "not equal queue with different number of elements" in {
        val queue2 = (new EmptyStepLimitQueue(2)).append(1,3).append(1,2).append(1,4).append(1,8)
        queue should not equal(queue2)
      }
    }

    "queue with zero length and seq (1,3) (1,4) (2,1)" should {
      val queue = (new EmptyStepLimitQueue(0)).append(1,3).append(1,4).append(2,1)

      "equal queue with (2.1)" in {
        val q2 = (new EmptyStepLimitQueue(0)).append(2,1)
        queue should equal(q2)
      }

      "iterate only on values from secont ts" in {
        val fun = mockFunction[Int, Unit]
        fun.expects(1)
        queue.foreach(fun)
      }

      "not equal with queue with some elements of length 1"  in {
        (new EmptyStepLimitQueue(1)).append(1,3).append(1,4).append(2,1) should not equal(queue)
      }
    }

    "queue with length 2" should {
      val queue = EmptyStepLimitQueue(2).append(1, 3).append(1, 4).append(2, 3).append(2,4).append(3,1)

      "visit elements from all timesteps" in {
        val fun = mockFunction[Int, Unit];
        fun.expects(3).twice
        fun.expects(4).twice
        fun.expects(1)
        queue.foreach(fun)
      }

      "not equal queue with different first ts" in {
        EmptyStepLimitQueue(2).append(1, 5).append(1, 4).append(2, 3).append(2,4).append(3,1) should not equal(queue)
      }

      "equal queue with the same history" in {
        EmptyStepLimitQueue(2).append(1, 3).append(1, 4).append(2, 3).append(2,4).append(3,1) should equal(queue)
      }

      "equal queue with overflown queue" in {
        EmptyStepLimitQueue(2).append(0,9).append(1, 3).append(1, 4).append(2, 3).append(2,4).append(3,1) should equal(queue)
      }
    }

    "queue after overflow" should {
      val queue = EmptyStepLimitQueue(2).append(1, 3).append(1, 4).append(2, 3).append(2,4).append(3,1).append(4,1).append(5,1)

      "visit elements only from recent timesteps" in {
        val fun = mockFunction[Int, Unit];
        fun.expects(1).repeated(3)
        queue.foreach(fun)
      }
    }
  }
}
