Skip to content

Commit af49cdc

Browse files
committed
A bit more progress on LocalContext
1 parent 43ed392 commit af49cdc

File tree

7 files changed

+164
-152
lines changed

7 files changed

+164
-152
lines changed

diff-sync-core/src/main/java/org/github/goldsam/diffsync/core/context/LocalContext.java

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.github.goldsam.diffsync.core.context;
22

3+
import java.util.ArrayList;
4+
import java.util.Iterator;
35
import java.util.List;
46
import java.util.function.Function;
57
import org.github.goldsam.diffsync.core.ConnectionListener;
@@ -51,6 +53,10 @@ public long getLocalVersion() {
5153
return localVersion;
5254
}
5355

56+
public D getShadow() {
57+
return shadow;
58+
}
59+
5460
public D getDocument() {
5561
return sharedContext.getDocument();
5662
}
@@ -121,38 +127,35 @@ void validateDocument(D document) {
121127
sharedContext.validateDocument(this, document);
122128
}
123129

124-
public void processEdits(List<Edit<P>> edits, long lastReceivedRemoteVersion) throws PatchFailedException {
125-
edits.sort(EditUtils.getVersionComparator());
126-
127-
if (!edits.isEmpty()) {
128-
for(Edit<P> edit : edits) {
129-
if (!processEdit(edit, lastReceivedRemoteVersion)) {
130-
edits = edits.subList(0, edits.indexOf(edit));
131-
break;
132-
}
130+
public boolean processEdits(List<Edit<P>> edits, long lastReceivedRemoteVersion) throws PatchFailedException {
131+
ArrayList<Edit<P>> processedEdits = new ArrayList<>();
132+
for (Edit<P> edit : edits) {
133+
if (processEdit(edit, lastReceivedRemoteVersion)) {
134+
processedEdits.add(edit);
133135
}
136+
}
134137

138+
if (!processedEdits.isEmpty()) {
135139
sharedContext.onEditsProcessed(this, edits);
136-
} else {
137-
editStack.popEdits(lastReceivedRemoteVersion);
140+
return true;
138141
}
142+
143+
return false;
139144
}
140145

141146
private boolean processEdit(Edit<P> edit, long lastReceivedRemoteVersion) throws PatchFailedException {
142-
boolean editApplied = false;
143-
if (lastReceivedRemoteVersion == localVersion && edit.getVersion() == remoteVersion) {
144-
// if (lastReceivedRemoteVersion == remoteVersion && edit.getVersion() == localVersion) {
145-
editApplied = tryApplyEdit(edit, lastReceivedRemoteVersion);
147+
if (tryApplyEdit(edit, lastReceivedRemoteVersion)) {
148+
return true;
146149
} else if (lastReceivedRemoteVersion < remoteVersion) {
147150
// duplicate message received.
148-
} else if (lastReceivedRemoteVersion == backupVersion && edit.getVersion() == remoteVersion) {
151+
} else if (lastReceivedRemoteVersion == backupVersion) {
149152
shadow = backup;
150153
localVersion = backupVersion;
151154
editStack.clear();
152-
editApplied = tryApplyEdit(edit, lastReceivedRemoteVersion);
153-
}
154-
155-
return editApplied;
155+
return tryApplyEdit(edit, lastReceivedRemoteVersion);
156+
}
157+
158+
return false;
156159
}
157160

158161
/**
@@ -165,6 +168,10 @@ private boolean processEdit(Edit<P> edit, long lastReceivedRemoteVersion) throws
165168
* @throws PatchFailedException
166169
*/
167170
private boolean tryApplyEdit(Edit<P> edit, long lastReceivedRemoteVersion) throws PatchFailedException {
171+
if (lastReceivedRemoteVersion != localVersion || edit.getVersion() != remoteVersion) {
172+
return false;
173+
}
174+
168175
Differencer<D, P> differencer = getDifferencer();
169176
D newShadowDocument = differencer.patch(shadow, edit.getPatch(), false);
170177
validateDocument(newShadowDocument);

diff-sync-core/src/main/java/org/github/goldsam/diffsync/core/edit/ImmutableEdit.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ public boolean equals(Object obj) {
4242
return false;
4343
}
4444
final ImmutableEdit<?> other = (ImmutableEdit<?>) obj;
45-
if (!Objects.equals(this.patch, other.patch)) {
46-
return false;
47-
}
48-
return true;
45+
return Objects.equals(this.patch, other.patch);
4946
}
5047

5148
@Override

diff-sync-core/src/test/java/org/github/goldsam/diffsync/core/MockContextListener.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.ArrayList;
66
import java.util.Collections;
77
import java.util.List;
8+
import java.util.Objects;
89
import org.github.goldsam.diffsync.core.edit.Edit;
910

1011
public class MockContextListener<D, P> implements ContextListener<D, P> {
@@ -58,6 +59,40 @@ public S getDocument() {
5859
public long getRemoteVersion() {
5960
return remoteVersion;
6061
}
62+
63+
@Override
64+
public int hashCode() {
65+
int hash = 7;
66+
hash = 19 * hash + Objects.hashCode(this.localContext);
67+
hash = 19 * hash + Objects.hashCode(this.edits);
68+
hash = 19 * hash + Objects.hashCode(this.document);
69+
hash = 19 * hash + (int) (this.remoteVersion ^ (this.remoteVersion >>> 32));
70+
return hash;
71+
}
72+
73+
@Override
74+
public boolean equals(Object obj) {
75+
if (this == obj) {
76+
return true;
77+
}
78+
if (obj == null) {
79+
return false;
80+
}
81+
if (getClass() != obj.getClass()) {
82+
return false;
83+
}
84+
final ProcessedEdit<?, ?> other = (ProcessedEdit<?, ?>) obj;
85+
return Objects.equals(document, other.document)
86+
&& edits.containsAll(other.edits)
87+
&& other.edits.containsAll(edits)
88+
&& localContext == other.localContext
89+
&& remoteVersion == other.remoteVersion;
90+
}
91+
92+
@Override
93+
public String toString() {
94+
return "ProcessedEdit{" + "localContext=" + localContext + ", edits=" + edits + ", document=" + document + ", remoteVersion=" + remoteVersion + '}';
95+
}
6196
}
6297

6398
private final List<ProcessedEdit<D, P>> processedEdits = new ArrayList<>();
Lines changed: 99 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
package org.github.goldsam.diffsync.core.context;
22

33
import java.util.Arrays;
4-
import java.util.List;
5-
import org.github.goldsam.diffsync.core.ConnectionListener;
64
import org.github.goldsam.diffsync.core.IntDifferencer;
75
import org.github.goldsam.diffsync.core.MockConnectionListener;
86
import org.github.goldsam.diffsync.core.MockContextListener;
9-
import org.github.goldsam.diffsync.core.edit.Edit;
7+
import org.github.goldsam.diffsync.core.PatchFailedException;
108
import org.github.goldsam.diffsync.core.edit.ImmutableEdit;
119
import org.github.goldsam.diffsync.core.edit.MemoryEditStack;
1210
import org.junit.Test;
1311
import static org.junit.Assert.*;
14-
import org.junit.runner.RunWith;
15-
import org.junit.runners.Parameterized;
1612

1713
public class LocalContextTest {
1814

@@ -97,7 +93,7 @@ public void updateAdvancesLocalVersion() {
9793
assertEquals(localContext.getLocalVersion(), 1);
9894

9995
localContext.update(-5);
100-
assertEquals(localContext.getLocalVersion(), 2);
96+
assertEquals(localContext.getLocalVersion(), 2);
10197
}
10298

10399
@Test
@@ -108,7 +104,7 @@ public void updateDoesNotAdvancesRemoteVersion() {
108104
assertEquals(localContext.getRemoteVersion(), 0);
109105

110106
localContext.update(-5);
111-
assertEquals(localContext.getRemoteVersion(), 0);
107+
assertEquals(localContext.getRemoteVersion(), 0);
112108
}
113109

114110
@Test
@@ -135,117 +131,104 @@ public void updatePushesToEditStack() {
135131
Arrays.asList(new ImmutableEdit<>(6, 0), new ImmutableEdit<>(-11, 1)),
136132
localContext.getEdits());
137133
}
138-
139-
//
134+
135+
@Test
136+
public void applyingEditsFromTheFutureDoesNothing() throws PatchFailedException {
137+
initializeAndReset();
138+
localContext.update(6);
139+
localContext.update(-5);
140+
141+
localContext.processEdits(Arrays.asList(new ImmutableEdit<>(-3, 5L)), 0L);
142+
assertEquals(
143+
Arrays.asList(new ImmutableEdit<>(6, 0), new ImmutableEdit<>(-11, 1)),
144+
localContext.getEdits());
145+
assertEquals(localContext.getLocalVersion(), 2);
146+
assertEquals(localContext.getRemoteVersion(), 0);
147+
}
148+
140149
// @Test
141-
// public void updateShouldSetTheCurrentDocuent() {
142-
// initialize(true);;
143-
//
144-
// localContext.update(6);
145-
// assertEquals(Long.valueOf(6), localContext.getDocument());
146-
//
147-
// localContext.update(-5);
148-
// assertEquals(Long.valueOf(-5), localContext.getDocument());
150+
// public void applyingEditMatchingRemoteAndLocalVersion_popsCorrespondingEditFromEditStack() throws PatchFailedException {
151+
// initializeAndReset();
152+
//// localContext.update(6);
153+
//
154+
// localContext.processEdits(Arrays.asList(new ImmutableEdit<>(6, 0)), 0L);
155+
//// assertTrue("edit stack is empty", localContext.getEdits().isEmpty());
149156
// }
157+
158+
@Test
159+
public void applyingEditsMatchingRemoteAndLocalVersion_updatesDocumentAndCurrentShadow() throws PatchFailedException {
160+
initializeAndReset();
161+
162+
localContext.processEdits(
163+
Arrays.asList(
164+
new ImmutableEdit<>(6, 0),
165+
new ImmutableEdit<>(-11, 1)),
166+
0L);
167+
assertEquals(
168+
Integer.valueOf(-5),
169+
localContext.getDocument());
170+
}
171+
172+
@Test
173+
public void applyingEditMatchingRemoteAndLocalVersion_updatesRemoteVersion() throws PatchFailedException {
174+
initializeAndReset();
175+
176+
localContext.processEdits(
177+
Arrays.asList(
178+
new ImmutableEdit<>(6, 0),
179+
new ImmutableEdit<>(-11, 1)),
180+
0L);
181+
assertEquals(2, localContext.getRemoteVersion());
182+
}
183+
184+
@Test
185+
public void applyingEditMatchingRemoteAndLocalVersion_firesEditsAppliedEvent() throws PatchFailedException {
186+
initializeAndReset();
150187

151-
// @Test
152-
// public void testGetSharedContext() {
153-
// System.out.println("getSharedContext");
154-
// LocalContext instance = null;
155-
// SharedContext expResult = null;
156-
// SharedContext result = instance.getSharedContext();
157-
// assertEquals(expResult, result);
158-
// fail("The test case is a prototype.");
159-
// }
160-
//
161-
// @Test
162-
// public void testGetConnectionListener() {
163-
// System.out.println("getConnectionListener");
164-
// LocalContext instance = null;
165-
// ConnectionListener expResult = null;
166-
// ConnectionListener result = instance.getConnectionListener();
167-
// assertEquals(expResult, result);
168-
// fail("The test case is a prototype.");
169-
// }
170-
//
171-
// @Test
172-
// public void testGetRemoteVersion() {
173-
// System.out.println("getRemoteVersion");
174-
// LocalContext instance = null;
175-
// long expResult = 0L;
176-
// long result = instance.getRemoteVersion();
177-
// assertEquals(expResult, result);
178-
// fail("The test case is a prototype.");
179-
// }
180-
//
181-
// @Test
182-
// public void testGetLocalVersion() {
183-
// System.out.println("getLocalVersion");
184-
// LocalContext instance = null;
185-
// long expResult = 0L;
186-
// long result = instance.getLocalVersion();
187-
// assertEquals(expResult, result);
188-
// fail("The test case is a prototype.");
189-
// }
190-
//
191-
// @Test
192-
// public void testReset_GenericType_long() {
193-
// System.out.println("reset");
194-
// Object document = null;
195-
// long version = 0L;
196-
// LocalContext instance = null;
197-
// instance.reset(document, version);
198-
// fail("The test case is a prototype.");
199-
// }
200-
//
201-
// @Test
202-
// public void testReset_long() {
203-
// System.out.println("reset");
204-
// long version = 0L;
205-
// LocalContext instance = null;
206-
// instance.reset(version);
207-
// fail("The test case is a prototype.");
208-
// }
209-
//
210-
// @Test
211-
// public void testReset_0args() {
212-
// System.out.println("reset");
213-
// LocalContext instance = null;
214-
// instance.reset();
215-
// fail("The test case is a prototype.");
216-
// }
217-
//
218-
// @Test
219-
// public void testUpdate_0args() {
220-
// System.out.println("update");
221-
// LocalContext instance = null;
222-
// instance.update();
223-
// fail("The test case is a prototype.");
224-
// }
225-
//
226-
// @Test
227-
// public void testUpdate_GenericType() {
228-
// System.out.println("update");
229-
// Object newCurrentDocument = null;
230-
// LocalContext instance = null;
231-
// instance.update(newCurrentDocument);
232-
// fail("The test case is a prototype.");
233-
// }
234-
//
235-
// @Test
236-
// public void testUpdate_Function() {
237-
// System.out.println("update");
238-
// LocalContext instance = null;
239-
// instance.update(null);
240-
// fail("The test case is a prototype.");
241-
// }
242-
//
243-
// @Test
244-
// public void testProcessEdits() throws Exception {
245-
// System.out.println("processEdits");
246-
// LocalContext instance = null;
247-
// instance.processEdits(null);
248-
// fail("The test case is a prototype.");
249-
// }
188+
localContext.processEdits(
189+
Arrays.asList(
190+
new ImmutableEdit<>(6, 0),
191+
new ImmutableEdit<>(-11, 1)),
192+
0L);
193+
194+
assertEquals(
195+
Arrays.asList(
196+
new MockContextListener.ProcessedEdit<>(
197+
localContext,
198+
Arrays.asList(
199+
new ImmutableEdit<>(6, 0),
200+
new ImmutableEdit<>(-11, 1)),
201+
-5,
202+
2L)),
203+
contextListener.getProcessedEdits());
204+
}
250205

206+
@Test
207+
public void applyingEditsAfterLostReturnAck() throws PatchFailedException {
208+
initializeAndReset();
209+
210+
localContext.processEdits(
211+
Arrays.asList(
212+
new ImmutableEdit<>(6, 0)),
213+
0L);
214+
215+
localContext.update(8);
216+
217+
localContext.processEdits(
218+
Arrays.asList(
219+
new ImmutableEdit<>(6, 0),
220+
new ImmutableEdit<>(-11, 1)),
221+
0L);
222+
//
223+
// assertEquals(
224+
// Arrays.asList(
225+
// new MockContextListener.ProcessedEdit<>(
226+
// localContext,
227+
// Arrays.asList(
228+
// new ImmutableEdit<>(6, 0),
229+
// new ImmutableEdit<>(-11, 1)),
230+
// -5,
231+
// 2L)),
232+
// contextListener.getProcessedEdits());
233+
}
251234
}

0 commit comments

Comments
 (0)