-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(json-crdt): 🎸 improve frontier decoding in LogDecoder
- Loading branch information
Showing
4 changed files
with
112 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import {Log} from '../../Log'; | ||
import {Model} from '../../../model'; | ||
import {logEncoderOpts} from '../logEncoderOpts'; | ||
import {EncodingParams, LogEncoder} from '../LogEncoder'; | ||
import {LogDecoder} from '../LogDecoder'; | ||
import {logDecoderOpts} from '../logDecoderOpts';; | ||
|
||
const setup = (view: unknown) => { | ||
const model = Model.withServerClock(); | ||
model.api.root(view); | ||
const log = Log.fromNewModel(model); | ||
const encoder = new LogEncoder(logEncoderOpts); | ||
const decoder = new LogDecoder(logDecoderOpts); | ||
return {model, log, encoder, decoder}; | ||
}; | ||
|
||
describe('can decode from blob', () => { | ||
test('.ndjson', () => { | ||
const {log, encoder, decoder} = setup({foo: 'bar'}); | ||
const blob = encoder.encode(log, {format: 'ndjson', model: 'compact', history: 'compact'}); | ||
const decoded = decoder.decode(blob, {format: 'ndjson', frontier: true, history: true}); | ||
const {frontier, history} = decoded; | ||
expect(frontier!.end.view()).toEqual({foo: 'bar'}); | ||
expect(frontier!.end !== log.end).toBe(true); | ||
expect(history!.start().view()).toEqual(undefined); | ||
expect(history!.end.view()).toEqual({foo: 'bar'}); | ||
}); | ||
|
||
test('.seq.cbor', () => { | ||
const {log, encoder, decoder} = setup({foo: 'bar'}); | ||
const blob = encoder.encode(log, {format: 'seq.cbor', model: 'binary', history: 'binary'}); | ||
const decoded = decoder.decode(blob, {format: 'seq.cbor', frontier: true, history: true}); | ||
const {frontier, history} = decoded; | ||
expect(frontier!.end.view()).toEqual({foo: 'bar'}); | ||
expect(frontier!.end !== log.end).toBe(true); | ||
expect(history!.start().view()).toEqual(undefined); | ||
expect(history!.end.view()).toEqual({foo: 'bar'}); | ||
}); | ||
}); | ||
|
||
const assertEncoding = (log: Log, params: EncodingParams) => { | ||
const encoder = new LogEncoder(logEncoderOpts); | ||
const decoder = new LogDecoder(logDecoderOpts); | ||
const encoded = encoder.encode(log, params); | ||
const decoded = decoder.decode(encoded, { | ||
format: params.format, | ||
frontier: true, | ||
history: true, | ||
}); | ||
expect(decoded.frontier!.end.view()).toEqual(log.end.view()); | ||
expect(decoded.frontier!.end !== log.end).toBe(true); | ||
expect(decoded.history!.start().view()).toEqual(undefined); | ||
expect(decoded.history!.replayToEnd().view()).toEqual(log.end.view()); | ||
expect(decoded.history!.patches.size()).toBe(log.patches.size()); | ||
}; | ||
|
||
describe('can encode/decode all format combinations', () => { | ||
const formats: EncodingParams['format'][] = ['ndjson', 'seq.cbor']; | ||
const modelFormats: EncodingParams['model'][] = ['sidecar', 'binary', 'compact', 'verbose']; | ||
const historyFormats: EncodingParams['history'][] = ['binary', 'compact', 'verbose']; | ||
const noViews = [true, false]; | ||
for (const format of formats) { | ||
for (const model of modelFormats) { | ||
for (const history of historyFormats) { | ||
for (const noView of noViews) { | ||
if (noView && model === 'sidecar') continue; | ||
const params = {format, model, history, noView}; | ||
test(JSON.stringify(params), () => { | ||
const {log} = setup({foo: 'bar'}); | ||
assertEncoding(log, params); | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
|
||
describe('.deserialize()', () => { | ||
test('applies frontier', () => { | ||
const {log, model, encoder, decoder} = setup({foo: 'bar'}); | ||
const clone = model.clone(); | ||
clone.api.obj([]).set({ | ||
xyz: 123, | ||
}); | ||
const serialized = encoder.serialize(log, { | ||
history: 'binary', | ||
}); | ||
serialized.push(clone.api.flush().toBinary()); | ||
expect(log.end.view()).toEqual({foo: 'bar'}); | ||
const deserialized1 = decoder.deserialize(serialized, {frontier: true}); | ||
const deserialized2 = decoder.deserialize(serialized, {history: true}); | ||
expect(deserialized1.frontier!.end.view()).toEqual({foo: 'bar', xyz: 123}); | ||
expect(deserialized2.history!.end.view()).toEqual({foo: 'bar', xyz: 123}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters