diff --git a/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/EditingResult.java b/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/EditingResult.java new file mode 100644 index 000000000..2bf078160 --- /dev/null +++ b/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/EditingResult.java @@ -0,0 +1,71 @@ +package org.wikidata.wdtk.wikibaseapi; + +/*- + * #%L + * Wikidata Toolkit Wikibase API + * %% + * Copyright (C) 2014 - 2023 Wikidata Toolkit Developers + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.Objects; +import java.util.OptionalLong; + +/** + * Holds information about a successful edit made via {@link WikibaseDataEditor}. + * The state of the entity after edit is not provided here because it is not possible + * for WDTK to determine it reliably from the response of the server. Indeed, it is + * possible that the data in the entity after the edit differs from the data in the + * entity before the edit plus the changes of the edit itself, because it can be that + * another edit touched independent parts of the entity. This can happen even if the base + * revision id is provided. + */ +public class EditingResult { + + private final long revisionId; + + public EditingResult(long revisionId) { + super(); + this.revisionId = revisionId; + } + + /** + * The identifier of the revision of the last edit made by the editing action, + * if any edit was made. + */ + public OptionalLong getLastRevisionId() { + return revisionId == 0 ? OptionalLong.empty() : OptionalLong.of(revisionId); + } + + @Override + public int hashCode() { + return Objects.hash(revisionId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + EditingResult other = (EditingResult) obj; + return revisionId == other.revisionId; + } + + @Override + public String toString() { + return "EditingResult [revisionId=" + revisionId + "]"; + } + +} diff --git a/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditor.java b/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditor.java index 60f5c3a29..1b0a9b697 100644 --- a/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditor.java +++ b/wdtk-wikibaseapi/src/main/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditor.java @@ -56,6 +56,9 @@ import org.wikidata.wdtk.datamodel.interfaces.TermedStatementDocumentUpdate; import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; + /** * Class that provides high-level editing functionality for Wikibase data. * @@ -530,13 +533,13 @@ public ItemDocument editItemDocument(ItemDocument itemDocument, * @throws MediaWikiApiErrorException * if MediaWiki API returned an error response */ - public void editEntityDocument( + public EditingResult editEntityDocument( EntityUpdate update, boolean clear, String summary, List tags) throws IOException, MediaWikiApiErrorException { long revisionId = update.getBaseRevisionId(); if (!clear) { if (update.isEmpty()) - return; + return new EditingResult(0L); if (update instanceof StatementDocumentUpdate) { StatementDocumentUpdate typed = (StatementDocumentUpdate) update; if (typed.getStatements().getAdded().size() == 1) { @@ -547,9 +550,9 @@ public void editEntityDocument( if (builder.build().equals(update)) { String statementId = guidGenerator.freshStatementId(typed.getEntityId().getId()); Statement prepared = statement.withStatementId(statementId); - wbEditingAction.wbSetClaim(JsonSerializer.getJsonString(prepared), + JsonNode response = wbEditingAction.wbSetClaim(JsonSerializer.getJsonString(prepared), editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } if (typed.getStatements().getReplaced().size() == 1) { @@ -558,9 +561,9 @@ public void editEntityDocument( Statement statement = typed.getStatements().getReplaced().values().stream().findFirst().get(); builder.updateStatements(StatementUpdateBuilder.create().replace(statement).build()); if (builder.build().equals(update)) { - wbEditingAction.wbSetClaim(JsonSerializer.getJsonString(statement), + JsonNode response = wbEditingAction.wbSetClaim(JsonSerializer.getJsonString(statement), editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } if (!typed.getStatements().getRemoved().isEmpty() @@ -574,8 +577,8 @@ public void editEntityDocument( } builder.updateStatements(statementBuilder.build()); if (builder.build().equals(update)) { - wbEditingAction.wbRemoveClaims(statementIds, editAsBot, revisionId, summary, tags); - return; + JsonNode response = wbEditingAction.wbRemoveClaims(statementIds, editAsBot, revisionId, summary, tags); + return new EditingResult(getRevisionIdFromResponse(response)); } } } @@ -587,9 +590,9 @@ public void editEntityDocument( MonolingualTextValue label = typed.getLabels().getModified().values().stream().findFirst().get(); builder.updateLabels(TermUpdateBuilder.create().put(label).build()); if (builder.build().equals(update)) { - wbEditingAction.wbSetLabel(update.getEntityId().getId(), null, null, null, + JsonNode response = wbEditingAction.wbSetLabel(update.getEntityId().getId(), null, null, null, label.getLanguageCode(), label.getText(), editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } if (typed.getLabels().getRemoved().size() == 1) { @@ -598,9 +601,9 @@ public void editEntityDocument( String language = typed.getLabels().getRemoved().stream().findFirst().get(); builder.updateLabels(TermUpdateBuilder.create().remove(language).build()); if (builder.build().equals(update)) { - wbEditingAction.wbSetLabel(update.getEntityId().getId(), null, null, null, + JsonNode response = wbEditingAction.wbSetLabel(update.getEntityId().getId(), null, null, null, language, null, editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } } @@ -613,10 +616,10 @@ public void editEntityDocument( .values().stream().findFirst().get(); builder.updateDescriptions(TermUpdateBuilder.create().put(description).build()); if (builder.build().equals(update)) { - wbEditingAction.wbSetDescription(update.getEntityId().getId(), null, null, null, + JsonNode response = wbEditingAction.wbSetDescription(update.getEntityId().getId(), null, null, null, description.getLanguageCode(), description.getText(), editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } if (typed.getDescriptions().getRemoved().size() == 1) { @@ -625,9 +628,9 @@ public void editEntityDocument( String language = typed.getDescriptions().getRemoved().stream().findFirst().get(); builder.updateDescriptions(TermUpdateBuilder.create().remove(language).build()); if (builder.build().equals(update)) { - wbEditingAction.wbSetDescription(update.getEntityId().getId(), null, null, null, + JsonNode response = wbEditingAction.wbSetDescription(update.getEntityId().getId(), null, null, null, language, null, editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } if (typed.getAliases().size() == 1) { @@ -646,9 +649,9 @@ public void editEntityDocument( List recreated = aliases.getRecreated() .map(l -> l.stream().map(a -> a.getText()).collect(toList())) .orElse(null); - wbEditingAction.wbSetAliases(update.getEntityId().getId(), null, null, null, + JsonNode response = wbEditingAction.wbSetAliases(update.getEntityId().getId(), null, null, null, language, added, removed, recreated, editAsBot, revisionId, summary, tags); - return; + return new EditingResult(getRevisionIdFromResponse(response)); } } } @@ -660,8 +663,7 @@ public void editEntityDocument( SenseUpdate sense = typed.getUpdatedSenses().values().stream().findFirst().get(); builder.updateSense(sense); if (builder.build().equals(update)) { - editEntityDocument(sense, false, summary, tags); - return; + return editEntityDocument(sense, false, summary, tags); } } if (typed.getUpdatedForms().size() == 1) { @@ -670,15 +672,15 @@ public void editEntityDocument( FormUpdate form = typed.getUpdatedForms().values().stream().findFirst().get(); builder.updateForm(form); if (builder.build().equals(update)) { - editEntityDocument(form, false, summary, tags); - return; + return editEntityDocument(form, false, summary, tags); } } } } String data = JsonSerializer.getJsonString(update); - wbEditingAction.wbEditEntity( + EntityDocument document = wbEditingAction.wbEditEntity( update.getEntityId().getId(), null, null, null, data, clear, editAsBot, revisionId, summary, tags); + return new EditingResult(document.getRevisionId()); } /** @@ -1131,4 +1133,29 @@ public T nullEdit(T currentDocument) JsonSerializer.getJsonString(update), false, editAsBot, currentDocument.getRevisionId(), null, null); } + /** + * Extracts the last revision id from the JSON response returned + * by the API after an edit + * + * @param response + * the response as returned by Mediawiki + * @return + * the new revision id of the edited entity + * @throws JsonProcessingException + */ + protected long getRevisionIdFromResponse(JsonNode response) throws JsonProcessingException { + if(response == null) { + throw new MalformedResponseException("API response is null"); + } + JsonNode entity = null; + if(response.has("entity")) { + entity = response.path("entity"); + } else if(response.has("pageinfo")) { + entity = response.path("pageinfo"); + } + if(entity != null && entity.has("lastrevid")) { + return entity.path("lastrevid").asLong(); + } + throw new MalformedResponseException("The last revision id could not be found in API response"); + } } diff --git a/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/EditingResultTest.java b/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/EditingResultTest.java new file mode 100644 index 000000000..6caa3b69e --- /dev/null +++ b/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/EditingResultTest.java @@ -0,0 +1,44 @@ +package org.wikidata.wdtk.wikibaseapi; + +/*- + * #%L + * Wikidata Toolkit Wikibase API + * %% + * Copyright (C) 2014 - 2023 Wikidata Toolkit Developers + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import static org.junit.Assert.assertEquals; + +import java.util.OptionalLong; + +import org.junit.Test; + +public class EditingResultTest { + + @Test + public void testGetRevisionId() { + EditingResult SUT = new EditingResult(1234L); + + assertEquals(SUT.getLastRevisionId(), OptionalLong.of(1234L)); + } + + @Test + public void testNoRevisionId() { + EditingResult SUT = new EditingResult(0L); + + assertEquals(SUT.getLastRevisionId(), OptionalLong.empty()); + } +} diff --git a/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditorTest.java b/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditorTest.java index 190382dba..b7a79fb02 100644 --- a/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditorTest.java +++ b/wdtk-wikibaseapi/src/test/java/org/wikidata/wdtk/wikibaseapi/WikibaseDataEditorTest.java @@ -22,9 +22,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.only; +import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeStringValue; +import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeQuantityValue; import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeWikidataFormIdValue; import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeWikidataItemIdValue; import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeWikidataLexemeIdValue; @@ -32,6 +34,7 @@ import static org.wikidata.wdtk.datamodel.helpers.Datamodel.makeWikidataSenseIdValue; import java.io.IOException; +import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -55,23 +58,30 @@ import org.wikidata.wdtk.datamodel.interfaces.DatatypeIdValue; import org.wikidata.wdtk.datamodel.interfaces.EntityDocument; import org.wikidata.wdtk.datamodel.interfaces.EntityUpdate; +import org.wikidata.wdtk.datamodel.interfaces.FormDocument; import org.wikidata.wdtk.datamodel.interfaces.FormUpdate; import org.wikidata.wdtk.datamodel.interfaces.ItemDocument; import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue; import org.wikidata.wdtk.datamodel.interfaces.ItemUpdate; +import org.wikidata.wdtk.datamodel.interfaces.LexemeDocument; import org.wikidata.wdtk.datamodel.interfaces.LexemeUpdate; import org.wikidata.wdtk.datamodel.interfaces.MediaInfoDocument; import org.wikidata.wdtk.datamodel.interfaces.MediaInfoIdValue; import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue; import org.wikidata.wdtk.datamodel.interfaces.PropertyDocument; import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue; +import org.wikidata.wdtk.datamodel.interfaces.SenseDocument; import org.wikidata.wdtk.datamodel.interfaces.SenseUpdate; import org.wikidata.wdtk.datamodel.interfaces.Statement; +import org.wikidata.wdtk.testing.MockStringContentFactory; import org.wikidata.wdtk.util.CompressionType; import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException; import org.wikidata.wdtk.wikibaseapi.apierrors.TagsApplyNotAllowedException; import org.wikidata.wdtk.wikibaseapi.apierrors.TokenErrorException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + import static org.junit.Assert.*; public class WikibaseDataEditorTest { @@ -81,6 +91,7 @@ public class WikibaseDataEditorTest { PropertyIdValue P31 = Datamodel.makeWikidataPropertyIdValue("P31"); static final String TEST_GUID = "427C0317-BA8C-95B0-16C8-1A1B5FAC1081"; MockGuidGenerator guids = new MockGuidGenerator(TEST_GUID); + ObjectMapper mapper = new ObjectMapper(); @Before public void setUp() throws IOException { @@ -878,26 +889,41 @@ public void testApplyInvalidTag() throws MediaWikiApiErrorException, IOException Collections.emptyList(), "testing tags", Collections.singletonList("tag_which_does_not_exist")); } - private WbEditingAction mockEntityUpdate(EntityUpdate update) throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mock(WbEditingAction.class); + private EditingResult mockEntityUpdate(WbEditingAction action, EntityUpdate update) throws MediaWikiApiErrorException, IOException { WikibaseDataFetcher fetcher = new WikibaseDataFetcher(con, Datamodel.SITE_WIKIDATA); WikibaseDataEditor wde = new WikibaseDataEditor(action, fetcher, Datamodel.SITE_WIKIDATA, guids); - wde.editEntityDocument(update, false, "test summary", Arrays.asList("tag1")); - return action; + return wde.editEntityDocument(update, false, "test summary", Arrays.asList("tag1")); + } + + private JsonNode json(String resourceFileName) { + try { + String contents = MockStringContentFactory + .getStringFromUrl(WikibaseDataEditor.class.getResource(resourceFileName)); + return mapper.readTree(contents); + } catch (Exception e) { + throw new IllegalArgumentException("Unable to read test JSON resource "+resourceFileName); + } } @Test public void testReductionToSetNewClaim() throws MediaWikiApiErrorException, IOException { ItemIdValue subject = makeWikidataItemIdValue("Q1"); Statement statement = StatementBuilder.forSubjectAndProperty(subject, makeWikidataPropertyIdValue("P1")) - .withValue(makeStringValue("some value")) + .withValue(makeQuantityValue(new BigDecimal("456"))) .build(); - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder.forBaseRevisionId(subject, 123) + Statement statementWithId = statement.withStatementId(guids.freshStatementId(subject.getId())); + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetClaim( + JsonSerializer.getJsonString(statementWithId), false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetclaim.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder.forBaseRevisionId(subject, 123) .updateStatements(StatementUpdateBuilder.create() .add(statement) .build()) .build()); - Statement statementWithId = statement.withStatementId(guids.freshStatementId(subject.getId())); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetClaim( JsonSerializer.getJsonString(statementWithId), false, 123, "test summary", Arrays.asList("tag1")); } @@ -906,12 +932,19 @@ public void testReductionToSetNewClaim() throws MediaWikiApiErrorException, IOEx public void testReductionToSetExistingClaim() throws MediaWikiApiErrorException, IOException { ItemIdValue subject = makeWikidataItemIdValue("Q1"); Statement statement = StatementBuilder.forSubjectAndProperty(subject, makeWikidataPropertyIdValue("P1")) - .withValue(makeStringValue("some value")) + .withValue(makeQuantityValue(new BigDecimal("456"))) .withId(guids.freshStatementId(subject.getId())) .build(); - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder.forBaseRevisionId(subject, 123) + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetClaim( + JsonSerializer.getJsonString(statement), false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetclaim.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder.forBaseRevisionId(subject, 123) .updateStatements(StatementUpdateBuilder.create().replace(statement).build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetClaim( JsonSerializer.getJsonString(statement), false, 123, "test summary", Arrays.asList("tag1")); } @@ -920,65 +953,106 @@ public void testReductionToSetExistingClaim() throws MediaWikiApiErrorException, public void testReductionToRemoveClaims() throws MediaWikiApiErrorException, IOException { ItemIdValue subject = makeWikidataItemIdValue("Q1"); String id = guids.freshStatementId(subject.getId()); - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder.forBaseRevisionId(subject, 123) + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbRemoveClaims(Arrays.asList(id), false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbremoveclaims.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder.forBaseRevisionId(subject, 123) .updateStatements(StatementUpdateBuilder.create().remove(id).build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbRemoveClaims(Arrays.asList(id), false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToSetLabel() throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetLabel( + "Q1", null, null, null, "en", "hello", false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetlabel.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateLabels(TermUpdateBuilder.create() .put(Datamodel.makeMonolingualTextValue("hello", "en")) .build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetLabel( "Q1", null, null, null, "en", "hello", false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToSetNullLabel() throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetLabel( + "Q1", null, null, null, "en", null, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetlabel-null.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateLabels(TermUpdateBuilder.create().remove("en").build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetLabel( "Q1", null, null, null, "en", null, false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToSetDescription() throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetDescription( + "Q1", null, null, null, "en", "hello", false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetdescription.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateDescriptions(TermUpdateBuilder.create() .put(Datamodel.makeMonolingualTextValue("hello", "en")) .build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetDescription( "Q1", null, null, null, "en", "hello", false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToSetNullDescription() throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetDescription( + "Q1", null, null, null, "en", null, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetdescription-null.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateDescriptions(TermUpdateBuilder.create().remove("en").build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetDescription( "Q1", null, null, null, "en", null, false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToSetAliases() throws MediaWikiApiErrorException, IOException { - WbEditingAction action = mockEntityUpdate(ItemUpdateBuilder + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbSetAliases("Q1", null, null, null, "en", + Arrays.asList("hello"), Arrays.asList("bye"), null, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(json("/wbsetaliases-add-remove.json")); + + EditingResult result = mockEntityUpdate(action, ItemUpdateBuilder .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateAliases("en", AliasUpdateBuilder.create() .add(Datamodel.makeMonolingualTextValue("hello", "en")) .remove(Datamodel.makeMonolingualTextValue("bye", "en")) .build()) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbSetAliases("Q1", null, null, null, "en", Arrays.asList("hello"), Arrays.asList("bye"), null, false, 123, "test summary", Arrays.asList("tag1")); } @@ -989,10 +1063,19 @@ public void testReductionToSenseEdit() throws MediaWikiApiErrorException, IOExce .forEntityId(makeWikidataSenseIdValue("L1-S1")) .updateGlosses(TermUpdateBuilder.create().remove("en").build()) .build(); - WbEditingAction action = mockEntityUpdate(LexemeUpdateBuilder + SenseDocument senseDocument = mock(SenseDocument.class); + when(senseDocument.getRevisionId()).thenReturn(1234L); + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbEditEntity("L1-S1", null, null, null, JsonSerializer.getJsonString(update), + false, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(senseDocument); + + EditingResult result = mockEntityUpdate(action, LexemeUpdateBuilder .forBaseRevisionId(makeWikidataLexemeIdValue("L1"), 123) .updateSense(update) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbEditEntity("L1-S1", null, null, null, JsonSerializer.getJsonString(update), false, false, 123, "test summary", Arrays.asList("tag1")); } @@ -1003,10 +1086,19 @@ public void testReductionToFormEdit() throws MediaWikiApiErrorException, IOExcep .forEntityId(makeWikidataFormIdValue("L1-F1")) .updateRepresentations(TermUpdateBuilder.create().remove("en").build()) .build(); - WbEditingAction action = mockEntityUpdate(LexemeUpdateBuilder + FormDocument formDocument = mock(FormDocument.class); + when(formDocument.getRevisionId()).thenReturn(1234L); + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbEditEntity("L1-F1", null, null, null, JsonSerializer.getJsonString(update), + false, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(formDocument); + + EditingResult result = mockEntityUpdate(action, LexemeUpdateBuilder .forBaseRevisionId(makeWikidataLexemeIdValue("L1"), 123) .updateForm(update) .build()); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbEditEntity("L1-F1", null, null, null, JsonSerializer.getJsonString(update), false, false, 123, "test summary", Arrays.asList("tag1")); } @@ -1017,7 +1109,16 @@ public void testUnreducedEntityEdit() throws MediaWikiApiErrorException, IOExcep .forBaseRevisionId(makeWikidataLexemeIdValue("L1"), 123) .setLanguage(Datamodel.makeWikidataItemIdValue("Q1")) .build(); - WbEditingAction action = mockEntityUpdate(update); + LexemeDocument lexemeDocument = mock(LexemeDocument.class); + when(lexemeDocument.getRevisionId()).thenReturn(1234L); + WbEditingAction action = mock(WbEditingAction.class); + when(action.wbEditEntity("L1", null, null, null, JsonSerializer.getJsonString(update), + false, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(lexemeDocument); + + EditingResult result = mockEntityUpdate(action, update); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbEditEntity("L1", null, null, null, JsonSerializer.getJsonString(update), false, false, 123, "test summary", Arrays.asList("tag1")); } @@ -1028,19 +1129,31 @@ public void testIrreducibleClearingEdit() throws MediaWikiApiErrorException, IOE .forBaseRevisionId(makeWikidataItemIdValue("Q1"), 123) .updateLabels(TermUpdateBuilder.create().remove("en").build()) .build(); + ItemDocument itemDocument = mock(ItemDocument.class); + when(itemDocument.getRevisionId()).thenReturn(1234L); WbEditingAction action = mock(WbEditingAction.class); + when(action.wbEditEntity("Q1", null, null, null, JsonSerializer.getJsonString(update), + true, false, 123, "test summary", Arrays.asList("tag1"))) + .thenReturn(itemDocument); WikibaseDataFetcher fetcher = new WikibaseDataFetcher(con, Datamodel.SITE_WIKIDATA); WikibaseDataEditor wde = new WikibaseDataEditor(action, fetcher, Datamodel.SITE_WIKIDATA, guids); - wde.editEntityDocument(update, true, "test summary", Arrays.asList("tag1")); + + EditingResult result = wde.editEntityDocument(update, true, "test summary", Arrays.asList("tag1")); + + assertEquals(result, new EditingResult(1234L)); verify(action, only()).wbEditEntity("Q1", null, null, null, JsonSerializer.getJsonString(update), true, false, 123, "test summary", Arrays.asList("tag1")); } @Test public void testReductionToNoEdit() throws MediaWikiApiErrorException, IOException { - verifyNoInteractions(mockEntityUpdate(LexemeUpdateBuilder - .forBaseRevisionId(makeWikidataLexemeIdValue("L1"), 123) - .build())); + WbEditingAction action = mock(WbEditingAction.class); + EditingResult result = mockEntityUpdate(action, LexemeUpdateBuilder + .forBaseRevisionId(makeWikidataLexemeIdValue("L1"), 123) + .build()); + + assertEquals(result, new EditingResult(0L)); + verifyNoInteractions(action); } } diff --git a/wdtk-wikibaseapi/src/test/resources/wbremoveclaims.json b/wdtk-wikibaseapi/src/test/resources/wbremoveclaims.json new file mode 100644 index 000000000..e58ff8ea8 --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbremoveclaims.json @@ -0,0 +1,7 @@ +{ + "pageinfo" : { + "lastrevid" : 1234 + }, + "success" : 1, + "claims" : [ "Q1$427C0317-BA8C-95B0-16C8-1A1B5FAC1081" ] +} diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetaliases-add-remove.json b/wdtk-wikibaseapi/src/test/resources/wbsetaliases-add-remove.json new file mode 100644 index 000000000..1e0944c5d --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetaliases-add-remove.json @@ -0,0 +1,17 @@ +{ + "entity" : { + "aliases" : { + "en" : [ { + "language" : "en", + "value" : "old alias" + }, { + "language" : "en", + "value" : "hello" + } ] + }, + "id" : "Q1", + "type" : "item", + "lastrevid" : 1234 + }, + "success" : 1 +} \ No newline at end of file diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetclaim.json b/wdtk-wikibaseapi/src/test/resources/wbsetclaim.json new file mode 100644 index 000000000..01abb0695 --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetclaim.json @@ -0,0 +1,24 @@ +{ + "pageinfo" : { + "lastrevid" : 1234 + }, + "success" : 1, + "claim" : { + "mainsnak" : { + "snaktype" : "value", + "property" : "P1", + "hash" : "a3438cfe0cbb10e069ce2dbae1d7baf9e81ac111", + "datavalue" : { + "value" : { + "amount" : "+456", + "unit" : "1" + }, + "type" : "quantity" + }, + "datatype" : "quantity" + }, + "type" : "statement", + "id" : "Q1$427C0317-BA8C-95B0-16C8-1A1B5FAC1081", + "rank" : "normal" + } +} \ No newline at end of file diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetdescription-null.json b/wdtk-wikibaseapi/src/test/resources/wbsetdescription-null.json new file mode 100644 index 000000000..5df1dec08 --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetdescription-null.json @@ -0,0 +1,14 @@ +{ + "entity" : { + "descriptions" : { + "en" : { + "language" : "en", + "value" : "hello" + } + }, + "id" : "Q1", + "type" : "item", + "lastrevid" : 1234 + }, + "success" : 1 +} \ No newline at end of file diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetdescription.json b/wdtk-wikibaseapi/src/test/resources/wbsetdescription.json new file mode 100644 index 000000000..5df1dec08 --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetdescription.json @@ -0,0 +1,14 @@ +{ + "entity" : { + "descriptions" : { + "en" : { + "language" : "en", + "value" : "hello" + } + }, + "id" : "Q1", + "type" : "item", + "lastrevid" : 1234 + }, + "success" : 1 +} \ No newline at end of file diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetlabel-null.json b/wdtk-wikibaseapi/src/test/resources/wbsetlabel-null.json new file mode 100644 index 000000000..a97d8e2e5 --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetlabel-null.json @@ -0,0 +1,11 @@ +{ + "entity" : { + "labels" : { + "en" : null + }, + "id" : "Q1", + "type" : "item", + "lastrevid" : 1234 + }, + "success" : 1 +} \ No newline at end of file diff --git a/wdtk-wikibaseapi/src/test/resources/wbsetlabel.json b/wdtk-wikibaseapi/src/test/resources/wbsetlabel.json new file mode 100644 index 000000000..7af27889c --- /dev/null +++ b/wdtk-wikibaseapi/src/test/resources/wbsetlabel.json @@ -0,0 +1,14 @@ +{ + "entity" : { + "labels" : { + "en" : { + "language" : "en", + "value" : "hello" + } + }, + "id" : "Q1", + "type" : "item", + "lastrevid" : 1234 + }, + "success" : 1 +} \ No newline at end of file