Skip to content

Instantly share code, notes, and snippets.

@BnayaZil
Created June 12, 2025 06:02
Show Gist options
  • Save BnayaZil/fadb639a2750b0875872f772b9fd0a95 to your computer and use it in GitHub Desktop.
Save BnayaZil/fadb639a2750b0875872f772b9fd0a95 to your computer and use it in GitHub Desktop.
Verify arrays order
/**
* Comprehensive Email Array Sorting and JSON.stringify Order Verification
* This program generates various email arrays, applies different sorting algorithms,
* and verifies that JSON.stringify preserves the array order consistently.
*/
class EmailSortingTester {
constructor() {
this.testResults = [];
this.emailSamples = this.generateEmailSamples();
}
// Generate diverse email samples for testing
generateEmailSamples() {
const domains = ['gmail.com', 'yahoo.com', 'outlook.com', 'company.com', 'test.org'];
const names = ['john', 'jane', 'bob', 'alice', 'charlie', 'diana', 'eve', 'frank'];
const prefixes = ['user', 'admin', 'test', 'demo', 'info'];
const numbers = ['', '1', '2', '123', '999'];
const specialChars = ['', '.', '_', '-'];
let emails = [];
// Generate basic combinations
for (let name of names) {
for (let domain of domains) {
emails.push(`${name}@${domain}`);
}
}
// Generate emails with numbers
for (let prefix of prefixes) {
for (let num of numbers) {
for (let domain of domains.slice(0, 2)) {
emails.push(`${prefix}${num}@${domain}`);
}
}
}
// Generate emails with special characters
for (let name of names.slice(0, 3)) {
for (let char of specialChars) {
for (let domain of domains.slice(0, 2)) {
if (char) {
emails.push(`${name}${char}test@${domain}`);
}
}
}
}
// Add some edge cases
emails.push(
'[email protected]',
'very-long-email-address-for-testing@very-long-domain-name-example.com',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]'
);
return [...new Set(emails)]; // Remove duplicates
}
// Helper method to compare arrays element by element
arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
// Core verification method - NOW WITH FULL ORDER VERIFICATION
verifyJsonStringifyOrder(sortedEmails, testName) {
const iterations = 100;
let stringifyConsistent = true;
let orderPreserved = true;
let firstStringification = null;
const timings = [];
const orderViolations = [];
console.log(`\n=== ${testName} ===`);
console.log(`Testing ${sortedEmails.length} emails with ${iterations} iterations`);
for (let i = 0; i < iterations; i++) {
const start = performance.now();
// Step 1: Stringify the array
const jsonString = JSON.stringify(sortedEmails);
// Step 2: Parse it back to array
const parsedArray = JSON.parse(jsonString);
const end = performance.now();
timings.push(end - start);
// Verify stringify consistency
if (i === 0) {
firstStringification = jsonString;
} else if (jsonString !== firstStringification) {
stringifyConsistent = false;
console.error(`❌ JSON.stringify inconsistency detected at iteration ${i + 1}`);
}
// Verify array order preservation
if (!this.arraysEqual(sortedEmails, parsedArray)) {
orderPreserved = false;
orderViolations.push({
iteration: i + 1,
originalLength: sortedEmails.length,
parsedLength: parsedArray.length,
firstDifference: this.findFirstDifference(sortedEmails, parsedArray)
});
console.error(`❌ Array order violation at iteration ${i + 1}`);
console.error(` Original[0-4]: ${sortedEmails.slice(0, 5).join(', ')}`);
console.error(` Parsed[0-4]: ${parsedArray.slice(0, 5).join(', ')}`);
// Only show first few violations to avoid spam
if (orderViolations.length >= 5) {
console.error(` ... stopping after 5 order violations`);
break;
}
}
// Additional deep verification every 10 iterations
if (i % 10 === 0) {
this.performDeepVerification(sortedEmails, parsedArray, i);
}
}
const avgTime = timings.reduce((a, b) => a + b, 0) / timings.length;
const minTime = Math.min(...timings);
const maxTime = Math.max(...timings);
const result = {
testName,
arrayLength: sortedEmails.length,
stringifyConsistent,
orderPreserved,
overallSuccess: stringifyConsistent && orderPreserved,
iterations: timings.length,
orderViolations: orderViolations.length,
avgTime: avgTime.toFixed(3),
minTime: minTime.toFixed(3),
maxTime: maxTime.toFixed(3),
firstFiveEmails: sortedEmails.slice(0, 5),
lastFiveEmails: sortedEmails.slice(-5),
violations: orderViolations.slice(0, 3) // Keep first 3 violations for analysis
};
// Enhanced reporting
if (result.overallSuccess) {
console.log(`βœ… ${testName}: PASSED`);
console.log(` βœ“ JSON.stringify output consistent across ${timings.length} iterations`);
console.log(` βœ“ Array order preserved through stringify/parse cycle`);
} else {
console.log(`❌ ${testName}: FAILED`);
if (!stringifyConsistent) {
console.log(` βœ— JSON.stringify output inconsistent`);
}
if (!orderPreserved) {
console.log(` βœ— Array order not preserved (${orderViolations.length} violations)`);
}
}
console.log(` Performance: ${avgTime.toFixed(3)}ms avg (min: ${minTime.toFixed(3)}ms, max: ${maxTime.toFixed(3)}ms)`);
console.log(` Sample data: [${result.firstFiveEmails.join(', ')}] ... [${result.lastFiveEmails.join(', ')}]`);
return result;
}
// Find first difference between two arrays
findFirstDifference(arr1, arr2) {
const minLength = Math.min(arr1.length, arr2.length);
for (let i = 0; i < minLength; i++) {
if (arr1[i] !== arr2[i]) {
return {
index: i,
original: arr1[i],
parsed: arr2[i]
};
}
}
if (arr1.length !== arr2.length) {
return {
index: minLength,
original: arr1[minLength] || 'undefined (array shorter)',
parsed: arr2[minLength] || 'undefined (array shorter)',
lengthDifference: arr1.length - arr2.length
};
}
return null; // No difference found
}
// Perform additional verification checks
performDeepVerification(original, parsed, iteration) {
// Check if arrays are exactly the same reference (should not be)
if (original === parsed) {
console.warn(`⚠️ Iteration ${iteration}: Parsed array is same reference as original (unexpected)`);
}
// Check data types of all elements
for (let i = 0; i < Math.min(original.length, parsed.length); i++) {
if (typeof original[i] !== typeof parsed[i]) {
console.error(`❌ Type mismatch at index ${i}: ${typeof original[i]} vs ${typeof parsed[i]}`);
}
}
// Check for any undefined or null values
const originalNulls = original.filter(x => x == null).length;
const parsedNulls = parsed.filter(x => x == null).length;
if (originalNulls !== parsedNulls) {
console.error(`❌ Null/undefined count mismatch: ${originalNulls} vs ${parsedNulls}`);
}
// Verify using Set for unordered comparison (should have same elements)
const originalSet = new Set(original);
const parsedSet = new Set(parsed);
if (originalSet.size !== parsedSet.size ||
![...originalSet].every(x => parsedSet.has(x))) {
console.error(`❌ Sets don't match - elements were added/removed during stringify/parse`);
}
}
// Enhanced verification with multiple JSON methods
verifyJsonStringifyOrderEnhanced(sortedEmails, testName) {
console.log(`\n=== ENHANCED: ${testName} ===`);
const methods = [
{
name: 'JSON.stringify default',
stringify: (arr) => JSON.stringify(arr),
parse: (str) => JSON.parse(str)
},
{
name: 'JSON.stringify with replacer',
stringify: (arr) => JSON.stringify(arr, null, 0),
parse: (str) => JSON.parse(str)
},
{
name: 'JSON.stringify with spaces',
stringify: (arr) => JSON.stringify(arr, null, 2),
parse: (str) => JSON.parse(str)
},
{
name: 'JSON.stringify with custom replacer',
stringify: (arr) => JSON.stringify(arr, (key, value) => value),
parse: (str) => JSON.parse(str)
}
];
const results = [];
for (const method of methods) {
console.log(`\n--- Testing: ${method.name} ---`);
let orderPreserved = true;
let errorCount = 0;
for (let i = 0; i < 20; i++) {
try {
const jsonString = method.stringify(sortedEmails);
const parsedArray = method.parse(jsonString);
if (!this.arraysEqual(sortedEmails, parsedArray)) {
orderPreserved = false;
errorCount++;
if (errorCount === 1) {
console.error(`❌ First failure in ${method.name}:`);
console.error(` Expected: ${sortedEmails.slice(0, 3).join(', ')}...`);
console.error(` Got: ${parsedArray.slice(0, 3).join(', ')}...`);
}
}
} catch (error) {
console.error(`❌ Error in ${method.name}:`, error.message);
orderPreserved = false;
errorCount++;
}
}
const result = {
method: method.name,
orderPreserved,
errorCount,
totalTests: 20
};
results.push(result);
if (orderPreserved) {
console.log(`βœ… ${method.name}: Order preserved in all tests`);
} else {
console.log(`❌ ${method.name}: ${errorCount}/20 tests failed`);
}
}
return results;
}
// Test 1: Lexicographic sorting with enhanced verification
testLexicographicSorting(emails) {
const sorted = [...emails].sort();
const basicResult = this.verifyJsonStringifyOrder(sorted, 'Lexicographic Sort');
const enhancedResults = this.verifyJsonStringifyOrderEnhanced(sorted, 'Lexicographic Sort');
return {
...basicResult,
enhancedResults
};
}
// Test 2: Reverse lexicographic sorting
testReverseLexicographicSorting(emails) {
const sorted = [...emails].sort().reverse();
return this.verifyJsonStringifyOrder(sorted, 'Reverse Lexicographic Sort');
}
// Test 3: Sort by email length
testLengthSorting(emails) {
const sorted = [...emails].sort((a, b) => a.length - b.length);
return this.verifyJsonStringifyOrder(sorted, 'Length Sort (Ascending)');
}
// Test 4: Sort by domain
testDomainSorting(emails) {
const sorted = [...emails].sort((a, b) => {
const domainA = a.split('@')[1];
const domainB = b.split('@')[1];
return domainA.localeCompare(domainB);
});
return this.verifyJsonStringifyOrder(sorted, 'Domain Sort');
}
// Test 5: Sort by local part (username)
testLocalPartSorting(emails) {
const sorted = [...emails].sort((a, b) => {
const localA = a.split('@')[0];
const localB = b.split('@')[0];
return localA.localeCompare(localB);
});
return this.verifyJsonStringifyOrder(sorted, 'Local Part Sort');
}
// Test 6: Random shuffle
testRandomSorting(emails) {
const shuffled = [...emails].sort(() => Math.random() - 0.5);
return this.verifyJsonStringifyOrder(shuffled, 'Random Shuffle');
}
// Test 7: Custom complex sorting
testComplexSorting(emails) {
const sorted = [...emails].sort((a, b) => {
// Sort by domain first, then by local part length, then lexicographically
const [localA, domainA] = a.split('@');
const [localB, domainB] = b.split('@');
if (domainA !== domainB) {
return domainA.localeCompare(domainB);
}
if (localA.length !== localB.length) {
return localA.length - localB.length;
}
return localA.localeCompare(localB);
});
return this.verifyJsonStringifyOrder(sorted, 'Complex Multi-criteria Sort');
}
// Test with edge cases that might break JSON order preservation
testEdgeCases() {
console.log('\nπŸ§ͺ TESTING EDGE CASES πŸ§ͺ');
// Test 1: Arrays with special email formats
const specialEmails = [
'[email protected]',
'"quoted.user"@domain.com',
'[email protected]',
'user@[192.168.1.1]',
'very.long.email.address.that.might.cause.issues@very.long.domain.name.that.could.break.things.com',
'[email protected]',
'user@domain'
];
this.verifyJsonStringifyOrder(specialEmails.sort(), 'Special Email Formats');
// Test 2: Mixed case scenarios
const mixedCaseEmails = [
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]'
];
this.verifyJsonStringifyOrder(mixedCaseEmails.sort(), 'Mixed Case Emails');
// Test 3: Emails with numbers in different positions
const numberEmails = [
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]'
];
this.verifyJsonStringifyOrder(numberEmails.sort(), 'Number Position Variance');
// Test 4: Duplicate emails (exact same strings)
const duplicates = [
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]'
];
this.verifyJsonStringifyOrder(duplicates.sort(), 'Duplicate Email Entries');
// Test 5: Arrays with very similar emails
const similarEmails = [
'[email protected]',
'[email protected]',
'[email protected]',
'user@domain.',
'user@domain',
'user@domai',
'user@doma',
'user@dom',
'user@do',
'user@d',
'user@'
];
this.verifyJsonStringifyOrder(similarEmails.sort(), 'Very Similar Emails');
}
// Test 8-15: All previous sorting algorithms with new verification
testBubbleSort(emails) {
const arr = [...emails];
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return this.verifyJsonStringifyOrder(arr, 'Bubble Sort');
}
testQuickSort(emails) {
const quickSort = (arr) => {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = arr.filter(x => x < pivot);
const middle = arr.filter(x => x === pivot);
const right = arr.filter(x => x > pivot);
return [...quickSort(left), ...middle, ...quickSort(right)];
};
const sorted = quickSort([...emails]);
return this.verifyJsonStringifyOrder(sorted, 'Quick Sort');
}
testMergeSort(emails) {
const mergeSort = (arr) => {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
const merge = (left, right) => {
const result = [];
let leftIndex = 0, rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] <= right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
};
return merge(left, right);
};
const sorted = mergeSort([...emails]);
return this.verifyJsonStringifyOrder(sorted, 'Merge Sort');
}
testHeapSort(emails) {
const heapSort = (arr) => {
const array = [...arr];
const heapify = (arr, length, i) => {
let largest = i;
const left = i * 2 + 1;
const right = left + 1;
if (left < length && arr[left] > arr[largest]) {
largest = left;
}
if (right < length && arr[right] > arr[largest]) {
largest = right;
}
if (largest !== i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
heapify(arr, length, largest);
}
return arr;
};
// Build heap
for (let i = Math.floor(array.length / 2 - 1); i >= 0; i--) {
heapify(array, array.length, i);
}
// Extract elements from heap
for (let i = array.length - 1; i >= 0; i--) {
[array[0], array[i]] = [array[i], array[0]];
heapify(array, i, 0);
}
return array;
};
const sorted = heapSort([...emails]);
return this.verifyJsonStringifyOrder(sorted, 'Heap Sort');
}
testLocaleSort(emails) {
const sorted = [...emails].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
return this.verifyJsonStringifyOrder(sorted, 'Locale-aware Sort');
}
testCaseInsensitiveSort(emails) {
const sorted = [...emails].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
return this.verifyJsonStringifyOrder(sorted, 'Case-insensitive Sort');
}
testInsertionSort(emails) {
const arr = [...emails];
for (let i = 1; i < arr.length; i++) {
const key = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
return this.verifyJsonStringifyOrder(arr, 'Insertion Sort');
}
testSelectionSort(emails) {
const arr = [...emails];
for (let i = 0; i < arr.length - 1; i++) {
let minIdx = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
[arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
}
return this.verifyJsonStringifyOrder(arr, 'Selection Sort');
}
// Additional stress tests
runStressTests() {
console.log('\nπŸ”₯ RUNNING STRESS TESTS πŸ”₯');
// Test with very large arrays
const largeEmailSet = [];
for (let i = 0; i < 10000; i++) {
largeEmailSet.push(`user${i}@domain${i % 100}.com`);
}
console.log('\n--- Large Array Test (10,000 emails) ---');
this.verifyJsonStringifyOrder(largeEmailSet.sort(), 'Large Array Stress Test');
// Test with duplicates
const duplicateEmails = [];
for (let i = 0; i < 1000; i++) {
duplicateEmails.push('[email protected]');
}
console.log('\n--- Duplicate Emails Test ---');
this.verifyJsonStringifyOrder(duplicateEmails, 'Duplicate Emails Test');
// Test with special characters
const specialEmails = [
'test@тСст.com',
'user@mΓΌnchen.de',
'test@δΈ­ζ–‡.com',
'quotes@"test".com',
'slashes@test\\.com'
].filter(email => {
try {
JSON.stringify([email]);
return true;
} catch (e) {
console.warn(`Skipping problematic email: ${email}`);
return false;
}
});
console.log('\n--- Special Characters Test ---');
this.verifyJsonStringifyOrder(specialEmails.sort(), 'Special Characters Test');
}
// Run all tests
runAllTests() {
console.log('πŸš€ Starting Comprehensive Email Sorting and JSON.stringify Order Preservation Tests');
console.log('πŸ“‹ This test suite verifies that JSON.stringify β†’ JSON.parse preserves exact array order');
console.log(`πŸ“§ Generated ${this.emailSamples.length} unique email samples for testing\n`);
const testMethods = [
'testLexicographicSorting',
'testReverseLexicographicSorting',
'testLengthSorting',
'testDomainSorting',
'testLocalPartSorting',
'testRandomSorting',
'testComplexSorting',
'testBubbleSort',
'testQuickSort',
'testMergeSort',
'testHeapSort',
'testLocaleSort',
'testCaseInsensitiveSort',
'testInsertionSort',
'testSelectionSort'
];
// Run all sorting tests
for (const methodName of testMethods) {
try {
const result = this[methodName](this.emailSamples);
this.testResults.push(result);
} catch (error) {
console.error(`❌ Error in ${methodName}:`, error.message);
}
}
// Run edge case tests
this.testEdgeCases();
// Run stress tests
this.runStressTests();
// Generate summary
this.generateSummary();
}
generateSummary() {
console.log('\nπŸ“Š COMPREHENSIVE TEST SUMMARY πŸ“Š');
console.log('='.repeat(60));
const fullyPassed = this.testResults.filter(r => r.overallSuccess).length;
const stringifyConsistent = this.testResults.filter(r => r.stringifyConsistent).length;
const orderPreserved = this.testResults.filter(r => r.orderPreserved).length;
const total = this.testResults.length;
console.log(`Overall Success Rate: ${fullyPassed}/${total} (${((fullyPassed/total)*100).toFixed(1)}%)`);
console.log(`JSON.stringify Consistency: ${stringifyConsistent}/${total} (${((stringifyConsistent/total)*100).toFixed(1)}%)`);
console.log(`Array Order Preservation: ${orderPreserved}/${total} (${((orderPreserved/total)*100).toFixed(1)}%)`);
if (fullyPassed === total) {
console.log('\nπŸŽ‰ ALL TESTS PASSED!');
console.log('βœ… JSON.stringify maintains consistent output across all sorting methods');
console.log('βœ… Array order is perfectly preserved through stringify/parse cycle');
console.log('βœ… No data corruption or reordering detected in any scenario');
} else {
console.log('\n⚠️ Some tests revealed issues:');
if (stringifyConsistent < total) {
const failed = total - stringifyConsistent;
console.log(`❌ ${failed} tests had inconsistent JSON.stringify output`);
}
if (orderPreserved < total) {
const failed = total - orderPreserved;
console.log(`❌ ${failed} tests had array order corruption`);
// Show which tests had order issues
const orderFailures = this.testResults.filter(r => !r.orderPreserved);
console.log(' Order preservation failures:');
orderFailures.forEach(result => {
console.log(` - ${result.testName}: ${result.orderViolations} violations`);
});
}
}
console.log('\n⏱️ Performance Summary:');
const avgTimes = this.testResults.map(r => parseFloat(r.avgTime));
const fastestTest = this.testResults[avgTimes.indexOf(Math.min(...avgTimes))];
const slowestTest = this.testResults[avgTimes.indexOf(Math.max(...avgTimes))];
console.log(`⚑ Fastest: ${fastestTest.testName} (${fastestTest.avgTime}ms avg)`);
console.log(`🐌 Slowest: ${slowestTest.testName} (${slowestTest.avgTime}ms avg)`);
console.log(`πŸ“Š Average across all tests: ${(avgTimes.reduce((a,b) => a+b, 0) / avgTimes.length).toFixed(3)}ms`);
console.log('\nπŸ“‹ Detailed Results:');
this.testResults.forEach(result => {
const statusIcon = result.overallSuccess ? 'βœ…' :
(result.stringifyConsistent && result.orderPreserved) ? 'βœ…' :
(!result.stringifyConsistent && !result.orderPreserved) ? '❌❌' : '❌';
let details = '';
if (!result.stringifyConsistent) details += ' [STRINGIFY-FAIL]';
if (!result.orderPreserved) details += ` [ORDER-FAIL:${result.orderViolations}]`;
console.log(`${statusIcon} ${result.testName}: ${result.iterations} iterations, ${result.avgTime}ms avg${details}`);
});
console.log('\n🎯 Key Findings:');
console.log('- JSON.stringify output consistency indicates internal stability');
console.log('- Array order preservation through parse cycle tests data integrity');
console.log('- Performance metrics help identify optimal sorting approaches');
console.log('- Edge cases reveal potential issues with special characters/formats');
}
}
// Execute the comprehensive test suite
const tester = new EmailSortingTester();
tester.runAllTests();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment