Se ho una macro che tranforms
codice come:Perché l'universo riflettente runtime e l'universo macro creano due alberi diversi per scala.None?
(src: a.b.c.TestEntity) =>
{
z.y.TestTable(None)
}
per abbinare l'Nessuno parte di quella AST posso usare un estrattore come ad esempio:
object NoneExtractor {
def unapply(t: Tree): Boolean = t match {
case Select(Ident(scala), none) if scala.encoded == "scala" && none.encoded == "None" => true
case _ => false
}
}
Come il showRaw
della Nessuno parte della AST assomiglia:
Select(Ident(scala), None)
Eppure, se voglio scrivere uno unit test del NoneExtractor
io non voglio compilare e ricostruire i macro e ospitare il test nel progetto che la macro sta compilando. Voglio unit test l'estrattore nel progetto del macro che suggerisce runtime riflessione è la strada da percorrere con:
val t = reify {
(src: a.b.c.TestEntity) =>
{
z.y.TestTable(None)
}
}.tree
Ma l'albero è totalmente diverso e nel showRaw
di quell'albero l'Nessuno assomiglia:
Ident(scala.None)
Questa è una cattiva notizia per la scrittura di test negativi e il controllo della gestione degli errori della mia macro. Non è possibile scrivere test negativi per una macro utilizzando la macro da un altro progetto poiché il codice non verrà compilato (e non è possibile eseguire il debug del test negativo con errori di compilazione).
Perché le rappresentazioni di qualcosa di fondamentale come None così diverse tra riflessione del tempo di compilazione e riflessione di runtime? C'è un modo per creare i frammenti di albero testabili all'interno del progetto macro, che è lo stesso AST che sarebbe stato consegnato alla macro durante la riflessione del tempo di compilazione?
Scegliere un valore specifico basato sulla sua rappresentazione ad albero è sempre un po 'complicato, anche se sei interamente in macro-terra. Puoi fare qualcosa come 't.tpe =: = typeOf [None.type]' invece? –
Ho davvero bisogno di fare structual match AST con le dichiarazioni di match annidate. Sono nuovo al funzionale quindi ho iniziato con if/then/else/call codice imperativo stile. Quello era circa cinque volte il codice ora che sto rifattando alla corrispondenza funzionale/caso/partita/caso/.... L'api universo macro ha un'enorme quantità di estrattori integrati. Quindi mi rendo conto che gli estrattori e la corrispondenza annidata sono il modo canonico per farlo. La mia domanda è come testare quel modo canonico piuttosto che una domanda su come prendere completamente un approccio diverso. – simbo1905