233 lines
8.1 KiB
TypeScript
233 lines
8.1 KiB
TypeScript
|
|
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||
|
|
import * as smartmongo from '../ts/index.js';
|
||
|
|
|
||
|
|
const {
|
||
|
|
calculateCRC32,
|
||
|
|
calculateCRC32Buffer,
|
||
|
|
calculateDocumentChecksum,
|
||
|
|
addChecksum,
|
||
|
|
verifyChecksum,
|
||
|
|
removeChecksum,
|
||
|
|
} = smartmongo.tsmdb;
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// CRC32 String Tests
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should return consistent value for same input', async () => {
|
||
|
|
const result1 = calculateCRC32('hello world');
|
||
|
|
const result2 = calculateCRC32('hello world');
|
||
|
|
expect(result1).toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should return different values for different inputs', async () => {
|
||
|
|
const result1 = calculateCRC32('hello');
|
||
|
|
const result2 = calculateCRC32('world');
|
||
|
|
expect(result1).not.toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should return a 32-bit unsigned integer', async () => {
|
||
|
|
const result = calculateCRC32('test string');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
expect(result).toBeLessThanOrEqual(0xFFFFFFFF);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should handle empty string', async () => {
|
||
|
|
const result = calculateCRC32('');
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should handle special characters', async () => {
|
||
|
|
const result = calculateCRC32('hello\nworld\t!"#$%&\'()');
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32 should handle unicode characters', async () => {
|
||
|
|
const result = calculateCRC32('hello 世界 🌍');
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// CRC32 Buffer Tests
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32Buffer should return consistent value for same input', async () => {
|
||
|
|
const buffer = Buffer.from('hello world');
|
||
|
|
const result1 = calculateCRC32Buffer(buffer);
|
||
|
|
const result2 = calculateCRC32Buffer(buffer);
|
||
|
|
expect(result1).toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32Buffer should return different values for different inputs', async () => {
|
||
|
|
const buffer1 = Buffer.from('hello');
|
||
|
|
const buffer2 = Buffer.from('world');
|
||
|
|
const result1 = calculateCRC32Buffer(buffer1);
|
||
|
|
const result2 = calculateCRC32Buffer(buffer2);
|
||
|
|
expect(result1).not.toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32Buffer should handle empty buffer', async () => {
|
||
|
|
const result = calculateCRC32Buffer(Buffer.from(''));
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateCRC32Buffer should handle binary data', async () => {
|
||
|
|
const buffer = Buffer.from([0x00, 0xFF, 0x7F, 0x80, 0x01]);
|
||
|
|
const result = calculateCRC32Buffer(buffer);
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Document Checksum Tests
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
tap.test('checksum: calculateDocumentChecksum should return consistent value', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const result1 = calculateDocumentChecksum(doc);
|
||
|
|
const result2 = calculateDocumentChecksum(doc);
|
||
|
|
expect(result1).toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateDocumentChecksum should exclude _checksum field', async () => {
|
||
|
|
const doc1 = { name: 'John', age: 30 };
|
||
|
|
const doc2 = { name: 'John', age: 30, _checksum: 12345 };
|
||
|
|
const result1 = calculateDocumentChecksum(doc1);
|
||
|
|
const result2 = calculateDocumentChecksum(doc2);
|
||
|
|
expect(result1).toEqual(result2);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateDocumentChecksum should handle empty document', async () => {
|
||
|
|
const result = calculateDocumentChecksum({});
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateDocumentChecksum should handle nested objects', async () => {
|
||
|
|
const doc = {
|
||
|
|
name: 'John',
|
||
|
|
address: {
|
||
|
|
street: '123 Main St',
|
||
|
|
city: 'Springfield',
|
||
|
|
zip: {
|
||
|
|
code: '12345',
|
||
|
|
plus4: '6789',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
};
|
||
|
|
const result = calculateDocumentChecksum(doc);
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: calculateDocumentChecksum should handle arrays', async () => {
|
||
|
|
const doc = {
|
||
|
|
name: 'John',
|
||
|
|
tags: ['developer', 'tester', 'admin'],
|
||
|
|
scores: [95, 87, 92],
|
||
|
|
};
|
||
|
|
const result = calculateDocumentChecksum(doc);
|
||
|
|
expect(typeof result).toEqual('number');
|
||
|
|
expect(result).toBeGreaterThanOrEqual(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Add/Verify/Remove Checksum Tests
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
tap.test('checksum: addChecksum should add _checksum field to document', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const docWithChecksum = addChecksum(doc);
|
||
|
|
|
||
|
|
expect('_checksum' in docWithChecksum).toBeTrue();
|
||
|
|
expect(typeof docWithChecksum._checksum).toEqual('number');
|
||
|
|
expect(docWithChecksum.name).toEqual('John');
|
||
|
|
expect(docWithChecksum.age).toEqual(30);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: addChecksum should not modify the original document', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
addChecksum(doc);
|
||
|
|
expect('_checksum' in doc).toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: verifyChecksum should return true for valid checksum', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const docWithChecksum = addChecksum(doc);
|
||
|
|
const isValid = verifyChecksum(docWithChecksum);
|
||
|
|
expect(isValid).toBeTrue();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: verifyChecksum should return false for tampered document', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const docWithChecksum = addChecksum(doc);
|
||
|
|
|
||
|
|
// Tamper with the document
|
||
|
|
docWithChecksum.age = 31;
|
||
|
|
|
||
|
|
const isValid = verifyChecksum(docWithChecksum);
|
||
|
|
expect(isValid).toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: verifyChecksum should return false for wrong checksum', async () => {
|
||
|
|
const doc = { name: 'John', age: 30, _checksum: 12345 };
|
||
|
|
const isValid = verifyChecksum(doc);
|
||
|
|
expect(isValid).toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: verifyChecksum should return true for document without checksum', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const isValid = verifyChecksum(doc);
|
||
|
|
expect(isValid).toBeTrue();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: removeChecksum should remove _checksum field', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const docWithChecksum = addChecksum(doc);
|
||
|
|
const docWithoutChecksum = removeChecksum(docWithChecksum);
|
||
|
|
|
||
|
|
expect('_checksum' in docWithoutChecksum).toBeFalse();
|
||
|
|
expect(docWithoutChecksum.name).toEqual('John');
|
||
|
|
expect(docWithoutChecksum.age).toEqual(30);
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('checksum: removeChecksum should handle document without checksum', async () => {
|
||
|
|
const doc = { name: 'John', age: 30 };
|
||
|
|
const result = removeChecksum(doc);
|
||
|
|
|
||
|
|
expect('_checksum' in result).toBeFalse();
|
||
|
|
expect(result.name).toEqual('John');
|
||
|
|
expect(result.age).toEqual(30);
|
||
|
|
});
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Round-trip Tests
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
tap.test('checksum: full round-trip - add, verify, remove', async () => {
|
||
|
|
const original = { name: 'Test', value: 42, nested: { a: 1, b: 2 } };
|
||
|
|
|
||
|
|
// Add checksum
|
||
|
|
const withChecksum = addChecksum(original);
|
||
|
|
expect('_checksum' in withChecksum).toBeTrue();
|
||
|
|
|
||
|
|
// Verify checksum
|
||
|
|
expect(verifyChecksum(withChecksum)).toBeTrue();
|
||
|
|
|
||
|
|
// Remove checksum
|
||
|
|
const restored = removeChecksum(withChecksum);
|
||
|
|
expect('_checksum' in restored).toBeFalse();
|
||
|
|
|
||
|
|
// Original data should be intact
|
||
|
|
expect(restored.name).toEqual('Test');
|
||
|
|
expect(restored.value).toEqual(42);
|
||
|
|
expect(restored.nested.a).toEqual(1);
|
||
|
|
expect(restored.nested.b).toEqual(2);
|
||
|
|
});
|
||
|
|
|
||
|
|
export default tap.start();
|