# t/rename.t
#
# Test user renaming.
#
# Authors:
#      Afuna <coder.dw@afunamatata.com>
#
# Copyright (c) 2013-2014 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself.  For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#

use strict;
use warnings;

use Test::More tests => 153;

BEGIN { $LJ::_T_CONFIG = 1; require "$ENV{LJHOME}/cgi-bin/ljlib.pl"; }
use LJ::Test qw( temp_user temp_comm );
use DW::User::Rename;
use DW::RenameToken;

my $create_users = sub {
    my %opts = @_;

    my $fromu = temp_user();
    my $tou   = temp_user();

    unless ( $opts{match} ) {
        my %from_defaults = (
            status   => 'N',
            email    => 'from@testemail',
            password => 'from',
        );

        LJ::update_user( $fromu, { %from_defaults, %{ $opts{from_details} || {} } } );

        my %to_defaults = (
            status   => 'N',
            email    => 'to@testemail',
            password => 'to',
        );

        LJ::update_user( $tou, { %to_defaults, %{ $opts{to_details} || {} } } );
    }

    $fromu = LJ::load_userid( $fromu->userid ) if $opts{from_details};
    $tou   = LJ::load_userid( $tou->userid )   if $opts{to_details};

    if ( $opts{validated} ) {
        LJ::update_user( $fromu, { status => 'A' } );
        LJ::update_user( $tou,   { status => 'A' } );
    }

    return ( $fromu, $tou );
};

sub new_token { return DW::RenameToken->create_token( ownerid => $_[0]->id ) }

note("-- personal-to-unregistered, no redirect");
{

    my $u = temp_user();

    my $fromuid      = $u->userid;
    my $fromusername = $u->username;
    my $tousername   = $fromusername . "_renameto";

    ok( !LJ::load_user($tousername),    "Username '$tousername' is unregistered" );
    ok( $u->can_rename_to($tousername), "'" . $u->user . "' can rename to '$tousername'" );

    ok(
        $u->rename( $tousername, token => new_token($u), redirect => 0 ),
        "Rename fromu to a valid unregistered username, no redirect"
    );

    $u = LJ::load_userid( $u->userid );
    is( $u->userid, $fromuid,    "Id '#$fromuid' remains the same after rename." );
    is( $u->user,   $tousername, "fromu is now named '$tousername'" );
}

note("-- personal-to-unregistered, with redirect");
{

    my $u = temp_user();

    my $fromuid      = $u->userid;
    my $fromusername = $u->user;
    my $tousername   = $fromusername . "_renameto";

    ok( !LJ::load_user($tousername),    "Username '$tousername' is unregistered" );
    ok( $u->can_rename_to($tousername), "'" . $u->user . "' can rename to '$tousername'" );

    ok(
        $u->rename( $tousername, token => new_token($u), redirect => 1 ),
        "Rename fromu to a valid unregistered username, with redirect"
    );

    $u = LJ::load_userid( $u->userid );
    is( $u->userid, $fromuid,    "Id '#$fromuid' remains the same after rename." );
    is( $u->user,   $tousername, "fromu is now named '$tousername'" );

    my $orig_u = LJ::load_user($fromusername);
    ok( $orig_u->is_renamed,  "Yup, renamed" );
    ok( $orig_u->is_redirect, "Chose to redirect this rename" );
    is( $orig_u->get_renamed_user->user,
        $tousername, "Confirm redirect from $fromusername to $tousername" );
}

note("-- user-to-user, no redirect");
{
    my ( $fromu, $tou ) = $create_users->( match => 1, validated => 1 );

    my $fromuid    = $fromu->userid;
    my $touid      = $tou->userid;
    my $tousername = $tou->user;

    ok( $fromu->rename( $tousername, token => new_token($fromu), redirect => 0 ),
        "Rename fromu to existing user $tousername" );

    $fromu = LJ::load_userid( $fromu->userid );
    $tou   = LJ::load_userid( $tou->userid );
    is( $fromu->user, $tousername, "Rename fromu to tou, which is under the control of fromu" );
    my $ex_user = substr( $tousername, 0, 10 );
    like( $tou->user, qr/^ex_$ex_user/, "Moved out of the way." );
    is( $fromu->userid, $fromuid, "Id of fromu remains the same after rename." );
    is( $tou->userid,   $touid,   "Id of tou remains the same after rename." );
}

note("-- user-to-user, with redirect");
{
    my ( $fromu, $tou ) = $create_users->( match => 1, validated => 1 );

    my $fromuid      = $fromu->userid;
    my $fromusername = $fromu->username;
    my $touid        = $tou->userid;
    my $tousername   = $tou->user;

    ok( $fromu->rename( $tousername, token => new_token($fromu), redirect => 1 ),
        "Rename fromu to existing user $tousername" );

    $fromu = LJ::load_userid( $fromu->userid );
    $tou   = LJ::load_userid( $tou->userid );
    is( $fromu->user, $tousername, "Rename fromu to tou, which is under the control of fromu" );
    my $ex_user = substr( $tousername, 0, 10 );
    like( $tou->user, qr/^ex_$ex_user/, "Moved out of the way." );
    is( $fromu->userid, $fromuid, "Id of fromu remains the same after rename." );
    is( $tou->userid,   $touid,   "Id of tou remains the same after rename." );

    my $orig_u = LJ::load_user($fromusername);
    ok( $orig_u->is_renamed,  "Yup, renamed" );
    ok( $orig_u->is_redirect, "Chose to redirect this rename" );
    is( $orig_u->get_renamed_user->user,
        $tousername, "Confirm redirect from $fromusername to $tousername" );

}

note("-- rename opts: deleting relationships");
{
    my ($u) = temp_user();
    my $tousername = $u->user . "_renameto";

    my $watcher = temp_user();
    my $truster = temp_user();
    my $watched = temp_user();
    my $trusted = temp_user();
    my $comm    = temp_comm();

    $watcher->add_edge( $u, watch => { nonotify => 1 } );
    $truster->add_edge( $u, trust => { nonotify => 1 } );
    $u->add_edge( $watched, watch => { nonotify => 1 } );
    $u->add_edge( $trusted, trust => { nonotify => 1 } );
    $u->add_edge( $comm,    watch => { nonotify => 1 } );

    ok( $watcher->watches($u), "User has a watcher." );
    ok( $truster->trusts($u),  "User has a truster." );
    ok( $u->watches($watched), "User watches someone." );
    ok( $u->trusts($trusted),  "User trusts someone." );
    ok( $u->watches($comm),    "User watches a comm." );

    # no arguments means nothing was deleted
    $u->apply_rename_opts();
    ok( $watcher->watches($u), "User has a watcher." );
    ok( $truster->trusts($u),  "User has a truster." );
    ok( $u->watches($watched), "User watches someone." );
    ok( $u->trusts($trusted),  "User trusts someone." );
    ok( $u->watches($comm),    "User watches a comm." );

    $u->apply_rename_opts( del => { del_watched_by => 1 } );
    ok( !$watcher->watches($u), "User has no watcher." );
    ok( $truster->trusts($u),   "User has a truster." );
    ok( $u->watches($watched),  "User watches someone." );
    ok( $u->trusts($trusted),   "User trusts someone." );
    ok( $u->watches($comm),     "User watches a comm." );
    $watcher->add_edge( $u, watch => { nonotify => 1 } );

    $u->apply_rename_opts( del => { del_trusted_by => 1 } );
    ok( $watcher->watches($u), "User has a watcher." );
    ok( !$truster->trusts($u), "User has no truster." );
    ok( $u->watches($watched), "User watches someone." );
    ok( $u->trusts($trusted),  "User trusts someone." );
    ok( $u->watches($comm),    "User watches a comm." );
    $truster->add_edge( $u, trust => { nonotify => 1 } );

    $u->apply_rename_opts( del => { del_watched => 1 } );
    ok( $watcher->watches($u),  "User has a watcher." );
    ok( $truster->trusts($u),   "User has a truster." );
    ok( !$u->watches($watched), "User does not watch anyone." );
    ok( $u->trusts($trusted),   "User trusts someone." );
    ok( $u->watches($comm),     "User watches a comm." );
    $u->add_edge( $watched, watch => { nonotify => 1 } );

    $u->apply_rename_opts( del => { del_trusted => 1 } );
    ok( $watcher->watches($u), "User has a watcher." );
    ok( $truster->trusts($u),  "User has a truster." );
    ok( $u->watches($watched), "User watches someone." );
    ok( !$u->trusts($watched), "User does not trust anyone." );
    ok( $u->watches($comm),    "User watches a comm." );
    $u->add_edge( $trusted, trust => { nonotify => 1 } );

    $u->apply_rename_opts( del => { del_communities => 1 } );
    ok( $watcher->watches($u), "User has a watcher." );
    ok( $truster->trusts($u),  "User has a truster." );
    ok( $u->watches($watched), "User watches someone." );
    ok( $u->trusts($trusted),  "User trusts someone." );
    ok( !$u->watches($comm),   "User does not watch a comm." );

    ok(
        $u->rename(
            $tousername,
            token          => new_token($u),
            redirect       => 0,
            del_trusted_by => 1,
            del_watched_by => 1
        ),
        "Rename, break watchers and trusters"
    );
    ok( !$watcher->watches($u), "User has no watcher." );
    ok( !$truster->trusts($u),  "User has no truster." );
    ok( $u->watches($watched),  "User watches someone." );
    ok( $u->trusts($trusted),   "User trusts someone." );
    ok( !$u->watches($comm),    "User does not watch a comm." );
}

note("-- rename opts: breaking email redirection");
TODO: {
    local $TODO = "-- rename opts: breaking email redirection";
}

note("-- personal-to-personal, authorization");
{
    my ( $fromu, $tou, $tousername );
    my %rename_cond = (
        status   => 'A',
        password => 'rename',
        email    => 'rename@testemail',
    );
    ( $fromu, $tou ) = $create_users->(
        from_details => { %rename_cond, email => 'from@testemail' },
        to_details   => { %rename_cond, email => 'to@testemail' }
    );
    $tousername = $tou->user;
    ok( !$fromu->can_rename_to($tousername),
        "Cannot rename fromu to existing user $tousername (because: email)" );

    ( $fromu, $tou ) = $create_users->(
        from_details => { %rename_cond, status => 'N' },
        to_details   => { %rename_cond, status => 'N' }
    );
    $tousername = $tou->user;
    ok( !$fromu->can_rename_to($tousername),
        "Cannot rename fromu to existing user $tousername (because: validation)" );

    ( $fromu, $tou ) = $create_users->(
        from_details => {%rename_cond},
        to_details   => { %rename_cond, status => 'N' }
    );
    $tousername = $tou->user;
    ok( $fromu->can_rename_to($tousername),
        "Can rename fromu to existing user $tousername (at least one user is validated)" );
    ok( $fromu->rename( $tousername, token => new_token($fromu) ),
        "Renamed fromu to existing user $tousername" );
}

{
    my ( $fromu, $tou ) = $create_users->();
    my $tousername = $tou->user;

    ok( $fromu->can_rename_to( $tousername, force => 1 ),
        "Can force rename fromu to existing user $tousername not under their control" );
    ok( $fromu->rename( $tousername, token => new_token($fromu), force => 1 ),
        "Renamed fromu to existing user $tousername" );
}

TODO: {
    local $TODO =
        "rename to linked usernames, once we allow one account to control multiple usernames";
}

note("-- user status special casing");
{
    my ( $fromu, $tou ) = $create_users->();

    my $fromusername = $fromu->username;
    my $tousername   = $tou->user;

    $tou->update_self(
        {
            clusterid => 0,
            statusvis => 'X',
            raw       => "statusvisdate=NOW()"
        }
    );

    LJ::start_request();
    $tou   = LJ::load_user( $tousername,   1 );
    $fromu = LJ::load_user( $fromusername, 1 );

    ok( $fromu->can_rename_to($tousername), "Can always rename to expunged users." );
    ok( $fromu->rename( $tousername, token => new_token($fromu) ),
        "Rename to expunged user $tousername" );

    $fromu = LJ::load_userid( $fromu->userid, 1 );
    $tou   = LJ::load_userid( $tou->userid,   1 );
    is( $fromu->user, $tousername, "Rename fromu to tou, which is under the control of fromu" );
    my $ex_user = substr( $tousername, 0, 10 );
    like( $tou->user, qr/^ex_$ex_user/, "Moved out of the way." );
}

{
    my ( $fromu, $tou ) = $create_users->();

    my $fromusername = $fromu->username;
    my $tousername   = $tou->user;

    $tou->set_statusvis("D");

    ok( !$fromu->can_rename_to($tousername), "Cannot rename to (nonmatching) deleted users." );
}

{
    my ( $fromu, $tou, $tousername );

    ( $fromu, $tou ) = $create_users->( validated => 1 );
    $tousername = $tou->user;

    $tou->set_statusvis("S");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename to nonmatching suspended users." );

    ( $fromu, $tou ) = $create_users->( match => 1, validated => 1 );
    $tousername = $tou->user;

    $tou->set_statusvis("S");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename to matching suspended users." );

    $tou->set_statusvis("L");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename to matching locked users." );

    $tou->set_statusvis("M");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename to matching memorial users." );

    $tou->set_statusvis("O");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename to matching read-only users." );

    $tou->set_statusvis("R");
    ok( !$fromu->can_rename_to($tousername),
        "Cannot rename to matching renamed and redirecting users." );

    $tou->set_statusvis("V");
    ok( $fromu->can_rename_to($tousername), "(reset status)" );

    $fromu->set_statusvis("S");
    ok( !$fromu->can_rename_to($tousername), "Cannot rename from suspended users." );
}

note("-- username issues");
{
    my $fromu = temp_user();

    my $fromusername = $fromu->user;

    # taken from htdocs/inc/reserved-usernames. Production site may have more
    # but these are good enough for testing
    my @reserved_names = qw( dw_test ex_test ext_test s_test _test test__test );

    foreach my $name (@reserved_names) {
        ok( !$fromu->can_rename_to( $name . $fromusername, token => new_token($fromu) ),
            "Cannot rename to reserved username '$name'" );
    }

    # reserved usernames can be force-renamed to
    foreach my $name (@reserved_names) {
        ok(
            $fromu->can_rename_to( $name . $fromusername, token => new_token($fromu), force => 1 ),
            "Forced rename to reserved username '$name$fromusername'"
        );
    }

    ok( !$fromu->can_rename_to( $fromu->username, token => new_token($fromu) ),
        "Cannot rename to own name" );
}

{
    my $fromu = temp_user();

    my $fromusername      = $fromu->user;
    my @invalid_usernames = qw( a.b a!b a\x{123}b );
    push @invalid_usernames, "x" x 30;

    foreach my $name (@invalid_usernames) {
        ok(
            !$fromu->rename( $name, token => new_token($fromu) ),
            "Cannot rename to invalid username '$name'"
        );
    }

    # invalid usernames cannot be force-renamed to
    foreach my $name (@invalid_usernames) {
        ok( !$fromu->rename( $name, token => new_token($fromu), force => 1 ),
            "Cannot force rename to invalid username '$name'" );
    }
}

{
    my $fromu = temp_user();

    my $tousername = $fromu->user . "-abc";
    ok( $fromu->rename( $tousername, token => new_token($fromu) ), "Rename does canonicalization" );
    $fromu = LJ::load_userid( $fromu->userid );
    is( $fromu->user, LJ::canonical_username($tousername), "Canonicalize away hyphens" );
}

note("-- community-to-unregistered");
{
    my $admin       = temp_user();
    my $fromu       = temp_comm();
    my $oldusername = $fromu->username;
    my $tousername  = $fromu->username . "_renameto";

    ok( !$admin->can_manage($fromu), "User cannot manage community fromu." );
    ok(
        !$fromu->can_rename_to( $tousername, user => $admin ),
        "Cannot rename community to  $tousername (not admin)"
    );

    LJ::set_rel( $fromu, $admin, "A" );

    # FIXME: we shouldn't need to do this!
    delete $LJ::REQ_CACHE_REL{ $fromu->userid . "-" . $admin->userid . "-A" };
    ok( $admin->can_manage($fromu), "User can manage fromu." );

    ok( !LJ::load_user($tousername), "Username '$tousername' is unregistered" );
    ok( $fromu->can_rename_to( $tousername, user => $admin ), "Can rename to $tousername" );
    ok( $fromu->rename( $tousername, token => new_token($admin), user => $admin ),
        "Renamed community to $tousername" );

    LJ::update_user( $admin, { status => 'A' } );
    ok( $admin->is_validated, "Admin was validated so could rename." );
    LJ::update_user( $admin, { status => 'N' } );
    ok(
        !$admin->is_validated && !$fromu->can_rename_to( $tousername . "_rename", user => $admin ),
        "Admin no longer validated; can no longer rename"
    );

    ok( !$fromu->can_rename_to($tousername),
        "Cannot rename community without providing a user doing the renaming" );

    my $member = temp_user();
    $member->join_community($fromu);
    ok( !$fromu->can_rename_to( $oldusername, user => $admin ),
        "Cannot rename a community with members" );

    $member->leave_community($fromu);
    ok(
        $fromu->can_rename_to( $oldusername, user => $admin ),
        "Can rename community again, no members."
    );
}

note("-- community-to-personal");
{
    my ( $admin, $tou ) = $create_users->( validated => 1 );
    my $fromu      = temp_comm();
    my $tousername = $tou->user;

    # make admin of fromu
    LJ::set_rel( $fromu, $admin, "A" );
    delete $LJ::REQ_CACHE_REL{ $fromu->userid . "-" . $admin->userid . "-A" };

    ok(
        !$fromu->can_rename_to( $tousername, user => $admin ),
"Cannot rename fromu to existing user $tousername (tou is a personal journal not under admin's control)"
    );

    ( $admin, $tou ) = $create_users->( match => 1, validated => 1 );
    $tousername = $tou->user;

    # make admin of fromu
    LJ::set_rel( $fromu, $admin, "A" );
    delete $LJ::REQ_CACHE_REL{ $fromu->userid . "-" . $admin->userid . "-A" };
    ok(
        $fromu->can_rename_to( $tousername, user => $admin ),
        $admin->user
            . " can rename community fromu to existing user $tousername (tou is a personal journal under admin's control)"
    );
    ok(
        $fromu->rename( $tousername, token => new_token($admin), user => $admin ),
        $admin->user . " renamed community fromu to existing community $tousername"
    );
}

note("-- personal-to-community");
{
    my $fromu = temp_user();
    LJ::update_user( $fromu, { status => 'A' } );

    my $tou        = temp_comm();
    my $tousername = $tou->user;

    # make admin of tou
    LJ::set_rel( $tou, $fromu, "A" );
    delete $LJ::REQ_CACHE_REL{ $tou->userid . "-" . $fromu->userid . "-A" };

    my $member = temp_user();
    $member->join_community($tou);
    ok( !$fromu->can_rename_to( $tousername, user => $fromu, verbose => 1 ),
        "Cannot rename a community with members" );

    $member->leave_community($tou);
    ok( $fromu->can_rename_to($tousername),
        "Can rename to a community under your own control if it has no members." );
    ok(
        $fromu->rename( $tousername, token => new_token($fromu) ),
        "Renamed personal journal fromu to existing community."
    );
}

note("-- openid and feeds");
{
    my $u = temp_user();
    LJ::update_user( $u, { journaltype => 'I' } );

    ok( !$u->can_rename_to( $u->user . "_rename" ), "Cannot rename OpenID accounts" );

    LJ::update_user( $u, { journaltype => 'F' } );
    ok( !$u->can_rename_to( $u->user . "_rename" ), "Cannot rename feed accounts" );
}

note("-- rename token ownership ignored");
{
    my $u = temp_user();

    my $fromusername = $u->user;
    my $tousername   = $fromusername . "_renameto";

    ok( $u->rename( $tousername, token => new_token( temp_user() ) ),
        "Check that rename token ownership is ignored" );
}

note("-- two username swap (personal to personal)");
{
    my ( $u1, $u2 ) = $create_users->( match => 1, validated => 1 );

    my $u1id      = $u1->userid;
    my $u2id      = $u2->userid;
    my $u1sername = $u1->user;
    my $u2sername = $u2->user;

    ok( $u1sername ne $u2sername, "Not the same username" );

    my $token = new_token($u1);
    ok(
        !$u1->swap_usernames(
            $u2, tokens => [ $token, $token ]
        ),
        "Can't swap, token is the same"
    );

    ok(
        $u1->swap_usernames(
            $u2, tokens => [ new_token($u1), new_token($u1) ]
        ),
        "Swap usernames"
    );

    $u1 = LJ::load_userid( $u1->userid );
    $u2 = LJ::load_userid( $u2->userid );

    is( $u1->user, $u2sername, "Swap usernames of u1 and u2" );
    is( $u2->user, $u1sername, "Swap usernames of u2 and u1" );

    is( $u1->userid, $u1id, "Id of u1 remains the same after rename." );
    is( $u2->userid, $u2id, "Id of u2 remains the same after rename." );
}

note("-- two username swap (personal to personal), one token owned by each user");
{
    my ( $u1, $u2 ) = $create_users->( match => 1, validated => 1 );

    ok(
        $u1->swap_usernames(
            $u2, tokens => [ new_token($u1), new_token($u2) ]
        ),
        "Swap usernames with one token owned by each account"
    );
}

note("-- two username swap (one user is suspended)");
{
    my ( $u1, $u2 ) = $create_users->( match => 1, validated => 1 );
    $u2->set_statusvis("S");

    my $u1id      = $u1->userid;
    my $u2id      = $u2->userid;
    my $u1sername = $u1->user;
    my $u2sername = $u2->user;

    ok( $u1sername ne $u2sername, "Not the same username" );

    ok(
        !$u1->swap_usernames(
            $u2, tokens => [ new_token($u1), new_token($u1) ]
        ),
        "Cannot swap usernames."
    );

    $u1 = LJ::load_userid( $u1->userid );
    $u2 = LJ::load_userid( $u2->userid );

    is( $u1->user, $u1sername, "No swap" );
    is( $u2->user, $u2sername, "No swap" );
}

note("-- two username swap personal <=> community ");
{
    my $u = temp_user();
    LJ::update_user( $u, { status => 'A' } );

    my $comm     = temp_comm();
    my $uname    = $u->user;
    my $commname = $comm->user;

    ok(
        !$u->swap_usernames(
            $comm, tokens => [ new_token($u), new_token($u) ]
        ),
        "Cannot swap personal and community usernames (not an admin)"
    );

    # make admin of u
    LJ::set_rel( $comm, $u, "A" );
    delete $LJ::REQ_CACHE_REL{ $comm->userid . "-" . $u->userid . "-A" };

    ok(
        $u->swap_usernames(
            $comm, tokens => [ new_token($u), new_token($u) ],
        ),
        "Swap personal and community usernames"
    );

    is( $u->user,    $commname, "Swap usernames u => comm" );
    is( $comm->user, $uname,    "Swap usernames comm => u" );
}

note("-- two username swap personal <=> community (with malice)");
{
    my ( $u, $u2 ) = $create_users->( validate => 1 );

    my $comm     = temp_comm();
    my $uname    = $u->user;
    my $commname = $comm->user;

    # make admin of u
    LJ::set_rel( $comm, $u, "A" );
    delete $LJ::REQ_CACHE_REL{ $comm->userid . "-" . $u->userid . "-A" };

    LJ::set_rel( $comm, $u2, "A" );
    delete $LJ::REQ_CACHE_REL{ $comm->userid . "-" . $u2->userid . "-A" };

    ok(
        !$u->swap_usernames(
            $u2, tokens => [ new_token($u), new_token($u) ],
        ),
        "Swap usernames with someone not under your control"
    );

    ok(
        !$comm->swap_usernames(
            $u2,
            user   => $u,
            tokens => [ new_token($u), new_token($u) ],
        ),
        "Swapping the username of a co-admin"
    );
}

note("-- two username swap community <=> personal");
{
    my $u = temp_user();
    LJ::update_user( $u, { status => 'A' } );

    my $comm     = temp_comm();
    my $uname    = $u->user;
    my $commname = $comm->user;

    ok(
        !$comm->swap_usernames(
            $u, tokens => [ new_token($u), new_token($u) ]
        ),
        "Cannot swap personal and community usernames (not an admin)"
    );

    # make admin of u
    LJ::set_rel( $comm, $u, "A" );
    delete $LJ::REQ_CACHE_REL{ $comm->userid . "-" . $u->userid . "-A" };

    ok(
        !$comm->swap_usernames(
            $u, tokens => [ new_token($u), new_token($u) ]
        ),
        "Cannot swap community and personal when acting on the community"
    );
}

note("-- two username swap (community and community)");
{
    my $admin = temp_user();
    LJ::update_user( $admin, { status => 'A' } );

    my $c1 = temp_comm();
    my $c2 = temp_comm();

    LJ::set_rel( $c1, $admin, "A" );
    delete $LJ::REQ_CACHE_REL{ $c1->userid . "-" . $admin->userid . "-A" };
    LJ::set_rel( $c2, $admin, "A" );
    delete $LJ::REQ_CACHE_REL{ $c2->userid . "-" . $admin->userid . "-A" };

    my $c1sername = $c1->user;
    my $c2sername = $c2->user;

    ok( $c1sername ne $c2sername, "Not the same username" );

    ok(
        $c1->swap_usernames(
            $c2,
            user   => $admin,
            tokens => [ new_token($admin), new_token($admin) ],
        ),
        "Swap community usernames"
    );

    is( $c1->user, $c2sername, "Swap usernames of c1 and c2" );
    is( $c2->user, $c1sername, "Swap usernames of c2 and c1" );
}
