#!/usr/bin/python -tt
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (c) 2012 Intel, Inc.
#
# 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; version 2 of the License
#
# 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.

"""Unit tests for gbs trigger (QuickBuild) functionality"""

import os
import sys
import tempfile
import unittest
from xml.etree import ElementTree as et

from unittest.mock import patch, MagicMock

# Add parent directory to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from gitbuildsys.errors import GbsError


class TestConvertSpacesToNewlines(unittest.TestCase):
    """Test convert_spaces_to_newlines function"""

    def test_simple_spaces(self):
        """Test simple space-separated values"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("pkg1 pkg2 pkg3")
        self.assertEqual(result, "pkg1\npkg2\npkg3")

    def test_multiple_spaces(self):
        """Test multiple spaces between values"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("pkg1    pkg2     pkg3")
        self.assertEqual(result, "pkg1\npkg2\npkg3")

    def test_tabs(self):
        """Test tab-separated values"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("pkg1\tpkg2\tpkg3")
        self.assertEqual(result, "pkg1\npkg2\npkg3")

    def test_mixed_spaces_and_tabs(self):
        """Test mixed spaces and tabs"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("pkg1 \t pkg2\t pkg3")
        self.assertEqual(result, "pkg1\npkg2\npkg3")

    def test_empty_string(self):
        """Test empty string"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("")
        self.assertEqual(result, "")

    def test_none_value(self):
        """Test None value"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines(None)
        self.assertEqual(result, None)

    def test_single_value(self):
        """Test single value without spaces"""
        from gitbuildsys.cmd_qbbuild import convert_spaces_to_newlines
        result = convert_spaces_to_newlines("pkg1")
        self.assertEqual(result, "pkg1")


class TestReadValueFromFile(unittest.TestCase):
    """Test read_value_from_file function"""

    def test_read_simple_file(self):
        """Test reading a simple file with one value per line"""
        from gitbuildsys.cmd_qbbuild import read_value_from_file

        # Create a temporary file
        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("pkg1\n")
            f.write("pkg2\n")
            f.write("pkg3\n")
            temp_path = f.name

        try:
            result = read_value_from_file(temp_path)
            self.assertEqual(result, "pkg1\npkg2\npkg3")
        finally:
            os.unlink(temp_path)

    def test_read_file_with_comments(self):
        """Test reading file with comments (lines starting with #)"""
        from gitbuildsys.cmd_qbbuild import read_value_from_file

        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("# This is a comment\n")
            f.write("pkg1\n")
            f.write("# Another comment\n")
            f.write("pkg2\n")
            temp_path = f.name

        try:
            result = read_value_from_file(temp_path)
            self.assertEqual(result, "pkg1\npkg2")
        finally:
            os.unlink(temp_path)

    def test_read_file_with_empty_lines(self):
        """Test reading file with empty lines"""
        from gitbuildsys.cmd_qbbuild import read_value_from_file

        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("pkg1\n")
            f.write("\n")
            f.write("pkg2\n")
            f.write("\n")
            f.write("pkg3\n")
            temp_path = f.name

        try:
            result = read_value_from_file(temp_path)
            self.assertEqual(result, "pkg1\npkg2\npkg3")
        finally:
            os.unlink(temp_path)

    def test_file_not_found(self):
        """Test reading non-existent file"""
        from gitbuildsys.cmd_qbbuild import read_value_from_file

        with self.assertRaises(GbsError) as context:
            read_value_from_file('/nonexistent/path/file.txt')

        self.assertIn('File not found', str(context.exception))

    def test_read_file_with_trailing_spaces(self):
        """Test reading file with trailing spaces on lines"""
        from gitbuildsys.cmd_qbbuild import read_value_from_file

        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("pkg1  \n")
            f.write("  pkg2  \n")
            f.write("  pkg3\n")
            temp_path = f.name

        try:
            result = read_value_from_file(temp_path)
            self.assertEqual(result, "pkg1\npkg2\npkg3")
        finally:
            os.unlink(temp_path)


class TestProcessVariableValue(unittest.TestCase):
    """Test process_variable_value function"""

    def test_file_reference(self):
        """Test processing file reference (starts with @)"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        # Create a temporary file
        with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
            f.write("pkg1\n")
            f.write("pkg2\n")
            temp_path = f.name

        try:
            result = process_variable_value('build_pkg_list_add', '@' + temp_path)
            self.assertEqual(result, "pkg1\npkg2")
        finally:
            os.unlink(temp_path)

    def test_space_separated_multi_value(self):
        """Test processing space-separated multi-value variable"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        result = process_variable_value('build_pkg_list_add', 'pkg1 pkg2 pkg3')
        self.assertEqual(result, "pkg1\npkg2\npkg3")

    def test_single_value_multi_var(self):
        """Test single value for multi-value variable (no conversion needed)"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        result = process_variable_value('build_pkg_list_add', 'pkg1')
        self.assertEqual(result, "pkg1")

    def test_non_multi_value_variable(self):
        """Test non-multi-value variable (no space conversion)"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        result = process_variable_value('build_type', 'Full')
        self.assertEqual(result, "Full")

    def test_empty_value(self):
        """Test empty value"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        result = process_variable_value('build_type', '')
        self.assertEqual(result, '')

    def test_none_value(self):
        """Test None value"""
        from gitbuildsys.cmd_qbbuild import process_variable_value

        result = process_variable_value('build_type', None)
        self.assertEqual(result, None)


class TestRenderTemplate(unittest.TestCase):
    """Test render_template function"""

    def setUp(self):
        """Create a test template file"""
        self.template_content = '''<?xml version="1.0" encoding="UTF-8"?>
<build>
    <configurationId></configurationId>
    <variables>
        <entry>
            <string>build_type</string>
            <string>Partial</string>
        </entry>
        <entry>
            <string>repo_type</string>
            <string>ALL</string>
        </entry>
        <entry>
            <string>build_reference</string>
            <string>Ref. Snapshot</string>
        </entry>
        <entry>
            <string>build_pkg_list_add</string>
            <string></string>
        </entry>
        <entry>
            <string>build_pkg_list_modify</string>
            <string></string>
        </entry>
        <entry>
            <string>build_pkg_list_rm</string>
            <string></string>
        </entry>
    </variables>
</build>'''

        with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False) as f:
            f.write(self.template_content)
            self.template_path = f.name

    def tearDown(self):
        """Clean up template file"""
        if os.path.exists(self.template_path):
            os.unlink(self.template_path)

    def test_render_with_config_id(self):
        """Test rendering template with configuration ID"""
        from gitbuildsys.cmd_qbbuild import render_template

        tree = render_template(self.template_path, '12345', {})
        root = tree.find('configurationId')
        self.assertEqual(root.text, '12345')

    def test_render_with_single_variable(self):
        """Test rendering template with single variable"""
        from gitbuildsys.cmd_qbbuild import render_template

        variables = {'build_type': 'Full'}
        tree = render_template(self.template_path, '12345', variables)

        vars_elem = tree.find('variables')
        for entry in vars_elem.findall('entry'):
            strings = entry.findall('string')
            if strings[0].text == 'build_type':
                self.assertEqual(strings[1].text, 'Full')

    def test_render_with_multiple_variables(self):
        """Test rendering template with multiple variables"""
        from gitbuildsys.cmd_qbbuild import render_template

        variables = {
            'build_type': 'Full',
            'build_reference': 'Live',
            'build_pkg_list_add': 'pkg1\npkg2'
        }
        tree = render_template(self.template_path, '12345', variables)

        vars_elem = tree.find('variables')
        found_vars = {}
        for entry in vars_elem.findall('entry'):
            strings = entry.findall('string')
            if len(strings) >= 2:
                found_vars[strings[0].text] = strings[1].text

        self.assertEqual(found_vars['build_type'], 'Full')
        self.assertEqual(found_vars['build_reference'], 'Live')
        self.assertEqual(found_vars['build_pkg_list_add'], 'pkg1\npkg2')

    def test_render_preserves_unset_variables(self):
        """Test that unset variables keep their original values"""
        from gitbuildsys.cmd_qbbuild import render_template

        # Only set build_type, other variables should keep original values
        variables = {'build_type': 'Full'}
        tree = render_template(self.template_path, '12345', variables)

        vars_elem = tree.find('variables')
        for entry in vars_elem.findall('entry'):
            strings = entry.findall('string')
            if strings[0].text == 'repo_type':
                # Should keep original value 'ALL'
                self.assertEqual(strings[1].text, 'ALL')
            elif strings[0].text == 'build_reference':
                # Should keep original value 'Ref. Snapshot'
                self.assertEqual(strings[1].text, 'Ref. Snapshot')

    def test_render_empty_variables(self):
        """Test rendering template with empty variables dict"""
        from gitbuildsys.cmd_qbbuild import render_template

        tree = render_template(self.template_path, '12345', {})

        # Configuration ID should still be set
        root = tree.find('configurationId')
        self.assertEqual(root.text, '12345')

        # All variables should keep original values
        vars_elem = tree.find('variables')
        for entry in vars_elem.findall('entry'):
            strings = entry.findall('string')
            if strings[0].text == 'build_type':
                self.assertEqual(strings[1].text, 'Partial')


class TestNoDefaultMerge(unittest.TestCase):
    """Test that variables are NOT merged with defaults"""

    def test_only_user_variables_sent(self):
        """Test that only user-provided variables are included"""
        from gitbuildsys.cmd_qbbuild import render_template

        # Create a test template
        template_content = '''<?xml version="1.0" encoding="UTF-8"?>
<build>
    <configurationId></configurationId>
    <variables>
        <entry>
            <string>build_type</string>
            <string>Partial</string>
        </entry>
        <entry>
            <string>build_pkg_list_add</string>
            <string>original_value</string>
        </entry>
    </variables>
</build>'''

        with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False) as f:
            f.write(template_content)
            template_path = f.name

        try:
            # User only sets build_pkg_list_add
            # build_type should NOT be overwritten with default
            variables = {'build_pkg_list_add': 'new_package'}
            tree = render_template(template_path, '12345', variables)

            vars_elem = tree.find('variables')
            for entry in vars_elem.findall('entry'):
                strings = entry.findall('string')
                if strings[0].text == 'build_type':
                    # Should keep original template value, not default
                    self.assertEqual(strings[1].text, 'Partial')
                elif strings[0].text == 'build_pkg_list_add':
                    self.assertEqual(strings[1].text, 'new_package')
        finally:
            os.unlink(template_path)


class TestMultiValueVariables(unittest.TestCase):
    """Test multi-value variable handling"""

    def test_multi_value_vars_list(self):
        """Test that MULTI_VALUE_VARS contains correct variables"""
        from gitbuildsys.cmd_qbbuild import MULTI_VALUE_VARS

        self.assertIn('build_pkg_list_add', MULTI_VALUE_VARS)
        self.assertIn('build_pkg_list_modify', MULTI_VALUE_VARS)
        self.assertIn('build_pkg_list_rm', MULTI_VALUE_VARS)

    def test_space_conversion_for_multi_value(self):
        """Test space to newline conversion for multi-value variables"""
        from gitbuildsys.cmd_qbbuild import process_variable_value, MULTI_VALUE_VARS

        # Test all multi-value variables
        for var_name in MULTI_VALUE_VARS:
            result = process_variable_value(var_name, 'pkg1 pkg2 pkg3')
            self.assertEqual(result, 'pkg1\npkg2\npkg3',
                           f"Failed for {var_name}")


if __name__ == '__main__':
    unittest.main()