summaryrefslogtreecommitdiff
path: root/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
blob: 80cde6c9a940dd9f45613fb3615e329010b394b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package scala.tools.nsc
package backend.jvm

import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.Test
import scala.tools.asm.Opcodes._
import org.junit.Assert._

import scala.tools.testing.AssertUtil._

import CodeGenTools._
import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass

object StringConcatTest extends ClearAfterClass.Clearable {
  var compiler = newCompiler()
  def clear(): Unit = { compiler = null }
}

@RunWith(classOf[JUnit4])
class StringConcatTest extends ClearAfterClass {
  ClearAfterClass.stateToClear = StringConcatTest
  val compiler = StringConcatTest.compiler

  val commonPreInstructions = List(Label(0), LineNumber(1, Label(0)), TypeOp(NEW, "java/lang/StringBuilder"), Op(DUP), Invoke(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false), VarOp(ALOAD, 0))

  val commonPostInstructions = List(Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false), Op(ARETURN), Label(12))

  def instructionsWithCommonParts(instructions: List[Instruction]) = commonPreInstructions ++ instructions ++ commonPostInstructions

  def instructionsForResultMethod(code: String): List[Instruction] = {
    val methods = compileMethods(compiler)(code)
    val resultMethod = methods.find(_.name == "result").get
    instructionsFromMethod(resultMethod)
  }

  @Test
  def concatStringToStringBuilder: Unit = {
    val code = """ def string = "def"; def result = "abc" + string """
    val actualInstructions = instructionsForResultMethod(code)
    val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "string", "()Ljava/lang/String;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false)))
    assertSameCode(actualInstructions, expectedInstructions)
  }

  @Test
  def concatStringBufferToStringBuilder: Unit = {
    val code = """ def stringBuffer = new java.lang.StringBuffer("def"); def result = "abc" + stringBuffer """
    val actualInstructions = instructionsForResultMethod(code)
    val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "stringBuffer", "()Ljava/lang/StringBuffer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/StringBuffer;)Ljava/lang/StringBuilder;", false)))
    assertSameCode(actualInstructions, expectedInstructions)
  }

  @Test
  def concatCharSequenceToStringBuilder: Unit = {
    val code = """ def charSequence: CharSequence = "def"; def result = "abc" + charSequence """
    val actualInstructions = instructionsForResultMethod(code)
    val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "charSequence", "()Ljava/lang/CharSequence;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;", false)))
    assertSameCode(actualInstructions, expectedInstructions)
  }

  @Test
  def concatIntToStringBuilder: Unit = {
    val code = """ def int = 123; def result = "abc" + int """
    val actualInstructions = instructionsForResultMethod(code)
    val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "int", "()I", false), Invoke(INVOKESTATIC, "scala/runtime/BoxesRunTime", "boxToInteger", "(I)Ljava/lang/Integer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuilder;", false)))
    assertSameCode(actualInstructions, expectedInstructions)
  }
}