From 7fe42850dcf7b20682c064a61a7dc2a0762e6c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rg=20Prante?= Date: Thu, 14 Dec 2017 14:01:26 +0100 Subject: [PATCH] fixed validity check for subfield codes, changed MarcGenerator close() to flush() method, fixes for sonarqube, update to gradle 4.4 --- build.gradle | 16 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54731 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- src/docs/asciidoc/index.adoc | 2 - src/main/java/org/xbib/marc/Marc.java | 29 ++- src/main/java/org/xbib/marc/MarcField.java | 43 +++-- .../java/org/xbib/marc/MarcFieldAdapter.java | 6 + .../java/org/xbib/marc/MarcGenerator.java | 8 +- src/main/java/org/xbib/marc/MarcWriter.java | 4 +- .../marc/dialects/mab/MabSubfieldControl.java | 3 + .../org/xbib/marc/json/MarcJsonWriter.java | 20 ++- .../java/org/xbib/marc/tools/MarcTool.java | 61 +++---- .../field/MarcFieldTransformer.java | 25 +-- .../value/MarcValueTransformers.java | 8 +- .../java/org/xbib/marc/MarcFieldTest.java | 4 +- .../java/org/xbib/marc/MarcRecordTest.java | 168 +++++++++--------- .../org/xbib/marc/dialects/mab/HBZTest.java | 6 +- .../io/BufferedSeparatorInputStreamTest.java | 10 +- 19 files changed, 225 insertions(+), 194 deletions(-) diff --git a/build.gradle b/build.gradle index 190cc5e..63d16ae 100644 --- a/build.gradle +++ b/build.gradle @@ -64,13 +64,15 @@ test { } asciidoctor { - backends 'html5' - separateOutputDirs = false - attributes 'source-highlighter': 'coderay', - toc : '', - idprefix : '', - idseparator : '-', - stylesheet: "${projectDir}/src/docs/asciidoc/css/foundation.css" + attributes toc: 'left', + doctype: 'book', + icons: 'font', + encoding: 'utf-8', + sectlink: true, + sectanchors: true, + linkattrs: true, + imagesdir: 'img', + 'source-highlighter': 'coderay' } javadoc { diff --git a/gradle.properties b/gradle.properties index 6fe171c..fc70e2e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ group = org.xbib name = marc -version = 1.0.17 +version = 1.0.18 xbib-content.version = 1.0.7 xbib-bibliographic-character-sets.version = 1.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 6b6ea3ab4ff4f69d55c5fd9c0a6ac70f47d41008..01b8bf6b1f99cad9213fc495b33ad5bbab8efd20 100644 GIT binary patch delta 16191 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 Kh6es~_x}TS%?*eE delta 16600 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bb291e2..95fb45e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Dec 05 21:14:54 CET 2017 +#Thu Dec 14 12:16:56 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 1c7a1e2..c1b1003 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -5,10 +5,8 @@ Version 1.0 :toc: preamble :toclevels: 4 :!toc-title: Content -:experimental: :description: MARC bibliographic data processing :keywords: MARC, Java, bibliographic data processing -:icons: font == Introduction diff --git a/src/main/java/org/xbib/marc/Marc.java b/src/main/java/org/xbib/marc/Marc.java index 96dab1d..e1f73e0 100644 --- a/src/main/java/org/xbib/marc/Marc.java +++ b/src/main/java/org/xbib/marc/Marc.java @@ -314,7 +314,7 @@ public final class Marc { count++; } stream.close(); - builder.marcGenerator.close(); + builder.marcGenerator.flush(); if (withCollection) { marcListener.endCollection(); if (marcListener instanceof ContentHandler) { @@ -384,7 +384,7 @@ public final class Marc { l.incrementAndGet(); }); stream.close(); - builder.marcGenerator.close(); + builder.marcGenerator.flush(); if (withCollection) { marcRecordListener.endCollection(); if (marcRecordListener instanceof ContentHandler) { @@ -567,7 +567,7 @@ public final class Marc { while ((chunk = stream.readChunk()) != null) { marcGenerator.chunk(chunk); } - marcGenerator.close(); + marcGenerator.flush(); } finally { builder.getInputStream().close(); } @@ -1100,18 +1100,19 @@ public final class Marc { @Override public boolean hasNext() { try { - setMarcRecord(null); + MarcRecord record; + record(null); Chunk chunk; while ((chunk = stream.readChunk()) != null) { marcGenerator.chunk(chunk); - MarcRecord marcRecord = getMarcRecord(); - if (marcRecord != null) { + record = getMarcRecord(); + if (record != null) { return true; } } - marcGenerator.close(); - MarcRecord marcRecord = getMarcRecord(); - if (marcRecord != null) { + marcGenerator.flush(); + record = getMarcRecord(); + if (record != null) { return true; } } catch (IOException e) { @@ -1122,11 +1123,11 @@ public final class Marc { @Override public MarcRecord next() { - MarcRecord marcRecord = getMarcRecord(); - if (marcRecord == null) { + MarcRecord record = getMarcRecord(); + if (record == null) { throw new NoSuchElementException(); } - return marcRecord; + return record; } }; } @@ -1158,10 +1159,6 @@ public final class Marc { return this; } - private void setMarcRecord(MarcRecord marcRecord) { - this.marcRecord = marcRecord; - } - private MarcRecord getMarcRecord() { return marcRecord; } diff --git a/src/main/java/org/xbib/marc/MarcField.java b/src/main/java/org/xbib/marc/MarcField.java index 58bd98e..91a10b0 100644 --- a/src/main/java/org/xbib/marc/MarcField.java +++ b/src/main/java/org/xbib/marc/MarcField.java @@ -19,8 +19,12 @@ package org.xbib.marc; import org.xbib.marc.dialects.mab.MabSubfieldControl; import org.xbib.marc.label.RecordLabel; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashSet; import java.util.LinkedList; import java.util.ListIterator; +import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -39,6 +43,21 @@ public class MarcField implements Comparable { private static final String BLANK_STRING = " "; + private static final Set ASCII_GRAPHICS = new HashSet<>(Arrays.asList( + '\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\'', + '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '\u003A', '\u003B', '\u003C', '\u003D', '\u003E', '\u003F', '\u0040', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u005B', '\\', '\u005D', '\u005E', '\u005F', '\u0060', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', + '\u007B', '\u007C', '\u007D', '\u007E' + )); + private final String tag; private final String indicator; @@ -51,12 +70,12 @@ public class MarcField implements Comparable { private final String subfieldIds; - private final LinkedList subfields; + private final Deque subfields; private final boolean iscontrol; private MarcField(String tag, String indicator, int position, int length, - String value, LinkedList subfields, String subfieldIds, + String value, Deque subfields, String subfieldIds, boolean iscontrol) { this.tag = tag; this.indicator = indicator; @@ -120,7 +139,7 @@ public class MarcField implements Comparable { * Return the subfields associated with this MARC field. * @return a list of MARC subfields */ - public LinkedList getSubfields() { + public Deque getSubfields() { return subfields; } @@ -129,7 +148,7 @@ public class MarcField implements Comparable { * @param subfieldId subfield ID * @return list of subfields */ - public LinkedList getSubfield(String subfieldId) { + public Deque getSubfield(String subfieldId) { return subfields.stream() .filter(subfield -> subfield.getId().equals(subfieldId)) .collect(Collectors.toCollection(LinkedList::new)); @@ -144,8 +163,8 @@ public class MarcField implements Comparable { } public String getFirstSubfieldValue(String subfieldId) { - LinkedList list = getSubfield(subfieldId); - return list.isEmpty() ? null : list.getFirst().getValue(); + Deque deque = getSubfield(subfieldId); + return deque.isEmpty() ? null : deque.getFirst().getValue(); } /** @@ -157,8 +176,8 @@ public class MarcField implements Comparable { } public String getLastSubfieldValue(String subfieldId) { - LinkedList list = getSubfield(subfieldId); - return list.isEmpty() ? null : list.getLast().getValue(); + Deque deque = getSubfield(subfieldId); + return deque.isEmpty() ? null : deque.getLast().getValue(); } /** @@ -229,13 +248,7 @@ public class MarcField implements Comparable { } boolean b = true; for (int i = 0; i < subfieldIds.length(); i++) { - b = subfieldIds.charAt(i) == ' ' - || (subfieldIds.charAt(i) >= '0' && subfieldIds.charAt(i) <= '9') - || (subfieldIds.charAt(i) >= 'a' && subfieldIds.charAt(i) <= 'z') - || (subfieldIds.charAt(i) >= 'A' && subfieldIds.charAt(i) <= 'Z') // can appear in german MARC - || subfieldIds.charAt(i) == '$' // can appear in german MARC - || subfieldIds.charAt(i) == '=' // can appear in german MARC - ; + b = ASCII_GRAPHICS.contains(subfieldIds.charAt(i)); if (!b) { break; } diff --git a/src/main/java/org/xbib/marc/MarcFieldAdapter.java b/src/main/java/org/xbib/marc/MarcFieldAdapter.java index e4bdf5c..a5aa04c 100644 --- a/src/main/java/org/xbib/marc/MarcFieldAdapter.java +++ b/src/main/java/org/xbib/marc/MarcFieldAdapter.java @@ -22,25 +22,31 @@ package org.xbib.marc; public class MarcFieldAdapter implements MarcListener { @Override public void beginCollection() { + // empty by design } @Override public void beginRecord(String format, String type) { + // empty by design } @Override public void leader(String label) { + // empty by design } @Override public void field(MarcField field) { + // empty by design } @Override public void endRecord() { + // empty by design } @Override public void endCollection() { + // empty by design } } diff --git a/src/main/java/org/xbib/marc/MarcGenerator.java b/src/main/java/org/xbib/marc/MarcGenerator.java index 1472997..423264d 100644 --- a/src/main/java/org/xbib/marc/MarcGenerator.java +++ b/src/main/java/org/xbib/marc/MarcGenerator.java @@ -29,7 +29,6 @@ import org.xbib.marc.transformer.MarcTransformer; import org.xbib.marc.transformer.field.MarcFieldTransformers; import org.xbib.marc.transformer.value.MarcValueTransformers; -import java.io.Closeable; import java.io.IOException; import java.nio.charset.Charset; import java.util.LinkedList; @@ -38,7 +37,7 @@ import java.util.List; /** * This chunk listener interprets the chunks from a stream and generates MARC events to a given MARC listener. */ -public class MarcGenerator implements ChunkListener, Closeable { +public class MarcGenerator implements ChunkListener { private String format; @@ -180,7 +179,8 @@ public class MarcGenerator implements ChunkListener, Clo builder.indicator(data.substring(0, pos)); if (pos < data.length()) { builder.value(this.data.substring(pos)); - } } + } + } found = true; break; } else if (directory.containsKey(position - offset)) { @@ -221,7 +221,7 @@ public class MarcGenerator implements ChunkListener, Clo * This method will emit the last record, if not emitted already. * Useful if chunk streams have no closing record separator. */ - public void close() throws IOException { + public void flush() { if (position > 0) { emitMarcRecord(); } diff --git a/src/main/java/org/xbib/marc/MarcWriter.java b/src/main/java/org/xbib/marc/MarcWriter.java index 5a243bc..854239f 100644 --- a/src/main/java/org/xbib/marc/MarcWriter.java +++ b/src/main/java/org/xbib/marc/MarcWriter.java @@ -57,7 +57,7 @@ public class MarcWriter extends MarcContentHandler implements Flushable, Closeab * @param charset the character set * @throws IOException if writer can not be created */ - public MarcWriter(OutputStream out, Charset charset) throws IOException { + public MarcWriter(OutputStream out, Charset charset) { this(out, charset, DEFAULT_BUFFER_SIZE); } @@ -68,7 +68,7 @@ public class MarcWriter extends MarcContentHandler implements Flushable, Closeab * @param buffersize the buffer size writing to the underlying output stream * @throws IOException if writer can not be created */ - public MarcWriter(OutputStream out, Charset charset, int buffersize) throws IOException { + public MarcWriter(OutputStream out, Charset charset, int buffersize) { this.out = new SeparatorOutputStream(out, buffersize); this.charset = charset; this.bytesStreamOutput = new BytesStreamOutput(); diff --git a/src/main/java/org/xbib/marc/dialects/mab/MabSubfieldControl.java b/src/main/java/org/xbib/marc/dialects/mab/MabSubfieldControl.java index 2663d0a..bc07ce2 100644 --- a/src/main/java/org/xbib/marc/dialects/mab/MabSubfieldControl.java +++ b/src/main/java/org/xbib/marc/dialects/mab/MabSubfieldControl.java @@ -16,6 +16,9 @@ public class MabSubfieldControl { FIELDS.put("856", 2); } + private MabSubfieldControl() { + } + public static Integer getSubfieldIdLen(String tag) { return FIELDS.getOrDefault(tag, 0); } diff --git a/src/main/java/org/xbib/marc/json/MarcJsonWriter.java b/src/main/java/org/xbib/marc/json/MarcJsonWriter.java index 275cd85..a5ffab8 100644 --- a/src/main/java/org/xbib/marc/json/MarcJsonWriter.java +++ b/src/main/java/org/xbib/marc/json/MarcJsonWriter.java @@ -24,7 +24,15 @@ import org.xbib.marc.label.RecordLabel; import org.xbib.marc.transformer.value.MarcValueTransformers; import org.xbib.marc.xml.MarcContentHandler; -import java.io.*; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UncheckedIOException; +import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -97,23 +105,23 @@ public class MarcJsonWriter extends MarcContentHandler implements Flushable, Clo */ private boolean top; - public MarcJsonWriter(OutputStream out) throws IOException { + public MarcJsonWriter(OutputStream out) { this(out, Style.ARRAY); } - public MarcJsonWriter(OutputStream out, Style style) throws IOException { + public MarcJsonWriter(OutputStream out, Style style) { this(out, DEFAULT_BUFFER_SIZE, style); } - public MarcJsonWriter(OutputStream out, int bufferSize, Style style) throws IOException { + public MarcJsonWriter(OutputStream out, int bufferSize, Style style) { this(new OutputStreamWriter(out, StandardCharsets.UTF_8), style, bufferSize); } - public MarcJsonWriter(Writer writer) throws IOException { + public MarcJsonWriter(Writer writer) { this(writer, Style.ARRAY, DEFAULT_BUFFER_SIZE); } - public MarcJsonWriter(Writer writer, Style style, int bufferSize) throws IOException { + public MarcJsonWriter(Writer writer, Style style, int bufferSize) { this.writer = new BufferedWriter(writer, bufferSize); this.bufferSize = bufferSize; this.style = style; diff --git a/src/main/java/org/xbib/marc/tools/MarcTool.java b/src/main/java/org/xbib/marc/tools/MarcTool.java index a093ac7..1c79e41 100644 --- a/src/main/java/org/xbib/marc/tools/MarcTool.java +++ b/src/main/java/org/xbib/marc/tools/MarcTool.java @@ -45,7 +45,7 @@ public class MarcTool { private String stylesheet = null; private String result = null; - public static void main(String[] args) throws Exception { + public static void main(String[] args) { MarcTool marcTool = new MarcTool(); marcTool.parse(args); System.exit(marcTool.run()); @@ -99,39 +99,36 @@ public class MarcTool { if (mode == null) { mode = "marc2xml"; } - switch (mode) { - case "marc2xml": { - try (InputStream in = Files.newInputStream(Paths.get(input)); - MarcXchangeWriter writer = new MarcXchangeWriter(Files.newBufferedWriter(Paths.get(output)), true)) { - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName(charset)) - .setMarcListener(writer); - if (schema != null && stylesheet != null && result != null) { - System.setProperty("http.agent", "Java Agent"); - builder.setSchema(schema).build().transform(new URL(stylesheet), - new StreamResult(Files.newBufferedWriter(Paths.get(result)))); - } else { - builder.build().writeCollection(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, e.getMessage(), e); - return 1; + if ("marc2xml".equals(mode)) { + try (InputStream in = Files.newInputStream(Paths.get(input)); + MarcXchangeWriter writer = new MarcXchangeWriter(Files.newBufferedWriter(Paths.get(output)), true)) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName(charset)) + .setMarcListener(writer); + if (schema != null && stylesheet != null && result != null) { + System.setProperty("http.agent", "Java Agent"); + builder.setSchema(schema).build().transform(new URL(stylesheet), + new StreamResult(Files.newBufferedWriter(Paths.get(result)))); + } else { + builder.build().writeCollection(); } - return 0; - } - default: { - String help = "Usage: " + getClass().getName() - + " --mode [marc2xml] set operation mode\n" - + " --input \n" - + " --output \n" - + " --charset \n" - + " --schema [MARC21|MarcXchange] \n" - + " --stylesheet \n" - + " --result \n"; - logger.log(Level.INFO, help); - return 0; + } catch (Exception e) { + logger.log(Level.SEVERE, e.getMessage(), e); + return 1; } + return 0; + } else { + String help = "Usage: " + getClass().getName() + + " --mode [marc2xml] set operation mode\n" + + " --input \n" + + " --output \n" + + " --charset \n" + + " --schema [MARC21|MarcXchange] \n" + + " --stylesheet \n" + + " --result \n"; + logger.log(Level.INFO, help); + return 0; } } } diff --git a/src/main/java/org/xbib/marc/transformer/field/MarcFieldTransformer.java b/src/main/java/org/xbib/marc/transformer/field/MarcFieldTransformer.java index f4d0cc1..581b4ed 100644 --- a/src/main/java/org/xbib/marc/transformer/field/MarcFieldTransformer.java +++ b/src/main/java/org/xbib/marc/transformer/field/MarcFieldTransformer.java @@ -21,6 +21,7 @@ import static org.xbib.marc.transformer.field.MarcFieldTransformer.Operator.HEAD import org.xbib.marc.MarcField; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.logging.Level; @@ -131,12 +132,13 @@ public class MarcFieldTransformer extends LinkedHashMap { builder.subfield(subfield.getId(), subfield.getValue()); } } else { - // map subfields - for (int i = 0; i < marcField.getSubfields().size(); i++) { - if (i < newMarcField.getSubfields().size()) { - builder.subfield(newMarcField.getSubfields().get(i).getId(), - marcField.getSubfields().get(i).getValue()); - } + // transform subfields + Iterator subfields = marcField.getSubfields().iterator(); + Iterator newSubfields = newMarcField.getSubfields().iterator(); + while (subfields.hasNext() && newSubfields.hasNext()) { + MarcField.Subfield subfield = subfields.next(); + MarcField.Subfield newSubfield = newSubfields.next(); + builder.subfield(newSubfield.getId(), subfield.getValue()); } } } @@ -192,11 +194,12 @@ public class MarcFieldTransformer extends LinkedHashMap { } else { // get the correct MARC field to map subfield IDs MarcField marcField1 = get(key); - for (int i = 0; i < marcField.getSubfields().size(); i++) { - if (i < marcField1.getSubfields().size()) { - builder.subfield(marcField1.getSubfields().get(i).getId(), - marcField.getSubfields().get(i).getValue()); - } + Iterator subfields = marcField.getSubfields().iterator(); + Iterator newSubfields = marcField1.getSubfields().iterator(); + while (subfields.hasNext() && newSubfields.hasNext()) { + MarcField.Subfield subfield = subfields.next(); + MarcField.Subfield newSubfield = newSubfields.next(); + builder.subfield(newSubfield.getId(), subfield.getValue()); } } lastBuilt = builder.build(); diff --git a/src/main/java/org/xbib/marc/transformer/value/MarcValueTransformers.java b/src/main/java/org/xbib/marc/transformer/value/MarcValueTransformers.java index 7490984..b04e6b9 100644 --- a/src/main/java/org/xbib/marc/transformer/value/MarcValueTransformers.java +++ b/src/main/java/org/xbib/marc/transformer/value/MarcValueTransformers.java @@ -25,12 +25,14 @@ import java.util.Map; */ public class MarcValueTransformers { + private static final String DEFAULT = "_default"; + private final Map marcValueTransformerMap = new HashMap<>(); private final Map subfieldMap = new HashMap<>(); public MarcValueTransformers setMarcValueTransformer(MarcValueTransformer transformer) { - this.marcValueTransformerMap.put("_default", transformer); + this.marcValueTransformerMap.put(DEFAULT, transformer); return this; } @@ -62,7 +64,7 @@ public class MarcValueTransformers { return field; } final MarcValueTransformer transformer = marcValueTransformerMap.containsKey(key) ? - marcValueTransformerMap.get(key) : marcValueTransformerMap.get("_default"); + marcValueTransformerMap.get(key) : marcValueTransformerMap.get(DEFAULT); if (transformer != null) { MarcField.Builder builder = MarcField.builder(); builder.tag(field.getTag()).indicator(field.getIndicator()); @@ -80,7 +82,7 @@ public class MarcValueTransformers { } public String transform(String value) { - MarcValueTransformer marcValueTransformer = marcValueTransformerMap.get("_default"); + MarcValueTransformer marcValueTransformer = marcValueTransformerMap.get(DEFAULT); return marcValueTransformer != null ? marcValueTransformer.transform(value) : value; } } diff --git a/src/test/java/org/xbib/marc/MarcFieldTest.java b/src/test/java/org/xbib/marc/MarcFieldTest.java index 7ac75df..ad42924 100644 --- a/src/test/java/org/xbib/marc/MarcFieldTest.java +++ b/src/test/java/org/xbib/marc/MarcFieldTest.java @@ -29,7 +29,7 @@ public class MarcFieldTest extends Assert { @Test public void testFieldData() { MarcField marcField = MarcField.builder().tag("100").indicator("").value("Hello World").build(); - assertEquals(marcField.getValue(), "Hello World"); + assertEquals("Hello World", marcField.getValue()); } @Test @@ -159,7 +159,7 @@ public class MarcFieldTest extends Assert { MarcField marcField = MarcField.builder() .tag("100") .indicator("0") - .subfield("-", null) + .subfield("\u007f", null) .build(); assertFalse(marcField.isSubfieldValid()); } diff --git a/src/test/java/org/xbib/marc/MarcRecordTest.java b/src/test/java/org/xbib/marc/MarcRecordTest.java index 92027c5..4ba222b 100644 --- a/src/test/java/org/xbib/marc/MarcRecordTest.java +++ b/src/test/java/org/xbib/marc/MarcRecordTest.java @@ -92,85 +92,85 @@ public class MarcRecordTest extends Assert { @Test public void testFilterKeyIterable() throws Exception { String s = "summerland.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")); - // only single record - for (MarcRecord marcRecord : builder.iterable()) { - // single 245 field - assertEquals(1, marcRecord.filterKey(Pattern.compile("^245.*")).size()); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")); + // only single record + for (MarcRecord marcRecord : builder.iterable()) { + // single 245 field + assertEquals(1, marcRecord.filterKey(Pattern.compile("^245.*")).size()); + } } - in.close(); } @Test public void testFilterKey() throws Exception { String s = "summerland.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")) - .setKeyPattern(Pattern.compile("^245.*")); - // record with single field - for (MarcRecord marcRecord : builder.iterable()) { - assertEquals(1, marcRecord.getFields().size()); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")) + .setKeyPattern(Pattern.compile("^245.*")); + // record with single field + for (MarcRecord marcRecord : builder.iterable()) { + assertEquals(1, marcRecord.getFields().size()); + } } - in.close(); } @Test public void testFilterValueIterable() throws Exception { String s = "summerland.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")); - for (MarcRecord marcRecord : builder.iterable()) { - assertEquals(2, marcRecord.filterValue(Pattern.compile(".*?Chabon.*")).size()); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")); + for (MarcRecord marcRecord : builder.iterable()) { + assertEquals(2, marcRecord.filterValue(Pattern.compile(".*?Chabon.*")).size()); + } } - in.close(); } @Test public void testFilterValue() throws Exception { String s = "summerland.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")) - .setValuePattern(Pattern.compile(".*?Chabon.*")); - for (MarcRecord marcRecord : builder.iterable()) { - assertEquals(2, marcRecord.getFields().size()); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")) + .setValuePattern(Pattern.compile(".*?Chabon.*")); + for (MarcRecord marcRecord : builder.iterable()) { + assertEquals(2, marcRecord.getFields().size()); + } } - in.close(); } @Test public void testSequentialIteration() throws Exception { String s = "dialects/unimarc/periouni.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in).setCharset(StandardCharsets.UTF_8); - final AtomicInteger count = new AtomicInteger(); - // test for loop - for (MarcRecord marcRecord : builder.iterable()) { - count.incrementAndGet(); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in).setCharset(StandardCharsets.UTF_8); + final AtomicInteger count = new AtomicInteger(); + // test for loop + for (MarcRecord marcRecord : builder.iterable()) { + count.incrementAndGet(); + } + assertEquals(3064, count.get()); } - in.close(); - assertEquals(3064, count.get()); } @Test public void testRecordStream() throws Exception { String s = "dialects/unimarc/periouni.mrc"; - InputStream in = getClass().getResource(s).openStream(); - Marc.Builder builder = Marc.builder() - .setInputStream(in) - .setCharset(StandardCharsets.UTF_8); - long count = builder.recordStream().map(r -> r.get("001")).count(); - in.close(); - assertEquals(3064, count); + try (InputStream in = getClass().getResource(s).openStream()) { + Marc.Builder builder = Marc.builder() + .setInputStream(in) + .setCharset(StandardCharsets.UTF_8); + long count = builder.recordStream().map(r -> r.get("001")).count(); + assertEquals(3064, count); + } } /** @@ -179,47 +179,49 @@ public class MarcRecordTest extends Assert { @Test public void testIRMARC8AsRecordStream() throws Exception { String s = "IRMARC8.bin"; - InputStream in = getClass().getResource(s).openStream(); - File file = File.createTempFile(s + ".", ".xml"); - file.deleteOnExit(); - FileOutputStream out = new FileOutputStream(file); - MarcValueTransformers marcValueTransformers = new MarcValueTransformers(); - marcValueTransformers.setMarcValueTransformer(value -> Normalizer.normalize(value, Normalizer.Form.NFC)); - try (MarcXchangeWriter writer = new MarcXchangeWriter(out) - .setMarcValueTransformers(marcValueTransformers)) { - Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")) - .setMarcRecordListener(writer) - .build() - .writeRecordCollection(); - assertNull(writer.getException()); + try (InputStream in = getClass().getResource(s).openStream()) { + File file = File.createTempFile(s + ".", ".xml"); + file.deleteOnExit(); + FileOutputStream out = new FileOutputStream(file); + MarcValueTransformers marcValueTransformers = new MarcValueTransformers(); + marcValueTransformers.setMarcValueTransformer(value -> Normalizer.normalize(value, Normalizer.Form.NFC)); + try (MarcXchangeWriter writer = new MarcXchangeWriter(out) + .setMarcValueTransformers(marcValueTransformers)) { + Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")) + .setMarcRecordListener(writer) + .build() + .writeRecordCollection(); + assertNull(writer.getException()); + } + assertThat(file, CompareMatcher.isIdenticalTo(getClass().getResource(s + ".xml").openStream())); } - assertThat(file, CompareMatcher.isIdenticalTo(getClass().getResource(s + ".xml").openStream())); } @Test public void testIRMARC8AsLightweightRecordAdapter() throws Exception { String s = "IRMARC8.bin"; - InputStream in = getClass().getResource(s).openStream(); - File file = File.createTempFile(s + ".", ".xml"); - file.deleteOnExit(); - FileOutputStream out = new FileOutputStream(file); - MarcValueTransformers marcValueTransformers = new MarcValueTransformers(); - marcValueTransformers.setMarcValueTransformer(value -> Normalizer.normalize(value, Normalizer.Form.NFC)); - try (MarcXchangeWriter writer = new MarcXchangeWriter(out) - .setMarcValueTransformers(marcValueTransformers)) { - writer.startDocument(); // just write XML processing instruction - Marc.builder() - .setInputStream(in) - .setCharset(Charset.forName("ANSEL")) - .setMarcListener(new LightweightMarcRecordAdapter(writer)) - .build() - .writeCollection(); - assertNull(writer.getException()); - writer.endDocument(); + try (InputStream in = getClass().getResource(s).openStream()) { + File file = File.createTempFile(s + ".", ".xml"); + file.deleteOnExit(); + FileOutputStream out = new FileOutputStream(file); + MarcValueTransformers marcValueTransformers = new MarcValueTransformers(); + marcValueTransformers.setMarcValueTransformer(value -> Normalizer.normalize(value, Normalizer.Form.NFC)); + try (MarcXchangeWriter writer = new MarcXchangeWriter(out) + .setMarcValueTransformers(marcValueTransformers)) { + writer.startDocument(); // just write XML processing instruction + Marc.builder() + .setInputStream(in) + .setCharset(Charset.forName("ANSEL")) + .setMarcListener(new LightweightMarcRecordAdapter(writer)) + .build() + .writeCollection(); + assertNull(writer.getException()); + writer.endDocument(); + } + assertThat(file, CompareMatcher.isIdenticalTo(getClass().getResource(s + ".xml").openStream())); } - assertThat(file, CompareMatcher.isIdenticalTo(getClass().getResource(s + ".xml").openStream())); } } diff --git a/src/test/java/org/xbib/marc/dialects/mab/HBZTest.java b/src/test/java/org/xbib/marc/dialects/mab/HBZTest.java index ddd8a42..2741980 100644 --- a/src/test/java/org/xbib/marc/dialects/mab/HBZTest.java +++ b/src/test/java/org/xbib/marc/dialects/mab/HBZTest.java @@ -1,5 +1,8 @@ package org.xbib.marc.dialects.mab; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.junit.Test; import org.xbib.marc.Marc; import org.xbib.marc.MarcRecord; @@ -9,9 +12,6 @@ import java.nio.charset.Charset; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /** * */ diff --git a/src/test/java/org/xbib/marc/io/BufferedSeparatorInputStreamTest.java b/src/test/java/org/xbib/marc/io/BufferedSeparatorInputStreamTest.java index 2679154..d627774 100644 --- a/src/test/java/org/xbib/marc/io/BufferedSeparatorInputStreamTest.java +++ b/src/test/java/org/xbib/marc/io/BufferedSeparatorInputStreamTest.java @@ -89,11 +89,11 @@ public class BufferedSeparatorInputStreamTest { listener.chunk(chunk); } in.close(); - assertEquals(unitCount, 23); - assertEquals(groupCount, 9); - assertEquals(dataCount, 389); - assertEquals(recordCount, 356); - assertEquals(fileCount, 1); + assertEquals(23, unitCount); + assertEquals(9, groupCount); + assertEquals(389, dataCount); + assertEquals(356, recordCount); + assertEquals(1, fileCount); } @Test