# Copyright 2017-2019 IBM Corp. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Function tests for 'zhmc info' command, including tests for global options
that can be tested only with a subcommand.
"""

from __future__ import absolute_import, print_function

import os
import subprocess
import json
import pytest
import click

from zhmcclient_mock import FakedSession

from .utils import call_zhmc_child, call_zhmc_inline, assert_rc, \
    assert_patterns

CLICK_VERSION = [int(v) for v in click.__version__.split('.')]


class TestInfo(object):
    """
    All tests for the 'zhmc info' command, including tests for global options
    that can be tested only with a subcommand.
    """

    def test_info_help(self):
        # pylint: disable=no-self-use
        """Test 'zhmc info --help'"""

        # Invoke the command to be tested
        rc, stdout, stderr = call_zhmc_child(['info', '--help'])

        assert_rc(0, rc, stdout, stderr)
        assert stdout.startswith(
            "Usage: zhmc info [OPTIONS]\n"), \
            "stdout={s!r}".format(s=stdout)
        assert stderr == ""

    def test_info_error_no_host(self):
        # pylint: disable=no-self-use
        """Test 'zhmc info' when no host is provided"""

        # Invoke the command to be tested
        rc, stdout, stderr = call_zhmc_child(['info'])

        assert_rc(1, rc, stdout, stderr)
        assert stdout == ""
        assert stderr.startswith(
            "Error: No HMC host provided\n"), \
            "stderr={s!r}".format(s=stderr)

    def test_info_error_no_conn(self):
        # pylint: disable=no-self-use
        """Test zhmc info when host is specified but no connection to host"""

        # Invoke the command to be tested
        rc, stdout, stderr = call_zhmc_child(
            ['info'],
            {'ZHMC_HOST': 'invalid_host'}
        )

        assert_rc(1, rc, stdout, stderr)
        assert stdout == ""
        assert stderr.startswith(
            "Error: ConnectionError: "), \
            "stderr={s!r}".format(s=stderr)

    @pytest.mark.parametrize(
        # Transpose only affects metrics output, but not info output.
        # Transpose is accepted and ignored for all table output formats.
        "transpose_opt", [
            None,
            '-x',
            '--transpose',
        ]
    )
    @pytest.mark.parametrize(
        "out_format, exp_stdout_template", [
            ('table',
             # Order of properties must match:
             '+-------------------+----------+\n'
             '| Field Name        | Value    |\n'
             '|-------------------+----------|\n'
             '| api-major-version | {v[amaj]:<8} |\n'
             '| api-minor-version | {v[amin]:<8} |\n'
             '| hmc-name          | {v[hnam]:8} |\n'
             '| hmc-version       | {v[hver]:8} |\n'
             '+-------------------+----------+\n'),
            ('plain',
             # Order of properties must match:
             'Field Name         Value\n'
             'api-major-version  {v[amaj]}\n'
             'api-minor-version  {v[amin]}\n'
             'hmc-name           {v[hnam]}\n'
             'hmc-version        {v[hver]}\n'),
            ('simple',
             # Order of properties must match:
             'Field Name         Value\n'
             '-----------------  --------\n'
             'api-major-version  {v[amaj]}\n'
             'api-minor-version  {v[amin]}\n'
             'hmc-name           {v[hnam]}\n'
             'hmc-version        {v[hver]}\n'),
            ('psql',
             # Order of properties must match:
             '+-------------------+----------+\n'
             '| Field Name        | Value    |\n'
             '|-------------------+----------|\n'
             '| api-major-version | {v[amaj]:<8} |\n'
             '| api-minor-version | {v[amin]:<8} |\n'
             '| hmc-name          | {v[hnam]:8} |\n'
             '| hmc-version       | {v[hver]:8} |\n'
             '+-------------------+----------+\n'),
            ('rst',
             # Order of properties must match:
             '=================  ========\n'
             'Field Name         Value\n'
             '=================  ========\n'
             'api-major-version  {v[amaj]}\n'
             'api-minor-version  {v[amin]}\n'
             'hmc-name           {v[hnam]}\n'
             'hmc-version        {v[hver]}\n'
             '=================  ========\n'),
            ('mediawiki',
             # Order of properties must match:
             '{{| class="wikitable" style="text-align: left;"\n'
             '|+ <!-- caption -->\n'
             '|-\n'
             '! Field Name        !! Value\n'
             '|-\n'
             '| api-major-version || {v[amaj]}\n'
             '|-\n'
             '| api-minor-version || {v[amin]}\n'
             '|-\n'
             '| hmc-name          || {v[hnam]}\n'
             '|-\n'
             '| hmc-version       || {v[hver]}\n'
             '|}}\n'),
            ('html',
             # Order of properties must match:
             '<table>\n'
             '<thead>\n'
             '<tr><th>Field Name       </th><th>Value   </th></tr>\n'
             '</thead>\n'
             '<tbody>\n'
             '<tr><td>api-major-version</td><td>{v[amaj]:<8}</td></tr>\n'
             '<tr><td>api-minor-version</td><td>{v[amin]:<8}</td></tr>\n'
             '<tr><td>hmc-name         </td><td>{v[hnam]:8}</td></tr>\n'
             '<tr><td>hmc-version      </td><td>{v[hver]:8}</td></tr>\n'
             '</tbody>\n'
             '</table>\n'),
            ('latex',
             # Order of properties must match:
             '\\begin{{tabular}}{{ll}}\n'
             '\\hline\n'
             ' Field Name        & Value    \\\\\n'
             '\\hline\n'
             ' api-major-version & {v[amaj]:<8} \\\\\n'
             ' api-minor-version & {v[amin]:<8} \\\\\n'
             ' hmc-name          & {v[hnam]:8} \\\\\n'
             ' hmc-version       & {v[hver]:8} \\\\\n'
             '\\hline\n'
             '\\end{{tabular}}\n'),
        ]
    )
    @pytest.mark.parametrize(
        "out_opt", ['-o', '--output-format']
    )
    @pytest.mark.parametrize(
        "hmc_name, hmc_version, api_version", [
            ('hmc-name', '2.14.0', '2.20'),
        ]
    )
    def test_option_outputformat_table(
            self, hmc_name, hmc_version, api_version, out_opt, out_format,
            exp_stdout_template, transpose_opt):
        # pylint: disable=no-self-use
        """
        Test 'zhmc info' with global options (-o, --output-format) and
        (-x, --transpose), for all table formats.
        """

        faked_session = FakedSession(
            'fake-host', hmc_name, hmc_version, api_version)
        api_version_parts = [int(vp) for vp in api_version.split('.')]
        exp_values = {
            'hnam': hmc_name,
            'hver': hmc_version,
            'amaj': api_version_parts[0],
            'amin': api_version_parts[1],
        }
        exp_stdout = exp_stdout_template.format(v=exp_values)

        args = [out_opt, out_format]
        if transpose_opt is not None:
            args.append(transpose_opt)
        args.append('info')

        # Invoke the command to be tested
        rc, stdout, stderr = call_zhmc_inline(
            args, faked_session=faked_session)

        assert_rc(0, rc, stdout, stderr)
        assert stdout == exp_stdout
        assert stderr == ""

    JSON_STDOUT_TEMPLATE = \
        '{{' \
        '"api-major-version": {v[amaj]},' \
        '"api-minor-version": {v[amin]},' \
        '"hmc-name": "{v[hnam]}",' \
        '"hmc-version": "{v[hver]}"' \
        '}}'

    JSON_CONFLICT_PATTERNS = [
        r"Error: Transposing output tables .* conflicts with non-table "
        r"output format .* json",
    ]

    @pytest.mark.parametrize(
        "transpose_opt, exp_rc, exp_stdout_template, exp_stderr_patterns", [
            (None, 0, JSON_STDOUT_TEMPLATE, None),
            ('-x', 1, None, JSON_CONFLICT_PATTERNS),
            ('--transpose', 1, None, JSON_CONFLICT_PATTERNS),
        ]
    )
    @pytest.mark.parametrize(
        "out_opt", ['-o', '--output-format']
    )
    @pytest.mark.parametrize(
        "hmc_name, hmc_version, api_version", [
            ('hmc-name', '2.14.0', '2.20'),
        ]
    )
    def test_option_outputformat_json(
            self, hmc_name, hmc_version, api_version, out_opt, transpose_opt,
            exp_rc, exp_stdout_template, exp_stderr_patterns):
        # pylint: disable=no-self-use
        """
        Test 'zhmc info' with global options (-o, --output-format) and
        (-x, --transpose), for the 'json' output format.
        """

        faked_session = FakedSession(
            'fake-host', hmc_name, hmc_version, api_version)

        args = [out_opt, 'json']
        if transpose_opt is not None:
            args.append(transpose_opt)
        args.append('info')

        # Invoke the command to be tested
        rc, stdout, stderr = call_zhmc_inline(
            args, faked_session=faked_session)

        assert_rc(exp_rc, rc, stdout, stderr)

        if exp_stdout_template:
            api_version_parts = [int(vp) for vp in api_version.split('.')]
            exp_values = {