package org.jabref.logic.bibtex; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Collection; import java.util.Set; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.logic.util.OS; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.junit.Before; import org.junit.Test; import org.mockito.Answers; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; public class BibEntryWriterTest { private static ImportFormatPreferences importFormatPreferences; private BibEntryWriter writer; @Before public void setUpWriter() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); LatexFieldFormatterPreferences latexFieldFormatterPreferences = mock(LatexFieldFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); writer = new BibEntryWriter(new LatexFieldFormatter(latexFieldFormatterPreferences), true); } @Test public void testSerialization() throws IOException { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); //set a required field entry.setField("author", "Foo Bar"); entry.setField("journal", "International Journal of Something"); //set an optional field entry.setField("number", "1"); entry.setField("note", "some note"); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expected = OS.NEWLINE + "@Article{," + OS.NEWLINE + " author = {Foo Bar}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } @Test public void writeOtherTypeTest() throws Exception { String expected = OS.NEWLINE + "@Other{test," + OS.NEWLINE + " comment = {testentry}," + OS.NEWLINE + "}"+ OS.NEWLINE; BibEntry entry = new BibEntry(); entry.setType("other"); entry.setField("Comment","testentry"); entry.setCiteKey("test"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(expected, actual); } @Test public void writeReallyunknownTypeTest() throws Exception { String expected = OS.NEWLINE + "@Reallyunknowntype{test," + OS.NEWLINE + " comment = {testentry}," + OS.NEWLINE + "}"+ OS.NEWLINE; BibEntry entry = new BibEntry(); entry.setType("ReallyUnknownType"); entry.setField("Comment","testentry"); entry.setCiteKey("test"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(expected, actual); } @Test public void roundTripTest() throws IOException { // @formatter:off String bibtexEntry = "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(bibtexEntry, actual); } @Test public void roundTripWithPrependingNewlines() throws IOException { // @formatter:off String bibtexEntry = "\r\n@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(bibtexEntry, actual); } @Test public void roundTripWithModification() throws IOException { // @formatter:off String bibtexEntry = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}," + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // Modify entry entry.setField("author", "BlaBla"); // write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } @Test public void roundTripWithCamelCasingInTheOriginalEntryAndResultInLowerCase() throws IOException { // @formatter:off String bibtexEntry = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}," + OS.NEWLINE + " HowPublished = {asdf}," + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // modify entry entry.setField("author", "BlaBla"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } @Test public void testEntryTypeChange() throws IOException { // @formatter:off String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(expected)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // modify entry entry.setType("inproceedings"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expectedNewEntry = OS.NEWLINE + "@InProceedings{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expectedNewEntry, actual); } @Test public void roundTripWithAppendedNewlines() throws IOException { // @formatter:off String bibtexEntry = "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}\n\n"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // Only one appending newline is written by the writer, the rest by FileActions. So, these should be removed here. assertEquals(bibtexEntry.substring(0, bibtexEntry.length() - 1), actual); } @Test public void multipleWritesWithoutModification() throws IOException { // @formatter:off String bibtexEntry = "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on String result = testSingleWrite(bibtexEntry); result = testSingleWrite(result); result = testSingleWrite(result); assertEquals(bibtexEntry, result); } private String testSingleWrite(String bibtexEntry) throws IOException { // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(bibtexEntry, actual); return actual; } @Test public void monthFieldSpecialSyntax() throws IOException { // @formatter:off String bibtexEntry = "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Month = mar," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // modify month field Set<String> fields = entry.getFieldNames(); assertTrue(fields.contains("month")); assertEquals("#mar#", entry.getField("month").get()); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(bibtexEntry, actual); } @Test public void addFieldWithLongerLength() throws IOException { // @formatter:off String bibtexEntry = OS.NEWLINE + OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // modify entry entry.setField("howpublished", "asdf"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } @Test public void doNotWriteEmptyFields() throws IOException { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); entry.setField("author", " "); entry.setField("note", "some note"); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); String expected = OS.NEWLINE + "@Article{," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; assertEquals(expected, actual); } @Test public void trimFieldContents() throws IOException { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); entry.setField("note", " some note \t"); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); String expected = OS.NEWLINE + "@Article{," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; assertEquals(expected, actual); } @Test(expected = IOException.class) public void writeThrowsErrorIfFieldContainsUnbalancedBraces() throws IOException { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); entry.setField("note", "some text with unbalanced { braces"); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); } @Test public void roundTripWithPrecedingCommentTest() throws IOException { // @formatter:off String bibtexEntry = "% Some random comment that should stay here" + OS.NEWLINE + "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); assertEquals(bibtexEntry, actual); } @Test public void roundTripWithPrecedingCommentAndModificationTest() throws IOException { // @formatter:off String bibtexEntry = "% Some random comment that should stay here" + OS.NEWLINE + "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + " Note = {some note}," + OS.NEWLINE + " Number = {1}" + OS.NEWLINE + "}"; // @formatter:on // read in bibtex string ParserResult result = new BibtexParser(importFormatPreferences).parse(new StringReader(bibtexEntry)); Collection<BibEntry> entries = result.getDatabase().getEntries(); BibEntry entry = entries.iterator().next(); // change the entry entry.setField("author", "John Doe"); //write out bibtex string StringWriter stringWriter = new StringWriter(); writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); String actual = stringWriter.toString(); // @formatter:off String expected = "% Some random comment that should stay here" + OS.NEWLINE + OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {John Doe}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } }