diff --git a/.github/workflows/deployment-arm64.yml b/.github/workflows/deployment-arm64.yml index 9105597c42f..91a220d0d03 100644 --- a/.github/workflows/deployment-arm64.yml +++ b/.github/workflows/deployment-arm64.yml @@ -64,7 +64,7 @@ jobs: java-version: 20 distribution: 'temurin' cache: 'gradle' - - name: setup jdk JabRef-fix mac + - name: setup jdk jabref-fix mac shell: bash run: | mkdir ${{runner.temp}}/jdk @@ -114,8 +114,8 @@ jobs: --verbose \ --mac-sign \ --vendor JabRef \ - --mac-package-identifier Jabref \ - --mac-package-name JabRef \ + --mac-package-identifier JabRef \ + --mac-package-name "JabRef e.V." \ --type dmg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \ --mac-package-signing-prefix org.jabref \ --mac-entitlements buildres/mac/jabref.entitlements \ @@ -135,8 +135,8 @@ jobs: --app-version ${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }} \ --verbose \ --mac-sign \ - --vendor JabRef \ - --mac-package-identifier Jabref \ + --vendor "JabRef e.V." \ + --mac-package-identifier JabRef \ --mac-package-name JabRef \ --type pkg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \ --mac-package-signing-prefix org.jabref \ @@ -148,22 +148,22 @@ jobs: - name: Rename files with arm64 suffix as well shell: bash run: | - mv build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg - mv build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg + mv build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg + mv build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg - name: Notarize dmg if: (startsWith(github.ref, 'refs/tags/') || (${{ inputs.notarization }})) shell: bash run: | xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}" --keychain ${{runner.temp}}/keychain/notarization.keychain - xcrun notarytool submit build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg --keychain-profile "notarytool-profile" --keychain ${{runner.temp}}/keychain/notarization.keychain --wait - xcrun stapler staple build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg + xcrun notarytool submit build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg --keychain-profile "notarytool-profile" --keychain ${{runner.temp}}/keychain/notarization.keychain --wait + xcrun stapler staple build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.dmg - name: Notarize pkg if: (startsWith(github.ref, 'refs/tags/') || (${{ inputs.notarization }})) shell: bash run: | xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}" --keychain ${{runner.temp}}/keychain/notarization.keychain - xcrun notarytool submit build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg --keychain-profile "notarytool-profile" --keychain ${{runner.temp}}/keychain/notarization.keychain --wait - xcrun stapler staple build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg + xcrun notarytool submit build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg --keychain-profile "notarytool-profile" --keychain ${{runner.temp}}/keychain/notarization.keychain --wait + xcrun stapler staple build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}-arm64.pkg - name: Upload with rsync if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue') }} shell: bash @@ -178,5 +178,5 @@ jobs: if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue') }} uses: actions/upload-artifact@v3 with: - name: JabRef-${{ matrix.displayName }} + name: jabref-${{ matrix.displayName }} path: build/distribution diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 9f0e27108b4..547edb4b9f9 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -43,14 +43,14 @@ jobs: include: - os: ubuntu-latest displayName: linux - archivePortable: tar -c -C build/distribution JabRef | pigz --rsyncable > build/distribution/JabRef-portable_linux.tar.gz && rm -R build/distribution/JabRef + archivePortable: tar -c -C build/distribution jabref | pigz --rsyncable > build/distribution/jabref-portable_linux.tar.gz && rm -R build/distribution/jabref eaJdk: https://files.jabref.org/jdks/jdk-linux-x64.tar.gz - os: windows-latest displayName: windows - archivePortable: 7z a -r build/distribution/JabRef-portable_windows.zip ./build/distribution/JabRef && rm -R build/distribution/JabRef + archivePortable: 7z a -r build/distribution/jabref-portable_windows.zip ./build/distribution/jabref && rm -R build/distribution/jabref eaJDK: https://files.jabref.org/jdks/jdk-windows-x64.zip - os: macos-latest - displayName: macOS + displayName: macos eaJDK: https://files.jabref.org/jdks/jdk-macos-x64.tar.gz runs-on: ${{ matrix.os }} name: Create installer and portable version for ${{ matrix.displayName }} @@ -91,7 +91,7 @@ jobs: java-version: 20 distribution: 'temurin' cache: 'gradle' - - name: setup jdk JabRef-fix (windows) + - name: setup jdk jabref-fix (windows) if: (matrix.os == 'windows-latest') shell: bash run: | @@ -105,7 +105,7 @@ jobs: cat gradle.properties sed -i "s/JavaLanguageVersion.of(20)/JavaLanguageVersion.of(21)/" build.gradle - - name: setup jdk JabRef-fix (ubuntu) + - name: setup jdk jabref-fix (ubuntu) if: (matrix.os == 'ubuntu-latest') shell: bash run: | @@ -119,7 +119,7 @@ jobs: cat gradle.properties sed -i "s/JavaLanguageVersion.of(20)/JavaLanguageVersion.of(21)/" build.gradle - - name: setup jdk JabRef-fix (macos) + - name: setup jdk jabref-fix (macos) if: (matrix.os == 'macos-latest') shell: bash run: | @@ -152,13 +152,13 @@ jobs: - name: Build runtime image (non-macos) if: (matrix.os != 'macos-latest') run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jlinkZip - - name: Prepare merged jars and modules dir (macos) - if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') - run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" prepareModulesDir - name: Build installer (non-macos) if: (matrix.os != 'macos-latest') shell: bash run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jpackage + - name: Prepare merged jars and modules dir (macos) + if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') + run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" prepareModulesDir - name: Build dmg (macos) if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') shell: bash @@ -168,12 +168,12 @@ jobs: --module-path ${{env.JDK21}}/Contents/Home/jmods/:build/jlinkbase/jlinkjars \ --add-modules org.jabref,org.jabref.merged.module \ --dest build/distribution \ - --name JabRef \ + --name jabref \ --app-version ${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }} \ --verbose \ --mac-sign \ - --vendor JabRef \ - --mac-package-identifier Jabref \ + --vendor "JabRef e.V." \ + --mac-package-identifier JabRef \ --mac-package-name JabRef \ --type dmg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \ --mac-package-signing-prefix org.jabref \ @@ -195,8 +195,8 @@ jobs: --app-version ${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }} \ --verbose \ --mac-sign \ - --vendor JabRef \ - --mac-package-identifier Jabref \ + --vendor "JabRef e.V." \ + --mac-package-identifier JabRef \ --mac-package-name JabRef \ --type pkg --mac-signing-key-user-name "JabRef e.V. (6792V39SK3)" \ --mac-package-signing-prefix org.jabref \ @@ -241,14 +241,14 @@ jobs: if: (matrix.os == 'windows-latest') && (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) uses: actions/upload-artifact@v3 with: - name: JabRef-${{ matrix.displayName }} + name: jabref-${{ matrix.displayName }} path: build/distribution - name: Upload to GitHub workflow artifacts store (macos) if: (matrix.os == 'macos-latest') && (steps.checksecrets.outputs.secretspresent == 'YES') && (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) uses: actions/upload-artifact@v3 with: # tbn = to-be-notarized - name: JabRef-macOS-tbn + name: jabref-macos-tbn path: build/distribution notarize: # outsourced in a separate job to be able to rerun if this fails for timeouts name: Notarize and package Mac OS binaries @@ -283,26 +283,26 @@ jobs: if: steps.checksecrets.outputs.secretspresent == 'YES' id: gitversion uses: gittools/actions/gitversion/execute@v0.10.2 - - name: Get macOS binaries + - name: Get macos binaries if: steps.checksecrets.outputs.secretspresent == 'YES' uses: actions/download-artifact@master with: - name: JabRef-macOS-tbn + name: jabref-macos-tbn path: build/distribution/ - name: Notarize dmg if: (steps.checksecrets.outputs.secretspresent == 'YES') && (startsWith(github.ref, 'refs/tags/') || inputs.notarization == true) shell: bash run: | xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}" - xcrun notarytool submit build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg --keychain-profile "notarytool-profile" --wait - xcrun stapler staple build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg + xcrun notarytool submit build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg --keychain-profile "notarytool-profile" --wait + xcrun stapler staple build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.dmg - name: Notarize pkg if: (steps.checksecrets.outputs.secretspresent == 'YES') && (startsWith(github.ref, 'refs/tags/') || inputs.notarization == true) shell: bash run: | xcrun notarytool store-credentials "notarytool-profile" --apple-id "vorstand@jabref.org" --team-id "6792V39SK3" --password "${{ secrets.OSX_NOTARIZATION_APP_PWD }}" - xcrun notarytool submit build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg --keychain-profile "notarytool-profile" --wait - xcrun stapler staple build/distribution/JabRef-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg + xcrun notarytool submit build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg --keychain-profile "notarytool-profile" --wait + xcrun stapler staple build/distribution/jabref-${{ steps.gitversion.outputs.Major }}.${{ steps.gitversion.outputs.Minor }}.pkg - name: Package application image if: (steps.checksecrets.outputs.secretspresent == 'YES') && (matrix.os != 'macos-latest') shell: bash @@ -311,7 +311,7 @@ jobs: if: (steps.checksecrets.outputs.secretspresent == 'YES') && (!startsWith(github.ref, 'refs/heads/gh-readonly-queue')) uses: actions/upload-artifact@v3 with: - name: JabRef-macOS + name: jabref-macos path: build/distribution upload: strategy: @@ -352,19 +352,19 @@ jobs: if: steps.checksecrets.outputs.secretspresent == 'YES' uses: actions/download-artifact@master with: - name: JabRef-windows + name: jabref-windows path: build/distribution - - name: Get macOS binaries unsigned + - name: Get macos binaries unsigned if: (steps.checksecrets.outputs.secretspresent == 'YES') && (inputs.notarization == false && !startsWith(github.ref, 'refs/tags/')) uses: actions/download-artifact@master with: - name: JabRef-macOS-tbn + name: jabref-macos-tbn path: build/distribution/ - - name: Get macOS binaries notarized + - name: Get macos binaries notarized if: (steps.checksecrets.outputs.secretspresent == 'YES') && (inputs.notarization == true || startsWith(github.ref, 'refs/tags/')) uses: actions/download-artifact@master with: - name: JabRef-macOS + name: jabref-macos path: build/distribution/ # Upload to build server using rsync # The action runs on linux only (because it is a Dockerized action), therefore it is embedded in a separate workflow diff --git a/.gitignore b/.gitignore index 1d3864a220b..ee2a7ba2815 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ snap/.snapcraft/ # flatpak flatpak/.buildconfig +flatpak/jabref-portable_linux.tar.gz flatpak/JabRef-portable_linux.tar.gz # Gradle diff --git a/build.gradle b/build.gradle index 479b29d3f93..28f21de0546 100644 --- a/build.gradle +++ b/build.gradle @@ -552,7 +552,7 @@ jpackage.dependsOn deleteInstallerTemp jlink { addOptions('--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages') launcher { - name = 'JabRef' + name = 'jabref' } addOptions("--bind-services") @@ -625,7 +625,7 @@ jlink { '--icon', "${projectDir}/src/main/resources/icons/jabref.ico", ] installerOptions = [ - '--vendor', 'JabRef', + '--vendor', 'JabRef e.V.', '--app-version', "${project.version}", '--verbose', '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36', @@ -647,7 +647,7 @@ jlink { ] installerOptions = [ '--verbose', - '--vendor', 'JabRef', + '--vendor', 'JabRef e.V.', '--app-version', "${project.version}", // '--temp', "$buildDir/installer", '--resource-dir', "${projectDir}/buildres/linux", @@ -686,7 +686,7 @@ if (OperatingSystem.current().isWindows()) { from("${projectDir}/buildres/windows") { include "jabref-firefox.json", "jabref-chrome.json", "JabRefHost.bat", "JabRefHost.ps1" } - into "$buildDir/distribution/JabRef" + into "$buildDir/distribution/jabref" } } } @@ -697,7 +697,7 @@ if (OperatingSystem.current().isLinux()) { from("${projectDir}/buildres/linux") { include "native-messaging-host/**", "jabrefHost.py" } - into "$buildDir/distribution/JabRef/lib" + into "$buildDir/distribution/jabref/lib" } } } diff --git a/settings.gradle b/settings.gradle index 0d665b1d64f..5d9fc27de53 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,4 +11,4 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0" } -rootProject.name = "JabRef" +rootProject.name = "jabref" diff --git a/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java b/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java index 4e81e1b85dc..8c644ab40f2 100644 --- a/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java +++ b/src/test/java/org/jabref/logic/database/DuplicateCheckTest.java @@ -1,5 +1,7 @@ package org.jabref.logic.database; +import java.util.stream.Stream; + import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibEntryTypesManager; @@ -10,6 +12,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -23,88 +28,283 @@ public class DuplicateCheckTest { private BibEntry simpleIncollection; private DuplicateCheck duplicateChecker; - @BeforeEach - public void setUp() { - simpleArticle = new BibEntry(StandardEntryType.Article) + private static BibEntry getSimpleArticle() { + return new BibEntry(StandardEntryType.Article) .withField(StandardField.AUTHOR, "Single Author") .withField(StandardField.TITLE, "A serious paper about something") .withField(StandardField.YEAR, "2017"); - unrelatedArticle = new BibEntry(StandardEntryType.Article) - .withField(StandardField.AUTHOR, "Completely Different") - .withField(StandardField.TITLE, "Holy Moly Uffdada und Trallalla") - .withField(StandardField.YEAR, "1992"); - simpleInbook = new BibEntry(StandardEntryType.InBook) + } + + private static BibEntry getSimpleIncollection() { + return new BibEntry(StandardEntryType.InCollection) + .withField(StandardField.TITLE, "Innovation and Intellectual Property Rights") + .withField(StandardField.AUTHOR, "Ove Grandstrand") + .withField(StandardField.BOOKTITLE, "The Oxford Handbook of Innovation") + .withField(StandardField.PUBLISHER, "Oxford University Press") + .withField(StandardField.YEAR, "2004"); + } + + private static BibEntry getSimpleInbook() { + return new BibEntry(StandardEntryType.InBook) .withField(StandardField.TITLE, "Alice in Wonderland") .withField(StandardField.AUTHOR, "Charles Lutwidge Dodgson") .withField(StandardField.CHAPTER, "Chapter One – Down the Rabbit Hole") .withField(StandardField.LANGUAGE, "English") .withField(StandardField.PUBLISHER, "Macmillan") .withField(StandardField.YEAR, "1865"); - simpleIncollection = new BibEntry(StandardEntryType.InCollection) - .withField(StandardField.TITLE, "Innovation and Intellectual Property Rights") - .withField(StandardField.AUTHOR, "Ove Grandstrand") - .withField(StandardField.BOOKTITLE, "The Oxford Handbook of Innovation") - .withField(StandardField.PUBLISHER, "Oxford University Press") - .withField(StandardField.YEAR, "2004"); + } + + private static BibEntry getUnrelatedArticle() { + return new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Completely Different") + .withField(StandardField.TITLE, "Holy Moly Uffdada und Trallalla") + .withField(StandardField.YEAR, "1992"); + } + + @BeforeEach + public void setUp() { + simpleArticle = getSimpleArticle(); + unrelatedArticle = getUnrelatedArticle(); + simpleInbook = getSimpleInbook(); + simpleIncollection = getSimpleIncollection(); duplicateChecker = new DuplicateCheck(new BibEntryTypesManager()); } @Test - public void testDuplicateDetection() { - BibEntry one = new BibEntry(StandardEntryType.Article); - - BibEntry two = new BibEntry(StandardEntryType.Article); + public void testDuplicateDetectionWithSameAuthor() { + BibEntry one = new BibEntry(StandardEntryType.Article).withField(StandardField.AUTHOR, "Billy Bob"); + BibEntry two = new BibEntry(StandardEntryType.Article).withField(StandardField.AUTHOR, "Billy Bob"); - one.setField(StandardField.AUTHOR, "Billy Bob"); - two.setField(StandardField.AUTHOR, "Billy Bob"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithDifferentAuthors() { + BibEntry one = new BibEntry(StandardEntryType.Article).withField(StandardField.AUTHOR, "Billy Bob"); + BibEntry two = new BibEntry(StandardEntryType.Article).withField(StandardField.AUTHOR, "James Joyce"); - two.setField(StandardField.AUTHOR, "James Joyce"); assertFalse(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithDifferentTypes() { + BibEntry one = new BibEntry(StandardEntryType.Article).withField(StandardField.AUTHOR, "Billy Bob"); + BibEntry two = new BibEntry(StandardEntryType.Book).withField(StandardField.AUTHOR, "Billy Bob"); - two.setField(StandardField.AUTHOR, "Billy Bob"); - two.setType(StandardEntryType.Book); assertFalse(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithSameYearTitleJournal() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A"); - two.setType(StandardEntryType.Article); - one.setField(StandardField.YEAR, "2005"); - two.setField(StandardField.YEAR, "2005"); - one.setField(StandardField.TITLE, "A title"); - two.setField(StandardField.TITLE, "A title"); - one.setField(StandardField.JOURNAL, "A"); - two.setField(StandardField.JOURNAL, "A"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); assertEquals(1.01, DuplicateCheck.compareEntriesStrictly(one, two), 0.01); + } + + @Test + public void testDuplicateDetectionWithDifferentJournal() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "B"); - two.setField(StandardField.JOURNAL, "B"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); assertEquals(0.75, DuplicateCheck.compareEntriesStrictly(one, two), 0.01); + } - two.setField(StandardField.JOURNAL, "A"); - one.setField(StandardField.NUMBER, "1"); - two.setField(StandardField.VOLUME, "21"); - one.setField(StandardField.PAGES, "334--337"); - two.setField(StandardField.PAGES, "334--337"); - assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + @Test + public void testDuplicateDetectionWithDifferentVolume() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.VOLUME, "21"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.VOLUME, "22"); - two.setField(StandardField.NUMBER, "1"); - one.setField(StandardField.VOLUME, "21"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithDifferentTitleSameVolume() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.VOLUME, "21"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "Another title") + .withField(StandardField.JOURNAL, "") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.VOLUME, "21"); + + assertFalse(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithSamePages() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); - two.setField(StandardField.VOLUME, "22"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionWithSamePagesOneEntryNoVolume() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); - two.setField(StandardField.JOURNAL, "B"); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionDifferentVolumeNoJournal() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.VOLUME, "22") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); - one.setField(StandardField.JOURNAL, ""); - two.setField(StandardField.JOURNAL, ""); assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionDifferentTitleNoJournal() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "Another title") + .withField(StandardField.VOLUME, "22") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); - two.setField(StandardField.TITLE, "Another title"); assertFalse(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); } + @Test + public void testDuplicateDetectionDifferentVolumeAllOthersEqual() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "22") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + + @Test + public void testDuplicateDetectionDifferentVolumeDifferentJournalAllOthersEqual() { + BibEntry one = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "A") + .withField(StandardField.VOLUME, "21") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + BibEntry two = new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Billy Bob") + .withField(StandardField.YEAR, "2005") + .withField(StandardField.TITLE, "A title") + .withField(StandardField.JOURNAL, "B") + .withField(StandardField.VOLUME, "22") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.PAGES, "334--337"); + + assertTrue(duplicateChecker.isDuplicate(one, two, BibDatabaseMode.BIBTEX)); + } + @Test public void testWordCorrelation() { String d1 = "Characterization of Calanus finmarchicus habitat in the North Sea"; @@ -183,127 +383,115 @@ public void twoEntriesWithSameISBNButDifferentTypesAreDuplicates() { assertTrue(duplicateChecker.isDuplicate(simpleArticle, duplicateWithDifferentType, BibDatabaseMode.BIBTEX)); } - @Test - public void twoInbooksWithDifferentChaptersAreNotDuplicates() { - twoEntriesWithDifferentSpecificFieldsAreNotDuplicates(simpleInbook, StandardField.CHAPTER, - "Chapter One – Down the Rabbit Hole", - "Chapter Two – The Pool of Tears"); - } - - @Test - public void twoInbooksWithDifferentPagesAreNotDuplicates() { - twoEntriesWithDifferentSpecificFieldsAreNotDuplicates(simpleInbook, StandardField.PAGES, "1-20", "21-40"); - } - - @Test - public void twoIncollectionsWithDifferentChaptersAreNotDuplicates() { - twoEntriesWithDifferentSpecificFieldsAreNotDuplicates(simpleIncollection, StandardField.CHAPTER, "10", "9"); - } - - @Test - public void twoIncollectionsWithDifferentPagesAreNotDuplicates() { - twoEntriesWithDifferentSpecificFieldsAreNotDuplicates(simpleIncollection, StandardField.PAGES, "1-20", "21-40"); + public static Stream twoEntriesWithDifferentSpecificFieldsAreNotDuplicates() { + return Stream.of( + // twoInbooksWithDifferentChaptersAreNotDuplicates + Arguments.of(getSimpleInbook(), StandardField.CHAPTER, + "Chapter One – Down the Rabbit Hole", + "Chapter Two – The Pool of Tears"), + // twoInbooksWithDifferentPagesAreNotDuplicates + Arguments.of(getSimpleInbook(), StandardField.PAGES, "1-20", "21-40"), + // twoIncollectionsWithDifferentChaptersAreNotDuplicates + Arguments.of(getSimpleIncollection(), StandardField.CHAPTER, "10", "9"), + // twoEntriesWithDifferentSpecificFieldsAreNotDuplicates + Arguments.of(getSimpleIncollection(), StandardField.PAGES, "1-20", "21-40") + ); } + @ParameterizedTest + @MethodSource private void twoEntriesWithDifferentSpecificFieldsAreNotDuplicates(final BibEntry cloneable, final Field field, final String firstValue, final String secondValue) { - final BibEntry entry1 = (BibEntry) cloneable.clone(); - entry1.setField(field, firstValue); - - final BibEntry entry2 = (BibEntry) cloneable.clone(); - entry2.setField(field, secondValue); - + final BibEntry entry1 = ((BibEntry) cloneable.clone()).withField(field, firstValue); + final BibEntry entry2 = ((BibEntry) cloneable.clone()).withField(field, secondValue); assertFalse(duplicateChecker.isDuplicate(entry1, entry2, BibDatabaseMode.BIBTEX)); } @Test public void inbookWithoutChapterCouldBeDuplicateOfInbookWithChapter() { - final BibEntry inbook1 = (BibEntry) simpleInbook.clone(); - final BibEntry inbook2 = (BibEntry) simpleInbook.clone(); - inbook2.setField(StandardField.CHAPTER, ""); + final BibEntry inbook2 = ((BibEntry) simpleInbook.clone()).withField(StandardField.CHAPTER, ""); - assertTrue(duplicateChecker.isDuplicate(inbook1, inbook2, BibDatabaseMode.BIBTEX)); - assertTrue(duplicateChecker.isDuplicate(inbook2, inbook1, BibDatabaseMode.BIBTEX)); + assertTrue(duplicateChecker.isDuplicate(simpleInbook, inbook2, BibDatabaseMode.BIBTEX)); } @Test public void twoBooksWithDifferentEditionsAreNotDuplicates() { - BibEntry editionOne = new BibEntry(StandardEntryType.Book); - editionOne.setField(StandardField.TITLE, "Effective Java"); - editionOne.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionOne.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionOne.setField(StandardField.DATE, "2001"); - editionOne.setField(StandardField.EDITION, "1"); - - BibEntry editionTwo = new BibEntry(StandardEntryType.Book); - editionTwo.setField(StandardField.TITLE, "Effective Java"); - editionTwo.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionTwo.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionTwo.setField(StandardField.DATE, "2008"); - editionTwo.setField(StandardField.EDITION, "2"); + BibEntry editionOne = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2001") + .withField(StandardField.EDITION, "1"); + + BibEntry editionTwo = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2008") + .withField(StandardField.EDITION, "2"); assertFalse(duplicateChecker.isDuplicate(editionOne, editionTwo, BibDatabaseMode.BIBTEX)); } @Test public void sameBooksWithMissingEditionAreDuplicates() { - BibEntry editionOne = new BibEntry(StandardEntryType.Book); - editionOne.setField(StandardField.TITLE, "Effective Java"); - editionOne.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionOne.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionOne.setField(StandardField.DATE, "2001"); - - BibEntry editionTwo = new BibEntry(StandardEntryType.Book); - editionTwo.setField(StandardField.TITLE, "Effective Java"); - editionTwo.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionTwo.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionTwo.setField(StandardField.DATE, "2008"); + BibEntry editionOne = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2001"); + + BibEntry editionTwo = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2008"); assertTrue(duplicateChecker.isDuplicate(editionOne, editionTwo, BibDatabaseMode.BIBTEX)); } @Test public void sameBooksWithPartiallyMissingEditionAreDuplicates() { - BibEntry editionOne = new BibEntry(StandardEntryType.Book); - editionOne.setField(StandardField.TITLE, "Effective Java"); - editionOne.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionOne.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionOne.setField(StandardField.DATE, "2001"); - - BibEntry editionTwo = new BibEntry(StandardEntryType.Book); - editionTwo.setField(StandardField.TITLE, "Effective Java"); - editionTwo.setField(StandardField.AUTHOR, "Bloch, Joshua"); - editionTwo.setField(StandardField.PUBLISHER, "Prentice Hall"); - editionTwo.setField(StandardField.DATE, "2008"); - editionTwo.setField(StandardField.EDITION, "2"); + BibEntry editionOne = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2001"); + + BibEntry editionTwo = new BibEntry(StandardEntryType.Book) + .withField(StandardField.TITLE, "Effective Java") + .withField(StandardField.AUTHOR, "Bloch, Joshua") + .withField(StandardField.PUBLISHER, "Prentice Hall") + .withField(StandardField.DATE, "2008") + .withField(StandardField.EDITION, "2"); assertTrue(duplicateChecker.isDuplicate(editionOne, editionTwo, BibDatabaseMode.BIBTEX)); } @Test public void sameBooksWithDifferentEditionsAreNotDuplicates() { - BibEntry editionTwo = new BibEntry(StandardEntryType.Book); - editionTwo.setCitationKey("Sutton17reinfLrnIntroBook"); - editionTwo.setField(StandardField.TITLE, "Reinforcement learning:An introduction"); - editionTwo.setField(StandardField.PUBLISHER, "MIT Press"); - editionTwo.setField(StandardField.YEAR, "2017"); - editionTwo.setField(StandardField.AUTHOR, "Sutton, Richard S and Barto, Andrew G"); - editionTwo.setField(StandardField.ADDRESS, "Cambridge, MA.USA"); - editionTwo.setField(StandardField.EDITION, "Second"); - editionTwo.setField(StandardField.JOURNAL, "MIT Press"); - editionTwo.setField(StandardField.URL, "https://webdocs.cs.ualberta.ca/~sutton/book/the-book-2nd.html"); - - BibEntry editionOne = new BibEntry(StandardEntryType.Book); - editionOne.setCitationKey("Sutton98reinfLrnIntroBook"); - editionOne.setField(StandardField.TITLE, "Reinforcement learning: An introduction"); - editionOne.setField(StandardField.PUBLISHER, "MIT press Cambridge"); - editionOne.setField(StandardField.YEAR, "1998"); - editionOne.setField(StandardField.AUTHOR, "Sutton, Richard S and Barto, Andrew G"); - editionOne.setField(StandardField.VOLUME, "1"); - editionOne.setField(StandardField.NUMBER, "1"); - editionOne.setField(StandardField.EDITION, "First"); + BibEntry editionTwo = new BibEntry(StandardEntryType.Book) + .withCitationKey("Sutton17reinfLrnIntroBook") + .withField(StandardField.TITLE, "Reinforcement learning:An introduction") + .withField(StandardField.PUBLISHER, "MIT Press") + .withField(StandardField.YEAR, "2017") + .withField(StandardField.AUTHOR, "Sutton, Richard S and Barto, Andrew G") + .withField(StandardField.ADDRESS, "Cambridge, MA.USA") + .withField(StandardField.EDITION, "Second") + .withField(StandardField.JOURNAL, "MIT Press") + .withField(StandardField.URL, "https://webdocs.cs.ualberta.ca/~sutton/book/the-book-2nd.html"); + + BibEntry editionOne = new BibEntry(StandardEntryType.Book) + .withCitationKey("Sutton98reinfLrnIntroBook") + .withField(StandardField.TITLE, "Reinforcement learning: An introduction") + .withField(StandardField.PUBLISHER, "MIT press Cambridge") + .withField(StandardField.YEAR, "1998") + .withField(StandardField.AUTHOR, "Sutton, Richard S and Barto, Andrew G") + .withField(StandardField.VOLUME, "1") + .withField(StandardField.NUMBER, "1") + .withField(StandardField.EDITION, "First"); assertFalse(duplicateChecker.isDuplicate(editionOne, editionTwo, BibDatabaseMode.BIBTEX)); }