import iconv from 'iconv-lite';
import { stringify } from 'cloudflare/internal/qs';
import { encode } from 'cloudflare/internal/qs/utils';
import { StringifyOptions } from 'cloudflare/internal/qs/types';
import { empty_test_cases } from './empty-keys-cases';
import assert from 'assert';

describe('stringify()', function () {
  test('stringifies a querystring object', function () {
    expect(stringify({ a: 'b' })).toBe('a=b');
    expect(stringify({ a: 1 })).toBe('a=1');
    expect(stringify({ a: 1, b: 2 })).toBe('a=1&b=2');
    expect(stringify({ a: 'A_Z' })).toBe('a=A_Z');
    expect(stringify({ a: '€' })).toBe('a=%E2%82%AC');
    expect(stringify({ a: '' })).toBe('a=%EE%80%80');
    expect(stringify({ a: 'א' })).toBe('a=%D7%90');
    expect(stringify({ a: '𐐷' })).toBe('a=%F0%90%90%B7');
  });

  test('stringifies falsy values', function () {
    expect(stringify(undefined)).toBe('');
    expect(stringify(null)).toBe('');
    expect(stringify(null, { strictNullHandling: true })).toBe('');
    expect(stringify(false)).toBe('');
    expect(stringify(0)).toBe('');
  });

  test('stringifies symbols', function () {
    expect(stringify(Symbol.iterator)).toBe('');
    expect(stringify([Symbol.iterator])).toBe('0=Symbol%28Symbol.iterator%29');
    expect(stringify({ a: Symbol.iterator })).toBe('a=Symbol%28Symbol.iterator%29');
    expect(stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
      'a[]=Symbol%28Symbol.iterator%29',
    );
  });

  test('stringifies bigints', function () {
    var three = BigInt(3);
    // @ts-expect-error
    var encodeWithN = function (value, defaultEncoder, charset) {
      var result = defaultEncoder(value, defaultEncoder, charset);
      return typeof value === 'bigint' ? result + 'n' : result;
    };

    expect(stringify(three)).toBe('');
    expect(stringify([three])).toBe('0=3');
    expect(stringify([three], { encoder: encodeWithN })).toBe('0=3n');
    expect(stringify({ a: three })).toBe('a=3');
    expect(stringify({ a: three }, { encoder: encodeWithN })).toBe('a=3n');
    expect(stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=3');
    expect(
      stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }),
    ).toBe('a[]=3n');
  });

  test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function () {
    expect(
      stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: false }),
    ).toBe('name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe');
    expect(
      stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: false }),
    ).toBe('name.obj.first=John&name.obj.last=Doe');
    expect(
      stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: true }),
    ).toBe('name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe');
    expect(
      stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true }),
    ).toBe('name%252Eobj.first=John&name%252Eobj.last=Doe');

    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ allowDots: false, encodeDotInKeys: false },
    // 	),
    // 	'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe',
    // 	'with allowDots false and encodeDotInKeys false',
    // );
    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ allowDots: true, encodeDotInKeys: false },
    // 	),
    // 	'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
    // 	'with allowDots false and encodeDotInKeys false',
    // );
    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ allowDots: false, encodeDotInKeys: true },
    // 	),
    // 	'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe',
    // 	'with allowDots false and encodeDotInKeys true',
    // );
    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ allowDots: true, encodeDotInKeys: true },
    // 	),
    // 	'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
    // 	'with allowDots true and encodeDotInKeys true',
    // );
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { allowDots: false, encodeDotInKeys: false },
      ),
    ).toBe('name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe');
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { allowDots: true, encodeDotInKeys: false },
      ),
    ).toBe('name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe');
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { allowDots: false, encodeDotInKeys: true },
      ),
    ).toBe('name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe');
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { allowDots: true, encodeDotInKeys: true },
      ),
    ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe');
  });

  test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function () {
    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ encodeDotInKeys: true },
    // 	),
    // 	'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
    // 	'with allowDots undefined and encodeDotInKeys true',
    // );
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { encodeDotInKeys: true },
      ),
    ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe');
  });

  test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function () {
    // st.equal(
    // 	stringify(
    // 		{ 'name.obj': { first: 'John', last: 'Doe' } },
    // 		{
    // 			encodeDotInKeys: true,
    // 			allowDots: true,
    // 			encodeValuesOnly: true,
    // 		},
    // 	),
    // 	'name%2Eobj.first=John&name%2Eobj.last=Doe',
    // );
    expect(
      stringify(
        { 'name.obj': { first: 'John', last: 'Doe' } },
        {
          encodeDotInKeys: true,
          allowDots: true,
          encodeValuesOnly: true,
        },
      ),
    ).toBe('name%2Eobj.first=John&name%2Eobj.last=Doe');

    // st.equal(
    // 	stringify(
    // 		{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
    // 		{ allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true },
    // 	),
    // 	'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe',
    // );
    expect(
      stringify(
        { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
        { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true },
      ),
    ).toBe('name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe');
  });

  test('throws when `commaRoundTrip` is not a boolean', function () {
    // st['throws'](
    // 	function () {
    // 		stringify({}, { commaRoundTrip: 'not a boolean' });
    // 	},
    // 	TypeError,
    // 	'throws when `commaRoundTrip` is not a boolean',
    // );
    expect(() => {
      // @ts-expect-error
      stringify({}, { commaRoundTrip: 'not a boolean' });
    }).toThrow(TypeError);
  });

  test('throws when `encodeDotInKeys` is not a boolean', function () {
    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null });
    }).toThrow(TypeError);
  });

  test('adds query prefix', function () {
    // st.equal(stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
    expect(stringify({ a: 'b' }, { addQueryPrefix: true })).toBe('?a=b');
  });

  test('with query prefix, outputs blank string given an empty object', function () {
    // st.equal(stringify({}, { addQueryPrefix: true }), '');
    expect(stringify({}, { addQueryPrefix: true })).toBe('');
  });

  test('stringifies nested falsy values', function () {
    // st.equal(stringify({ a: { b: { c: null } } }), 'a%5Bb%5D%5Bc%5D=');
    // st.equal(
    // 	stringify({ a: { b: { c: null } } }, { strictNullHandling: true }),
    // 	'a%5Bb%5D%5Bc%5D',
    // );
    // st.equal(stringify({ a: { b: { c: false } } }), 'a%5Bb%5D%5Bc%5D=false');
    expect(stringify({ a: { b: { c: null } } })).toBe('a%5Bb%5D%5Bc%5D=');
    expect(stringify({ a: { b: { c: null } } }, { strictNullHandling: true })).toBe('a%5Bb%5D%5Bc%5D');
    expect(stringify({ a: { b: { c: false } } })).toBe('a%5Bb%5D%5Bc%5D=false');
  });

  test('stringifies a nested object', function () {
    // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
    // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
    expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c');
    expect(stringify({ a: { b: { c: { d: 'e' } } } })).toBe('a%5Bb%5D%5Bc%5D%5Bd%5D=e');
  });

  test('`allowDots` option: stringifies a nested object with dots notation', function () {
    // st.equal(stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
    // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
    expect(stringify({ a: { b: 'c' } }, { allowDots: true })).toBe('a.b=c');
    expect(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true })).toBe('a.b.c.d=e');
  });

  test('stringifies an array value', function () {
    // st.equal(
    // 	stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }),
    // 	'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }),
    // 	'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' }),
    // 	'a=b%2Cc%2Cd',
    // 	'comma => comma',
    // );
    // st.equal(
    // 	stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
    // 	'a=b%2Cc%2Cd',
    // 	'comma round trip => comma',
    // );
    // st.equal(
    // 	stringify({ a: ['b', 'c', 'd'] }),
    // 	'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
    // 	'default => indices',
    // );
    expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' })).toBe(
      'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
    );
    expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' })).toBe(
      'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
    );
    expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' })).toBe('a=b%2Cc%2Cd');
    expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe(
      'a=b%2Cc%2Cd',
    );
    expect(stringify({ a: ['b', 'c', 'd'] })).toBe('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
  });

  test('`skipNulls` option', function () {
    // st.equal(
    // 	stringify({ a: 'b', c: null }, { skipNulls: true }),
    // 	'a=b',
    // 	'omits nulls when asked',
    // );
    expect(stringify({ a: 'b', c: null }, { skipNulls: true })).toBe('a=b');

    // st.equal(
    // 	stringify({ a: { b: 'c', d: null } }, { skipNulls: true }),
    // 	'a%5Bb%5D=c',
    // 	'omits nested nulls when asked',
    // );
    expect(stringify({ a: { b: 'c', d: null } }, { skipNulls: true })).toBe('a%5Bb%5D=c');
  });

  test('omits array indices when asked', function () {
    // st.equal(stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
    expect(stringify({ a: ['b', 'c', 'd'] }, { indices: false })).toBe('a=b&a=c&a=d');
  });

  test('omits object key/value pair when value is empty array', function () {
    // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz');
    expect(stringify({ a: [], b: 'zz' })).toBe('b=zz');
  });

  test('should not omit object key/value pair when value is empty array and when asked', function () {
    // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz');
    // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz');
    // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz');
    expect(stringify({ a: [], b: 'zz' })).toBe('b=zz');
    expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false })).toBe('b=zz');
    expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true })).toBe('a[]&b=zz');
  });

  test('should throw when allowEmptyArrays is not of type boolean', function () {
    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN });
    }).toThrow(TypeError);

    // st['throws'](function () {
    // 	stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null });
    // }, TypeError);
    expect(() => {
      // @ts-expect-error
      stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null });
    }).toThrow(TypeError);
  });

  test('allowEmptyArrays + strictNullHandling', function () {
    // st.equal(
    // 	stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true }),
    // 	'testEmptyArray[]',
    // );
    expect(stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true })).toBe(
      'testEmptyArray[]',
    );
  });

  describe('stringifies an array value with one item vs multiple items', function () {
    test('non-array item', function () {
      // s2t.equal(
      // 	stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
      // 	'a=c',
      // );
      // s2t.equal(
      // 	stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
      // 	'a=c',
      // );
      // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c');
      // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true }), 'a=c');
      expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a=c');
      expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a=c');
      expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c');
      expect(stringify({ a: 'c' }, { encodeValuesOnly: true })).toBe('a=c');
    });

    test('array with a single item', function () {
      // s2t.equal(
      // 	stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
      // 	'a[0]=c',
      // );
      // s2t.equal(
      // 	stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
      // 	'a[]=c',
      // );
      // s2t.equal(
      // 	stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
      // 	'a=c',
      // );
      // s2t.equal(
      // 	stringify(
      // 		{ a: ['c'] },
      // 		{ encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
      // 	),
      // 	'a[]=c',
      // ); // so it parses back as an array
      // s2t.equal(stringify({ a: ['c'] }, { encodeValuesOnly: true }), 'a[0]=c');
      expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a[0]=c');
      expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=c');
      expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c');
      expect(
        stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }),
      ).toBe('a[]=c');
      expect(stringify({ a: ['c'] }, { encodeValuesOnly: true })).toBe('a[0]=c');
    });

    test('array with multiple items', function () {
      // s2t.equal(
      // 	stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
      // 	'a[0]=c&a[1]=d',
      // );
      // s2t.equal(
      // 	stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
      // 	'a[]=c&a[]=d',
      // );
      // s2t.equal(
      // 	stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
      // 	'a=c,d',
      // );
      // s2t.equal(
      // 	stringify(
      // 		{ a: ['c', 'd'] },
      // 		{ encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
      // 	),
      // 	'a=c,d',
      // );
      // s2t.equal(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d');
      expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
        'a[0]=c&a[1]=d',
      );
      expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
        'a[]=c&a[]=d',
      );
      expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c,d');
      expect(
        stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }),
      ).toBe('a=c,d');
      expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true })).toBe('a[0]=c&a[1]=d');
    });

    test('array with multiple items with a comma inside', function () {
      // s2t.equal(
      // 	stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
      // 	'a=c%2Cd,e',
      // );
      // s2t.equal(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
      expect(stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe(
        'a=c%2Cd,e',
      );
      expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' })).toBe('a=c%2Cd%2Ce');

      // s2t.equal(
      // 	stringify(
      // 		{ a: ['c,d', 'e'] },
      // 		{ encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
      // 	),
      // 	'a=c%2Cd,e',
      // );
      // s2t.equal(
      // 	stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
      // 	'a=c%2Cd%2Ce',
      // );
      expect(
        stringify(
          { a: ['c,d', 'e'] },
          { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
        ),
      ).toBe('a=c%2Cd,e');
      expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe(
        'a=c%2Cd%2Ce',
      );
    });
  });

  test('stringifies a nested array value', function () {
    expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
      'a[b][0]=c&a[b][1]=d',
    );
    expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
      'a[b][]=c&a[b][]=d',
    );
    expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe(
      'a[b]=c,d',
    );
    expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true })).toBe('a[b][0]=c&a[b][1]=d');
  });

  test('stringifies comma and empty array values', function () {
    // st.equal(
    // 	stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }),
    // 	'a[0]=,&a[1]=&a[2]=c,d%',
    // );
    // st.equal(
    // 	stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }),
    // 	'a[]=,&a[]=&a[]=c,d%',
    // );
    // st.equal(
    // 	stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }),
    // 	'a=,,,c,d%',
    // );
    // st.equal(
    // 	stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }),
    // 	'a=,&a=&a=c,d%',
    // );
    expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' })).toBe(
      'a[0]=,&a[1]=&a[2]=c,d%',
    );
    expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' })).toBe(
      'a[]=,&a[]=&a[]=c,d%',
    );
    expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' })).toBe('a=,,,c,d%');
    expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' })).toBe(
      'a=,&a=&a=c,d%',
    );

    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a[0]=%2C&a[1]=&a[2]=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a[]=%2C&a[]=&a[]=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'comma' },
    // 	),
    // 	'a=%2C,,c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a=%2C&a=&a=c%2Cd%25',
    // );
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }),
    ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }),
    ).toBe('a=%2C%2C%2Cc%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
    ).toBe('a=%2C&a=&a=c%2Cd%25');

    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
    // 	),
    // 	'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
    // 	),
    // 	'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
    // 	),
    // 	'a=%2C%2C%2Cc%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [',', '', 'c,d%'] },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
    // 	),
    // 	'a=%2C&a=&a=c%2Cd%25',
    // );
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
    ).toBe('a=%2C&a=&a=c%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }),
    ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }),
    ).toBe('a=%2C%2C%2Cc%2Cd%25');
    expect(
      stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
    ).toBe('a=%2C&a=&a=c%2Cd%25');
  });

  test('stringifies comma and empty non-array values', function () {
    // st.equal(
    // 	stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }),
    // 	'a=,&b=&c=c,d%',
    // );
    // st.equal(
    // 	stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }),
    // 	'a=,&b=&c=c,d%',
    // );
    // st.equal(
    // 	stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }),
    // 	'a=,&b=&c=c,d%',
    // );
    // st.equal(
    // 	stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }),
    // 	'a=,&b=&c=c,d%',
    // );
    expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' })).toBe(
      'a=,&b=&c=c,d%',
    );
    expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' })).toBe(
      'a=,&b=&c=c,d%',
    );

    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'comma' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');

    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: ',', b: '', c: 'c,d%' },
    // 		{ encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
    // 	),
    // 	'a=%2C&b=&c=c%2Cd%25',
    // );
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
    expect(
      stringify(
        { a: ',', b: '', c: 'c,d%' },
        { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
      ),
    ).toBe('a=%2C&b=&c=c%2Cd%25');
  });

  test('stringifies a nested array value with dots notation', function () {
    // st.equal(
    // 	stringify(
    // 		{ a: { b: ['c', 'd'] } },
    // 		{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a.b[0]=c&a.b[1]=d',
    // 	'indices: stringifies with dots + indices',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: { b: ['c', 'd'] } },
    // 		{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a.b[]=c&a.b[]=d',
    // 	'brackets: stringifies with dots + brackets',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: { b: ['c', 'd'] } },
    // 		{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' },
    // 	),
    // 	'a.b=c,d',
    // 	'comma: stringifies with dots + comma',
    // );
    // st.equal(
    // 	stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true }),
    // 	'a.b[0]=c&a.b[1]=d',
    // 	'default: stringifies with dots + indices',
    // );
    expect(
      stringify(
        { a: { b: ['c', 'd'] } },
        { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' },
      ),
    ).toBe('a.b[0]=c&a.b[1]=d');
    expect(
      stringify(
        { a: { b: ['c', 'd'] } },
        { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
      ),
    ).toBe('a.b[]=c&a.b[]=d');
    expect(
      stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }),
    ).toBe('a.b=c,d');
    expect(stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true })).toBe(
      'a.b[0]=c&a.b[1]=d',
    );
  });

  test('stringifies an object inside an array', function () {
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
    // 	'a[0][b]=c',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
    // 	'a[b]=c',
    // 	'repeat => repeat',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
    // 	'a[][b]=c',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }),
    // 	'a[0][b]=c',
    // 	'default => indices',
    // );
    expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe(
      'a[0][b]=c',
    );
    expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe('a[b]=c');
    expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe(
      'a[][b]=c',
    );
    expect(stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true })).toBe('a[0][b]=c');

    // st.equal(
    // 	stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
    // 	'a[0][b][c][0]=1',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
    // 	'a[b][c]=1',
    // 	'repeat => repeat',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
    // 	'a[][b][c][]=1',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }),
    // 	'a[0][b][c][0]=1',
    // 	'default => indices',
    // );
    expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe(
      'a[0][b][c][0]=1',
    );
    expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe(
      'a[b][c]=1',
    );
    expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe(
      'a[][b][c][]=1',
    );
    expect(stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true })).toBe('a[0][b][c][0]=1');
  });

  test('stringifies an array with mixed objects and primitives', function () {
    // st.equal(
    // 	stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    // 	'a[0][b]=1&a[1]=2&a[2]=3',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    // 	'a[][b]=1&a[]=2&a[]=3',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
    // 	'???',
    // 	'brackets => brackets',
    // 	{ skip: 'TODO: figure out what this should do' },
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }),
    // 	'a[0][b]=1&a[1]=2&a[2]=3',
    // 	'default => indices',
    // );
    expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
      'a[0][b]=1&a[1]=2&a[2]=3',
    );
    expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
      'a[][b]=1&a[]=2&a[]=3',
    );
    // !Skipped: Figure out what this should do
    // expect(
    // 	stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
    // ).toBe('???');
    expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true })).toBe('a[0][b]=1&a[1]=2&a[2]=3');
  });

  test('stringifies an object inside an array with dots notation', function () {
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }),
    // 	'a[0].b=c',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [{ b: 'c' }] },
    // 		{ allowDots: true, encode: false, arrayFormat: 'brackets' },
    // 	),
    // 	'a[].b=c',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false }),
    // 	'a[0].b=c',
    // 	'default => indices',
    // );
    expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' })).toBe(
      'a[0].b=c',
    );
    expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' })).toBe(
      'a[].b=c',
    );
    expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false })).toBe('a[0].b=c');

    // st.equal(
    // 	stringify(
    // 		{ a: [{ b: { c: [1] } }] },
    // 		{ allowDots: true, encode: false, arrayFormat: 'indices' },
    // 	),
    // 	'a[0].b.c[0]=1',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [{ b: { c: [1] } }] },
    // 		{ allowDots: true, encode: false, arrayFormat: 'brackets' },
    // 	),
    // 	'a[].b.c[]=1',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false }),
    // 	'a[0].b.c[0]=1',
    // 	'default => indices',
    // );
    expect(
      stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }),
    ).toBe('a[0].b.c[0]=1');
    expect(
      stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' }),
    ).toBe('a[].b.c[]=1');
    expect(stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false })).toBe('a[0].b.c[0]=1');
  });

  test('does not omit object keys when indices = false', function () {
    // st.equal(stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c');
    expect(stringify({ a: [{ b: 'c' }] }, { indices: false })).toBe('a%5Bb%5D=c');
  });

  test('uses indices notation for arrays when indices=true', function () {
    // st.equal(stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c');
    expect(stringify({ a: ['b', 'c'] }, { indices: true })).toBe('a%5B0%5D=b&a%5B1%5D=c');
  });

  test('uses indices notation for arrays when no arrayFormat is specified', function () {
    // st.equal(stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c');
    expect(stringify({ a: ['b', 'c'] })).toBe('a%5B0%5D=b&a%5B1%5D=c');
  });

  test('uses indices notation for arrays when arrayFormat=indices', function () {
    // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
    expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).toBe('a%5B0%5D=b&a%5B1%5D=c');
  });

  test('uses repeat notation for arrays when arrayFormat=repeat', function () {
    // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
    expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).toBe('a=b&a=c');
  });

  test('uses brackets notation for arrays when arrayFormat=brackets', function () {
    // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
    expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).toBe('a%5B%5D=b&a%5B%5D=c');
  });

  test('stringifies a complicated object', function () {
    // st.equal(stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e');
    expect(stringify({ a: { b: 'c', d: 'e' } })).toBe('a%5Bb%5D=c&a%5Bd%5D=e');
  });

  test('stringifies an empty value', function () {
    // st.equal(stringify({ a: '' }), 'a=');
    // st.equal(stringify({ a: null }, { strictNullHandling: true }), 'a');
    expect(stringify({ a: '' })).toBe('a=');
    expect(stringify({ a: null }, { strictNullHandling: true })).toBe('a');

    // st.equal(stringify({ a: '', b: '' }), 'a=&b=');
    // st.equal(stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b=');
    expect(stringify({ a: '', b: '' })).toBe('a=&b=');
    expect(stringify({ a: null, b: '' }, { strictNullHandling: true })).toBe('a&b=');

    // st.equal(stringify({ a: { b: '' } }), 'a%5Bb%5D=');
    // st.equal(stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D');
    // st.equal(stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D=');
    expect(stringify({ a: { b: '' } })).toBe('a%5Bb%5D=');
    expect(stringify({ a: { b: null } }, { strictNullHandling: true })).toBe('a%5Bb%5D');
    expect(stringify({ a: { b: null } }, { strictNullHandling: false })).toBe('a%5Bb%5D=');
  });

  test('stringifies an empty array in different arrayFormat', function () {
    // st.equal(stringify({ a: [], b: [null], c: 'c' }, { encode: false }), 'b[0]=&c=c');
    expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false })).toBe('b[0]=&c=c');
    // arrayFormat default
    // st.equal(
    // 	stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' }),
    // 	'b[0]=&c=c',
    // );
    // st.equal(
    // 	stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }),
    // 	'b[]=&c=c',
    // );
    // st.equal(
    // 	stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }),
    // 	'b=&c=c',
    // );
    // st.equal(
    // 	stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }),
    // 	'b=&c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'comma', commaRoundTrip: true },
    // 	),
    // 	'b[]=&c=c',
    // );
    expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' })).toBe(
      'b[0]=&c=c',
    );
    expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' })).toBe(
      'b[]=&c=c',
    );
    expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' })).toBe('b=&c=c');
    expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' })).toBe('b=&c=c');
    expect(
      stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', commaRoundTrip: true }),
    ).toBe('b[]=&c=c');

    // with strictNullHandling
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'indices', strictNullHandling: true },
    // 	),
    // 	'b[0]&c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'brackets', strictNullHandling: true },
    // 	),
    // 	'b[]&c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'repeat', strictNullHandling: true },
    // 	),
    // 	'b&c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'comma', strictNullHandling: true },
    // 	),
    // 	'b&c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true },
    // 	),
    // 	'b[]&c=c',
    // );

    expect(
      stringify(
        { a: [], b: [null], c: 'c' },
        { encode: false, arrayFormat: 'indices', strictNullHandling: true },
      ),
    ).toBe('b[0]&c=c');
    expect(
      stringify(
        { a: [], b: [null], c: 'c' },
        { encode: false, arrayFormat: 'brackets', strictNullHandling: true },
      ),
    ).toBe('b[]&c=c');
    expect(
      stringify(
        { a: [], b: [null], c: 'c' },
        { encode: false, arrayFormat: 'repeat', strictNullHandling: true },
      ),
    ).toBe('b&c=c');
    expect(
      stringify(
        { a: [], b: [null], c: 'c' },
        { encode: false, arrayFormat: 'comma', strictNullHandling: true },
      ),
    ).toBe('b&c=c');
    expect(
      stringify(
        { a: [], b: [null], c: 'c' },
        { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true },
      ),
    ).toBe('b[]&c=c');

    // with skipNulls
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'indices', skipNulls: true },
    // 	),
    // 	'c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'brackets', skipNulls: true },
    // 	),
    // 	'c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'repeat', skipNulls: true },
    // 	),
    // 	'c=c',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [], b: [null], c: 'c' },
    // 		{ encode: false, arrayFormat: 'comma', skipNulls: true },
    // 	),
    // 	'c=c',
    // );
    expect(
      stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }),
    ).toBe('c=c');
    expect(
      stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }),
    ).toBe('c=c');
    expect(
      stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', skipNulls: true }),
    ).toBe('c=c');
    expect(
      stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', skipNulls: true }),
    ).toBe('c=c');
  });

  test('stringifies a null object', function () {
    var obj = Object.create(null);
    obj.a = 'b';
    // st.equal(stringify(obj), 'a=b');
    expect(stringify(obj)).toBe('a=b');
  });

  test('returns an empty string for invalid input', function () {
    // st.equal(stringify(undefined), '');
    // st.equal(stringify(false), '');
    // st.equal(stringify(null), '');
    // st.equal(stringify(''), '');
    expect(stringify(undefined)).toBe('');
    expect(stringify(false)).toBe('');
    expect(stringify(null)).toBe('');
    expect(stringify('')).toBe('');
  });

  test('stringifies an object with a null object as a child', function () {
    var obj = { a: Object.create(null) };

    obj.a.b = 'c';
    // st.equal(stringify(obj), 'a%5Bb%5D=c');
    expect(stringify(obj)).toBe('a%5Bb%5D=c');
  });

  test('drops keys with a value of undefined', function () {
    // st.equal(stringify({ a: undefined }), '');
    expect(stringify({ a: undefined })).toBe('');

    // st.equal(
    // 	stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }),
    // 	'a%5Bc%5D',
    // );
    // st.equal(
    // 	stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }),
    // 	'a%5Bc%5D=',
    // );
    // st.equal(stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D=');
    expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).toBe('a%5Bc%5D');
    expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).toBe('a%5Bc%5D=');
    expect(stringify({ a: { b: undefined, c: '' } })).toBe('a%5Bc%5D=');
  });

  test('url encodes values', function () {
    // st.equal(stringify({ a: 'b c' }), 'a=b%20c');
    expect(stringify({ a: 'b c' })).toBe('a=b%20c');
  });

  test('stringifies a date', function () {
    var now = new Date();
    var str = 'a=' + encodeURIComponent(now.toISOString());
    // st.equal(stringify({ a: now }), str);
    expect(stringify({ a: now })).toBe(str);
  });

  test('stringifies the weird object from qs', function () {
    // st.equal(
    // 	stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }),
    // 	'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F',
    // );
    expect(stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).toBe(
      'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F',
    );
  });

  // TODO: Investigate how to to intercept in vitest
  // TODO(rob)
  test('skips properties that are part of the object prototype', function () {
    // st.intercept(Object.prototype, 'crash', { value: 'test' });
    // @ts-expect-error
    Object.prototype.crash = 'test';

    // st.equal(stringify({ a: 'b' }), 'a=b');
    // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
    expect(stringify({ a: 'b' })).toBe('a=b');
    expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c');
  });

  test('stringifies boolean values', function () {
    // st.equal(stringify({ a: true }), 'a=true');
    // st.equal(stringify({ a: { b: true } }), 'a%5Bb%5D=true');
    // st.equal(stringify({ b: false }), 'b=false');
    // st.equal(stringify({ b: { c: false } }), 'b%5Bc%5D=false');
    expect(stringify({ a: true })).toBe('a=true');
    expect(stringify({ a: { b: true } })).toBe('a%5Bb%5D=true');
    expect(stringify({ b: false })).toBe('b=false');
    expect(stringify({ b: { c: false } })).toBe('b%5Bc%5D=false');
  });

  test('stringifies buffer values', function () {
    // st.equal(stringify({ a: Buffer.from('test') }), 'a=test');
    // st.equal(stringify({ a: { b: Buffer.from('test') } }), 'a%5Bb%5D=test');
  });

  test('stringifies an object using an alternative delimiter', function () {
    // st.equal(stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
    expect(stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).toBe('a=b;c=d');
  });

  // We dont target environments which dont even have Buffer
  // test('does not blow up when Buffer global is missing', function () {
  // 	var restore = mockProperty(global, 'Buffer', { delete: true });

  // 	var result = stringify({ a: 'b', c: 'd' });

  // 	restore();

  // 	st.equal(result, 'a=b&c=d');
  // 	st.end();
  // });

  test('does not crash when parsing circular references', function () {
    var a: any = {};
    a.b = a;

    // st['throws'](
    // 	function () {
    // 		stringify({ 'foo[bar]': 'baz', 'foo[baz]': a });
    // 	},
    // 	/RangeError: Cyclic object value/,
    // 	'cyclic values throw',
    // );
    expect(() => {
      stringify({ 'foo[bar]': 'baz', 'foo[baz]': a });
    }).toThrow('Cyclic object value');

    var circular: any = {
      a: 'value',
    };
    circular.a = circular;
    // st['throws'](
    // 	function () {
    // 		stringify(circular);
    // 	},
    // 	/RangeError: Cyclic object value/,
    // 	'cyclic values throw',
    // );
    expect(() => {
      stringify(circular);
    }).toThrow('Cyclic object value');

    var arr = ['a'];
    // st.doesNotThrow(function () {
    // 	stringify({ x: arr, y: arr });
    // }, 'non-cyclic values do not throw');
    expect(() => {
      stringify({ x: arr, y: arr });
    }).not.toThrow();
  });

  test('non-circular duplicated references can still work', function () {
    var hourOfDay = {
      function: 'hour_of_day',
    };

    var p1 = {
      function: 'gte',
      arguments: [hourOfDay, 0],
    };
    var p2 = {
      function: 'lte',
      arguments: [hourOfDay, 23],
    };

    // st.equal(
    // 	stringify(
    // 		{ filters: { $and: [p1, p2] } },
    // 		{ encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23',
    // );
    // st.equal(
    // 	stringify(
    // 		{ filters: { $and: [p1, p2] } },
    // 		{ encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23',
    // );
    // st.equal(
    // 	stringify(
    // 		{ filters: { $and: [p1, p2] } },
    // 		{ encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23',
    // );
    expect(
      stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    ).toBe(
      'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23',
    );
    expect(
      stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe(
      'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23',
    );
    expect(
      stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
    ).toBe(
      'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23',
    );
  });

  test('selects properties when filter=array', function () {
    // st.equal(stringify({ a: 'b' }, { filter: ['a'] }), 'a=b');
    // st.equal(stringify({ a: 1 }, { filter: [] }), '');
    expect(stringify({ a: 'b' }, { filter: ['a'] })).toBe('a=b');
    expect(stringify({ a: 1 }, { filter: [] })).toBe('');

    // st.equal(
    // 	stringify(
    // 		{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
    // 		{ filter: ['a', 'b', 0, 2], arrayFormat: 'indices' },
    // 	),
    // 	'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
    // 	'indices => indices',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
    // 		{ filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' },
    // 	),
    // 	'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3',
    // 	'brackets => brackets',
    // );
    // st.equal(
    // 	stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] }),
    // 	'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
    // 	'default => indices',
    // );
    expect(stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).toBe(
      'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
    );
    expect(
      stringify(
        { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
        { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' },
      ),
    ).toBe('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
    expect(
      stringify(
        { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
        { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' },
      ),
    ).toBe('a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3');
  });

  test('supports custom representations when filter=function', function () {
    var calls = 0;
    var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
    var filterFunc: StringifyOptions['filter'] = function (prefix, value) {
      calls += 1;
      if (calls === 1) {
        // st.equal(prefix, '', 'prefix is empty');
        // st.equal(value, obj);
        expect(prefix).toBe('');
        expect(value).toBe(obj);
      } else if (prefix === 'c') {
        return void 0;
      } else if (value instanceof Date) {
        // st.equal(prefix, 'e[f]');
        expect(prefix).toBe('e[f]');
        return value.getTime();
      }
      return value;
    };

    // st.equal(stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000');
    // st.equal(calls, 5);
    expect(stringify(obj, { filter: filterFunc })).toBe('a=b&e%5Bf%5D=1257894000000');
    expect(calls).toBe(5);
  });

  test('can disable uri encoding', function () {
    // st.equal(stringify({ a: 'b' }, { encode: false }), 'a=b');
    // st.equal(stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c');
    // st.equal(
    // 	stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }),
    // 	'a=b&c',
    // );
    expect(stringify({ a: 'b' }, { encode: false })).toBe('a=b');
    expect(stringify({ a: { b: 'c' } }, { encode: false })).toBe('a[b]=c');
    expect(stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false })).toBe('a=b&c');
  });

  test('can sort the keys', function () {
    // @ts-expect-error
    var sort: NonNullable<StringifyOptions['sort']> = function (a: string, b: string) {
      return a.localeCompare(b);
    };
    // st.equal(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y');
    // st.equal(
    // 	stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }),
    // 	'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a',
    // );
    expect(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort })).toBe('a=c&b=f&z=y');
    expect(stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort })).toBe(
      'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a',
    );
  });

  test('can sort the keys at depth 3 or more too', function () {
    // @ts-expect-error
    var sort: NonNullable<StringifyOptions['sort']> = function (a: string, b: string) {
      return a.localeCompare(b);
    };
    // st.equal(
    // 	stringify(
    // 		{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
    // 		{ sort: sort, encode: false },
    // 	),
    // 	'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
    // 		{ sort: null, encode: false },
    // 	),
    // 	'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b',
    // );
    expect(
      stringify(
        { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
        { sort: sort, encode: false },
      ),
    ).toBe('a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb');
    expect(
      stringify(
        { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
        { sort: null, encode: false },
      ),
    ).toBe('a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b');
  });

  test('can stringify with custom encoding', function () {
    // st.equal(
    // 	stringify(
    // 		{ 県: '大阪府', '': '' },
    // 		{
    // 			encoder: function (str) {
    // 				if (str.length === 0) {
    // 					return '';
    // 				}
    // 				var buf = iconv.encode(str, 'shiftjis');
    // 				var result = [];
    // 				for (var i = 0; i < buf.length; ++i) {
    // 					result.push(buf.readUInt8(i).toString(16));
    // 				}
    // 				return '%' + result.join('%');
    // 			},
    // 		},
    // 	),
    // 	'%8c%a7=%91%e5%8d%e3%95%7b&=',
    // );
    expect(
      stringify(
        { 県: '大阪府', '': '' },
        {
          encoder: function (str) {
            if (str.length === 0) {
              return '';
            }
            var buf = iconv.encode(str, 'shiftjis');
            var result = [];
            for (var i = 0; i < buf.length; ++i) {
              result.push(buf.readUInt8(i).toString(16));
            }
            return '%' + result.join('%');
          },
        },
      ),
    ).toBe('%8c%a7=%91%e5%8d%e3%95%7b&=');
  });

  test('receives the default encoder as a second argument', function () {
    // stringify(
    // 	{ a: 1, b: new Date(), c: true, d: [1] },
    // 	{
    // 		encoder: function (str) {
    // 			st.match(typeof str, /^(?:string|number|boolean)$/);
    // 			return '';
    // 		},
    // 	},
    // );

    stringify(
      { a: 1, b: new Date(), c: true, d: [1] },
      {
        encoder: function (str) {
          // st.match(typeof str, /^(?:string|number|boolean)$/);
          assert.match(typeof str, /^(?:string|number|boolean)$/);
          return '';
        },
      },
    );
  });

  test('receives the default encoder as a second argument', function () {
    // stringify(
    // 	{ a: 1 },
    // 	{
    // 		encoder: function (str, defaultEncoder) {
    // 			st.equal(defaultEncoder, utils.encode);
    // 		},
    // 	},
    // );

    stringify(
      { a: 1 },
      {
        // @ts-ignore
        encoder: function (_str, defaultEncoder) {
          expect(defaultEncoder).toBe(encode);
        },
      },
    );
  });

  test('throws error with wrong encoder', function () {
    // st['throws'](function () {
    // 	stringify({}, { encoder: 'string' });
    // }, new TypeError('Encoder has to be a function.'));
    // st.end();
    expect(() => {
      // @ts-expect-error
      stringify({}, { encoder: 'string' });
    }).toThrow(TypeError);
  });

  (typeof Buffer === 'undefined' ? test.skip : test)(
    'can use custom encoder for a buffer object',
    function () {
      // st.equal(
      // 	stringify(
      // 		{ a: Buffer.from([1]) },
      // 		{
      // 			encoder: function (buffer) {
      // 				if (typeof buffer === 'string') {
      // 					return buffer;
      // 				}
      // 				return String.fromCharCode(buffer.readUInt8(0) + 97);
      // 			},
      // 		},
      // 	),
      // 	'a=b',
      // );
      expect(
        stringify(
          { a: Buffer.from([1]) },
          {
            encoder: function (buffer) {
              if (typeof buffer === 'string') {
                return buffer;
              }
              return String.fromCharCode(buffer.readUInt8(0) + 97);
            },
          },
        ),
      ).toBe('a=b');

      // st.equal(
      // 	stringify(
      // 		{ a: Buffer.from('a b') },
      // 		{
      // 			encoder: function (buffer) {
      // 				return buffer;
      // 			},
      // 		},
      // 	),
      // 	'a=a b',
      // );
      expect(
        stringify(
          { a: Buffer.from('a b') },
          {
            encoder: function (buffer) {
              return buffer;
            },
          },
        ),
      ).toBe('a=a b');
    },
  );

  test('serializeDate option', function () {
    var date = new Date();
    // st.equal(
    // 	stringify({ a: date }),
    // 	'a=' + date.toISOString().replace(/:/g, '%3A'),
    // 	'default is toISOString',
    // );
    expect(stringify({ a: date })).toBe('a=' + date.toISOString().replace(/:/g, '%3A'));

    var mutatedDate = new Date();
    mutatedDate.toISOString = function () {
      throw new SyntaxError();
    };
    // st['throws'](function () {
    // 	mutatedDate.toISOString();
    // }, SyntaxError);
    expect(() => {
      mutatedDate.toISOString();
    }).toThrow(SyntaxError);
    // st.equal(
    // 	stringify({ a: mutatedDate }),
    // 	'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
    // 	'toISOString works even when method is not locally present',
    // );
    expect(stringify({ a: mutatedDate })).toBe(
      'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
    );

    var specificDate = new Date(6);
    // st.equal(
    // 	stringify(
    // 		{ a: specificDate },
    // 		{
    // 			serializeDate: function (d) {
    // 				return d.getTime() * 7;
    // 			},
    // 		},
    // 	),
    // 	'a=42',
    // 	'custom serializeDate function called',
    // );
    expect(
      stringify(
        { a: specificDate },
        {
          // @ts-ignore
          serializeDate: function (d) {
            return d.getTime() * 7;
          },
        },
      ),
    ).toBe('a=42');

    // st.equal(
    // 	stringify(
    // 		{ a: [date] },
    // 		{
    // 			serializeDate: function (d) {
    // 				return d.getTime();
    // 			},
    // 			arrayFormat: 'comma',
    // 		},
    // 	),
    // 	'a=' + date.getTime(),
    // 	'works with arrayFormat comma',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [date] },
    // 		{
    // 			serializeDate: function (d) {
    // 				return d.getTime();
    // 			},
    // 			arrayFormat: 'comma',
    // 			commaRoundTrip: true,
    // 		},
    // 	),
    // 	'a%5B%5D=' + date.getTime(),
    // 	'works with arrayFormat comma',
    // );
    expect(
      stringify(
        { a: [date] },
        {
          // @ts-expect-error
          serializeDate: function (d) {
            return d.getTime();
          },
          arrayFormat: 'comma',
        },
      ),
    ).toBe('a=' + date.getTime());
    expect(
      stringify(
        { a: [date] },
        {
          // @ts-expect-error
          serializeDate: function (d) {
            return d.getTime();
          },
          arrayFormat: 'comma',
          commaRoundTrip: true,
        },
      ),
    ).toBe('a%5B%5D=' + date.getTime());
  });

  test('RFC 1738 serialization', function () {
    // st.equal(stringify({ a: 'b c' }, { format: formats.RFC1738 }), 'a=b+c');
    // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC1738 }), 'a+b=c+d');
    // st.equal(
    // 	stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC1738 }),
    // 	'a+b=a+b',
    // );
    expect(stringify({ a: 'b c' }, { format: 'RFC1738' })).toBe('a=b+c');
    expect(stringify({ 'a b': 'c d' }, { format: 'RFC1738' })).toBe('a+b=c+d');
    expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC1738' })).toBe('a+b=a+b');

    // st.equal(stringify({ 'foo(ref)': 'bar' }, { format: formats.RFC1738 }), 'foo(ref)=bar');
    expect(stringify({ 'foo(ref)': 'bar' }, { format: 'RFC1738' })).toBe('foo(ref)=bar');
  });

  test('RFC 3986 spaces serialization', function () {
    // st.equal(stringify({ a: 'b c' }, { format: formats.RFC3986 }), 'a=b%20c');
    // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC3986 }), 'a%20b=c%20d');
    // st.equal(
    // 	stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC3986 }),
    // 	'a%20b=a%20b',
    // );
    expect(stringify({ a: 'b c' }, { format: 'RFC3986' })).toBe('a=b%20c');
    expect(stringify({ 'a b': 'c d' }, { format: 'RFC3986' })).toBe('a%20b=c%20d');
    expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC3986' })).toBe('a%20b=a%20b');
  });

  test('Backward compatibility to RFC 3986', function () {
    // st.equal(stringify({ a: 'b c' }), 'a=b%20c');
    // st.equal(stringify({ 'a b': Buffer.from('a b') }), 'a%20b=a%20b');
    expect(stringify({ a: 'b c' })).toBe('a=b%20c');
    expect(stringify({ 'a b': Buffer.from('a b') })).toBe('a%20b=a%20b');
  });

  test('Edge cases and unknown formats', function () {
    ['UFO1234', false, 1234, null, {}, []].forEach(function (format) {
      // st['throws'](function () {
      // 	stringify({ a: 'b c' }, { format: format });
      // }, new TypeError('Unknown format option provided.'));
      expect(() => {
        // @ts-expect-error
        stringify({ a: 'b c' }, { format: format });
      }).toThrow(TypeError);
    });
  });

  test('encodeValuesOnly', function () {
    // st.equal(
    // 	stringify(
    // 		{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h',
    // 	'encodeValuesOnly + indices',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h',
    // 	'encodeValuesOnly + brackets',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a=b&c=d&c=e%3Df&f=g&f=h',
    // 	'encodeValuesOnly + repeat',
    // );
    expect(
      stringify(
        { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
        { encodeValuesOnly: true, arrayFormat: 'indices' },
      ),
    ).toBe('a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
    expect(
      stringify(
        { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
        { encodeValuesOnly: true, arrayFormat: 'brackets' },
      ),
    ).toBe('a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h');
    expect(
      stringify(
        { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
        { encodeValuesOnly: true, arrayFormat: 'repeat' },
      ),
    ).toBe('a=b&c=d&c=e%3Df&f=g&f=h');

    // st.equal(
    // 	stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' }),
    // 	'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
    // 	'no encodeValuesOnly + indices',
    // );
    // st.equal(
    // 	stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' }),
    // 	'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
    // 	'no encodeValuesOnly + brackets',
    // );
    // st.equal(
    // 	stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' }),
    // 	'a=b&c=d&c=e&f=g&f=h',
    // 	'no encodeValuesOnly + repeat',
    // );
    expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' })).toBe(
      'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
    );
    expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' })).toBe(
      'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
    );
    expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' })).toBe(
      'a=b&c=d&c=e&f=g&f=h',
    );
  });

  test('encodeValuesOnly - strictNullHandling', function () {
    // st.equal(
    // 	stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true }),
    // 	'a[b]',
    // );
    expect(stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true })).toBe('a[b]');
  });

  test('throws if an invalid charset is specified', function () {
    // st['throws'](function () {
    // 	stringify({ a: 'b' }, { charset: 'foobar' });
    // }, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
    expect(() => {
      // @ts-expect-error
      stringify({ a: 'b' }, { charset: 'foobar' });
    }).toThrow(TypeError);
  });

  test('respects a charset of iso-8859-1', function () {
    // st.equal(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }), '%E6=%E6');
    expect(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' })).toBe('%E6=%E6');
  });

  test('encodes unrepresentable chars as numeric entities in iso-8859-1 mode', function () {
    // st.equal(stringify({ a: '☺' }, { charset: 'iso-8859-1' }), 'a=%26%239786%3B');
    expect(stringify({ a: '☺' }, { charset: 'iso-8859-1' })).toBe('a=%26%239786%3B');
  });

  test('respects an explicit charset of utf-8 (the default)', function () {
    // st.equal(stringify({ a: 'æ' }, { charset: 'utf-8' }), 'a=%C3%A6');
    expect(stringify({ a: 'æ' }, { charset: 'utf-8' })).toBe('a=%C3%A6');
  });

  test('`charsetSentinel` option', function () {
    // st.equal(
    // 	stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }),
    // 	'utf8=%E2%9C%93&a=%C3%A6',
    // 	'adds the right sentinel when instructed to and the charset is utf-8',
    // );
    expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' })).toBe(
      'utf8=%E2%9C%93&a=%C3%A6',
    );

    // st.equal(
    // 	stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }),
    // 	'utf8=%26%2310003%3B&a=%E6',
    // 	'adds the right sentinel when instructed to and the charset is iso-8859-1',
    // );
    expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' })).toBe(
      'utf8=%26%2310003%3B&a=%E6',
    );
  });

  test('does not mutate the options argument', function () {
    var options = {};
    stringify({}, options);
    // st.deepEqual(options, {});
    expect(options).toEqual({});
  });

  test('strictNullHandling works with custom filter', function () {
    // @ts-expect-error
    var filter = function (_prefix, value) {
      return value;
    };

    var options = { strictNullHandling: true, filter: filter };
    // st.equal(stringify({ key: null }, options), 'key');
    expect(stringify({ key: null }, options)).toBe('key');
  });

  test('strictNullHandling works with null serializeDate', function () {
    var serializeDate = function () {
      return null;
    };
    var options = { strictNullHandling: true, serializeDate: serializeDate };
    var date = new Date();
    // st.equal(stringify({ key: date }, options), 'key');
    // @ts-expect-error
    expect(stringify({ key: date }, options)).toBe('key');
  });

  test('allows for encoding keys and values differently', function () {
    // @ts-expect-error
    var encoder = function (str, defaultEncoder, charset, type) {
      if (type === 'key') {
        return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase();
      }
      if (type === 'value') {
        return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase();
      }
      throw 'this should never happen! type: ' + type;
    };

    // st.deepEqual(stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE');
    expect(stringify({ KeY: 'vAlUe' }, { encoder: encoder })).toBe('key=VALUE');
  });

  test('objects inside arrays', function () {
    var obj = { a: { b: { c: 'd', e: 'f' } } };
    var withArray = { a: { b: [{ c: 'd', e: 'f' }] } };

    // st.equal(
    // 	stringify(obj, { encode: false }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'no array, no arrayFormat',
    // );
    // st.equal(
    // 	stringify(obj, { encode: false, arrayFormat: 'brackets' }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'no array, bracket',
    // );
    // st.equal(
    // 	stringify(obj, { encode: false, arrayFormat: 'indices' }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'no array, indices',
    // );
    // st.equal(
    // 	stringify(obj, { encode: false, arrayFormat: 'repeat' }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'no array, repeat',
    // );
    // st.equal(
    // 	stringify(obj, { encode: false, arrayFormat: 'comma' }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'no array, comma',
    // );
    expect(stringify(obj, { encode: false })).toBe('a[b][c]=d&a[b][e]=f');
    expect(stringify(obj, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][c]=d&a[b][e]=f');
    expect(stringify(obj, { encode: false, arrayFormat: 'indices' })).toBe('a[b][c]=d&a[b][e]=f');
    expect(stringify(obj, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f');
    expect(stringify(obj, { encode: false, arrayFormat: 'comma' })).toBe('a[b][c]=d&a[b][e]=f');

    // st.equal(
    // 	stringify(withArray, { encode: false }),
    // 	'a[b][0][c]=d&a[b][0][e]=f',
    // 	'array, no arrayFormat',
    // );
    // st.equal(
    // 	stringify(withArray, { encode: false, arrayFormat: 'brackets' }),
    // 	'a[b][][c]=d&a[b][][e]=f',
    // 	'array, bracket',
    // );
    // st.equal(
    // 	stringify(withArray, { encode: false, arrayFormat: 'indices' }),
    // 	'a[b][0][c]=d&a[b][0][e]=f',
    // 	'array, indices',
    // );
    // st.equal(
    // 	stringify(withArray, { encode: false, arrayFormat: 'repeat' }),
    // 	'a[b][c]=d&a[b][e]=f',
    // 	'array, repeat',
    // );
    // st.equal(
    // 	stringify(withArray, { encode: false, arrayFormat: 'comma' }),
    // 	'???',
    // 	'array, comma',
    // 	{ skip: 'TODO: figure out what this should do' },
    // );
    expect(stringify(withArray, { encode: false })).toBe('a[b][0][c]=d&a[b][0][e]=f');
    expect(stringify(withArray, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][][c]=d&a[b][][e]=f');
    expect(stringify(withArray, { encode: false, arrayFormat: 'indices' })).toBe('a[b][0][c]=d&a[b][0][e]=f');
    expect(stringify(withArray, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f');
    // !TODo: Figure out what this should do
    // expect(stringify(withArray, { encode: false, arrayFormat: 'comma' })).toBe(
    // 	'a[b][c]=d&a[b][e]=f',
    // );
  });

  test('stringifies sparse arrays', function () {
    // st.equal(
    // 	stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    // 	'a[1]=2&a[4]=1',
    // );
    // st.equal(
    // 	stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    // 	'a[]=2&a[]=1',
    // );
    // st.equal(
    // 	stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
    // 	'a=2&a=1',
    // );
    expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
      'a[1]=2&a[4]=1',
    );
    expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
      'a[]=2&a[]=1',
    );
    expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' })).toBe(
      'a=2&a=1',
    );

    // st.equal(
    // 	stringify(
    // 		{ a: [, { b: [, , { c: '1' }] }] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a[1][b][2][c]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, { b: [, , { c: '1' }] }] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a[][b][][c]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, { b: [, , { c: '1' }] }] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a[b][c]=1',
    // );
    expect(
      stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    ).toBe('a[1][b][2][c]=1');
    expect(
      stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe('a[][b][][c]=1');
    expect(
      stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
    ).toBe('a[b][c]=1');

    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: '1' }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a[1][2][3][c]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: '1' }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a[][][][c]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: '1' }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a[c]=1',
    // );
    expect(
      stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    ).toBe('a[1][2][3][c]=1');
    expect(
      stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe('a[][][][c]=1');
    expect(
      stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
    ).toBe('a[c]=1');

    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: [, '1'] }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'indices' },
    // 	),
    // 	'a[1][2][3][c][1]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: [, '1'] }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'brackets' },
    // 	),
    // 	'a[][][][c][]=1',
    // );
    // st.equal(
    // 	stringify(
    // 		{ a: [, [, , [, , , { c: [, '1'] }]]] },
    // 		{ encodeValuesOnly: true, arrayFormat: 'repeat' },
    // 	),
    // 	'a[c]=1',
    // );
    expect(
      stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
    ).toBe('a[1][2][3][c][1]=1');
    expect(
      stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
    ).toBe('a[][][][c][]=1');
    expect(
      stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
    ).toBe('a[c]=1');
  });

  test('encodes a very long string', function () {
    var chars = [];
    var expected = [];
    for (var i = 0; i < 5e3; i++) {
      chars.push(' ' + i);

      expected.push('%20' + i);
    }

    var obj = {
      foo: chars.join(''),
    };

    // st.equal(
    // 	stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }),
    // 	'foo=' + expected.join(''),
    // );
    // @ts-expect-error
    expect(stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' })).toBe('foo=' + expected.join(''));
  });
});

describe('stringifies empty keys', function () {
  empty_test_cases.forEach(function (testCase) {
    test('stringifies an object with empty string key with ' + testCase.input, function () {
      // st.deepEqual(
      // 	stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }),
      // 	testCase.stringifyOutput.indices,
      // 	'test case: ' + testCase.input + ', indices',
      // );
      // st.deepEqual(
      // 	stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }),
      // 	testCase.stringifyOutput.brackets,
      // 	'test case: ' + testCase.input + ', brackets',
      // );
      // st.deepEqual(
      // 	stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }),
      // 	testCase.stringifyOutput.repeat,
      // 	'test case: ' + testCase.input + ', repeat',
      // );
      expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'indices' })).toBe(
        testCase.stringify_output.indices,
      );
      expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'brackets' })).toBe(
        testCase.stringify_output.brackets,
      );
      expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'repeat' })).toBe(
        testCase.stringify_output.repeat,
      );
    });
  });

  test('edge case with object/arrays', function () {
    // st.deepEqual(stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3');
    // st.deepEqual(
    // 	stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }),
    // 	'[][0]=2&[][1]=3&[a]=2',
    // );
    // st.deepEqual(
    // 	stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }),
    // 	'[][0]=2&[][1]=3',
    // );
    // st.deepEqual(
    // 	stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }),
    // 	'[][0]=2&[][1]=3&[a]=2',
    // );
    expect(stringify({ '': { '': [2, 3] } }, { encode: false })).toBe('[][0]=2&[][1]=3');
    expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false })).toBe('[][0]=2&[][1]=3&[a]=2');
    expect(stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' })).toBe(
      '[][0]=2&[][1]=3',
    );
    expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' })).toBe(
      '[][0]=2&[][1]=3&[a]=2',
    );
  });
});
