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 16946x 1118x 1100x 1125x 1143x 1156x 1170x 1098x   1142x   6344x   1102x 1101x 1146x   1166x     6288x   1104x 1129x 1146x   16946x   1600x       800x 800x 800x       800x     1x 15334x 15334x 15334x     1x 14163x 14163x     1x               800x       1600x       3362x       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);
  }
}