package wacc

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.Inspectors.forEvery
import cats.data.Chain

class ExtensionsSpec extends AnyFlatSpec {
  import asmGenerator.concatAll
  import asmGenerator.escaped

  behavior of "concatAll"

  it should "handle int chains" in {
    val chain = Chain(1, 2, 3).concatAll(
      Chain(4, 5, 6),
      Chain.empty,
      Chain.one(-1)
    )
    assert(chain == Chain(1, 2, 3, 4, 5, 6, -1))
  }

  it should "handle AsmLine chains" in {
    object lines {
      import assemblyIR._
      import assemblyIR.commonRegisters._
      val main = LabelDef("main")
      val pop = Pop(RAX)
      val add = Add(RAX, ImmediateVal(1))
      val push = Push(RAX)
      val ret = Return()
    }
    val chain = Chain(lines.main).concatAll(
      Chain.empty,
      Chain.one(lines.pop),
      Chain(lines.add, lines.push),
      Chain.one(lines.ret)
    )
    assert(chain == Chain(lines.main, lines.pop, lines.add, lines.push, lines.ret))
  }

  behavior of "escaped"

  val escapedStrings = Map(
    "hello" -> "hello",
    "world" -> "world",
    "hello\nworld" -> "hello\\nworld",
    "hello\tworld" -> "hello\\tworld",
    "hello\\world" -> "hello\\\\world",
    "hello\"world" -> "hello\\\"world",
    "hello'world" -> "hello\\'world",
    "hello\\nworld" -> "hello\\\\nworld",
    "hello\\tworld" -> "hello\\\\tworld",
    "hello\\\\world" -> "hello\\\\\\\\world",
    "hello\\\"world" -> "hello\\\\\\\"world",
    "hello\\'world" -> "hello\\\\\\'world",
    "hello\\n\\t\\'world" -> "hello\\\\n\\\\t\\\\\\'world",
    "hello\u0000world" -> "hello\\0world",
    "hello\bworld" -> "hello\\bworld",
    "hello\fworld" -> "hello\\fworld"
  )
  forEvery(escapedStrings) { (input, expected) =>
    it should s"return $expected" in {
      assert(input.escaped == expected)
    }
  }
}
