coberturaに日本語パッチをあてる

以前の日記でコードカバレッジで、djUnitを使用するように書きましたが、
Antから実行するのがどうにも厄介そう*1なので、急遽jcoverageの後継であるcoberturaを使用するように変更しました。

しかし、このツールも他のツールと同様、お米の国の方が作成したツール同様マルチバイト文字に関する扱いはぞんざいで、UTF-8以外の文字コードを使用したコードの場合は見事に文字化けさせてくれちゃいます。*2

最初は、まぁいいやとも思ってたのですが、若干客先対応で時間が空いたのでパッチをあててみました。
ベースとなるバージョンは現時点で最新の1.9を利用します。

なお、パッチ適用済みのcobertura.jarはこちらから入手可能です。
coberturaは、GPLライセンスでの提供ですので、公開したソースに対しても当然動作保障はしませんのであしからず。
ただし、質問は受け付けますので、本日記にコメントでも入れてくださいな。


通常antから、coberturaのレポートを作成する場合は、


と記述するのですが、

<cobertura-report srcdir="..." destdir="..." sourceEncoding="..." />

と書けば、その文字コードソースコードを読み込むようにします。

net.sourceforge.cobertura.ant.ReportTask

085:    public void execute() throws BuildException {
086:        CommandLineBuilder builder = null;
087:        try {
088:            builder = new CommandLineBuilder();
089:            if (dataFile != null)
090:                builder.addArg("--datafile", dataFile);
091:            if (destDir != null)
092:                builder.addArg("--destination", destDir.getAbsolutePath());
093:            if (format != null)
094:                builder.addArg("--format", format);
095:            if(sourceEncoding != null)            //(2)
096:                builder.addArg("--sourceEncoding", sourceEncoding);
097:            if (srcDir != null)
098:                builder.addArg(srcDir);
099:   
:
:
どっか適当な位置に。。。
        private String sourceEncoding = "UTF-8";      //(1)
        public void setSourceEncoding(String sourceEncoding) {
            this.sourceEncoding = sourceEncoding;
        }
  1. Antのタスクに属性を増やしたので、そのセッターメソッドと対応プロパティを追加。デフォルト動作は変えたくないので、省略時は「UTF-8」とする。
  2. レポート生成のスタートクラス(net.sourceforge.cobertura.reporting.Main)へのコマンドライン引数にsourceEncodingを渡すようにする。多分nullの事は無いと思うけどとりあえずnullチェックもしてる

net.sourceforge.cobertura.reporting.Main

047:    private void parseArguments(String[] args) throws Exception {
048:        FileFinder finder = new FileFinder();
049:        String baseDir = null;
050:        String sourceEncoding = "UTF-8";    //(1)
051:        for (int i = 0; i < args.length; i++) {
052:            if (args[i].equals("--basedir")) {
053:                baseDir = args[++i];
054:            } else if (args[i].equals("--sourceEncoding")) {
055:                sourceEncoding = args[++i];                             //(2)
056:            } else if (args[i].equals("--datafile")) {
:
102:        if (format.equalsIgnoreCase("html")) {
103:            new HTMLReport(projectData, destinationDir, finder, complexity, sourceEncoding);    //(3)
104:        } else if (format.equalsIgnoreCase("xml")) {
105:            //TODO XMLの方は未対応    //(4)
106:            new XMLReport(projectData, destinationDir, finder, complexity);
107:        }
:
  1. コマンドライン引数として渡された文字コード名を保持する変数定義。ここも従来の動作を維持するため、デフォルトは「UTF-8
  2. コマンドライン引数として渡された文字コードを変数にセットする
  3. HTMLのレポートを作成するジェネレーターに文字コード名を引き渡す
  4. 読んで字のごとく!!

net.sourceforge.cobertura.reporting.html.HTMLReport

074:    private String sourceEncoding = "UTF-8";    //(1)
:
079:    public HTMLReport(ProjectData projectData, File outputDir,
080:            FileFinder finder, ComplexityCalculator complexity, String sourceEncoding)
081:            throws Exception                                                //(2)
082:    {
083:        this.destinationDir = outputDir;
084:        this.finder = finder;
085:        this.complexity = complexity;
086:        this.projectData = projectData;
087:        this.sourceEncoding = sourceEncoding;                              //(3)
:
540:    private String generateHtmlizedJavaSource(SourceFileData sourceFileData)
:
553:        BufferedReader br = null;
554:        try
555:        {
556:            br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile), this.sourceEncoding));//(4)
557:        }
558:        catch (UnsupportedEncodingException e)
559:        {
560:            return "<p>Unable to open " + sourceFile.getAbsolutePath()
561:                  + ": The encoding '"+ this.sourceEncoding + "' is not supported by your JVM.</p>";    //(5)
562:        }
:
  1. 例によって文字コードを退避するメンバ変数の定義
  2. 引数を当然のごとく増やす
  3. そして、当然退避する
  4. オブジェクト生成時に渡された文字コードでBufferedReaderを生成する。元のコードは「UTF-8」とべたに書いてある
  5. エラーメッセージも一応直しておいた。元のコードは当然「UTF-8」と直書きされている

これだけで、対応可能でした。思ったより楽チンでよかった。

*1:内部で使用しているjcoverageがオープンソースではなくなったっぽい

*2:それでも、AntのJUnitレポートよりはまし、なんせXSLTにもろ「US-ASCII」って書いてあるし^^;