Integrate µTest (micro test) for Scala into a Gradle project - scala

I'm using Gradle for my Scala projects and a bit frustrated about documentation of scalatest. So I searched for a alternative test framework. The only one I found was µTest (micro test). But so far I could not found a way to integrate µTest into Gradle.

After time of investigation I found a solution. If I have a sample test:
import utest._
object SampleTests extends TestSuite {
val tests:Tests = Tests {
var x = 0
'outer1 - {
x += 1
'inner1 - {
x += 2
assert(x == 3) // 0 + 1 + 2
x
}
'inner2 - {
x += 3
assert(x == 4) // 0 + 1 + 3
x
}
}
'outer2 - {
x += 4
'inner3 - {
x += 5
assert(x == 9) // 0 + 4 + 5
x
}
}
}
def main(args: Array[String]): Unit = {
val results = TestRunner.runAndPrint(SampleTests.tests, "SampleTests")
}
}
Importent is that there is a main funtion which calls a method of the TestRunner with a parameter of type Tests. This parameter can be a value or a method defined with def.
Furthermore the test code should be inside test source location (test instead of main).
For triggering this code you need to modify the build.gradle file. There you can insert a user defined task like this:
task microTest(type: JavaExec) {
main = 'package.SampleTests'
classpath = sourceSets.test.runtimeClasspath
}
Of course you need to declare the dependency inside build.gradle to the test framework:
testImplementation "com.lihaoyi:utest_2.a:x.y.z"
Fazit:
There is a way to trigger the tests with
./gradlew microTest
or click with the mouse inside your IDE at the listed gradle task. The output of the test framework micro test will be printed to the console in the expected way. But when you call this task indirectly by defining the following line inside build.gradle:
test.finalizedBy microTest
with click at the test task in the IDE (Intellij), then the colored output is replaced by special characters.
When not clicking (entering the command line: ./gradlew test) all output is printed correctly.

Related

Chisel persist value in module until new write

I have created a basic module that is meant to represent a unit of memory in Chisel3:
class MemristorCellBundle() extends Bundle {
val writeBus = Input(UInt(1.W))
val dataBus = Input(UInt(8.W))
val cellBus = Output(UInt(8.W))
}
class MemCell() extends Module {
val io = IO(new MemCellBundle())
val write = Wire(UInt())
write := io.voltageBus
val internalValue = Reg(UInt())
// More than 50% of total voltage in (255).
when(write === 1.U) {
internalValue := io.dataBus
io.cellBus := io.dataBus
} .otherwise {
io.cellBus := internalValue
}
}
What I want is for it to output the internalValue when the write bus is logic LOW, and change this value with logic HIGH. My understanding of Chisel is that the register can persist this internalValue between clock cycles, so that this basically acts as a single unit of memory.
I'm doing it in this way as part of a larger project. However when writing a unit test I am finding that the 'read-after-write' scenario fails.
class MemCellTest extends FlatSpec with ChiselScalatestTester with Matchers {
behavior of "MemCell"
it should "read and write" in {
test(new MemCell()) { c =>
c.io.dataBus.poke(5.U)
c.io.write.poke(0.U)
c.io.cellBus.expect(0.U)
// Write
c.io.dataBus.poke(5.U)
c.io.write.poke(1.U)
c.io.cellBus.expect(5.U)
// Verify read-after-write
c.io.dataBus.poke(12.U)
c.io.write.poke(0.U)
c.io.cellBus.expect(5.U)
}
}
}
The first two expectations work just as I would expect. However, when I try to read after writing, the cellBus returns to 0 instead of persisting the 5 that I had written previously.
test MemCell Success: 0 tests passed in 1 cycles in 0.035654 seconds 28.05 Hz
[info] MemCellTest:
[info] MemCell
[info] - should read and write *** FAILED ***
[info] io_cellBus=0 (0x0) did not equal expected=5 (0x5) (lines in MyTest.scala: 10) (MyTest.scala:21)
Clearly the register is not keeping this value, and so internalValue reverts to 0. But why does this happen, and how would I be able to create a value that can persist?
Drakinite's comment is correct. You need to make sure to step the clock in order to see the register latch the value. I tweaked your test to include a couple of steps and it works as expected:
c.io.dataBus.poke(5.U)
c.io.writeBus.poke(0.U)
c.io.cellBus.expect(0.U)
c.clock.step() // Added step
// Write passthrough (same cycle)
c.io.dataBus.poke(5.U)
c.io.writeBus.poke(1.U)
c.io.cellBus.expect(5.U)
c.clock.step() // Added step
// Verify read-after-write
c.io.dataBus.poke(12.U)
c.io.writeBus.poke(0.U)
c.io.cellBus.expect(5.U)
Here's an executable example showing that this works (using chisel3 v3.4.4 and chiseltest v0.3.4): https://scastie.scala-lang.org/5E1rOEsYSzSUrLXZCvoyNA

How to write dependsOn in Custom plugin

I have a task in my build.gradle :
task makeJar(type: Copy) {
delete('dist/')
from('build/intermediates/bundles/release')
into('dist/')
include('classes.jar')
def jarName = new VersionName().getNameWithVersion() + '.jar'
rename('classes.jar', jarName)
}
makeJar.dependsOn('clearTask', build)
Now, I want to remove this from my build.gradle and create a custom plugin like this : MakeJarTask.groovy (this is in eclipse project)
class MakeJarPluginTask extends Copy{
#TaskAction
def makeJar(){
logger.lifecycle("creating a jar *********************")
delete('dist/')
from('build/intermediates/bundles/release')
into('dist/')
include('classes.jar')
def jarName = new VersionName().getNameWithVersion() + '.jar'
rename('classes.jar', jarName)
}
Calling this Task in callGroovy.class (that implements Plugin)
project.tasks.create("makeJarPlugin1", MakeJarPluginTask.class){
dependsOn("clearDist", "build")
}
But this doesn't give the correct output .
The error is in last part, I think this is not the correct way to use dependsOn but I am not able to get how to use this. Any help will be highly appreciated.
Task task = project.tasks.create("makeJarPlugin1", MakeJarPluginTask.class);
task.dependsOn("clearDist", "build")

Shell like application using sbt console

I would like to deploy some scala code, to be used very similar to sbt console
(command line interface, history, etc)
and would like to
customize it
and made it simple to deploy.
Can sbt console be used with these changes:
Removed startup info messages
Removed scala welcome message
Customized command prompt instead of "scala>" to be "myApp>"
No access to local nor global ivy/maven repositories (all jars
available, including sbt jars and dependencies)
Anybody passed this path ?
I have tried
Using sbt to build command line application
but with no much progress so far
(I guessed it was intented to very similar situation)
Are there ready made plugin available ?
Any other tool related or unrelated to sbt ?
Thank you
Actully, no need for sbt. To have it tweaked, scala code should be changed.
For the sbt "Customized command prompt" part, you have a good example with "sbt: Customize the Shell prompt in sbt" from Patrick Bailey (patmandenver).
create the ~/.sbt/0.13/global.sbt file:
vi ~/.sbt/0.13/global.sbt
And place the following in it.
shellPrompt := { state =>
def textColor(color: Int) = { s"\033[38;5;${color}m" }
def backgroundColor(color:Int) = { s"\033[48;5;${color}m" }
def reset = { s"\033[0m" }
def formatText(str: String)(txtColor: Int, backColor: Int) = {
s"${textColor(txtColor)}${backgroundColor(backColor)}${str}${reset}"
}
val red = 1
val green = 2
val yellow = 11
val white = 15
val black = 16
val orange = 166
formatText(s"[${name.value}]")(white, orange) +
"\n " +
formatText("\u276f")(green, black) +
formatText("\u276f")(yellow, black) +
formatText("\u276f ")(red, black)
}
Run reload in sbt and….
That can be amended/enhanced/completed to add other information you would need in your case.

How to fork the jvm for each test in sbt

I am working with some classes that (for some reason) can only be used once within a single VM. My test cases work if I run them individually (fork := true) enabled in my sbt settings.
If I run more than one of these tests, they fail with an exception that has to with a thread executor rejecting a task (it's most likely closed). It would be very time consuming to find out what causes the problem and even if I find the problem, I might not be able to resolve it (I do not have access to the source code).
I am currently using the specs2 test framework, but any test framework using sbt would be acceptable.
Is there any test framework for sbt that is capable of running each test in a jvm fork?
Thoughts or ideas on possible other solutions are of course welcome.
It turns out this is fairly easy to achieve. The documentation is sufficient and can be found at Testing - Forking tests
// Define a method to group tests, in my case a single test per group
def singleTests(tests: Seq[TestDefinition]) =
tests map { test =>
new Group(
name = test.name,
tests = Seq(test),
runPolicy = SubProcess(javaOptions = Seq.empty[String]))
}
// Add the following to the `Project` settings
testGrouping in Test <<= definedTests in Test map singleTests
Using non-deprecated syntax:
testGrouping in Test := (definedTests in Test).value map { test =>
Tests.Group(name = test.name, tests = Seq(test), runPolicy = Tests.SubProcess(
ForkOptions(
javaHome.value,
outputStrategy.value,
Nil,
Some(baseDirectory.value),
javaOptions.value,
connectInput.value,
envVars.value
)))
}
2023 proper syntax:
Test / testGrouping := (Test / definedTests).value map { test =>
Tests.Group(name = test.name, tests = Seq(test), runPolicy = Tests.SubProcess(
ForkOptions(
javaHome = javaHome.value,
outputStrategy = outputStrategy.value,
bootJars = Vector.empty,
workingDirectory = Some(baseDirectory.value),
runJVMOptions = javaOptions.value.toVector,
connectInput = connectInput.value,
envVars = envVars.value
)))

Disabling play.jobs.Job from running while in test mode in play framework

Using play framework 1.2.4 with scala.
I have few play jobs that looks like like
#OnApplicationStart class MyOtherJob extends Job { ... }
#Every("30s") class MyJob extends Job { ... }
These jobs are running while the application is in test mode, so they
mess up things.
How can I disable them from running while testing?
I tried the following application config, didn't help:
# Jobs executor
# ~~~~~~
# Size of the Jobs pool
play.jobs.pool=10
test.play.jobs.pool=0
test.cron.queue.every=never
dev.cron.queue.every=20s
prod.cron.queue.every=20s
test.cron.onApplicationStart.trigger=never
dev.cron.onApplicationStart.trigger=auto
prod.cron.onApplicationStart.trigger=auto
It is possible to check if Play is running in test mode using the following syntax.
play.Play.runingInTestMode()
Note: the spelling mistake is not accidental. That is the method name in the API.
Therefore, in your Jobs, you should be able to wrap the job execution around an IF statement using the above, and therefore, preventing test mode jobs.
EDIT: Ugh, my formatting is off. Will fix in a bit.
We have a nice little wrapper that checks if a job is enabled in a specific environment.
Example entry in application.conf
job.myjob.enabled=true
%test.job.myjob.enabled=false
%prod.job.myjob.enabled=true
and so on.
def ifEnabled(property: String)(runnable: => Unit) =
play.conf.configuration.getProperty(property + ".enabled", "false") match {
case "true" => runnable
case _ => Logger info "Ignoring " + property + " since it's disabled!"
}
Then in your job
class MyJob extends Job {
ifEnabled("job.myJob") {
// code goes here
}
}
This way you don't have to check each individual environment.
if (clazz.isAnnotationPresent(Every.class)) {
try {
Job job = (Job) clazz.newInstance();
scheduledJobs.add(job);
String value = job.getClass().getAnnotation(Every.class).value();
if (value.startsWith("cron.")) {
value = Play.configuration.getProperty(value);
}
value = Expression.evaluate(value, value).toString();
if(!"never".equalsIgnoreCase(value)){
executor.scheduleWithFixedDelay(job, Time.parseDuration(value), Time.parseDuration(value), TimeUnit.SECONDS);
}
so you should define cron.myjob=3min %test.cron.myjob=never and on("cron.myjob")
ex:
cron.SyncWeixinInfo=never
%prod.cron.SyncWeixinInfo=0 0 0 1 * ?
%test.cron.SyncWeixinInfo=0 0 0 1 * ?
%localtest.cron.SyncWeixinInfo=0 0 0 1 * ?
%prodSlave.cron.SyncWeixinInfo=never
#On("cron.SyncWeixinInfo")//每月1号凌晨0点
public class SyncWeixinInfo extends Job {