From 000d77395f29325e606ae140fe2635bfd6accdac Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Fri, 28 Aug 2020 10:49:42 +0200 Subject: [PATCH 1/6] Clean up commit and remove unwanted changes. Signed-off-by: Dominik Voigt --- .../org/jabref/gui/importer/ImportAction.java | 58 +------- .../gui/importer/ImportEntriesViewModel.java | 66 +-------- .../logic/bibtex/BibDatabaseMerger.java | 65 +++++++++ .../jabref/model/database/BibDatabase.java | 6 +- .../org/jabref/model/metadata/MetaData.java | 59 +++++++- .../logic/bibtex/BibDatabaseMergerTest.java | 134 ++++++++++++++++++ 6 files changed, 273 insertions(+), 115 deletions(-) create mode 100644 src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java create mode 100644 src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java diff --git a/src/main/java/org/jabref/gui/importer/ImportAction.java b/src/main/java/org/jabref/gui/importer/ImportAction.java index d49010cb6fc..5257353c1cf 100644 --- a/src/main/java/org/jabref/gui/importer/ImportAction.java +++ b/src/main/java/org/jabref/gui/importer/ImportAction.java @@ -16,6 +16,7 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.bibtex.BibDatabaseMerger; import org.jabref.logic.importer.ImportException; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.importer.Importer; @@ -23,12 +24,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.UpdateField; import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibtexString; -import org.jabref.model.groups.AllEntriesGroup; -import org.jabref.model.groups.ExplicitGroup; -import org.jabref.model.groups.GroupHierarchyType; -import org.jabref.model.metadata.ContentSelector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -135,55 +130,14 @@ private ParserResult mergeImportResults(List entries = parserResult.getDatabase().getEntries(); - resultDatabase.insertEntries(entries); + new BibDatabaseMerger().merge(resultDatabase, parserResult.getDatabase()); if (ImportFormatReader.BIBTEX_FORMAT.equals(importResult.format)) { // additional treatment of BibTeX - // merge into existing database - - // Merge strings - for (BibtexString bibtexString : parserResult.getDatabase().getStringValues()) { - String bibtexStringName = bibtexString.getName(); - if (resultDatabase.hasStringByName(bibtexStringName)) { - String importedContent = bibtexString.getContent(); - String existingContent = resultDatabase.getStringByName(bibtexStringName).get().getContent(); - if (!importedContent.equals(existingContent)) { - LOGGER.warn("String contents differ for {}: {} != {}", bibtexStringName, importedContent, existingContent); - // TODO: decide what to do here (in case the same string exits) - } - } else { - resultDatabase.addString(bibtexString); - } - } - - // Merge groups - // Adds the specified node as a child of the current root. The group contained in newGroups must not be of - // type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are - // inserted directly, i.e. they are not deepCopy()'d. - parserResult.getMetaData().getGroups().ifPresent(newGroups -> { - // ensure that there is always only one AllEntriesGroup in the resulting database - // "Rename" the AllEntriesGroup of the imported database to "Imported" - if (newGroups.getGroup() instanceof AllEntriesGroup) { - // create a dummy group - try { - // This will cause a bug if the group already exists - // There will be group where the two groups are merged - String newGroupName = importResult.parserResult.getFile().map(File::getName).orElse("unknown"); - ExplicitGroup group = new ExplicitGroup("Imported " + newGroupName, GroupHierarchyType.INDEPENDENT, - Globals.prefs.getKeywordDelimiter()); - newGroups.setGroup(group); - group.add(parserResult.getDatabase().getEntries()); - } catch (IllegalArgumentException e) { - LOGGER.error("Problem appending entries to group", e); - } - } - result.getMetaData().getGroups().ifPresent(newGroups::moveTo); - }); - - for (ContentSelector selector : parserResult.getMetaData().getContentSelectorList()) { - result.getMetaData().addContentSelector(selector); - } + result.getMetaData().merge( + parserResult.getMetaData(), + importResult.parserResult.getFile().map(File::getName).orElse("unknown"), + parserResult.getDatabase().getEntries()); } // TODO: collect errors into ParserResult, because they are currently ignored (see caller of this method) } diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index 2c12cd4cda4..d3027160022 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -1,5 +1,6 @@ package org.jabref.gui.importer; +import java.io.File; import java.util.List; import java.util.Optional; @@ -19,23 +20,16 @@ import org.jabref.gui.externalfiles.ImportHandler; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.fieldeditors.LinkedFileViewModel; -import org.jabref.gui.groups.GroupTreeNodeViewModel; -import org.jabref.gui.groups.UndoableAddOrRemoveGroup; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableInsertEntries; -import org.jabref.gui.undo.UndoableInsertString; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.bibtex.BibDatabaseMerger; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibtexString; import org.jabref.model.entry.LinkedFile; -import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.metadata.FilePreferences; -import org.jabref.model.metadata.MetaData; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; @@ -145,58 +139,12 @@ public void importEntries(List entriesToImport, boolean shouldDownload } } - NamedCompound namedCompound = new NamedCompound(Localization.lang("Import file")); - namedCompound.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), entriesToImport)); + new BibDatabaseMerger().mergeStrings(databaseContext.getDatabase(), parserResult.getDatabase()); + databaseContext.getMetaData().merge( + parserResult.getMetaData(), + parserResult.getFile().map(File::getName).orElse("unknown"), + parserResult.getDatabase().getEntries()); - // merge strings into target database - for (BibtexString bibtexString : parserResult.getDatabase().getStringValues()) { - String bibtexStringName = bibtexString.getName(); - if (databaseContext.getDatabase().hasStringByName(bibtexStringName)) { - String importedContent = bibtexString.getContent(); - String existingContent = databaseContext.getDatabase().getStringByName(bibtexStringName).get().getContent(); - if (!importedContent.equals(existingContent)) { - LOGGER.warn("String contents differ for {}: {} != {}", bibtexStringName, importedContent, existingContent); - // TODO: decide what to do here (in case the same string exits) - } - } else { - databaseContext.getDatabase().addString(bibtexString); - // FIXME: this prevents this method to be moved to logic - we need to implement a new undo/redo data model - namedCompound.addEdit(new UndoableInsertString(databaseContext.getDatabase(), bibtexString)); - } - } - - // copy content selectors to target database - MetaData targetMetada = databaseContext.getMetaData(); - parserResult.getMetaData() - .getContentSelectorList() - .forEach(targetMetada::addContentSelector); - // TODO undo of content selectors (currently not implemented) - - // copy groups to target database - parserResult.getMetaData().getGroups().ifPresent( - newGroupsTreeNode -> { - if (targetMetada.getGroups().isPresent()) { - GroupTreeNode groupTreeNode = targetMetada.getGroups().get(); - newGroupsTreeNode.moveTo(groupTreeNode); - namedCompound.addEdit( - new UndoableAddOrRemoveGroup( - new GroupTreeNodeViewModel(groupTreeNode), - new GroupTreeNodeViewModel(newGroupsTreeNode), - UndoableAddOrRemoveGroup.ADD_NODE)); - } else { - // target does not contain any groups, so we can just use the new groups - targetMetada.setGroups(newGroupsTreeNode); - namedCompound.addEdit( - new UndoableAddOrRemoveGroup( - new GroupTreeNodeViewModel(newGroupsTreeNode), - new GroupTreeNodeViewModel(newGroupsTreeNode), - UndoableAddOrRemoveGroup.ADD_NODE)); - } - } - ); - - namedCompound.end(); - Globals.undoManager.addEdit(namedCompound); JabRefGUI.getMainFrame().getCurrentBasePanel().markBaseChanged(); } diff --git a/src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java b/src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java new file mode 100644 index 00000000000..14601526bfb --- /dev/null +++ b/src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java @@ -0,0 +1,65 @@ +package org.jabref.logic.bibtex; + +import java.util.List; +import java.util.stream.Collectors; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseModeDetection; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibEntryTypesManager; +import org.jabref.model.entry.BibtexString; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BibDatabaseMerger { + + private static final Logger LOGGER = LoggerFactory.getLogger(BibDatabaseMerger.class); + + /** + * Merges all entries and strings of the other database into the target database. Any duplicates are ignored. + * In case a string has a different content, it is added with a new unique name. + * The unique name is generated by suffix "_i", where i runs from 1 onwards. + * + * @param other The other databases that is merged into this database + */ + public synchronized void merge(BibDatabase target, BibDatabase other) { + mergeEntries(target, other); + mergeStrings(target, other); + } + + private void mergeEntries(BibDatabase target, BibDatabase other) { + DuplicateCheck duplicateCheck = new DuplicateCheck(new BibEntryTypesManager()); + List newEntries = other.getEntries().stream() + // Remove all entries that are already part of the database (duplicate) + .filter(entry -> duplicateCheck.containsDuplicate(target, entry, BibDatabaseModeDetection.inferMode(target)).isEmpty()) + .collect(Collectors.toList()); + target.insertEntries(newEntries); + } + + public void mergeStrings(BibDatabase target, BibDatabase other) { + for (BibtexString bibtexString : other.getStringValues()) { + String bibtexStringName = bibtexString.getName(); + if (target.hasStringByName(bibtexStringName)) { + String importedContent = bibtexString.getContent(); + String existingContent = target.getStringByName(bibtexStringName).get().getContent(); + if (!importedContent.equals(existingContent)) { + LOGGER.info("String contents differ for {}: {} != {}", bibtexStringName, importedContent, existingContent); + int suffix = 1; + String newName = bibtexStringName + "_" + suffix; + while (target.hasStringByName(newName)) { + suffix++; + newName = bibtexStringName + "_" + suffix; + } + BibtexString newBibtexString = new BibtexString(newName, importedContent); + // TODO undo/redo + target.addString(newBibtexString); + LOGGER.info("New string added: {} = {}", newBibtexString.getName(), newBibtexString.getContent()); + } + } else { + // TODO undo/redo + target.addString(bibtexString); + } + } + } +} diff --git a/src/main/java/org/jabref/model/database/BibDatabase.java b/src/main/java/org/jabref/model/database/BibDatabase.java index 7ba57bf2efc..d609f5a9b8a 100644 --- a/src/main/java/org/jabref/model/database/BibDatabase.java +++ b/src/main/java/org/jabref/model/database/BibDatabase.java @@ -548,9 +548,9 @@ public void setEpilog(String epilog) { * Registers an listener object (subscriber) to the internal event bus. * The following events are posted: * - * - {@link EntryAddedEvent} - * - {@link EntryChangedEvent} - * - {@link EntriesRemovedEvent} + * - {@link EntriesAddedEvent} + * - {@link EntryChangedEvent} + * - {@link EntriesRemovedEvent} * * @param listener listener (subscriber) to add */ diff --git a/src/main/java/org/jabref/model/metadata/MetaData.java b/src/main/java/org/jabref/model/metadata/MetaData.java index c76442373fc..2287fdb7ad7 100644 --- a/src/main/java/org/jabref/model/metadata/MetaData.java +++ b/src/main/java/org/jabref/model/metadata/MetaData.java @@ -15,13 +15,20 @@ import org.jabref.model.cleanup.FieldFormatterCleanups; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.event.ChangePropagation; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.types.EntryType; +import org.jabref.model.groups.AllEntriesGroup; +import org.jabref.model.groups.ExplicitGroup; +import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.event.GroupUpdatedEvent; import org.jabref.model.metadata.event.MetaDataChangedEvent; +import org.jabref.preferences.JabRefPreferences; import com.google.common.eventbus.EventBus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MetaData { @@ -41,6 +48,8 @@ public class MetaData { public static final char SEPARATOR_CHARACTER = ';'; public static final String SEPARATOR_STRING = String.valueOf(SEPARATOR_CHARACTER); + private static final Logger LOGGER = LoggerFactory.getLogger(MetaData.class); + private final EventBus eventBus = new EventBus(); private final Map citeKeyPatterns = new HashMap<>(); // private final Map userFileDirectory = new HashMap<>(); // @@ -245,6 +254,54 @@ public void clearSaveOrderConfig() { postChange(); } + /** + * @param other the metaData to merge into this one + * @param otherFilename the filename of the other library. Pass "unknown" if not known. + * @param allOtherEntries list of all other entries + */ + public void merge(MetaData other, String otherFilename, List allOtherEntries) { + Objects.requireNonNull(other); + Objects.requireNonNull(otherFilename); + Objects.requireNonNull(allOtherEntries); + + mergeGroups(other, otherFilename, allOtherEntries); + mergeContentSelectors(other); + } + + private void mergeGroups(MetaData other, String otherFilename, List allOtherEntries) { + // Adds the specified node as a child of the current root. The group contained in newGroups must not be of + // type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are + // inserted directly, i.e. they are not deepCopy()'d. + other.getGroups().ifPresent(newGroups -> { + // ensure that there is always only one AllEntriesGroup in the resulting database + // "Rename" the AllEntriesGroup of the imported database to "Imported" + if (newGroups.getGroup() instanceof AllEntriesGroup) { + // create a dummy group + try { + // This will cause a bug if the group already exists + // There will be group where the two groups are merged + String newGroupName = otherFilename; + ExplicitGroup group = new ExplicitGroup("Imported " + newGroupName, GroupHierarchyType.INDEPENDENT, + JabRefPreferences.getInstance().getKeywordDelimiter()); + newGroups.setGroup(group); + group.add(allOtherEntries); + } catch (IllegalArgumentException e) { + LOGGER.error("Problem appending entries to group", e); + } + } + this.getGroups().ifPresentOrElse( + newGroups::moveTo, + // target does not contain any groups, so we can just use the new groups + () -> this.setGroups(newGroups)); + }); + } + + private void mergeContentSelectors(MetaData other) { + for (ContentSelector selector : other.getContentSelectorList()) { + this.addContentSelector(selector); + } + } + /** * Posts a new {@link MetaDataChangedEvent} on the {@link EventBus}. */ @@ -266,7 +323,7 @@ public void setEncoding(Charset encoding) { } /** - * This Method (with additional parameter) has been introduced to avoid event loops while saving a database. + * This method (with additional parameter) has been introduced to avoid event loops while saving a database. */ public void setEncoding(Charset encoding, ChangePropagation postChanges) { this.encoding = Objects.requireNonNull(encoding); diff --git a/src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java b/src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java new file mode 100644 index 00000000000..c1b8297bb12 --- /dev/null +++ b/src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java @@ -0,0 +1,134 @@ +package org.jabref.logic.bibtex; + +import java.util.List; +import java.util.stream.Collectors; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibtexString; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BibDatabaseMergerTest { + + @Test + void mergeAddsNonDuplicateEntries() { + // Entries 2 and 3 are identical + BibEntry entry1 = new BibEntry() + .withField(StandardField.AUTHOR, "Stephen Blaha") + .withField(StandardField.TITLE, "Quantum Computers and Quantum Computer Languages: Quantum Assembly Language and Quantum C Language") + .withField(StandardField.DATE, "2002-01-18") + .withField(StandardField.ABSTRACT, "We show a representation of Quantum Computers defines Quantum Turing Machines with associated Quantum Grammars. We then create examples of Quantum Grammars. Lastly we develop an algebraic approach to high level Quantum Languages using Quantum Assembly language and Quantum C language as examples.") + .withField(StandardField.EPRINT, "quant-ph/0201082") + .withField(StandardField.FILE, ":http\\://arxiv.org/pdf/quant-ph/0201082v1:PDF") + .withField(StandardField.EPRINTTYPE, "arXiv") + .withField(StandardField.EPRINTCLASS, "quant-ph") + .withField(StandardField.KEYWORDS, "quant-ph, cs.PL"); + entry1.setType(StandardEntryType.Article); + BibEntry entry2 = new BibEntry() + .withField(StandardField.AUTHOR, "Phillip Kaye and Michele Mosca") + .withField(StandardField.TITLE, "Quantum Networks for Generating Arbitrary Quantum States") + .withField(StandardField.DATE, "2004-07-14") + .withField(StandardField.ABSTRACT, "Quantum protocols often require the generation of specific quantum states. We describe a quantum algorithm for generating any prescribed quantum state. For an important subclass of states, including pure symmetric states, this algorithm is efficient.") + .withField(StandardField.EPRINT, "quant-ph/0407102") + .withField(StandardField.FILE, ":http\\://arxiv.org/pdf/quant-ph/0407102v1:PDF") + .withField(StandardField.EPRINTTYPE, "arXiv") + .withField(StandardField.EPRINTCLASS, "quant-ph") + .withField(StandardField.KEYWORDS, "quant-ph") + .withField(StandardField.JOURNALTITLE, "Phillip Kaye, Michele Mosca, \"Quantum Networks for Generating Arbitrary Quantum States\", Proceedings, International Conference on Quantum Information (ICQI). Rochester, New York, USA, 2001"); + entry2.setType(StandardEntryType.Article); + BibEntry entry3 = new BibEntry() + .withField(StandardField.AUTHOR, "Phillip Kaye and Michele Mosca") + .withField(StandardField.TITLE, "Quantum Networks for Generating Arbitrary Quantum States") + .withField(StandardField.DATE, "2004-07-14") + .withField(StandardField.ABSTRACT, "Quantum protocols often require the generation of specific quantum states. We describe a quantum algorithm for generating any prescribed quantum state. For an important subclass of states, including pure symmetric states, this algorithm is efficient.") + .withField(StandardField.EPRINT, "quant-ph/0407102") + .withField(StandardField.FILE, ":http\\://arxiv.org/pdf/quant-ph/0407102v1:PDF") + .withField(StandardField.EPRINTTYPE, "arXiv") + .withField(StandardField.EPRINTCLASS, "quant-ph") + .withField(StandardField.KEYWORDS, "quant-ph") + .withField(StandardField.JOURNALTITLE, "Phillip Kaye, Michele Mosca, \"Quantum Networks for Generating Arbitrary Quantum States\", Proceedings, International Conference on Quantum Information (ICQI). Rochester, New York, USA, 2001"); + entry3.setType(StandardEntryType.Article); + BibEntry entry4 = new BibEntry() + .withField(StandardField.AUTHOR, "John Watrous") + .withField(StandardField.TITLE, "Quantum Computational Complexity") + .withField(StandardField.DATE, "2008-04-21") + .withField(StandardField.ABSTRACT, "This article surveys quantum computational complexity, with a focus on three fundamental notions: polynomial-time quantum computations, the efficient verification of quantum proofs, and quantum interactive proof systems. Properties of quantum complexity classes based on these notions, such as BQP, QMA, and QIP, are presented. Other topics in quantum complexity, including quantum advice, space-bounded quantum computation, and bounded-depth quantum circuits, are also discussed.") + .withField(StandardField.EPRINT, "0804.3401") + .withField(StandardField.FILE, ":http\\://arxiv.org/pdf/0804.3401v1:PDF") + .withField(StandardField.EPRINTTYPE, "arXiv") + .withField(StandardField.EPRINTCLASS, "quant-ph") + .withField(StandardField.KEYWORDS, "quant-ph"); + entry4.setType(StandardEntryType.Article); + + BibDatabase database = new BibDatabase(List.of(entry1, entry2)); + BibDatabase other = new BibDatabase(List.of(entry3, entry4)); + new BibDatabaseMerger().merge(database, other); + + assertEquals(3, database.getEntries().size()); + assertEquals(List.of(entry1, entry3, entry4), database.getEntries()); + } + + @Test + void mergeBibTexStringsWithSameNameAreImportedWithModifiedName() { + BibtexString targetString = new BibtexString("name", "content1"); + + // BibTeXStrings that are imported from two sources (same name different content) + BibtexString sourceString1 = new BibtexString("name", "content2"); + BibtexString sourceString2 = new BibtexString("name", "content3"); + + // The expected source BibTeXStrings after import (different name, different content) + BibtexString importedBibTeXString1 = new BibtexString("name_1", "content2"); + BibtexString importedBibTeXString2 = new BibtexString("name_2", "content3"); + + BibDatabase target = new BibDatabase(); + BibDatabase source1 = new BibDatabase(); + BibDatabase source2 = new BibDatabase(); + target.addString(targetString); + source1.addString(sourceString1); + source2.addString(sourceString2); + + new BibDatabaseMerger().mergeStrings(target, source1); + new BibDatabaseMerger().mergeStrings(target, source2); + // Use string representation to compare since the id will not match + List resultStringsSorted = target.getStringValues() + .stream() + .map(BibtexString::toString) + .sorted() + .collect(Collectors.toList()); + + assertEquals(List.of(targetString.toString(), importedBibTeXString1.toString(), + importedBibTeXString2.toString()), resultStringsSorted); + } + + @Test + void mergeBibTexStringsWithSameNameAndContentAreIgnored() { + BibtexString targetString1 = new BibtexString("name1", "content1"); + BibtexString targetString2 = new BibtexString("name2", "content2"); + + // BibTeXStrings that are imported (equivalent to target strings) + BibtexString sourceString1 = new BibtexString("name1", "content1"); + BibtexString sourceString2 = new BibtexString("name2", "content2"); + + BibDatabase target = new BibDatabase(); + BibDatabase source = new BibDatabase(); + target.addString(targetString1); + target.addString(targetString2); + source.addString(sourceString1); + source.addString(sourceString2); + + new BibDatabaseMerger().mergeStrings(target, source); + // Use string representation to compare since the id will not match + List resultStringsSorted = target.getStringValues() + .stream() + .map(BibtexString::toString) + .sorted() + .collect(Collectors.toList()); + + assertEquals(List.of(targetString1.toString(), targetString2.toString()), resultStringsSorted); + } +} From dda5e45516560315183718f8b46a5965d5c612a1 Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 29 Aug 2020 14:02:45 +0200 Subject: [PATCH 2/6] Move Merger and DuplicateCheck into database package Signed-off-by: Dominik Voigt --- src/main/java/org/jabref/gui/EntryTypeViewModel.java | 2 +- .../gui/duplicationFinder/DuplicateSearch.java | 2 +- .../java/org/jabref/gui/importer/ImportAction.java | 3 +-- .../jabref/gui/importer/ImportEntriesViewModel.java | 6 +++--- .../logic/bibtex/comparator/BibDatabaseDiff.java | 2 +- .../DatabaseMerger.java} | 6 +++--- .../logic/{bibtex => database}/DuplicateCheck.java | 2 +- .../DatabaseMergerTest.java} | 12 ++++++------ .../{bibtex => database}/DuplicateCheckTest.java | 2 +- 9 files changed, 18 insertions(+), 19 deletions(-) rename src/main/java/org/jabref/logic/{bibtex/BibDatabaseMerger.java => database/DatabaseMerger.java} (96%) rename src/main/java/org/jabref/logic/{bibtex => database}/DuplicateCheck.java (99%) rename src/test/java/org/jabref/logic/{bibtex/BibDatabaseMergerTest.java => database/DatabaseMergerTest.java} (96%) rename src/test/java/org/jabref/logic/{bibtex => database}/DuplicateCheckTest.java (99%) diff --git a/src/main/java/org/jabref/gui/EntryTypeViewModel.java b/src/main/java/org/jabref/gui/EntryTypeViewModel.java index 2326c66cf7e..c8b11e5e1e7 100644 --- a/src/main/java/org/jabref/gui/EntryTypeViewModel.java +++ b/src/main/java/org/jabref/gui/EntryTypeViewModel.java @@ -16,8 +16,8 @@ import org.jabref.Globals; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog; -import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.citationkeypattern.CitationKeyGenerator; +import org.jabref.logic.database.DuplicateCheck; import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.IdBasedFetcher; import org.jabref.logic.importer.WebFetchers; diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index eeb4528de9f..9f5c778e677 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -25,7 +25,7 @@ import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.logic.bibtex.DuplicateCheck; +import org.jabref.logic.database.DuplicateCheck; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; diff --git a/src/main/java/org/jabref/gui/importer/ImportAction.java b/src/main/java/org/jabref/gui/importer/ImportAction.java index 5257353c1cf..9ba50daa546 100644 --- a/src/main/java/org/jabref/gui/importer/ImportAction.java +++ b/src/main/java/org/jabref/gui/importer/ImportAction.java @@ -16,7 +16,6 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; -import org.jabref.logic.bibtex.BibDatabaseMerger; import org.jabref.logic.importer.ImportException; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.importer.Importer; @@ -130,7 +129,7 @@ private ParserResult mergeImportResults(List entriesToImport, boolean shouldDownload } } - new BibDatabaseMerger().mergeStrings(databaseContext.getDatabase(), parserResult.getDatabase()); + new DatabaseMerger().mergeStrings(databaseContext.getDatabase(), parserResult.getDatabase()); databaseContext.getMetaData().merge( parserResult.getMetaData(), parserResult.getFile().map(File::getName).orElse("unknown"), diff --git a/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java b/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java index e3435b7ac7b..44ff461ee73 100644 --- a/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java +++ b/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java @@ -7,7 +7,7 @@ import java.util.Optional; import java.util.Set; -import org.jabref.logic.bibtex.DuplicateCheck; +import org.jabref.logic.database.DuplicateCheck; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; diff --git a/src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java b/src/main/java/org/jabref/logic/database/DatabaseMerger.java similarity index 96% rename from src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java rename to src/main/java/org/jabref/logic/database/DatabaseMerger.java index 14601526bfb..56d36638219 100644 --- a/src/main/java/org/jabref/logic/bibtex/BibDatabaseMerger.java +++ b/src/main/java/org/jabref/logic/database/DatabaseMerger.java @@ -1,4 +1,4 @@ -package org.jabref.logic.bibtex; +package org.jabref.logic.database; import java.util.List; import java.util.stream.Collectors; @@ -12,9 +12,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BibDatabaseMerger { +public class DatabaseMerger { - private static final Logger LOGGER = LoggerFactory.getLogger(BibDatabaseMerger.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseMerger.class); /** * Merges all entries and strings of the other database into the target database. Any duplicates are ignored. diff --git a/src/main/java/org/jabref/logic/bibtex/DuplicateCheck.java b/src/main/java/org/jabref/logic/database/DuplicateCheck.java similarity index 99% rename from src/main/java/org/jabref/logic/bibtex/DuplicateCheck.java rename to src/main/java/org/jabref/logic/database/DuplicateCheck.java index d601b92a41f..ec82b223d4d 100644 --- a/src/main/java/org/jabref/logic/bibtex/DuplicateCheck.java +++ b/src/main/java/org/jabref/logic/database/DuplicateCheck.java @@ -1,4 +1,4 @@ -package org.jabref.logic.bibtex; +package org.jabref.logic.database; import java.util.Collection; import java.util.HashMap; diff --git a/src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java similarity index 96% rename from src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java rename to src/test/java/org/jabref/logic/database/DatabaseMergerTest.java index c1b8297bb12..d0c6cbc6e19 100644 --- a/src/test/java/org/jabref/logic/bibtex/BibDatabaseMergerTest.java +++ b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.bibtex; +package org.jabref.logic.database; import java.util.List; import java.util.stream.Collectors; @@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -class BibDatabaseMergerTest { +class DatabaseMergerTest { @Test void mergeAddsNonDuplicateEntries() { @@ -67,7 +67,7 @@ void mergeAddsNonDuplicateEntries() { BibDatabase database = new BibDatabase(List.of(entry1, entry2)); BibDatabase other = new BibDatabase(List.of(entry3, entry4)); - new BibDatabaseMerger().merge(database, other); + new DatabaseMerger().merge(database, other); assertEquals(3, database.getEntries().size()); assertEquals(List.of(entry1, entry3, entry4), database.getEntries()); @@ -92,8 +92,8 @@ void mergeBibTexStringsWithSameNameAreImportedWithModifiedName() { source1.addString(sourceString1); source2.addString(sourceString2); - new BibDatabaseMerger().mergeStrings(target, source1); - new BibDatabaseMerger().mergeStrings(target, source2); + new DatabaseMerger().mergeStrings(target, source1); + new DatabaseMerger().mergeStrings(target, source2); // Use string representation to compare since the id will not match List resultStringsSorted = target.getStringValues() .stream() @@ -121,7 +121,7 @@ void mergeBibTexStringsWithSameNameAndContentAreIgnored() { source.addString(sourceString1); source.addString(sourceString2); - new BibDatabaseMerger().mergeStrings(target, source); + new DatabaseMerger().mergeStrings(target, source); // Use string representation to compare since the id will not match List resultStringsSorted = target.getStringValues() .stream() diff --git a/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java b/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java similarity index 99% rename from src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java rename to src/test/java/org/jabref/logic/database/DuplicateCheckTest.java index a4dddfacea5..6e76c89d14f 100644 --- a/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java +++ b/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.bibtex; +package org.jabref.logic.database; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; From 6cc4e7749f0d690f70eda77af6ffe7dd93b368cf Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 29 Aug 2020 14:45:24 +0200 Subject: [PATCH 3/6] Move meta data merging into DatabaseMerger Add DatabaseContext merging capability to DatabaseMerger Signed-off-by: Dominik Voigt --- .../org/jabref/gui/importer/ImportAction.java | 4 +- .../gui/importer/ImportEntriesViewModel.java | 2 +- .../jabref/logic/database/DatabaseMerger.java | 69 +++++++++++++++++++ .../org/jabref/model/metadata/MetaData.java | 53 -------------- 4 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportAction.java b/src/main/java/org/jabref/gui/importer/ImportAction.java index 9ba50daa546..badede2b39b 100644 --- a/src/main/java/org/jabref/gui/importer/ImportAction.java +++ b/src/main/java/org/jabref/gui/importer/ImportAction.java @@ -16,6 +16,7 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.database.DatabaseMerger; import org.jabref.logic.importer.ImportException; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.importer.Importer; @@ -133,7 +134,8 @@ private ParserResult mergeImportResults(List entriesToImport, boolean shouldDownload } new DatabaseMerger().mergeStrings(databaseContext.getDatabase(), parserResult.getDatabase()); - databaseContext.getMetaData().merge( + new DatabaseMerger().mergeMetaData(databaseContext.getMetaData(), parserResult.getMetaData(), parserResult.getFile().map(File::getName).orElse("unknown"), parserResult.getDatabase().getEntries()); diff --git a/src/main/java/org/jabref/logic/database/DatabaseMerger.java b/src/main/java/org/jabref/logic/database/DatabaseMerger.java index 56d36638219..dae09f8a591 100644 --- a/src/main/java/org/jabref/logic/database/DatabaseMerger.java +++ b/src/main/java/org/jabref/logic/database/DatabaseMerger.java @@ -1,13 +1,21 @@ package org.jabref.logic.database; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseModeDetection; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.entry.BibtexString; +import org.jabref.model.groups.AllEntriesGroup; +import org.jabref.model.groups.ExplicitGroup; +import org.jabref.model.groups.GroupHierarchyType; +import org.jabref.model.metadata.ContentSelector; +import org.jabref.model.metadata.MetaData; +import org.jabref.preferences.JabRefPreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +36,19 @@ public synchronized void merge(BibDatabase target, BibDatabase other) { mergeStrings(target, other); } + /** + * Merges all entries, strings, and metaData of the other database context into the target database context. Any duplicates are ignored. + * In case a string has a different content, it is added with a new unique name. + * The unique name is generated by suffix "_i", where i runs from 1 onwards. + * + * @param other The other databases that is merged into this database + */ + public synchronized void merge(BibDatabaseContext target, BibDatabaseContext other, String otherFileName) { + mergeEntries(target.getDatabase(), other.getDatabase()); + mergeStrings(target.getDatabase(), other.getDatabase()); + mergeMetaData(target.getMetaData(), other.getMetaData(), otherFileName, other.getEntries()); + } + private void mergeEntries(BibDatabase target, BibDatabase other) { DuplicateCheck duplicateCheck = new DuplicateCheck(new BibEntryTypesManager()); List newEntries = other.getEntries().stream() @@ -62,4 +83,52 @@ public void mergeStrings(BibDatabase target, BibDatabase other) { } } } + + /** + * @param target the metaData that is the merge target + * @param other the metaData to merge into the target + * @param otherFilename the filename of the other library. Pass "unknown" if not known. + */ + public void mergeMetaData(MetaData target, MetaData other, String otherFilename, List allOtherEntries) { + Objects.requireNonNull(other); + Objects.requireNonNull(otherFilename); + Objects.requireNonNull(allOtherEntries); + + mergeGroups(target, other, otherFilename, allOtherEntries); + mergeContentSelectors(target, other); + } + + private void mergeGroups(MetaData target, MetaData other, String otherFilename, List allOtherEntries) { + // Adds the specified node as a child of the current root. The group contained in newGroups must not be of + // type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are + // inserted directly, i.e. they are not deepCopy()'d. + other.getGroups().ifPresent(newGroups -> { + // ensure that there is always only one AllEntriesGroup in the resulting database + // "Rename" the AllEntriesGroup of the imported database to "Imported" + if (newGroups.getGroup() instanceof AllEntriesGroup) { + // create a dummy group + try { + // This will cause a bug if the group already exists + // There will be group where the two groups are merged + String newGroupName = otherFilename; + ExplicitGroup group = new ExplicitGroup("Imported " + newGroupName, GroupHierarchyType.INDEPENDENT, + JabRefPreferences.getInstance().getKeywordDelimiter()); + newGroups.setGroup(group); + group.add(allOtherEntries); + } catch (IllegalArgumentException e) { + LOGGER.error("Problem appending entries to group", e); + } + } + target.getGroups().ifPresentOrElse( + newGroups::moveTo, + // target does not contain any groups, so we can just use the new groups + () -> target.setGroups(newGroups)); + }); + } + + private void mergeContentSelectors(MetaData target, MetaData other) { + for (ContentSelector selector : other.getContentSelectorList()) { + target.addContentSelector(selector); + } + } } diff --git a/src/main/java/org/jabref/model/metadata/MetaData.java b/src/main/java/org/jabref/model/metadata/MetaData.java index 2287fdb7ad7..e1c409a22e8 100644 --- a/src/main/java/org/jabref/model/metadata/MetaData.java +++ b/src/main/java/org/jabref/model/metadata/MetaData.java @@ -15,16 +15,11 @@ import org.jabref.model.cleanup.FieldFormatterCleanups; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.event.ChangePropagation; -import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.types.EntryType; -import org.jabref.model.groups.AllEntriesGroup; -import org.jabref.model.groups.ExplicitGroup; -import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.event.GroupUpdatedEvent; import org.jabref.model.metadata.event.MetaDataChangedEvent; -import org.jabref.preferences.JabRefPreferences; import com.google.common.eventbus.EventBus; import org.slf4j.Logger; @@ -254,54 +249,6 @@ public void clearSaveOrderConfig() { postChange(); } - /** - * @param other the metaData to merge into this one - * @param otherFilename the filename of the other library. Pass "unknown" if not known. - * @param allOtherEntries list of all other entries - */ - public void merge(MetaData other, String otherFilename, List allOtherEntries) { - Objects.requireNonNull(other); - Objects.requireNonNull(otherFilename); - Objects.requireNonNull(allOtherEntries); - - mergeGroups(other, otherFilename, allOtherEntries); - mergeContentSelectors(other); - } - - private void mergeGroups(MetaData other, String otherFilename, List allOtherEntries) { - // Adds the specified node as a child of the current root. The group contained in newGroups must not be of - // type AllEntriesGroup, since every tree has exactly one AllEntriesGroup (its root). The newGroups are - // inserted directly, i.e. they are not deepCopy()'d. - other.getGroups().ifPresent(newGroups -> { - // ensure that there is always only one AllEntriesGroup in the resulting database - // "Rename" the AllEntriesGroup of the imported database to "Imported" - if (newGroups.getGroup() instanceof AllEntriesGroup) { - // create a dummy group - try { - // This will cause a bug if the group already exists - // There will be group where the two groups are merged - String newGroupName = otherFilename; - ExplicitGroup group = new ExplicitGroup("Imported " + newGroupName, GroupHierarchyType.INDEPENDENT, - JabRefPreferences.getInstance().getKeywordDelimiter()); - newGroups.setGroup(group); - group.add(allOtherEntries); - } catch (IllegalArgumentException e) { - LOGGER.error("Problem appending entries to group", e); - } - } - this.getGroups().ifPresentOrElse( - newGroups::moveTo, - // target does not contain any groups, so we can just use the new groups - () -> this.setGroups(newGroups)); - }); - } - - private void mergeContentSelectors(MetaData other) { - for (ContentSelector selector : other.getContentSelectorList()) { - this.addContentSelector(selector); - } - } - /** * Posts a new {@link MetaDataChangedEvent} on the {@link EventBus}. */ From fe9d46c5b38d302abcc638ca8d95028987220150 Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 29 Aug 2020 15:35:47 +0200 Subject: [PATCH 4/6] Add one meta data merge test (unfinished) Signed-off-by: Dominik Voigt --- .../logic/database/DatabaseMergerTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java index d0c6cbc6e19..11cdae38a4d 100644 --- a/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java +++ b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java @@ -1,5 +1,6 @@ package org.jabref.logic.database; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -8,6 +9,11 @@ import org.jabref.model.entry.BibtexString; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.groups.AbstractGroup; +import org.jabref.model.groups.GroupHierarchyType; +import org.jabref.model.groups.GroupTreeNode; +import org.jabref.model.metadata.ContentSelector; +import org.jabref.model.metadata.MetaData; import org.junit.jupiter.api.Test; @@ -131,4 +137,53 @@ void mergeBibTexStringsWithSameNameAndContentAreIgnored() { assertEquals(List.of(targetString1.toString(), targetString2.toString()), resultStringsSorted); } + + @Test + void mergeMetaDataWithoutAllEntriesGroup() { + MetaData target = new MetaData(); + target.addContentSelector(new ContentSelector(StandardField.AUTHOR, List.of("Test Author"))); + GroupTreeNode targetRootGroup = new GroupTreeNode(new TestGroup("targetGroup", GroupHierarchyType.INDEPENDENT)); + target.setGroups(targetRootGroup); + MetaData other = new MetaData(); + GroupTreeNode otherRootGroup = new GroupTreeNode(new TestGroup("otherGroup", GroupHierarchyType.INCLUDING)); + other.setGroups(otherRootGroup); + other.addContentSelector(new ContentSelector(StandardField.TITLE, List.of("Test Title"))); + List expectedContentSelectors = + List.of(new ContentSelector(StandardField.AUTHOR, List.of("Test Author")), + new ContentSelector(StandardField.TITLE, List.of("Test Title"))); + + new DatabaseMerger().mergeMetaData(target, other, "unknown", List.of()); + + // Assert that content selectors are all merged + List sortedResultSelectors = target.getContentSelectorList(); + sortedResultSelectors.sort(Comparator.comparing(contentSelector -> contentSelector.getField().getName())); + assertEquals(expectedContentSelectors, sortedResultSelectors); + + // Assert that groups of other are children of root node of target + assertEquals(targetRootGroup, target.getGroups().get()); + assertEquals(target.getGroups().get().getChildren().size(), 1); + assertEquals(otherRootGroup, target.getGroups().get().getChildren().get(0)); + } + + static class TestGroup extends AbstractGroup { + + protected TestGroup(String name, GroupHierarchyType context) { + super(name, context); + } + + @Override + public boolean contains(BibEntry entry) { + return false; + } + + @Override + public boolean isDynamic() { + return false; + } + + @Override + public AbstractGroup deepCopy() { + return null; + } + } } From 70c8dbaaa9ae10be546536c138acaf29d4979903 Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 29 Aug 2020 16:21:46 +0200 Subject: [PATCH 5/6] Add meta data merging tests. Signed-off-by: Dominik Voigt --- .../logic/database/DatabaseMergerTest.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java index 11cdae38a4d..9b6ac9d5859 100644 --- a/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java +++ b/src/test/java/org/jabref/logic/database/DatabaseMergerTest.java @@ -1,6 +1,5 @@ package org.jabref.logic.database; -import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -10,10 +9,13 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; import org.jabref.model.groups.AbstractGroup; +import org.jabref.model.groups.AllEntriesGroup; +import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.metadata.ContentSelector; import org.jabref.model.metadata.MetaData; +import org.jabref.preferences.JabRefPreferences; import org.junit.jupiter.api.Test; @@ -155,9 +157,7 @@ void mergeMetaDataWithoutAllEntriesGroup() { new DatabaseMerger().mergeMetaData(target, other, "unknown", List.of()); // Assert that content selectors are all merged - List sortedResultSelectors = target.getContentSelectorList(); - sortedResultSelectors.sort(Comparator.comparing(contentSelector -> contentSelector.getField().getName())); - assertEquals(expectedContentSelectors, sortedResultSelectors); + assertEquals(expectedContentSelectors, target.getContentSelectorList()); // Assert that groups of other are children of root node of target assertEquals(targetRootGroup, target.getGroups().get()); @@ -165,6 +165,29 @@ void mergeMetaDataWithoutAllEntriesGroup() { assertEquals(otherRootGroup, target.getGroups().get().getChildren().get(0)); } + @Test + void mergeMetaDataWithAllEntriesGroup() { + MetaData target = new MetaData(); + target.addContentSelector(new ContentSelector(StandardField.AUTHOR, List.of("Test Author"))); + GroupTreeNode targetRootGroup = new GroupTreeNode(new AllEntriesGroup("targetGroup")); + target.setGroups(targetRootGroup); + MetaData other = new MetaData(); + GroupTreeNode otherRootGroup = new GroupTreeNode(new AllEntriesGroup("otherGroup")); + other.setGroups(otherRootGroup); + other.addContentSelector(new ContentSelector(StandardField.TITLE, List.of("Test Title"))); + List expectedContentSelectors = + List.of(new ContentSelector(StandardField.AUTHOR, List.of("Test Author")), + new ContentSelector(StandardField.TITLE, List.of("Test Title"))); + GroupTreeNode expectedImportedGroupNode = new GroupTreeNode(new ExplicitGroup("Imported unknown", GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance().getKeywordDelimiter())); + + new DatabaseMerger().mergeMetaData(target, other, "unknown", List.of()); + + // Assert that groups of other are children of root node of target + assertEquals(targetRootGroup, target.getGroups().get()); + assertEquals(target.getGroups().get().getChildren().size(), 1); + assertEquals(expectedImportedGroupNode, target.getGroups().get().getChildren().get(0)); + } + static class TestGroup extends AbstractGroup { protected TestGroup(String name, GroupHierarchyType context) { From a247d85fb89cf7322010ce698403992cd98bf064 Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 29 Aug 2020 16:34:34 +0200 Subject: [PATCH 6/6] Reduce test example Signed-off-by: Dominik Voigt --- .../org/jabref/gui/importer/ImportAction.java | 2 +- .../logic/database/DatabaseMergerTest.java | 56 ++++--------------- 2 files changed, 12 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportAction.java b/src/main/java/org/jabref/gui/importer/ImportAction.java index badede2b39b..2a607482fce 100644 --- a/src/main/java/org/jabref/gui/importer/ImportAction.java +++ b/src/main/java/org/jabref/gui/importer/ImportAction.java @@ -130,7 +130,7 @@ private ParserResult mergeImportResults(List