package projet

import chisel3.simulator.scalatest.ChiselSim
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.must.Matchers
import org.scalatest.prop.TableDrivenPropertyChecks._
import java.nio.file.{Files, Paths}
import scala.jdk.CollectionConverters._
import scala.collection.mutable.ListBuffer
import projet.ZzTopCommon.expectedValuesFromAsm
import projet.ZzTopCommon.expectNextValue

class ZzTopSpec extends AnyFreeSpec with Matchers with ChiselSim {
    // Fonction de test commune
    def testWith(file: String): Unit = {
        val path = file.replace("/mem/", "/").replace(".mem", ".s")
        if (Files.exists(Paths.get(path))) {
            val expected = expectedValuesFromAsm(path)
            simulate(new ZzTop(file, true)) { dut =>
                val trace = ListBuffer[String]()
                expected.foreach { value =>
                    expectNextValue(dut, value, timeout = 100, trace)
                }
            }
        }
    }

    val dir = sys.env("PROOT") + "/bench/mem/"
    val suffix = ".mem"
    val programFile = sys.env.get("PROG")
    if (programFile.isDefined) {
        val name = programFile.get
        val path = dir + name + suffix

        "Simulation pour gtkwave" in {
            simulate(new ZzTop(path, true)) { dut =>
                dut.io.switch.poke(8) // Paramétrage de l'affichage
                dut.io.led.expect(dut.io.led.peek()) // test dummy
                dut.clock.step(sys.env("CYCLES").toInt)
            }
        }

        s"Test unitaire $name" in testWith(path)

    } else {
        // Récupération des fichiers .mem et génération de la table de programmes
        val programs = Files
            .list(Paths.get(dir))
            .iterator()
            .asScala
            .filter(_.toString.endsWith(suffix))
        val p2 = programs
            .map(path =>
                (path.getFileName.toString.stripSuffix(suffix), path.toString)
            )
            .toSeq
        val table = Table(("name", "path"), p2: _*)

        // Déclaration des tests à partir de la table
        forAll(table) { (name, path) =>
            s"Programme $name" in testWith(path)
        }
    }
}
