How to test macro annotations?

287 views
Skip to first unread message

Felix Dietze

unread,
May 31, 2015, 8:48:31 PM5/31/15
to scala...@googlegroups.com
Hi everyone,

I wrote a fairly big macro using macro annotations and would like to write tests for it.
Unit tests as well as Tests where I check the generated AST would be nice.

For Unit tests I would need to mock a Context, which I think is impossible right now.

But testing the generated AST should be possible.

After trying lots of stuff I gave up.

This is my attempt:

I tried to have an sbt subproject in the macro project which should trigger the macro expansion in a toolbox. But when I run
$ sbt "project test" test

I get this error:

[error] scala.tools.reflect.ToolBoxError: reflective compilation has failed:
[error]
[error] macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)


I also tried to pass the paradise plugin as compile option to the toolbox, but without any luck.

How can I test my macro annotation?

thank you!
Felix

Eugene Burmako

unread,
Jun 29, 2015, 10:47:41 AM6/29/15
to scala...@googlegroups.com
There's been some private discussion going on because I forgot to /cc the mailing list. Here's the summary:

A) I suggested to to enable the paradise plugin in the toolbox via "-Xplugin:path/to/plugin -Xplugin-require:macroparadise". The require thingie is useful, because then it'll make the compiler fail if you provide a non-existent path to the paradise plugin, rather than silently ignore that fact. Felix mentioned that it doesn't quite work and linked to https://github.com/renesca/renesca-magic/blob/9af07e4a31daa655d0135718df109f9fb5ab4985/test/src/test/scala/GenerationSpec.scala. Felix, could you make it work in the end? Sorry for neglecting our discussion - first it was the ScalaDays rush and then it slip through cracks...

B) Felix also brought up another issue. When the quasiquote-generated code contains wildcards "_" in the generics, he was getting something like this:

val nodeLabelToFactory = Map[raw.Label, (NodeFactory[_$1] forSome { 
    type _$1 <: Node
  })]();

With every run the type was changing its name "_$1". This is bad, because it prevent comparisons of generated code and reference code. The counter can be reset by restarting the jvm, but that was unsatisfying. The solution that Felix arrived at is illustrated in https://github.com/renesca/renesca-magic/blob/master/test/src/test/scala/GenerationSpec.scala and https://github.com/renesca/renesca-magic/blob/master/test/src/test/scala/TestHelpers.scala

C) Another interesting finding by Felix is that it's actually possible to mock scala.reflect.macros.Context.

trait ContextMock extends Mockito {
  val contextMock: whitebox.Context = {
    import scala.reflect.macros.{Universe => macroUniverse}
    import scala.reflect.runtime.{universe => runtimeUniverse}
    mock[whitebox.Context].universe returns runtimeUniverse.asInstanceOf[macroUniverse]
  }
}

I guess, this might even be enough if we don't query any semantic information (i.e. just construct and deconstruct trees, and not calling things like Tree.tpe or c.typecheck). It's very cool that this simple solution works! To the best of my knowledge, that's the best workaround for the problem of mocking a context.

Felix Dietze

unread,
Jun 29, 2015, 12:00:02 PM6/29/15
to Eugene Burmako, scala...@googlegroups.com

--
You received this message because you are subscribed to a topic in the Google Groups "scala-user" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-user/iYkSAoTdIFM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Eugene Burmako

unread,
Jul 3, 2015, 5:55:57 AM7/3/15
to Felix Dietze, scala-user
A) The problem was in the way how toolbox is implemented internally. After I replaced it with a manual Global (more work, but still could be classified as approachable enough imho), annotations started expanding: https://github.com/renesca/renesca-magic/pull/16.

Felix Dietze

unread,
Jul 11, 2015, 8:37:49 AM7/11/15
to Eugene Burmako, scala-user

Thank you very much, Eugene! Now all our generated code in the tests is automatically compiled with your code.

Reply all
Reply to author
Forward
0 new messages