Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Test Coverage for packages/web3/src/utils #468

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion packages/web3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,4 @@
"node": ">=14.0.0",
"npm": ">=7.0.0"
}
}
}
Benjtalkshow marked this conversation as resolved.
Show resolved Hide resolved
35 changes: 29 additions & 6 deletions packages/web3/src/utils/bs58.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,35 @@ You should have received a copy of the GNU Lesser General Public License
along with the library. If not, see <http://www.gnu.org/licenses/>.
*/

import { isBase58 } from './bs58'
import { isBase58, base58ToBytes, bs58 } from './bs58'
import { TraceableError } from '../error'

describe('bs58', () => {
it('should validate bs58 string', () => {
expect(isBase58('32UWxgjUHwH7P1J61tb12')).toEqual(true)
expect(isBase58('32U.WxgjUHwH7P1J61tb12')).toEqual(false)
expect(isBase58('')).toEqual(false)
describe('isBase58', () => {
it('should validate bs58 string', () => {
expect(isBase58('32UWxgjUHwH7P1J61tb12')).toEqual(true)
expect(isBase58('32U.WxgjUHwH7P1J61tb12')).toEqual(false)
expect(isBase58('')).toEqual(false)
})
})
})

describe('base58ToBytes', () => {
it('should convert valid base58 strings to bytes', () => {
const input = '32UWxgjUHwH7P1J61tb12'
const result = base58ToBytes(input)
expect(result).toBeInstanceOf(Uint8Array)
expect(result.length).toBeGreaterThan(0)
Benjtalkshow marked this conversation as resolved.
Show resolved Hide resolved
expect(bs58.encode(result)).toBe(input)
})

it('should handle empty string', () => {
const result = base58ToBytes('')
expect(result).toBeInstanceOf(Uint8Array)
expect(result.length).toBe(0)
})

it('should throw TraceableError for invalid base58 strings', () => {
expect(() => base58ToBytes('Invalid!Base58')).toThrow(TraceableError)
})
})
})
4 changes: 3 additions & 1 deletion packages/web3/src/utils/bs58.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ export function isBase58(s: string): boolean {
}

export function base58ToBytes(s: string): Uint8Array {
if (s === '') {
Benjtalkshow marked this conversation as resolved.
Show resolved Hide resolved
return new Uint8Array(0)
}
try {
return bs58.decode(s)
} catch (e) {
throw new TraceableError(`Invalid base58 string ${s}`, e)
}
}

export default bs58
28 changes: 15 additions & 13 deletions packages/web3/src/utils/djb2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.

import djb2 from './djb2'

describe('djb2', function () {
it('djb2', () => {
function check(str: string, expected: number) {
const bytes = new TextEncoder().encode(str)
expect(djb2(bytes)).toEqual(expected)
}
describe('djb2 Hashing Algorithm', function () {
function check(str: string, expected: number) {
const bytes = new TextEncoder().encode(str);
expect(djb2(bytes)).toEqual(expected);
}

check('', 5381)
check('a', 177670)
check('z', 177695)
check('foo', 193491849)
check('bar', 193487034)
})
})
it('should handle empty string', () => check('', 5381));
it('should handle single characters', () => {
check('a', 177670);
check('z', 177695);
});
it('should handle short strings', () => {
check('foo', 193491849);
check('bar', 193487034);
});
});
2 changes: 1 addition & 1 deletion packages/web3/src/utils/djb2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ export default function djb2(bytes: Uint8Array): number {
hash = (hash << 5) + hash + (bytes[`${i}`] & 0xff)
}
return hash
}
}
Benjtalkshow marked this conversation as resolved.
Show resolved Hide resolved
90 changes: 90 additions & 0 deletions packages/web3/src/utils/subscription.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import EventEmitter from 'eventemitter3'
import { Subscription, SubscribeOptions } from './subscription'

class TestSubscription<Message> extends Subscription<Message> {
public pollingCallCount = 0
private pollingPromise: Promise<void> | null = null

constructor(options: SubscribeOptions<Message>) {
super(options)
}

protected override async polling(): Promise<void> {
this.pollingCallCount++
if (this.pollingPromise) {
await this.pollingPromise
}
}

public setPollingDelay(delay: number): void {
this.pollingPromise = new Promise(resolve => setTimeout(resolve, delay))
}
}

describe('Subscription', () => {
let subscription: TestSubscription<string>
let messageCallback: jest.Mock
let errorCallback: jest.Mock

beforeAll(() => {
Object.defineProperty(global, 'performance', {
writable: true,
})

jest.useFakeTimers()
})

afterAll(() => {
jest.useRealTimers()
})

beforeEach(() => {
jest.clearAllMocks()
jest.clearAllTimers()

messageCallback = jest.fn()
errorCallback = jest.fn()
subscription = new TestSubscription({
pollingInterval: 1000,
messageCallback,
errorCallback,
})
})

it('should initialize with correct properties', () => {
expect(subscription.pollingInterval).toBe(1000)
expect(subscription['messageCallback']).toBe(messageCallback)
expect(subscription['errorCallback']).toBe(errorCallback)
expect(subscription['cancelled']).toBe(false)
expect(subscription['eventEmitter']).toBeInstanceOf(EventEmitter)
})

it('should report correct cancellation status', () => {
expect(subscription.isCancelled()).toBe(false)
subscription.unsubscribe()
expect(subscription.isCancelled()).toBe(true)
})

it('should not start a new polling cycle if cancelled during polling', async () => {
const slowPollingSubscription = new TestSubscription<string>({
pollingInterval: 1000,
messageCallback,
errorCallback,
})
slowPollingSubscription.setPollingDelay(500)

slowPollingSubscription.subscribe()
jest.advanceTimersByTime(100)
slowPollingSubscription.unsubscribe()
jest.advanceTimersByTime(2000)
expect(slowPollingSubscription.pollingCallCount).toBe(1)
})

it('should remove all event listeners when unsubscribed', () => {
const removeAllListenersSpy = jest.spyOn(subscription['eventEmitter'], 'removeAllListeners')
subscription.subscribe()
subscription.unsubscribe()
expect(removeAllListenersSpy).toHaveBeenCalled()
})
})

2 changes: 1 addition & 1 deletion packages/web3/src/utils/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,4 @@ describe('utils', function () {
'Invalid target 1b01ae9z, expected a hex string of length 8'
)
})
})
})
2 changes: 1 addition & 1 deletion packages/web3/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,4 @@ export type Narrow<type> =
| (type extends Function ? type : never)
| (type extends bigint | boolean | number | string ? type : never)
| (type extends [] ? [] : never)
| { [K in keyof type]: Narrow<type[K]> }
| { [K in keyof type]: Narrow<type[K]> }