From 08eccb629d3214301d8b37862e10e2a10939b221 Mon Sep 17 00:00:00 2001 From: k3KAW8Pnf7mkmdSMPHz27 <2598631+k3KAW8Pnf7mkmdSMPHz27@users.noreply.github.com> Date: Thu, 28 May 2020 11:27:15 -0400 Subject: [PATCH] Fixes generated bibtex key and display of institute authors (#6479) * Fix Pattern.compile for frequently used regexes * Fix one additional Pattern.compile * Fix style and unnecessary escape sequences * Fix invalid index in call to substring The original condition is evaluated to false. The substring is shorter than "uni". * Refactor name and javadoc of a regex * Fix use of compiled regex for matching department * Fix check for uppercase letter Perhaps the assumption should be that the letters are ASCII. If all letters are ASCII checking 'A' <= k.charAt(0) <= 'Z' might make more sense. I am not convinced about doing this with a regex. * Fix usage of uncompiled regex * Fix readability? * Add test cases Both test cases involves an author name containing department or school without university or institute of technology. * Fix `null` appearing as part of author name Corporate authors without university/institute of technology * Refactor name of capital regex pattern * Add debug output for reordering of names in fields * Add helper methods * Fix missing negation in "uni" matching * Fix test cases for corporate authors * Fix to keep all uppercase letters in abbreviation * Fix commented out code * Fix key for institution's name containing keyword If the name of an institution can't be split, assume that "School"/"Department" is part of the name. * Fix test case for short institution name * Refactor check for institution types * Refactor comments and names improving readability? * Refactor to improve readability and closure * Fix JavaDoc Minor typos and the "rest" part is now created differently. * Fix JavaDoc typos * Fix preliminary order for authors -> latexfree * Drop logger * Add convenience methods for cached latexfree names * Add name format method for names containing latex * Add call to formatNameLatexFree * Fix unclear statement in JavaDoc * Fix to only keep the first character of each word There are some examples that will turn out wrong if only capital letters are kept, e.g., "iOS Developer University Program". The original problem with "The School of Life" becoming too short is avoided by only removing school/department for names containing two or more ',' separated strings. This will still produce an unexpected result if the address of the institution is part of the authors field * Add latexfree Natbib test cases * Fix typo in latex-free test cases * Add Natbib test with escaped brackets * Add Natbib institution test with escaped brackets * Add test for latex-free comma separated lastnames * Add test for latex-free comma separated first name First name first and abbreviated first name first * Add test for latex-free comma separated last name Last name first and abbreviated first names * Fix adherence to JavaDoc and readability(?) * Fix readability(?) * Fix CheckStyle issues The deprecated static methods BibtexKeyGenerator.generateKey are moved to the test file as a similar convenience method is required for the test cases. Suppress warning has been added for some methods. * Fix CHANGELOG.md * Fix mistake in BibtexKeyGeneratorTest generateKey was not copy-pasted properly. * Add test for oxford comma * Fix miss-capitalization of enum * Fix fields not displayed latex-free * Fix in-line methods in MainTableNameFormatter * Fix in-line of generateKey() method * Fix separating tests into parsing/representation * Fix cache check and simplify expressions * Drop inlined methods * Fix most abbreviated abbreviations * Drop old formatName method * Refactor formatNameLatexFree The author list parsing is moved outside of the if/else statements * Refactor new parse tests * Add more parse tests * Drop all test cases containing escaped brackets * Refactor parse with latex tests Move them close to other parse tests * Fix my own spelling mistakes * Refactor abbreviation name --- CHANGELOG.md | 2 + .../gui/maintable/BibEntryTableViewModel.java | 37 +- .../gui/maintable/MainTableNameFormatter.java | 14 +- .../bibtexkeypattern/BracketedPattern.java | 229 +++++--- .../org/jabref/model/entry/AuthorList.java | 128 ++-- .../BibtexKeyGeneratorTest.java | 216 ++++--- .../jabref/model/entry/AuthorListTest.java | 555 ++++++++++++++++-- 7 files changed, 894 insertions(+), 287 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 331c0d41e44..970c9d65237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where brackets in regular expressions were not working. [6469](https://github.com/JabRef/jabref/pull/6469) - We fixed an issue where LaTeX citations for specific commands (\autocites) of biblatex-mla were not recognized. [#6476](https://github.com/JabRef/jabref/issues/6476) - We fixed an issue where drag and drop was not working on empty database. [#6487](https://github.com/JabRef/jabref/issues/6487) +- We fixed an issue where "null" appeared in generated BibTeX keys. [#6459](https://github.com/JabRef/jabref/issues/6459) +- We fixed an issue where the authors' names were incorrectly displayed in the authors' column when they were bracketed. [#6465](https://github.com/JabRef/jabref/issues/6465) [#6459](https://github.com/JabRef/jabref/issues/6459) ### Removed diff --git a/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java index c09c540ef39..91da602cdf7 100644 --- a/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java +++ b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java @@ -115,28 +115,27 @@ public ObservableValue getFields(OrFields fields) { ObservableValue value = fieldValues.get(fields); if (value != null) { return value; - } else { - value = Bindings.createStringBinding(() -> { - boolean isName = false; + } - Optional content = Optional.empty(); - for (Field field : fields) { - content = entry.getResolvedFieldOrAliasLatexFree(field, database); - if (content.isPresent()) { - isName = field.getProperties().contains(FieldProperty.PERSON_NAMES); - break; - } - } + value = Bindings.createStringBinding(() -> { + for (Field field : fields) { + if (field.getProperties().contains(FieldProperty.PERSON_NAMES)) { + Optional name = entry.getResolvedFieldOrAlias(field, database); - String result = content.orElse(null); - if (isName) { - return nameFormatter.formatName(result); + if (name.isPresent()) { + return nameFormatter.formatNameLatexFree(name.get()); + } } else { - return result; + Optional content = entry.getResolvedFieldOrAliasLatexFree(field, database); + + if (content.isPresent()) { + return content.get(); + } } - }, entry.getObservables()); - fieldValues.put(fields, value); - return value; - } + } + return ""; + }, entry.getObservables()); + fieldValues.put(fields, value); + return value; } } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java b/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java index 741c0027c66..287f249a17a 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java @@ -20,26 +20,28 @@ public class MainTableNameFormatter { } /** - * Format a name field for the table, according to user preferences. + * Format a name field for the table, according to user preferences and with latex expressions translated if + * possible. * * @param nameToFormat The contents of the name field. * @return The formatted name field. */ - public String formatName(final String nameToFormat) { + public String formatNameLatexFree(final String nameToFormat) { if (nameToFormat == null) { return null; } + AuthorList authors = AuthorList.parse(nameToFormat); if (namesAsIs) { return nameToFormat; } else if (namesNatbib) { - return AuthorList.fixAuthorNatbib(nameToFormat); + return authors.getAsNatbibLatexFree(); } else if (namesLastOnly) { - return AuthorList.fixAuthorLastNameOnlyCommas(nameToFormat, false); + return authors.getAsLastNamesLatexFree(false); } else if (namesFf) { - return AuthorList.fixAuthorFirstNameFirstCommas(nameToFormat, abbrAuthorNames, false); + return authors.getAsFirstLastNamesLatexFree(abbrAuthorNames, false); } else { - return AuthorList.fixAuthorLastNameFirstCommas(nameToFormat, abbrAuthorNames, false); + return authors.getAsLastFirstNamesLatexFree(abbrAuthorNames, false); } } } diff --git a/src/main/java/org/jabref/logic/bibtexkeypattern/BracketedPattern.java b/src/main/java/org/jabref/logic/bibtexkeypattern/BracketedPattern.java index cc7e843d016..d5ca948d037 100644 --- a/src/main/java/org/jabref/logic/bibtexkeypattern/BracketedPattern.java +++ b/src/main/java/org/jabref/logic/bibtexkeypattern/BracketedPattern.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -10,6 +11,7 @@ import java.util.Scanner; import java.util.StringJoiner; import java.util.StringTokenizer; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,9 +43,54 @@ public class BracketedPattern { private static final Logger LOGGER = LoggerFactory.getLogger(BracketedPattern.class); - private static final String STARTING_CAPITAL_PATTERN = "[^A-Z]"; private static final int CHARS_OF_FIRST = 5; - private static final Pattern REGEX_PATTERN = Pattern.compile(".*\\(\\{([A-Z]+)\\}\\).*"); + + /** Matches everything that is not an uppercase ASCII letter */ + private static final Pattern NOT_CAPITAL_FIRST_CHARACTER = Pattern.compile("[^A-Z]"); + /** Matches with "({[A-Z]}+)", which should be used to abbreviate the name of an institution */ + private static final Pattern ABBREVIATIONS = Pattern.compile(".*\\(\\{[A-Z]+}\\).*"); + /** Matches with "dep"/"dip", case insensitive */ + private static final Pattern DEPARTMENTS = Pattern.compile("^d[ei]p.*", Pattern.CASE_INSENSITIVE); + private enum Institution { + SCHOOL, + DEPARTMENT, + UNIVERSITY, + TECHNOLOGY; + + /** Matches "uni" at the start of a string or after a space, case insensitive */ + private static final Pattern UNIVERSITIES = Pattern.compile("^uni.*", Pattern.CASE_INSENSITIVE); + /** Matches with "tech", case insensitive */ + private static final Pattern TECHNOLOGICAL_INSTITUTES = Pattern.compile("^tech.*", Pattern.CASE_INSENSITIVE); + /** Matches with "dep"/"dip"/"lab", case insensitive */ + private static final Pattern DEPARTMENTS_OR_LABS = Pattern.compile("^(d[ei]p|lab).*", Pattern.CASE_INSENSITIVE); + + /** + * Find which types of institutions have words in common with the given name parts. + * @param nameParts a list of words that constitute parts of an institution's name. + * @return set containing all types that matches + */ + public static EnumSet findTypes(List nameParts) { + EnumSet parts = EnumSet.noneOf(Institution.class); + // Deciding about a part type… + for (String namePart : nameParts) { + if (UNIVERSITIES.matcher(namePart).matches()) { + parts.add(Institution.UNIVERSITY); + } else if (TECHNOLOGICAL_INSTITUTES.matcher(namePart).matches()) { + parts.add(Institution.TECHNOLOGY); + } else if (StandardField.SCHOOL.getName().equalsIgnoreCase(namePart)) { + parts.add(Institution.SCHOOL); + } else if (DEPARTMENTS_OR_LABS.matcher(namePart).matches()) { + parts.add(Institution.DEPARTMENT); + } + } + + if (parts.contains(Institution.TECHNOLOGY)) { + parts.remove(Institution.UNIVERSITY); // technology institute isn't university :-) + } + + return parts; + } + } private final String pattern; @@ -1200,8 +1247,8 @@ private static boolean isInstitution(String author) { * *

* An institution name should be inside {} brackets. If the - * institution name also includes its abbreviation this abbreviation should - * be also in {} brackets. For the previous example the value + * institution name includes its abbreviation this abbreviation should + * be in {} brackets. For the previous example the value * should look like: * {The Attributed Graph Grammar System ({AGG})}. *

@@ -1213,15 +1260,15 @@ private static boolean isInstitution(String author) { * *

* If an institution does not include its abbreviation the key should be - * generated form its name in the following way: + * generated from its name in the following way: *

* *

* The institution value can contain: institution name, part of the - * institution, address, etc. Those information should be separated by - * comma. Name of the institution and possible part of the institution - * should be on the beginning, while address and secondary information - * should be on the end. + * institution, address, etc. These values should be comma separated. + * Institution name and possible part of the institution + * should be in the beginning, while address and secondary information + * should be in the end. *

* * Each part is examined separately: @@ -1229,17 +1276,18 @@ private static boolean isInstitution(String author) { *
  • We remove all tokens of a part which are one of the defined ignore * words (the, press), which end with a dot (ltd., co., ...) and which first * character is lowercase (of, on, di, ...).
  • - *
  • We detect a type of the part: university, technology institute, + *
  • We detect the types of the part: university, technology institute, * department, school, rest *
      *
    • University: "Uni[NameOfTheUniversity]"
    • - *
    • Department: will be an abbreviation of all words beginning with the - * uppercase letter except of words: d[ei]p.*, school, - * faculty
    • + *
    • Department: If the institution value contains more than one comma + * separated part, the department will be an abbreviation of all words + * beginning with the uppercase letter except of words: + * d[ei]p.*, school, faculty
    • *
    • School: same as department
    • *
    • Rest: If there are less than 3 tokens in such part than the result - * will be by concatenating those tokens, otherwise the result will be build - * from the first letters of words starting with and uppercase letter.
    • + * is a concatenation of those tokens. Otherwise, the result will be built + * from the first letter in each token. *
    * *

    @@ -1262,20 +1310,23 @@ private static boolean isInstitution(String author) { * */ private static String generateInstitutionKey(String content) { - if (content.isEmpty()) { - return content; + if (content == null) { + return null; + } + if (content.isBlank()) { + return ""; } String result = content; result = unifyDiacritics(result); - result = result.replaceAll("^\\{", "").replaceAll("\\}$", ""); - Matcher matcher = REGEX_PATTERN.matcher(result); + result = result.replaceAll("^\\{", "").replaceAll("}$", ""); + Matcher matcher = ABBREVIATIONS.matcher(result); if (matcher.matches()) { return matcher.group(1); } result = removeDiacritics(result); - String[] parts = result.split(","); + String[] institutionNameTokens = result.split(","); // Key parts String university = null; @@ -1283,113 +1334,97 @@ private static String generateInstitutionKey(String content) { String school = null; String rest = null; - List ignore = Arrays.asList("press", "the"); - for (int index = 0; index < parts.length; index++) { - List part = new ArrayList<>(); - - // Cleanup: remove unnecessary words. - for (String k : parts[index].replaceAll("\\{[A-Z]+\\}", "").split("[ \\-_]")) { - if ((!(k.isEmpty()) // remove empty - && !ignore.contains(k.toLowerCase(Locale.ENGLISH)) // remove ignored words - && (k.charAt(k.length() - 1) != '.') - && (String.valueOf(k.charAt(0))).matches("[A-Z]")) - || ((k.length() >= 3) && "uni".equalsIgnoreCase(k.substring(0, 2)))) { - part.add(k); - } - } + for (int index = 0; index < institutionNameTokens.length; index++) { + List tokenParts = getValidInstitutionNameParts(institutionNameTokens[index]); + EnumSet tokenTypes = Institution.findTypes(tokenParts); - boolean isUniversity = false; // university - boolean isTechnology = false; // technology institute - boolean isDepartment = false; // departments - boolean isSchool = false; // schools - - // Deciding about a part type... - for (String k : part) { - if (k.matches("^[Uu][Nn][Ii].*")) { // Starts with "uni" case and locale independent - isUniversity = true; - } - if (k.matches("^[Tt][Ee][Cc][Hh].*")) { // Starts with "tech" case and locale independent - isTechnology = true; - } - if (StandardField.SCHOOL.getName().equalsIgnoreCase(k)) { - isSchool = true; - } - if (k.matches("^[Dd][EeIi][Pp].*") || k.matches("^[Ll][Aa][Bb].*")) { // Starts with "dep"/"dip"/"lab", case and locale independent - isDepartment = true; - } - } - if (isTechnology) { - isUniversity = false; // technology institute isn't university :-) - } - - // University part looks like: Uni[NameOfTheUniversity] - // - // If university is detected than the previous part is suggested - // as department - if (isUniversity) { + if (tokenTypes.contains(Institution.UNIVERSITY)) { StringBuilder universitySB = new StringBuilder(); + // University part looks like: Uni[NameOfTheUniversity] universitySB.append("Uni"); - for (String k : part) { - if (!k.matches("^[Uu][Nn][Ii].*")) { + for (String k : tokenParts) { + if (!"uni".regionMatches(true, 0, k, 0, 3)) { universitySB.append(k); } } university = universitySB.toString(); + // If university is detected than the previous part is suggested + // as department if ((index > 0) && (department == null)) { - department = parts[index - 1]; + department = institutionNameTokens[index - 1]; } - + } else if ((tokenTypes.contains(Institution.SCHOOL) + || tokenTypes.contains(Institution.DEPARTMENT)) + && institutionNameTokens.length > 1) { // School is an abbreviation of all the words beginning with a // capital letter excluding: department, school and faculty words. - // - // Explicitly defined department part is build the same way as - // school - } else if (isSchool || isDepartment) { StringBuilder schoolSB = new StringBuilder(); StringBuilder departmentSB = new StringBuilder(); - for (String k : part) { - if (!k.matches("^[Dd][EeIi][Pp].*") && !StandardField.SCHOOL.getName().equalsIgnoreCase(k) - && !"faculty".equalsIgnoreCase(k) - && !(k.replaceAll(STARTING_CAPITAL_PATTERN, "").isEmpty())) { - if (isSchool) { - schoolSB.append(k.replaceAll(STARTING_CAPITAL_PATTERN, "")); + for (String k : tokenParts) { + if (noOtherInstitutionKeyWord(k)) { + if (tokenTypes.contains(Institution.SCHOOL)) { + schoolSB.append(NOT_CAPITAL_FIRST_CHARACTER.matcher(k).replaceAll("")); } - if (isDepartment) { - departmentSB.append(k.replaceAll(STARTING_CAPITAL_PATTERN, "")); + // Explicitly defined department part is build the same way as school + if (tokenTypes.contains(Institution.DEPARTMENT)) { + departmentSB.append(NOT_CAPITAL_FIRST_CHARACTER.matcher(k).replaceAll("")); } } } - if (isSchool) { + if (tokenTypes.contains(Institution.SCHOOL)) { school = schoolSB.toString(); } - if (isDepartment) { + if (tokenTypes.contains(Institution.DEPARTMENT)) { department = departmentSB.toString(); } - // A part not matching university, department nor school. } else if (rest == null) { - StringBuilder restSB = new StringBuilder(); - // Less than 3 parts -> concatenate those - if (part.size() < 3) { - for (String k : part) { - restSB.append(k); - // More than 3 parts -> use 1st letter abbreviation - } + // A part not matching university, department nor school + if (tokenParts.size() >= 3) { + // If there are more than 3 parts, only keep the first character of each word + final int[] codePoints = tokenParts.stream() + .filter(Predicate.not(String::isBlank)) + .mapToInt((s) -> s.codePointAt(0)) + .toArray(); + rest = new String(codePoints, 0, codePoints.length); } else { - for (String k : part) { - k = k.replaceAll(STARTING_CAPITAL_PATTERN, ""); - if (!(k.isEmpty())) { - restSB.append(k); - } - } + rest = String.join("", tokenParts); } - rest = restSB.toString(); } } // Putting parts together. - return (university == null ? rest : university) + return (university == null ? Objects.toString(rest, "") : university) + (school == null ? "" : school) + ((department == null) || ((school != null) && department.equals(school)) ? "" : department); } + + /** + * Checks that this is not an institution keyword and has an uppercase first letter, except univ/tech key word. + * @param word to check + * @return + */ + private static boolean noOtherInstitutionKeyWord(String word) { + return !DEPARTMENTS.matcher(word).matches() + && !StandardField.SCHOOL.getName().equalsIgnoreCase(word) + && !"faculty".equalsIgnoreCase(word) + && !NOT_CAPITAL_FIRST_CHARACTER.matcher(word).replaceAll("").isEmpty(); + } + + private static List getValidInstitutionNameParts(String name) { + List nameParts = new ArrayList<>(); + List ignore = Arrays.asList("press", "the"); + + // Cleanup: remove unnecessary words. + for (String part : name.replaceAll("\\{[A-Z]+}", "").split("[ \\-_]")) { + if ((!(part.isEmpty()) // remove empty + && !ignore.contains(part.toLowerCase(Locale.ENGLISH)) // remove ignored words + && (part.charAt(part.length() - 1) != '.') + && Character.isUpperCase(part.charAt(0))) + || ((part.length() >= 3) && "uni".equalsIgnoreCase(part.substring(0, 3)))) { + nameParts.add(part); + } + } + return nameParts; + } } diff --git a/src/main/java/org/jabref/model/entry/AuthorList.java b/src/main/java/org/jabref/model/entry/AuthorList.java index 6acc67deabb..b617b792632 100644 --- a/src/main/java/org/jabref/model/entry/AuthorList.java +++ b/src/main/java/org/jabref/model/entry/AuthorList.java @@ -11,6 +11,8 @@ import java.util.WeakHashMap; import java.util.stream.Collectors; +import org.jabref.model.strings.LatexToUnicodeAdapter; + /** * This is an immutable class representing information of either author * or editor field in bibtex record. @@ -125,14 +127,18 @@ public class AuthorList { private final static Collection AVOID_TERMS_IN_LOWER_CASE = Arrays.asList("jr", "sr", "jnr", "snr", "von", "zu", "van", "der"); private final List authors; private final String[] authorsFirstFirst = new String[4]; + private final String[] authorsFirstFirstLatexFree = new String[4]; private final String[] authorsLastOnly = new String[2]; + private final String[] authorsLastOnlyLatexFree = new String[2]; private final String[] authorLastFirstAnds = new String[2]; private final String[] authorsLastFirst = new String[4]; + private final String[] authorsLastFirstLatexFree = new String[4]; private final String[] authorsLastFirstFirstLast = new String[2]; // Variables for storing computed strings, so they only need to be created once: private String authorsNatbib; private String authorsFirstFirstAnds; private String authorsAlph; + private String authorsNatbibLatexFree; /** * Creates a new list of authors. @@ -223,8 +229,8 @@ public static AuthorList parse(String authors) { * * @see AuthorList#getAsFirstLastNames */ - public static String fixAuthorFirstNameFirstCommas(String authors, boolean abbr, boolean oxfordComma) { - return AuthorList.parse(authors).getAsFirstLastNames(abbr, oxfordComma); + public static String fixAuthorFirstNameFirstCommas(String authors, boolean abbreviate, boolean oxfordComma) { + return AuthorList.parse(authors).getAsFirstLastNames(abbreviate, oxfordComma); } /** @@ -241,8 +247,8 @@ public static String fixAuthorFirstNameFirst(String authors) { * * @see AuthorList#getAsLastFirstNames */ - public static String fixAuthorLastNameFirstCommas(String authors, boolean abbr, boolean oxfordComma) { - return AuthorList.parse(authors).getAsLastFirstNames(abbr, oxfordComma); + public static String fixAuthorLastNameFirstCommas(String authors, boolean abbreviate, boolean oxfordComma) { + return AuthorList.parse(authors).getAsLastFirstNames(abbreviate, oxfordComma); } /** @@ -390,6 +396,15 @@ public String getAsNatbib() { return authorsNatbib; } + public String getAsNatbibLatexFree() { + // Check if we've computed this before: + if (authorsNatbibLatexFree != null) { + return authorsNatbibLatexFree; + } + authorsNatbibLatexFree = LatexToUnicodeAdapter.format(getAsNatbib()); + return authorsNatbibLatexFree; + } + /** * Returns the list of authors separated by commas with last name only; If * the list consists of two or more authors, "and" is inserted before the @@ -409,11 +424,11 @@ public String getAsNatbib() { * Oxford comma. */ public String getAsLastNames(boolean oxfordComma) { - int abbrInt = oxfordComma ? 0 : 1; + int abbreviationIndex = oxfordComma ? 0 : 1; // Check if we've computed this before: - if (authorsLastOnly[abbrInt] != null) { - return authorsLastOnly[abbrInt]; + if (authorsLastOnly[abbreviationIndex] != null) { + return authorsLastOnly[abbreviationIndex]; } StringBuilder result = new StringBuilder(); @@ -433,8 +448,19 @@ public String getAsLastNames(boolean oxfordComma) { result.append(getAuthor(i).getLastOnly()); } } - authorsLastOnly[abbrInt] = result.toString(); - return authorsLastOnly[abbrInt]; + authorsLastOnly[abbreviationIndex] = result.toString(); + return authorsLastOnly[abbreviationIndex]; + } + + public String getAsLastNamesLatexFree(boolean oxfordComma) { + int abbreviationIndex = oxfordComma ? 0 : 1; + + // Check if we've computed this before: + if (authorsLastOnlyLatexFree[abbreviationIndex] != null) { + return authorsLastOnlyLatexFree[abbreviationIndex]; + } + authorsLastOnlyLatexFree[abbreviationIndex] = LatexToUnicodeAdapter.format(getAsLastNames(oxfordComma)); + return authorsLastOnlyLatexFree[abbreviationIndex]; } /** @@ -460,12 +486,12 @@ public String getAsLastNames(boolean oxfordComma) { * Oxford comma. */ public String getAsLastFirstNames(boolean abbreviate, boolean oxfordComma) { - int abbrInt = abbreviate ? 0 : 1; - abbrInt += oxfordComma ? 0 : 2; + int abbreviationIndex = abbreviate ? 0 : 1; + abbreviationIndex += oxfordComma ? 0 : 2; // Check if we've computed this before: - if (authorsLastFirst[abbrInt] != null) { - return authorsLastFirst[abbrInt]; + if (authorsLastFirst[abbreviationIndex] != null) { + return authorsLastFirst[abbreviationIndex]; } StringBuilder result = new StringBuilder(); @@ -485,8 +511,21 @@ public String getAsLastFirstNames(boolean abbreviate, boolean oxfordComma) { result.append(getAuthor(i).getLastFirst(abbreviate)); } } - authorsLastFirst[abbrInt] = result.toString(); - return authorsLastFirst[abbrInt]; + authorsLastFirst[abbreviationIndex] = result.toString(); + return authorsLastFirst[abbreviationIndex]; + } + + public String getAsLastFirstNamesLatexFree(boolean abbreviate, boolean oxfordComma) { + int abbreviationIndex = abbreviate ? 0 : 1; + abbreviationIndex += oxfordComma ? 0 : 2; + + // Check if we've computed this before: + if (authorsLastFirstLatexFree[abbreviationIndex] != null) { + return authorsLastFirstLatexFree[abbreviationIndex]; + } + + authorsLastFirstLatexFree[abbreviationIndex] = LatexToUnicodeAdapter.format(getAsLastFirstNames(abbreviate, oxfordComma)); + return authorsLastFirstLatexFree[abbreviationIndex]; } @Override @@ -509,22 +548,22 @@ public String toString() { * @return formatted list of authors. */ public String getAsLastFirstNamesWithAnd(boolean abbreviate) { - int abbrInt = abbreviate ? 0 : 1; + int abbreviationIndex = abbreviate ? 0 : 1; // Check if we've computed this before: - if (authorLastFirstAnds[abbrInt] != null) { - return authorLastFirstAnds[abbrInt]; + if (authorLastFirstAnds[abbreviationIndex] != null) { + return authorLastFirstAnds[abbreviationIndex]; } - authorLastFirstAnds[abbrInt] = getAuthors().stream().map(author -> author.getLastFirst(abbreviate)) + authorLastFirstAnds[abbreviationIndex] = getAuthors().stream().map(author -> author.getLastFirst(abbreviate)) .collect(Collectors.joining(" and ")); - return authorLastFirstAnds[abbrInt]; + return authorLastFirstAnds[abbreviationIndex]; } public String getAsLastFirstFirstLastNamesWithAnd(boolean abbreviate) { - int abbrInt = abbreviate ? 0 : 1; + int abbreviationIndex = abbreviate ? 0 : 1; // Check if we've computed this before: - if (authorsLastFirstFirstLast[abbrInt] != null) { - return authorsLastFirstFirstLast[abbrInt]; + if (authorsLastFirstFirstLast[abbreviationIndex] != null) { + return authorsLastFirstFirstLast[abbreviationIndex]; } StringBuilder result = new StringBuilder(); @@ -536,8 +575,8 @@ public String getAsLastFirstFirstLastNamesWithAnd(boolean abbreviate) { } } - authorsLastFirstFirstLast[abbrInt] = result.toString(); - return authorsLastFirstFirstLast[abbrInt]; + authorsLastFirstFirstLast[abbreviationIndex] = result.toString(); + return authorsLastFirstFirstLast[abbreviationIndex]; } /** @@ -555,29 +594,29 @@ public String getAsLastFirstFirstLastNamesWithAnd(boolean abbreviate) { * Smith and P. Black Brown"

  • * * - * @param abbr whether to abbreivate first names. + * @param abbreviate whether to abbreivate first names. * @param oxfordComma Whether to put a comma before the and at the end. * @return formatted list of authors. * @see serial comma for an detailed explaination about the * Oxford comma. */ - public String getAsFirstLastNames(boolean abbr, boolean oxfordComma) { + public String getAsFirstLastNames(boolean abbreviate, boolean oxfordComma) { - int abbrInt = abbr ? 0 : 1; - abbrInt += oxfordComma ? 0 : 2; + int abbreviationIndex = abbreviate ? 0 : 1; + abbreviationIndex += oxfordComma ? 0 : 2; // Check if we've computed this before: - if (authorsFirstFirst[abbrInt] != null) { - return authorsFirstFirst[abbrInt]; + if (authorsFirstFirst[abbreviationIndex] != null) { + return authorsFirstFirst[abbreviationIndex]; } StringBuilder result = new StringBuilder(); if (!isEmpty()) { - result.append(getAuthor(0).getFirstLast(abbr)); + result.append(getAuthor(0).getFirstLast(abbreviate)); int i = 1; while (i < (getNumberOfAuthors() - 1)) { result.append(", "); - result.append(getAuthor(i).getFirstLast(abbr)); + result.append(getAuthor(i).getFirstLast(abbreviate)); i++; } if ((getNumberOfAuthors() > 2) && oxfordComma) { @@ -585,11 +624,24 @@ public String getAsFirstLastNames(boolean abbr, boolean oxfordComma) { } if (getNumberOfAuthors() > 1) { result.append(" and "); - result.append(getAuthor(i).getFirstLast(abbr)); + result.append(getAuthor(i).getFirstLast(abbreviate)); } } - authorsFirstFirst[abbrInt] = result.toString(); - return authorsFirstFirst[abbrInt]; + authorsFirstFirst[abbreviationIndex] = result.toString(); + return authorsFirstFirst[abbreviationIndex]; + } + + public String getAsFirstLastNamesLatexFree(boolean abbreviate, boolean oxfordComma) { + int abbreviationIndex = abbreviate ? 0 : 1; + abbreviationIndex += oxfordComma ? 0 : 2; + + // Check if we've computed this before: + if (authorsFirstFirstLatexFree[abbreviationIndex] != null) { + return authorsFirstFirstLatexFree[abbreviationIndex]; + } + + authorsFirstFirstLatexFree[abbreviationIndex] = LatexToUnicodeAdapter.format(getAsFirstLastNames(abbreviate, oxfordComma)); + return authorsFirstFirstLatexFree[abbreviationIndex]; } /** @@ -660,7 +712,7 @@ public String getForAlphabetization() { return authorsAlph; } - public void addAuthor(String first, String firstabbr, String von, String last, String jr) { - authors.add(new Author(first, firstabbr, von, last, jr)); + public void addAuthor(String first, String firstNameAbbreviation, String von, String last, String jr) { + authors.add(new Author(first, firstNameAbbreviation, von, last, jr)); } } diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java index 6d42a9d7ac6..e7d44365ec2 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java @@ -1,10 +1,12 @@ package org.jabref.logic.bibtexkeypattern; +import java.util.Collections; import java.util.Optional; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParseException; import org.jabref.logic.importer.fileformat.BibtexParser; +import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -52,17 +54,38 @@ void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } + static String generateKey(BibEntry entry, String pattern) { + return generateKey(entry, pattern, new BibDatabase()); + } + + static String generateKey(BibEntry entry, String pattern, BibDatabase database) { + GlobalBibtexKeyPattern keyPattern = new GlobalBibtexKeyPattern(Collections.emptyList()); + keyPattern.setDefaultValue("[" + pattern + "]"); + BibtexKeyPatternPreferences patternPreferences = new BibtexKeyPatternPreferences( + false, + false, + false, + BibtexKeyPatternPreferences.KeySuffix.SECOND_WITH_A, + "", + "", + DEFAULT_UNWANTED_CHARACTERS, + keyPattern, + ','); + + return new BibtexKeyGenerator(keyPattern, database, patternPreferences).generateKey(entry); + } + @Test void testAndInAuthorName() throws ParseException { Optional entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Simon Holland}}", importFormatPreferences, fileMonitor); assertEquals("Holland", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testCrossrefAndInAuthorNames() throws Exception { + void testCrossrefAndInAuthorNames() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -73,7 +96,7 @@ void testCrossrefAndInAuthorNames() throws Exception { database.insertEntry(entry2); assertEquals("Holland", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "auth", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -82,12 +105,12 @@ void testAndAuthorNames() throws ParseException { String bibtexString = "@ARTICLE{whatevery, author={Mari D. Herland and Mona-Iren Hauge and Ingeborg M. Helgeland}}"; Optional entry = BibtexParser.singleFromString(bibtexString, importFormatPreferences, fileMonitor); assertEquals("HerlandHaugeHelgeland", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "authors3", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "authors3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testCrossrefAndAuthorNames() throws Exception { + void testCrossrefAndAuthorNames() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -98,7 +121,7 @@ void testCrossrefAndAuthorNames() throws Exception { database.insertEntry(entry2); assertEquals("HerlandHaugeHelgeland", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "authors3", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "authors3", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -107,7 +130,7 @@ void testSpecialLatexCharacterInAuthorName() throws ParseException { Optional entry = BibtexParser.singleFromString( "@ARTICLE{kohn, author={Simon Popovi\\v{c}ov\\'{a}}}", importFormatPreferences, fileMonitor); assertEquals("Popovicova", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @@ -121,73 +144,73 @@ void testMakeLabelAndCheckLegalKeys() throws ParseException { Optional entry0 = BibtexParser.singleFromString( "@ARTICLE{kohn, author={Andreas Köning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Koe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Áöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Aoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Éöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Eoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Íöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Ioe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ĺöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Loe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ńöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Noe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Óöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Ooe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ŕöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Roe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Śöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Soe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Úöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Uoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ýöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Yoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Źöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Zoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @@ -199,57 +222,56 @@ void testMakeLabelAndCheckLegalKeysAccentGrave() throws ParseException { Optional entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Àöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Aoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Èöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Eoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ìöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Ioe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Òöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Ooe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ùöning}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Uoe", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Oraib Al-Ketan}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("AlK", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andrés D'Alessandro}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("DAl", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andrés Aʹrnold}, year={2000}}", importFormatPreferences, fileMonitor); assertEquals("Arn", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + BibtexKeyGenerator.cleanKey(generateKey(entry0.orElse(null), "auth3", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } /** - * Tests if checkLegalKey replaces Non-ASCII chars. There are quite a few chars that should be replaced. Perhaps + * Tests if cleanKey replaces Non-ASCII chars. There are quite a few chars that should be replaced. Perhaps * there is a better method than the current. - * - * @see BibtexKeyGenerator#checkLegalKey(String) + * @see BibtexKeyGenerator#cleanKey(String, String) */ @Test void testCheckLegalKey() { @@ -330,12 +352,12 @@ void testUniversity() throws ParseException { Optional entry = BibtexParser.singleFromString( "@ARTICLE{kohn, author={{Link{\\\"{o}}ping University}}}", importFormatPreferences, fileMonitor); assertEquals("UniLinkoeping", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testcrossrefUniversity() throws Exception { + void testcrossrefUniversity() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -346,7 +368,7 @@ void testcrossrefUniversity() throws Exception { database.insertEntry(entry2); assertEquals("UniLinkoeping", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "auth", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -356,12 +378,12 @@ void testDepartment() throws ParseException { "@ARTICLE{kohn, author={{Link{\\\"{o}}ping University, Department of Electrical Engineering}}}", importFormatPreferences, fileMonitor); assertEquals("UniLinkoepingEE", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testcrossrefDepartment() throws Exception { + void testcrossrefDepartment() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -372,7 +394,7 @@ void testcrossrefDepartment() throws Exception { database.insertEntry(entry2); assertEquals("UniLinkoepingEE", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "auth", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -382,12 +404,32 @@ void testSchool() throws ParseException { "@ARTICLE{kohn, author={{Link{\\\"{o}}ping University, School of Computer Engineering}}}", importFormatPreferences, fileMonitor); assertEquals("UniLinkoepingCE", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", + new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); + } + + @Test + void generateKeyAbbreviateCorporateAuthorDepartmentWithoutAcademicInstitute() throws ParseException { + Optional entry = BibtexParser.singleFromString( + "@ARTICLE{null, author={{Department of Localhost NullGenerators}}}", + importFormatPreferences, fileMonitor); + assertEquals("DLN", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", + new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); + } + + @Test + void generateKeyAbbreviateCorporateAuthorSchoolWithoutAcademicInstitute() throws ParseException { + Optional entry = BibtexParser.singleFromString( + "@ARTICLE{null, author={{The School of Null}}}", + importFormatPreferences, fileMonitor); + assertEquals("SchoolNull", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testcrossrefSchool() throws Exception { + void testcrossrefSchool() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -398,7 +440,7 @@ void testcrossrefSchool() throws Exception { database.insertEntry(entry2); assertEquals("UniLinkoepingCE", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "auth", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -407,12 +449,12 @@ void testInstituteOfTechnology() throws ParseException { Optional entry = BibtexParser.singleFromString( "@ARTICLE{kohn, author={{Massachusetts Institute of Technology}}}", importFormatPreferences, fileMonitor); assertEquals("MIT", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry.get(), "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry.orElse(null), "auth", new BibDatabase()), DEFAULT_UNWANTED_CHARACTERS)); } @Test - void testcrossrefInstituteOfTechnology() throws Exception { + void testcrossrefInstituteOfTechnology() { BibDatabase database = new BibDatabase(); BibEntry entry1 = new BibEntry(); entry1.setField(StandardField.CROSSREF, "entry2"); @@ -423,7 +465,7 @@ void testcrossrefInstituteOfTechnology() throws Exception { database.insertEntry(entry2); assertEquals("MIT", - BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry1, "auth", + BibtexKeyGenerator.cleanKey(generateKey(entry1, "auth", database), DEFAULT_UNWANTED_CHARACTERS)); } @@ -709,6 +751,8 @@ void testFirstPage() { assertEquals("43", BibtexKeyGenerator.firstPage("43+")); } + @SuppressWarnings("ConstantConditions") + @Test void testFirstPageNull() { assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.firstPage(null)); } @@ -731,6 +775,7 @@ void testPagePrefix() { assertEquals("", BibtexKeyGenerator.pagePrefix("43+")); } + @SuppressWarnings("ConstantConditions") @Test void testPagePrefixNull() { assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.pagePrefix(null)); @@ -748,6 +793,7 @@ void testLastPage() { assertEquals("43", BibtexKeyGenerator.lastPage("43+")); } + @SuppressWarnings("ConstantConditions") @Test void testLastPageNull() { assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.lastPage(null)); @@ -879,16 +925,13 @@ void keywordNKeywordsSeparatedBySpace() { BibEntry entry = new BibEntry(); entry.setField(StandardField.KEYWORDS, "w1, w2a w2b, w3"); - String result = BibtexKeyGenerator.generateKey(entry, "keyword1"); - assertEquals("w1", result); + assertEquals("w1", generateKey(entry, "keyword1")); // check keywords with space - result = BibtexKeyGenerator.generateKey(entry, "keyword2"); - assertEquals("w2aw2b", result); + assertEquals("w2aw2b", generateKey(entry, "keyword2")); // check out of range - result = BibtexKeyGenerator.generateKey(entry, "keyword4"); - assertEquals("", result); + assertEquals("", generateKey(entry, "keyword4")); } @Test @@ -902,9 +945,7 @@ void crossrefkeywordNKeywordsSeparatedBySpace() { database.insertEntry(entry1); entry2.setField(StandardField.KEYWORDS, "w1, w2a w2b, w3"); - String result = BibtexKeyGenerator.generateKey(entry1, "keyword1", database); - - assertEquals("w1", result); + assertEquals("w1", generateKey(entry1, "keyword1", database)); } @Test @@ -913,16 +954,13 @@ void keywordsNKeywordsSeparatedBySpace() { entry.setField(StandardField.KEYWORDS, "w1, w2a w2b, w3"); // all keywords - String result = BibtexKeyGenerator.generateKey(entry, "keywords"); - assertEquals("w1w2aw2bw3", result); + assertEquals("w1w2aw2bw3", generateKey(entry, "keywords")); // check keywords with space - result = BibtexKeyGenerator.generateKey(entry, "keywords2"); - assertEquals("w1w2aw2b", result); + assertEquals("w1w2aw2b", generateKey(entry, "keywords2")); // check out of range - result = BibtexKeyGenerator.generateKey(entry, "keywords55"); - assertEquals("w1w2aw2bw3", result); + assertEquals("w1w2aw2bw3", generateKey(entry, "keywords55")); } @Test @@ -936,9 +974,7 @@ void crossrefkeywordsNKeywordsSeparatedBySpace() { database.insertEntry(entry1); entry2.setField(StandardField.KEYWORDS, "w1, w2a w2b, w3"); - String result = BibtexKeyGenerator.generateKey(entry1, "keywords", database); - - assertEquals("w1w2aw2bw3", result); + assertEquals("w1w2aw2bw3", generateKey(entry1, "keywords", database)); } @Test @@ -965,8 +1001,8 @@ void testCheckLegalNullInNullOut() { void testApplyModifiers() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "Green Scheduling of Whatever"); - assertEquals("GSo", BibtexKeyGenerator.generateKey(entry, "shorttitleINI")); - assertEquals("GreenSchedulingWhatever", BibtexKeyGenerator.generateKey(entry, "shorttitle", + assertEquals("GSo", generateKey(entry, "shorttitleINI")); + assertEquals("GreenSchedulingWhatever", generateKey(entry, "shorttitle", new BibDatabase())); } @@ -981,7 +1017,7 @@ void testcrossrefShorttitle() { database.insertEntry(entry1); entry2.setField(StandardField.TITLE, "Green Scheduling of Whatever"); - assertEquals("GreenSchedulingWhatever", BibtexKeyGenerator.generateKey(entry1, "shorttitle", + assertEquals("GreenSchedulingWhatever", generateKey(entry1, "shorttitle", database)); } @@ -996,105 +1032,105 @@ void testcrossrefShorttitleInitials() { database.insertEntry(entry1); entry2.setField(StandardField.TITLE, "Green Scheduling of Whatever"); - assertEquals("GSo", BibtexKeyGenerator.generateKey(entry1, "shorttitleINI", database)); + assertEquals("GSo", generateKey(entry1, "shorttitleINI", database)); } @Test - void generateKeyStripsColonFromTitle() throws Exception { + void generateKeyStripsColonFromTitle() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "Green Scheduling of: Whatever"); - assertEquals("GreenSchedulingOfWhatever", BibtexKeyGenerator.generateKey(entry, "title")); + assertEquals("GreenSchedulingOfWhatever", generateKey(entry, "title")); } @Test - void generateKeyStripsApostropheFromTitle() throws Exception { + void generateKeyStripsApostropheFromTitle() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "Green Scheduling of `Whatever`"); - assertEquals("GreenSchedulingofWhatever", BibtexKeyGenerator.generateKey(entry, "title")); + assertEquals("GreenSchedulingofWhatever", generateKey(entry, "title")); } @Test - void generateKeyWithOneModifier() throws Exception { + void generateKeyWithOneModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "The Interesting Title"); - assertEquals("theinterestingtitle", BibtexKeyGenerator.generateKey(entry, "title:lower")); + assertEquals("theinterestingtitle", generateKey(entry, "title:lower")); } @Test - void generateKeyWithTwoModifiers() throws Exception { + void generateKeyWithTwoModifiers() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "The Interesting Title"); - assertEquals("theinterestingtitle", BibtexKeyGenerator.generateKey(entry, "title:lower:(_)")); + assertEquals("theinterestingtitle", generateKey(entry, "title:lower:(_)")); } @Test - void generateKeyWithTitleCapitalizeModifier() throws Exception { + void generateKeyWithTitleCapitalizeModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "the InTeresting title longer than THREE words"); - assertEquals("TheInterestingTitleLongerThanThreeWords", BibtexKeyGenerator.generateKey(entry, "title:capitalize")); + assertEquals("TheInterestingTitleLongerThanThreeWords", generateKey(entry, "title:capitalize")); } @Test - void generateKeyWithShortTitleCapitalizeModifier() throws Exception { + void generateKeyWithShortTitleCapitalizeModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "the InTeresting title longer than THREE words"); - assertEquals("InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "shorttitle:capitalize")); + assertEquals("InterestingTitleLonger", generateKey(entry, "shorttitle:capitalize")); } @Test - void generateKeyWithTitleTitleCaseModifier() throws Exception { + void generateKeyWithTitleTitleCaseModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "A title WITH some of The key words"); - assertEquals("ATitlewithSomeoftheKeyWords", BibtexKeyGenerator.generateKey(entry, "title:titlecase")); + assertEquals("ATitlewithSomeoftheKeyWords", generateKey(entry, "title:titlecase")); } @Test - void generateKeyWithShortTitleTitleCaseModifier() throws Exception { + void generateKeyWithShortTitleTitleCaseModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "the InTeresting title longer than THREE words"); - assertEquals("InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "shorttitle:titlecase")); + assertEquals("InterestingTitleLonger", generateKey(entry, "shorttitle:titlecase")); } @Test - void generateKeyWithTitleSentenceCaseModifier() throws Exception { + void generateKeyWithTitleSentenceCaseModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "A title WITH some of The key words"); - assertEquals("Atitlewithsomeofthekeywords", BibtexKeyGenerator.generateKey(entry, "title:sentencecase")); + assertEquals("Atitlewithsomeofthekeywords", generateKey(entry, "title:sentencecase")); } @Test - void generateKeyWithAuthUpperYearShortTitleCapitalizeModifier() throws Exception { + void generateKeyWithAuthUpperYearShortTitleCapitalizeModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_1); entry.setField(StandardField.YEAR, "2019"); entry.setField(StandardField.TITLE, "the InTeresting title longer than THREE words"); - assertEquals("NEWTON2019InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "[auth:upper][year][shorttitle:capitalize]")); + assertEquals("NEWTON2019InterestingTitleLonger", generateKey(entry, "[auth:upper][year][shorttitle:capitalize]")); } @Test - void generateKeyWithYearAuthUpperTitleSentenceCaseModifier() throws Exception { + void generateKeyWithYearAuthUpperTitleSentenceCaseModifier() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_3); entry.setField(StandardField.YEAR, "2019"); entry.setField(StandardField.TITLE, "the InTeresting title longer than THREE words"); - assertEquals("NewtonMaxwellEtAl_2019_TheInterestingTitleLongerThanThreeWords", BibtexKeyGenerator.generateKey(entry, "[authors2]_[year]_[title:capitalize]")); + assertEquals("NewtonMaxwellEtAl_2019_TheInterestingTitleLongerThanThreeWords", generateKey(entry, "[authors2]_[year]_[title:capitalize]")); } @Test - void generateKeyWithMinusInCitationStyleOutsideAField() throws Exception { + void generateKeyWithMinusInCitationStyleOutsideAField() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_1); entry.setField(StandardField.YEAR, "2019"); - assertEquals("Newton-2019", BibtexKeyGenerator.generateKey(entry, "[auth]-[year]")); + assertEquals("Newton-2019", generateKey(entry, "[auth]-[year]")); } @Test - void generateKeyWithWithFirstNCharacters() throws Exception { + void generateKeyWithWithFirstNCharacters() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Newton, Isaac"); entry.setField(StandardField.YEAR, "2019"); - assertEquals("newt-2019", BibtexKeyGenerator.generateKey(entry, "[auth4:lower]-[year]")); + assertEquals("newt-2019", generateKey(entry, "[auth4:lower]-[year]")); } } diff --git a/src/test/java/org/jabref/model/entry/AuthorListTest.java b/src/test/java/org/jabref/model/entry/AuthorListTest.java index 77bb79b5b7d..eda59858ac6 100644 --- a/src/test/java/org/jabref/model/entry/AuthorListTest.java +++ b/src/test/java/org/jabref/model/entry/AuthorListTest.java @@ -7,15 +7,58 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class AuthorListTest { + /* + Examples are similar to page 4 in + [BibTeXing by Oren Patashnik](https://ctan.org/tex-archive/biblio/bibtex/contrib/doc/) + */ + private static final String MUHAMMAD_ALKHWARIZMI = "Mu{\\d{h}}ammad al-Khw{\\={a}}rizm{\\={i}}"; + private static final String CORRADO_BOHM = "Corrado B{\\\"o}hm"; + private static final String KURT_GODEL = "Kurt G{\\\"{o}}del"; + private static final String BANU_MOSA = "{The Ban\\={u} M\\={u}s\\={a} brothers}"; + public static int size(String bibtex) { return AuthorList.parse(bibtex).getNumberOfAuthors(); } + private static AuthorList emptyAuthor() { + return AuthorList.parse(""); + } + + private static AuthorList oneAuthorWithLatex() { + return AuthorList.parse(MUHAMMAD_ALKHWARIZMI); + } + + private static AuthorList twoAuthorsWithLatex() { + return AuthorList.parse(MUHAMMAD_ALKHWARIZMI + " and " + CORRADO_BOHM); + } + + private static AuthorList threeAuthorsWithLatex() { + return AuthorList.parse(MUHAMMAD_ALKHWARIZMI + " and " + CORRADO_BOHM + " and " + KURT_GODEL); + } + + private static AuthorList oneInstitutionWithLatex() { + return AuthorList.parse(BANU_MOSA); + } + + private static AuthorList oneInstitutionWithParanthesisAtStart() { + return AuthorList.parse("{{\\L{}}ukasz Micha\\l{}}"); + } + + private static AuthorList twoInstitutionsWithLatex() { + return AuthorList.parse(BANU_MOSA + " and " + BANU_MOSA); + } + + private static AuthorList mixedAuthorAndInstituteWithLatex() { + return AuthorList.parse(BANU_MOSA + " and " + CORRADO_BOHM); + } + @Test public void testFixAuthorNatbib() { assertEquals("", AuthorList.fixAuthorNatbib("")); @@ -26,9 +69,62 @@ public void testFixAuthorNatbib() { .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter")); // Is not cached! - assertTrue(AuthorList - .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList - .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter"))); + assertSame(AuthorList + .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter"), AuthorList + .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter")); + } + + @Test + public void getAsNatbibLatexFreeEmptyAuthorStringForEmptyInput() { + assertEquals("", emptyAuthor().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeCachesLatexFreeString() { + String cachedString = oneAuthorWithLatex().getAsNatbibLatexFree(); + assertSame(cachedString, oneAuthorWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeOneAuthorNameFromLatex() { + assertEquals("al-Khwārizmī", + oneAuthorWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeTwoAuthorNamesFromLatex() { + assertEquals("al-Khwārizmī and Böhm", + twoAuthorsWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeAuthorEtAlFromLatex() { + assertEquals("al-Khwārizmī et al.", + threeAuthorsWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeOneInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeTwoInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeUnicodeMixedAuthorsFromLatex() { + assertEquals("The Banū Mūsā brothers and Böhm", + mixedAuthorAndInstituteWithLatex().getAsNatbibLatexFree()); + } + + @Test + public void getAsNatbibLatexFreeOneInstitutionWithParanthesisAtStart() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsNatbibLatexFree()); } @Test @@ -36,7 +132,7 @@ public void testGetAuthorList() { // Test caching in authorCache. AuthorList al = AuthorList.parse("John Smith"); assertEquals(al, AuthorList.parse("John Smith")); - assertFalse(al.equals(AuthorList.parse("Smith"))); + assertNotEquals(al, AuthorList.parse("Smith")); } @Test @@ -52,10 +148,9 @@ public void testFixAuthorFirstNameFirstCommas() { false)); // Check caching - assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( - "John von Neumann and John Smith and Black Brown, Peter", true, false).equals( - AuthorList - .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, false))); + assertEquals(AuthorList.fixAuthorFirstNameFirstCommas( + "John von Neumann and John Smith and Black Brown, Peter", true, false), AuthorList + .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, false)); assertEquals("John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas("John Smith and Black Brown, Peter", false, false)); @@ -83,10 +178,9 @@ public void testFixAuthorFirstNameFirstCommas() { true)); // Check caching - assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( - "John von Neumann and John Smith and Black Brown, Peter", true, true).equals( - AuthorList - .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, true))); + assertEquals(AuthorList.fixAuthorFirstNameFirstCommas( + "John von Neumann and John Smith and Black Brown, Peter", true, true), AuthorList + .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, true)); assertEquals("John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas("John Smith and Black Brown, Peter", false, true)); @@ -106,6 +200,111 @@ public void testFixAuthorFirstNameFirstCommas() { "John Peter von Neumann", true, true)); } + @Test + public void getAsFirstLastNamesLatexFreeEmptyAuthorStringForEmptyInputAbbr() { + assertEquals("", emptyAuthor().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeCachesLatexFreeStringAbbr() { + String cachedString = oneAuthorWithLatex().getAsFirstLastNamesLatexFree(true, false); + assertSame(cachedString, oneAuthorWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeOneAuthorNameFromLatexAbbr() { + assertEquals("M. al-Khwārizmī", + oneAuthorWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeTwoAuthorNamesFromLatexAbbr() { + assertEquals("M. al-Khwārizmī and C. Böhm", + twoAuthorsWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeThreeUnicodeAuthorsFromLatexAbbr() { + assertEquals("M. al-Khwārizmī, C. Böhm and K. Gödel", + threeAuthorsWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeOneInsitutionNameFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers", oneInstitutionWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeTwoInsitutionNameFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeMixedAuthorsFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers and C. Böhm", + mixedAuthorAndInstituteWithLatex().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeOneInstitutionWithParanthesisAtStartAbbr() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsFirstLastNamesLatexFree(true, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeEmptyAuthorStringForEmptyInput() { + assertEquals("", emptyAuthor().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeCachesLatexFreeString() { + String cachedString = oneAuthorWithLatex().getAsFirstLastNamesLatexFree(false, false); + assertSame(cachedString, oneAuthorWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeOneAuthorNameFromLatex() { + assertEquals("Muḥammad al-Khwārizmī", + oneAuthorWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeTwoAuthorNamesFromLatex() { + assertEquals("Muḥammad al-Khwārizmī and Corrado Böhm", + twoAuthorsWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeThreeUnicodeAuthorsFromLatex() { + assertEquals("Muḥammad al-Khwārizmī, Corrado Böhm and Kurt Gödel", + threeAuthorsWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeOneInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeTwoInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeUnicodeMixedAuthorsFromLatex() { + assertEquals("The Banū Mūsā brothers and Corrado Böhm", + mixedAuthorAndInstituteWithLatex().getAsFirstLastNamesLatexFree(false, false)); + } + + @Test + public void getAsFirstLastNamesLatexFreeOneInstitutionWithParanthesisAtStart() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsFirstLastNamesLatexFree(false, false)); + } + @Test public void testFixAuthorFirstNameFirst() { assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirst("John Smith")); @@ -120,9 +319,9 @@ public void testFixAuthorFirstNameFirst() { .fixAuthorFirstNameFirst("von Last, Jr. III, First")); // Check caching - assertTrue(AuthorList - .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList - .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter"))); + assertEquals(AuthorList + .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter"), AuthorList + .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter")); } @Test @@ -141,7 +340,7 @@ public void testFixAuthorLastNameFirstCommasNoComma() { // Check caching assertEquals(a, b); - assertTrue(a.equals(b)); + assertSame(a, b); assertEquals("Smith, John and Black Brown, Peter", AuthorList.fixAuthorLastNameFirstCommas("John Smith and Black Brown, Peter", false, false)); @@ -174,7 +373,7 @@ public void testFixAuthorLastNameFirstCommasOxfordComma() { // Check caching assertEquals(a, b); - assertTrue(a.equals(b)); + assertSame(a, b); assertEquals("Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirstCommas("John Smith and Black Brown, Peter", false, true)); @@ -192,6 +391,218 @@ public void testFixAuthorLastNameFirstCommasOxfordComma() { "John Peter von Neumann", true, true)); } + @Test + public void getAsLastFirstNamesLatexFreeEmptyAuthorStringForEmptyInputAbbr() { + assertEquals("", emptyAuthor().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeCachesLatexFreeStringAbbr() { + String cachedString = oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, false); + assertSame(cachedString, oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneAuthorNameFromLatexAbbr() { + assertEquals("al-Khwārizmī, M.", + oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoAuthorNamesFromLatexAbbr() { + assertEquals("al-Khwārizmī, M. and Böhm, C.", + twoAuthorsWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeThreeUnicodeAuthorsFromLatexAbbr() { + assertEquals("al-Khwārizmī, M., Böhm, C. and Gödel, K.", + threeAuthorsWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneInsitutionNameFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoInsitutionNameFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeMixedAuthorsFromLatexAbbr() { + assertEquals("The Banū Mūsā brothers and Böhm, C.", + mixedAuthorAndInstituteWithLatex().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeOneInstitutionWithParanthesisAtStartAbbr() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsLastFirstNamesLatexFree(true, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeEmptyAuthorStringForEmptyInput() { + assertEquals("", emptyAuthor().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeCachesLatexFreeString() { + String cachedString = oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, false); + assertSame(cachedString, oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneAuthorNameFromLatex() { + assertEquals("al-Khwārizmī, Muḥammad", + oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoAuthorNamesFromLatex() { + assertEquals("al-Khwārizmī, Muḥammad and Böhm, Corrado", + twoAuthorsWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeThreeUnicodeAuthorsFromLatex() { + assertEquals("al-Khwārizmī, Muḥammad, Böhm, Corrado and Gödel, Kurt", + threeAuthorsWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeMixedAuthorsFromLatex() { + assertEquals("The Banū Mūsā brothers and Böhm, Corrado", + mixedAuthorAndInstituteWithLatex().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeOneInstitutionWithParanthesisAtStart() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsLastFirstNamesLatexFree(false, false)); + } + + @Test + public void getAsLastFirstNamesLatexFreeEmptyAuthorStringForEmptyInputAbbrOxfordComma() { + assertEquals("", emptyAuthor().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeCachesLatexFreeStringAbbrOxfordComma() { + String cachedString = oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, true); + assertSame(cachedString, oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneAuthorNameFromLatexAbbrOxfordComma() { + assertEquals("al-Khwārizmī, M.", + oneAuthorWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoAuthorNamesFromLatexAbbrOxfordComma() { + assertEquals("al-Khwārizmī, M. and Böhm, C.", + twoAuthorsWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeThreeUnicodeAuthorsFromLatexAbbrOxfordComma() { + assertEquals("al-Khwārizmī, M., Böhm, C., and Gödel, K.", + threeAuthorsWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneInsitutionNameFromLatexAbbrOxfordComma() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoInsitutionNameFromLatexAbbrOxfordComma() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeMixedAuthorsFromLatexAbbrOxfordComma() { + assertEquals("The Banū Mūsā brothers and Böhm, C.", + mixedAuthorAndInstituteWithLatex().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeOneInstitutionWithParanthesisAtStartAbbrOxfordComma() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsLastFirstNamesLatexFree(true, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeEmptyAuthorStringForEmptyInputOxfordComma() { + assertEquals("", emptyAuthor().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeCachesLatexFreeStringOxfordComma() { + String cachedString = oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, true); + assertSame(cachedString, oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneAuthorNameFromLatexOxfordComma() { + assertEquals("al-Khwārizmī, Muḥammad", + oneAuthorWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoAuthorNamesFromLatexOxfordComma() { + assertEquals("al-Khwārizmī, Muḥammad and Böhm, Corrado", + twoAuthorsWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeThreeUnicodeAuthorsFromLatexOxfordComma() { + assertEquals("al-Khwārizmī, Muḥammad, Böhm, Corrado, and Gödel, Kurt", + threeAuthorsWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeOneInsitutionNameFromLatexOxfordComma() { + assertEquals("The Banū Mūsā brothers", + oneInstitutionWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeTwoInsitutionNameFromLatexOxfordComma() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeUnicodeMixedAuthorsFromLatexOxfordComma() { + assertEquals("The Banū Mūsā brothers and Böhm, Corrado", + mixedAuthorAndInstituteWithLatex().getAsLastFirstNamesLatexFree(false, true)); + } + + @Test + public void getAsLastFirstNamesLatexFreeOneInstitutionWithParanthesisAtStartOxfordComma() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsLastFirstNamesLatexFree(false, true)); + } + @Test public void testFixAuthorLastNameFirst() { @@ -208,9 +619,9 @@ public void testFixAuthorLastNameFirst() { assertEquals("von Last, Jr, First", AuthorList .fixAuthorLastNameFirst("von Last, Jr ,First")); - assertTrue(AuthorList - .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList - .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter"))); + assertEquals(AuthorList + .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter"), AuthorList + .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter")); // Test Abbreviation == false assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirst("John Smith", false)); @@ -225,10 +636,9 @@ public void testFixAuthorLastNameFirst() { assertEquals("von Last, Jr, First", AuthorList.fixAuthorLastNameFirst( "von Last, Jr ,First", false)); - assertTrue(AuthorList.fixAuthorLastNameFirst( - "John von Neumann and John Smith and Black Brown, Peter", false).equals( - AuthorList - .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", false))); + assertEquals(AuthorList.fixAuthorLastNameFirst( + "John von Neumann and John Smith and Black Brown, Peter", false), AuthorList + .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", false)); // Test Abbreviate == true assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirst("John Smith", true)); @@ -243,10 +653,9 @@ public void testFixAuthorLastNameFirst() { assertEquals("von Last, Jr, F.", AuthorList.fixAuthorLastNameFirst("von Last, Jr ,First", true)); - assertTrue(AuthorList.fixAuthorLastNameFirst( - "John von Neumann and John Smith and Black Brown, Peter", true).equals( - AuthorList - .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", true))); + assertEquals(AuthorList.fixAuthorLastNameFirst( + "John von Neumann and John Smith and Black Brown, Peter", true), AuthorList + .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", true)); } @Test @@ -257,10 +666,9 @@ public void testFixAuthorLastNameOnlyCommas() { assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", false)); assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", false)); - assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( - "John von Neumann and John Smith and Black Brown, Peter", false).equals( - AuthorList - .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", false))); + assertEquals(AuthorList.fixAuthorLastNameOnlyCommas( + "John von Neumann and John Smith and Black Brown, Peter", false), AuthorList + .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", false)); assertEquals("von Neumann, Smith and Black Brown", AuthorList .fixAuthorLastNameOnlyCommas( @@ -270,16 +678,59 @@ public void testFixAuthorLastNameOnlyCommas() { assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", true)); assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", true)); - assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( - "John von Neumann and John Smith and Black Brown, Peter", true).equals( - AuthorList - .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", true))); + assertEquals(AuthorList.fixAuthorLastNameOnlyCommas( + "John von Neumann and John Smith and Black Brown, Peter", true), AuthorList + .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", true)); assertEquals("von Neumann, Smith, and Black Brown", AuthorList .fixAuthorLastNameOnlyCommas( "John von Neumann and John Smith and Black Brown, Peter", true)); } + @Test + public void getAsLastNamesLatexFreeCachesLatexFreeString() { + String cachedString = oneAuthorWithLatex().getAsLastNamesLatexFree(false); + assertSame(cachedString, oneAuthorWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeOneAuthorNameFromLatex() { + assertEquals("al-Khwārizmī", oneAuthorWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeTwoAuthorNamesFromLatex() { + assertEquals("al-Khwārizmī and Böhm", twoAuthorsWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeThreeUnicodeAuthorsFromLatex() { + assertEquals("al-Khwārizmī, Böhm and Gödel", threeAuthorsWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeOneInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers", oneInstitutionWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeTwoInsitutionNameFromLatex() { + assertEquals("The Banū Mūsā brothers and The Banū Mūsā brothers", + twoInstitutionsWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeUnicodeMixedAuthorsFromLatex() { + assertEquals("The Banū Mūsā brothers and Böhm", + mixedAuthorAndInstituteWithLatex().getAsLastNamesLatexFree(false)); + } + + @Test + public void getAsLastNamesLatexFreeOneInstitutionWithParanthesisAtStart() { + assertEquals("Łukasz Michał", + oneInstitutionWithParanthesisAtStart().getAsLastNamesLatexFree(false)); + } + @Test public void testFixAuthorForAlphabetization() { assertEquals("Smith, J.", AuthorList.fixAuthorForAlphabetization("John Smith")); @@ -409,7 +860,7 @@ public void testGetAuthorsNatbib() { // Test caching AuthorList al = AuthorList .parse("John von Neumann and John Smith and Black Brown, Peter"); - assertTrue(al.getAsNatbib().equals(al.getAsNatbib())); + assertEquals(al.getAsNatbib(), al.getAsNatbib()); } @Test @@ -654,6 +1105,36 @@ public void parseNameWithBraces() throws Exception { assertEquals(new AuthorList(expected), AuthorList.parse("H{e}lene Fiaux")); } + @Test + public void parseFirstNameFromFirstAuthorMultipleAuthorsWithLatexNames() throws Exception { + assertEquals("Mu{\\d{h}}ammad", + twoAuthorsWithLatex().getAuthor(0).getFirst().orElse(null)); + } + + @Test + public void parseFirstNameFromSecondAuthorMultipleAuthorsWithLatexNames() throws Exception { + assertEquals("Corrado", + twoAuthorsWithLatex().getAuthor(1).getFirst().orElse(null)); + } + + @Test + public void parseLastNameFromFirstAuthorMultipleAuthorsWithLatexNames() throws Exception { + assertEquals("al-Khw{\\={a}}rizm{\\={i}}", + twoAuthorsWithLatex().getAuthor(0).getLast().orElse(null)); + } + + @Test + public void parseLastNameFromSecondAuthorMultipleAuthorsWithLatexNames() throws Exception { + assertEquals("B{\\\"o}hm", + twoAuthorsWithLatex().getAuthor(1).getLast().orElse(null)); + } + + @Test + public void parseInstitutionAuthorWithLatexNames() throws Exception { + assertEquals("The Ban\\={u} M\\={u}s\\={a} brothers", + oneInstitutionWithLatex().getAuthor(0).getLast().orElse(null)); + } + /** * This tests the issue described at https://github.com/JabRef/jabref/pull/2669#issuecomment-288519458 */