From 382c4b2190164ec5db9e473cb05ea831b44827eb Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 28 Nov 2019 07:54:34 +0100 Subject: [PATCH] Add tests for "changed" flag (#5640) - Add tests - Guard AtomicFileWriter with a try-with-resources during save - use Objects.requireNonNull in DefaultFileUpdateMontitor - add comment - some auto-formattings - Fix typo in comment --- .gitattributes | 10 +- .../jabref/gui/dialogs/AutosaveUIManager.java | 2 +- .../gui/exporter/SaveDatabaseAction.java | 14 +- .../gui/util/DefaultFileUpdateMonitor.java | 7 +- .../logic/exporter/BibDatabaseWriter.java | 2 +- .../model/database/BibDatabaseContext.java | 16 +- .../java/org/jabref/model/entry/BibEntry.java | 2 +- .../gui/exporter/SaveDatabaseActionTest.java | 71 ++++++++- .../exporter/BibtexDatabaseWriterTest.java | 148 +++++++++++++++--- .../org/jabref/model/entry/BibEntryTest.java | 11 ++ 10 files changed, 235 insertions(+), 48 deletions(-) diff --git a/.gitattributes b/.gitattributes index 3b82dbaf9bd..27afdcafc40 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,13 +1,19 @@ # unix line endings at unix files gradlew text eol=lf *.sh text eol=lf + +# windows line endings at windows files *.bat text eol=crlf +# required for proper releasing AUTHORS text eol=lf -# ensure that line endings of *.java and *.properties are normalized -*.properties text +# ensure that line endings of *.java, and *.properties are normalized *.java text +*.properties text + +# .bib files have to be written using OS specific line endings to enable our tests working +*.bib text !eol # disable after a release # CHANGELOG.md merge=union diff --git a/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java index 8a1fa463e59..c9268c40dc1 100644 --- a/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java +++ b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java @@ -28,7 +28,7 @@ public void listen(@SuppressWarnings("unused") AutosaveEvent event) { try { new SaveDatabaseAction(panel, Globals.prefs, Globals.entryTypesManager).save(SaveDatabaseAction.SaveDatabaseMode.SILENT); } catch (Throwable e) { - LOGGER.error("Problem occured while saving.", e); + LOGGER.error("Problem occurred while saving.", e); } } } diff --git a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java index 6d9dcfed408..f3b55ea48ec 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java @@ -42,7 +42,7 @@ /** * Action for the "Save" and "Save as" operations called from BasePanel. This class is also used for save operations * when closing a database or quitting the applications. - * + *

* The save operation is loaded off of the GUI thread using {@link BackgroundTask}. Callers can query whether the * operation was canceled, or whether it was successful. */ @@ -69,12 +69,10 @@ public SaveDatabaseAction(BasePanel panel, JabRefPreferences prefs, BibEntryType } private boolean saveDatabase(Path file, boolean selectedOnly, Charset encoding, SavePreferences.DatabaseSaveType saveType) throws SaveException { - try { - SavePreferences preferences = prefs.loadForSaveFromPreferences() - .withEncoding(encoding) - .withSaveType(saveType); - - AtomicFileWriter fileWriter = new AtomicFileWriter(file, preferences.getEncoding(), preferences.makeBackup()); + SavePreferences preferences = prefs.loadForSaveFromPreferences() + .withEncoding(encoding) + .withSaveType(saveType); + try (AtomicFileWriter fileWriter = new AtomicFileWriter(file, preferences.getEncoding(), preferences.makeBackup())) { BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(fileWriter, preferences, entryTypesManager); if (selectedOnly) { @@ -148,7 +146,7 @@ private boolean doSave() { // Reset title of tab frame.setTabTitle(panel, panel.getTabTitle(), - panel.getBibDatabaseContext().getDatabaseFile().get().getAbsolutePath()); + panel.getBibDatabaseContext().getDatabasePath().get().toAbsolutePath().toString()); frame.setWindowTitle(); frame.updateAllTabTitles(); } diff --git a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java index bdf0b51e2a6..f5600df45c5 100644 --- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java +++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java @@ -7,6 +7,7 @@ import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; +import java.util.Objects; import org.jabref.model.util.FileUpdateListener; import org.jabref.model.util.FileUpdateMonitor; @@ -19,7 +20,7 @@ /** * This class monitors a set of files for changes. Upon detecting a change it notifies the registered {@link * FileUpdateListener}s. - * + *

* Implementation based on https://stackoverflow.com/questions/16251273/can-i-watch-for-single-file-change-with-watchservice-not-the-whole-directory */ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor { @@ -69,9 +70,7 @@ private void notifyAboutChange(Path path) { @Override public void addListenerForFile(Path file, FileUpdateListener listener) throws IOException { - if (watcher == null) { - throw new IllegalStateException("You need to start the file monitor before watching files"); - } + Objects.requireNonNull(watcher, "You need to start the file monitor before watching files"); // We can't watch files directly, so monitor their parent directory for updates Path directory = file.toAbsolutePath().getParent(); diff --git a/src/main/java/org/jabref/logic/exporter/BibDatabaseWriter.java b/src/main/java/org/jabref/logic/exporter/BibDatabaseWriter.java index 94a8beb41c1..d5c238b09cd 100644 --- a/src/main/java/org/jabref/logic/exporter/BibDatabaseWriter.java +++ b/src/main/java/org/jabref/logic/exporter/BibDatabaseWriter.java @@ -151,8 +151,8 @@ public void saveDatabase(BibDatabaseContext bibDatabaseContext) throws IOExcepti */ public void savePartOfDatabase(BibDatabaseContext bibDatabaseContext, List entries) throws IOException { Optional sharedDatabaseIDOptional = bibDatabaseContext.getDatabase().getSharedDatabaseID(); - if (sharedDatabaseIDOptional.isPresent()) { + // may throw an IOException. Thus, we do not use "ifPresent", but the "old" isPresent way writeDatabaseID(sharedDatabaseIDOptional.get()); } diff --git a/src/main/java/org/jabref/model/database/BibDatabaseContext.java b/src/main/java/org/jabref/model/database/BibDatabaseContext.java index 0798b168fe2..4e5a46e3dd1 100644 --- a/src/main/java/org/jabref/model/database/BibDatabaseContext.java +++ b/src/main/java/org/jabref/model/database/BibDatabaseContext.java @@ -29,10 +29,12 @@ public class BibDatabaseContext { private final BibDatabase database; private final Defaults defaults; private MetaData metaData; + /** * The file where this database was last saved to. */ private Optional file; + private DatabaseSynchronizer dbmsSynchronizer; private CoarseChangeFilter dbmsListener; private DatabaseLocation location; @@ -115,7 +117,6 @@ public Optional getDatabaseFile() { } /** - * * @param file the database file * @deprecated use {@link #setDatabaseFile(Path)} */ @@ -155,11 +156,11 @@ public boolean isBiblatexMode() { public List getFileDirectoriesAsPaths(FilePreferences preferences) { // Filter for empty string, as this would be expanded to the jar-directory with Paths.get() return getFileDirectories(preferences).stream() - .filter(s -> !s.isEmpty()) - .map(Paths::get) - .map(Path::toAbsolutePath) - .map(Path::normalize) - .collect(Collectors.toList()); + .filter(s -> !s.isEmpty()) + .map(Paths::get) + .map(Path::toAbsolutePath) + .map(Path::normalize) + .collect(Collectors.toList()); } /** @@ -192,7 +193,7 @@ public Optional getFirstExistingFileDir(FilePreferences preferences) { *

  • BIB file directory
  • * * - * @param field The field + * @param field The field * @param preferences The fileDirectory preferences * @return The default directory for this field type. */ @@ -293,5 +294,4 @@ public void convertToLocalDatabase() { public List getEntries() { return database.getEntries(); } - } diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java index 845d482c3d0..49e548b2a44 100644 --- a/src/main/java/org/jabref/model/entry/BibEntry.java +++ b/src/main/java/org/jabref/model/entry/BibEntry.java @@ -81,7 +81,7 @@ public class BibEntry implements Cloneable { /** * Marks whether the complete serialization, which was read from file, should be used. * - * Is set to false, if parts of the entry change. This causes the entry to be serialized based on the internal state (and not based on the old serialization) + * Is set to true, if parts of the entry changed. This causes the entry to be serialized based on the internal state (and not based on the old serialization) */ private boolean changed; diff --git a/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java b/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java index 7e06be4af15..285f06c5611 100644 --- a/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java +++ b/src/test/java/org/jabref/gui/exporter/SaveDatabaseActionTest.java @@ -1,20 +1,36 @@ package org.jabref.gui.exporter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.logic.bibtex.FieldContentParserPreferences; +import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; +import org.jabref.logic.exporter.SavePreferences; +import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; +import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.shared.DatabaseLocation; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibEntryTypesManager; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.metadata.MetaData; import org.jabref.preferences.JabRefPreferences; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; @@ -27,8 +43,7 @@ class SaveDatabaseActionTest { private static final String TEST_BIBTEX_LIBRARY_LOCATION = "C:\\Users\\John_Doe\\Jabref\\literature.bib"; - private final Path file = Path.of(TEST_BIBTEX_LIBRARY_LOCATION); - + private Path file = Path.of(TEST_BIBTEX_LIBRARY_LOCATION); private DialogService dialogService = mock(DialogService.class); private JabRefPreferences preferences = mock(JabRefPreferences.class); private BasePanel basePanel = mock(BasePanel.class); @@ -91,6 +106,58 @@ public void saveShouldShowSaveAsIfDatabaseNotSelected() { verify(saveDatabaseAction, times(1)).saveAs(file); } + private SaveDatabaseAction createSaveDatabaseActionForBibDatabase(BibDatabase database) throws IOException { + file = Files.createTempFile("JabRef", ".bib"); + file.toFile().deleteOnExit(); + + LatexFieldFormatterPreferences latexFieldFormatterPreferences = mock(LatexFieldFormatterPreferences.class); + when(latexFieldFormatterPreferences.getFieldContentParserPreferences()).thenReturn(mock(FieldContentParserPreferences.class)); + SavePreferences savePreferences = mock(SavePreferences.class); + // In case a "thenReturn" is modified, the whole mock has to be recreated + dbContext = mock(BibDatabaseContext.class); + basePanel = mock(BasePanel.class); + MetaData metaData = mock(MetaData.class); + when(savePreferences.withEncoding(any(Charset.class))).thenReturn(savePreferences); + when(savePreferences.withSaveType(any(SavePreferences.DatabaseSaveType.class))).thenReturn(savePreferences); + when(savePreferences.getEncoding()).thenReturn(Charset.forName("UTF-8")); + when(savePreferences.getLatexFieldFormatterPreferences()).thenReturn(latexFieldFormatterPreferences); + GlobalBibtexKeyPattern emptyGlobalBibtexKeyPattern = GlobalBibtexKeyPattern.fromPattern(""); + when(savePreferences.getGlobalCiteKeyPattern()).thenReturn(emptyGlobalBibtexKeyPattern); + when(metaData.getCiteKeyPattern(any(GlobalBibtexKeyPattern.class))).thenReturn(emptyGlobalBibtexKeyPattern); + when(dbContext.getDatabasePath()).thenReturn(Optional.of(file)); + when(dbContext.getLocation()).thenReturn(DatabaseLocation.LOCAL); + when(dbContext.getDatabase()).thenReturn(database); + when(dbContext.getMetaData()).thenReturn(metaData); + when(dbContext.getEntries()).thenReturn(database.getEntries()); + when(preferences.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE)).thenReturn(false); + when(preferences.getDefaultEncoding()).thenReturn(Charset.forName("UTF-8")); + when(preferences.getFieldContentParserPreferences()).thenReturn(mock(FieldContentParserPreferences.class)); + when(preferences.loadForSaveFromPreferences()).thenReturn(savePreferences); + when(basePanel.frame()).thenReturn(jabRefFrame); + when(basePanel.getBibDatabaseContext()).thenReturn(dbContext); + when(basePanel.getUndoManager()).thenReturn(mock(CountingUndoManager.class)); + when(basePanel.getBibDatabaseContext()).thenReturn(dbContext); + saveDatabaseAction = new SaveDatabaseAction(basePanel, preferences, mock(BibEntryTypesManager.class)); + return saveDatabaseAction; + } + + @Test + public void saveKeepsChangedFlag() throws Exception { + BibEntry firstEntry = new BibEntry().withField(StandardField.AUTHOR, "first"); + firstEntry.setChanged(true); + BibEntry secondEntry = new BibEntry().withField(StandardField.AUTHOR, "second"); + secondEntry.setChanged(true); + BibDatabase database = new BibDatabase(List.of(firstEntry, secondEntry)); + + saveDatabaseAction = createSaveDatabaseActionForBibDatabase(database); + saveDatabaseAction.save(); + + assertEquals(database + .getEntries().stream() + .map(entry -> entry.hasChanged()).filter(changed -> false).collect(Collectors.toList()), + Collections.emptyList()); + } + @Test public void saveShouldNotSaveDatabaseIfPathNotSet() { when(dbContext.getDatabasePath()).thenReturn(Optional.empty()); diff --git a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java index f6ee7f5c92b..1d779dd50c0 100644 --- a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java +++ b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java @@ -4,11 +4,12 @@ import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; -import java.util.Scanner; import org.jabref.logic.formatter.casechanger.LowerCaseFormatter; import org.jabref.logic.formatter.casechanger.TitleCaseFormatter; @@ -332,9 +333,7 @@ void roundtripWithArticleMonths() throws Exception { new Defaults(BibDatabaseMode.BIBTEX)); databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(testBibtexFile, encoding), stringWriter.toString()); } @Test @@ -349,9 +348,7 @@ void roundtripWithComplexBib() throws Exception { new Defaults(BibDatabaseMode.BIBTEX)); databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(testBibtexFile, encoding), stringWriter.toString()); } @Test @@ -366,9 +363,7 @@ void roundtripWithUserComment() throws Exception { new Defaults(BibDatabaseMode.BIBTEX)); databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(testBibtexFile, encoding), stringWriter.toString()); } @Test @@ -386,10 +381,7 @@ void roundtripWithUserCommentAndEntryChange() throws Exception { new Defaults(BibDatabaseMode.BIBTEX)); databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - - try (Scanner scanner = new Scanner(Paths.get("src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib"), encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(Paths.get("src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib"), encoding), stringWriter.toString()); } @Test @@ -410,9 +402,7 @@ void roundtripWithUserCommentBeforeStringAndChange() throws Exception { databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(testBibtexFile, encoding), stringWriter.toString()); } @Test @@ -427,9 +417,7 @@ void roundtripWithUnknownMetaData() throws Exception { new Defaults(BibDatabaseMode.BIBTEX)); databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries()); - try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) { - assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString()); - } + assertEquals(Files.readString(testBibtexFile, encoding), stringWriter.toString()); } @Test @@ -570,7 +558,7 @@ void writeFileDirectories() throws Exception { assertEquals(OS.NEWLINE + "@Comment{jabref-meta: fileDirectory:\\\\Literature\\\\;}" + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}" - + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: fileDirectoryLatex-defaultOwner-user:D:\\\\Latex;}" + OS.NEWLINE, stringWriter.toString()); + + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: fileDirectoryLatex-defaultOwner-user:D:\\\\Latex;}" + OS.NEWLINE, stringWriter.toString()); } @Test @@ -683,4 +671,122 @@ void roundtripWithContentSelectorsAndUmlauts() throws Exception { assertEquals(fileContent, stringWriter.toString()); } + + @Test + public void saveAlsoSavesSecondModification() throws Exception { + // @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 + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + ParserResult firstParse = new BibtexParser(importFormatPreferences, new DummyFileUpdateMonitor()).parse(new StringReader(bibtexEntry)); + Collection entries = firstParse.getDatabase().getEntries(); + BibEntry entry = entries.iterator().next(); + + // modify entry + entry.setField(StandardField.AUTHOR, "BlaBla"); + + BibDatabaseContext context = new BibDatabaseContext(firstParse.getDatabase(), firstParse.getMetaData(), + new Defaults(BibDatabaseMode.BIBTEX)); + + databaseWriter.savePartOfDatabase(context, firstParse.getDatabase().getEntries()); + + // modify entry a second time + entry.setField(StandardField.AUTHOR, "Test"); + + // write a second time + stringWriter = new StringWriter(); + databaseWriter = new BibtexDatabaseWriter(stringWriter, preferences, entryTypesManager); + databaseWriter.savePartOfDatabase(context, firstParse.getDatabase().getEntries()); + + assertEquals(OS.NEWLINE + + "@Article{test," + OS.NEWLINE + + " author = {Test}," + OS.NEWLINE + + " journal = {International Journal of Something}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + + " number = {1}," + OS.NEWLINE + + "}" + OS.NEWLINE + + "" + OS.NEWLINE + + "@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString()); + } + + @Test + public void saveReturnsToOriginalEntryWhenEntryIsFlaggedUnchanged() throws Exception { + // @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 + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + ParserResult firstParse = new BibtexParser(importFormatPreferences, new DummyFileUpdateMonitor()).parse(new StringReader(bibtexEntry)); + Collection entries = firstParse.getDatabase().getEntries(); + BibEntry entry = entries.iterator().next(); + + // modify entry + entry.setField(StandardField.AUTHOR, "BlaBla"); + + // flag unchanged + entry.setChanged(false); + + // write entry + stringWriter = new StringWriter(); + databaseWriter = new BibtexDatabaseWriter(stringWriter, preferences, entryTypesManager); + BibDatabaseContext context = new BibDatabaseContext(firstParse.getDatabase(), firstParse.getMetaData(), + new Defaults(BibDatabaseMode.BIBTEX)); + databaseWriter.savePartOfDatabase(context, firstParse.getDatabase().getEntries()); + + assertEquals(bibtexEntry + OS.NEWLINE + + "@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString()); + } + + @Test + public void saveReturnsToOriginalEntryWhenEntryIsFlaggedUnchangedEvenInThePrecenseOfSavedModifications() throws Exception { + // @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 + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + ParserResult firstParse = new BibtexParser(importFormatPreferences, new DummyFileUpdateMonitor()).parse(new StringReader(bibtexEntry)); + Collection entries = firstParse.getDatabase().getEntries(); + BibEntry entry = entries.iterator().next(); + + // modify entry + entry.setField(StandardField.AUTHOR, "BlaBla"); + + BibDatabaseContext context = new BibDatabaseContext(firstParse.getDatabase(), firstParse.getMetaData(), + new Defaults(BibDatabaseMode.BIBTEX)); + + databaseWriter.savePartOfDatabase(context, firstParse.getDatabase().getEntries()); + + // modify entry a second time + entry.setField(StandardField.AUTHOR, "Test"); + + entry.setChanged(false); + + // write a second time + stringWriter = new StringWriter(); + databaseWriter = new BibtexDatabaseWriter(stringWriter, preferences, entryTypesManager); + databaseWriter.savePartOfDatabase(context, firstParse.getDatabase().getEntries()); + + // returns tu original entry, not to the last saved one + assertEquals(bibtexEntry + OS.NEWLINE + + "@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString()); + } } diff --git a/src/test/java/org/jabref/model/entry/BibEntryTest.java b/src/test/java/org/jabref/model/entry/BibEntryTest.java index 02acbfc2863..e7038e12fd7 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTest.java @@ -74,6 +74,17 @@ public void getFieldWorksWithBibFieldAsWell() throws Exception { assertEquals(Optional.of("value"), entry.getField(new BibField(StandardField.AUTHOR, FieldPriority.IMPORTANT).getField())); } + @Test + public void newBibEntryIsUnchanged() { + assertFalse(entry.hasChanged()); + } + + @Test + public void setFieldLeadsToAChangedEntry() throws Exception { + entry.setField(StandardField.AUTHOR, "value"); + assertTrue(entry.hasChanged()); + } + @Test public void setFieldWorksWithBibFieldAsWell() throws Exception { entry.setField(new BibField(StandardField.AUTHOR, FieldPriority.IMPORTANT).getField(), "value");