code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Abort if called from a web server
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

function update_core($dir, $domain)
{
    $old = getcwd();
    chdir($dir);
    passthru(<<<END
xgettext \
    --from-code=UTF-8 \
    --default-domain=$domain \
    --output=locale/$domain.pot \
    --language=PHP \
    --add-comments=TRANS \
    --keyword="_m:1,1t" \
    --keyword="_m:1c,2,2t" \
    --keyword="_m:1,2,3t" \
    --keyword="_m:1c,2,3,4t" \
    --keyword="pgettext:1c,2" \
    --keyword="npgettext:1c,2,3" \
    index.php \
    actions/*.php \
    classes/*.php \
    lib/*.php \
    scripts/*.php
END
);
    chdir($old);
}

function do_update_plugin($dir, $domain)
{
    $old = getcwd();
    chdir($dir);
    if (!file_exists('locale')) {
        mkdir('locale');
    }
    $files = get_plugin_sources(".");
    $cmd = <<<END
xgettext \
    --from-code=UTF-8 \
    --default-domain=$domain \
    --output=locale/$domain.pot \
    --language=PHP \
    --add-comments=TRANS \
    --keyword='' \
    --keyword="_m:1,1t" \
    --keyword="_m:1c,2,2t" \
    --keyword="_m:1,2,3t" \
    --keyword="_m:1c,2,3,4t" \

END;
    foreach ($files as $file) {
      $cmd .= ' ' . escapeshellarg($file);
    }
    passthru($cmd);
    chdir($old);
}

function get_plugins($dir)
{
    $plugins = array();
    $dirs = new DirectoryIterator("$dir/plugins");
    foreach ($dirs as $item) {
        if ($item->isDir() && !$item->isDot()) {
            $name = $item->getBasename();
            if (file_exists("$dir/plugins/$name/{$name}Plugin.php")) {
                $plugins[] = $name;
            }
        }
    }
    return $plugins;
}

function get_plugin_sources($dir)
{
    $files = array();

    $dirs = new RecursiveDirectoryIterator($dir);
    $iter = new RecursiveIteratorIterator($dirs);
    foreach ($iter as $pathname => $item) {
        if ($item->isFile() && preg_match('/\.php$/', $item->getBaseName())) {
            $files[] = $pathname;
        }
    }
    return $files;
}

function plugin_using_gettext($dir)
{
    $files = get_plugin_sources($dir);
    foreach ($files as $pathname) {
        // Check if the file is using our _m gettext wrapper
        $code = file_get_contents($pathname);
        if (preg_match('/\b_m\(/', $code)) {
            return true;
        }
    }

    return false;
}

function update_plugin($basedir, $name)
{
    $dir = "$basedir/plugins/$name";
    if (plugin_using_gettext($dir)) {
        do_update_plugin($dir, $name);
        return true;
    } else {
        return false;
    }
}

$args = $_SERVER['argv'];
array_shift($args);

$all = false;
$core = false;
$allplugins = false;
$plugins = array();
if (count($args) == 0) {
    $all = true;
}
foreach ($args as $arg) {
    if ($arg == '--all') {
        $all = true;
    } elseif ($arg == "--core") {
        $core = true;
    } elseif ($arg == "--plugins") {
        $allplugins = true;
    } elseif (substr($arg, 0, 9) == "--plugin=") {
        $plugins[] = substr($arg, 9);
    } elseif ($arg == '--help') {
        echo "options: --all --core --plugins --plugin=Foo\n\n";
        exit(0);
    }
}

if ($all || $core) {
    echo "core...";
    update_core(INSTALLDIR, 'statusnet');
    echo " ok\n";
}
if ($all || $allplugins) {
    $plugins = get_plugins(INSTALLDIR);
}
if ($plugins) {
    foreach ($plugins as $plugin) {
        echo "$plugin...";
        if (update_plugin(INSTALLDIR, $plugin)) {
            echo " ok\n";
        } else {
            echo " not localized\n";
        }
    }
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Abort if called from a web server
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once(INSTALLDIR . '/lib/common.php');

// Master StatusNet .pot file location (created by update_pot.sh)
$statusnet_pot = INSTALLDIR . '/locale/statusnet.pot';

set_time_limit(60);

/* Languages to pull */
$languages = get_all_languages();

/* Update the languages */
// Language code conversion for translatewiki.net (these are MediaWiki codes)
$codeMap = array(
	'nb'    => 'no',
	'pt_BR' => 'pt-br',
	'zh_CN' => 'zh-hans',
	'zh_TW' => 'zh-hant'
);

$doneCodes = array();

foreach ($languages as $language) {
	$code = $language['lang'];

	// Skip export of source language
	// and duplicates
	if( $code == 'en' || $code == 'no' ) {
		continue;
	}

	// Do not export codes twice (happens for 'nb')
	if( in_array( $code, $doneCodes ) ) {
		continue;
	} else {
		$doneCodes[] = $code;
	}

	// Convert code if needed
	if( isset( $codeMap[$code] ) ) {
		$twnCode = $codeMap[$code];
	} else {
		$twnCode = str_replace('_', '-', strtolower($code)); // pt_BR -> pt-br
	}

    // Fetch updates from translatewiki.net...
    $file_url = 'http://translatewiki.net/w/i.php?' .
        http_build_query(array(
            'title' => 'Special:Translate',
            'task' => 'export-to-file',
            'group' => 'out-statusnet-core',
            'language' => $twnCode));

    $lcdir = INSTALLDIR . '/locale/' . $code;
    $msgdir = "$lcdir/LC_MESSAGES";
    $pofile = "$msgdir/statusnet.po";
    $mofile = "$msgdir/statusnet.mo";

    /* Check for an existing */
    if (!is_dir($msgdir)) {
        mkdir($lcdir);
        mkdir($msgdir);
        $existingSHA1 = '';
    } else {
        $existingSHA1 = file_exists($pofile) ? sha1_file($pofile) : '';
    }

    /* Get the remote one */
    $new_file = curl_get_file($file_url);

    if ($new_file === FALSE) {
        echo "Could not retrieve .po file for $code: $file_url\n";
        continue;
    }

    // Update if the local .po file is different to the one downloaded, or
    // if the .mo file is not present.
    if (sha1($new_file) != $existingSHA1 || !file_exists($mofile)) {
        echo "Updating ".$code."\n";
        file_put_contents($pofile, $new_file);
        // --backup=off is workaround for Mac OS X fail
        system(sprintf('msgmerge -U --backup=off %s %s', $pofile, $statusnet_pot));
        /* Do not rebuild/add .mo files by default
         * FIXME: should be made a command line parameter.
        system(sprintf('msgfmt -o %s %s', $mofile, $pofile));
         */
    } else {
        echo "Unchanged - ".$code."\n";
    }
}

echo "Finished\n";

function curl_get_file($url)
{
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_URL, $url);
    $contents = curl_exec($c);
    curl_close($c);

    if (!empty($contents)) {
        return $contents;
    }

    return FALSE;
}

repo_name: andremichelle/gnu

license: mit


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:af';
$longoptions = array('id=', 'nickname=', 'all', 'force');

$helptext = <<<END_OF_UPDATELOCATION_HELP
updatelocation.php [options]
set the location for a profile

  -i --id       ID of user to update
  -n --nickname nickname of the user to update
  -f --force    force update even if user already has a location
  -a --all      update all

END_OF_UPDATELOCATION_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

try {
    $user = null;

    if (have_option('i', 'id')) {
        $id = get_option_value('i', 'id');
        $user = User::getKV('id', $id);
        if (empty($user)) {
            throw new Exception("Can't find user with id '$id'.");
        }
        updateLocation($user);
    } else if (have_option('n', 'nickname')) {
        $nickname = get_option_value('n', 'nickname');
        $user = User::getKV('nickname', $nickname);
        if (empty($user)) {
            throw new Exception("Can't find user with nickname '$nickname'");
        }
        updateLocation($user);
    } else if (have_option('a', 'all')) {
        $user = new User();
        if ($user->find()) {
            while ($user->fetch()) {
                updateLocation($user);
            }
        }
    } else {
        show_help();
        exit(1);
    }
} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}

function updateLocation($user)
{
    $profile = $user->getProfile();

    if (empty($profile)) {
        throw new Exception("User has no profile: " . $user->nickname);
    }

    if (empty($profile->location)) {
        if (have_option('v', 'verbose')) {
            print "No location string for '".$user->nickname."'\n";
        }
        return;
    }

    if (!empty($profile->location_id) && !have_option('f', 'force')) {
        if (have_option('v', 'verbose')) {
            print "Location ID already set for '".$user->nickname."'\n";
        }
        return;
    }

    $loc = Location::fromName($profile->location);

    if (empty($loc)) {
        if (have_option('v', 'verbose')) {
            print "No structured location for string '".$profile->location."' for user '".$user->nickname."'\n";
        }
        return;
    } else {
        $orig = clone($profile);

        $profile->lat         = $loc->lat;
        $profile->lon         = $loc->lon;
        $profile->location_id = $loc->location_id;
        $profile->location_ns = $loc->location_ns;

        $result = $profile->update($orig);

        if (!$result) {
            common_log_db_error($profile, 'UPDATE', __FILE__);
        }

        if (!have_option('q', 'quiet')) {
            print "Location ID " . $profile->location_id . " set for user " . $user->nickname . "\n";
        }
    }

    $profile->free();
    unset($loc);
    unset($profile);

    return;
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008-2011, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = '';
$longoptions = array();

$helptext = <<<END_OF_UPDATEURLS_HELP
updateurls.php [options]
update stored URLs in the system

END_OF_UPDATEURLS_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

function main()
{
    updateUserUrls();
    updateGroupUrls();
}

function updateUserUrls()
{
    printfnq("Updating user URLs...\n");

    // XXX: only update user URLs where out-of-date

    $user = new User();
    if ($user->find()) {
        while ($user->fetch()) {
            printfv("Updating user {$user->nickname}...");
            try {
                $profile = $user->getProfile();

                updateProfileUrl($profile);
            } catch (Exception $e) {
                echo "Error updating URLs: " . $e->getMessage();
            }
            printfv("DONE.");
        }
    }
}

function updateProfileUrl($profile)
{
    $orig = clone($profile);
    $profile->profileurl = common_profile_url($profile->nickname);
    $profile->update($orig);
}

function updateGroupUrls()
{
    printfnq("Updating group URLs...\n");

    $group = new User_group();

    if ($group->find()) {
        while ($group->fetch()) {
            try {
                printfv("Updating group {$group->nickname}...");
                $orig = User_group::getKV('id', $group->id);
                if (!empty($group->original_logo)) {
                    $group->original_logo = Avatar::url(basename($group->original_logo));
                    $group->homepage_logo = Avatar::url(basename($group->homepage_logo));
                    $group->stream_logo = Avatar::url(basename($group->stream_logo));
                    $group->mini_logo = Avatar::url(basename($group->mini_logo));
                }
                // XXX: this is a hack to see if a group is local or not
                $localUri = common_local_url('groupbyid',
                                             array('id' => $group->id));
                if ($group->getUri() != $localUri) {
                    $group->mainpage = common_local_url('showgroup',
                                                        array('nickname' => $group->nickname));
                }
                $group->update($orig);
                printfv("DONE.");
            } catch (Exception $e) {
                echo "Can't update avatars for group " . $group->nickname . ": ". $e->getMessage();
            }
        }
    }
}

main();


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008-2011 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'dfx::';
$longoptions = array('debug', 'files', 'extensions=');

$helptext = <<<END_OF_UPGRADE_HELP
php upgrade.php [options]
Upgrade database schema and data to latest software

END_OF_UPGRADE_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (!defined('DEBUG')) {
    define('DEBUG', (bool)have_option('d', 'debug'));
}

function main()
{
    // "files" option enables possibly disk/resource intensive operations
    // that aren't really _required_ for the upgrade
    $iterate_files = (bool)have_option('f', 'files');

    if (Event::handle('StartUpgrade')) {
        fixupConversationURIs();

        updateSchemaCore();
        updateSchemaPlugins();

        // These replace old "fixup_*" scripts

        fixupNoticeConversation();
        initConversation();
        fixupGroupURI();
        if ($iterate_files) {
            printfnq("Running file iterations:\n");
            printfnq("* "); fixupFileGeometry();
            printfnq("* "); deleteLocalFileThumbnailsWithoutFilename();
            printfnq("* "); deleteMissingLocalFileThumbnails();
            printfnq("* "); fixupFileThumbnailUrlhash();
            printfnq("* "); setFilehashOnLocalFiles();
            printfnq("DONE.\n");
        } else {
            printfnq("Skipping intensive/long-running file iteration functions (enable with -f, should be done at least once!)\n");
        }

        initGroupProfileId();
        initLocalGroup();
        initNoticeReshare();

        initSubscriptionURI();
        initGroupMemberURI();

        initProfileLists();

        migrateProfilePrefs();

        Event::handle('EndUpgrade');
    }
}

function tableDefs()
{
	$schema = array();
	require INSTALLDIR.'/db/core.php';
	return $schema;
}

function updateSchemaCore()
{
    printfnq("Upgrading core schema...");

    $schema = Schema::get();
    $schemaUpdater = new SchemaUpdater($schema);
    foreach (tableDefs() as $table => $def) {
        $schemaUpdater->register($table, $def);
    }
    $schemaUpdater->checkSchema();

    printfnq("DONE.\n");
}

function updateSchemaPlugins()
{
    printfnq("Upgrading plugin schema...");

    Event::handle('BeforePluginCheckSchema');
    Event::handle('CheckSchema');

    printfnq("DONE.\n");
}

function fixupNoticeConversation()
{
    printfnq("Ensuring all notices have a conversation ID...");

    $notice = new Notice();
    $notice->whereAdd('conversation is null');
    $notice->whereAdd('conversation = 0', 'OR');
    $notice->orderBy('id'); // try to get originals before replies
    $notice->find();

    while ($notice->fetch()) {
        try {
            $cid = null;

            $orig = clone($notice);

            if (!empty($notice->reply_to)) {
                $reply = Notice::getKV('id', $notice->reply_to);

                if ($reply instanceof Notice && !empty($reply->conversation)) {
                    $notice->conversation = $reply->conversation;
                }
                unset($reply);
            }

            // if still empty
            if (empty($notice->conversation)) {
                $child = new Notice();
                $child->reply_to = $notice->getID();
                $child->limit(1);
                if ($child->find(true) && !empty($child->conversation)) {
                    $notice->conversation = $child->conversation;
                }
                unset($child);
            }

            // if _still_ empty we just create our own conversation
            if (empty($notice->conversation)) {
                $notice->conversation = $notice->getID();
            }

            $result = $notice->update($orig);

            unset($orig);
        } catch (Exception $e) {
            print("Error setting conversation: " . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function fixupGroupURI()
{
    printfnq("Ensuring all groups have an URI...");

    $group = new User_group();
    $group->whereAdd('uri IS NULL');

    if ($group->find()) {
        while ($group->fetch()) {
            $orig = User_group::getKV('id', $group->id);
            $group->uri = $group->getUri();
            $group->update($orig);
        }
    }

    printfnq("DONE.\n");
}

function initConversation()
{
    if (common_config('fix', 'upgrade_initConversation') <= 1) {
        printfnq(sprintf("Skipping %s, fixed by previous upgrade.\n", __METHOD__));
        return;
    }

    printfnq("Ensuring all conversations have a row in conversation table...");

    $notice = new Notice();
    $notice->selectAdd();
    $notice->selectAdd('DISTINCT conversation');
    $notice->joinAdd(['conversation', 'conversation:id'], 'LEFT');  // LEFT to get the null values for conversation.id
    $notice->whereAdd('conversation.id IS NULL');

    if ($notice->find()) {
        printfnq(" fixing {$notice->N} missing conversation entries...");
    }

    while ($notice->fetch()) {

        $id = $notice->conversation;

        $uri = common_local_url('conversation', array('id' => $id));

        // @fixme db_dataobject won't save our value for an autoincrement
        // so we're bypassing the insert wrappers
        $conv = new Conversation();
        $sql = "insert into conversation (id,uri,created) values(%d,'%s','%s')";
        $sql = sprintf($sql,
                       $id,
                       $conv->escape($uri),
                       $conv->escape(common_sql_now()));
        $conv->query($sql);
    }

    // This is something we should only have to do once unless introducing new, bad code.
    if (DEBUG) printfnq(sprintf('Storing in config that we have done %s', __METHOD__));
    common_config_set('fix', 'upgrade_initConversation', 1);

    printfnq("DONE.\n");
}

function fixupConversationURIs()
{
    printfnq("Ensuring all conversations have a URI...");

    $conv = new Conversation();
    $conv->whereAdd('uri IS NULL');

    if ($conv->find()) {
        $rounds = 0;
        while ($conv->fetch()) {
            $uri = common_local_url('conversation', array('id' => $conv->id));
            $sql = sprintf('UPDATE conversation SET uri="%1$s" WHERE id="%2$d";',
                            $conv->escape($uri), $conv->id);
            $conv->query($sql);
            if (($conv->N-++$rounds) % 500 == 0) {
                printfnq(sprintf(' %d items left...', $conv->N-$rounds));
            }
        }
    }

    printfnq("DONE.\n");
}

function initGroupProfileId()
{
    printfnq("Ensuring all User_group entries have a Profile and profile_id...");

    $group = new User_group();
    $group->whereAdd('NOT EXISTS (SELECT id FROM profile WHERE id = user_group.profile_id)');
    $group->find();

    while ($group->fetch()) {
        try {
            // We must create a new, incrementally assigned profile_id
            $profile = new Profile();
            $profile->nickname   = $group->nickname;
            $profile->fullname   = $group->fullname;
            $profile->profileurl = $group->mainpage;
            $profile->homepage   = $group->homepage;
            $profile->bio        = $group->description;
            $profile->location   = $group->location;
            $profile->created    = $group->created;
            $profile->modified   = $group->modified;

            $profile->query('BEGIN');
            $id = $profile->insert();
            if (empty($id)) {
                $profile->query('ROLLBACK');
                throw new Exception('Profile insertion failed, profileurl: '.$profile->profileurl);
            }
            $group->query("UPDATE user_group SET profile_id={$id} WHERE id={$group->id}");
            $profile->query('COMMIT');

            $profile->free();
        } catch (Exception $e) {
            printfv("Error initializing Profile for group {$group->nickname}:" . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function initLocalGroup()
{
    printfnq("Ensuring all local user groups have a local_group...");

    $group = new User_group();
    $group->whereAdd('NOT EXISTS (select group_id from local_group where group_id = user_group.id)');
    $group->find();

    while ($group->fetch()) {
        try {
            // Hack to check for local groups
            if ($group->getUri() == common_local_url('groupbyid', array('id' => $group->id))) {
                $lg = new Local_group();

                $lg->group_id = $group->id;
                $lg->nickname = $group->nickname;
                $lg->created  = $group->created; // XXX: common_sql_now() ?
                $lg->modified = $group->modified;

                $lg->insert();
            }
        } catch (Exception $e) {
            printfv("Error initializing local group for {$group->nickname}:" . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function initNoticeReshare()
{
    if (common_config('fix', 'upgrade_initNoticeReshare') <= 1) {
        printfnq(sprintf("Skipping %s, fixed by previous upgrade.\n", __METHOD__));
        return;
    }

    printfnq("Ensuring all reshares have the correct verb and object-type...");

    $notice = new Notice();
    $notice->whereAdd('repeat_of is not null');
    $notice->whereAdd('(verb != "'.ActivityVerb::SHARE.'" OR object_type != "'.ActivityObject::ACTIVITY.'")');

    if ($notice->find()) {
        while ($notice->fetch()) {
            try {
                $orig = Notice::getKV('id', $notice->id);
                $notice->verb = ActivityVerb::SHARE;
                $notice->object_type = ActivityObject::ACTIVITY;
                $notice->update($orig);
            } catch (Exception $e) {
                printfv("Error updating verb and object_type for {$notice->id}:" . $e->getMessage());
            }
        }
    }

    // This is something we should only have to do once unless introducing new, bad code.
    if (DEBUG) printfnq(sprintf('Storing in config that we have done %s', __METHOD__));
    common_config_set('fix', 'upgrade_initNoticeReshare', 1);

    printfnq("DONE.\n");
}

function initSubscriptionURI()
{
    printfnq("Ensuring all subscriptions have a URI...");

    $sub = new Subscription();
    $sub->whereAdd('uri IS NULL');

    if ($sub->find()) {
        while ($sub->fetch()) {
            try {
                $sub->decache();
                $sub->query(sprintf('update subscription '.
                                    'set uri = "%s" '.
                                    'where subscriber = %d '.
                                    'and subscribed = %d',
                                    $sub->escape(Subscription::newUri($sub->getSubscriber(), $sub->getSubscribed(), $sub->created)),
                                    $sub->subscriber,
                                    $sub->subscribed));
            } catch (Exception $e) {
                common_log(LOG_ERR, "Error updated subscription URI: " . $e->getMessage());
            }
        }
    }

    printfnq("DONE.\n");
}

function initGroupMemberURI()
{
    printfnq("Ensuring all group memberships have a URI...");

    $mem = new Group_member();
    $mem->whereAdd('uri IS NULL');

    if ($mem->find()) {
        while ($mem->fetch()) {
            try {
                $mem->decache();
                $mem->query(sprintf('update group_member set uri = "%s" '.
                                    'where profile_id = %d ' .
                                    'and group_id = %d ',
                                    Group_member::newUri(Profile::getByID($mem->profile_id), User_group::getByID($mem->group_id), $mem->created),
                                    $mem->profile_id,
                                    $mem->group_id));
            } catch (Exception $e) {
                common_log(LOG_ERR, "Error updated membership URI: " . $e->getMessage());
          }
        }
    }

    printfnq("DONE.\n");
}

function initProfileLists()
{
    printfnq("Ensuring all profile tags have a corresponding list...");

    $ptag = new Profile_tag();
    $ptag->selectAdd();
    $ptag->selectAdd('tagger, tag, count(*) as tagged_count');
    $ptag->whereAdd('NOT EXISTS (SELECT tagger, tagged from profile_list '.
                    'where profile_tag.tagger = profile_list.tagger '.
                    'and profile_tag.tag = profile_list.tag)');
    $ptag->groupBy('tagger, tag');
    $ptag->orderBy('tagger, tag');

    if ($ptag->find()) {
        while ($ptag->fetch()) {
            $plist = new Profile_list();

            $plist->tagger   = $ptag->tagger;
            $plist->tag      = $ptag->tag;
            $plist->private  = 0;
            $plist->created  = common_sql_now();
            $plist->modified = $plist->created;
            $plist->mainpage = common_local_url('showprofiletag',
                                                array('tagger' => $plist->getTagger()->nickname,
                                                      'tag'    => $plist->tag));;

            $plist->tagged_count     = $ptag->tagged_count;
            $plist->subscriber_count = 0;

            $plist->insert();

            $orig = clone($plist);
            // After insert since it uses auto-generated ID
            $plist->uri      = common_local_url('profiletagbyid',
                                        array('id' => $plist->id, 'tagger_id' => $plist->tagger));

            $plist->update($orig);
        }
    }

    printfnq("DONE.\n");
}

/*
 * Added as we now store interpretd width and height in File table.
 */
function fixupFileGeometry()
{
    printfnq("Ensuring width and height is set for supported local File objects...");

    $file = new File();
    $file->whereAdd('filename IS NOT NULL');    // local files
    $file->whereAdd('width IS NULL OR width = 0');

    if ($file->find()) {
        while ($file->fetch()) {
            if (DEBUG) printfnq(sprintf('Found file without width: %s\n', _ve($file->getFilename())));

            // Set file geometrical properties if available
            try {
                $image = ImageFile::fromFileObject($file);
            } catch (ServerException $e) {
                // We couldn't make out an image from the file.
                if (DEBUG) printfnq(sprintf('Could not make an image out of the file.\n'));
                continue;
            }
            $orig = clone($file);
            $file->width = $image->width;
            $file->height = $image->height;
            if (DEBUG) printfnq(sprintf('Setting image file and with to %sx%s.\n', $file->width, $file->height));
            $file->update($orig);

            // FIXME: Do this more automagically inside ImageFile or so.
            if ($image->getPath() != $file->getPath()) {
                if (DEBUG) printfnq(sprintf('Deleting the temporarily stored ImageFile.\n'));
                $image->unlink();
            }
            unset($image);
        }
    }

    printfnq("DONE.\n");
}

/*
 * File_thumbnail objects for local Files store their own filenames in the database.
 */
function deleteLocalFileThumbnailsWithoutFilename()
{
    printfnq("Removing all local File_thumbnail entries without filename property...");

    $file = new File();
    $file->whereAdd('filename IS NOT NULL');    // local files

    if ($file->find()) {
        // Looping through local File entries
        while ($file->fetch()) {
            $thumbs = new File_thumbnail();
            $thumbs->file_id = $file->id;
            $thumbs->whereAdd('filename IS NULL OR filename = ""');
            // Checking if there were any File_thumbnail entries without filename
            if (!$thumbs->find()) {
                continue;
            }
            // deleting incomplete entry to allow regeneration
            while ($thumbs->fetch()) {
                $thumbs->delete();
            }
        }
    }

    printfnq("DONE.\n");
}

/*
 * Delete File_thumbnail entries where the referenced file does not exist.
 */
function deleteMissingLocalFileThumbnails()
{
    printfnq("Removing all local File_thumbnail entries without existing files...");

    $thumbs = new File_thumbnail();
    $thumbs->whereAdd('filename IS NOT NULL AND filename != ""');
    // Checking if there were any File_thumbnail entries without filename
    if ($thumbs->find()) {
        while ($thumbs->fetch()) {
            try {
                $thumbs->getPath();
            } catch (FileNotFoundException $e) {
                $thumbs->delete();
            }
        }
    }

    printfnq("DONE.\n");
}

/*
 * Files are now stored with their hash, so let's generate for previously uploaded files.
 */
function setFilehashOnLocalFiles()
{
    printfnq('Ensuring all local files have the filehash field set...');

    $file = new File();
    $file->whereAdd('filename IS NOT NULL AND filename != ""');        // local files
    $file->whereAdd('filehash IS NULL', 'AND');     // without filehash value

    if ($file->find()) {
        while ($file->fetch()) {
            try {
                $orig = clone($file);
                $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath());
                $file->update($orig);
            } catch (FileNotFoundException $e) {
                echo "\n    WARNING: file ID {$file->id} does not exist on path '{$e->path}'. If there is no file system error, run: php scripts/clean_file_table.php";
            }
        }
    }

    printfnq("DONE.\n");
}

function fixupFileThumbnailUrlhash()
{
    printfnq("Setting urlhash for File_thumbnail entries: ");

    $thumb = new File_thumbnail();
    $thumb->query('UPDATE '.$thumb->escapedTableName().' SET urlhash=SHA2(url, 256) WHERE'.
                    ' url IS NOT NULL AND'. // find all entries with a url value
                    ' url != "" AND'.       // precaution against non-null empty strings
                    ' urlhash IS NULL');    // but don't touch those we've already calculated

    printfnq("DONE.\n");
}

function migrateProfilePrefs()
{
    printfnq("Finding and possibly migrating Profile_prefs entries: ");

    $prefs = array();   // ['qvitter' => ['cover_photo'=>'profile_banner_url', ...], ...]
    Event::handle('GetProfilePrefsMigrations', array(&$prefs));

    foreach($prefs as $namespace=>$mods) {
        echo "$namespace... ";
        assert(is_array($mods));
        $p = new Profile_prefs();
        $p->namespace = $namespace;
        // find all entries in all modified topics given in this namespace
        $p->whereAddIn('topic', array_keys($mods), $p->columnType('topic'));
        $p->find();
        while ($p->fetch()) {
            // for each entry, update 'topic' to the new key value
            $orig = clone($p);
            $p->topic = $mods[$p->topic];
            $p->updateWithKeys($orig);
        }
    }

    printfnq("DONE.\n");
}

main();


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:e:';
$longoptions = array('id=', 'nickname=', 'email=');

$helptext = <<<END_OF_USEREMAIL_HELP
useremail.php [options]
Queries a user's registered email address, or queries the users with a given registered email.

  -i --id       id of the user to query
  -n --nickname nickname of the user to query
  -e --email    email address to query

END_OF_USEREMAIL_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (have_option('i', 'id')) {
    $id = get_option_value('i', 'id');
    $user = User::getKV('id', $id);
    if (empty($user)) {
        print "Can't find user with ID $id\n";
        exit(1);
    }
} else if (have_option('n', 'nickname')) {
    $nickname = get_option_value('n', 'nickname');
    $user = User::getKV('nickname', $nickname);
    if (empty($user)) {
        print "Can't find user with nickname '$nickname'\n";
        exit(1);
    }
}

if (!empty($user)) {
    if (empty($user->email)) {
        // Check for unconfirmed emails
        $unconfirmed_email = new Confirm_address();
        $unconfirmed_email->user_id = $user->id;
        $unconfirmed_email->address_type = 'email';
        $unconfirmed_email->find(true);

        if (empty($unconfirmed_email->address)) {
            print "No email registered for user '$user->nickname'\n";
        } else {
            print "Unconfirmed Adress: $unconfirmed_email->address\n";
        }
    } else {
        print "$user->email\n";
    }
    exit(0);
}

if (have_option('e', 'email')) {
    $user = new User();
    $user->email = get_option_value('e', 'email');
    $user->find(false);
    if (!$user->fetch()) {
        // Check unconfirmed emails
        $unconfirmed_email = new Confirm_address();
        $unconfirmed_email->address = $user->email;
        $unconfirmed_email->address_type = 'email';
        $unconfirmed_email->find(true);

        if (empty($unconfirmed_email->user_id)) {
            print "No users with email $user->email\n";
        } else {
            $user=User::getKV('id', $unconfirmed_email->user_id);
            print "Unconfirmed Address: $user->id $user->nickname\n";
        }
        exit(0);
    }
    do {
        print "$user->id $user->nickname\n";
    } while ($user->fetch());
} else {
    print "You must provide either an ID, email, or a nickname.\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:r:d';
$longoptions = array('id=', 'nickname=', 'role=', 'delete');

$helptext = <<<END_OF_USERROLE_HELP
userrole.php [options]
modifies a role for the given user

Available roles: owner moderator administrator sandboxed silenced deleted

  -d --delete   delete the role
  -i --id       ID of the user
  -n --nickname nickname of the user
  -r --role     role to add (or delete)

END_OF_USERROLE_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (have_option('i', 'id')) {
    $id = get_option_value('i', 'id');
    $profile = Profile::getKV('id', $id);
    if (empty($profile)) {
        print "Can't find user with ID $id\n";
        exit(1);
    }
} else if (have_option('n', 'nickname')) {
    $nickname = get_option_value('n', 'nickname');
    $user = User::getKV('nickname', $nickname);
    if (empty($user)) {
        print "Can't find user with nickname '$nickname'\n";
        exit(1);
    }
    $profile = $user->getProfile();
    if (empty($profile)) {
        print "User with ID $id has no profile\n";
        exit(1);
    }
} else {
    print "You must provide either an ID or a nickname.\n";
    exit(1);
}

$role = get_option_value('r', 'role');

if (empty($role)) {
    print "You must provide a role.\n";
    exit(1);
}

if (have_option('d', 'delete')) {
    print "Revoking role '$role' from user '$profile->nickname' ($profile->id)...";
    try {
        $profile->revokeRole($role);
        print "OK\n";
    } catch (Exception $e) {
        print "FAIL\n";
        print $e->getMessage();
        print "\n";
    }
} else {
    print "Granting role '$role' to user '$profile->nickname' ($profile->id)...";
    try {
        $profile->grantRole($role);
        print "OK\n";
    } catch (Exception $e) {
        print "FAIL\n";
        print $e->getMessage();
        print "\n";
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

// XXX: we should probably have some common source for this stuff

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

class ActivityGenerationTests extends PHPUnit_Framework_TestCase
{
    static $author1 = null;
    static $author2 = null;

    static $targetUser1 = null;
    static $targetUser2 = null;

    static $targetGroup1 = null;
    static $targetGroup2 = null;

    public static function setUpBeforeClass()
    {
        $authorNick1 = 'activitygenerationtestsuser' . common_random_hexstr(4);
        $authorNick2 = 'activitygenerationtestsuser' . common_random_hexstr(4);

        $targetNick1 = 'activitygenerationteststarget' . common_random_hexstr(4);
        $targetNick2 = 'activitygenerationteststarget' . common_random_hexstr(4);

        $groupNick1 = 'activitygenerationtestsgroup' . common_random_hexstr(4);
        $groupNick2 = 'activitygenerationtestsgroup' . common_random_hexstr(4);

        try{
        	self::$author1 = User::register(array('nickname' => $authorNick1,
                                              'email' => $authorNick1 . '@example.net',
                                              'email_confirmed' => true));

        	self::$author2 = User::register(array('nickname' => $authorNick2,
                                              'email' => $authorNick2 . '@example.net',
                                              'email_confirmed' => true));

        	self::$targetUser1 = User::register(array('nickname' => $targetNick1,
                                                  'email' => $targetNick1 . '@example.net',
                                                  'email_confirmed' => true));

        	self::$targetUser2 = User::register(array('nickname' => $targetNick2,
                                                  'email' => $targetNick2 . '@example.net',
                                                  'email_confirmed' => true));

        	self::$targetGroup1 = User_group::register(array('nickname' => $groupNick1,
                                                         'userid' => self::$author1->id,
                                                         'aliases' => array(),
                                                         'local' => true,
                                                         'location' => null,
                                                         'description' => null,
                                                         'fullname' => null,
                                                         'homepage' => null,
                                                         'mainpage' => null));
        	self::$targetGroup2 = User_group::register(array('nickname' => $groupNick2,
                                                         'userid' => self::$author1->id,
                                                         'aliases' => array(),
                                                         'local' => true,
                                                         'location' => null,
                                                         'description' => null,
                                                         'fullname' => null,
                                                         'homepage' => null,
                                                         'mainpage' => null));
        } catch (Exception $e) {
        	self::tearDownAfterClass();
        	throw $e;
        }
    }

    public function testBasicNoticeActivity()
    {
        $notice = $this->_fakeNotice();

        $entry = $notice->asAtomEntry(true);

        $element = $this->_entryToElement($entry, false);

        $this->assertEquals($notice->getUri(), ActivityUtils::childContent($element, 'id'));
        $this->assertEquals('New note by '. self::$author1->nickname, ActivityUtils::childContent($element, 'title'));
        $this->assertEquals($notice->rendered, ActivityUtils::childContent($element, 'content'));
        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'published')));
        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'updated')));
        $this->assertEquals(ActivityVerb::POST, ActivityUtils::childContent($element, 'verb', Activity::SPEC));
        $this->assertEquals(ActivityObject::NOTE, ActivityUtils::childContent($element, 'object-type', Activity::SPEC));
    }

    public function testNamespaceFlag()
    {
        $notice = $this->_fakeNotice();

        $entry = $notice->asAtomEntry(true);

        $element = $this->_entryToElement($entry, false);

        $this->assertTrue($element->hasAttribute('xmlns'));
        $this->assertTrue($element->hasAttribute('xmlns:thr'));
        $this->assertTrue($element->hasAttribute('xmlns:georss'));
        $this->assertTrue($element->hasAttribute('xmlns:activity'));
        $this->assertTrue($element->hasAttribute('xmlns:media'));
        $this->assertTrue($element->hasAttribute('xmlns:poco'));
        $this->assertTrue($element->hasAttribute('xmlns:ostatus'));
        $this->assertTrue($element->hasAttribute('xmlns:statusnet'));

        $entry = $notice->asAtomEntry(false);

        $element = $this->_entryToElement($entry, true);

        $this->assertFalse($element->hasAttribute('xmlns'));
        $this->assertFalse($element->hasAttribute('xmlns:thr'));
        $this->assertFalse($element->hasAttribute('xmlns:georss'));
        $this->assertFalse($element->hasAttribute('xmlns:activity'));
        $this->assertFalse($element->hasAttribute('xmlns:media'));
        $this->assertFalse($element->hasAttribute('xmlns:poco'));
        $this->assertFalse($element->hasAttribute('xmlns:ostatus'));
        $this->assertFalse($element->hasAttribute('xmlns:statusnet'));
    }

    public function testSourceFlag()
    {
        $notice = $this->_fakeNotice();

        // Test with no source

        $entry = $notice->asAtomEntry(false, false);

        $element = $this->_entryToElement($entry, true);

        $source = ActivityUtils::child($element, 'source');

        $this->assertNull($source);

        // Test with source

        $entry = $notice->asAtomEntry(false, true);

        $element = $this->_entryToElement($entry, true);

        $source = ActivityUtils::child($element, 'source');

        $this->assertNotNull($source);
    }

    public function testSourceContent()
    {
        $notice = $this->_fakeNotice();
        // make a time difference!
        sleep(2);
        $notice2 = $this->_fakeNotice();

        $entry = $notice->asAtomEntry(false, true);

        $element = $this->_entryToElement($entry, true);

        $source = ActivityUtils::child($element, 'source');

        $atomUrl = common_local_url('ApiTimelineUser', array('id' => self::$author1->id, 'format' => 'atom'));

        $profile = self::$author1->getProfile();

        $this->assertEquals($atomUrl, ActivityUtils::childContent($source, 'id'));
        $this->assertEquals($atomUrl, ActivityUtils::getLink($source, 'self', 'application/atom+xml'));
        $this->assertEquals($profile->profileurl, ActivityUtils::getPermalink($source));
        $this->assertEquals(strtotime($notice2->created), strtotime(ActivityUtils::childContent($source, 'updated')));
        // XXX: do we care here?
        $this->assertFalse(is_null(ActivityUtils::childContent($source, 'title')));
        $this->assertEquals(common_config('license', 'url'), ActivityUtils::getLink($source, 'license'));
    }

    public function testAuthorFlag()
    {
        $notice = $this->_fakeNotice();

        // Test with no author

        $entry = $notice->asAtomEntry(false, false, false);

        $element = $this->_entryToElement($entry, true);

        $this->assertNull(ActivityUtils::child($element, 'author'));
        $this->assertNull(ActivityUtils::child($element, 'actor', Activity::SPEC));

        // Test with source

        $entry = $notice->asAtomEntry(false, false, true);

        $element = $this->_entryToElement($entry, true);

        $author = ActivityUtils::child($element, 'author');
        $actor  = ActivityUtils::child($element, 'actor', Activity::SPEC);

        $this->assertFalse(is_null($author));
        $this->assertTrue(is_null($actor)); // <activity:actor> is obsolete, no longer added
    }

    public function testAuthorContent()
    {
        $notice = $this->_fakeNotice();

        // Test with author

        $entry = $notice->asAtomEntry(false, false, true);

        $element = $this->_entryToElement($entry, true);

        $author = ActivityUtils::child($element, 'author');

        $this->assertEquals(self::$author1->getNickname(), ActivityUtils::childContent($author, 'name'));
        $this->assertEquals(self::$author1->getUri(), ActivityUtils::childContent($author, 'uri'));
    }

    /**
     * We no longer create <activity:actor> entries, they have merged to <atom:author>
     */
    public function testActorContent()
    {
        $notice = $this->_fakeNotice();

        // Test with author

        $entry = $notice->asAtomEntry(false, false, true);

        $element = $this->_entryToElement($entry, true);

        $actor = ActivityUtils::child($element, 'actor', Activity::SPEC);

        $this->assertEquals($actor, null);
    }

    public function testReplyLink()
    {
        $orig = $this->_fakeNotice(self::$targetUser1);

        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);

        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));

        $entry = $reply->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $irt = ActivityUtils::child($element, 'in-reply-to', 'http://purl.org/syndication/thread/1.0');

        $this->assertNotNull($irt);
        $this->assertEquals($orig->getUri(), $irt->getAttribute('ref'));
        $this->assertEquals($orig->getUrl(), $irt->getAttribute('href'));
    }

    public function testReplyAttention()
    {
        $orig = $this->_fakeNotice(self::$targetUser1);

        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);

        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));

        $entry = $reply->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $this->assertEquals(self::$targetUser1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
    }

    public function testMultipleReplyAttention()
    {
        $orig = $this->_fakeNotice(self::$targetUser1);

        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);

        $reply = Notice::saveNew(self::$targetUser2->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));

        $text = "@" . self::$targetUser1->nickname . " @" . self::$targetUser2->nickname . " reply text " . common_random_hexstr(4);

        $reply2 = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $reply->id));

        $entry = $reply2->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $links = ActivityUtils::getLinks($element, 'mentioned');

        $hrefs = array();

        foreach ($links as $link) {
            $hrefs[] = $link->getAttribute('href');
        }

        $this->assertTrue(in_array(self::$targetUser1->getUri(), $hrefs));
        $this->assertTrue(in_array(self::$targetUser2->getUri(), $hrefs));
    }

    public function testGroupPostAttention()
    {
        $text = "!" . self::$targetGroup1->nickname . " reply text " . common_random_hexstr(4);

        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $this->assertEquals(self::$targetGroup1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
    }

    public function testMultipleGroupPostAttention()
    {
        $text = "!" . self::$targetGroup1->nickname . " !" . self::$targetGroup2->nickname . " reply text " . common_random_hexstr(4);

        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $links = ActivityUtils::getLinks($element, 'mentioned');

        $hrefs = array();

        foreach ($links as $link) {
            $hrefs[] = $link->getAttribute('href');
        }

        $this->assertTrue(in_array(self::$targetGroup1->getUri(), $hrefs));
        $this->assertTrue(in_array(self::$targetGroup2->getUri(), $hrefs));

    }

    public function testRepeatLink()
    {
        $notice = $this->_fakeNotice(self::$author1);
        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');

        $entry = $repeat->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', 'http://status.net/schema/api/1/');

        $this->assertNotNull($noticeInfo);
        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
        $this->assertEquals($repeat->id, $noticeInfo->getAttribute('local_id'));
    }

    public function testTag()
    {
        $tag1 = common_random_hexstr(4);

        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1);

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $category = ActivityUtils::child($element, 'category');

        $this->assertNotNull($category);
        $this->assertEquals($tag1, $category->getAttribute('term'));
    }

    public function testMultiTag()
    {
        $tag1 = common_random_hexstr(4);
        $tag2 = common_random_hexstr(4);

        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1 . ' #' . $tag2);

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $categories = $element->getElementsByTagName('category');

        $this->assertNotNull($categories);
        $this->assertEquals(2, $categories->length);

        $terms = array();

        for ($i = 0; $i < $categories->length; $i++) {
            $cat = $categories->item($i);
            $terms[] = $cat->getAttribute('term');
        }

        $this->assertTrue(in_array($tag1, $terms));
        $this->assertTrue(in_array($tag2, $terms));
    }

    public function testGeotaggedActivity()
    {
        $notice = Notice::saveNew(self::$author1->id, common_random_hexstr(4), 'test', array('uri' => null, 'lat' => 45.5, 'lon' => -73.6));

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $this->assertEquals('45.5000000 -73.6000000', ActivityUtils::childContent($element, 'point', "http://www.georss.org/georss"));
    }

    public function testNoticeInfo()
    {
        $notice = $this->_fakeNotice();

        $entry = $notice->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals($notice->id, $noticeInfo->getAttribute('local_id'));
        $this->assertEquals($notice->source, $noticeInfo->getAttribute('source'));
        $this->assertEquals('', $noticeInfo->getAttribute('repeat_of'));
        $this->assertEquals('', $noticeInfo->getAttribute('repeated'));
//        $this->assertEquals('', $noticeInfo->getAttribute('favorite'));
        $this->assertEquals('', $noticeInfo->getAttribute('source_link'));
    }

    public function testNoticeInfoRepeatOf()
    {
        $notice = $this->_fakeNotice();

        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');

        $entry = $repeat->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
    }

    public function testNoticeInfoRepeated()
    {
        $notice = $this->_fakeNotice();

        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');

        $entry = $notice->asAtomEntry(false, false, false, self::$author2->getProfile());

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals('true', $noticeInfo->getAttribute('repeated'));

        $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1->getProfile());

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals('false', $noticeInfo->getAttribute('repeated'));
    }

/*    public function testNoticeInfoFave()
    {
        $notice = $this->_fakeNotice();

        $fave = Fave::addNew(self::$author2->getProfile(), $notice);

        // Should be set if user has faved

        $entry = $notice->asAtomEntry(false, false, false, self::$author2);

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals('true', $noticeInfo->getAttribute('favorite'));

        // Shouldn't be set if user has not faved

        $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1);

        $element = $this->_entryToElement($entry, true);

        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");

        $this->assertEquals('false', $noticeInfo->getAttribute('favorite'));
    }*/

    public function testConversationLink()
    {
        $orig = $this->_fakeNotice(self::$targetUser1);

        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);

        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));

        $conv = Conversation::getKV('id', $reply->conversation);

        $entry = $reply->asAtomEntry();

        $element = $this->_entryToElement($entry, true);

        $this->assertEquals($conv->getUrl(), ActivityUtils::getLink($element, 'ostatus:conversation'));
    }

    public static function tearDownAfterClass()
    {
        if (!is_null(self::$author1)) {
            self::$author1->getProfile()->delete();
        }

        if (!is_null(self::$author2)) {
            self::$author2->getProfile()->delete();
        }

        if (!is_null(self::$targetUser1)) {
            self::$targetUser1->getProfile()->delete();
        }

        if (!is_null(self::$targetUser2)) {
            self::$targetUser2->getProfile()->delete();
        }

        if (!is_null(self::$targetGroup1)) {
            self::$targetGroup1->delete();
        }

        if (!is_null(self::$targetGroup2)) {
            self::$targetGroup2->delete();
        }
    }

    private function _fakeNotice($user = null, $text = null)
    {
        if (empty($user)) {
            $user = self::$author1;
        }

        if (empty($text)) {
            $text = "fake-o text-o " . common_random_hexstr(32);
        }

        return Notice::saveNew($user->id, $text, 'test', array('uri' => null));
    }

    private function _entryToElement($entry, $namespace = false)
    {
        $xml = '<?xml version="1.0" encoding="utf-8"?>'."\n\n";
        $xml .= '<feed';
        if ($namespace) {
            $xml .= ' xmlns="http://www.w3.org/2005/Atom"';
            $xml .= ' xmlns:thr="http://purl.org/syndication/thread/1.0"';
            $xml .= ' xmlns:georss="http://www.georss.org/georss"';
            $xml .= ' xmlns:activity="http://activitystrea.ms/spec/1.0/"';
            $xml .= ' xmlns:media="http://purl.org/syndication/atommedia"';
            $xml .= ' xmlns:poco="http://portablecontacts.net/spec/1.0"';
            $xml .= ' xmlns:ostatus="http://ostatus.org/schema/1.0"';
            $xml .= ' xmlns:statusnet="http://status.net/schema/api/1/"';
        }
        $xml .= '>' . "\n" . $entry . "\n" . '</feed>' . "\n";
        $doc = DOMDocument::loadXML($xml);
        $feed = $doc->documentElement;
        $entries = $feed->getElementsByTagName('entry');

        return $entries->item(0);
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

class CommandInterpreterTest extends PHPUnit_Framework_TestCase
{

    /**
     * @dataProvider commandInterpreterCases
     */
    public function testCommandInterpreter($input, $expectedType, $comment='')
    {
        $inter = new CommandInterpreter();

        $cmd = $inter->handle_command(null, $input);

        $type = $cmd ? get_class($cmd) : null;
        $this->assertEquals(strtolower($expectedType), strtolower($type), $comment);
    }

    static public function commandInterpreterCases()
    {
        $sets = array(
            array('help', 'HelpCommand'),
            array('help me bro', null, 'help does not accept multiple params'),
            array('HeLP', 'HelpCommand', 'case check'),
            array('HeLP Me BRO!', null, 'case & non-params check'),

            array('login', 'LoginCommand'),
            array('login to savings!', null, 'login does not accept params'),

            array('lose', null, 'lose must have at least 1 parameter'),
            array('lose foobar', 'LoseCommand', 'lose requires 1 parameter'),
            array('lose        foobar', 'LoseCommand', 'check for space norm'),
            array('lose more weight', null, 'lose does not accept multiple params'),

            array('subscribers', 'SubscribersCommand'),
            array('subscribers foo', null, 'subscribers does not take params'),

            array('subscriptions', 'SubscriptionsCommand'),
            array('subscriptions foo', null, 'subscriptions does not take params'),

            array('groups', 'GroupsCommand'),
            array('groups foo', null, 'groups does not take params'),

            array('off', 'OffCommand', 'off accepts 0 or 1 params'),
            array('off foo', 'OffCommand', 'off accepts 0 or 1 params'),
            array('off foo bar', null, 'off accepts 0 or 1 params'),

            array('stop', 'OffCommand', 'stop accepts 0 params'),
            array('stop foo', null, 'stop accepts 0 params'),

            array('quit', 'OffCommand', 'quit accepts 0 params'),
            array('quit foo', null, 'quit accepts 0 params'),

            array('on', 'OnCommand', 'on accepts 0 or 1 params'),
            array('on foo', 'OnCommand', 'on accepts 0 or 1 params'),
            array('on foo bar', null, 'on accepts 0 or 1 params'),

            array('join', null),
            array('join foo', 'JoinCommand'),
            array('join foo bar', null),

            array('drop', null),
            array('drop foo', 'DropCommand'),
            array('drop foo bar', null),

            array('follow', null),
            array('follow foo', 'SubCommand'),
            array('follow foo bar', null),

            array('sub', null),
            array('sub foo', 'SubCommand'),
            array('sub foo bar', null),

            array('leave', null),
            array('leave foo', 'UnsubCommand'),
            array('leave foo bar', null),

            array('unsub', null),
            array('unsub foo', 'UnsubCommand'),
            array('unsub foo bar', null),

            array('leave', null),
            array('leave foo', 'UnsubCommand'),
            array('leave foo bar', null),

            array('d', null),
            array('d foo', null),
            array('d foo bar', 'MessageCommand'),

            array('dm', null),
            array('dm foo', null),
            array('dm foo bar', 'MessageCommand'),

            array('r', null),
            array('r foo', null),
            array('r foo bar', 'ReplyCommand'),

            array('reply', null),
            array('reply foo', null),
            array('reply foo bar', 'ReplyCommand'),

            array('repeat', null),
            array('repeat foo', 'RepeatCommand'),
            array('repeat foo bar', null),

            array('rp', null),
            array('rp foo', 'RepeatCommand'),
            array('rp foo bar', null),

            array('rt', null),
            array('rt foo', 'RepeatCommand'),
            array('rt foo bar', null),

            array('rd', null),
            array('rd foo', 'RepeatCommand'),
            array('rd foo bar', null),

            array('whois', null),
            array('whois foo', 'WhoisCommand'),
            array('whois foo bar', null),

/*            array('fav', null),
            array('fav foo', 'FavCommand'),
            array('fav foo bar', null),*/

            array('nudge', null),
            array('nudge foo', 'NudgeCommand'),
            array('nudge foo bar', null),

            array('stats', 'StatsCommand'),
            array('stats foo', null),

            array('invite', null),
            array('invite foo', 'InviteCommand'),
            array('invite foo bar', null),

            array('track', null),
            array('track foo', 'SearchSubTrackCommand'),
            array('track off', 'SearchSubTrackOffCommand'),
            array('track foo bar', null),
            array('track off foo', null),

            array('untrack', null),
            array('untrack foo', 'SearchSubUntrackCommand'),
            array('untrack all', 'SearchSubTrackOffCommand'),
            array('untrack foo bar', null),
            array('untrack all foo', null),

            array('tracking', 'SearchSubTrackingCommand'),
            array('tracking foo', null),

            array('tracks', 'SearchSubTrackingCommand'),
            array('tracks foo', null),

        );
        return $sets;
    }

}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

class CurryTest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider provider
     *
     */
    public function testProduction($callback, $curry_params, $call_params, $expected)
    {
        $params = array_merge(array($callback), $curry_params);
        $curried = call_user_func_array('curry', $params);
        $result = call_user_func_array($curried, $call_params);
        $this->assertEquals($expected, $result);
    }

    static public function provider()
    {
        $obj = new CurryTestHelperObj('oldval');
        return array(array(array('CurryTest', 'callback'),
                           array('curried'),
                           array('called'),
                           'called|curried'),
                     array(array('CurryTest', 'callback'),
                           array('curried1', 'curried2'),
                           array('called1', 'called2'),
                           'called1|called2|curried1|curried2'),
                     array(array('CurryTest', 'callbackObj'),
                           array($obj),
                           array('newval1'),
                           'oldval|newval1'),
                     // Confirm object identity is retained...
                     array(array('CurryTest', 'callbackObj'),
                           array($obj),
                           array('newval2'),
                           'newval1|newval2'));
    }

    static function callback()
    {
        $args = func_get_args();
        return implode("|", $args);
    }

    static function callbackObj($val, $obj)
    {
        $old = $obj->val;
        $obj->val = $val;
        return "$old|$val";
    }
}

class CurryTestHelperObj
{
    public $val='';

    function __construct($val)
    {
        $this->val = $val;
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

class HashTagDetectionTests extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider provider
     *
     */
    public function testProduction($content, $expected)
    {
        $rendered = common_render_text($content);
        $this->assertEquals($expected, $rendered);
    }

    static public function provider()
    {
        return array(
                     array('hello',
                           'hello'),
                     array('#hello people',
                           '# common_canonical_tag('hello'))) . '" rel="tag">hello people'),
                     array('"#hello" people',
                           '"# common_canonical_tag('hello'))) . '" rel="tag">hello" people'),
                     array('say "#hello" people',
                           'say "# common_canonical_tag('hello'))) . '" rel="tag">hello" people'),
                     array('say (#hello) people',
                           'say (# common_canonical_tag('hello'))) . '" rel="tag">hello) people'),
                     array('say [#hello] people',
                           'say [# common_canonical_tag('hello'))) . '" rel="tag">hello] people'),
                     array('say {#hello} people',
                           'say {# common_canonical_tag('hello'))) . '" rel="tag">hello} people'),
                     array('say \'#hello\' people',
                           'say \'# common_canonical_tag('hello'))) . '" rel="tag">hello\' people'),

                     // Unicode legit letters
                     array('#éclair yummy',
                           '# common_canonical_tag('éclair'))) . '" rel="tag">éclair yummy'),
                     array('#维基百科 zh.wikipedia!',
                           '# common_canonical_tag('维基百科'))) . '" rel="tag">维基百科 zh.wikipedia!'),
                     array('#Россия russia',
                           '# common_canonical_tag('Россия'))) . '" rel="tag">Россия russia'),

                     // Unicode punctuators -- the ideographic "，" separates the tag, just as "," does
                     array('#维基百科,zh.wikipedia!',
                           '# common_canonical_tag('维基百科'))) . '" rel="tag">维基百科,zh.wikipedia!'),
                     array('#维基百科，zh.wikipedia!',
                           '# common_canonical_tag('维基百科'))) . '" rel="tag">维基百科，zh.wikipedia!'),

                     );
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

// Make sure this is loaded
// XXX: how to test other plugins...?

addPlugin('Geonames');

class LocationTest extends PHPUnit_Framework_TestCase
{

    /**
     * @dataProvider locationNames
     */

    public function testLocationFromName($name, $language, $location)
    {
        $result = Location::fromName($name, $language);
        $this->assertEquals($result, $location);
    }

    static public function locationNames()
    {
        return array(array('Montreal', 'en', null),
                     array('San Francisco, CA', 'en', null),
                     array('Paris, France', 'en', null),
                     array('Paris, Texas', 'en', null));
    }

    /**
     * @dataProvider locationIds
     */

    public function testLocationFromId($id, $ns, $language, $location)
    {
        $result = Location::fromId($id, $ns, $language);
        $this->assertEquals($result, $location);
    }

    static public function locationIds()
    {
        return array(array(6077243, GeonamesPlugin::LOCATION_NS, 'en', null),
                     array(5391959, GeonamesPlugin::LOCATION_NS, 'en', null));
    }

    /**
     * @dataProvider locationLatLons
     */

    public function testLocationFromLatLon($lat, $lon, $language, $location)
    {
        $result = Location::fromLatLon($lat, $lon, $language);
        $this->assertEquals($location, $result->location_id);
    }

    static public function locationLatLons()
    {
        return array(array(37.77493, -122.41942, 'en', null),
                     array(45.509, -73.588, 'en', null));
    }

    /**
     * @dataProvider nameOfLocation
     */

    public function testLocationGetName($location, $language, $name)
    {
        $result = empty($location)?null:$location->getName($language);
        $this->assertEquals($name, $result);
    }

    static public function nameOfLocation()
    {
        $loc = Location::fromName('Montreal', 'en');
        return array(array($loc, 'en', null), //'Montreal'),
                     array($loc, 'fr', null));//'Montréal'));
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

class MediaFileTest extends PHPUnit_Framework_TestCase
{

    public function setup()
    {
        $this->old_attachments_supported = common_config('attachments', 'supported');
        $GLOBALS['config']['attachments']['supported'] = true;
    }

    public function tearDown()
    {
        $GLOBALS['config']['attachments']['supported'] = $this->old_attachments_supported;
    }

    /**
     * @dataProvider fileTypeCases
     *
     */
    public function testMimeType($filename, $expectedType)
    {
        if (!file_exists($filename)) {
            throw new Exception("Test file $filename missing");
        }

        $type = MediaFile::getUploadedMimeType($filename, basename($filename));
        $this->assertEquals($expectedType, $type);
    }

    /**
     * @dataProvider fileTypeCases
     *
     */
    public function testUploadedMimeType($filename, $expectedType)
    {
        if (!file_exists($filename)) {
            throw new Exception("WTF? $filename test file missing");
        }
        $tmp = tmpfile();
        fwrite($tmp, file_get_contents($filename));

        $tmp_metadata = stream_get_meta_data($tmp);
        $type = MediaFile::getUploadedMimeType($tmp_metadata['uri'], basename($filename));
        $this->assertEquals($expectedType, $type);
    }

    static public function fileTypeCases()
    {
        $base = dirname(__FILE__);
        $dir = "$base/sample-uploads";
        $files = array(
            "image.png" => "image/png",
            "image.gif" => "image/gif",
            "image.jpg" => "image/jpeg",
            "image.jpeg" => "image/jpeg",

            "office.pdf" => "application/pdf",

            "wordproc.odt" => "application/vnd.oasis.opendocument.text",
            "wordproc.ott" => "application/vnd.oasis.opendocument.text-template",
            "wordproc.doc" => "application/msword",
            "wordproc.docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "wordproc.rtf" => "text/rtf",

            "spreadsheet.ods" => "application/vnd.oasis.opendocument.spreadsheet",
            "spreadsheet.ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
            "spreadsheet.xls" => "application/vnd.ms-office", //"application/vnd.ms-excel",
            "spreadsheet.xlt" => "application/vnd.ms-office", //"application/vnd.ms-excel",
            "spreadsheet.xlsx" => "application/octet-stream", //"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",

            "presentation.odp" => "application/vnd.oasis.opendocument.presentation",
            "presentation.otp" => "application/vnd.oasis.opendocument.presentation-template",
            "presentation.ppt" => "application/vnd.ms-powerpoint",
            "presentation.pptx" => 'application/zip', //"application/vnd.openxmlformats-officedocument.presentationml.presentation",
        );

        $dataset = array();
        foreach ($files as $file => $type) {
            $dataset[] = array("$dir/$file", $type);
        }
        return $dataset;
    }

}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

/**
 * Test cases for nickname validity and normalization.
 */
class NicknameTest extends PHPUnit_Framework_TestCase
{
    /**
     * Basic test using Nickname::normalize()
     *
     * @dataProvider provider
     */
    public function testBasic($input, $expected, $expectedException=null)
    {
        $exception = null;
        $normalized = false;
        try {
            $normalized = Nickname::normalize($input);
        } catch (NicknameException $e) {
            $exception = $e;
        }

        if ($expected === false) {
            if ($expectedException) {
                if ($exception) {
                    $stuff = get_class($exception) . ': ' . $exception->getMessage();
                } else {
                    $stuff = var_export($exception, true);
                }
                $this->assertTrue($exception && $exception instanceof $expectedException,
                        "invalid input '$input' expected to fail with $expectedException, " .
                        "got $stuff");
            } else {
                $this->assertTrue($normalized == false,
                        "invalid input '$input' expected to fail");
            }
        } else {
            $msg = "normalized input nickname '$input' expected to normalize to '$expected', got ";
            if ($exception) {
                $msg .= get_class($exception) . ': ' . $exception->getMessage();
            } else {
                $msg .= "'$normalized'";
            }
            $this->assertEquals($expected, $normalized, $msg);
        }
    }

    /**
     * Test on the regex matching used in common_find_mentions
     * (testing on the full notice rendering is difficult as it needs
     * to be able to pull from global state)
     *
     * @dataProvider provider
     */
    public function testAtReply($input, $expected, $expectedException=null)
    {
        if ($expected == false) {
            // nothing to do
        } else {
            $text = "@{$input} awesome! :)";
            $matches = common_find_mentions_raw($text);
            $this->assertEquals(1, count($matches));
            $this->assertEquals($expected, Nickname::normalize($matches[0][0]));
        }
    }

    static public function provider()
    {
        return array(
                     array('evan', 'evan'),

                     // Case and underscore variants
                     array('Evan', 'evan'),
                     array('EVAN', 'evan'),
                     array('ev_an', 'evan'),
                     array('E__V_an', 'evan'),
                     array('evan1', 'evan1'),
                     array('evan_1', 'evan1'),
                     array('0x20', '0x20'),
                     array('1234', '1234'), // should this be allowed though? :)
                     array('12__34', '1234'),

                     // Some (currently) invalid chars...
                     array('^#@&^#@', false, 'NicknameInvalidException'), // all invalid :D
                     array('ev.an', false, 'NicknameInvalidException'),
                     array('ev/an', false, 'NicknameInvalidException'),
                     array('ev an', false, 'NicknameInvalidException'),
                     array('ev-an', false, 'NicknameInvalidException'),

                     // Non-ASCII letters; currently not allowed, in future
                     // we'll add them at least with conversion to ASCII.
                     // Not much use until we have storage of display names,
                     // though.
                     array('évan', false, 'NicknameInvalidException'), // so far...
                     array('Évan', false, 'NicknameInvalidException'), // so far...

                     // Length checks
                     array('', false, 'NicknameEmptyException'),
                     array('___', false, 'NicknameEmptyException'),
                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), // 64 chars
                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_', false, 'NicknameTooLongException'), // the _ is too long...
                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', false, 'NicknameTooLongException'), // 65 chars -- too long
                     );
    }
}


code:
<?php

if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once INSTALLDIR . '/lib/common.php';

$config['site']['server'] = 'example.net';
$config['site']['path']   = '/apps/statusnet';

class TagURITest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider provider
     */
    public function testProduction($format, $args, $uri)
    {
        $minted = call_user_func_array(array('TagURI', 'mint'),
                                       array_merge(array($format), $args));

        $this->assertEquals($uri, $minted);
    }

    static public function provider()
    {
        return array(array('favorite:%d:%d',
                           array(1, 3),
                           'tag:example.net,'.date('Y-m-d').':apps:statusnet:favorite:1:3'));
    }
}