aboutsummaryrefslogblamecommitdiff
path: root/src/test/scala/scala/async/run/live/LiveVariablesSpec.scala
blob: 9b36faa7d21f05a5c52a3de5bf55ba3fcf11fdf5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
  
                                                                         










                           






                                         
                         
                     

       
                                                     












                                                   
                                                                      
                                                   
                                                     






                       
                                               












                                                   
                                                     
                                                   
                                                     






                             
                                                            

                       

                               
 
                            


                          
                                                   
               

                                                   
                                                                  
                                                   
                                                     






                             
                                                       












                                                    
                                                     
                                                    
                                                                        





                       
       
                                                     


















                                                    
                                                                          


                                                    

                                                                        


       
                            

   
       
                                                              














                                       
                                                               















                                             
                                                           

















                                            
                                                            

















                                            
                                                         















                                       
                               






















                                            


                                                         





















                                                                                      
 
/*
 * Copyright (C) 2012-2014-2013 Lightbend Inc. <http://www.lightbend.com>
 */

package scala.async
package run
package live

import org.junit.Test

import internal.AsyncTestLV
import AsyncTestLV._

case class Cell[T](v: T)

class Meter(val len: Long) extends AnyVal

case class MCell[T](var v: T)


class LiveVariablesSpec {
  AsyncTestLV.clear()

  @Test
  def `zero out fields of reference type`(): Unit = {
    val f = async { Cell(1) }

    def m1(x: Cell[Int]): Cell[Int] =
      async { Cell(x.v + 1) }

    def m2(x: Cell[Int]): String =
      async { x.v.toString }

    def m3() = async {
      val a: Cell[Int] = await(f)      // await$1$1
      // a == Cell(1)
      val b: Cell[Int] = await(m1(a))  // await$2$1
      // b == Cell(2)
      assert(AsyncTestLV.log.exists(_._2 == Cell(1)), AsyncTestLV.log)
      val res = await(m2(b))           // await$3$1
      assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
      res
    }

    assert(m3() == "2")
  }

  @Test
  def `zero out fields of type Any`(): Unit = {
    val f = async { Cell(1) }

    def m1(x: Cell[Int]): Cell[Int] =
      async { Cell(x.v + 1) }

    def m2(x: Any): String =
      async { x.toString }

    def m3() = async {
      val a: Cell[Int] = await(f)      // await$4$1
      // a == Cell(1)
      val b: Any = await(m1(a))        // await$5$1
      // b == Cell(2)
      assert(AsyncTestLV.log.exists(_._2 == Cell(1)))
      val res = await(m2(b))           // await$6$1
      assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
      res
    }

    assert(m3() == "Cell(2)")
  }

  @Test
  def `do not zero out fields of primitive type`(): Unit = {
    val f = async { 1 }

    def m1(x: Int): Cell[Int] =
      async { Cell(x + 1) }

    def m2(x: Any): String =
      async { x.toString }

    def m3() = async {
      val a: Int = await(f)            // await$7$1
      // a == 1
      val b: Any = await(m1(a))        // await$8$1
      // b == Cell(2)
      // assert(!AsyncTestLV.log.exists(p => p._1 == "await$7$1"))
      val res = await(m2(b))           // await$9$1
      assert(AsyncTestLV.log.exists(_._2 == Cell(2)))
      res
    }

    assert(m3() == "Cell(2)")
  }

  @Test
  def `zero out fields of value class type`(): Unit = {
    val f = async { Cell(1) }

    def m1(x: Cell[Int]): Meter =
      async { new Meter(x.v + 1) }

    def m2(x: Any): String =
      async { x.toString }

    def m3() = async {
      val a: Cell[Int] = await(f)      // await$10$1
      // a == Cell(1)
      val b: Meter = await(m1(a))      // await$11$1
      // b == Meter(2)
      assert(AsyncTestLV.log.exists(_._2 == Cell(1)))
      val res = await(m2(b.len))       // await$12$1
      assert(AsyncTestLV.log.exists(_._2.asInstanceOf[Meter].len == 2L))
      res
    }

    assert(m3() == "2")
  }

  @Test
  def `zero out fields after use in loop`(): Unit = {
    val f = async { MCell(1) }

    def m1(x: MCell[Int], y: Int): Int =
      async { x.v + y }

    def m3() = async {
      // state #1
      val a: MCell[Int] = await(f)     // await$13$1
      // state #2
      var y = MCell(0)

      while (a.v < 10) {
        // state #4
        a.v = a.v + 1
        y = MCell(await(a).v + 1)      // await$14$1
        // state #7
      }

      // state #3
      // assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1"))

      val b = await(m1(a, y.v))        // await$15$1
      // state #8
      assert(AsyncTestLV.log.exists(_._2 == MCell(10)), AsyncTestLV.log)
      assert(AsyncTestLV.log.exists(_._2 == MCell(11)))
      b
    }

    assert(m3() == 21, m3())
  }

  @Test
  def `don't zero captured fields captured lambda`(): Unit = {
    val f = async {
      val x = "x"
      val y = "y"
      await(0)
      y.reverse
      val f = () => assert(x != null)
      await(0)
      f
    }
    AsyncTestLV.assertNotNulledOut("x")
    AsyncTestLV.assertNulledOut("y")
    f()
  }

  @Test
  def `don't zero captured fields captured by-name`(): Unit = {
    def func0[A](a: => A): () => A =  () => a
    val f = async {
      val x = "x"
      val y = "y"
      await(0)
      y.reverse
      val f = func0(assert(x != null))
      await(0)
      f
    }
    AsyncTestLV.assertNotNulledOut("x")
    AsyncTestLV.assertNulledOut("y")
    f()
  }

  @Test
  def `don't zero captured fields nested class`(): Unit = {
    def func0[A](a: => A): () => A = () => a
    val f = async {
      val x = "x"
      val y = "y"
      await(0)
      y.reverse
      val f = new Function0[Unit] {
        def apply = assert(x != null)
      }
      await(0)
      f
    }
    AsyncTestLV.assertNotNulledOut("x")
    AsyncTestLV.assertNulledOut("y")
    f()
  }

  @Test
  def `don't zero captured fields nested object`(): Unit = {
    def func0[A](a: => A): () => A = () => a
    val f = async {
      val x = "x"
      val y = "y"
      await(0)
      y.reverse
      object f extends Function0[Unit] {
        def apply = assert(x != null)
      }
      await(0)
      f
    }
    AsyncTestLV.assertNotNulledOut("x")
    AsyncTestLV.assertNulledOut("y")
    f()
  }

  @Test
  def `don't zero captured fields nested def`(): Unit = {
    val f = async {
      val x = "x"
      val y = "y"
      await(0)
      y.reverse
      def xx = x
      val f = xx _
      await(0)
      f
    }
    AsyncTestLV.assertNotNulledOut("x")
    AsyncTestLV.assertNulledOut("y")
    f()
  }

  @Test
  def `capture bug`(): Unit = {
    sealed trait Base
    case class B1() extends Base
    case class B2() extends Base
    val outer = List[(Base, Int)]((B1(), 8))

    def getMore(b: Base) = 4

    def baz = async {
      outer.head match {
        case (a @ B1(), r) => {
          val ents = await(getMore(a))

          { () =>
            println(a)
            assert(a ne null)
          }
        }
        case (b @ B2(), x) =>
          () => ???
      }
    }
    baz()
  }

  // https://github.com/scala/async/issues/104
  @Test def dontNullOutVarsOfTypeNothing_t104(): Unit = {
    import scala.async.Async._
    import scala.concurrent.duration.Duration
    import scala.concurrent.{Await, Future}
    import scala.concurrent.ExecutionContext.Implicits.global
    def errorGenerator(randomNum: Double) = {
      Future {
        if (randomNum < 0) {
          throw new IllegalStateException("Random number was too low!")
        } else {
          throw new IllegalStateException("Random number was too high!")
        }
      }
    }
    def randomTimesTwo = async {
      val num = _root_.scala.math.random
      if (num < 0 || num > 1) {
        await(errorGenerator(num))
      }
      num * 2
    }
    Await.result(randomTimesTwo, TestLatch.DefaultTimeout) // was: NotImplementedError
  }
}