All files / json-crdt-patch/codec/__tests__ PatchFuzzer.ts

92.98% Statements 53/57
100% Branches 0/0
96.66% Functions 29/30
92.85% Lines 52/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 1011x 1x 1x 1x   1x   1x   800x 800x 800x 800x       800x 800x 800x 800x       1600x 1600x 16480x 1108x 1096x 1096x 1078x 1093x 1134x 1111x   1101x   5865x   1042x 1079x 1114x   1106x     5986x   1130x 1084x 1108x   16480x   1600x       800x 800x 800x       800x     1x 14366x 14366x 14366x     1x 13891x 13891x     1x               800x       1600x       3298x       1600x      
import {RandomJson} from '@jsonjoy.com/util/lib/json-random';
import {Fuzzer} from '@jsonjoy.com/util/lib/Fuzzer';
import {interval, type ITimestampStruct, Timespan, ClockVector, ServerClockVector, ts} from '../../clock';
import {SESSION} from '../../constants';
import type {Patch} from '../../Patch';
import {PatchBuilder} from '../../PatchBuilder';
 
export class PatchFuzzer extends Fuzzer {
  public generateLogicalPatch(): Patch {
    const clock = this.generateLogicalClock();
    const builder = new PatchBuilder(clock);
    this.generateLogicalPatchBase(builder, this.generateLogicalTimestamp);
    return builder.patch;
  }
 
  public generateServerPatch(): Patch {
    const clock = this.generateServerClock();
    const builder = new PatchBuilder(clock);
    this.generateLogicalPatchBase(builder, this.generateServerTimestamp);
    return builder.patch;
  }
 
  public generateLogicalPatchBase(builder: PatchBuilder, ts: () => ITimestampStruct): Patch {
    const length = this.generatePatchLength();
    for (let i = 0; i < length; i++) {
      const build = Fuzzer.pick([
        () => builder.obj(),
        () => builder.arr(),
        () => builder.str(),
        () => builder.bin(),
        () => builder.val(),
        () => builder.const(RandomJson.generate()),
        () => builder.root(ts()),
        () =>
          builder.insObj(
            ts(),
            Fuzzer.repeat(Fuzzer.randomInt(1, 10), () => [RandomJson.genString(), ts()]),
          ),
        () => builder.setVal(ts(), ts()),
        () => builder.insStr(ts(), ts(), RandomJson.genString()),
        () => builder.insBin(ts(), ts(), RandomJson.genBinary()),
        () =>
          builder.insArr(
            ts(),
            ts(),
            Fuzzer.repeat(Fuzzer.randomInt(1, 10), () => ts()),
          ),
        () => builder.del(ts(), [interval(ts(), 0, this.generateSpan())]),
        () => builder.del(ts(), [interval(ts(), 0, this.generateSpan()), interval(ts(), 0, this.generateSpan())]),
        () => builder.nop(Fuzzer.randomInt(1, 20)),
      ]);
      build();
    }
    return builder.patch;
  }
 
  public generateLogicalClock(): ClockVector {
    const sessionId = this.generateSessionId();
    const time = this.generateTime();
    return new ClockVector(sessionId, time);
  }
 
  public generateServerClock(): ServerClockVector {
    return new ServerClockVector(SESSION.SERVER, this.generateTime());
  }
 
  public readonly generateLogicalTimestamp = (): ITimestampStruct => {
    const sessionId = Fuzzer.randomInt(0xffff + 1, SESSION.MAX);
    const time = Fuzzer.randomInt(0, 0xffffff);
    return ts(sessionId, time);
  };
 
  public readonly generateServerTimestamp = (): ITimestampStruct => {
    const time = Fuzzer.randomInt(0, 0xffffff);
    return ts(SESSION.SERVER, time);
  };
 
  public readonly generateLogicalTimespan = (): Timespan => {
    const sessionId = this.generateSessionId();
    const time = this.generateTime();
    const span = this.generateSpan();
    return new Timespan(sessionId, time, span);
  };
 
  public generateSessionId(): number {
    return Fuzzer.randomInt(0xffff + 1, SESSION.MAX);
  }
 
  public generateTime(): number {
    return Fuzzer.randomInt(0, 0xffffffffff);
  }
 
  public generateSpan(): number {
    return Fuzzer.randomInt(1, 0xffff);
  }
 
  public generatePatchLength(): number {
    return Fuzzer.randomInt(1, 20);
  }
}