# Elisa - Home multimedia server
# Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

from twisted.trial import unittest
from elisa.core.tests.elisa_test_case import ElisaTestCase

import new, os, sys
import platform
from elisa.core import component
from elisa.core import config
from elisa.core import common

class FooComponent(component.Component):

    default_config = {'str_option': 'default str',
                      'list_option': ['default','list'],
                      'another_option': 'bar'

                      }

    config_doc = {'str_option': 'a string option quoi',
                  'list_option': 'gimme a list'
                  }

    # this modules depends on a non-existant foo module
    dependencies = ['site','foo']

class BarComponent(component.Component):
    """
    For test purpose this component depends explicitely on stdlib's modules
    """

    dependencies = ['site','sys', 'os.path']

class WinComponent(component.Component):

    platforms = ['Windows',]


class LinComponent(component.Component):

    platforms = ['Linux',]

class FakeApplication:

    config = None

class TestComponent(ElisaTestCase):

    def test_init(self):
        """ Check the component correctly loads its config
        """

        comp = FooComponent()
        conf = config.Config('test.conf')

        section = {'str_option':'some string',
                   'list_option':['some','list'],
                  }
        conf.set_section('foo', section)

        comp.name = 'foo'
        comp.id = 0
        comp.load_config(conf)

        keys = comp.config.keys()
        self.failUnless('str_option' in keys)
        self.failUnless('list_option' in keys)
        self.failUnless('another_option' in keys)

        self.assertEqual(comp.config['str_option'], 'some string')
        self.assertEqual(comp.config['list_option'], ['some', 'list'])
        self.assertEqual(comp.config['another_option'], 'bar')

    def test_no_config(self):
        """ Check the default config of the component is used when
        it's not found in the application's config.
        """
        comp = FooComponent()
        conf = config.Config('test.conf')

        comp.name = 'foo'
        comp.id = 0
        comp.load_config(conf)

        self.assertEqual(comp.config, comp.default_config)

    def test_multiple_instances(self):
        """ Check we can use multiple instances of the same component

        But with different configurations
        """
        conf = config.Config('test.conf')

        section0 = {'str_option':'some string',
                   'list_option':['some','list'],
                  }
        conf.set_section('foo:0', section0)

        # hey, we should have a config for that instance in the app's config
        comp0 = FooComponent()
        comp0.name = 'foo'
        comp0.id = 0
        comp0.load_config(conf)

        # ho shit, no config for that one should be found
        comp1 = FooComponent()
        comp1.name = 'foo'
        comp1.id = 1
        comp1.load_config(conf)

        keys = comp0.config.keys()
        self.failUnless('str_option' in keys)
        self.failUnless('list_option' in keys)
        self.failUnless('another_option' in keys)

        self.assertEqual(comp0.config['str_option'], 'some string')
        self.assertEqual(comp0.config['list_option'], ['some', 'list'])
        self.assertEqual(comp0.config['another_option'], 'bar')

        self.assertEqual(comp1.config, comp1.default_config)

    def test_clean(self):
        """ Check the config is saved on component.clean()
        """
        empty = 'empty.conf'
        try:
            os.unlink(empty)
        except:
            pass

        conf = config.Config(empty)

        fake_app = FakeApplication()
        fake_app.config = conf
        common.set_application(fake_app)

        comp = FooComponent()
        comp.name = 'foo'
        comp.id = 0
        comp.load_config(conf)

        self.assertEqual(comp.config, comp.default_config)

        comp.clean()
        self.assertEqual(conf.get_section('foo'), comp.config)

    def test_check_python_dependencies(self):
        #print self.__module__
        #import pdb; pdb.set_trace()
        self.assertRaises(component.UnMetDependency,
                          component.check_python_dependencies,
                          'test', ['ponyheaven'])

        test_mod = new.module('test_mod')
        test_mod.__version__ = '0.1'
        sys.modules['test_mod'] = test_mod
        self.failUnless(component.check_python_dependencies('test',
                                                            ['test_mod >= 0.1']))
    def test_parse_dependency(self):
        dep = component.parse_dependency("pgm")
        self.assertEqual(dep, ("pgm", "", ""))

        for sign in ("=", "==", ">=", ">", "<=", "<"):
            dep = component.parse_dependency("pgm %s 0.3" % sign)
            self.assertEqual(dep, ("pgm", sign, "0.3"))

    def test_check_version(self):

        mod = new.module('test_module')
        mod.__version__ = '0.1'

        for sign in ("=", "==", ">=", "<="):
            self.failUnless(component._check_version('test_component',
                                                     'test_module', mod,
                                                     sign, '0.1'))
        self.assertRaises(component.UnMetDependency,
                          component._check_version,'test_component',
                                                   'test_module', mod, '>',
                                                   '0.2')

        del mod.__version__
        self.failIf(component._check_version('test_component', 'test_module',
                                             mod, '==', '0.1'))

        def version():
            return (0, 1)

        mod.version = version
        self.failUnless(component._check_version('test_component', 'test_module',
                                                 mod, '==', '0.1'))

    def test_check_platforms(self):

        if os.name == 'posix':
            platforms = ('win32',)
        else:
            platforms = ('posix',)

        self.assertRaises(component.UnSupportedPlatform,
                          component.check_platforms, 'test', platforms)
        self.failUnless(component.check_platforms('test', (os.name,)))
