scalapropsというテストライブラリをscala-native対応させてリリースした

世界初のscala-native用テストライブラリ! といっても過言ではない。*1

github.com

リリースしたのは先週ですが、実装にばかり時間をかけていたら、解説というか経緯などを書いてる暇がなかったので、ようやく今書いているところです。

前提として、scalapropsとscala-nativeについて説明しておくと

  • scalapropsは2年少し前に作って今もメンテしている、自作のproperty based testingのライブラリで (これ参照 Property Based Testing - scalapropsとscalacheckとその他色々 )
  • scala-nativeは、LLVM使うことにより、scalaJVMなしのネイティブで動く、というものです。まだ最初の version 0.1 が出てから半年も経っていない、比較的若いプロジェクトです

以前scalazでの対応については、簡単に書きました

xuwei-k.hatenablog.com

それ以来、scala-native本体に色々細かいpull reqやissue報告したり、対応できそうなライブラリ(自作のmsgpackのやつ、argonautというjsonライブラリ、shapeless)で、いくつか対応させるなどもしています。

github.com

github.com

github.com

ここからscalapropsでの対応させようとした経緯や試行錯誤などをはなしていきます。 scalapropsでのscala-native対応も、ごく初期のscala-native 0.1時点からやろうとしたわけですが、

  • 0.3で、ようやく動くようになったので、対応させてリリースした(イマココ

という状態です。

さて、scala-nativeでは(いくつかリリース後すぐにバグが見つかったものの) 0.3.0 から、sbtのtest-interfaceをサポートしています。

github.com

test-interfaceについては、こちらも参照

xuwei-k.hatenablog.com

しかし、scalapropsでのscala-native対応では、それを直接使っていません。なぜかというと、

  • scala-nativeでは version 0.3 時点ではリフレクションをサポートしていない
  • scalapropsは、 “object内のfield” = “テスト一覧” を、JVMscala-jsではリフレクションで取得する実装になっている
  • 既存のscalapropsのソース互換を保ったまま、かつscala-native 0.3 から提供されたtest-interfaceを使うのは、色々と相性が悪く厳しい

という理由です。結論としては、だいぶscala-native側がやった方法に近いのですが、微妙に違ったかたちで独自にscalapropsのsbt-pluginでコード生成する形式にしました

scala-native · scalaprops/sbt-scalaprops@522ca13 · GitHub

それ以外に考えた選択肢としては

  • scalapropsの「フィールドを定義しただけでテスト定義」というインターフェイスを変える => 大幅にソース互換崩れるので、scala-nativeのためだけにやりたくない
  • コード生成ではなく、コンパイラプラグインで、コンパイル時に “object内のfield” = “テスト一覧” を呼び出せるメソッドを生成する => ソース互換は保てるが、コンパイラプラグインはメンテが大変だしできるだけ避けたい
  • scalametaのマクロアノテーションで “object内のfield” = “テスト一覧” を呼び出せるメソッドを生成 => アノテーション一つとはいえ、それぞれのテストのobjectにつけて回るの面倒

などですが、やめて、完全独自コード生成になってしまいました。とにかくそれ以外も含め何らかのかたちで、scala-native側が用意してくれたtest-interfaceの仕組みを使っておきたい気持ちがあるにはあったのですが、色々考えた末あきらめ、現在はそれらを 完全に独自にscalapropsのsbt pluginが上書きしています

これはこれでわりと邪道感あるので、将来的にリフレクションがscala-nativeでも可能になって、JVMやJSと同じ方式でテストできればいいのですが、今後のscala-nativeの動向や、自分の気分次第なので、どうなるのか不明です。

細かい点では他にも色々書きたいことがなくもないですが、blog書くの疲れるので、このあたりにしておきましょう。 しばらく飽きるまで、もっとscala-native試してバグ見つける、対応可能そうなライブラリへpull reqする、などの貢献続けるつもりです。

scala-nativeやることにより、

  • まだまだ若いプロジェクトなので、わりとバグに頻繁に出会ったり
  • JVMでは例外なのにscala-nativeではセグフォしたり、scala-nativeと比較してscala-jsの完成度の高さすごいなぁ

と思える、といった効果があるので、みなさんも積極的にscala-native試しましょう

*1:maven centralにpublishされているものとしては。scala-native version 0.3.0 時点で、maven centralにはpublishされていないが、scala-native内部のみで使っているとても簡易的なテストライブラリはある