Skip to content

Commit

Permalink
Test interface (scala-native#755)
Browse files Browse the repository at this point in the history
* Make `StackTraceElement` closer to Java's impl

* Add initial version of the test interface

There are still many rough edges and issues with it. See comments in the
code for the different issues to tackle :)

* Teach Travis how to build scalacheck

* scalafmt

* Cleanup

* Remove debug info from serializers

* Fix how tests are instantiated

We were assuming that tests are always inside objects, but that's not
true. Fortunately, fingerprints tell us all we need to instantiate the
tests.

* Don't do `rebuild` twice in Travis CI

* scalafmt

* Correctly convert variants of `struct sockaddr`

Previously we would just copy a pre-defined number of bytes, now matter
what the actual underlying struct was. Now, we use the length of the
input struct to determine its type, and correctly convert to the
operating system implementation, so that no information is lost.

* %s/PreLoaded/Preloaded/g

* Remove `stubs` project

* Remove impls in `Class.getField` and `Field.get`

* Deprecate `JSExportDescendent{Classes,Objects}`

* Simpler serialization

* Add implicit classes for `sockaddr` and friends

* Give names to fields of structs for sockets

* Fix review comments

* Prefix test name with `_root_.`

* Add NativeFramework to run our unit tests

* Remove utest and scalacheck tests

* Remove old, dead code
  • Loading branch information
Duhemm authored and asoltysik committed Jul 14, 2017
1 parent d7c6676 commit e775181
Show file tree
Hide file tree
Showing 114 changed files with 2,179 additions and 62 deletions.
86 changes: 59 additions & 27 deletions build.sbt
Expand Up @@ -28,6 +28,8 @@ addCommandAlias(
Seq(
"nscplugin/publishLocal",
"nativelib/publishLocal",
"javalib/publishLocal",
"scalalib/publishLocal",
"publishLocal"
).mkString(";", ";", "")
)
Expand All @@ -37,7 +39,7 @@ addCommandAlias(
Seq(
"sandbox/run",
"demoNative/run",
"tests/run",
"tests/test",
"tools/test",
"benchmarks/run --test",
"scripted"
Expand Down Expand Up @@ -272,15 +274,24 @@ lazy val sbtScalaNative =
addSbtPlugin("org.scala-native" % "sbt-crossproject" % "0.1.0"),
moduleName := "sbt-scala-native",
sbtTestDirectory := (baseDirectory in ThisBuild).value / "scripted-tests",
// `testInterfaceSerialization` needs to be available from the sbt plugin,
// but it's a Scala Native project (and thus 2.11), and the plugin is 2.10.
// We simply add the sources to mimic cross-compilation.
sources in Compile ++= (sources in Compile in testInterfaceSerialization).value,
// publish the other projects before running scripted tests.
scripted := scripted
.dependsOn(publishLocal in util,
publishLocal in nir,
publishLocal in tools,
publishLocal in nscplugin,
publishLocal in nativelib,
publishLocal in javalib,
publishLocal in scalalib)
.dependsOn(
publishLocal in util,
publishLocal in nir,
publishLocal in tools,
publishLocal in nscplugin,
publishLocal in nativelib,
publishLocal in javalib,
publishLocal in scalalib,
publishLocal in testInterfaceSbtDefs,
publishLocal in testInterfaceSerialization,
publishLocal in testInterface
)
.evaluated,
publishLocal := publishLocal.dependsOn(publishLocal in tools).value
)
Expand Down Expand Up @@ -395,24 +406,9 @@ lazy val tests =
.settings(
// nativeOptimizerReporter := OptimizerReporter.toDirectory(
// crossTarget.value),
sourceGenerators in Compile += Def.task {
val dir = (scalaSource in Compile).value
val suites = (dir ** "*Suite.scala").get
.flatMap(IO.relativizeFile(dir, _))
.map(file => packageNameFromPath(file.toPath))
.filter(_ != "tests.Suite")
.mkString("Seq(", ", ", ")")
val file = (sourceManaged in Compile).value / "tests" / "Discover.scala"
IO.write(file,
s"""
package tests
object Discover {
val suites: Seq[tests.Suite] = $suites
}
""")
Seq(file)
},
envVars in run ++= Map(
libraryDependencies += "org.scala-native" %%% "test-interface" % nativeVersion,
testFrameworks += new TestFramework("tests.NativeFramework"),
envVars in (Test, test) ++= Map(
"USER" -> "scala-native",
"HOME" -> baseDirectory.value.getAbsolutePath,
"SCALA_NATIVE_ENV_WITH_EQUALS" -> "1+1=2",
Expand All @@ -424,11 +420,11 @@ lazy val tests =
lazy val sandbox =
project
.in(file("sandbox"))
.settings(projectSettings)
.settings(noPublishSettings)
.settings(
// nativeOptimizerReporter := OptimizerReporter.toDirectory(
// crossTarget.value)
scalaVersion := libScalaVersion
)
.enablePlugins(ScalaNativePlugin)

Expand Down Expand Up @@ -483,3 +479,39 @@ lazy val testingCompiler =
)
)
.dependsOn(testingCompilerInterface, nativelib)

lazy val testInterface =
project
.settings(toolSettings)
.settings(scalaVersion := libScalaVersion)
.in(file("test-interface"))
.settings(
name := "test-interface",
libraryDependencies += "org.scala-sbt" % "test-interface" % "1.0",
libraryDependencies -= "org.scala-native" %%% "test-interface" % version.value % Test
)
.enablePlugins(ScalaNativePlugin)
.dependsOn(testInterfaceSerialization)

lazy val testInterfaceSerialization =
project
.settings(toolSettings)
.settings(scalaVersion := libScalaVersion)
.in(file("test-interface-serialization"))
.settings(
name := "test-interface-serialization",
libraryDependencies -= "org.scala-native" %%% "test-interface" % version.value % Test
)
.dependsOn(testInterfaceSbtDefs)
.enablePlugins(ScalaNativePlugin)

lazy val testInterfaceSbtDefs =
project
.settings(toolSettings)
.settings(scalaVersion := libScalaVersion)
.in(file("test-interface-sbt-defs"))
.settings(
name := "test-interface-sbt-defs",
libraryDependencies -= "org.scala-native" %%% "test-interface" % version.value % Test
)
.enablePlugins(ScalaNativePlugin)
6 changes: 6 additions & 0 deletions javalib/src/main/scala/java/lang/ClassLoader.scala
@@ -0,0 +1,6 @@
package java.lang

class ClassLoader protected (parent: ClassLoader) {
def this() = this(null)
def loadClass(name: String): Class[_] = null
}
2 changes: 2 additions & 0 deletions javalib/src/main/scala/java/lang/StringBuffer.scala
Expand Up @@ -250,6 +250,8 @@ final class StringBuffer
return this
}

override def length(): Int = super.length()

override def setCharAt(index: scala.Int, ch: scala.Char): Unit =
synchronized {
super.setCharAt(index, ch)
Expand Down
@@ -0,0 +1,12 @@
package java.util.concurrent.locks

import java.io.Serializable

abstract class AbstractOwnableSynchronizer protected () extends Serializable {
private var exclusiveOwner: Thread = _

protected final def setExclusiveOwnerThread(thread: Thread): Unit =
exclusiveOwner = thread
protected final def getExclusiveOwnerThread(): Thread =
exclusiveOwner
}
@@ -0,0 +1,16 @@
package java.util.concurrent.locks

abstract class AbstractQueuedSynchronizer protected ()
extends AbstractOwnableSynchronizer() {

def acquireSharedInterruptibly(arg: Int): Unit = ()

def releaseSharedInterruptibly(arg: Int): Boolean = true

def releaseShared(arg: Int): Boolean = true

override def toString(): String = "AbstractQueuedSynchronizer"

def tryAcquireSharedNanos(arg: Int, nanos: Long): Boolean = true

}
5 changes: 5 additions & 0 deletions nativelib/src/main/scala/java/lang/Class.scala
@@ -1,5 +1,7 @@
package java.lang

import java.lang.reflect.Field

import scalanative.native._
import scalanative.runtime.{Array => _, _}

Expand Down Expand Up @@ -43,6 +45,9 @@ final class _Class[A](val ty: Ptr[Type]) {
def getSuperclass(): Class[_ >: A] =
???

def getField(name: String): Field =
???

def isArray(): scala.Boolean =
(ty == typeof[BooleanArray] ||
ty == typeof[CharArray] ||
Expand Down
5 changes: 5 additions & 0 deletions nativelib/src/main/scala/java/lang/reflect/Field.scala
@@ -0,0 +1,5 @@
package java.lang.reflect

class Field {
def get(obj: Object): Object = ???
}
Expand Up @@ -17,7 +17,7 @@ object in {
in_port_t, // sin_port
in_addr] // sin_addr

type in6_addr = CStruct1[CArray[uint8_t, _16]]
type in6_addr = CStruct1[CArray[uint8_t, _16]] // s6_addr
type sockaddr_in6 = CStruct5[in6_addr, // sin6_addr
socket.sa_family_t, // sin6_family
in_port_t, // sin6_port
Expand Down Expand Up @@ -115,3 +115,49 @@ object in {
def IN6_IS_ADDR_MC_GLOBAL(arg: Ptr[in6_addr]): CInt = extern

}

object inOps {
import in._

implicit class sockaddr_inOps(val ptr: Ptr[sockaddr_in]) extends AnyVal {
def sin_family: socket.sa_family_t = !ptr._1
def sin_port: in_port_t = !ptr._2
def sin_addr: Ptr[in_addr] = ptr._3

def sin_family_=(v: socket.sa_family_t): Unit = !ptr._1 = v
def sin_port_=(v: in_port_t): Unit = !ptr._2 = v
def sin_addr_=(v: Ptr[in_addr]): Unit = !ptr._3 = !v
}

implicit class sockaddr_in6Ops(val ptr: Ptr[sockaddr_in6]) extends AnyVal {
def sin6_addr: Ptr[in6_addr] = ptr._1
def sin6_family: socket.sa_family_t = !ptr._2
def sin6_port: in_port_t = !ptr._3
def sin6_flowinfo: uint32_t = !ptr._4
def sin6_scope_id: uint32_t = !ptr._5

def sin6_addr_=(v: Ptr[in6_addr]): Unit = !ptr._1 = !v
def sin6_family_=(v: socket.sa_family_t): Unit = !ptr._2 = v
def sin6_port_=(v: in_port_t): Unit = !ptr._3 = v
def sin6_flowinfo_=(v: uint32_t): Unit = !ptr._4 = v
def sin6_scope_id_=(v: uint32_t): Unit = !ptr._5 = v
}

implicit class in_addrOps(val ptr: Ptr[in_addr]) extends AnyVal {
def in_addr: in_addr_t = !ptr._1
def in_addr_=(v: in_addr_t): Unit = !ptr._1 = v
}

implicit class in6_addrOps(val ptr: Ptr[in6_addr]) extends AnyVal {
def s6_addr: CArray[uint8_t, _16] = !ptr._1
def s6_addr_=(v: CArray[uint8_t, _16]): Unit = !ptr._1 = v
}

implicit class ipv6_mreqOps(val ptr: Ptr[ipv6_mreq]) extends AnyVal {
def ipv6mr_multiaddr: Ptr[in6_addr] = ptr._1
def ipv6mr_interface: CUnsignedInt = !ptr._2

def ipv6mr_multiaddr_=(v: Ptr[in6_addr]): Unit = !ptr._1 = !v
def ipv6mr_interface_=(v: CUnsignedInt): Unit = !ptr._2 = v
}
}
55 changes: 55 additions & 0 deletions nativelib/src/main/scala/scala/scalanative/posix/sys/socket.scala
Expand Up @@ -168,3 +168,58 @@ object socket {
length: CSize,
flags: CInt): CSSize = extern
}

object socketOps {
import socket._

implicit class sockaddrOps(val ptr: Ptr[sockaddr]) extends AnyVal {
def sa_family: sa_family_t = !ptr._1
def sa_data: CArray[CChar, _14] = !ptr._2

def sa_family_=(v: sa_family_t): Unit = !ptr._1 = v
def sa_data_=(v: CArray[CChar, _14]): Unit = !ptr._2 = v
}

implicit class sockaddr_storageOps(val ptr: Ptr[sockaddr_storage])
extends AnyVal {
def ss_family: sa_family_t = !ptr._1
def ss_family_=(v: sa_family_t): Unit = !ptr._1 = v
}

implicit class msghdrOps(val ptr: Ptr[msghdr]) extends AnyVal {
def msg_name: Ptr[Byte] = !ptr._1
def msg_namelen: socklen_t = !ptr._2
def msg_iov: Ptr[uio.iovec] = !ptr._3
def msg_iovlen: CInt = !ptr._4
def msg_control: Ptr[Byte] = !ptr._5
def msg_controllen: socklen_t = !ptr._6
def msg_flags: CInt = !ptr._7

def msg_name_=(v: Ptr[Byte]): Unit = !ptr._1 = v
def msg_namelen_=(v: socklen_t): Unit = !ptr._2 = v
def msg_iov_=(v: Ptr[uio.iovec]): Unit = !ptr._3 = v
def msg_iovlen_=(v: CInt): Unit = !ptr._4 = v
def msg_control_=(v: Ptr[Byte]): Unit = !ptr._5 = v
def msg_controllen_=(v: socklen_t): Unit = !ptr._6 = v
def msg_flags_=(v: CInt): Unit = !ptr._7 = v
}

implicit class cmsghdrOps(val ptr: Ptr[cmsghdr]) extends AnyVal {
def cmsg_len: socklen_t = !ptr._1
def cmsg_level: CInt = !ptr._2
def cmsg_type: CInt = !ptr._3

def cmsg_len_=(v: socklen_t): Unit = !ptr._1 = v
def cmsg_level_=(v: CInt): Unit = !ptr._2 = v
def cmsg_type_=(v: CInt): Unit = !ptr._3 = v
}

implicit class lingerOps(val ptr: Ptr[linger]) extends AnyVal {
def l_onoff: CInt = !ptr._1
def l_linger: CInt = !ptr._2

def l_onoff_=(v: CInt): Unit = !ptr._1 = v
def l_linger_=(v: CInt): Unit = !ptr._2 = v
}

}
3 changes: 2 additions & 1 deletion project/build.sbt
Expand Up @@ -5,7 +5,8 @@ unmanagedSourceDirectories in Compile ++= {
"util",
"nir",
"tools",
"sbt-scala-native"
"sbt-scala-native",
"test-interface-serialization"
).map(dir => root / s"$dir/src/main/scala")
}

Expand Down

0 comments on commit e775181

Please sign in to comment.