Cobertura に日本語パッチを当てる 1.9.4.1 版

タイトルは coberturaに日本語パッチをあてる - お仕事の備忘録みたいなもの からいただきました。どもすみません。

※ cobertura のテストが幾つか失敗してます。参考程度にどうぞ。
Cobertura が用意しているテストはクリアしたので、まぁまぁ大丈夫だと思います。が、動作の保証まではできません。ごめんなさい。

  • UTF-8 で "(" を含んだ文字列

が入っていると、ant の cobertura-report タスクで以下のようなエラーを吐いて死ぬ。超困る。何とかせねば。

TokenMgrError: Lexical error at line 17, column 38.  Encountered: "\r" (13), after : "\"\u8b41\uff70\u7e3a\u52b1\uff1e\ufffd\ufffd.equals(arg) ) {"
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParserTokenManager.getNextToken(JavaParserTokenManager.java:2078)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_scan_token(JavaParser.java:10181)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_3R_198(JavaParser.java:8524)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_3R_178(JavaParser.java:8924)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_3R_151(JavaParser.java:8901)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_3R_102(JavaParser.java:8960)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_3_25(JavaParser.java:9977)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.jj_2_25(JavaParser.java:5999)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.Expression(JavaParser.java:2762)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.IfStatement(JavaParser.java:4251)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.Statement(JavaParser.java:3816)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.BlockStatement(JavaParser.java:3997)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.Block(JavaParser.java:3947)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.MethodDeclaration(JavaParser.java:2039)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.ClassBodyDeclaration(JavaParser.java:1082)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.ClassBody(JavaParser.java:941)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.UnmodifiedClassDeclaration(JavaParser.java:854)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.ClassDeclaration(JavaParser.java:761)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.TypeDeclaration(JavaParser.java:608)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.CompilationUnit(JavaParser.java:353)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.parser.JavaParser.parse(JavaParser.java:137)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.Javancss._measureSource(Javancss.java:256)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.Javancss._measureRoot(Javancss.java:339)
[cobertura-report] 	at net.sourceforge.cobertura.javancss.Javancss.<init>(Javancss.java:419)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.ComplexityCalculator.getAccumlatedCCNForSource(ComplexityCalculator.java:104)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.ComplexityCalculator.getAccumlatedCCNForSingleFile(ComplexityCalculator.java:141)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.ComplexityCalculator.getCCNForSourceFileNameInternal(ComplexityCalculator.java:226)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.ComplexityCalculator.getCCNForPackageInternal(ComplexityCalculator.java:196)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.ComplexityCalculator.getCCNForProject(ComplexityCalculator.java:166)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.html.HTMLReport.generateTableRowForTotal(HTMLReport.java:704)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.html.HTMLReport.generateOverview(HTMLReport.java:336)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.html.HTMLReport.generateOverviews(HTMLReport.java:271)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.html.HTMLReport.<init>(HTMLReport.java:96)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.Main.parseArguments(Main.java:107)
[cobertura-report] 	at net.sourceforge.cobertura.reporting.Main.main(Main.java:176)
[cobertura-report] WARN   getAccumlatedCCNForSource, JavaNCSS got an error while parsing the java file D:\Development\_Projects\cobertura-test\.\src\local\my\project\HelloWorld.java
[cobertura-report] TokenMgrError in STDIN
[cobertura-report] Lexical error at line 17, column 38.  Encountered: "\r" (13), after : "\"\u8b41\uff70\u7e3a\u52b1\uff1e\ufffd\ufffd.equals(arg) ) {"

調査

Cobertura をビルドできるようにする
> ant jar

で JAR作成してくれる。

やばそうなところを見つける

スタックトレースから追いかけるだけの簡単なお仕事。
最初は net.sourceforge.cobertura.javancss.parser.JavaParserTokenManager.getNextToken
辺りを見ていたんだけど、さっぱり分からないので、呼び出し元を見ながら分かりそうなところまで行ってみる。

で、分かったこと。

            private Complexity getAccumlatedCCNForSource(String sourceFileName,
                    Source source) {
                if (source == null) {
                    return ZERO_COMPLEXITY;
                }
                if (!sourceFileName.endsWith(".java")) {
                    return ZERO_COMPLEXITY;
                }
                Javancss javancss = new Javancss(source.getInputStream()); /* ここだ! */

コードを修正する

Ant の cobertura-report タスクにある encoding プロパティ?を使えるように修正してみる。

net.sourceforge.cobertura.reporting.Main.java
103:   ComplexityCalculator complexity = new ComplexityCalculator(finder);
104:    complexity.setEncoding(encoding);
net.sourceforge.cobertura.reporting.ComplexityCalculator
 67:    private Map packageCNNCache = new HashMap();
 68:    
 69:    private String encoding;
 95:    private Complexity getAccumlatedCCNForSource(String sourceFileName, Source source) {
 96:    if (source == null)
 97:    {
 98:        return ZERO_COMPLEXITY;
 99:    }
100:    if (!sourceFileName.endsWith(".java"))
101:    {
102:        return ZERO_COMPLEXITY;
103:    }
104:    Javancss javancss = new Javancss(source.getInputStream(), encoding);
245:    public void setEncoding(String encoding) {
246:        this.encoding = encoding;
247:    }
net.sourceforge.cobertura.javancss.Javancss
413:    public Javancss(InputStream isJavaSource_, String encoding) {
414:        Util.debug( "Javancss.(InputStream).sJavaSourceFile_: " + isJavaSource_ );
415:        _sErrorMessage = null;
416:        _vJavaSourceFiles = null;
417:        this.encoding = encoding;

ビルドして実験

無事カバレッジが作成された!!
気の迷いかもしれないので、ソースを元に戻して再度挑戦。大丈夫そう。

テストを通す

せっかく作ってくれているテストは通しておきたい…。

> ant

net.sourceforge.cobertura.test.SwitchFunctionalTest のテストが1つこけるけども、これは修正前もこけてたのでよしとする。