おがさわらなるひこのオープンソースとかプログラミングとか印刷技術とか

おがさわらなるひこ @naru0ga が技術系で興味を持ったりなんだりしたことをたまーに書くブログです。最近はてなダイアリー放置しすぎて記事書くたびにはてな記法忘れるのではてなブログに移行しました。

クリエイティブ・コモンズ・ライセンス
特に断りがない場合は、本ブログの筆者によるコンテンツは クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンスの下に提供されています。

jOpenDocumentを2021年にリブートしてみる その2: テストを動かす

前回の記事

naruoga.hatenablog.com

のつづき。今回は目標が低くてテストを動かすところまで。 これが全然苦戦して、ほとんど進捗がないんですねえこれが。

テストの位置をMaven標準に動かす

その前に前の記事の落穂ひろいですが、

To compile you need to put iText ( http://www.lowagie.com/iText/download.html ) and junit4 ( http://www.junit.org/ ) into the lib/ dir.

って書いてあるので、iText と Junit4 が必要ですね。ということで pom.xml に次の二つを追加しておいてました。

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.2</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
</dependency>

(なんで最初からlibディレクトリに入ってないんでしょ、再配布制限的な何かあるのかな)

それとこれも前回からの書き漏れですが、 src/product.properties を参照できなくてコケるので src/main/resources に移動しておきました。 ここまでは前回の落穂ひろい。

で、ここからが今回の本題ですが、junit4が必要だよと言ってるってことは当然テストコードがあるわけで、 Maven的には src/test/java 以下にソースがないとたぶんだめですよね。

まあこれはきっと @Test アノテーションがあるファイルはテストコードだと見極めをつけて移動しました。

$ grep -rl "@Test"
src/main/java/org/jopendocument/dom/ODSingleXMLDocumentTest.java
src/main/java/org/jopendocument/dom/OOXMLTest.java
src/main/java/org/jopendocument/util/cache/ICacheTest.java

こいつらをまるっと test に(同名のフォルダを掘って)移動。 すると Intellij IDEA上でテストコードが実行できるようになりました。やった!

で、まあテストはrunできるようになったんですが結果を見ると真っ赤っ赤。 あとはぼちぼちこれを直していけばよかろうと。

リソースの移動

まずはテストコードの中で指定されてる .odt がないとテストコード内でファイルが読めないので移動します。これは簡単。 diff見るとこんな感じですね。

diff --git a/src/main/java/org/jopendocument/dom/empty.odt b/src/test/resources/org/jopendocument/dom/empty.odt
similarity index 100%
rename from src/main/java/org/jopendocument/dom/empty.odt
rename to src/test/resources/org/jopendocument/dom/empty.odt
diff --git a/src/main/java/org/jopendocument/dom/styles.odt b/src/test/resources/org/jopendocument/dom/styles.odt
similarity index 100%
rename from src/main/java/org/jopendocument/dom/styles.odt
rename to src/test/resources/org/jopendocument/dom/styles.odt
diff --git a/src/main/java/org/jopendocument/dom/test.odt b/src/test/resources/org/jopendocument/dom/test.odt
similarity index 100%
rename from src/main/java/org/jopendocument/dom/test.odt
rename to src/test/resources/org/jopendocument/dom/test.odt

で、よく見ると、普通に src/main/java にもいかにもリソースなファイルがあるので移動しとかないとですね。 具体的には src/main/java/org/jopendocument/dom/oofficeDTDs/ にあるやつを丸っと src/main/resources/ 以下に移動します。

ほかにも getResource(AsStream)() で参照されてるファイルを探してはリソースに放り込む日々。

XML関係のテストがそもそも動いてない

これで結構テスト通るようになってきたんですが、問題は、XML関係のテストでスキーマによるバリデーションを試みてるところで落ちてる。 具体的には

private Schema createSchema(final String name) throws SAXException {
    return SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI).newSchema(getClass().getResource("/oofficeDTDs/" + name));
}

こんなコードが、

Caused by: java.util.ServiceConfigurationError: javax.xml.validation.SchemaFactory: org.iso_relax.verifier.jaxp.validation.RELAXNGSchemaFactoryImpl Unable to get public no-arg constructor

こういう例外を吐いて落ちるんですな。

なぬ?スキーマに対する適切なコンストラクタがない? いやいや、XMLConstants.RELAXNG_NS_URIJava標準なんだからそんなわけないだろう……と、Java力(ちから)がないわたくしは考えておりました。

しかし色々調べると「java.xml.validation のデフォルトの実装に含むべきなのはW3Cなソレだけで、それ以外のスキーマを利用したい場合は自分で何とかしなさい」ってことらしいじゃーないですか。おうふ。なるほど……。ここでしばらく停滞、袋小路にハマってました*1

でもよく見るとREADMEにこんな記述がありました。

To validate XML (needed for JUnit tests) you need to download http://java.net/downloads/msv/releases/msv.20090415.zip and put msv.jar, relaxngDatatype.jar, xsdlib.jar and isorelax.jar in the classpath.

いや、だったらなんで最初から入れといてくれないの……というのはともかく、これらをMavenの依存関係に足せばよいのですね。足しましょう。足しました。

<dependency>
    <groupId>msv</groupId>
    <artifactId>msv</artifactId>
    <version>20050913</version>
</dependency>
<dependency>
    <groupId>msv</groupId>
    <artifactId>relaxngDatatype</artifactId>
    <version>20050913</version>
</dependency>
<dependency>
    <groupId>msv</groupId>
    <artifactId>xsdlib</artifactId>
    <version>20050913</version>
</dependency>
<dependency>
    <groupId>msv</groupId>
    <artifactId>isorelax</artifactId>
    <version>20050913</version>
</dependency>

これで行けるだろ!と思ったんですが、いざValidationをしようとするとコケるのです……しくしく。

@Override
public Validator getValidator(final Document doc, final boolean ignoreForeign) {
    final Schema schema;
    try {
        if (doc.getRootElement().getQualifiedName().equals("manifest:manifest"))
            schema = this.getManifestSchema();
        else
            schema = this.getSchema();
    } catch (SAXException e) {
        throw new IllegalStateException("relaxNG schemas pb", e);
    }
    return schema == null ? null : new Validator.JAXPValidator(doc, ignoreForeign ? UNKNOWN_PRED : null, schema);
}

こういうコードで、 this.getSchema() したところで

Caused by: org.xml.sax.SAXParseException; systemId: file:/C:/Users/naruhiko/gosrc/src/github.com/naruoga/jOpenDocument/target/classes/oofficeDTDs/OpenDocument-schema-v1.1.rng; lineNumber: 123; columnNumber: 36; 同名のパターンが既に定義されています。combine属性を使って結合するか、パターン名を"office-meta-content"以外のものに変更してください

って例外が出ちゃうのです(しかし上のコードの "relaxNG schemas pb" ってどういう意味なんだろう。pbってスイスの工具屋さんじゃないよね)。

うーん。わからん。言葉通りだとすると元のスキーマに問題があるっぽく読めるけどスキーマは何にも変えてないしなあ(当たり前)。

office-meta-contentgrepしてみると

 grep -r "\"office-meta-content\""
src/main/resources/oofficeDTDs/OpenDocument-schema-v1.1.rng:            <ref name="office-meta-content"/>
src/main/resources/oofficeDTDs/OpenDocument-schema-v1.1.rng:<define name="office-meta-content">
src/main/resources/oofficeDTDs/OpenDocument-strict-schema-v1.1.rng:        <define name="office-meta-content">

となってるのは確かにそうなんだけど、これがいいのか悪いのか……何も変えてないので悪いってことはないと思うし、そもそもスキーマなんだから標準から引っ張ってきてると思うんで、なにがなんやらさっぱりです。

わからないので後回しにして*2落ちてるほかのテストを調べることにします。次回へ続く。

*1:関係ないけど、そして昔からJavaやってる人なら当たり前すぎることなんですが、RelaxNGについて調べたらJenkinsの創始者で現Launchableの川口さんが出てきて、あー世界はこんな風につながっておるのだなと思いました(?)。

*2:こうやって書いておくと優しい人が誰かSNSで教えてくれたりしないかなとかすかに期待しつつ……。