Skip to content

Commit

Permalink
distribute core code across diff + munit
Browse files Browse the repository at this point in the history
  • Loading branch information
majk-p committed Apr 16, 2024
1 parent 87e0f88 commit 017c242
Show file tree
Hide file tree
Showing 29 changed files with 968 additions and 31 deletions.
51 changes: 30 additions & 21 deletions build.sbt
Expand Up @@ -244,7 +244,8 @@ lazy val munit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
)
.jvmConfigure(_.dependsOn(junit))
.dependsOn(munitDiff, munitCore)
.dependsOn(munitDiff)
// .dependsOn(munitDiff, munitCore)

lazy val munitJVM = munit.jvm
lazy val munitJS = munit.js
Expand Down Expand Up @@ -290,13 +291,37 @@ lazy val munitScalacheck = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.jsConfigure(sharedJSConfigure)
.jsSettings(sharedJSSettings)

lazy val munitCore = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("munit-core"))
// lazy val munitCore = crossProject(JSPlatform, JVMPlatform, NativePlatform)
// .in(file("munit-core"))
// .settings(
// moduleName := "munit-core",
// sharedSettings,
// Compile / unmanagedSourceDirectories ++=
// crossBuildingDirectories("munit-core", "main").value,
// libraryDependencies ++= List(
// "org.scala-lang" % "scala-reflect" % {
// if (isScala3Setting.value) scala213
// else scalaVersion.value
// } % Provided
// )
// )
// .jvmSettings(
// sharedJVMSettings
// )
// .nativeConfigure(sharedNativeConfigure)
// .nativeSettings(
// sharedNativeSettings
// )
// .jsConfigure(sharedJSConfigure)
// .jsSettings(sharedJSSettings)

lazy val munitDiff = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("scala-diff"))
.settings(
moduleName := "munit-core",
moduleName := "scala-diff",
sharedSettings,
Compile / unmanagedSourceDirectories ++=
crossBuildingDirectories("munit-core", "main").value,
crossBuildingDirectories("scala-diff", "main").value,
libraryDependencies ++= List(
"org.scala-lang" % "scala-reflect" % {
if (isScala3Setting.value) scala213
Expand All @@ -313,22 +338,6 @@ lazy val munitCore = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
.jsConfigure(sharedJSConfigure)
.jsSettings(sharedJSSettings)

lazy val munitDiff = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("scala-diff"))
.settings(
moduleName := "scala-diff",
sharedSettings
)
.jvmSettings(
sharedJVMSettings
)
.nativeConfigure(sharedNativeConfigure)
.nativeSettings(
sharedNativeSettings
)
.jsConfigure(sharedJSConfigure)
.jsSettings(sharedJSSettings)
// .dependsOn(munitCore)

lazy val munitScalacheckJVM = munitScalacheck.jvm
Expand Down
78 changes: 78 additions & 0 deletions munit/js/src/main/scala/munit/internal/io/File.scala
@@ -0,0 +1,78 @@
package munit.internal.io

import java.net.URI

// obtained implementation by experimentation on the JDK.
class File(path: String) {
def this(parent: String, child: String) =
this(parent + File.separator + child)
def this(parent: File, child: String) =
this(parent.getPath, child)
def this(uri: URI) =
this(
if (uri.getScheme != "file") {
throw new IllegalArgumentException("URI scheme is not \"file\"")
} else {
uri.getPath
}
)
def toPath: MunitPath =
MunitPath(path)
def toURI: URI = {
val file = getAbsoluteFile.toString
val uripath =
if (file.startsWith("/")) file
else "/" + file.replace(File.separator, "/")
val withslash =
if (isDirectory && !uripath.endsWith("/")) uripath + "/" else uripath
new URI("file", null, withslash, null)
}
def getAbsoluteFile: File =
toPath.toAbsolutePath.toFile
def getAbsolutePath: String =
getAbsoluteFile.toString
def getParentFile: File =
toPath.getParent.toFile
def mkdirs(): Unit =
throw new UnsupportedOperationException(
"mkdirs() is not supported in Scala.js"
)
def getPath: String =
path
def exists(): Boolean =
JSIO.exists(path)
def isFile: Boolean =
JSIO.isFile(path)
def isDirectory: Boolean =
JSIO.isDirectory(path)
override def toString: String =
path
}

object File {
def listRoots(): Array[File] = Array(
new File(
JSIO.path match {
case Some(p) => p.parse(p.resolve()).root.asInstanceOf[String]
case None => "/"
}
// if (JSIO.isNode) JSPath.parse(JSPath.resolve()).root
// else "/"
)
)

def separatorChar: Char =
separator.charAt(0)

def separator: String =
JSIO.path match {
case Some(p) => p.sep.asInstanceOf[String]
case None => "/"
}

def pathSeparator: String =
JSIO.path match {
case Some(p) => p.delimeter.asInstanceOf[String]
case None => ":"
}
}
30 changes: 30 additions & 0 deletions munit/js/src/main/scala/munit/internal/io/Files.scala
@@ -0,0 +1,30 @@
package munit.internal.io

import scala.scalajs.js
import java.{util => ju}
import java.nio.charset.StandardCharsets

import scala.collection.JavaConverters._

object Files {
def readAllLines(path: MunitPath): ju.List[String] = {
val bytes = readAllBytes(path)
val text = new String(bytes, StandardCharsets.UTF_8)
text.linesIterator.toSeq.asJava
}
def readAllBytes(path: MunitPath): Array[Byte] = {
val jsArray = JSIO.fs match {
case Some(fs) =>
fs.readFileSync(path.toString).asInstanceOf[js.Array[Int]]
case None => new js.Array[Int](0)
}
val len = jsArray.length
val result = new Array[Byte](len)
var curr = 0
while (curr < len) {
result(curr) = jsArray(curr).toByte
curr += 1
}
result
}
}
42 changes: 42 additions & 0 deletions munit/js/src/main/scala/munit/internal/io/JSIO.scala
@@ -0,0 +1,42 @@
package munit.internal.io

import scala.scalajs.js
import scala.util.Try

object JSIO {

private def require(module: String): Option[js.Dynamic] = {
Try(js.Dynamic.global.require(module)) // Node.js
.orElse( // JSDOM
Try(js.Dynamic.global.Node.constructor("return require")()(module))
)
.toOption
}
val process: Option[js.Dynamic] = require("process")
val path: Option[js.Dynamic] = require("path")
val fs: Option[js.Dynamic] = require("fs")

def cwd(): String =
process match {
case Some(p) => p.cwd().asInstanceOf[String]
case None => "/"
}

def exists(path: String): Boolean =
fs match {
case Some(f) => f.existsSync(path).asInstanceOf[Boolean]
case None => false
}

def isFile(path: String): Boolean =
exists(path) && (fs match {
case Some(f) => f.lstatSync(path).isFile().asInstanceOf[Boolean]
case None => false
})

def isDirectory(path: String): Boolean =
exists(path) && (fs match {
case Some(f) => f.lstatSync(path).isDirectory().asInstanceOf[Boolean]
case None => false
})
}
149 changes: 149 additions & 0 deletions munit/js/src/main/scala/munit/internal/io/MunitPath.scala
@@ -0,0 +1,149 @@
package munit.internal.io

import java.net.URI
import java.util

import scala.collection.JavaConverters._

// Rough implementation of java.nio.Path, should work similarly for the happy
// path but has undefined behavior for error handling.
case class MunitPath(filename: String) {
private[this] val escapedSeparator =
java.util.regex.Pattern.quote(File.separator)

private def adjustIndex(idx: Int): Int =
if (isAbsolute) idx + 1 else idx
def subpath(beginIndex: Int, endIndex: Int): MunitPath =
MunitPath(
filename
.split(escapedSeparator)
.slice(adjustIndex(beginIndex), adjustIndex(endIndex))
.mkString
)
def toFile: File =
new File(filename)
def isAbsolute: Boolean = JSIO.path match {
case Some(path) => path.isAbsolute(filename).asInstanceOf[Boolean]
case None => filename.startsWith(File.separator)
}
def getName(index: Int): MunitPath =
MunitPath(
filename
.split(escapedSeparator)
.lift(adjustIndex(index))
.getOrElse(throw new IllegalArgumentException)
)
def getParent: MunitPath =
JSIO.path match {
case Some(path) =>
MunitPath(path.dirname(filename).asInstanceOf[String])
case None =>
throw new UnsupportedOperationException(
"Path.getParent() is only supported in Node.js"
)
}

def toAbsolutePath: MunitPath =
if (isAbsolute) this
else MunitPath.workingDirectory.resolve(this)
def relativize(other: MunitPath): MunitPath =
JSIO.path match {
case Some(path) =>
MunitPath(
path.relative(filename, other.toString()).asInstanceOf[String]
)
case None =>
throw new UnsupportedOperationException(
"Path.relativize() is only supported in Node.js"
)
}
def getNameCount: Int = {
val strippeddrive =
if ((filename.length > 1) && (filename(1) == ':')) filename.substring(2)
else filename
val (first, remaining) =
strippeddrive.split(escapedSeparator + "+").span(_.isEmpty)
if (remaining.isEmpty) first.length
else remaining.length
}
def toUri: URI = toFile.toURI
def getFileName(): MunitPath =
JSIO.path match {
case Some(path) =>
MunitPath(path.basename(filename).asInstanceOf[String])
case None =>
throw new UnsupportedOperationException(
"Path.getFileName() is only supported in Node.js"
)
}
def getRoot: MunitPath =
if (!isAbsolute) null
else MunitPath(File.separator)
def normalize(): MunitPath =
JSIO.path match {
case Some(path) =>
MunitPath(path.normalize(filename).asInstanceOf[String])
case None =>
throw new UnsupportedOperationException(
"Path.normalize() is only supported in Node.js"
)
}
def endsWith(other: MunitPath): Boolean =
endsWith(other.toString)
def endsWith(other: String): Boolean =
paths(filename).endsWith(paths(other))
// JSPath.resolve(relpath, relpath) produces an absolute path from cwd.
// This method turns the generated absolute path back into a relative path.
private def adjustResolvedPath(resolved: MunitPath): MunitPath =
if (isAbsolute) resolved
else MunitPath.workingDirectory.relativize(resolved)
def resolveSibling(other: MunitPath): MunitPath =
resolveSibling(other.toString)
def resolveSibling(other: String): MunitPath =
JSIO.path match {
case Some(path) =>
adjustResolvedPath(
MunitPath(
path
.resolve(path.dirname(filename).asInstanceOf[String], other)
.asInstanceOf[String]
)
)
case None =>
throw new UnsupportedOperationException(
"Path.normalize() is only supported in Node.js"
)
}
def resolve(other: MunitPath): MunitPath =
resolve(other.toString)
def resolve(other: String): MunitPath =
JSIO.path match {
case Some(path) =>
adjustResolvedPath(
MunitPath(path.resolve(filename, other).asInstanceOf[String])
)
case None =>
throw new UnsupportedOperationException(
"Path.normalize() is only supported in Node.js"
)
}
def startsWith(other: MunitPath): Boolean =
startsWith(other.toString)
def startsWith(other: String): Boolean =
paths(filename).startsWith(paths(other))
private def paths(name: String) =
name.split(escapedSeparator)
override def toString: String =
filename
def iterator(): util.Iterator[MunitPath] =
filename
.split(File.separator)
.iterator
.map(name => MunitPath(name): MunitPath)
.asJava
}

object MunitPath {
def workingDirectory: MunitPath =
MunitPath(JSIO.cwd())
}

0 comments on commit 017c242

Please sign in to comment.