OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-social / bridge-envelope / test / envelope.test.js

239 lines · javascript ref:
import test from 'brittle'
import { createEnvelope, TYPES, PLATFORMS, encode, decode, envelopeCodec } from '../index.js'
import cenc from 'compact-encoding'

test('createEnvelope - basic text message', (t) => {
  const env = createEnvelope({
    type: TYPES.TEXT,
    platform: PLATFORMS.IRC,
    author: 'testuser',
    content: 'Hello from IRC!',
    channel: '#test'
  })

  t.is(env.type, TYPES.TEXT)
  t.is(env.platform, PLATFORMS.IRC)
  t.is(env.author, 'testuser')
  t.is(env.content, 'Hello from IRC!')
  t.is(env.channel, '#test')
  t.ok(env.id, 'has content-hash id')
  t.ok(env.timestamp > 0, 'has timestamp')
})

test('createEnvelope - defaults', (t) => {
  const env = createEnvelope({ content: 'test' })

  t.is(env.type, TYPES.TEXT)
  t.is(env.platform, PLATFORMS.KEET)
  t.is(env.author, '')
  t.is(env.replyTo, '')
  t.is(env.mediaUrl, '')
  t.is(env.editOf, '')
  t.is(env.deleteOf, '')
})

test('createEnvelope - custom id', (t) => {
  const env = createEnvelope({ content: 'test', id: 'custom-123' })
  t.is(env.id, 'custom-123')
})

test('createEnvelope - content hash is deterministic', (t) => {
  const ts = Date.now()
  const a = createEnvelope({ platform: PLATFORMS.IRC, author: 'u', content: 'msg', timestamp: ts })
  const b = createEnvelope({ platform: PLATFORMS.IRC, author: 'u', content: 'msg', timestamp: ts })
  t.is(a.id, b.id)
})

test('createEnvelope - different content gives different hash', (t) => {
  const ts = Date.now()
  const a = createEnvelope({ author: 'u', content: 'msg1', timestamp: ts })
  const b = createEnvelope({ author: 'u', content: 'msg2', timestamp: ts })
  t.not(a.id, b.id)
})

test('createEnvelope - all message types', (t) => {
  for (const [name, value] of Object.entries(TYPES)) {
    const env = createEnvelope({ type: value, content: `${name} message` })
    t.is(env.type, value, `type ${name} = ${value}`)
  }
})

test('createEnvelope - all platforms', (t) => {
  for (const [name, value] of Object.entries(PLATFORMS)) {
    const env = createEnvelope({ platform: value, content: `from ${name}` })
    t.is(env.platform, value, `platform ${name} = ${value}`)
  }
})

test('createEnvelope - media message', (t) => {
  const env = createEnvelope({
    type: TYPES.MEDIA,
    platform: PLATFORMS.DISCORD,
    author: 'user#1234',
    content: 'Check this out',
    mediaUrl: 'https://cdn.discord.com/attachments/abc.png',
    mediaType: 'image/png'
  })

  t.is(env.type, TYPES.MEDIA)
  t.is(env.mediaUrl, 'https://cdn.discord.com/attachments/abc.png')
  t.is(env.mediaType, 'image/png')
})

test('createEnvelope - reply message', (t) => {
  const original = createEnvelope({ content: 'original' })
  const reply = createEnvelope({
    type: TYPES.REPLY,
    content: 'reply to that',
    replyTo: original.id
  })

  t.is(reply.type, TYPES.REPLY)
  t.is(reply.replyTo, original.id)
})

test('createEnvelope - edit message', (t) => {
  const original = createEnvelope({ content: 'typo' })
  const edit = createEnvelope({
    type: TYPES.EDIT,
    content: 'fixed',
    editOf: original.id
  })

  t.is(edit.type, TYPES.EDIT)
  t.is(edit.editOf, original.id)
})

test('createEnvelope - delete message', (t) => {
  const original = createEnvelope({ content: 'oops' })
  const del = createEnvelope({
    type: TYPES.DELETE,
    deleteOf: original.id
  })

  t.is(del.type, TYPES.DELETE)
  t.is(del.deleteOf, original.id)
})

test('codec - encode/decode roundtrip', (t) => {
  const env = createEnvelope({
    type: TYPES.TEXT,
    platform: PLATFORMS.IRC,
    author: 'testuser',
    content: 'Hello world!',
    channel: '#general',
    timestamp: 1707000000000
  })

  const buf = encode(env)
  t.ok(Buffer.isBuffer(buf), 'encoded to buffer')
  t.ok(buf.length > 0, 'buffer has content')

  const decoded = decode(buf)
  t.alike(decoded, env, 'roundtrip preserves all fields')
})

test('codec - roundtrip all message types', (t) => {
  for (const [name, type] of Object.entries(TYPES)) {
    const env = createEnvelope({
      type,
      platform: PLATFORMS.KEET,
      author: 'user',
      content: `${name} content`,
      channel: 'room1'
    })

    const decoded = decode(encode(env))
    t.is(decoded.type, type, `roundtrip for ${name}`)
    t.is(decoded.content, env.content)
  }
})

test('codec - roundtrip with all fields populated', (t) => {
  const env = createEnvelope({
    type: TYPES.REPLY,
    platform: PLATFORMS.DISCORD,
    author: 'alice#1234',
    content: 'replying with image',
    channel: 'discord-channel-123',
    replyTo: 'abc123',
    mediaUrl: 'https://example.com/image.png',
    mediaType: 'image/png',
    editOf: 'def456',
    deleteOf: 'ghi789',
    id: 'custom-id-000',
    timestamp: 1707123456789
  })

  const decoded = decode(encode(env))
  t.alike(decoded, env, 'all fields preserved')
})

test('codec - empty strings handled correctly', (t) => {
  const env = createEnvelope({ content: '' })
  const decoded = decode(encode(env))
  t.is(decoded.content, '')
  t.is(decoded.replyTo, '')
  t.is(decoded.mediaUrl, '')
})

test('codec - unicode content', (t) => {
  const env = createEnvelope({
    author: 'ユーザー',
    content: '🎉 Hello 世界! مرحبا'
  })

  const decoded = decode(encode(env))
  t.is(decoded.author, 'ユーザー')
  t.is(decoded.content, '🎉 Hello 世界! مرحبا')
})

test('codec - large content', (t) => {
  const content = 'x'.repeat(10000)
  const env = createEnvelope({ content })
  const decoded = decode(encode(env))
  t.is(decoded.content, content)
})

test('codec - compact size is smaller than JSON', (t) => {
  const env = createEnvelope({
    type: TYPES.TEXT,
    platform: PLATFORMS.IRC,
    author: 'user',
    content: 'Hello world',
    channel: '#test'
  })

  const compactBuf = encode(env)
  const jsonBuf = Buffer.from(JSON.stringify(env))

  t.ok(compactBuf.length < jsonBuf.length, `compact (${compactBuf.length}) < JSON (${jsonBuf.length})`)
})

test('codec - works with cenc.encode/decode directly', (t) => {
  const env = createEnvelope({ content: 'direct codec usage' })
  const buf = cenc.encode(envelopeCodec, env)
  const decoded = cenc.decode(envelopeCodec, buf)
  t.alike(decoded, env)
})

test('TYPES constants', (t) => {
  t.is(TYPES.TEXT, 0)
  t.is(TYPES.MEDIA, 1)
  t.is(TYPES.REACTION, 2)
  t.is(TYPES.EDIT, 3)
  t.is(TYPES.DELETE, 4)
  t.is(TYPES.SYSTEM, 5)
  t.is(TYPES.REPLY, 6)
})

test('PLATFORMS constants', (t) => {
  t.is(PLATFORMS.KEET, 0)
  t.is(PLATFORMS.IRC, 1)
  t.is(PLATFORMS.DISCORD, 2)
  t.is(PLATFORMS.MATRIX, 3)
  t.is(PLATFORMS.MASTODON, 4)
  t.is(PLATFORMS.EMAIL, 5)
  t.is(PLATFORMS.ANDROID, 6)
})