#!/usr/bin/python

# debtagshw: lib to detect what hardware tags apply to the current system
#
# Copyright (C) 2012  Canonical
#
# Author:
#  Michael Vogt <mvo@ubuntu.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from __future__ import absolute_import

import logging
import unittest
import tempfile

from mock import Mock, patch


import sys

from debtagshw.detectors import (
    Detector,
    DetectorCmdline,
)

from debtagshw.debtagshw import (
    DebtagsAvailableHW,
    HardwareSupported,
    )

class TestDebtagsHW(unittest.TestCase):

    def test__check_hw_debtags(self):
        hw = DebtagsAvailableHW()
        # run over all hwtags that we support
        for hwtag in hw.get_supported_tags() + [
            # TODO
            "hardware::camera",
            "hardware::gps",
            "hardware::input:joystick",
            "hardware::memory:1GB",
            "hardware::power:ups",
            "hardware::storage:floppy",
            ]:
            hw._check_hw_debtag(hwtag)

    def test_keyboard(self):
        # this may fail on a buildd with no keyboard
        hw = DebtagsAvailableHW()
        self.assertTrue(hw._check_hw_debtag("hardware::input:keyboard"))

    def test_laptop_detect(self):
        d = DetectorCmdline()
        d.LAPTOP_DETECT = "/bin/true"
        self.assertEqual(d.is_supported("hardware::laptop"),
                        HardwareSupported.YES)
        d.LAPTOP_DETECT = "/bin/false"
        self.assertEqual(d.is_supported("hardware::laptop"),
                         HardwareSupported.NO)

    def test_scanner(self):
        f = tempfile.NamedTemporaryFile()
        test_bytes = "device 'uri' is a foo bar bar"
        if sys.version > '3':
            test_bytes = test_bytes.encode()
        f.write(test_bytes)
        f.flush()
        d = DetectorCmdline()
        d.SCANIMAGE = ["cat", f.name]
        self.assertEqual(d.is_supported("hardware::scanner"),
                         HardwareSupported.YES)
        d.SCANIMAGE = ["cat", "/dev/null"]
        self.assertEqual(d.is_supported("hardware::scanner"),
                         HardwareSupported.NO)

class TestPublicAPI(unittest.TestCase):

    def setUp(self):
        class MockDetector(Detector):
            TEST_TAGS = {  "hardware::scanner" : HardwareSupported.YES,
                           "hardware::printer":  HardwareSupported.NO,
                           "hardware::gps":  HardwareSupported.NO,
                           "hardware::testme1":  HardwareSupported.NO,
                           "hardware::testme2":  HardwareSupported.YES,
                    }
            def get_supported_tags(self):
                return self.TEST_TAGS.keys()
            def is_supported(self, tag):
                if tag in self.TEST_TAGS:
                    return self.TEST_TAGS[tag]
                return HardwareSupported.UNKNOWN
        self._mock_detector = MockDetector()
        self.hw = DebtagsAvailableHW()
        self.hw._detectors.insert(0, self._mock_detector)

    def test_get_missing_hw(self):
        # test
        tags = ["hardware::scanner", "hardware::gps", "hardware::xxx" ]
        result = self.hw.get_hardware_support_for_tags(tags)
        self.assertEqual(result, {
            'hardware::scanner' : HardwareSupported.YES,
            'hardware::gps' : HardwareSupported.NO,
            'hardware::xxx' : HardwareSupported.UNKNOWN,
            })

    def test_generate_tag_expressions(self):
        res = {}
        # test
        for supported, tags in self.hw.generate_tag_expressions():
            for tag in tags:
                res[tag] = supported
        self.assertEqual(res["hardware::testme2"], "yes")
        self.assertEqual(res["hardware::testme1"], "no")

class TestCasePrinter(unittest.TestCase):

    def _make_cups_mock(self):
        import cups
        cups_mock = Mock()
        cups_connection_mock = Mock(cups.Connection)
        cups_mock.Connection.return_value = cups_connection_mock
        return cups_mock, cups_connection_mock

    def test_printer(self):
        cups_mock, cups_connection_mock = self._make_cups_mock()
        with patch.dict('sys.modules', { 'cups' : cups_mock }):
            hw = DebtagsAvailableHW()
            cups_connection_mock.getPrinters.return_value = {}
            self.assertEqual(hw._check_hw_debtag("hardware::printer"),
                             HardwareSupported.NO)
            cups_connection_mock.getPrinters.return_value = {
                'deskjet' : { 'print-info' : "some info",
                            },
                }
            self.assertEqual(hw._check_hw_debtag("hardware::printer"),
                            HardwareSupported.YES)

class TestCaseOpenGL(unittest.TestCase):

    TEST_DATA = {
        # these are the strings returns from pyhton debtagshw/opengl.py
        # (vendor, renderer, version)
        ('intel' , ( "Tungsten Graphics, Inc",
                    "Mesa DRI Intel(R) Ironlake Mobile",
                    "2.1 Mesa 7.11")),
        ('amd', ( "X.Org",
                  "Gallium 0.4 on AMD REDWOOD",
                  "2.1 Mesa 8.0.1")),
        ('nouveau', ( "nouveau",
                      "Gallium 0.4 on NVC3",
                      "3.0 Mesa 8.0.1")),
        # binary-only
        ('fglrx', ( "Advanced Micro Devices, Inc.",
                    "ATI Radeon HD 5570",
                    "4.1.11251 Compatibility Profile Context")),
        ('fglrx', ( "Advanced Micro Devices, Inc.",
                    "ATI Radeon HD 5570",
                    "4.1.11251 Compatibility Profile Context")),
        ('nvidia', ( "NVIDIA Corporation",
                     "GeForce GT 440/PCIe/SSE2",
                     "4.2.0 NVIDIA 295.20")),
        # ensure the random one is right
        ('unknown', ( "xxx", "yyy", "zzz" )),
        }

    def test_opengl_driver_detection(self):
        from debtagshw.opengl import OpenGL
        detector = OpenGL()
        func = "_get_opengl_vendor_renderer_version_tuple"
        with patch.object(detector, func) as mock_func:
            for driver, mock_data in self.TEST_DATA:
                mock_func.return_value = mock_data
                self.assertEqual(detector.opengl_driver(), driver)
                if driver != "unknown":
                    opengl_version = detector.opengl_version()
                    self.assertNotEqual(opengl_version, "unknown")


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    unittest.main()
