<?php
/*
* Copyright (c) 2009-2010 ATMAIL. All rights reserved
* See http://atmail.com/license.php for license agreement
*/

/**
 * Implements comprehensive Unit Testing on Atmail
 *
 * @author Brad Kowalczyk
 * @package Atmail_Test
 * @todo complete implementation of all tests
 */
class Atmail_Test_Suite extends Zend_Test_PHPUnit_ControllerTestCase
{

    /**
     * Test that login page displays
     * if user attempts to view /main
     */
    public function testLoginPageDisplay()
    {
        $this->dispatch('index');
        $this->assertController('auth');
        $this->assertAction('index');
    
        // Look for the login form, it contains an action
        // attribute with a URL that calls the 'processlogin'
        // action
        $this->assertQuery('form[action*="/processlogin"]');
    }
    
    /**
     * Test that an invalid account fails login
     *
     */
    public function testLoginWithBadAccount()
    {
        $this->doLogin('IMAP', 'invalid@test.com', 'password', 'localhost');
        $this->assertQuery('form[action*="/processlogin"]');
        $this->assertQueryContentContains('font', 'Error:');
    }
    
    /**
     * Test that a valid login works
     *
     * @param String $protocol
     * @param String $account
     * @param String $password
     * @param String $host
     */
    public function testLoginWithValidAccount()
    {
        $this->doLogin('IMAP', 'test@unit.atmail.com', 'un1tt3st1ng', 'localhost');
        $this->assertController('mail');
        $this->assertAction('index');
        
        //
        // Ensure the main navbar is loaded
        //
        
        // Email tab
        $this->assertQuery('li#nav_ema');
        //$this->assertQuery('a[href="#Email"]');
        
        // Abook tab
        $this->assertQuery('li#nav_add');
        $this->assertQuery('a[href*="/mail/contacts"]');
        
        // Calendar tab
        $this->assertQuery('li#nav_cal');
        $this->assertQuery('a[href*="/mail/calendar"]');
        
        // Settings tab
        $this->assertQuery('li#nav_set');
        $this->assertQuery('a[href*="/mail/settings"]');
        
        // Search bar
        $this->assertQuery('div#search_anything');
        
        // Logout button
        $this->assertQuery('div#sign_out');
        $this->assertQuery('a[href*="/mail/auth/logout"]');
    
        // Mail related menu bar
        
        // New button
        $this->assertQuery('li#action_new');
        
        // Reply button
        $this->assertQuery('li#action_reply');
        
        // Reply All button
        $this->assertQuery('li#action_reply_all');
        
        // Forward button
        $this->assertQuery('li#action_forward');
        
        // Junk button
        $this->assertQuery('li#action_junk');
        
        // Delete button
        $this->assertQuery('li#action_delete');
        
        // More button
        //$this->assertQuery('li#action_more');
        
        // View toggle
        $this->assertQuery('li#two_pane');
        $this->assertQuery('li#three_pane');
        //echo $this->getResponse()->getBody();
        // Default folders
        $this->assertQuery('li#folder_inbox');
        $this->assertQuery('li#folder_inbox_drafts');
        $this->assertQuery('li#folder_inbox_sent');
        $this->assertQuery('li#folder_inbox_spam');
        $this->assertQuery('li#folder_inbox_trash');
        
        // Folder Actions
        $this->assertQuery('li#folder_add');
        $this->assertQuery('li#folder_remove');
    }


    /**
     * Test that a login using an illegal domain fails
     *
     * @param String $protocol
     * @param String $account
     * @param String $password
     * @param String $host
     */
    public function offtestLoginWithIllegalDomain($protocol, $account, $password, $host)
    {
        $this->doLogin($protocol, $account, $password, $host);
        $this->assertQuery('form[action*="/processlogin"]');
        $this->assertQueryContentContains('font', 'Error:');
    }

    /**
     * Test that a login with an illegal mailserver fails
     *
     * @param String $protocol
     * @param String $account
     * @param String $password
     * @param String $host
     */
    public function offtestLoginWithIllegalServer($protocol, $account, $password, $host)
    {
        $this->doLogin($protocol, $account, $password, $host);
        $this->assertQuery('form[action*="/processlogin"]');
        $this->assertQueryContentContains('font', 'Error:');
    }

    /**
     * Perform actual login
     *
     * @param String $protocol
     * @param String $account
     * @param String $password
     * @param String $host
     * @access private
     */
    private function doLogin($protocol, $account, $password, $host)
    {
        list($emailName, $emailDomain) = explode('@', $account);
        $params = array(
            'emailName'       => $emailName,
            'emailDomain'     => $emailDomain,
            'password'        => $password,
            'requestedServer' => $host,
            'MailType'        => $protocol
        );

        $this->request->setMethod('POST')->setPost($params);
        $this->dispatch('/mail/auth/processlogin');
    }


    /**
     * mailbox listing test
     *
     */
    public function offtestListMailboxes()
    {
        $this->dispatch('/folders/index/format/xml');
        $this->assertController('folders');
        $this->assertAction('index');
    }

    /**
     * Test listing mailbox contents
     *
     * @todo Find a way to test that the emails are listing.
     *       At the moment an AJAX request is made and a
     *       JSON response is sent
     */
    public function testReadMailboxHTML()
    {
        $this->dispatch('/mail/mail/listfoldermessages');
        $json = json_decode($this->getResponse()->getBody());
        $html = $json->q[1]->a[0][0];
        $this->getResponse()->setBody($html);
        $this->assertController('mail');
        $this->assertAction('listfoldermessages');
        $this->assertQueryCount('div.mail_row', 9);
    
        // Make sure a messages are listed correctly
        $this->assertQueryContentContains('div.mailFrom h3', 'Danny Scheers');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Re: @Mail Purchase Follow Up for Thales Securities SA');
        $this->assertQueryContentContains('div.mailFrom h3', 'Bushey, Daniel (H USA)');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'RE: not being heard [Incident: 090319-000092]');
        $this->assertQueryContentContains('div.mailFrom h3', '2259371289@mms.att.net');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Multimedia message');
        $this->assertQueryContentContains('div.mailFrom h3', 'Alister Tagg');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Fwd: You have a PXT from 64211290201');
        $this->assertQueryContentContains('div.mailFrom h3', 'Chris Lambert');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'QPD Ongoing Mail Server Problems');
        $this->assertQueryContentContains('div.mailFrom h3', 'Jules Toure');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Re: AtMail Support Contact Form (Mamadou687DE)');
        $this->assertQueryContentContains('div.mailFrom h3', 'ALLIED SEISMIC');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Re: Wood Buffalo / ASL 36212');
        $this->assertQueryContentContains('div.mailFrom h3', 'S FLEMING');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'Fw: ALCOHOL IS BAD FOR  YOUR LEGS');
        $this->assertQueryContentContains('div.mailFrom h3', 'Jill Southworth');
        $this->assertQueryContentContains('div.mailSubject h4 span', 'test');
    }

    public function createMailbox($mailbox)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function selectMailbox($mailbox)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function moveMessage($mailbox, $newMailbox=null, $uid=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function testReadMessageBasic()
    {
        $this->dispatch('/mail/viewmessage/index/uniqueId/6/viewmessageTabNumber/6/isAjax/1');
        $this->assertController('viewmessage');
        $this->assertAction('index');
        $json = json_decode($this->getResponse()->getBody());
        $html = $json->q[5]->a[0][0];
        $this->getResponse()->setBody($html);
        //$this->_printBody();
        $this->assertQueryContentContains('div#primary_header h1', 'QPD Ongoing Mail Server Problems');
        $this->assertQueryContentContains('div.details h3 strong', '"Chris Lambert"');
        $this->assertQueryContentContains('div.details h3', '&lt;chris.lambert@rig.net&gt;');
        //$this->assertQuery('div.meta h4[title="Sun, 28 Sep 2008 23:43 +1000"]');
        $this->assertQueryContentContains('div.body>div.Section1>p>span', "particular the QPD Email Problem attached email with virus attachment.");
        //$this->assertQueryContentContains('div.body div.Section1 p span', "We need full assistance and help to fix this guys.");
        $this->assertQueryCount('div.body div.attachments', 5);
        $this->assertQueryContentContains('li#attachment1>a', 'embeddedEmail1.eml');
        $this->assertQueryContentContains('li#attachment1', '36kB');
        $this->assertQueryContentContains('li#attachment2>a', 'embeddedEmail2.eml');
        $this->assertQueryContentContains('li#attachment2', '7kB');
        $this->assertQueryContentContains('li#attachment3>a', 'embeddedEmail3.eml');
        $this->assertQueryContentContains('li#attachment3', '28kB');
        $this->assertQueryContentContains('li#attachment4>a', 'embeddedEmail4.eml');
        $this->assertQueryContentContains('li#attachment4', '167kB');
        $this->assertQueryContentContains('li#attachment5>a', 'embeddedEmail5.eml');
        $this->assertQueryContentContains('li#attachment5', '28kB');
    }


	/**
	 * Test a message that has 4 attachments
	 *
	 * Test that the attachment list is created with correct
	 * number of attachments, attachment names and attachment sizes
	 */
	public function testReadMessageWithAttachments()
    {
        $this->dispatch('/mail/viewmessage/index/uniqueId/5/viewmessageTabNumber/5/isAjax/1');
        $this->assertController('viewmessage');
        $this->assertAction('index');
        $json = json_decode($this->getResponse()->getBody());
        $html = $json->q[9]->a[0][0];
        $this->getResponse()->setBody($html);

        // Test for some basic header info
        $this->assertQueryContentContains('div#primary_header h1', 'Re: AtMail Support Contact Form (Mamadou687DE)');
        $this->assertQueryContentContains('div.details h3 strong', 'Jules Toure');
        $this->assertQueryContentContains('div.details h3', '&lt;demalson@yahoo.fr&gt;');
    
        // Test that all attachments are correctly listed with correct filenames and related sizes
        $this->assertQueryContentContains('li#attachment1 a', 'WebadminconfigInterface.JPG');
        $this->assertQueryContentContains('li#attachment1', '124kB');
        $this->assertQueryContentContains('li#attachment2 a', 'WebadminUsersInterface.JPG');
        $this->assertQueryContentContains('li#attachment2', '122kB');
        $this->assertQueryContentContains('li#attachment3 a', 'WebMailInterface.JPG');
        $this->assertQueryContentContains('li#attachment3', '88kB');
        $this->assertQueryContentContains('li#attachment4', 'WebSecurityInterface.JPG');
        $this->assertQueryContentContains('li#attachment4', '112kB');
    }

    public function testReadMessageWithCidImageButNoCidReference()
    {
        $this->dispatch('/mail/viewmessage/index/uniqueId/7/viewmessageTabNumber/7/isAjax/1');
        $this->assertController('viewmessage');
        $this->assertAction('index');
        //var_dump($this->getResponse()->getBody());exit;
        $json = json_decode($this->getResponse()->getBody());
        //var_dump($json);exit;
        $html = $json->q[13]->a[0][0];
        $this->getResponse()->setBody($html);
        
        $this->assertQueryContentContains('h1', 'Fwd: You have a PXT from 64211290201');
        $this->assertQueryContentContains('div.body', 'Original Message');
        $this->assertQueryContentContains('div.body', 'From: Alister Tagg allie@woosh.co.nz');
        $this->assertQueryContentContains('div.body', 'To: lcorles@woosh.com');
        $this->assertQueryContentContains('div.body', 'Sent: Mon 16/03/09  3:06 PM');
        $this->assertQueryContentContains('div.body', 'Subject: Fwd: You have a PXT from 64211290201');
        $this->assertQueryContentContains('div.body', 'From: PXT 64211290201@pxt.vodafone.net.nz');
        $this->assertQueryContentContains('div.body', 'To: allie@woosh.co.nz');
        $this->assertQueryContentContains('div.body', 'Sent: Sun 15/03/09 9:35 PM');
        $this->assertQueryContentContains('div.body', 'Subject: Fwd: You have a PXT from 64211290201');
        $this->assertQuery('img[src="/tmp/t/e/test@unit.atmail.com/12-03-09_1338.jpg"]');
    }


    public function flagMessage($mailbox, $uid=null, $flag=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
        $this->_printResult();
    }

    public function deleteMessage($mailbox, $uid=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function emailComposePage()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function emailComposeAndSend()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function emailReplyTo()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function emailReplyAll()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function emailForward()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
        $this->_printResult();
    }

    public function emailSaveToDrafts()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }


	/**
	 * Test opening address book
	 */
    public function openAbook()
    {
        $this->dispatch('mail/contacts/viewcontacts/');
        //echo $this->getResponse()->getBody();
        $this->assertController('contacts');
        $this->assertAction('viewcontacts');
        $this->assertQuery('form#listcontacts');
        //$this->assertQuery('li#action_contact_new');
        //$this->assertQuery('div#actions ul#for_messages li#action_contact_newgroup');
        //$this->assertQuery('div#actions ul#for_messages li#action_contact_edit');
        //$this->assertQuery('div#actions ul#for_messages li#action_contact_delete');
        //$this->assertQueryContentContains('div#primary_header h1', 'Address Book');
        //$this->assertQueryCount('div.address_row', 7);
        //$this->assertQuery('div#contact_info');
        
        // Check all groups are displayed
        //$this->assertQuery('li[groupname="All"]');
        //$this->assertQuery('li[groupname="t1"]');
        //$this->assertQuery('li[groupname="t2"]');
        //$this->assertQuery('li[groupname="t3"]');
        //$this->assertQuery('li[groupname="t4"]');
        //$this->assertQuery('li[groupname="t5"]');
    }

	/**
	 * Test display of a groups contacts
	 */
    public function viewAbookGroup()
    {
        $this->dispatch('contacts/viewcontacts/GroupName/t1');
        $this->assertController('contacts');
        $this->assertAction('viewcontacts');
        $this->assertQueryCount('div.address_row', 4);
        $this->assertQueryContentContains('a[contactid="3"] div div div span.first_name', 'Ben122');
        $this->assertQueryContentContains('a[contactid="3"] div div div span.last_name', 'Duncan1');
        $this->assertQueryContentContains('a[contactid="7"] div div div span.first_name', 'Ben2');
        $this->assertQueryContentContains('a[contactid="7"] div div div span.last_name', 'Ben2');
        $this->assertQueryContentContains('a[contactid="2"] div div div span.first_name', 'Benjamin');
        $this->assertQueryContentContains('a[contactid="2"] div div div span.last_name', 'Duncan');
        $this->assertQueryContentContains('a[contactid="10"] div div div span.first_name', 'Mikaela');
        $this->assertQueryContentContains('a[contactid="10"] div div div span.last_name', 'Duncan');
    }

	/**
	 * Test display of a contact's details
	 */
    public function viewAbookContact()
    {
        $this->dispatch('contacts/viewcontact/id/10');
        $this->assertController('contacts');
        $this->assertAction('viewcontact');
        $this->assertQuery('table[contactid="10"]');
        $this->assertQueryContentContains('span.full_name', 'Mikaela Duncan');
        $this->assertQueryContentContains('td', 'cefceredw');
        $this->assertQueryContentContains('td', '458 Greggs Road');
    }


	/**
	 * Test display of the Add Contact page
	 */
    public function addNewAbookContactForm()
    {
        $this->dispatch('contacts/newcontact/new');
        $this->assertController('contacts');
        $this->assertAction('newcontact');
        $this->assertQuery('form[action*="contacts/addcontact"]');
    }


	/**
	 * Test adding a new contact
	 */
    public function addNewAbookContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }


    public function addAbookSharedContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function addAbookGroup()
    {          
        //create random group name
        $name = $this->_randomName();
        $this->dispatch("/mail/contacts/creategroup/newGroupName/$name");
        $this->assertController('contacts');
        $this->assertAction('creategroup');
        
        // Make sure new group is in the DB
        require_once '../application/models/contacts.php';
        $this->_contacts = new contacts(array('Account' => 'test@duo.calacode.com', 1));
        $groups = $this->getGroups();
        if (!in_array($name, $groups)) {
            throw new Atmail_Exception('group does not exist in DB'); 
        }
    }


    private function _randomName($size=10)
    {
        $alpha = range('a', 'z');
        $name = '';
        for ($i=0; $i<$size; $i++) {
            $name .= $alpha[mt_rand(0, 25)];
        }
        
        return $name;
    }
    
    public function addAbookSharedGroup()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyAbookContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyAbookGroup()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyAbookSharedContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyAbookSharedGroup()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function displayAbookPersonal()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function displayAbookGlobal()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function displayAbookShared()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteAbookContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteAbookSharedContact()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteAbookGroup()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteAbookSharedGroup()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function addCalendarTask()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyCalendarTask()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteCalendarTask()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function createNewCalendar($calName)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function addCalendarAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyCalendarAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteCalendarAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function addCalendarSharedAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function modifyCalendarSharedAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteCalendarSharedAppointment($calName=null)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function deleteCalendar($calName)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function calendarSwitchView($view)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function calendarIcalExport()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function calendarIcalImport($path)
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function calendarViewHelp()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    public function calendarBackToEmail()
    {
        $this->dispatch('');
        $this->assertController('');
        $this->assertAction('');
    }

    /**
     * Test for successful logout
     *
     */
    public function testLogout()
    {
        $this->dispatch('/mail/auth/logout');
        $this->assertQueryContentContains('body', 'Logout successful');
    }
    
    /**
     * Print a formatted result from a test
     *
     * @param Exception $e (optional)
     */
    private function _printResult($e=null)
    {
        if ($e instanceof Exception) {
            fwrite(STDOUT, "FAIL\n   " . $e->getMessage() . "\n----------------------------\n");
            fwrite(STDERR, "Test Status: FAIL\n");
        } else {
            fwrite(STDOUT, "OK\n");
        }
    }
    
    private function _printBody()
    {
        echo $this->getResponse()->getBody();
    }
    
}
