import test from 'node:test'; import assert from 'node:assert/strict'; import { DatabaseSync } from 'node:sqlite'; import { canonicalKeySql, canonicalPhoneKey, canonicalPhoneVariants, canonicalVariantSql, equivalentPhoneNumbers, equivalentSql, normalizePhone, normalizedSql } from '../src/phone.mjs'; // A regra 8/9 digitos existe duas vezes: em JS (equivalentPhoneNumbers / // canonicalPhoneKey, usadas pelo envio manual e pela revalidacao de ultima // milha) e em SQL (equivalentSql / canonicalKeySql, usadas pela selecao de // candidatos da campanha e pela listagem de tratamento). Se alguem editar uma // sem a outra, o bloqueio automatico e o manual passam a discordar em silencio. // Estes testes rodam o mesmo conjunto de numeros pelos dois caminhos. const NUMBERS = [ '5575999091780', // celular BR de 13 digitos com nono digito '557599091780', // mesma linha em 8 digitos (local comeca com 9) '5571993335451', // outro celular de 13 digitos '557193335451', // fixo/8 digitos que comeca com 9 -> tem par '557133334444', // fixo de 12 digitos, local comeca com 3 (sem par direto) '5575933334444', // par assimetrico do numero abaixo '557533334444', // 12 digitos, local '33334444' fora da faixa 6-9 '551140028922', // 12 digitos, local comeca com 4 '557561234567', // 12 digitos, local comeca com 6 (limite inferior da faixa) '557551234567', // 12 digitos, local comeca com 5 (logo abaixo da faixa) '557591234567', // 12 digitos, local comeca com 9 (limite superior da faixa) '5511987654321', // 13 digitos comum '11987654321', // sem DDI 55 '5575', // curto demais '' // vazio ]; function sqlDb() { const db = new DatabaseSync(':memory:'); db.exec('CREATE TABLE amostra (bruto TEXT)'); return db; } function sqlValues(db, numero) { db.prepare('DELETE FROM amostra').run(); db.prepare('INSERT INTO amostra (bruto) VALUES (?)').run(numero); return db.prepare( `SELECT ${normalizedSql('bruto')} AS normalizado, ${equivalentSql('bruto')} AS equivalente, ${canonicalKeySql('bruto')} AS canonico, ${canonicalVariantSql('bruto')} AS variante FROM amostra` ).get(); } test('normalizedSql concorda com normalizePhone', () => { const db = sqlDb(); for (const numero of [...NUMBERS, '+55 (75) 99909-1780', '55 71 9333-5451']) { assert.equal(sqlValues(db, numero).normalizado, normalizePhone(numero), numero); } db.close(); }); test('equivalentSql concorda com equivalentPhoneNumbers em todas as amostras', () => { const db = sqlDb(); for (const numero of NUMBERS) { const equivalentes = equivalentPhoneNumbers(numero); // equivalentPhoneNumbers devolve [proprio, alternativo?]; equivalentSql // devolve apenas o "outro lado" (ou o proprio quando nao ha alternativa). const esperado = equivalentes.length > 1 ? equivalentes[1] : normalizePhone(numero); assert.equal(sqlValues(db, numero).equivalente, esperado, numero); } db.close(); }); test('canonicalKeySql concorda com canonicalPhoneKey em todas as amostras', () => { const db = sqlDb(); for (const numero of NUMBERS) { assert.equal(sqlValues(db, numero).canonico, canonicalPhoneKey(numero), numero); } db.close(); }); test('canonicalKeySql + canonicalVariantSql cobrem o mesmo conjunto de canonicalPhoneVariants', () => { const db = sqlDb(); for (const numero of NUMBERS) { const { canonico, variante } = sqlValues(db, numero); const sqlSet = [...new Set([canonico, variante].filter(Boolean))].sort(); const jsSet = [...new Set(canonicalPhoneVariants(numero))].sort(); assert.deepEqual(sqlSet, jsSet, numero); } db.close(); }); test('a chave canonica e simetrica onde equivalentPhoneNumbers nao e', () => { // Caso concreto: A tem 12 digitos com local fora da faixa 6-9, B tem 13. assert.deepEqual(equivalentPhoneNumbers('557533334444'), ['557533334444']); assert.deepEqual(equivalentPhoneNumbers('5575933334444'), ['5575933334444', '557533334444']); assert.equal(canonicalPhoneKey('557533334444'), '557533334444'); assert.equal(canonicalPhoneKey('5575933334444'), '557533334444'); // E os pares 8/9 digitos ja cobertos pela suite continuam batendo entre si. assert.equal(canonicalPhoneKey('5575999091780'), canonicalPhoneKey('557599091780')); assert.equal(canonicalPhoneKey('5571993335451'), canonicalPhoneKey('557193335451')); // Simetria total do conjunto de casamento nas amostras brasileiras. for (const numero of NUMBERS) { for (const outro of canonicalPhoneVariants(numero)) { assert.ok( canonicalPhoneVariants(outro).includes(normalizePhone(numero)), `${numero} <-> ${outro}` ); } } // Numeros de linhas diferentes nao podem colidir. assert.notEqual(canonicalPhoneKey('557533334444'), canonicalPhoneKey('557133334444')); assert.notEqual(canonicalPhoneKey('5511987654321'), canonicalPhoneKey('551140028922')); });