aboutsummaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/eu/mulk/aendggner/ZipAuspackerTest.java138
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();
+ }
+}