Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for month issue and strings (and some minor code impr… #5531

Merged
merged 6 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/main/java/org/jabref/logic/shared/DBMSProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,10 @@ public List<BibEntry> getSharedEntries(List<Integer> sharedIDs) {
lastId = selectEntryResultSet.getInt("SHARED_ID");
}

bibEntry.setField(FieldFactory.parseField(selectEntryResultSet.getString("NAME")), Optional.ofNullable(selectEntryResultSet.getString("VALUE")), EntryEventSource.SHARED);
String value = selectEntryResultSet.getString("VALUE");
if (value != null) {
bibEntry.setField(FieldFactory.parseField(selectEntryResultSet.getString("NAME")), value, EntryEventSource.SHARED);
}
}
} catch (SQLException e) {
LOGGER.error("SQL Error", e);
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,10 @@ public void synchronizeLocalDatabase() {
localEntry.getSharedBibEntryData()
.setVersion(sharedEntry.get().getSharedBibEntryData().getVersion());
for (Field field : sharedEntry.get().getFields()) {
localEntry.setField(field, sharedEntry.get().getField(field), EntryEventSource.SHARED);
Optional<String> sharedFieldValue = sharedEntry.get().getField(field);
if (sharedFieldValue.isPresent()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a good use case for ifPresent lambda, I guess.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sharedEntry.get().getField(field).ifPresent((v) -> localEntry.setField)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for hint. I fixed a modification of an unmodifiable collection. Seems that this feature is used very seldom. Hope, it gets better.

localEntry.setField(field, sharedFieldValue.get(), EntryEventSource.SHARED);
}
}

Set<Field> redundantLocalEntryFields = localEntry.getFields();
Expand Down
43 changes: 34 additions & 9 deletions src/main/java/org/jabref/model/entry/BibEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,44 @@ public class BibEntry implements Cloneable {
private ObservableMap<Field, String> fields = FXCollections.observableMap(new ConcurrentHashMap<>());
private String parsedSerialization = "";
private String commentsBeforeEntry = "";

/**
* Marks whether the complete serialization, which was read from file, should be used.
*
* Is set to false, if parts of the entry change. This causes the entry to be serialized based on the internal state (and not based on the old serialization)
*/
private boolean changed;

/**
* A simple builder to enable quick creation of BibEntry instances.
*
* Builder pattern as described in Item 2 of the book "Effective Java".
*/
public static class Builder {

private BibEntry bibEntry;

public Builder(EntryType type) {
Objects.requireNonNull(type);
bibEntry = new BibEntry(type);
}

public Builder citeKey(String citeKey) {
bibEntry.setCiteKey(citeKey);
return this;
}

public Builder field(Field field, String value) {
koppor marked this conversation as resolved.
Show resolved Hide resolved
bibEntry.setField(field, value);
return this;
}

public BibEntry build() {
return bibEntry;
}

}

/**
* Constructs a new BibEntry. The internal ID is set to IdGenerator.next()
*/
Expand Down Expand Up @@ -266,8 +297,9 @@ public String getId() {
}

/**
* Sets this entry's ID, provided the database containing it
* doesn't veto the change.
* Sets this entry's identifier (ID). It is used internally to distinguish different BibTeX entries. It is <emph>not</emph> the BibTeX key. The BibTexKey is the {@link InternalField.KEY_FIELD}.
*
* The entry is also updated in the shared database - provided the database containing it doesn't veto the change.
*
* @param id The ID to be used
*/
Expand Down Expand Up @@ -523,13 +555,6 @@ public Optional<FieldChange> setField(Field field, String value, EntryEventSourc
return Optional.of(change);
}

public Optional<FieldChange> setField(Field field, Optional<String> value, EntryEventSource eventSource) {
if (value.isPresent()) {
return setField(field, value.get(), eventSource);
}
return Optional.empty();
}

/**
* Set a field, and notify listeners about the change.
*
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/org/jabref/model/entry/field/InternalField.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@
* JabRef internal fields
*/
public enum InternalField implements Field {
INTERNAL_ALL_FIELD("all"),
INTERNAL_ALL_TEXT_FIELDS_FIELD("all-text-fields"),
MARKED_INTERNAL("__markedentry"),
MARKED_INTERNAL("__markedentry"), // used in old versions of JabRef. Currently used for conversion only
OWNER("owner"),
TIMESTAMP("timestamp", FieldProperty.DATE),
GROUPS("groups"),
KEY_FIELD("bibtexkey"),
TYPE_HEADER("entrytype"),
OBSOLETE_TYPE_HEADER("bibtextype"),
BIBTEX_STRING("__string"),
// all field names starting with "Jabref-internal-" are not appearing in .bib files
BIBTEX_STRING("JabRef-internal-bibtex-string"), // marker that the content is just a BibTeX string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing these values might lead to problems as they are (maybe) stored in bib files as keys for save actions or in the preferences.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the usage of this string. It is called at the formatter only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but all and all-text-field should be used elsewhere too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really thought on these things and they MUST NOT stored in bib files. Otherwise, something will go completely wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken, they are used in the serialization of save actions, e.g.

@Comment{
   jabref-meta: saveActions:enabled;
   all[normalize_month]
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups. OK, I put the old values back.

INTERNAL_ALL_FIELD("JabRef-internal-all"), // virtual field to denote "all fields"
INTERNAL_ALL_TEXT_FIELDS_FIELD("JabRef-internal-all-text-fields"), // virtual field to denote "all text fields"
INTERNAL_ID_FIELD("JabRef-internal-id");

private final String name;
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/csl-locales
Submodule csl-locales updated 1 files
+10 −11 Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,56 @@ void writeEntryWithCustomizedTypeAlsoWritesTypeDeclaration() throws Exception {
}

@Test
void roundtrip() throws Exception {
void writeEntryWithConstantMonthApril() throws Exception {
BibEntry entry = new BibEntry.Builder(StandardEntryType.Misc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests should go to the BibEntryWriterTest as they are more concerned with a single entry than a complete database

.field(StandardField.MONTH, "#apr#")
.build();
database.insertEntry(entry);

databaseWriter.savePartOfDatabase(bibtexContext, Collections.singletonList(entry));

assertEquals(OS.NEWLINE +
"@Misc{," + OS.NEWLINE +
" month = apr," + OS.NEWLINE +
"}" + OS.NEWLINE + OS.NEWLINE +
"@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString());
}

@Test
void writeEntryWithMonthApril() throws Exception {
BibEntry entry = new BibEntry.Builder(StandardEntryType.Misc)
.field(StandardField.MONTH, "apr")
.build();
database.insertEntry(entry);

databaseWriter.savePartOfDatabase(bibtexContext, Collections.singletonList(entry));

assertEquals(OS.NEWLINE +
"@Misc{," + OS.NEWLINE +
" month = {apr}," + OS.NEWLINE +
"}" + OS.NEWLINE + OS.NEWLINE +
"@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString());
}

@Test
void roundtripWithArticleMonths() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/articleWithMonths.bib");
Charset encoding = StandardCharsets.UTF_8;
ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(Importer.getReader(testBibtexFile, encoding));

when(preferences.getEncoding()).thenReturn(encoding);
when(preferences.isSaveInOriginalOrder()).thenReturn(true);
BibDatabaseContext context = new BibDatabaseContext(result.getDatabase(), result.getMetaData(),
new Defaults(BibDatabaseMode.BIBTEX));

databaseWriter.savePartOfDatabase(context, result.getDatabase().getEntries());
try (Scanner scanner = new Scanner(testBibtexFile, encoding.name())) {
assertEquals(scanner.useDelimiter("\\A").next(), stringWriter.toString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Files.readAllLines instead of the Scanner?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried Files.readString. Failed, because of newline issues (LF vs. CRLF).

I came up with

Files.readAllLines(testBibtexFile, Charset.forName(encoding.name())).stream().collect(Collectors.joining(OS.NEWLINE)) + OS.NEWLINE

Feels more complicated and I can't really get it to work as the assertion fails, but "Contents are equal"

}
}

@Test
void roundtripWithComplexBib() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/complex.bib");
Charset encoding = StandardCharsets.UTF_8;
ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(Importer.getReader(testBibtexFile, encoding));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.jabref.model.entry.BibEntryType;
import org.jabref.model.entry.BibtexString;
import org.jabref.model.entry.Date;
import org.jabref.model.entry.Month;
import org.jabref.model.entry.field.BibField;
import org.jabref.model.entry.field.FieldPriority;
import org.jabref.model.entry.field.InternalField;
Expand Down Expand Up @@ -1711,4 +1712,78 @@ void parseYear() throws Exception {

assertEquals(new Date(2003), result.get().getPublicationDate().get());
}

@Test
void parseEntryUsingStringConstantsForTwoAuthorsWithEtAsStringConstant() throws ParseException {
// source of the example: /~https://github.com/JabRef/help.jabref.org/blob/gh-pages/en/Strings.md
Collection<BibEntry> parsed = parser
.parseEntries("@String { kopp = \"Kopp, Oliver\" }" +
"@String { kubovy = \"Kubovy, Jan\" }" +
"@String { et = \" and \" }" +
"@Misc{m1, author = kopp # et # kubovy }" );

BibEntry expectedEntry = new BibEntry.Builder(StandardEntryType.Misc)
.citeKey("m1")
.field(StandardField.AUTHOR, "#kopp##et##kubovy#")
.build();

assertEquals(List.of(expectedEntry), parsed);
}

@Test
void parseStringConstantsForTwoAuthorsHasCorrectBibTeXEntry() throws ParseException {
// source of the example: /~https://github.com/JabRef/help.jabref.org/blob/gh-pages/en/Strings.md
Collection<BibEntry> parsed = parser
.parseEntries("@String { kopp = \"Kopp, Oliver\" }" +
"@String { kubovy = \"Kubovy, Jan\" }" +
"@String { et = \" and \" }" +
"@Misc{m2, author = kopp # \" and \" # kubovy }" );

BibEntry expectedEntry = new BibEntry.Builder(StandardEntryType.Misc)
.citeKey("m2")
.field(StandardField.AUTHOR, "#kopp# and #kubovy#")
.build();

assertEquals(List.of(expectedEntry), parsed);
}

@Test
void parseStringConstantsForTwoAuthors() throws ParseException {
// source of the example: /~https://github.com/JabRef/help.jabref.org/blob/gh-pages/en/Strings.md
Collection<BibEntry> parsed = parser
.parseEntries("@String { kopp = \"Kopp, Oliver\" }" +
"@String { kubovy = \"Kubovy, Jan\" }" +
"@String { et = \" and \" }" +
"@Misc{m2, author = kopp # \" and \" # kubovy }" );

assertEquals("#kopp# and #kubovy#", parsed.iterator().next().getField(StandardField.AUTHOR).get());
}

@Test
void textAprilIsParsedAsMonthApril() throws ParseException {
Optional<BibEntry> result = parser.parseSingleEntry("@Misc{m, month = \"apr\" }" );

assertEquals(Month.APRIL, result.get().getMonth().get());
}

@Test
void textAprilIsDisplayedAsConstant() throws ParseException {
Optional<BibEntry> result = parser.parseSingleEntry("@Misc{m, month = \"apr\" }" );

assertEquals("apr", result.get().getField(StandardField.MONTH).get());
}

@Test
void bibTeXConstantAprilIsParsedAsMonthApril() throws ParseException {
Optional<BibEntry> result = parser.parseSingleEntry("@Misc{m, month = apr }" );

assertEquals(Month.APRIL, result.get().getMonth().get());
}

@Test
void bibTeXConstantAprilIsDisplayedAsConstant() throws ParseException {
Optional<BibEntry> result = parser.parseSingleEntry("@Misc{m, month = apr }" );

assertEquals("#apr#", result.get().getField(StandardField.MONTH).get());
}
}
92 changes: 87 additions & 5 deletions src/test/java/org/jabref/model/entry/BibtexStringTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,117 @@
public class BibtexStringTest {

@Test
public void test() {
public void initalizationWorksCorrectly() {
// Instantiate
BibtexString bs = new BibtexString("AAA", "An alternative action");
bs.setId("ID");
assertEquals("ID", bs.getId());
assertEquals("AAA", bs.getName());
assertEquals("An alternative action", bs.getContent());
assertEquals(BibtexString.Type.OTHER, bs.getType());
}

@Test
public void idIsUpdatedAtSetId() {
// Instantiate
BibtexString bs = new BibtexString("AAA", "An alternative action");
bs.setId("ID");
assertEquals("ID", bs.getId());
}

@Test
public void cloningDoesNotChangeContents() {
BibtexString bs = new BibtexString("AAA", "An alternative action");
bs.setId("ID");

// Clone
BibtexString bs2 = (BibtexString) bs.clone();

assertEquals(bs.getId(), bs2.getId());
assertEquals(bs.getName(), bs2.getName());
assertEquals(bs.getContent(), bs2.getContent());
assertEquals(bs.getType(), bs2.getType());
}

@Test
public void clonedBibtexStringEqualsOriginalString() {
BibtexString bibtexString = new BibtexString("AAA", "An alternative action");
bibtexString.setId("ID");

BibtexString clone = (BibtexString) bibtexString.clone();

assertEquals(bibtexString, clone);
}

// Change cloned BibtexString
@Test
public void usingTheIdGeneratorDoesNotHitTheOriginalId() {
// Instantiate
BibtexString bs = new BibtexString("AAA", "An alternative action");
bs.setId("ID");
BibtexString bs2 = (BibtexString) bs.clone();
bs2.setId(IdGenerator.next());
assertNotEquals(bs.getId(), bs2.getId());
}

@Test
public void settingFieldsInACloneWorks() {
// Instantiate
BibtexString bs = new BibtexString("AAA", "An alternative action");
bs.setId("ID");
BibtexString bs2 = (BibtexString) bs.clone();

bs2.setId(IdGenerator.next());
bs2.setName("aOG");
assertEquals(BibtexString.Type.AUTHOR, bs2.getType());

bs2.setContent("Oscar Gustafsson");
assertEquals("aOG", bs2.getName());
assertEquals("Oscar Gustafsson", bs2.getContent());
}

@Test
public void modifyingACloneDoesNotModifyTheOriginalEntry() {
// Instantiate
BibtexString original = new BibtexString("AAA", "An alternative action");
original.setId("ID");

BibtexString clone = (BibtexString) original.clone();
clone.setId(IdGenerator.next());
clone.setName("aOG");
clone.setContent("Oscar Gustafsson");

assertEquals("AAA", original.getName());
assertEquals("An alternative action", original.getContent());
}

@Test
public void getContentNeverReturnsNull() {
BibtexString bs = new BibtexString("SomeName", null);
assertNotNull(bs.getContent());
}

@Test
public void authorTypeCorrectlyDetermined() {
// Source of the example: https://help.jabref.org/en/Strings
BibtexString bibtexString = new BibtexString("aKopp", "KoppOliver");
assertEquals(BibtexString.Type.AUTHOR, bibtexString.getType());
}

@Test
public void institutionTypeCorrectlyDetermined() {
// Source of the example: https://help.jabref.org/en/Strings
BibtexString bibtexString = new BibtexString("iMIT", "{Massachusetts Institute of Technology ({MIT})}");
assertEquals(BibtexString.Type.INSTITUTION, bibtexString.getType());
}

@Test
public void otherTypeCorrectlyDeterminedForLowerCase() {
// Source of the example: https://help.jabref.org/en/Strings
BibtexString bibtexString = new BibtexString("anct", "Anecdote");
assertEquals(BibtexString.Type.OTHER, bibtexString.getType());
}

@Test
public void otherTypeCorrectlyDeterminedForUpperCase() {
// Source of the example: https://help.jabref.org/en/Strings
BibtexString bibtexString = new BibtexString("lTOSCA", "Topology and Orchestration Specification for Cloud Applications");
assertEquals(BibtexString.Type.OTHER, bibtexString.getType());
}
}
10 changes: 10 additions & 0 deletions src/test/resources/testbib/articleWithMonths.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
% Encoding: UTF-8
@Article{constant,
month = apr
koppor marked this conversation as resolved.
Show resolved Hide resolved
}

@Article{text,
month = {apr}
}

@Comment{jabref-meta: databaseType:bibtex;}