At

 view release on metacpan or  search on metacpan

t/01_at_uri.t  view on Meta::CPAN

        is $urip, 'at://foo.com/foo?foo=bar&baz=buux#hash', 'hash: #hash';
        $urip->hash('hash');
        is $urip, 'at://foo.com/foo?foo=bar&baz=buux#hash', 'hash: hash';
    };
};
subtest 'supports relative URIs' => sub {
    my @tests = (

        # [ input, host, path, query, hash]
        [ '', '', '', '' ], [ '/', '/', '', '' ], [ '/foo', '/foo', '', '' ], [ '/foo/', '/foo/', '', '' ], [ '/foo/bar', '/foo/bar', '', '' ],
        [ '?foo=bar',     '',     'foo=bar', '' ], [ '?foo=bar&baz=buux', '',      'foo=bar&baz=buux', '' ], [ '/?foo=bar', '/', 'foo=bar', '' ],
        [ '/foo?foo=bar', '/foo', 'foo=bar', '' ], [ '/foo/?foo=bar',     '/foo/', 'foo=bar',          '' ], [ '#hash',     '',  '',        '#hash' ],
        [ '/#hash',       '/',    '',        '#hash' ], [ '/foo#hash', '/foo', '', '#hash' ],                [ '/foo/#hash', '/foo/', '', '#hash' ],
        [ '?foo=bar#hash', '',    'foo=bar', '#hash' ]
    );
    my @bases = (
        'did:web:localhost%3A1234',                                    'at://did:web:localhost%3A1234',
        'at://did:web:localhost%3A1234/foo/bar?foo=bar&baz=buux#hash', 'did:web:localhost%3A1234',
        'at://did:web:localhost%3A1234',                               'at://did:web:localhost%3A1234/foo/bar?foo=bar&baz=buux#hash'
    );
    for my $base (@bases) {
        subtest 'base: ' . $base => sub {
            isa_ok my $basep = At::Protocol::URI->new($base), ['At::Protocol::URI'], '$basep = ...->new( "' . $base . '" )';
            for my $test (@tests) {
                subtest 'rel: ' . $test->[0] => sub {
                    isa_ok my $urip = At::Protocol::URI->new( $test->[0], $base ), ['At::Protocol::URI'],
                        '->new( "' . $base . '", "' . $test->[0] . '" )';
                    is $urip->protocol, 'at:',          '->protocol';
                    is $urip->host,     $basep->host,   '->host matches $basep->host';
                    is $urip->origin,   $basep->origin, '->origin matches $basep->origin';
                    is $urip->pathname, $test->[1],     '->pathname';
                    is $urip->search,   $test->[2],     '->search';
                    is $urip->hash,     $test->[3],     '->hash';
                }
            }
        };
    }
};
subtest 'AT URI validation' => sub {

    sub expectValid($uri) {
        subtest $uri => sub {
            ok ensureValidAtUri($uri),      'ensureValidAtUri( ... )';
            ok ensureValidAtUriRegex($uri), 'ensureValidAtUriRegex( ... )';
        }
    }

    sub expectInvalid($uri) {
        subtest $uri => sub {
            ok dies { ensureValidAtUri($uri) },      'ensureValidAtUri( ... ) dies';
            ok dies { ensureValidAtUriRegex($uri) }, 'ensureValidAtUriRegex( ... ) dies';
        }
    }
    #
    subtest 'enfore spec basics' => sub {
        expectValid('at://did:plc:asdf123');
        expectValid('at://user.bsky.social');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/record');
        #
        expectValid('at://did:plc:asdf123#/frag');
        expectValid('at://user.bsky.social#/frag');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post#/frag');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/record#/frag');
        #
        expectInvalid('a://did:plc:asdf123');
        expectInvalid('at//did:plc:asdf123');
        expectInvalid('at:/a/did:plc:asdf123');
        expectInvalid('at:/did:plc:asdf123');
        expectInvalid('AT://did:plc:asdf123');
        expectInvalid('http://did:plc:asdf123');
        expectInvalid('://did:plc:asdf123');
        expectInvalid('at:did:plc:asdf123');
        expectInvalid('at:/did:plc:asdf123');
        expectInvalid('at:///did:plc:asdf123');
        expectInvalid('at://:/did:plc:asdf123');
        expectInvalid('at:/ /did:plc:asdf123');
        expectInvalid('at://did:plc:asdf123 ');
        expectInvalid('at://did:plc:asdf123/ ');
        expectInvalid(' at://did:plc:asdf123');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post ');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post# ');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#/ ');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#/frag ');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post#fr ag');
        expectInvalid('//did:plc:asdf123');
        expectInvalid('at://name');
        expectInvalid('at://name.0');
        expectInvalid('at://diD:plc:asdf123');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.p@st');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.p$st');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.p%st');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.p&st');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.p()t');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed_post');
        expectInvalid('at://did:plc:asdf123/-com.atproto.feed.post');
        expectInvalid('at://did:plc:asdf@123/com.atproto.feed.post');
        #
        expectInvalid('at://DID:plc:asdf123');
        expectInvalid('at://user.bsky.123');
        expectInvalid('at://bsky');
        expectInvalid('at://did:plc:');
        expectInvalid('at://did:plc:');
        expectInvalid('at://frag');
        #
        expectValid( 'at://did:plc:asdf123/com.atproto.feed.post/' . ( 'o' x 800 ) );
        expectInvalid( 'at://did:plc:asdf123/com.atproto.feed.post/' . ( 'o' x 8200 ) );
    };
    subtest 'has specified behavior on edge cases' => sub {
        expectInvalid('at://user.bsky.social//');
        expectInvalid('at://user.bsky.social//com.atproto.feed.post');
        expectInvalid('at://user.bsky.social/com.atproto.feed.post//');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/asdf123/more/more');
        expectInvalid('at://did:plc:asdf123/short/stuff');
        expectInvalid('at://did:plc:asdf123/12345');
    };
    subtest 'enforces no trailing slashes' => sub {
        expectValid('at://did:plc:asdf123');
        expectInvalid('at://did:plc:asdf123/');
        #
        expectValid('at://user.bsky.social');
        expectInvalid('at://user.bsky.social/');
        #
        expectValid('at://did:plc:asdf123/com.atproto.feed.post');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/');
        #
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/record');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/record/#/frag');
    };
    subtest 'enforces strict paths' => sub {
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/asdf123');
        expectInvalid('at://did:plc:asdf123/com.atproto.feed.post/asdf123/asdf');
    };
    subtest 'is very permissive about record keys' => sub {
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/asdf123');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/a');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%23');
        #
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/$@!*)(:,;~.sdf123');
        expectValid("at://did:plc:asdf123/com.atproto.feed.post/~'sdf123");
        #
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/$');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/@');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/!');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/*');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/(');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/,');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/;');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/abc%30123');
    };
    subtest 'is probably too permissive about URL encoding' => sub {
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%30');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%3');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%zz');
        expectValid('at://did:plc:asdf123/com.atproto.feed.post/%%%');
    };
    subtest 'is very permissive about fragments' => sub {
        expectValid('at://did:plc:asdf123#/frac');
        #
        expectInvalid('at://did:plc:asdf123#');
        expectInvalid('at://did:plc:asdf123##');
        expectInvalid('#at://did:plc:asdf123');
        expectInvalid('at://did:plc:asdf123#/asdf#/asdf');
        #
        expectValid('at://did:plc:asdf123#/com.atproto.feed.post');
        expectValid('at://did:plc:asdf123#/com.atproto.feed.post/');
        expectValid('at://did:plc:asdf123#/asdf/');
        #
        expectValid('at://did:plc:asdf123/com.atproto.feed.post#/$@!*():,;~.sdf123');
        expectValid('at://did:plc:asdf123#/[asfd]');
        #
        expectValid('at://did:plc:asdf123#/$');
        expectValid('at://did:plc:asdf123#/*');
        expectValid('at://did:plc:asdf123#/;');
        expectValid('at://did:plc:asdf123#/,');
    };
    subtest 'conforms to interop valid ATURIs' => sub {
        my $path = path(__FILE__)->sibling('interop-test-files')->child(qw[syntax aturi_syntax_valid.txt])->realpath;
        $path // skip_all 'failed to locate invalid test data';
        for my $line ( grep {length} $path->lines( { chomp => 1 } ) ) {
            if ( $line =~ /^#\s*/ ) {

                #~ diag $';
                next;
            }
            expectValid($line);
        }
    };
    subtest 'conforms to interop invalid ATURIs' => sub {
        my $todo
            = todo 'Like the official project, this package is currently more permissive than spec about AT URIs, so invalid cases are not errors';
        my $path = path(__FILE__)->sibling('interop-test-files')->child(qw[syntax aturi_syntax_invalid.txt])->realpath;
        $path // skip_all 'failed to locate invalid test data';
        for my $line ( grep {length} $path->lines( { chomp => 1 } ) ) {
            if ( $line =~ /^#\s*/ ) {

                #~ diag $';
                next;
            }
            expectInvalid($line);
        }
    };
};
#
done_testing;



( run in 0.782 second using v1.01-cache-2.11-cpan-364913b4093 )