Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScalaMock 4.3.0 regression: referring to non-existent method scala.scalajs.runtime.RuntimeString$.lines(java.lang.String)java.util.stream.Stream #268

Closed
Atry opened this issue Jun 24, 2019 · 2 comments · Fixed by #271
Projects
Milestone

Comments

@Atry
Copy link

Atry commented Jun 24, 2019

ScalaMock Version (e.g. 3.5.0)

4.3.0

Scala Version (e.g. 2.12)

2.12.8

Runtime (JVM or JS)

JS

Please describe the expected behavior of the issue

Show compile and link

Please provide a description of what actually happens

[error] Referring to non-existent method scala.scalajs.runtime.RuntimeString$.lines(java.lang.String)java.util.stream.Stream
[error]   called from org.scalamock.handlers.Handlers.$$anonfun$toString$1(org.scalamock.handlers.Handler)[java.lang.String
[error]   called from org.scalamock.handlers.Handlers.toString()java.lang.String
[error]   called from org.scalactic.Requirements$RequirementsHelper.append(java.lang.String,java.lang.Object)java.lang.String
[error]   called from org.scalactic.Requirements$RequirementsHelper.macroRequire(org.scalactic.Bool,java.lang.Object)scala.Unit
[error]   called from org.scalatest.Failed.<init>(java.lang.Throwable)
[error]   called from org.scalatest.OutcomeOf.outcomeOf(scala.Function0)org.scalatest.Outcome
[error]   called from org.scalatest.OutcomeOf$.outcomeOf(scala.Function0)org.scalatest.Outcome
[error]   called from org.scalatest.Transformer.apply()org.scalatest.Outcome
[error]   called from org.scalatest.Transformer.apply()java.lang.Object
[error]   called from org.scalatest.SuperEngine.registerNestedBranch(java.lang.String,scala.Option,scala.Function0,scala.Function0,java.lang.String,java.lang.String,scala.Int,scala.Int,scala.Option,scala.Option)scala.Unit
[error]   called from org.scalatest.FreeSpecLike$FreeSpecStringWrapper.$$minus(scala.Function0)scala.Unit
[error]   called from com.yang_bo.dsl.domains.akka.actor.typedExample.<init>()
[error]   called from com.yang_bo.dsl.domains.akka.actor.typedExample.<clinit>()
[error]   called from core module analyzer
[error] involving instantiated classes:
[error]   org.scalamock.handlers.UnorderedHandlers
[error]   org.scalactic.Requirements$RequirementsHelper
[error]   org.scalatest.OutcomeOf$
[error]   org.scalatest.Transformer
[error]   org.scalatest.Engine
[error]   org.scalatest.FreeSpecLike$FreeSpecStringWrapper

Reproducible Test Case

package com.yang_bo.dsl.domains.akka.actor
final class typedExample extends _root_.org.scalatest.FreeSpec with _root_.org.scalatest.Matchers with org.scalamock.scalatest.MockFactory {
  "com.yang_bo.dsl.domains.akka.actor" - {
    "typed" - {
      this.markup("Contains the [[com.thoughtworks.dsl.Dsl]] instances in a typed actor.")
      this.markup("<h4>Installation</h4>")
      this.markup("""This [[typed]] object supports [[keywords.akka.actor.ReceiveMessage.unary_$bang !]]-notation for [[keywords.akka.actor.ReceiveMessage]] in the typed actor domains,
which requires [[com.thoughtworks.dsl.compilerplugins.BangNotation BangNotation]] and [[com.thoughtworks.dsl.compilerplugins.ResetEverywhere ResetEverywhere]] compiler plugins along with this `typed` library.
For sbt, add the following settings to your `build.sbt`:""")
      this.markup("""<pre>
addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")
addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" % "latest.release")
libraryDependencies += "com.yang-bo.dsl.domains.akka.actor" %% "typed" % "latest.release"
</pre>""")
      this.markup("<h4>Imports</h4>")
      this.markup("Then, add the following import statement to enable `ReceiveMessage` in the [[akka.actor.typed.Behavior]] domain.")
      import com.yang_bo.dsl.domains.akka.actor.typed._
      import com.yang_bo.dsl.keywords.akka.actor.ReceiveMessage
      """@example This library can be used as an alternative to [[akka.actor.FSM]],
for creating state machines in simple Scala control flow.""".in(try {
        this.markup("The following state machine contains two states and two transitions between them.")
        this.markup("<br/><img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Finite_state_machine_example_with_comments.svg/420px-Finite_state_machine_example_with_comments.svg.png\"/><br/>")
        this.markup("It can be created as a simple `while` loop with the help of [[keywords.akka.actor.ReceiveMessage.Partial]]:")
        import akka.actor.typed._
        sealed trait State
        case object Opened extends State
        case object Closed extends State
        sealed trait Transition
        case class Open(response: ActorRef[State]) extends Transition
        case class Close(response: ActorRef[State]) extends Transition
        def doorActor: Behavior[Transition] = {
          while (true) {
            val open = !ReceiveMessage.Partial[Open]
            open.response ! Opened
            val close = !ReceiveMessage.Partial[Close]
            close.response ! Closed
          }
          throw new Exception("Unreachable code!")
        }
        this.markup("The door should reply an `Opened` state after performing an `Open` transition,")
        import akka.actor.testkit.typed.scaladsl._
        val door = BehaviorTestKit(doorActor)
        val state = TestInbox[State]()
        door.run(Open(state.ref))
        state.expectMessage(Opened)
        this.markup("and the state of the door can be switched between `Opend` and `Closed` according to `Open` and `Close` transition.")
        door.run(Close(state.ref))
        state.expectMessage(Closed)
        door.run(Open(state.ref))
        state.expectMessage(Opened)
        door.run(Close(state.ref))
        state.expectMessage(Closed)
      } finally {})
      """@note To use `try` / `catch` / `finally` expressions with !-notation,
the return type of enclosing function should be `Behavior[?] !! Throwable`,
as shown in the following `createDecoderActor` method.""".in(try {
        this.markup("""It will open an [[java.io.InputStream]],
read [[String]] from the stream,
and close the stream in a `finally` block.""")
        import akka.actor.typed._
        import akka.actor.typed.scaladsl._
        import com.thoughtworks.dsl.Dsl.!!
        import java.io._
        import java.net._
        sealed trait Command
        case class Open(open: () => InputStream) extends Command
        case class ReadObject(response: ActorRef[String]) extends Command
        case object Close extends Command
        class DecoderException(cause: Throwable) extends Exception(cause)
        def createDecoderActor: Behavior[Command] !! Throwable = {
          while (true) {
            val inputStream = (!ReceiveMessage.Partial[Open]).open()
            try {
              val ReadObject(replyTo) = !ReceiveMessage.Partial[ReadObject]
              replyTo ! new java.io.DataInputStream(inputStream).readUTF()
              !ReceiveMessage.Partial[Close.type]
            } catch {
              case e: IOException =>
                throw new DecoderException(e)
            } finally {
              inputStream.close()
            }
          }
          throw new AssertionError("Unreachable code!")
        }
        this.markup("""Since `createDecoderActor` returns `Behavior[Command] !! Throwable`,
it receives message of type `Command`,
and accepts an additional callback function
to handle exceptions that are not handled in `createDecoderActor`.""")
        import akka.actor.testkit.typed.scaladsl._
        val errorHandler = mockFunction[Throwable, Behavior[Command]]
        val decoderActor = BehaviorTestKit(createDecoderActor(errorHandler))
        this.markup("Given an `InputStream` that throws an [[java.io.IOException]] when read from it,")
        val inputStream: InputStream = mock[InputStream]
        toMockFunction0(inputStream.read _).expects().throws(new IOException())
        decoderActor.run(Open { () => inputStream })
        this.markup("""when the `decoderActor` try to read a [[String]] from the stream,
it should close the stream due to `finally` block triggered by the exception.""")
        val inbox = TestInbox[String]()
        errorHandler.expects(where[Throwable](_.isInstanceOf[DecoderException])).returns(Behaviors.stopped)
        toMockFunction0(inputStream.close _).expects().returns(()).once()
        decoderActor.run(ReadObject(inbox.ref))
        inbox.receiveAll() should be(empty)
      } finally {})
      "@author 杨博 (Yang Bo)" - {}
      "typedReceiveMessageDsl" - {
        this.markup("Returns an [[com.thoughtworks.dsl.Dsl]] instance for [[keywords.akka.actor.ReceiveMessage]] in the [[akka.actor.typed.Behavior]] domain.")
        "@example Given an `echoActor` that receives `Ping` messages and replies corresponding `Pong` messages".in(try {
          import akka.actor.typed._
          case class Ping(message: String, response: ActorRef[Pong])
          case class Pong(message: String)
          def echoActor: Behavior[Ping] = {
            while (true) {
              val Ping(m, replyTo) = !ReceiveMessage[Ping]
              replyTo ! Pong(m)
            }
            throw new Exception("Unreachable code!")
          }
          this.markup("""When pinging it with "hello",
then it should reply a `Pong` with the same message "hello".""")
          import akka.actor.testkit.typed.scaladsl._
          val pinger = BehaviorTestKit(echoActor)
          val probe = TestInbox[Pong]()
          pinger.run(Ping("hello", probe.ref))
          probe.expectMessage(Pong("hello"))
        } finally {})
      }
      "typedReceiveMessagePartialDsl" - {
        this.markup("Returns an [[com.thoughtworks.dsl.Dsl]] instance for [[keywords.akka.actor.ReceiveMessage.Partial]] in the [[akka.actor.typed.Behavior]] domain.")
        "@example Given an `echoActor` that receives `Ping` messages and replies corresponding `Pong` messages".in(try {
          import akka.actor.typed._
          case class Ping(message: String, response: ActorRef[Pong])
          case class Pong(message: String)
          def echoActor: Behavior[AnyRef] = {
            while (true) {
              val Ping(m, replyTo) = !ReceiveMessage.Partial[Ping]
              replyTo ! Pong(m)
            }
            throw new Exception("Unreachable code!")
          }
          this.markup("""When pinging it with "hello",
then it should reply a `Pong` with the same message "message",
and other types of messages should not be handled.""")
          import akka.actor.testkit.typed.scaladsl._
          val pinger = BehaviorTestKit(echoActor)
          object UnhandledMessage
          pinger.run(UnhandledMessage)
          val probe = TestInbox[Pong]()
          pinger.run(Ping("hello", probe.ref))
          probe.expectMessage(Pong("hello"))
        } finally {})
      }
    }
  }
}

The reproduction code can be found in this PR: Atry/Dsl.scala-akka-actor#12
Full log: https://travis-ci.org/Atry/Dsl.scala-akka-actor/jobs/549688495

Atry added a commit to Atry/ScalaMock that referenced this issue Jun 24, 2019
@barkhorn barkhorn added this to Backlog in ScalaMock via automation Jun 24, 2019
@vmencik
Copy link

vmencik commented Jul 3, 2019

Note that this also affects all pre-Java 11 JVM runtimes and IMHO is caused by releasing with OpenJDK 11.

 java.lang.NoSuchMethodError: java.lang.String.lines()Ljava/util/stream/Stream;
	at org.scalamock.handlers.Handlers.$anonfun$toString$1(Handlers.scala:35)

@barkhorn
Copy link
Collaborator

Caused by scala/bug/issues/11125

@barkhorn barkhorn mentioned this issue Jul 20, 2019
3 tasks
@barkhorn barkhorn moved this from Backlog to In progress in ScalaMock Jul 20, 2019
ScalaMock automation moved this from In progress to Done Jul 20, 2019
@barkhorn barkhorn added this to the v4.4.0 milestone Aug 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging a pull request may close this issue.

3 participants