#!perl
use Cassandane::Tiny;

#
# Test the /private/specialuse annotation defined by RFC6154.
#
sub test_specialuse
{
    my ($self) = @_;

    xlog $self, "testing /private/specialuse";

    my $imaptalk = $self->{store}->get_client();
    my $res;
    my $entry = '/private/specialuse';
    my $sentry = '/shared/specialuse';
    my @testcases = (
        # Cyrus has no virtual folders, so cannot do \All
        {
            folder => 'a',
            specialuse => '\All',
            result => 'no'
        },
        {
            folder => 'b',
            specialuse => '\Archive',
            result => 'ok'
        },
        {
            folder => 'c',
            specialuse => '\Drafts',
            result => 'ok'
        },
        # Cyrus has no virtual folders, so cannot do \Flagged
        {
            folder => 'd',
            specialuse => '\Flagged',
            result => 'no'
        },
        {
            folder => 'e',
            specialuse => '\Junk',
            result => 'ok'
        },
        {
            folder => 'f',
            specialuse => '\Sent',
            result => 'ok'
        },
        {
            folder => 'g',
            specialuse => '\Trash',
            result => 'ok'
        },
        # Tokens not defined in the RFC are rejected
        {
            folder => 'h',
            specialuse => '\Nonesuch',
            result => 'no'
        },
    );

    xlog $self, "First create all the folders";
    foreach my $tc (@testcases)
    {
        $imaptalk->create("INBOX.$tc->{folder}")
            or die "Cannot create mailbox INBOX.$tc->{folder}: $@";
    }

    foreach my $tc (@testcases)
    {
        my $folder = "INBOX.$tc->{folder}";

        xlog $self, "initial value for $folder is NIL";
        $res = $imaptalk->getmetadata($folder, $entry);
        $self->assert_str_equals('ok', $imaptalk->get_last_completion_response());
        $self->assert_not_null($res);
        delete $res->{$sentry}; # may return a shared entry as well...
        $self->assert_deep_equals({
            $folder => { $entry => undef }
        }, $res);

        xlog $self, "can set $folder to $tc->{specialuse}";
        $imaptalk->setmetadata($folder, $entry, $tc->{specialuse});
        $self->assert_str_equals($tc->{result}, $imaptalk->get_last_completion_response());

        xlog $self, "can get the set value back";
        $res = $imaptalk->getmetadata($folder, $entry);
        $self->assert_str_equals('ok', $imaptalk->get_last_completion_response());
        $self->assert_not_null($res);
        delete $res->{$sentry}; # may return a shared entry as well...
        my $expected = {
                $folder => { $entry => ($tc->{result} eq 'ok' ?  $tc->{specialuse} : undef) }
            };
        $self->assert_deep_equals($expected, $res);
    }

    xlog $self, "can get same values in a new connection";
    $self->{store}->disconnect();
    $imaptalk = $self->{store}->get_client();

    foreach my $tc (@testcases)
    {
        my $folder = "INBOX.$tc->{folder}";

        $res = $imaptalk->getmetadata($folder, $entry);
        $self->assert_str_equals('ok', $imaptalk->get_last_completion_response());
        $self->assert_not_null($res);
        delete $res->{$sentry}; # may return a shared entry as well...
        my $expected = {
                $folder => { $entry => ($tc->{result} eq 'ok' ?  $tc->{specialuse} : undef) }
            };
        $self->assert_deep_equals($expected, $res);
    }

    xlog $self, "can delete values";
    foreach my $tc (@testcases)
    {
        next unless ($tc->{result} eq 'ok');
        my $folder = "INBOX.$tc->{folder}";

        $imaptalk->setmetadata($folder, $entry, undef);
        $self->assert_str_equals('ok', $imaptalk->get_last_completion_response());

        $res = $imaptalk->getmetadata($folder, $entry);
        $self->assert_str_equals('ok', $imaptalk->get_last_completion_response());
        $self->assert_not_null($res);
        delete $res->{$sentry}; # may return a shared entry as well...
        my $expected = {
                $folder => { $entry => undef }
            };
        $self->assert_deep_equals($expected, $res);
    }

}
