Skip to content

Commit

Permalink
feat: config and logger instances
Browse files Browse the repository at this point in the history
  • Loading branch information
tabaktoni committed Jan 28, 2025
1 parent 88e4b52 commit 88e62cc
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 29 deletions.
2 changes: 1 addition & 1 deletion __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
stark,
waitForTransactionOptions,
} from '../src';
import { StarknetChainId } from '../src/constants';
import { StarknetChainId } from '../src/global/constants';
import { felt, uint256 } from '../src/utils/calldata/cairo';
import { toBigInt, toHexString } from '../src/utils/num';
import {
Expand Down
102 changes: 102 additions & 0 deletions __tests__/utils/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { constants, config } from '../../src';

describe('Configuration', () => {
// Reset the configuration before each test to avoid side effects
beforeEach(() => {
config.reset();
});

describe('Initial Configuration', () => {
it('should initialize with default values', () => {
expect(config.get('legacyMode')).toBe(constants.DEFAULT_GLOBAL_CONFIG.legacyMode);
expect(config.get('logLevel')).toBe(constants.DEFAULT_GLOBAL_CONFIG.logLevel);
});
});

describe('get()', () => {
it('should retrieve the value of an existing key', () => {
expect(config.get('logLevel')).toBe(constants.DEFAULT_GLOBAL_CONFIG.logLevel);
});

it('should return the default value for a non-existent key', () => {
expect(config.get('nonExistentKey', 'default')).toBe('default');
});

it('should return undefined for a non-existent key without a default', () => {
expect(config.get('nonExistentKey')).toBeUndefined();
});
});

describe('set()', () => {
it('should update the value of an existing key', () => {
config.set('logLevel', 'DEBUG');
expect(config.get('logLevel')).toBe('DEBUG');
});

it('should add a new key-value pair', () => {
config.set('newKey', 'value');
expect(config.get('newKey')).toBe('value');
});
});

describe('update()', () => {
it('should merge provided configuration with existing values', () => {
config.update({ legacyMode: true, newKey: 'value' });
expect(config.get('legacyMode')).toBe(true);
expect(config.get('newKey')).toBe('value');
expect(config.get('logLevel')).toBe('INFO'); // Existing key remains unchanged
});
});

describe('getAll()', () => {
it('should return a copy of the configuration', () => {
const all = config.getAll();
all.legacyMode = true; // Modify the copy
expect(config.get('legacyMode')).toBe(false); // Original remains unaffected
});
});

describe('reset()', () => {
it('should restore the configuration to initial defaults', () => {
config.set('logLevel', 'ERROR');
config.reset();
expect(config.get('logLevel')).toBe('INFO');
});
});

describe('delete()', () => {
it('should remove a key from the configuration', () => {
config.set('newKey', 'value');
config.delete('newKey');
expect(config.hasKey('newKey')).toBe(false);
});

it('should do nothing if the key does not exist', () => {
config.delete('nonExistentKey');
expect(config.hasKey('nonExistentKey')).toBe(false);
});
});

describe('hasKey()', () => {
it('should return true for existing keys', () => {
expect(config.hasKey('logLevel')).toBe(true);
});

it('should return false for non-existent keys', () => {
expect(config.hasKey('nonExistentKey')).toBe(false);
});
});

describe('Edge Cases', () => {
it('should handle undefined values with default in get()', () => {
config.set('logLevel', undefined);
expect(config.get('logLevel', 'DEFAULT')).toBe('DEFAULT');
});

it('should treat keys as case-sensitive', () => {
config.set('LogLevel', 'DEBUG');
expect(config.hasKey('LogLevel')).toBe(true);
expect(config.hasKey('logLevel')).toBe(true); // Original key still exists
});
});
});
2 changes: 1 addition & 1 deletion __tests__/utils/ellipticalCurve.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { constants, ec } from '../../src';
import { StarknetChainId } from '../../src/constants';
import { StarknetChainId } from '../../src/global/constants';
import { computeHashOnElements } from '../../src/utils/hash';
import { calculateTransactionHash } from '../../src/utils/hash/transactionHash/v2';
import { fromCallsToExecuteCalldataWithNonce } from '../../src/utils/transaction';
Expand Down
161 changes: 161 additions & 0 deletions __tests__/utils/logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* eslint-disable no-console */
import { logger, LogLevel } from '../../src';

// Mock the config module
const mockConfigStore: { logLevel: LogLevel; [key: string]: any } = {
logLevel: 'INFO',
};

jest.mock('../../src/global/config', () => ({
config: {
get: jest.fn().mockImplementation((key: string, defaultValue?: any) => {
return mockConfigStore[key] ?? defaultValue;
}),
set: jest.fn().mockImplementation((key: string, value: any) => {
mockConfigStore[key] = value;
}),
},
}));

// Mock console methods
const mockConsole = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
log: jest.fn(),
};

global.console = mockConsole as any;

describe('Logger', () => {
// const gLog = jest.spyOn(global.console, 'log');
const gInfo = jest.spyOn(global.console, 'info');
const gDebug = jest.spyOn(global.console, 'debug');
const gWarn = jest.spyOn(global.console, 'warn');
const gError = jest.spyOn(global.console, 'error');

beforeEach(() => {
// Reset mock config and console calls
mockConfigStore.logLevel = 'INFO';
jest.clearAllMocks();
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01T00:00:00Z'));
});

afterEach(() => {
jest.useRealTimers();
});

describe('Log Level Configuration', () => {
it('should have config log level', () => {
expect(logger.getLogLevel()).toBe('INFO');
});

it('should set and get log level OFF', () => {
logger.setLogLevel('OFF');
expect(logger.getLogLevel()).toBe('OFF');
expect(logger.getEnabledLogLevels()).toStrictEqual([]);
});

it('should set and get log level FATAL', () => {
logger.setLogLevel('FATAL');
expect(logger.getLogLevel()).toBe('FATAL');
expect(logger.getEnabledLogLevels()).toStrictEqual(['FATAL']);
});

it('should set and get log level ERROR', () => {
logger.setLogLevel('ERROR');
expect(logger.getLogLevel()).toBe('ERROR');
expect(logger.getEnabledLogLevels()).toStrictEqual(['ERROR', 'FATAL']);
});

it('should set and get log level WARN', () => {
logger.setLogLevel('WARN');
expect(logger.getLogLevel()).toBe('WARN');
expect(logger.getEnabledLogLevels()).toStrictEqual(['WARN', 'ERROR', 'FATAL']);
});

it('should set and get log level INFO', () => {
logger.setLogLevel('INFO');
expect(logger.getLogLevel()).toBe('INFO');
expect(logger.getEnabledLogLevels()).toStrictEqual(['INFO', 'WARN', 'ERROR', 'FATAL']);
});

it('should set and get log level DEBUG', () => {
logger.setLogLevel('DEBUG');
expect(logger.getLogLevel()).toBe('DEBUG');
expect(logger.getEnabledLogLevels()).toStrictEqual([
'DEBUG',
'INFO',
'WARN',
'ERROR',
'FATAL',
]);
});
});

describe('Log Filtering', () => {
it('should log messages at or above current level', () => {
logger.setLogLevel('WARN');

logger.debug('Debug message');
logger.warn('Warning message');

expect(gDebug).not.toHaveBeenCalled();
expect(gWarn).toHaveBeenCalled();
});

it('should not log when level is OFF', () => {
logger.setLogLevel('OFF');

logger.error('Error message');
logger.fatal('Fatal message');

expect(gError).not.toHaveBeenCalled();
expect(gError).not.toHaveBeenCalled();
});
});

describe('Log Methods', () => {
it('should format messages correctly', () => {
logger.info('Test message', { key: 'value' });

const expectedMessage = `[2024-01-01T00:00:00.000Z] INFO: Test message\n${JSON.stringify({ key: 'value' }, null, 2)}`;
expect(gInfo).toHaveBeenCalledWith(expectedMessage);
});

it('should use appropriate console methods', () => {
logger.setLogLevel('DEBUG');
logger.debug('Debug');
logger.info('Info');
logger.warn('Warn');
logger.error('Error');
logger.fatal('Fatal');

expect(gDebug).toHaveBeenCalled();
expect(gInfo).toHaveBeenCalled();
expect(gWarn).toHaveBeenCalled();
expect(gError).toHaveBeenCalledTimes(2);
});
});

describe('Edge Cases', () => {
it('should handle empty data', () => {
logger.info('Message without data');
const expectedMessage = '[2024-01-01T00:00:00.000Z] INFO: Message without data';
expect(gInfo).toHaveBeenCalledWith(expectedMessage);
});

it('should handle circular data structures', () => {
logger.setLogLevel('DEBUG');
const circularObj: any = { a: 'test' };
circularObj.myself = circularObj;

logger.error('Circular error', circularObj);

// Should handle circular references in stringification
expect(gError).toHaveBeenCalled();
});
});
});
2 changes: 1 addition & 1 deletion __tests__/utils/stark.browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import { TextEncoder } from 'util';

import * as constants from '../../src/constants';
import * as constants from '../../src/global/constants';
import * as json from '../../src/utils/json';

const { IS_BROWSER } = constants;
Expand Down
2 changes: 1 addition & 1 deletion __tests__/utils/starknetId.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StarknetChainId } from '../../src/constants';
import { StarknetChainId } from '../../src/global/constants';
import { getStarknetIdContract, useDecoded, useEncoded } from '../../src/utils/starknetId';

function randomWithSeed(seed: number) {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/utils/typedData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
type ArraySignatureType,
type Signature,
} from '../../src';
import { PRIME } from '../../src/constants';
import { PRIME } from '../../src/global/constants';
import { getSelectorFromName } from '../../src/utils/hash';
import { MerkleTree } from '../../src/utils/merkle';
import {
Expand Down
9 changes: 3 additions & 6 deletions src/global/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DEFAULT_GLOBAL_CONFIG } from './constants';

type ConfigData = {
legacyMode: boolean;
logLevel: string;
[key: string]: any;
};

Expand All @@ -14,10 +14,7 @@ class Configuration {
}

private initialize(): void {
this.config = {
legacyMode: false,
logLevel: 'INFO',
};
this.config = { ...DEFAULT_GLOBAL_CONFIG };
}

public static getInstance(): Configuration {
Expand Down
7 changes: 7 additions & 0 deletions src/global/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ETransactionVersion } from '../types/api';
import { type LogLevel } from './logger.type';

export { IS_BROWSER } from '../utils/encode';

Expand Down Expand Up @@ -88,3 +89,9 @@ export const SNIP9_V2_INTERFACE_ID =
export const HARDENING_BYTE = 128;
// 0x80000000
export const HARDENING_4BYTES = 2147483648n;

// Default initial global config
export const DEFAULT_GLOBAL_CONFIG: { legacyMode: boolean; logLevel: LogLevel } = {
legacyMode: false,
logLevel: 'INFO',
};
Loading

0 comments on commit 88e62cc

Please sign in to comment.