const test = require('node:test'); const assert = require('node:assert/strict'); const { DEFAULT_LUCKMAIL_BASE_URL, DEFAULT_LUCKMAIL_EMAIL_TYPE, DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, buildLuckmailBaselineCursor, buildLuckmailMailCursor, extractLuckmailVerificationCode, filterReusableLuckmailPurchases, isLuckmailMailNewerThanCursor, isLuckmailPurchaseForProject, normalizeLuckmailBaseUrl, normalizeLuckmailEmailType, normalizeLuckmailProjectName, normalizeLuckmailPurchaseListPage, normalizeLuckmailTags, normalizeLuckmailUsedPurchases, normalizeTimestamp, normalizeLuckmailTokenCode, normalizeLuckmailTokenMail, pickReusableLuckmailPurchase, pickLuckmailVerificationMail, } = require('../luckmail-utils.js'); test('normalizeLuckmailEmailType keeps supported values and falls back to ms_graph', () => { assert.equal(normalizeLuckmailEmailType('self_built'), 'self_built'); assert.equal(normalizeLuckmailEmailType('ms_imap'), 'ms_imap'); assert.equal(normalizeLuckmailEmailType('ms_graph'), 'ms_graph'); assert.equal(normalizeLuckmailEmailType('google_variant'), 'google_variant'); assert.equal(normalizeLuckmailEmailType(''), DEFAULT_LUCKMAIL_EMAIL_TYPE); assert.equal(normalizeLuckmailEmailType('unknown'), DEFAULT_LUCKMAIL_EMAIL_TYPE); }); test('normalizeLuckmailBaseUrl trims invalid input to default base url', () => { assert.equal(normalizeLuckmailBaseUrl(''), DEFAULT_LUCKMAIL_BASE_URL); assert.equal(normalizeLuckmailBaseUrl('https://mails.luckyous.com/'), DEFAULT_LUCKMAIL_BASE_URL); assert.equal(normalizeLuckmailBaseUrl('https://demo.example.com/api/'), 'https://demo.example.com/api'); assert.equal(normalizeLuckmailBaseUrl('notaurl'), DEFAULT_LUCKMAIL_BASE_URL); }); test('normalizeLuckmailTokenCode and normalizeLuckmailTokenMail extract verification code', () => { const tokenCode = normalizeLuckmailTokenCode({ email_address: 'demo@outlook.com', project: 'openai', has_new_mail: true, verification_code: '123456', mail: { message_id: 'mail-1', from: 'noreply@openai.com', subject: 'Your ChatGPT code is 123456', received_at: '2026-04-14T10:00:00Z', }, }); assert.equal(tokenCode.verification_code, '123456'); assert.equal(tokenCode.mail.message_id, 'mail-1'); assert.equal(tokenCode.mail.verification_code, '123456'); const normalizedMail = normalizeLuckmailTokenMail({ message_id: 'mail-2', from: 'noreply@openai.com', subject: 'OpenAI security message', body: 'Your verification code is 654321.', received_at: '2026-04-14T10:01:00Z', }); assert.equal(normalizedMail.verification_code, '654321'); assert.equal(extractLuckmailVerificationCode('你的验证码为 778899'), '778899'); assert.equal( extractLuckmailVerificationCode('ChatGPT Log-in Code\nIf that was you, enter this code:\n\n982219'), '982219' ); const suspiciousLoginMail = normalizeLuckmailTokenMail({ message_id: 'mail-3', from: 'noreply@openai.com', subject: 'ChatGPT Log-in Code', body: 'We noticed a suspicious log-in on your account. If that was you, enter this code:\n\n982219', received_at: '2026-04-14T10:02:00Z', }); assert.equal(suspiciousLoginMail.verification_code, '982219'); }); test('normalizeLuckmailProjectName and isLuckmailPurchaseForProject match openai case-insensitively', () => { assert.equal(normalizeLuckmailProjectName(' OpenAi '), 'openai'); assert.equal(isLuckmailPurchaseForProject({ id: 1, email_address: 'demo@outlook.com', token: 'tok-1', project_name: 'OpenAi', }, 'openai'), true); assert.equal(isLuckmailPurchaseForProject({ id: 2, email_address: 'other@example.com', token: 'tok-2', project: 'OtherProject', }, 'openai'), false); }); test('normalizeLuckmailPurchaseListPage and normalizeLuckmailTags normalize list payloads', () => { const page = normalizeLuckmailPurchaseListPage({ list: [{ id: 3, email_address: 'demo@outlook.com', token: 'tok-3', project_name: 'OpenAi', }], total: 4, page: 2, page_size: 1, }); assert.equal(page.total, 4); assert.equal(page.page, 2); assert.equal(page.page_size, 1); assert.equal(page.list[0].project_code, 'openai'); const tags = normalizeLuckmailTags([{ id: 9, name: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, limit_type: 0, }]); assert.deepEqual(tags[0], { id: 9, name: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, remark: '', limit_type: 0, purchase_count: 0, created_at: null, }); }); test('normalizeLuckmailUsedPurchases keeps positive numeric keys only', () => { assert.deepEqual(normalizeLuckmailUsedPurchases({ 1: true, foo: true, '-2': true, 3: false, }), { 1: true, 3: false, }); }); test('pickReusableLuckmailPurchase only returns reusable openai purchase', () => { const purchases = [{ id: 10, email_address: 'used@outlook.com', token: 'tok-used', project_name: 'openai', }, { id: 11, email_address: 'preserved@outlook.com', token: 'tok-preserved', project_name: 'OpenAi', tag_name: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, }, { id: 12, email_address: 'disabled@outlook.com', token: 'tok-disabled', project_name: 'openai', user_disabled: 1, }, { id: 13, email_address: 'expired@outlook.com', token: 'tok-expired', project_name: 'openai', warranty_until: '2026-04-14T09:00:00Z', }, { id: 14, email_address: 'other@example.com', token: 'tok-other', project_name: 'other', }, { id: 15, email_address: 'ready@outlook.com', token: 'tok-ready', project_name: 'OpenAi', warranty_until: '2026-04-15T09:00:00Z', }]; const reusable = filterReusableLuckmailPurchases(purchases, { projectCode: 'openai', usedPurchases: { 10: true }, preserveTagName: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, now: Date.parse('2026-04-14T10:00:00Z'), }); assert.deepEqual(reusable.map((purchase) => purchase.id), [15]); assert.equal(pickReusableLuckmailPurchase(purchases, { projectCode: 'openai', usedPurchases: { 10: true }, preserveTagName: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME, now: Date.parse('2026-04-14T10:00:00Z'), }).id, 15); }); test('pickLuckmailVerificationMail respects sender filters, time filters, and excluded codes', () => { const match = pickLuckmailVerificationMail([ { message_id: 'old-mail', from: 'noreply@openai.com', subject: 'Your code is 111111', received_at: '2026-04-14T09:59:00Z', }, { message_id: 'new-mail', from: 'noreply@openai.com', subject: 'Your code is 222222', received_at: '2026-04-14T10:05:00Z', }, ], { senderFilters: ['openai'], subjectFilters: ['code'], excludeCodes: ['111111'], afterTimestamp: Date.parse('2026-04-14T10:00:00Z'), }); assert.equal(match.code, '222222'); assert.equal(match.mail.message_id, 'new-mail'); }); test('isLuckmailMailNewerThanCursor compares message id and timestamp safely', () => { const cursor = buildLuckmailMailCursor({ message_id: 'mail-1', received_at: '2026-04-14T10:00:00Z', }); assert.equal(isLuckmailMailNewerThanCursor({ message_id: 'mail-1', received_at: '2026-04-14T10:00:00Z', }, cursor), false); assert.equal(isLuckmailMailNewerThanCursor({ message_id: 'mail-2', received_at: '2026-04-14T10:01:00Z', }, cursor), true); }); test('normalizeLuckmailMailCursor tolerates null cursor input', () => { const { normalizeLuckmailMailCursor } = require('../luckmail-utils.js'); assert.deepEqual(normalizeLuckmailMailCursor(null), { messageId: '', receivedAt: '', }); }); test('normalizeTimestamp treats LuckMail naive datetime strings as UTC', () => { assert.equal( normalizeTimestamp('2026-04-14 13:32:05'), Date.UTC(2026, 3, 14, 13, 32, 5, 0) ); }); test('buildLuckmailBaselineCursor tracks newest existing mail as baseline', () => { const cursor = buildLuckmailBaselineCursor([ { message_id: 'mail-old', received_at: '2026-04-14 13:31:15', subject: '你的 ChatGPT 代码为 111111', }, { message_id: 'mail-new', received_at: '2026-04-14 13:32:05', subject: '你的 ChatGPT 代码为 222222', }, ]); assert.deepEqual(cursor, { messageId: 'mail-new', receivedAt: '2026-04-14 13:32:05', }); });