<?php

/**
 * @file
 * Tests for the user destination plugin.
 */

/**
 * Test user migration.
 */
class MigrateUserUnitTest extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'User migration',
      'description' => 'Test migration of user data',
      'group' => 'Migrate',
    );
  }

  function setUp() {
    parent::setUp('migrate', 'migrate_example');

    // To test timestamps
    date_default_timezone_set('US/Mountain');

    // Make sure the migrations are registered.
    migrate_static_registration();
  }

  function testUserImport() {
    $migration = Migration::getInstance('WineFileCopy');
    $result = $migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('File import returned RESULT_COMPLETED'));
    $migration = Migration::getInstance('WineRole');
    $result = $migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('Role import returned RESULT_COMPLETED'));
    // Confirm both roles were successfully imported
    $result = db_select('role', 'r')
      ->fields('r', array('rid', 'name'))
      ->condition('name', array('Taster', 'Vintner'), 'IN')
      ->execute();
    $roles = array();
    foreach ($result as $row) {
      $roles[$row->name] = $row->rid;
    }
    $this->assertEqual(count($roles), 2, t('Both roles imported'));

    // Make sure update does not fail (regression test of
    // http://drupal.org/node/1872446)
    $migration->prepareUpdate();
    $migration->processImport();
    $num_messages = $migration->getMap()->messageCount();
    $this->assertEqual($num_messages, 0, t('No messages generated'));

    $migration = Migration::getInstance('WineUser');
    $result = $migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('User import returned RESULT_COMPLETED'));
    $result = db_select('migrate_example_wine_account', 'mea')
      ->fields('mea', array(
        'accountid',
        'status',
        'posted',
        'name',
        'sex',
        'password',
        'mail',
        'last_access',
        'last_login',
        'sig',
        'original_mail',
      ))
      ->execute();
    $uids = db_select('users', 'u')
      ->fields('u', array('uid'))
      ->execute()
      ->fetchCol();
    // Index by name
    $users = array();
    foreach ($uids as $uid) {
      // Skip anon/admin users
      if ($uid > 1) {
        $account = user_load($uid);
        $users[$account->name] = $account;
      }
    }

    $rows = array();
    foreach ($result as $row) {
      $rows[$row->name] = $row;
    }
    $this->assertEqual(count($users), count($rows),
      t('Counts of users and input rows match'));

    // Test each base user field
    $this->assert(isset($users['darren']) && isset($rows['darren']),
      t("Username 'darren' migrated correctly"));
    $this->assertEqual($users['darren']->mail, $rows['darren']->mail,
      t('Email addresses match'));
    $this->assertEqual($users['darren']->status, $rows['darren']->status,
      t('Statuses match'));
    $this->assertNotNull($users['darren']->roles[2], t('Authenticated role'));
    $this->assertNotNull($users['darren']->roles[$roles['Taster']], t('Taster role'));
    $this->assertFalse(isset($users['darren']->roles[$roles['Vintner']]), t('No Vintner role'));
    $this->assertEqual($users['darren']->created, strtotime($rows['darren']->posted),
      t('Created times match'));
    $this->assertEqual($users['darren']->access, strtotime($rows['darren']->last_access),
      t('Access times match'));
    $this->assertEqual($users['darren']->login, strtotime($rows['darren']->last_login),
      t('Login times match'));
    $this->assertTrue(user_check_password($rows['darren']->password, $users['darren']),
      t('Passwords match'));
    $this->assertEqual($users['darren']->init, $rows['darren']->original_mail,
      t('Init mails match'));
    $this->assertEqual($users['darren']->signature, $rows['darren']->sig,
      t('Signatures match'));
    $this->assertEqual($users['darren']->signature_format, $migration->basicFormat->format,
      t('Signature formats match'));
    $this->assertEqual($users['darren']->field_migrate_example_gender[LANGUAGE_NONE][0]['value'],
      0, t('Male gender migrated'));
    $this->assertEqual($users['emily']->field_migrate_example_gender[LANGUAGE_NONE][0]['value'],
      1, t('Female gender migrated'));
    $this->assert(!isset($users['fonzie']->field_migrate_example_gender[LANGUAGE_NONE][0]['value']),
      t('Missing gender left unmigrated'));
    /* For some reason, this fails on d.o but not in local environments
        $this->assert(is_object($users['fonzie']->picture) &&
                      $users['fonzie']->picture->filename == '200',
          t('Picture migrated'));*/
    $this->assertNotNull($users['fonzie']->roles[$roles['Taster']], t('Taster role'));
    $this->assertNotNull($users['fonzie']->roles[$roles['Vintner']], t('Vintner role'));

    // TODO: Theme, timezone, language

    // Test updates
    // Capture original users
    $query = new EntityFieldQuery;
    $result = $query
      ->entityCondition('entity_type', 'user')
      ->propertyCondition('uid', 1, '>')
      ->execute();
    $uids = array_keys($result['user']);
    $original_users = user_load_multiple($uids, array(), TRUE);
    $update_migration = Migration::getInstance('WineUserUpdates');
    $result = $update_migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('Wine user updates import returned RESULT_COMPLETED'));
    $final_users = user_load_multiple($uids, array(), TRUE);
    foreach ($original_users as $uid => $original_user) {
      foreach ($original_user as $field => $value) {
        if ($field == 'field_migrate_example_gender') {
          if ($value == $final_users[$uid]->{$field}) {
            $this->error(t('For user !name, field !field should have changed but did not, value=!value',
              array(
                '!name' => $final_users[$uid]->name,
                '!field' => $field,
                '!value' => print_r($value, TRUE),
              )));
          }
        }
        else {
          if ($value != $final_users[$uid]->{$field}) {
            // Core bug http://drupal.org/node/935592 causes picture mismatches, ignore until it's fixed
            if ($field != 'picture') {
              $this->error(t('For user !name, field !field mismatch: original !value1, result !value2',
                array(
                  '!name' => $final_users[$uid]->name,
                  '!field' => $field,
                  '!value1' => print_r($value, TRUE),
                  '!value2' => print_r($final_users[$uid]->{$field}, TRUE),
                )));
            }
          }
        }
      }
    }

    // Test rollback
    $result = $migration->processRollback(array('force' => TRUE));
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('User rollback returned RESULT_COMPLETED'));
    $count = db_select('users', 'u')
      ->fields('u', array('uid'))
      ->countQuery()
      ->execute()
      ->fetchField();
    // 2 users left - anon and admin
    $this->assertEqual($count, 2, t('All imported users deleted'));
    $count = db_select('migrate_map_wineuser', 'map')
      ->fields('map', array('sourceid1'))
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertEqual($count, 0, t('Map cleared'));
    $count = db_select('migrate_message_wineuser', 'msg')
      ->fields('msg', array('sourceid1'))
      ->countQuery()
      ->execute()
      ->fetchField();
    $this->assertEqual($count, 0, t('Messages cleared'));

    // Test deduping
    // First, do the original import
    $migration = Migration::getInstance('BeerUser');
    $result = $migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('User import returned RESULT_COMPLETED'));
    $accounts = db_select('users', 'u')
      ->fields('u', array('mail', 'name'))
      ->execute()
      ->fetchAllKeyed();
    if (!$this->assertEqual($accounts['alice@example.com'], 'alice', t('alice found'))) {
      $this->error(t('Expected alice, found !name', array('!name' => $accounts['alice@example.com'])));
    }
    if (!$this->assertEqual($accounts['alice2@example.com'], 'alice_2', t('alice_2 found'))) {
      $this->error(t('Expected alice_2, found !name', array('!name' => $accounts['alice2@example.com'])));
    }

    // Then, update in place and make sure the usernames did not change
    $migration->prepareUpdate();
    $result = $migration->processImport();
    $this->assertEqual($result, Migration::RESULT_COMPLETED,
      t('User import returned RESULT_COMPLETED'));
    $accounts = db_select('users', 'u')
      ->fields('u', array('mail', 'name'))
      ->execute()
      ->fetchAllKeyed();
    if (!$this->assertEqual($accounts['alice@example.com'], 'alice', t('alice found'))) {
      $this->error(t('Expected alice, found !name', array('!name' => $accounts['alice@example.com'])));
    }
    if (!$this->assertEqual($accounts['alice2@example.com'], 'alice_2', t('alice_2 found'))) {
      $this->error(t('Expected alice_2, found !name', array('!name' => $accounts['alice2@example.com'])));
    }
  }
}
