Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions common/src/util/__tests__/currency.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { describe, expect, it } from 'bun:test'

import {
convertCreditsToUsdCents,
convertStripeGrantAmountToCredits,
} from '../currency'

describe('convertCreditsToUsdCents', () => {
it('converts credits to cents correctly', () => {
expect(convertCreditsToUsdCents(1, 100)).toBe(100)
expect(convertCreditsToUsdCents(1.5, 100)).toBe(150)
expect(convertCreditsToUsdCents(0.1, 100)).toBe(10)
})

it('throws for non-positive centsPerCredit', () => {
expect(() => convertCreditsToUsdCents(100, 0)).toThrow('centsPerCredit must be positive')
expect(() => convertCreditsToUsdCents(100, -10)).toThrow('centsPerCredit must be positive')
})

it('throws for NaN credits', () => {
expect(() => convertCreditsToUsdCents(NaN, 100)).toThrow('credits must be finite')
})

it('throws for Infinity credits', () => {
expect(() => convertCreditsToUsdCents(Infinity, 100)).toThrow('credits must be finite')
})

it('throws for negative Infinity credits', () => {
expect(() => convertCreditsToUsdCents(-Infinity, 100)).toThrow('credits must be finite')
})
})

describe('convertStripeGrantAmountToCredits', () => {
it('converts cents to credits correctly', () => {
expect(convertStripeGrantAmountToCredits(10000, 100)).toBe(100)
expect(convertStripeGrantAmountToCredits(15000, 100)).toBe(150)
expect(convertStripeGrantAmountToCredits(1000, 100)).toBe(10)
})

it('throws for non-positive centsPerCredit', () => {
expect(() => convertStripeGrantAmountToCredits(10000, 0)).toThrow('centsPerCredit must be positive')
expect(() => convertStripeGrantAmountToCredits(10000, -10)).toThrow('centsPerCredit must be positive')
})

it('throws for NaN amountInCents', () => {
expect(() => convertStripeGrantAmountToCredits(NaN, 100)).toThrow('amountInCents must be finite')
})

it('throws for Infinity amountInCents', () => {
expect(() => convertStripeGrantAmountToCredits(Infinity, 100)).toThrow('amountInCents must be finite')
})

it('throws for negative Infinity amountInCents', () => {
expect(() => convertStripeGrantAmountToCredits(-Infinity, 100)).toThrow('amountInCents must be finite')
})
})
22 changes: 22 additions & 0 deletions common/src/util/currency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@
* @param credits The number of credits to convert
* @param centsPerCredit The cost per credit in cents
* @returns The amount in USD cents
* @throws Error if centsPerCredit is not positive or credits is not finite
*/
export function convertCreditsToUsdCents(
credits: number,
centsPerCredit: number,
): number {
if (!(centsPerCredit > 0)) {
throw new Error(
`convertCreditsToUsdCents: centsPerCredit must be positive, got ${centsPerCredit}`,
)
}
if (!Number.isFinite(credits)) {
throw new Error(
`convertCreditsToUsdCents: credits must be finite, got ${credits}`,
)
}
return Math.ceil(credits * centsPerCredit)
}

Expand All @@ -16,10 +27,21 @@ export function convertCreditsToUsdCents(
* @param amountInCents The amount in USD cents
* @param centsPerCredit The cost per credit in cents
* @returns The number of credits
* @throws Error if centsPerCredit is not positive or amountInCents is not finite
*/
export function convertStripeGrantAmountToCredits(
amountInCents: number,
centsPerCredit: number,
): number {
if (!(centsPerCredit > 0)) {
throw new Error(
`convertStripeGrantAmountToCredits: centsPerCredit must be positive, got ${centsPerCredit}`,
)
}
if (!Number.isFinite(amountInCents)) {
throw new Error(
`convertStripeGrantAmountToCredits: amountInCents must be finite, got ${amountInCents}`,
)
}
return Math.floor(amountInCents / centsPerCredit)
}
Loading