Skip to content

Commit

Permalink
fix: bigint
Browse files Browse the repository at this point in the history
  • Loading branch information
soc221b committed Jan 3, 2025
1 parent 7857a72 commit 9324f9e
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 30 deletions.
64 changes: 34 additions & 30 deletions src/zod-bigint-faker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,43 @@ import { ZodTypeFaker } from './zod-type-faker'

export class ZodBigIntFaker extends ZodTypeFaker<z.ZodBigInt> {
fake(): z.infer<z.ZodBigInt> {
const min = (() => {
for (const check of this.schema._def.checks) {
if (check.kind === 'min') {
return check.value + (check.inclusive ? 0n : 1n)
}
}
return -1_000_000n
})()
const max = (() => {
for (const check of this.schema._def.checks) {
if (check.kind === 'max') {
return check.value + (check.inclusive ? 0n : -1n)
}
}
return 1_000_000n
})()
let min: undefined | bigint = undefined
let max: undefined | bigint = undefined
let multipleOf: undefined | bigint = undefined
for (const check of this.schema._def.checks) {
if (check.kind === 'multipleOf') {
const absMultipleOf = check.value < 0n ? -1n * check.value : check.value
const r = min % check.value
const absR = r < 0n ? -1n * r : r
let start = min + absR
while (start <= max) {
if (runFake(faker => faker.datatype.boolean())) {
return start
} else {
start += absMultipleOf
}
}
return start <= max ? start : min + absR
switch (check.kind) {
case 'min':
min = check.value + (check.inclusive ? 0n : 1n)
break
case 'max':
max = check.value - (check.inclusive ? 0n : 1n)
break
case 'multipleOf':
multipleOf = check.value
break
default:
const _: never = check
}
}

// workaround: https://github.com/faker-js/faker/pull/3363
if (min === undefined && max !== undefined && max < 0n) {
min = max - (multipleOf ?? 1_000n)
}

if (multipleOf !== undefined) {
if (min !== undefined && max !== undefined) {
return min + runFake(faker => faker.number.bigInt({ min: 0n, max: (max - min) / multipleOf })) * multipleOf
} else if (min !== undefined) {
return min + runFake(faker => faker.number.bigInt({ min: 0n })) * multipleOf
} else if (max !== undefined) {
return max - runFake(faker => faker.number.bigInt({ min: 0n })) * multipleOf
} else {
return runFake(faker => faker.number.bigInt({ min: 0n })) * multipleOf
}
} else {
return runFake(faker => faker.number.bigInt({ min, max }))
}
return runFake(faker => faker.number.bigInt({ min, max }))
}

static create(schema: z.ZodBigInt): ZodBigIntFaker {
Expand Down
96 changes: 96 additions & 0 deletions tests/zod-bigint-faker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,99 @@ testMultipleTimes('multiplyOf 4', () => {
}
expect(schema.safeParse(data).success).toBe(true)
})

describe('edge case', () => {
test('gt', () => {
const schema = z.bigint().gt(100n).lte(101n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(101n)
})

test('gte', () => {
const schema = z.bigint().gte(100n).lt(101n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(100n)
})

test('lt', () => {
const schema = z.bigint().lt(100n).gte(99n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(99n)
})

test('lte', () => {
const schema = z.bigint().lte(100n).gt(99n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(100n)
})

test('positive', () => {
const schema = z.bigint().positive().lt(2n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(1n)
})

test('nonnegative', () => {
const schema = z.bigint().nonnegative().lt(1n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(0n)
})

test('negative', () => {
const schema = z.bigint().negative().gt(-2n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(-1n)
})

test('nonpositive', () => {
const schema = z.bigint().nonpositive().gt(-1n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(0n)
})

test('multiplyOf positive', () => {
const schema = z.bigint().multipleOf(37n).gte(37n).lte(37n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(37n)
})

test('multiplyOf negative', () => {
const schema = z.bigint().multipleOf(-37n).gte(-37n).lte(-37n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
expect(data).toBe(-37n)
})

test('multiplyOf + min', () => {
const schema = z.bigint().multipleOf(37n).min(37n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
})

test('multiplyOf + max', () => {
const schema = z.bigint().multipleOf(37n).max(37n)
const faker = zodBigIntFaker(schema)
const data = faker.fake()
expect(schema.safeParse(data).success).toBe(true)
})
})

0 comments on commit 9324f9e

Please sign in to comment.