tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

params_builder_and_utils.spec.ts (14024B)


      1 export const description = `
      2 Unit tests for parameterization helpers.
      3 `;
      4 
      5 import { TestParams } from '../common/framework/fixture.js';
      6 import {
      7  kUnitCaseParamsBuilder,
      8  CaseSubcaseIterable,
      9  ParamsBuilderBase,
     10  builderIterateCasesWithSubcases,
     11 } from '../common/framework/params_builder.js';
     12 import { makeTestGroup } from '../common/framework/test_group.js';
     13 import {
     14  mergeParams,
     15  mergeParamsChecked,
     16  publicParamsEquals,
     17 } from '../common/internal/params_utils.js';
     18 import { assert, objectEquals } from '../common/util/util.js';
     19 
     20 import { UnitTest } from './unit_test.js';
     21 
     22 class ParamsTest extends UnitTest {
     23  expectParams<CaseP extends {}, SubcaseP extends {}>(
     24    act: ParamsBuilderBase<CaseP, SubcaseP>,
     25    exp: CaseSubcaseIterable<{}, {}>,
     26    caseFilter: TestParams | null = null
     27  ): void {
     28    const a = Array.from(builderIterateCasesWithSubcases(act, caseFilter)).map(
     29      ([caseP, subcases]) => [caseP, subcases ? Array.from(subcases) : undefined]
     30    );
     31    const e = Array.from(exp);
     32    this.expect(
     33      objectEquals(a, e),
     34      `
     35 got      ${JSON.stringify(a)}
     36 expected ${JSON.stringify(e)}`
     37    );
     38  }
     39 }
     40 
     41 export const g = makeTestGroup(ParamsTest);
     42 
     43 const u = kUnitCaseParamsBuilder;
     44 
     45 g.test('combine').fn(t => {
     46  t.expectParams<{ hello: number }, {}>(u.combine('hello', [1, 2, 3]), [
     47    [{ hello: 1 }, undefined],
     48    [{ hello: 2 }, undefined],
     49    [{ hello: 3 }, undefined],
     50  ]);
     51  t.expectParams<{ hello: number }, {}>(
     52    u.combine('hello', [1, 2, 3]),
     53    [
     54      [{ hello: 1 }, undefined],
     55      [{ hello: 2 }, undefined],
     56      [{ hello: 3 }, undefined],
     57    ],
     58    {}
     59  );
     60  t.expectParams<{ hello: number }, {}>(
     61    u.combine('hello', [1, 2, 3]),
     62    [[{ hello: 2 }, undefined]],
     63    { hello: 2 }
     64  );
     65  t.expectParams<{ hello: 1 | 2 | 3 }, {}>(u.combine('hello', [1, 2, 3] as const), [
     66    [{ hello: 1 }, undefined],
     67    [{ hello: 2 }, undefined],
     68    [{ hello: 3 }, undefined],
     69  ]);
     70  t.expectParams<{}, { hello: number }>(u.beginSubcases().combine('hello', [1, 2, 3]), [
     71    [{}, [{ hello: 1 }, { hello: 2 }, { hello: 3 }]],
     72  ]);
     73  t.expectParams<{}, { hello: number }>(
     74    u.beginSubcases().combine('hello', [1, 2, 3]),
     75    [[{}, [{ hello: 1 }, { hello: 2 }, { hello: 3 }]]],
     76    {}
     77  );
     78  t.expectParams<{}, { hello: number }>(u.beginSubcases().combine('hello', [1, 2, 3]), [], {
     79    hello: 2,
     80  });
     81  t.expectParams<{}, { hello: 1 | 2 | 3 }>(u.beginSubcases().combine('hello', [1, 2, 3] as const), [
     82    [{}, [{ hello: 1 }, { hello: 2 }, { hello: 3 }]],
     83  ]);
     84 });
     85 
     86 g.test('empty').fn(t => {
     87  t.expectParams<{}, {}>(u, [
     88    [{}, undefined], //
     89  ]);
     90  t.expectParams<{}, {}>(u.beginSubcases(), [
     91    [{}, [{}]], //
     92  ]);
     93 });
     94 
     95 g.test('combine,zeroes_and_ones').fn(t => {
     96  t.expectParams<{}, {}>(u.combineWithParams([]).combineWithParams([]), []);
     97  t.expectParams<{}, {}>(u.combineWithParams([]).combineWithParams([{}]), []);
     98  t.expectParams<{}, {}>(u.combineWithParams([{}]).combineWithParams([]), []);
     99  t.expectParams<{}, {}>(u.combineWithParams([{}]).combineWithParams([{}]), [
    100    [{}, undefined], //
    101  ]);
    102 
    103  t.expectParams<{}, {}>(u.combine('x', []).combine('y', []), []);
    104  t.expectParams<{}, {}>(u.combine('x', []).combine('y', [1]), []);
    105  t.expectParams<{}, {}>(u.combine('x', [1]).combine('y', []), []);
    106  t.expectParams<{}, {}>(u.combine('x', [1]).combine('y', [1]), [
    107    [{ x: 1, y: 1 }, undefined], //
    108  ]);
    109 });
    110 
    111 g.test('combine,mixed').fn(t => {
    112  t.expectParams<{ x: number; y: string; p: number | undefined; q: number | undefined }, {}>(
    113    u
    114      .combine('x', [1, 2])
    115      .combine('y', ['a', 'b'])
    116      .combineWithParams([{ p: 4 }, { q: 5 }])
    117      .combineWithParams([{}]),
    118    [
    119      [{ x: 1, y: 'a', p: 4 }, undefined],
    120      [{ x: 1, y: 'a', q: 5 }, undefined],
    121      [{ x: 1, y: 'b', p: 4 }, undefined],
    122      [{ x: 1, y: 'b', q: 5 }, undefined],
    123      [{ x: 2, y: 'a', p: 4 }, undefined],
    124      [{ x: 2, y: 'a', q: 5 }, undefined],
    125      [{ x: 2, y: 'b', p: 4 }, undefined],
    126      [{ x: 2, y: 'b', q: 5 }, undefined],
    127    ]
    128  );
    129 });
    130 
    131 g.test('filter').fn(t => {
    132  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined }, {}>(
    133    u
    134      .combineWithParams([
    135        { a: true, x: 1 },
    136        { a: false, y: 2 },
    137      ])
    138      .filter(p => p.a),
    139    [
    140      [{ a: true, x: 1 }, undefined], //
    141    ]
    142  );
    143 
    144  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined }, {}>(
    145    u
    146      .combineWithParams([
    147        { a: true, x: 1 },
    148        { a: false, y: 2 },
    149      ])
    150      .beginSubcases()
    151      .filter(p => p.a),
    152    [
    153      [{ a: true, x: 1 }, [{}]], //
    154      // Case with no subcases is filtered out.
    155    ]
    156  );
    157 
    158  t.expectParams<{}, { a: boolean; x: number | undefined; y: number | undefined }>(
    159    u
    160      .beginSubcases()
    161      .combineWithParams([
    162        { a: true, x: 1 },
    163        { a: false, y: 2 },
    164      ])
    165      .filter(p => p.a),
    166    [
    167      [{}, [{ a: true, x: 1 }]], //
    168    ]
    169  );
    170 });
    171 
    172 g.test('unless').fn(t => {
    173  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined }, {}>(
    174    u
    175      .combineWithParams([
    176        { a: true, x: 1 },
    177        { a: false, y: 2 },
    178      ])
    179      .unless(p => p.a),
    180    [
    181      [{ a: false, y: 2 }, undefined], //
    182    ]
    183  );
    184 
    185  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined }, {}>(
    186    u
    187      .combineWithParams([
    188        { a: true, x: 1 },
    189        { a: false, y: 2 },
    190      ])
    191      .beginSubcases()
    192      .unless(p => p.a),
    193    [
    194      // Case with no subcases is filtered out.
    195      [{ a: false, y: 2 }, [{}]], //
    196    ]
    197  );
    198 
    199  t.expectParams<{}, { a: boolean; x: number | undefined; y: number | undefined }>(
    200    u
    201      .beginSubcases()
    202      .combineWithParams([
    203        { a: true, x: 1 },
    204        { a: false, y: 2 },
    205      ])
    206      .unless(p => p.a),
    207    [
    208      [{}, [{ a: false, y: 2 }]], //
    209    ]
    210  );
    211 });
    212 
    213 g.test('expandP').fn(t => {
    214  // simple
    215  t.expectParams<{}, {}>(
    216    u.expandWithParams(function* () {}),
    217    []
    218  );
    219  t.expectParams<{}, {}>(
    220    u.expandWithParams(function* () {
    221      yield {};
    222    }),
    223    [[{}, undefined]]
    224  );
    225  t.expectParams<{ z: number | undefined; w: number | undefined }, {}>(
    226    u.expandWithParams(function* () {
    227      yield* kUnitCaseParamsBuilder.combine('z', [3, 4]);
    228      yield { w: 5 };
    229    }),
    230    [
    231      [{ z: 3 }, undefined],
    232      [{ z: 4 }, undefined],
    233      [{ w: 5 }, undefined],
    234    ]
    235  );
    236  t.expectParams<{ z: number | undefined; w: number | undefined }, {}>(
    237    u.expandWithParams(function* () {
    238      yield* kUnitCaseParamsBuilder.combine('z', [3, 4]);
    239      yield { w: 5 };
    240    }),
    241    [
    242      [{ z: 3 }, undefined],
    243      [{ z: 4 }, undefined],
    244      [{ w: 5 }, undefined],
    245    ],
    246    {}
    247  );
    248  t.expectParams<{ z: number | undefined; w: number | undefined }, {}>(
    249    u.expandWithParams(function* () {
    250      yield* kUnitCaseParamsBuilder.combine('z', [3, 4]);
    251      yield { w: 5 };
    252    }),
    253    [[{ z: 4 }, undefined]],
    254    { z: 4 }
    255  );
    256  t.expectParams<{ z: number | undefined; w: number | undefined }, {}>(
    257    u.expandWithParams(function* () {
    258      yield* kUnitCaseParamsBuilder.combine('z', [3, 4]);
    259      yield { w: 5 };
    260    }),
    261    [[{ z: 3 }, undefined]],
    262    { z: 3 }
    263  );
    264  t.expectParams<{}, { z: number | undefined; w: number | undefined }>(
    265    u.beginSubcases().expandWithParams(function* () {
    266      yield* kUnitCaseParamsBuilder.combine('z', [3, 4]);
    267      yield { w: 5 };
    268    }),
    269    [[{}, [{ z: 3 }, { z: 4 }, { w: 5 }]]]
    270  );
    271 
    272  t.expectParams<{ x: [] | {} }, {}>(
    273    u.expand('x', () => [[], {}] as const),
    274    [
    275      [{ x: [] }, undefined],
    276      [{ x: {} }, undefined],
    277    ]
    278  );
    279  t.expectParams<{ x: [] | {} }, {}>(
    280    u.expand('x', () => [[], {}] as const),
    281    [[{ x: [] }, undefined]],
    282    { x: [] }
    283  );
    284  t.expectParams<{ x: [] | {} }, {}>(
    285    u.expand('x', () => [[], {}] as const),
    286    [[{ x: {} }, undefined]],
    287    { x: {} }
    288  );
    289 
    290  // more complex
    291  {
    292    const p = u
    293      .combineWithParams([
    294        { a: true, x: 1 },
    295        { a: false, y: 2 },
    296      ])
    297      .expandWithParams(function* (p) {
    298        if (p.a) {
    299          yield { z: 3 };
    300          yield { z: 4 };
    301        } else {
    302          yield { w: 5 };
    303        }
    304      });
    305    type T = {
    306      a: boolean;
    307      x: number | undefined;
    308      y: number | undefined;
    309      z: number | undefined;
    310      w: number | undefined;
    311    };
    312    t.expectParams<T, {}>(p, [
    313      [{ a: true, x: 1, z: 3 }, undefined],
    314      [{ a: true, x: 1, z: 4 }, undefined],
    315      [{ a: false, y: 2, w: 5 }, undefined],
    316    ]);
    317    t.expectParams<T, {}>(
    318      p,
    319      [
    320        [{ a: true, x: 1, z: 3 }, undefined],
    321        [{ a: true, x: 1, z: 4 }, undefined],
    322        [{ a: false, y: 2, w: 5 }, undefined],
    323      ],
    324      {}
    325    );
    326    t.expectParams<T, {}>(
    327      p,
    328      [
    329        [{ a: true, x: 1, z: 3 }, undefined],
    330        [{ a: true, x: 1, z: 4 }, undefined],
    331      ],
    332      { a: true }
    333    );
    334    t.expectParams<T, {}>(p, [[{ a: false, y: 2, w: 5 }, undefined]], { a: false });
    335  }
    336 
    337  t.expectParams<
    338    { a: boolean; x: number | undefined; y: number | undefined },
    339    { z: number | undefined; w: number | undefined }
    340  >(
    341    u
    342      .combineWithParams([
    343        { a: true, x: 1 },
    344        { a: false, y: 2 },
    345      ])
    346      .beginSubcases()
    347      .expandWithParams(function* (p) {
    348        if (p.a) {
    349          yield { z: 3 };
    350          yield { z: 4 };
    351        } else {
    352          yield { w: 5 };
    353        }
    354      }),
    355    [
    356      [{ a: true, x: 1 }, [{ z: 3 }, { z: 4 }]],
    357      [{ a: false, y: 2 }, [{ w: 5 }]],
    358    ]
    359  );
    360 });
    361 
    362 g.test('expand').fn(t => {
    363  // simple
    364  t.expectParams<{}, {}>(
    365    u.expand('x', function* () {}),
    366    []
    367  );
    368  t.expectParams<{ z: number }, {}>(
    369    u.expand('z', function* () {
    370      yield 3;
    371      yield 4;
    372    }),
    373    [
    374      [{ z: 3 }, undefined],
    375      [{ z: 4 }, undefined],
    376    ]
    377  );
    378  t.expectParams<{ z: number }, {}>(
    379    u.expand('z', function* () {
    380      yield 3;
    381      yield 4;
    382    }),
    383    [
    384      [{ z: 3 }, undefined],
    385      [{ z: 4 }, undefined],
    386    ],
    387    {}
    388  );
    389  t.expectParams<{ z: number }, {}>(
    390    u.expand('z', function* () {
    391      yield 3;
    392      yield 4;
    393    }),
    394    [[{ z: 3 }, undefined]],
    395    { z: 3 }
    396  );
    397  t.expectParams<{}, { z: number }>(
    398    u.beginSubcases().expand('z', function* () {
    399      yield 3;
    400      yield 4;
    401    }),
    402    [[{}, [{ z: 3 }, { z: 4 }]]]
    403  );
    404 
    405  // more complex
    406  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined; z: number }, {}>(
    407    u
    408      .combineWithParams([
    409        { a: true, x: 1 },
    410        { a: false, y: 2 },
    411      ])
    412      .expand('z', function* (p) {
    413        if (p.a) {
    414          yield 3;
    415        } else {
    416          yield 5;
    417        }
    418      }),
    419    [
    420      [{ a: true, x: 1, z: 3 }, undefined],
    421      [{ a: false, y: 2, z: 5 }, undefined],
    422    ]
    423  );
    424  t.expectParams<{ a: boolean; x: number | undefined; y: number | undefined }, { z: number }>(
    425    u
    426      .combineWithParams([
    427        { a: true, x: 1 },
    428        { a: false, y: 2 },
    429      ])
    430      .beginSubcases()
    431      .expand('z', function* (p) {
    432        if (p.a) {
    433          yield 3;
    434        } else {
    435          yield 5;
    436        }
    437      }),
    438    [
    439      [{ a: true, x: 1 }, [{ z: 3 }]],
    440      [{ a: false, y: 2 }, [{ z: 5 }]],
    441    ]
    442  );
    443 });
    444 
    445 g.test('invalid,shadowing').fn(t => {
    446  // Existing CaseP is shadowed by a new CaseP.
    447  {
    448    const p = u
    449      .combineWithParams([
    450        { a: true, x: 1 },
    451        { a: false, x: 2 },
    452      ])
    453      .expandWithParams(function* (p) {
    454        if (p.a) {
    455          yield { x: 3 };
    456        } else {
    457          yield { w: 5 };
    458        }
    459      });
    460    // Iterating causes merging e.g. ({x:1}, {x:3}), which fails.
    461    t.shouldThrow('Error', () => {
    462      Array.from(p.iterateCasesWithSubcases(null));
    463    });
    464  }
    465  // Existing SubcaseP is shadowed by a new SubcaseP.
    466  {
    467    const p = u
    468      .beginSubcases()
    469      .combineWithParams([
    470        { a: true, x: 1 },
    471        { a: false, x: 2 },
    472      ])
    473      .expandWithParams(function* (p) {
    474        if (p.a) {
    475          yield { x: 3 };
    476        } else {
    477          yield { w: 5 };
    478        }
    479      });
    480    // Iterating causes merging e.g. ({x:1}, {x:3}), which fails.
    481    t.shouldThrow('Error', () => {
    482      Array.from(p.iterateCasesWithSubcases(null));
    483    });
    484  }
    485  // Existing CaseP is shadowed by a new SubcaseP.
    486  {
    487    const p = u
    488      .combineWithParams([
    489        { a: true, x: 1 },
    490        { a: false, x: 2 },
    491      ])
    492      .beginSubcases()
    493      .expandWithParams(function* (p) {
    494        if (p.a) {
    495          yield { x: 3 };
    496        } else {
    497          yield { w: 5 };
    498        }
    499      });
    500    const cases = Array.from(p.iterateCasesWithSubcases(null));
    501    // Iterating cases is fine...
    502    for (const [caseP, subcases] of cases) {
    503      assert(subcases !== undefined);
    504      // Iterating subcases is fine...
    505      for (const subcaseP of subcases) {
    506        if (caseP.a) {
    507          assert(subcases !== undefined);
    508 
    509          // Only errors once we try to merge e.g. ({x:1}, {x:3}).
    510          mergeParams(caseP, subcaseP);
    511          t.shouldThrow('Error', () => {
    512            mergeParamsChecked(caseP, subcaseP);
    513          });
    514        }
    515      }
    516    }
    517  }
    518 });
    519 
    520 g.test('undefined').fn(t => {
    521  t.expect(!publicParamsEquals({ a: undefined }, {}));
    522  t.expect(!publicParamsEquals({}, { a: undefined }));
    523 });
    524 
    525 g.test('private').fn(t => {
    526  t.expect(publicParamsEquals({ _a: 0 }, {}));
    527  t.expect(publicParamsEquals({}, { _a: 0 }));
    528 });
    529 
    530 g.test('value,array').fn(t => {
    531  t.expectParams<{ a: number[] }, {}>(u.combineWithParams([{ a: [1, 2] }]), [
    532    [{ a: [1, 2] }, undefined], //
    533  ]);
    534  t.expectParams<{}, { a: number[] }>(u.beginSubcases().combineWithParams([{ a: [1, 2] }]), [
    535    [{}, [{ a: [1, 2] }]], //
    536  ]);
    537 });
    538 
    539 g.test('value,object').fn(t => {
    540  t.expectParams<{ a: { [k: string]: number } }, {}>(u.combineWithParams([{ a: { x: 1 } }]), [
    541    [{ a: { x: 1 } }, undefined], //
    542  ]);
    543  t.expectParams<{}, { a: { [k: string]: number } }>(
    544    u.beginSubcases().combineWithParams([{ a: { x: 1 } }]),
    545    [
    546      [{}, [{ a: { x: 1 } }]], //
    547    ]
    548  );
    549 });