import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import test from 'node:test'; import { format } from '../src/format/index.js'; import { messages } from './fixtures.js'; // Validates with the Python mail parser (the same kind of strict parser MUAs use). function parseMbox(text) { const py = ` import sys, json, mailbox, email.policy, tempfile, os f = tempfile.NamedTemporaryFile('w', delete=False, suffix='.mbox'); f.write(sys.stdin.read()); f.close() out = [] for m in mailbox.mbox(f.name, factory=lambda fp: email.message_from_binary_file(fp, policy=email.policy.default)): body = m.get_body(('plain',)) atts = [(a.get_filename(), a.get_content_type(), len(a.get_content())) for a in m.iter_attachments()] out.append({k: str(m[k]) for k in ('From','To','Reply-To','Subject','Message-ID','In-Reply-To','X-WA-Id','X-WA-Chat-Name')} | {'body': body.get_content(), 'atts': atts, 'defects': [str(d) for d in m.defects]}) os.unlink(f.name) print(json.dumps(out))`; return JSON.parse(execFileSync('python3', ['-c', py], { input: text, encoding: 'utf8' })); } test('mbox: headers, QP body, attachments and threads', () => { const parsed = parseMbox(format(messages, 'mbox') + '\n'); assert.equal(parsed.length, 3); const [a, b, c] = parsed; assert.equal(a.From, 'Juan Pérez <5491122334455@c.us>'); assert.equal(a['Message-ID'], '<3EB0AAA1@wa>'); assert.equal(a.body.trimEnd(), messages[0].body); // QP round trip, including the "From " line assert.match(a.Subject, /^Hola! ¿venís mañana\? 🎉$/); assert.deepEqual(a.defects, []); assert.equal(b['In-Reply-To'], '<3EB0AAA1@wa>'); assert.equal(b.To, 'Juan Pérez <5491122334455@c.us>'); assert.deepEqual(b.atts, [['captura año.png', 'image/png', 70]]); assert.equal(b.body.trimEnd(), 'la foto'); assert.equal(c['Reply-To'], 'Familia <120363000000@g.us>'); assert.equal(c.From, '5491133334444@c.us'); assert.match(c.body, /attachment not downloaded: application\/pdf, 20 KB/); assert.equal(c['X-WA-Id'], messages[2].id); }); test('eml: a single message; with several it asks for mbox', () => { assert.match(format(messages[0], 'eml'), /^From: =\?UTF-8\?B\?/); assert.throws(() => format(messages, 'eml'), /use --format mbox/); assert.throws(() => format([{ id: 1 }], 'mbox'), /only apply to messages/); }); test('table / csv / yaml / text', () => { process.stdout.columns = 80; const t = format(messages, 'table', { columns: ['date', 'senderName', 'body'] }); assert.ok(t.split('\n').every((l) => l.length <= 80), t); assert.match(t.split('\n')[0], /^DATE\s+SENDERNAME\s+BODY$/); const csv = format([{ a: 'x,y', b: 'di "hola"', c: { d: 1 } }], 'csv', { columns: ['a', 'b', 'c.d'] }); assert.equal(csv, 'a,b,c.d\n"x,y","di ""hola""",1'); assert.equal(format({ a: 'yes', b: [1, { c: 'x: y' }], e: {} }, 'yaml'), 'a: "yes"\nb:\n - 1\n - c: "x: y"\ne: {}'); const txt = format(messages, 'text'); assert.match(txt, /\] Juan Pérez: Hola!/); assert.match(txt, /\] me: ↩ \[image captura año.png\] la foto/); assert.match(txt, /\] 5491133334444@c.us: \[document boleta.pdf\]/); assert.equal(format({ x: 1 }, 'ndjson'), '{"x":1}'); });