# -*- coding: utf-8 -*-
'''
    :codeauthor: :email:`Nicole Thomas <nicole@saltstack.com>`
'''

# Import python libs
from __future__ import absolute_import
import grp
import pwd

# Import Salt Testing Libs
from salttesting import TestCase, skipIf
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON

ensure_in_syspath('../../')

# Import Salt Libs
from salt.modules import mac_user
from salt.exceptions import SaltInvocationError, CommandExecutionError


@skipIf(NO_MOCK, NO_MOCK_REASON)
class MacUserTestCase(TestCase):
    '''
    TestCase for the salt.modules.mac_user modules
    '''

    mac_user.__context__ = {}
    mac_user.__grains__ = {}
    mac_user.__salt__ = {}

    mock_pwall = [pwd.struct_passwd(('_amavisd', '*', 83, 83, 'AMaViS Daemon',
                                    '/var/virusmails', '/usr/bin/false')),
                  pwd.struct_passwd(('_appleevents', '*', 55, 55,
                                     'AppleEvents Daemon',
                                    '/var/empty', '/usr/bin/false')),
                  pwd.struct_passwd(('_appowner', '*', 87, 87,
                                     'Application Owner',
                                     '/var/empty', '/usr/bin/false'))]
    mock_pwnam = pwd.struct_passwd(('_TEST_GROUP', '*', 83, 83, 'AMaViS Daemon',
                                    '/var/virusmails', '/usr/bin/false'))
    mock_getgrgid = grp.struct_group(('_TEST_GROUP', '*', 83, []))
    mock_getgrall = [grp.struct_group(('accessibility', '*', 90, [])),
                     grp.struct_group(('admin', '*', 80, ['root', 'admin']))]
    mock_info_ret = {'shell': '/bin/bash', 'name': 'test', 'gid': 4376,
                     'groups': ['TEST_GROUP'], 'home': '/Users/foo',
                     'fullname': 'TEST USER', 'uid': 4376}

    @skipIf(True, 'Waiting on some clarifications from bug report #10594')
    def test_flush_dscl_cache(self):
        # TODO: Implement tests after clarifications come in
        pass

    def test_dscl(self):
        '''
        Tests the creation of a dscl node
        '''
        mac_mock = MagicMock(return_value={'pid': 4948,
                                           'retcode': 0,
                                           'stderr': '',
                                           'stdout': ''})
        with patch.dict(mac_user.__salt__, {'cmd.run_all': mac_mock}):
            with patch.dict(mac_user.__grains__,
                            {'kernel': 'Darwin', 'osrelease': '10.9.1',
                             'osrelease_info': (10, 9, 1)}):
                self.assertEqual(mac_user._dscl(['username', 'UniqueID', 501]),
                                 {'pid': 4948,
                                  'retcode': 0,
                                  'stderr': '',
                                  'stdout': ''})

    @patch('pwd.getpwall', MagicMock(return_value=mock_pwall))
    def test_first_avail_uid(self):
        '''
        Tests the availability of the next uid
        '''
        self.assertEqual(mac_user._first_avail_uid(), 501)

    # 'add' function tests: 4
    # Only tested error handling
    # Full functionality tests covered in integration testing

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_add_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.add, 'test')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_add_whitespace(self):
        '''
        Tests if there is whitespace in the user name
        '''
        self.assertRaises(SaltInvocationError, mac_user.add, 'foo bar')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_add_uid_int(self):
        '''
        Tests if the uid is an int
        '''
        self.assertRaises(SaltInvocationError, mac_user.add, 'foo', 'foo')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_add_gid_int(self):
        '''
        Tests if the gid is an int
        '''
        self.assertRaises(SaltInvocationError, mac_user.add, 'foo', 20, 'foo')

    # 'delete' function tests: 2
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    def test_delete_whitespace(self):
        '''
        Tests if there is whitespace in the user name
        '''
        self.assertRaises(SaltInvocationError, mac_user.delete, 'foo bar')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_delete_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertTrue(mac_user.delete('foo'))

    @patch('pwd.getpwall', MagicMock(return_value=mock_pwall))
    @patch('salt.modules.mac_user.list_groups',
           MagicMock(return_value=['TEST_GROUP']))
    def test_getent(self):
        '''
        Tests the list of information for all users
        '''
        ret = [{'shell': '/usr/bin/false', 'name': '_amavisd', 'gid': 83,
                'groups': ['TEST_GROUP'], 'home': '/var/virusmails',
                'fullname': 'AMaViS Daemon', 'uid': 83},
               {'shell': '/usr/bin/false', 'name': '_appleevents', 'gid': 55,
                'groups': ['TEST_GROUP'], 'home': '/var/empty',
                'fullname': 'AppleEvents Daemon', 'uid': 55},
               {'shell': '/usr/bin/false', 'name': '_appowner', 'gid': 87,
                'groups': ['TEST_GROUP'], 'home': '/var/empty',
                'fullname': 'Application Owner', 'uid': 87}]
        self.assertEqual(mac_user.getent(), ret)

    # 'chuid' function tests: 3
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    def test_chuid_int(self):
        '''
        Tests if the uid is an int
        '''
        self.assertRaises(SaltInvocationError, mac_user.chuid, 'foo', 'foo')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chuid_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chuid, 'foo', 4376)

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chuid_same_uid(self):
        '''
        Tests if the user's uid is the same as as the argument
        '''
        self.assertTrue(mac_user.chuid('foo', 4376))

    # 'chgid' function tests: 3
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    def test_chgid_int(self):
        '''
        Tests if the gid is an int
        '''
        self.assertRaises(SaltInvocationError, mac_user.chgid, 'foo', 'foo')

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chgid_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chgid, 'foo', 4376)

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chgid_same_gid(self):
        '''
        Tests if the user's gid is the same as as the argument
        '''
        self.assertTrue(mac_user.chgid('foo', 4376))

    # 'chshell' function tests: 2
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chshell_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chshell,
                          'foo', '/bin/bash')

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chshell_same_shell(self):
        '''
        Tests if the user's shell is the same as the argument
        '''
        self.assertTrue(mac_user.chshell('foo', '/bin/bash'))

    # 'chhome' function tests: 2
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chhome_user_exists(self):
        '''
        Test if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chhome,
                          'foo', '/Users/foo')

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chhome_same_home(self):
        '''
        Tests if the user's home is the same as the argument
        '''
        self.assertTrue(mac_user.chhome('foo', '/Users/foo'))

    # 'chfullname' function tests: 2
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chfullname_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chfullname,
                          'test', 'TEST USER')

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chfullname_same_name(self):
        '''
        Tests if the user's full name is the same as the argument
        '''
        self.assertTrue(mac_user.chfullname('test', 'TEST USER'))

    # 'chgroups' function tests: 3
    # Only tested pure logic of function
    # Full functionality tests covered in integration testing

    @patch('salt.modules.mac_user.info', MagicMock(return_value={}))
    def test_chgroups_user_exists(self):
        '''
        Tests if the user exists or not
        '''
        self.assertRaises(CommandExecutionError, mac_user.chgroups,
                          'foo', 'wheel,root')

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    def test_chgroups_bad_groups(self):
        '''
        Test if there is white space in groups argument
        '''
        self.assertRaises(SaltInvocationError, mac_user.chgroups,
                          'test', 'bad group')

    @patch('salt.modules.mac_user.info', MagicMock(return_value=mock_info_ret))
    @patch('salt.modules.mac_user.list_groups',
           MagicMock(return_value=('wheel', 'root')))
    def test_chgroups_same_desired(self):
        '''
        Tests if the user's list of groups is the same as the arguments
        '''
        mock_primary = MagicMock(return_value='wheel')
        with patch.dict(mac_user.__salt__, {'file.gid_to_group': mock_primary}):
            self.assertTrue(mac_user.chgroups('test', 'wheel,root'))

    @patch('salt.modules.mac_user.list_groups',
           MagicMock(return_value=['_TEST_GROUP']))
    def test_info(self):
        '''
        Tests the return of user information
        '''
        mock_pwnam = pwd.struct_passwd(('test', '*', 0, 0, 'TEST USER',
                                        '/var/test', '/bin/bash'))
        ret = {'shell': '/bin/bash', 'name': 'test', 'gid': 0,
               'groups': ['_TEST_GROUP'], 'home': '/var/test',
               'fullname': 'TEST USER', 'uid': 0}
        with patch('pwd.getpwnam', MagicMock(return_value=mock_pwnam)):
            self.assertEqual(mac_user.info('root'), ret)

    @patch('salt.modules.mac_user.list_groups',
           MagicMock(return_value=['_TEST_GROUP']))
    def test_format_info(self):
        '''
        Tests the formatting of returned user information
        '''
        data = pwd.struct_passwd(('_TEST_GROUP', '*', 83, 83, 'AMaViS Daemon',
                                  '/var/virusmails', '/usr/bin/false'))
        ret = {'shell': '/usr/bin/false', 'name': '_TEST_GROUP', 'gid': 83,
                     'groups': ['_TEST_GROUP'], 'home': '/var/virusmails',
                     'fullname': 'AMaViS Daemon', 'uid': 83}
        self.assertEqual(mac_user._format_info(data), ret)

    @patch('pwd.getpwall', MagicMock(return_value=mock_pwall))
    def test_list_users(self):
        '''
        Tests the list of all users
        '''
        ret = ['_amavisd', '_appleevents', '_appowner']
        self.assertEqual(mac_user.list_users(), ret)


if __name__ == '__main__':
    from integration import run_tests
    run_tests(MacUserTestCase, needs_daemon=False)
