diff options
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/java/eu/mulk/aendggner/ZipAuspackerTest.java | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/test/java/eu/mulk/aendggner/ZipAuspackerTest.java b/src/test/java/eu/mulk/aendggner/ZipAuspackerTest.java new file mode 100644 index 0000000..5f0530d --- /dev/null +++ b/src/test/java/eu/mulk/aendggner/ZipAuspackerTest.java @@ -0,0 +1,138 @@ +package eu.mulk.aendggner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import org.junit.jupiter.api.Test; + +/** + * Die Archive werden zur Laufzeit gebaut statt als Binärdatei abgelegt: So steht neben jedem Fall, + * was ihn ausmacht, und der Quellbaum bleibt frei von undurchsichtigen Beilagen. + */ +class ZipAuspackerTest { + + private static final Path MINI_GII = Path.of("src/test/resources/eu/mulk/aendggner/mini-gii.xml"); + + @Test + void packtDenXmlEintragAus() throws Exception { + var xml = Files.readAllBytes(MINI_GII); + var archiv = zip(Map.of("BJNR000000000.xml", xml), ZipEntry.DEFLATED); + + var ausgepackt = ZipAuspacker.auspacken(new Quelle("xml.zip", archiv)); + + assertThat(ausgepackt.inhalt()).isEqualTo(xml); + // Der Name folgt dem Eintrag, nicht der Verpackung: Protokoll und Ladefehler sollen das + // Gesetz benennen. + assertThat(ausgepackt.name()).isEqualTo("BJNR000000000.xml"); + } + + @Test + void packtAuchUnkomprimierteEintraegeAus() throws Exception { + var xml = Files.readAllBytes(MINI_GII); + var archiv = zip(Map.of("BJNR000000000.xml", xml), ZipEntry.STORED); + + assertThat(ZipAuspacker.auspacken(new Quelle("xml.zip", archiv)).inhalt()).isEqualTo(xml); + } + + @Test + void uebergehtBeiwerkNebenDemXml() throws Exception { + var xml = Files.readAllBytes(MINI_GII); + // So sehen die Archive der Gesetze mit Anlagen aus: neben dem Norm-XML liegen Bilddateien. + var eintraege = new LinkedHashMap<String, byte[]>(); + eintraege.put("__MACOSX/", new byte[0]); + eintraege.put("BJNR000000000.xml", xml); + eintraege.put("anlage_1.gif", new byte[] {'G', 'I', 'F', '8'}); + + assertThat(ZipAuspacker.auspacken(new Quelle("xml.zip", zip(eintraege, ZipEntry.DEFLATED)))) + .extracting(Quelle::name) + .isEqualTo("BJNR000000000.xml"); + } + + @Test + void reichtNichtArchiveUnveraendertDurch() throws Exception { + var quelle = new Quelle("stamm.xml", Files.readAllBytes(MINI_GII)); + + assertThat(ZipAuspacker.auspacken(quelle)).isSameAs(quelle); + } + + @Test + void meldetArchivOhneXml() { + var archiv = zip(Map.of("liesmich.txt", "nichts hierin".getBytes(StandardCharsets.UTF_8))); + + assertThatThrownBy(() -> ZipAuspacker.auspacken(new Quelle("xml.zip", archiv))) + .isInstanceOf(IOException.class) + .hasMessageContaining("keine XML-Datei"); + } + + @Test + void meldetArchivMitMehrerenXml() { + var eintraege = new LinkedHashMap<String, byte[]>(); + eintraege.put("eins.xml", "<a/>".getBytes(StandardCharsets.UTF_8)); + eintraege.put("zwei.xml", "<b/>".getBytes(StandardCharsets.UTF_8)); + + assertThatThrownBy(() -> ZipAuspacker.auspacken(new Quelle("xml.zip", zip(eintraege)))) + .isInstanceOf(IOException.class) + .hasMessageContaining("eins.xml, zwei.xml"); + } + + @Test + void meldetBeschaedigtesArchiv() throws Exception { + var archiv = zip(Map.of("BJNR000000000.xml", Files.readAllBytes(MINI_GII))); + // Das Zentralverzeichnis steht am Ende; ein abgeschnittenes Archiv verliert es. + var abgeschnitten = new byte[archiv.length / 2]; + System.arraycopy(archiv, 0, abgeschnitten, 0, abgeschnitten.length); + + assertThatThrownBy(() -> ZipAuspacker.auspacken(new Quelle("xml.zip", abgeschnitten))) + .isInstanceOf(IOException.class) + .hasMessageContaining("beschädigt"); + } + + @Test + void gezipptesStammgesetzErgibtDasselbeGesetz() throws Exception { + var xml = Files.readAllBytes(MINI_GII); + + var direkt = Pipeline.ladeStammgesetz(new Quelle("mini-gii.xml", xml)); + var gezippt = Pipeline.ladeStammgesetz(new Quelle("xml.zip", zip(Map.of("mini-gii.xml", xml)))); + + assertThat(gezippt.normen()).isEqualTo(direkt.normen()); + assertThat(gezippt.jurabk()).isEqualTo(direkt.jurabk()); + } + + private static byte[] zip(Map<String, byte[]> eintraege) { + return zip(eintraege, ZipEntry.DEFLATED); + } + + private static byte[] zip(Map<String, byte[]> eintraege, int verfahren) { + var aus = new ByteArrayOutputStream(); + try (var zip = new ZipOutputStream(aus)) { + for (var eintrag : eintraege.entrySet()) { + var kopf = new ZipEntry(eintrag.getKey()); + kopf.setMethod(verfahren); + if (verfahren == ZipEntry.STORED) { + // Gespeicherte Einträge verlangen Größe und Prüfsumme vorab. + var pruefsumme = new CRC32(); + pruefsumme.update(eintrag.getValue()); + kopf.setSize(eintrag.getValue().length); + kopf.setCompressedSize(eintrag.getValue().length); + kopf.setCrc(pruefsumme.getValue()); + } + zip.putNextEntry(kopf); + zip.write(eintrag.getValue()); + zip.closeEntry(); + } + } catch (IOException e) { + throw new AssertionError("Das Testarchiv ließ sich nicht bauen", e); + } + return aus.toByteArray(); + } +} |
