Anonymous avatar Anonymous committed e3cf842

Added unit tests for ARC, WARC and GZip modules. Minor bug fixes also included.

Comments (0)

Files changed (191)

config/spring/module/format/warc/jhove2-warc-config.xml

     <constructor-arg type="java.lang.String" value="http://jhove2.org/terms/format/warc"/>
   </bean>
 
-  <!-- ARC PUID x-fmt/219 alias identifier bean -->
+  <!-- WARC PUID x-fmt/289 alias identifier bean -->
   <bean id="WarcXFmt219Identifier" class="org.jhove2.core.I8R" scope="singleton">
     <constructor-arg type="java.lang.String" value="fmt/289"/>
     <constructor-arg type="org.jhove2.core.I8R$Namespace" value="PUID"/>

src/main/java/org/jhove2/module/format/arc/ArcModule.java

 import org.jwat.arc.ArcReaderFactory;
 import org.jwat.arc.ArcRecordBase;
 import org.jwat.common.Diagnosis;
+import org.jwat.common.Diagnostics;
 import org.jwat.common.HttpHeader;
+import org.jwat.common.InputStreamNoSkip;
 import org.jwat.common.Payload;
 import org.jwat.common.PayloadWithHeaderAbstract;
 
       this(null, null);
     }
 
+    /**
+     * Method for creating test instances.
+     * @return <code>ArcModule</code> instance
+     */
+    protected ArcModule getTestInstance() {
+        ArcModule arcModule = new ArcModule(format, (FormatModuleAccessor)moduleAccessor);
+        arcModule.isValid = Validity.Undetermined;
+        arcModule.recurse = recurse;
+        arcModule.bComputeBlockDigest = bComputeBlockDigest;
+        arcModule.blockDigestAlgorithm = blockDigestAlgorithm;
+        arcModule.blockDigestEncoding = blockDigestEncoding;
+        arcModule.bComputePayloadDigest = bComputePayloadDigest;
+        arcModule.payloadDigestAlgorithm = payloadDigestAlgorithm;
+        arcModule.payloadDigestEncoding = payloadDigestEncoding;
+        return arcModule;
+    }
+
     //------------------------------------------------------------------------
     // BaseFormatModule contract support
     //------------------------------------------------------------------------
                 // Remove ArcModule from source instance since we added one to the parent source.
 //                this.setParentSourceId(null);
                 this.getParentSource().deleteModule(this);
+                // Reader diagnostics.
+                reportValidationErrors(source, reader.diagnostics, jhove2);
+                reader.diagnostics.reset();
+                // Source update.
                 source = source.getSourceAccessor().persistSource(source);
             }
             consumed = reader.getConsumed();
             /*
              * Not GZip compressed.
              */
-            reader = ArcReaderFactory.getReaderUncompressed(source.getInputStream(), 8192);
+            reader = ArcReaderFactory.getReaderUncompressed(new InputStreamNoSkip(source.getInputStream()), 8192);
             setDigestOptions(reader);
             parseRecordsUncompressed(jhove2, sourceFactory, source, reader, true);
             reader.close();
             consumed = reader.getConsumed();
+            // Reader diagnostics.
+            reportValidationErrors(source, reader.diagnostics, jhove2);
+            reader.diagnostics.reset();
             // Reportable.
             arcReaderConsumedBytes = reader.getConsumed();
             if (blockDescVersions.size() == 1) {
                 	arcBlockDescVersion = entry.getKey();
                 }
             }
+
             /*
              * Validity.
              */
          */
         if (recordNumber == 1) {
         	if (record.recordType == ArcRecordBase.RT_VERSION_BLOCK) {
-        		if (record.versionHeader.bValidVersionFormat) {
+        		if (record.versionHeader != null && record.versionHeader.bValidVersionFormat) {
         			arcFileVersion = record.versionHeader.versionStr;
         		}
         	}
         /*
          * Report errors.
          */
-        reportValidationErrors(recordSrc, record, jhove2);
+        reportValidationErrors(recordSrc, record.diagnostics, jhove2);
         recordSrc.close();
     }
 
     }
 
     /**
-     * Checks ARC record validity and reports validation errors.
+     * Reports validation errors/warnings on <code>Source</code>, if any.
      * @param src ARC source unit
-     * @param record the ARC record to characterize.
+     * @param diagnostics diagnostics object with possible errors/warnings.
      * @param jhove2 the JHove2 characterization context.
      * @throws IOException if an IO error occurs while processing
      * @throws JHOVE2Exception if a serious problem needs to be reported
      */
-    private void reportValidationErrors(Source src, ArcRecordBase record,
+    private void reportValidationErrors(Source src, Diagnostics<Diagnosis> diagnostics,
                         JHOVE2 jhove2) throws JHOVE2Exception, IOException {
-        if (record.diagnostics.hasErrors()) {
+        if (diagnostics.hasErrors()) {
             // Report errors on source object.
-           for (Diagnosis d : record.diagnostics.getErrors()) {
+           for (Diagnosis d : diagnostics.getErrors()) {
                src.addMessage(newValidityError(jhove2, Message.Severity.ERROR,
                        d.type.toString().toLowerCase(), d.getMessageArgs()));
                //updateMap(e.error.toString() + '-' + e.field, this.errors);
            }
         }
-        if (record.diagnostics.hasWarnings()) {
+        if (diagnostics.hasWarnings()) {
             // Report warnings on source object.
-            for (Diagnosis d : record.diagnostics.getWarnings()) {
+            for (Diagnosis d : diagnostics.getWarnings()) {
                 src.addMessage(newValidityError(jhove2, Message.Severity.WARNING,
                         d.type.toString().toLowerCase(), d.getMessageArgs()));
             }

src/main/java/org/jhove2/module/format/arc/ArcRecordSource.java

 
 import org.jhove2.core.JHOVE2;
 import org.jhove2.core.source.AbstractSource;
+import org.jhove2.core.source.Source;
 
 import com.sleepycat.persist.model.Persistent;
 
         super(jhove2);
     }
 
+	@Override
+	public int compareTo(Source src) {
+		if (src == null ){
+			return 1;
+		}
+		if (this == src) {
+			return 0;
+		}
+		return this.toString().compareTo(src.toString());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == null) {
+			return false;
+		}
+		if (obj == this) {
+			return true;
+		}
+		return false;
+	}
+
 }

src/main/java/org/jhove2/module/format/arc/properties/ArcRecordData.java

         switch (record.recordType) {
         case ArcRecordBase.RT_VERSION_BLOCK:
         	ArcVersionHeader versionHeader = record.versionHeader;
-            if (versionHeader.versionNumber != null) {
-                versionNumber = versionHeader.versionNumberStr;
-            }
-            if (versionHeader.reserved != null) {
-                reserved = versionHeader.reservedStr;
-            }
-            originCode = versionHeader.originCode;
+        	if (versionHeader != null) {
+                if (versionHeader.versionNumber != null) {
+                    versionNumber = versionHeader.versionNumberStr;
+                }
+                if (versionHeader.reserved != null) {
+                    reserved = versionHeader.reservedStr;
+                }
+                originCode = versionHeader.originCode;
+        	}
         	break;
         case ArcRecordBase.RT_ARC_RECORD:
             Payload payload = record.getPayload();

src/main/java/org/jhove2/module/format/gzip/GzipModule.java

 import java.util.LinkedList;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.zip.DataFormatException;
 
 import org.jhove2.annotation.ReportableProperty;
 import org.jhove2.core.JHOVE2;
 import org.jhove2.persist.FormatModuleAccessor;
 import org.jwat.arc.ArcReader;
 import org.jwat.common.Diagnosis;
+import org.jwat.common.Diagnostics;
 import org.jwat.gzip.GzipConstants;
 import org.jwat.gzip.GzipEntry;
 import org.jwat.gzip.GzipReader;
         this(null, null);
     }
 
+    /**
+     * Method for creating test instances.
+     * @return <code>GzipModule</code> instance
+     */
+    protected GzipModule getTestInstance() {
+        GzipModule gzipModule = new GzipModule(format, (FormatModuleAccessor)moduleAccessor);
+        gzipModule.isValid = Validity.Undetermined;
+        gzipModule.recurse = recurse;
+        return gzipModule;
+    }
+
     //------------------------------------------------------------------------
     // BaseFormatModule contract support
     //------------------------------------------------------------------------
                     ++invalidMembers;
                     isValid = Validity.False;
                     // Report errors on child source object.
-                    reportValidationErrors(gzipEntry, src, jhove2);
+                    reportValidationErrors(src, gzipEntry.diagnostics, jhove2);
                 }
             }
+            // Report reader errors on source object.
+            reportValidationErrors(source, gzipReader.diagnostics, jhove2);
+        	if (!gzipReader.isCompliant()) {
+                isValid = Validity.False;
+        	}
             consumed = gzipReader.getConsumed();
             gzipReaderConsumedBytes = gzipReader.getConsumed();
             if (isValid == Validity.Undetermined) {
         }
         catch (IOException e) {
             handleError(e, jhove2, gzipEntry.getStartOffset());
-            if (! ((e instanceof EOFException) && (gzipEntry.getStartOffset() != 0L))) {
+            if (e.getCause() != null && e.getCause() instanceof DataFormatException) {
+            	isValid = Validity.False;
+                source.addMessage(newValidityError(jhove2, Message.Severity.ERROR,
+                        "error", new Object[]{"GZip data", e.getMessage()}));
+            }
+            else if (! ((e instanceof EOFException) && (gzipEntry.getStartOffset() != 0L))) {
                 // Not an EOF error occurring before the very first entry.
                 throw e;
             }
      * @throws IOException if an IO error occurs while processing
      * @throws JHOVE2Exception if a serious problem needs to be reported
      */
-    private void reportValidationErrors(GzipEntry entry, Source src,
+    private void reportValidationErrors(Source src, Diagnostics<Diagnosis> diagnostics,
                                         JHOVE2 jhove2) throws JHOVE2Exception {
-        if (entry.diagnostics.hasErrors()) {
+        if (diagnostics.hasErrors()) {
             // Report errors on source object.
-           for (Diagnosis d : entry.diagnostics.getErrors()) {
+           for (Diagnosis d : diagnostics.getErrors()) {
                src.addMessage(newValidityError(jhove2, Message.Severity.ERROR,
                        d.type.toString().toLowerCase(), d.getMessageArgs()));
            }
         }
-        if (entry.diagnostics.hasWarnings()) {
+        if (diagnostics.hasWarnings()) {
             // Report warnings on source object.
-            for (Diagnosis d : entry.diagnostics.getWarnings()) {
+            for (Diagnosis d : diagnostics.getWarnings()) {
                 src.addMessage(newValidityError(jhove2, Message.Severity.WARNING,
                         d.type.toString().toLowerCase(), d.getMessageArgs()));
             }

src/main/java/org/jhove2/module/format/warc/WarcModule.java

 import org.jhove2.module.format.warc.properties.WarcRecordData;
 import org.jhove2.persist.FormatModuleAccessor;
 import org.jwat.common.Diagnosis;
+import org.jwat.common.Diagnostics;
 import org.jwat.common.HttpHeader;
+import org.jwat.common.InputStreamNoSkip;
 import org.jwat.common.Payload;
 import org.jwat.common.PayloadWithHeaderAbstract;
 import org.jwat.warc.WarcReader;
         this(null, null);
     }
 
+    /**
+     * Method for creating test instances.
+     * @return <code>WarcModule</code> instance
+     */
+    protected WarcModule getTestInstance() {
+        WarcModule warcModule = new WarcModule(format, (FormatModuleAccessor)moduleAccessor);
+        warcModule.isValid = Validity.Undetermined;
+        warcModule.recurse = recurse;
+        warcModule.bComputeBlockDigest = bComputeBlockDigest;
+        warcModule.blockDigestAlgorithm = blockDigestAlgorithm;
+        warcModule.blockDigestEncoding = blockDigestEncoding;
+        warcModule.bComputePayloadDigest = bComputePayloadDigest;
+        warcModule.payloadDigestAlgorithm = payloadDigestAlgorithm;
+        warcModule.payloadDigestEncoding = payloadDigestEncoding;
+        return warcModule;
+    }
+
     //------------------------------------------------------------------------
     // BaseFormatModule contract support
     //------------------------------------------------------------------------
                 // Remove WarcModule from source instance since we added one to the parent source.
 //                this.setParentSourceId(null);
                 this.getParentSource().deleteModule(this);
+                // Reader diagnostics.
+                reportValidationErrors(source, reader.diagnostics, jhove2);
+                reader.diagnostics.reset();
+                // Source update.
                 source = source.getSourceAccessor().persistSource(source);
             }
             consumed = reader.getConsumed();
             /*
              * Not GZip compressed.
              */
-            reader = WarcReaderFactory.getReaderUncompressed(source.getInputStream(), 8192);
+            reader = WarcReaderFactory.getReaderUncompressed(new InputStreamNoSkip(source.getInputStream()), 8192);
             setDigestOptions(reader);
             parseRecordsUncompressed(jhove2, sourceFactory, source, reader);
             reader.close();
             consumed = reader.getConsumed();
+            // Reader diagnostics.
+            reportValidationErrors(source, reader.diagnostics, jhove2);
+            reader.diagnostics.reset();
             // Reportable.
             warcReaderConsumedBytes = reader.getConsumed();
             if (versions.size() == 1) {
         /*
          * Report errors.
          */
-        reportValidationErrors(recordSrc, record, jhove2);
+        reportValidationErrors(recordSrc, record.diagnostics, jhove2);
     }
 
     /**
     }
 
     /**
-     * Checks WARC record validity and reports validation errors.
+     * Reports validation errors/warnings on <code>Source</code>, if any.
      * @param src WARC source unit
-     * @param record the WARC record to characterize.
+     * @param diagnostics diagnostics object with possible errors/warnings.
      * @param jhove2 the JHove2 characterization context.
      * @throws IOException if an IO error occurs while processing
      * @throws JHOVE2Exception if a serious problem needs to be reported
      */
-    private void reportValidationErrors(Source src, WarcRecord record,
+    private void reportValidationErrors(Source src, Diagnostics<Diagnosis> diagnostics,
                         JHOVE2 jhove2) throws JHOVE2Exception, IOException {
-        if (record.diagnostics.hasErrors()) {
+        if (diagnostics.hasErrors()) {
             // Report errors on source object.
-           for (Diagnosis d : record.diagnostics.getErrors()) {
+           for (Diagnosis d : diagnostics.getErrors()) {
                src.addMessage(newValidityError(jhove2, Message.Severity.ERROR,
                        d.type.toString().toLowerCase(), d.getMessageArgs()));
                //updateMap(e.error.toString() + '-' + e.field, this.errors);
            }
         }
-        if (record.diagnostics.hasWarnings()) {
+        if (diagnostics.hasWarnings()) {
             // Report warnings on source object.
-            for (Diagnosis d : record.diagnostics.getWarnings()) {
+            for (Diagnosis d : diagnostics.getWarnings()) {
                 src.addMessage(newValidityError(jhove2, Message.Severity.WARNING,
                         d.type.toString().toLowerCase(), d.getMessageArgs()));
             }

src/main/java/org/jhove2/module/format/warc/WarcRecordSource.java

 
 import org.jhove2.core.JHOVE2;
 import org.jhove2.core.source.AbstractSource;
+import org.jhove2.core.source.Source;
 
 import com.sleepycat.persist.model.Persistent;
 
         super(jhove2);
     }
 
+	@Override
+	public int compareTo(Source src) {
+		if (src == null ){
+			return 1;
+		}
+		if (this == src) {
+			return 0;
+		}
+		return this.toString().compareTo(src.toString());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == null) {
+			return false;
+		}
+		if (obj == this) {
+			return true;
+		}
+		return false;
+	}
+
 }

src/test/java/org/jhove2/module/format/arc/ArcHeaderTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcHeaderTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-archeader-1.arc", new String[][] {
+			}, new String[] {
+					"[ERROR/OBJECT] Invalid Empty lines before ARC record",
+					"[ERROR/OBJECT] Error in ARC file, expected 'One or more records'"
+			}},
+			{Validity.False, "invalid-archeader-2.arc", new String[][] {
+			}, new String[] {
+					"[ERROR/OBJECT] Invalid Data before ARC record",
+					"[ERROR/OBJECT] Error in ARC file, expected 'One or more records'"
+			}},
+			{Validity.False, "invalid-archeader-3.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Required 'URL' value is missing",
+						"[ERROR/OBJECT] Required 'IP-address' value is missing",
+						"[ERROR/OBJECT] Required 'Archive-date' value is missing",
+						"[ERROR/OBJECT] Required 'Content-type' value is missing",
+						"[ERROR/OBJECT] Required 'Result-code' value is missing",
+						"[ERROR/OBJECT] Required 'Offset' value is missing",
+						"[ERROR/OBJECT] Required 'Filename' value is missing",
+						"[ERROR/OBJECT] Required 'Archive-length' value is missing",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-archeader-4.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'URL' value, value: '4270', expected: 'Absolute URI'",
+						"[ERROR/OBJECT] Invalid 'IP-address' value, value: 'http://cctr.umkc.edu:80/user/jbenz/tst.htm', expected: 'IPv4 or IPv6 format'",
+						"[ERROR/OBJECT] Invalid 'Archive-date' value, value: '134.193.4.1', expected: 'yyyyMMddHHmmss'",
+						"[ERROR/OBJECT] Invalid 'Content-type' value, value: '19970417175710', expected: '<type>/<sub-type>(; <argument>=<value>)*'",
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: 'text/html', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-archeader-5.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'URL' value, value: '40', expected: 'Absolute URI'",
+						"[ERROR/OBJECT] Invalid 'IP-address' value, value: 'http://www.antiaction.com/', expected: 'IPv4 or IPv6 format'",
+						"[ERROR/OBJECT] Invalid 'Archive-date' value, value: '192.168.1.2', expected: 'yyyyMMddHHmmss'",
+						"[ERROR/OBJECT] Invalid 'Content-type' value, value: '20120712144000', expected: '<type>/<sub-type>(; <argument>=<value>)*'",
+						"[ERROR/OBJECT] Invalid 'Result-code' value, value: 'text/htlm', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid 'Offset' value, value: 'location', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: 'filename', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-archeader-6.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Result-code' value, value: '99', expected: 'A number between 100 and 999'",
+						"[ERROR/OBJECT] Invalid 'Offset' value, value: '-4321', expected: 'A non negative number'",
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: '-42', expected: 'A non negative number'",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-archeader-7.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Result-code' value, value: '1000', expected: 'A number between 100 and 999'",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'",
+						"[ERROR/OBJECT] Invalid Payload length mismatch, 'Payload truncated'"
+					}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-archeader-1.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-archeader-2.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-archeader-3.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}}
+	};
+
+	@Test
+	public void test_archeaders() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/arc/ArcModuleTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcModuleTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-empty.arc", new String[][] {
+			}, new String[] {
+					"[ERROR/OBJECT] Error in ARC file, expected 'One or more records'"
+			}}
+	};
+
+	@Test
+	public void test_archeaders() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/arc/ArcModuleTestBase.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.jhove2.ConfigTestBase;
+import org.jhove2.app.util.FeatureConfigurationUtil;
+import org.jhove2.core.JHOVE2;
+import org.jhove2.core.JHOVE2Exception;
+import org.jhove2.core.Message;
+import org.jhove2.core.io.Input;
+import org.jhove2.core.source.FileSource;
+import org.jhove2.core.source.Source;
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+		"classpath*:**/arc-test-config.xml",
+		"classpath*:**/persist-test-config.xml",
+        "classpath*:**/test-config.xml",
+        "classpath*:**/filepaths-config.xml" })
+public class ArcModuleTestBase extends ConfigTestBase {
+
+    protected JHOVE2 JHOVE2;
+
+    protected String arcDirBasePath;
+
+	protected ArcModule arcModuleMold;
+
+	@BeforeClass 
+	public static void setUpBeforeClass() throws Exception {
+    	ArrayList<String> paths = new ArrayList<String>();
+    	paths.add("classpath*:**/arc-test-config.xml");
+    	paths.add("classpath*:**/persist-test-config.xml");
+    	paths.add("classpath*:**/test-config.xml");
+    	ConfigTestBase.setCONTEXT_PATHS(paths);
+    	ConfigTestBase.setUpBeforeClass();
+    }
+
+    public JHOVE2 getJHOVE2() {
+        return JHOVE2;
+    }
+
+    @Resource
+    public void setJHOVE2(JHOVE2 jHOVE2) {
+        JHOVE2 = jHOVE2;
+    }
+
+    public String getArcDirBasePath() {
+        return arcDirBasePath;
+    }
+
+    @Resource
+    public void setArcDirBasePath(String arcDirBasePath) {
+        this.arcDirBasePath = arcDirBasePath;
+    }
+
+    public ArcModule getArcModule() {
+    	return arcModuleMold;
+    }
+
+    @Resource(name = "ArcModule")
+    public void setArcModule(ArcModule arcModule) {
+    	this.arcModuleMold = arcModule;
+    }
+
+    /**
+     * Test method for ARC Declaration information
+     */
+    @Test
+    public void testTruth() {
+        assertTrue(true);
+    }
+
+    public void test_cases(Object[][] cases, boolean debug) {
+        String arcExampleDirPath = null;
+        // debug
+        //System.out.println("arcDirBasePath: " + arcDirBasePath);
+        try {
+            arcExampleDirPath = FeatureConfigurationUtil
+                    .getFilePathFromClasspath(arcDirBasePath,
+                            "ARC examples base directory");
+        }
+        catch (JHOVE2Exception e) {
+            fail("Could not create base directory");
+        }
+        File arcExampleDir = new File(arcExampleDirPath);
+        // debug
+        //System.out.println(arcExampleDir.getPath());
+        assertTrue("Directory does not exist: " + arcExampleDir.getPath(), arcExampleDir.exists());
+
+    	ArcModule arcModule;
+    	long consumed;
+    	Validity validity;
+
+    	for (int i=0; i<cases.length; ++i) {
+        	Validity expectedValidity = (Validity)cases[i][0];
+        	String testFilename = (String)cases[i][1];
+        	String[][] expectedRecordMessages = (String[][])cases[i][2];
+        	String[] expectedReaderMessages = (String[])cases[i][3];
+
+        	File testFile = new File(arcExampleDirPath, testFilename);
+            //System.out.println(testFile.getPath());
+            assertTrue("File does not exist: " + testFile.getPath(), testFile.exists());
+            try {
+                FileSource fileSource = (FileSource)JHOVE2.getSourceFactory().getSource(JHOVE2, testFile);
+    			Input input = fileSource.getInput(JHOVE2);
+            	arcModule = arcModuleMold.getTestInstance();
+    			consumed = arcModule.parse(JHOVE2, fileSource, input);
+    			validity = arcModule.validate(JHOVE2, fileSource, input);
+
+    			/*
+    			System.out.println(" " + testFilename);
+    			System.out.println(" " + consumed);
+    			System.out.println(" " + validity.toString());
+    			*/
+
+    			Assert.assertEquals(expectedValidity, validity);
+
+    			List<Message> messages = fileSource.getMessages();
+    			Assert.assertEquals(expectedReaderMessages.length, messages.size());
+
+    			for (int j=0; j<messages.size(); ++j) {
+    				//System.out.println(" " + messages.get(j));
+    				Assert.assertEquals(expectedReaderMessages[j], messages.get(j).toString());
+    			}
+
+    			List<Source> children = fileSource.getChildSources();
+    			Assert.assertEquals(expectedRecordMessages.length, children.size());
+
+    			for (int j=0; j<children.size(); ++j) {
+    				messages = children.get(j).getMessages();
+    				Assert.assertEquals(expectedRecordMessages[j].length, messages.size());
+
+    				//System.out.println(" >" + j);
+    				for (int k=0; k<messages.size(); ++k) {
+        				//System.out.println("  " + messages.get(k));
+        				Assert.assertEquals(expectedRecordMessages[j][k], messages.get(k).toString());
+        			}
+    			}
+            }
+            catch (Exception e) {
+                fail("Exception thrown: " + e.getMessage());
+            }        
+        }
+    }
+
+}

src/test/java/org/jhove2/module/format/arc/ArcRecordBaseTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcRecordBaseTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-arcrecordbase-1.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'text/htlm', expected: 'text/plain'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecordbase-2.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'text/htlm', expected: 'text/plain'"
+					},
+					{
+						"[ERROR/OBJECT] Invalid 'Offset' value, value: '2', expected: '251'",
+						"[ERROR/OBJECT] Invalid Payload length mismatch, 'Payload truncated'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecordbase-3.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					},
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected an ARC record not version block.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecordbase-4.arc", new String[][] {
+					{},
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected an ARC record not version block.'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecordbase-5.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected a version block as the first record.'"
+					},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecordbase-1.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}}
+	};
+
+	@Test
+	public void test_arcrecordbase() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/arc/ArcRecordTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcRecordTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-arcrecord-1.arc", new String[][] {
+					{},
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected payload not found in the record block'"
+					},
+					{
+						"[ERROR/OBJECT] Invalid 'IP-address' value, value: 'Tuesday,', expected: 'IPv4 or IPv6 format'",
+						"[ERROR/OBJECT] Invalid 'Archive-date' value, value: '21-Aug-96', expected: 'yyyyMMddHHmmss'",
+						"[ERROR/OBJECT] Invalid 'Content-type' value, value: '05:14:05', expected: '<type>/<sub-type>(; <argument>=<value>)*'",
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: 'GMT', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid Data before ARC record",
+						"[WARNING/OBJECT] Error in Misplaced CR, expected 'Sequence of LFs'",
+						"[WARNING/OBJECT] Error in Misplaced LF, expected 'Sequence of LFs'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecord-2.arc", new String[][] {
+					{},
+					{
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: 'invalid', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected payload not found in the record block'"
+					},
+					{
+						"[ERROR/OBJECT] Invalid 'IP-address' value, value: 'Tuesday,', expected: 'IPv4 or IPv6 format'",
+						"[ERROR/OBJECT] Invalid 'Archive-date' value, value: '21-Aug-96', expected: 'yyyyMMddHHmmss'",
+						"[ERROR/OBJECT] Invalid 'Content-type' value, value: '05:14:05', expected: '<type>/<sub-type>(; <argument>=<value>)*'",
+						"[ERROR/OBJECT] Invalid 'Archive-length' value, value: 'GMT', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid Data before ARC record",
+						"[WARNING/OBJECT] Error in Misplaced CR, expected 'Sequence of LFs'",
+						"[WARNING/OBJECT] Error in Misplaced LF, expected 'Sequence of LFs'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-arcrecord-3.arc", new String[][] {
+					{},
+					{
+						"[ERROR/OBJECT] Error in http header, reason 'Unable to parse http header!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-1.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-2.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-3.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-4.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-5.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-6.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-arcrecord-7.arc", new String[][] {
+					{},
+					{}
+			}, new String[] {
+			}}
+	};
+
+	@Test
+	public void test_arcrecords() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/arc/ArcVersionBlockTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcVersionBlockTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-versionblock-1.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC file"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-2.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Required 'Archive-length' value is missing",
+						"[ERROR/OBJECT] Invalid ARC file"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-3.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '1', expected: '2'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-4.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC file, expected 'Expected metadata payload not found in the version block'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-5.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Undesired version block metadata payload: value: 'Metadata payload must not be present in this version'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-6.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Undesired version block metadata payload: value: 'Metadata payload must not be present in this version'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-7.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Required 'Content-type' value is missing",
+						"[ERROR/OBJECT] Error in Content-type, expected '<type>/<sub-type>(; <argument>=<value>)*'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-8.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'application/plain', expected: 'text/plain'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-9.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'text/binary', expected: 'text/plain'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-10.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'text/binary', expected: 'text/plain'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionblock-11.arc", new String[][] {
+					{
+						"[WARNING/OBJECT] Invalid Content-type, value: 'text/binary', expected: 'text/plain'"
+					}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionblock-1.arc", new String[][] {
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionblock-2.arc", new String[][] {
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionblock-3.arc", new String[][] {
+					{}
+			}, new String[] {
+			}}
+	};
+
+	@Test
+	public void test_arcversionblocks() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/arc/ArcVersionHeaderTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.arc;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of ARC Module
+ * @see org.jhove2.module.warc.ArcModule
+ * @author nicl
+ */
+public class ArcVersionHeaderTest extends ArcModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-versionheader-1.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC file"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-2.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC file"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-3.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-4.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-5.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-6.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-7.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-8.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '2', expected: '1'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-9.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '1', expected: '2'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-10.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version line empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-11.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-12.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-13.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-14.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-15.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-16.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-17.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Version-number' value, value: 'x', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-18.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Version-number' value, value: 'x', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-19.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Reserved' value, value: 'x', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-20.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid 'Reserved' value, value: 'x', expected: 'Numeric format'",
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-21.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-22.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-23.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-24.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-25.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-26.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Block definition empty'",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-27.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-28.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '2', expected: '1'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-29.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '1', expected: '2'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-30.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-31.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'",
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '1', expected: '2'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-32.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC version block",
+						"[ERROR/OBJECT] Error in ARC version block, reason 'Version block is not valid!'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-33.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '2', expected: '1'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-34.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '2', expected: '1'"
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-versionheader-35.arc", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid ARC record does not match the version block definition, value: '1', expected: '2'"
+					}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionheader-1.arc", new String[][] {
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionheader-2.arc", new String[][] {
+					{}
+			}, new String[] {
+			}},
+			{Validity.True, "valid-versionheader-3.arc", new String[][] {
+					{}
+			}, new String[] {
+			}}
+	};
+
+	@Test
+	public void test_arcversionheaders() {
+		test_cases(cases, false);
+	}
+
+}

src/test/java/org/jhove2/module/format/gzip/GzipModuleTest.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ * <p>
+ * Copyright (c) 2009 by The Regents of the University of California, Ithaka
+ * Harbors, Inc., and The Board of Trustees of the Leland Stanford Junior
+ * University. All rights reserved.
+ * </p>
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * </p>
+ * <ul>
+ * <li>Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.</li>
+ * <li>Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.</li>
+ * <li>Neither the name of the University of California/California Digital
+ * Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.</li>
+ * </ul>
+ * <p>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * </p>
+ */
+package org.jhove2.module.format.gzip;
+
+import org.jhove2.module.format.Validator.Validity;
+import org.junit.Test;
+
+/**
+ * Tests of GZip Module
+ * @see org.jhove2.module.warc.GzipModule
+ * @author nicl
+ */
+public class GzipModuleTest extends GzipModuleTestBase {
+
+	Object[][] cases = new Object[][] {
+			{Validity.False, "invalid-empty.gzip", new String[][] {
+			}, new String[] {
+					"[ERROR/OBJECT] Error in GZip file, expected 'One or more records'"
+			}},
+			{Validity.False, "invalid-compression.gz", new String[][] {
+					{
+						"[ERROR/OBJECT] Invalid Compression Method, value: '4', expected: '8'"					
+					}
+			}, new String[] {
+			}},
+			{Validity.False, "invalid-entries.gz", new String[][] {
+					{
+						"[WARNING/OBJECT] Reserved eXtra FLags: value: '1'"
+					},
+					{