Net-Nostr

 view release on metacpan or  search on metacpan

t/nip/53.t  view on Meta::CPAN

my $PK  = 'a' x 64;
my $PK2 = 'b' x 64;
my $PK3 = 'c' x 64;

###############################################################################
# Live Streaming Event (kind 30311)
###############################################################################

subtest 'live_event: kind 30311' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'demo-stream',
    );
    is($event->kind, 30311, 'kind is 30311');
    ok($event->is_addressable, 'addressable');
};

# Spec: d tag with unique identifier
subtest 'live_event: d tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'demo-cf-stream',
    );
    my @d = grep { $_->[0] eq 'd' } @{$event->tags};
    is($d[0][1], 'demo-cf-stream', 'd tag');
};

# Spec: title tag
subtest 'live_event: title tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        title      => 'Adult Swim Metalocalypse',
    );
    my @t = grep { $_->[0] eq 'title' } @{$event->tags};
    is($t[0][1], 'Adult Swim Metalocalypse', 'title');
};

# Spec: summary tag
subtest 'live_event: summary tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        summary    => 'Live stream from IPTV-ORG collection',
    );
    my @s = grep { $_->[0] eq 'summary' } @{$event->tags};
    is($s[0][1], 'Live stream from IPTV-ORG collection', 'summary');
};

# Spec: image tag
subtest 'live_event: image tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        image      => 'https://i.imgur.com/CaKq6Mt.png',
    );
    my @i = grep { $_->[0] eq 'image' } @{$event->tags};
    is($i[0][1], 'https://i.imgur.com/CaKq6Mt.png', 'image');
};

# Spec: streaming tag
subtest 'live_event: streaming tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        streaming  => 'https://example.com/stream.m3u8',
    );
    my @s = grep { $_->[0] eq 'streaming' } @{$event->tags};
    is($s[0][1], 'https://example.com/stream.m3u8', 'streaming');
};

# Spec: recording tag
subtest 'live_event: recording tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        recording  => 'https://example.com/recording.mp4',
    );
    my @r = grep { $_->[0] eq 'recording' } @{$event->tags};
    is($r[0][1], 'https://example.com/recording.mp4', 'recording');
};

# Spec: starts and ends timestamps
subtest 'live_event: starts and ends tags' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        starts     => '1687182672',
        ends       => '1687186272',
    );
    my @s = grep { $_->[0] eq 'starts' } @{$event->tags};
    is($s[0][1], '1687182672', 'starts');
    my @e = grep { $_->[0] eq 'ends' } @{$event->tags};
    is($e[0][1], '1687186272', 'ends');
};

# Spec: status tag (planned, live, ended)
subtest 'live_event: status tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        status     => 'live',
    );
    my @s = grep { $_->[0] eq 'status' } @{$event->tags};
    is($s[0][1], 'live', 'status');
};

# Spec: current_participants and total_participants
subtest 'live_event: participant count tags' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey               => $PK,
        identifier           => 'x',
        current_participants => '100',
        total_participants   => '200',
    );
    my @cp = grep { $_->[0] eq 'current_participants' } @{$event->tags};
    is($cp[0][1], '100', 'current_participants');
    my @tp = grep { $_->[0] eq 'total_participants' } @{$event->tags};
    is($tp[0][1], '200', 'total_participants');
};

# Spec: t (hashtag) tags, multiple allowed
subtest 'live_event: hashtag tags' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        hashtags   => ['animation', 'iptv'],
    );
    my @t = grep { $_->[0] eq 't' } @{$event->tags};

t/nip/53.t  view on Meta::CPAN

# Spec: relays tag
subtest 'live_event: relays tag' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        relays     => ['wss://one.com', 'wss://two.com'],
    );
    my @r = grep { $_->[0] eq 'relays' } @{$event->tags};
    is(scalar @r, 1, 'one relays tag');
    is($r[0][1], 'wss://one.com', 'first relay');
    is($r[0][2], 'wss://two.com', 'second relay');
};

# Spec: pinned tag for pinned live chat message
subtest 'live_event: pinned tag' => sub {
    my $event_id = 'e' x 64;
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        pinned     => [$event_id],
    );
    my @pin = grep { $_->[0] eq 'pinned' } @{$event->tags};
    is($pin[0][1], $event_id, 'pinned event id');
};

# Spec line 85: "pin one or more live chat messages"
subtest 'live_event: multiple pinned tags' => sub {
    my $id1 = 'e' x 64;
    my $id2 = 'f' x 64;
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
        pinned     => [$id1, $id2],
    );
    my @pin = grep { $_->[0] eq 'pinned' } @{$event->tags};
    is(scalar @pin, 2, 'two pinned tags');
    is($pin[0][1], $id1, 'first pinned');
    is($pin[1][1], $id2, 'second pinned');
};

# Spec: content is empty
subtest 'live_event: content defaults to empty' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => $PK,
        identifier => 'x',
    );
    is($event->content, '', 'empty content');
};

# Spec: requires identifier
subtest 'live_event: requires identifier' => sub {
    like(
        dies {
            Net::Nostr::LiveActivity->live_event(pubkey => $PK)
        },
        qr/identifier/i,
        'requires identifier'
    );
};

# Spec example: live streaming
subtest 'live_event: spec example' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey     => '1597246ac22f7d1375041054f2a4986bd971d8d196d7997e48973263ac9879ec',
        identifier => 'demo-cf-stream',
        title      => 'Adult Swim Metalocalypse',
        summary    => 'Live stream from IPTV-ORG collection',
        streaming  => 'https://adultswim-vodlive.cdn.turner.com/live/metalocalypse/stream.m3u8',
        starts     => '1687182672',
        status     => 'live',
        hashtags   => ['animation', 'iptv'],
        image      => 'https://i.imgur.com/CaKq6Mt.png',
    );
    is($event->kind, 30311, 'kind');
    my @d = grep { $_->[0] eq 'd' } @{$event->tags};
    is($d[0][1], 'demo-cf-stream', 'd');
    my @title = grep { $_->[0] eq 'title' } @{$event->tags};
    is($title[0][1], 'Adult Swim Metalocalypse', 'title');
    my @streaming = grep { $_->[0] eq 'streaming' } @{$event->tags};
    is($streaming[0][1], 'https://adultswim-vodlive.cdn.turner.com/live/metalocalypse/stream.m3u8', 'streaming');
    my @status = grep { $_->[0] eq 'status' } @{$event->tags};
    is($status[0][1], 'live', 'status');
    my @t = grep { $_->[0] eq 't' } @{$event->tags};
    is(scalar @t, 2, 'hashtag count');
    is($t[0][1], 'animation', 'first hashtag');
    is($t[1][1], 'iptv', 'second hashtag');
};

###############################################################################
# Live Chat Message (kind 1311)
###############################################################################

subtest 'chat_message: kind 1311' => sub {
    my $event = Net::Nostr::LiveActivity->chat_message(
        pubkey   => $PK,
        activity => "30311:${PK2}:demo",
        content  => 'Hello',
    );
    is($event->kind, 1311, 'kind is 1311');
    ok($event->is_regular, 'regular');
};

# Spec: MUST include a tag of the activity
subtest 'chat_message: a tag' => sub {
    my $event = Net::Nostr::LiveActivity->chat_message(
        pubkey   => $PK,
        activity => "30311:${PK2}:demo-cf-stream",
        content  => 'Zaps to live streams is beautiful.',
    );
    my @a = grep { $_->[0] eq 'a' } @{$event->tags};
    is($a[0][1], "30311:${PK2}:demo-cf-stream", 'a tag');
};

# Spec: a tag with optional relay url and root marker
subtest 'chat_message: a tag with relay hint' => sub {
    my $event = Net::Nostr::LiveActivity->chat_message(
        pubkey     => $PK,
        activity   => "30311:${PK2}:demo",
        relay_hint => 'wss://relay.example.com',
        content    => 'Hello',
    );
    my @a = grep { $_->[0] eq 'a' } @{$event->tags};
    is($a[0][2], 'wss://relay.example.com', 'relay hint');
    is($a[0][3], 'root', 'root marker');
};

# Spec: e tag for reply
subtest 'chat_message: e tag for reply' => sub {
    my $parent_id = 'f' x 64;
    my $event = Net::Nostr::LiveActivity->chat_message(
        pubkey   => $PK,
        activity => "30311:${PK2}:demo",
        reply_to => $parent_id,
        content  => 'Reply',
    );
    my @e = grep { $_->[0] eq 'e' } @{$event->tags};
    is($e[0][1], $parent_id, 'e tag');
};

# Spec: requires activity

t/nip/53.t  view on Meta::CPAN


# Spec: hand tag (optional, raised flag)
subtest 'room_presence: hand tag' => sub {
    my $event = Net::Nostr::LiveActivity->room_presence(
        pubkey   => $PK,
        activity => "30312:${PK2}:main-room",
        hand     => '1',
    );
    my @h = grep { $_->[0] eq 'hand' } @{$event->tags};
    is($h[0][1], '1', 'hand raised');
};

# Spec: hand tag omitted when not set
subtest 'room_presence: no hand tag by default' => sub {
    my $event = Net::Nostr::LiveActivity->room_presence(
        pubkey   => $PK,
        activity => "30312:${PK2}:main-room",
    );
    my @h = grep { $_->[0] eq 'hand' } @{$event->tags};
    is(scalar @h, 0, 'no hand tag');
};

# Spec: requires activity
subtest 'room_presence: requires activity' => sub {
    like(
        dies {
            Net::Nostr::LiveActivity->room_presence(pubkey => $PK)
        },
        qr/activity/i,
        'requires activity'
    );
};

# Spec example
subtest 'room_presence: spec example' => sub {
    my $event = Net::Nostr::LiveActivity->room_presence(
        pubkey     => $PK,
        activity   => "30312:${PK2}:main-room",
        relay_hint => 'wss://relay.com',
        hand       => '1',
    );
    is($event->kind, 10312, 'kind');
    ok($event->is_replaceable, 'replaceable');
    my @a = grep { $_->[0] eq 'a' } @{$event->tags};
    is($a[0][3], 'root', 'root marker');
    my @h = grep { $_->[0] eq 'hand' } @{$event->tags};
    is($h[0][1], '1', 'hand');
};

###############################################################################
# from_event: round-trip parsing
###############################################################################

subtest 'from_event: live_event round-trip' => sub {
    my $event = Net::Nostr::LiveActivity->live_event(
        pubkey               => $PK,
        identifier           => 'demo-stream',
        title                => 'Test Stream',
        summary              => 'A test',
        image                => 'https://example.com/img.png',
        streaming            => 'https://example.com/stream.m3u8',
        recording            => 'https://example.com/rec.mp4',
        starts               => '1687182672',
        ends                 => '1687186272',
        status               => 'live',
        current_participants => '50',
        total_participants   => '100',
        hashtags             => ['test', 'live'],
        participants         => [[$PK2, 'wss://relay.com/', 'Host']],
        relays               => ['wss://one.com'],
        pinned               => ['e' x 64],
    );
    my $parsed = Net::Nostr::LiveActivity->from_event($event);
    is($parsed->identifier, 'demo-stream', 'identifier');
    is($parsed->title, 'Test Stream', 'title');
    is($parsed->summary, 'A test', 'summary');
    is($parsed->image, 'https://example.com/img.png', 'image');
    is($parsed->streaming, 'https://example.com/stream.m3u8', 'streaming');
    is($parsed->recording, 'https://example.com/rec.mp4', 'recording');
    is($parsed->starts, '1687182672', 'starts');
    is($parsed->ends, '1687186272', 'ends');
    is($parsed->status, 'live', 'status');
    is($parsed->current_participants, '50', 'current_participants');
    is($parsed->total_participants, '100', 'total_participants');
    is($parsed->hashtags, ['test', 'live'], 'hashtags');
    is($parsed->participants->[0][0], $PK2, 'participant pubkey');
    is($parsed->participants->[0][2], 'Host', 'participant role');
    is($parsed->relays, ['wss://one.com'], 'relays');
    is($parsed->pinned->[0], 'e' x 64, 'pinned');
};

subtest 'from_event: chat_message round-trip' => sub {
    my $event = Net::Nostr::LiveActivity->chat_message(
        pubkey     => $PK,
        activity   => "30311:${PK2}:demo",
        relay_hint => 'wss://relay.com',
        reply_to   => 'f' x 64,
        content    => 'Hello!',
    );
    my $parsed = Net::Nostr::LiveActivity->from_event($event);
    is($parsed->activity, "30311:${PK2}:demo", 'activity');
    is($parsed->relay_hint, 'wss://relay.com', 'relay_hint');
    is($parsed->reply_to, 'f' x 64, 'reply_to');
};

subtest 'from_event: meeting_space round-trip' => sub {
    my $event = Net::Nostr::LiveActivity->meeting_space(
        pubkey       => $PK,
        identifier   => 'main-room',
        room         => 'Main Room',
        status       => 'open',
        service      => 'https://meet.example.com',
        endpoint     => 'https://api.example.com',
        participants => [[$PK2, 'wss://relay.com/', 'Host']],
    );
    my $parsed = Net::Nostr::LiveActivity->from_event($event);
    is($parsed->identifier, 'main-room', 'identifier');
    is($parsed->room, 'Main Room', 'room');
    is($parsed->status, 'open', 'status');
    is($parsed->service, 'https://meet.example.com', 'service');
    is($parsed->endpoint, 'https://api.example.com', 'endpoint');
    is($parsed->participants->[0][0], $PK2, 'participant');
};

subtest 'from_event: meeting_room round-trip' => sub {
    my $event = Net::Nostr::LiveActivity->meeting_room(
        pubkey     => $PK,
        identifier => 'mtg-1',
        space_ref  => ["30312:${PK2}:room", 'wss://relay.com'],
        title      => 'Meeting',
        starts     => '1676262123',
        ends       => '1676269323',
        status     => 'live',
    );
    my $parsed = Net::Nostr::LiveActivity->from_event($event);
    is($parsed->identifier, 'mtg-1', 'identifier');
    is($parsed->space_ref->[0], "30312:${PK2}:room", 'space_ref coord');
    is($parsed->space_ref->[1], 'wss://relay.com', 'space_ref relay');



( run in 0.714 second using v1.01-cache-2.11-cpan-140bd7fdf52 )