How to test build.sbt code? - scala

I've got a moderately simple but slightly tricky sbt setup code I want write a few tests for. I would, however, like it to stay in build.sbt.
For the time being I've moved it to an object (in project/), referenced it in the build.sbt as well as in the tests in project/src/test/scala.
But is it possible for code in build.sbt to be tested?

According to the advice in the SBT docs:
The recommended approach is to define most configuration in .sbt files, using .scala files for task implementations or to share values, such as keys, across .sbt files.
So since this sounds like testable code, and not static configuration, your best bet is to leave it in a Scala file.
I'm sure there's a way to manually evaluate the SBT DSL if you really, really want to, but you'll probably have to dig deep into the docs or the SBT source. I can't help you there, though.

Related

Is there a way to list all tests with ScalaTest?

I'm trying to inventory all the tests in a Scala project and I'd prefer to not have to do this manually (there are hundreds) or write a script (I'd hope something already exists). I assume that there must be a way to list all the tests as you can tell ScalaTest or Maven to run all tests in a project so they must be doing some enumeration of tests behind the scenes. The end goal here is to get a list of all tests with their runtimes, to know which are the slow ones to focus on optimizing first (I mention this in case there is a more straightforward way of getting this information, I'd love to know).
If you wish to list down the tests and you have sbt, then the command below will help -
sbt "show test:definedTests"

Does same scala code might produce different bytecodes?

I have a jar file contains scala files which I'd like to version somehow. Sometimes I can use git SHA inserted in METADATA but it's not always the case.
As a "fallback" I thought doing md5 on the bytecodes themselfs (*.class files). For that I'll need to make sure same code given to maven package will produce same bytecode. I found out here that:
Different versions of Scala may produce slightly different bytecode.
which is fine by me, I'm asking if there are more variables involved, mainly time as in jar creation date presented in bytecode somehow.
Thanks!

How do you comment a line in .sbt file

This may sound like a stupid question, but I've been searching all over the internet on how to comment a line in an sbt file. Does anyone know how to?
// creates the comment.
It is rather easy to find.
Edit: An sbt build file uses Scala syntax with some DSL on top of it. As per documentation:
Each Setting is defined with a Scala expression. The expressions in
settings are independent of one another, and they are expressions,
rather than complete Scala statements.
So if you wonder what for instance lazy val root means you should rather search Scala documentation (or SO) for the answer.
On the other hand many "operators" (like +=, :=) are the part of sbt's DSL - they simply methods explained to some degree in the settings section.

Macro project - macro in its own configuration

The SBT documentation about Macro Projects starts with the following:
The current macro implementation in the compiler requires that macro implementations be compiled before they are used. The solution is typically to put the macros in a subproject or in their own configuration.
What does exactly mean to put the macros "in their own configuration"? Does it mean there is an alternative to putting macro source in a subproject? If so, what would that alternative be? I'm looking for an option where I'd not have to separate macro source from invocations, mainly because I don't want yet another subproject for common code.
I believe the author refers to the Configuration scop. In short: you already know that diffrent sources can reside under src/main/scala and src/test/scala, and that code in the test configuration can use code from the compile (main) configuration. so why not having a custom configuration, e.g. macro, and sources for it can reside under src/macro/scala?
there's a great answer on this matter, I suggest you take a look.
also, you could find useful examples here. it's an explanation on defining new configurations for tests. but you could exploit it for your needs.
I don't know what the author meant by own configuration.
An alternative is to use SBT's ability to generate sources (c.f. sourceGenerators) before they get compiled. "Generating" in fact allows you for instance to copy macro source files from elsewhere.
However that's convoluted, so I'd recommend to separate macros in a sub-project. Besides, separating macros still allows you to build even if you switch to an IDE that doesn't support SBT (then you have a macro-defining project and a macro-using project).

Graphing sbt's incremental compilation logic

sbt maintains dependencies between tasks, and the resulting graph can be reasoned about fairly easily. On the other hand, skimming the source code, it seems like the incremental compilation logic is a lot more opaque. I'd like to be able to do the following things:
Say the equivalent of "if I modified this interface [in this way], what would get invalidated?"
Build a graph of how modifying different class interfaces affects the rest of the build. Graphing scala import dependencies isn't a particularly good approximation of this, given how complicated implicit dependencies can get in Scala. It seems like sbt must maintain this information in some form or another to do incremental compilation, so I "just" need to figure out how to access it and hope that it's in a form suitable for my use case.
Are either of these feasible? I'm not opposed to writing sbt plugins, but would appreciate hints about how to proceed.
Edit: it looks like Relation's usesInternalSrc(dep: File): Set[File] could be promising. Does that capture all of sbt's dependency knowledge?
Edit 2: even more promising, there's a DotGraph object inside the sbt source tree. It has no documentation and google doesn't have any human-readable text about it. If I can figure out how to use it I'll post an answer.
Sample console-project session:
> val (s, a) = runTask(compile in Compile, currentState)
> DotGraph.sources(a.relations, file("source-graph"), Nil)
source-graph is a directory that will contain two dot files, one with source dependencies and one with binary. You can alternatively directly interact with a.relations of type Relations, as suggested in the question, and which does capture all of sbt's dependency knowledge. In 0.13 there will also be information about which dependencies are due to inheriting from something in another source file.
In terms of how modifying a source file affects invalidation, it is very coarse grained. Any change to any non-private signature marks a source as changed. In 0.12 and earlier, this will at least invalidate direct dependencies and maybe more. In 0.13, this will invalidate direct dependencies only, except for inherited dependencies, which are transitively invalidated. There is currently no way to see what will be invalidated when a source file's non-private API is modified except by doing it.