import platform
from datetime import datetime
import os
import time
import unittest
import threading

from collections import defaultdict

from logz import log
from jinja2 import Template

from htmlrunner.result import Result
from htmlrunner.loader import Loader
from htmlrunner.utils import isnotsuite, group_test_by_class


BASEDIR = os.path.dirname(os.path.abspath(__file__))


DEFAULT_REPORT_FILE = 'report.html'

DEFAULT_LOG_FILE = 'run.log'

DEFAULT_REPORT_TITLE = 'TEST REPORT BY HTMLRUNNER'

DEFAULT_TEMPLATE = 'default'


def run_suite_after(suite, result):  # todo
    suite._tearDownPreviousClass(None, result)
    suite._handleModuleTearDown(result)


def run_suite_before_case(suite, case, result):  # todo
    suite._tearDownPreviousClass(case, result)
    suite._handleModuleFixture(case, result)
    suite._handleClassSetUp(case, result)
    result._previousTestClass = case.__class__
    if (getattr(case.__class__, '_classSetupFailed', False) or getattr(result, '_moduleSetUpFailed', False)):
        return False
    return True


class Runner(object):
    def __init__(self,
                 threads=None,
                 timeout=None,
                 interval=None,
                 failfast=False,
                 ensure_sequence=True,
                 check_all=False,
                 **kwargs):
        self.threads = threads
        self.interval = interval
        self.reruns = False  # todo
        self.timeout = timeout   # 每个用例的执行时间
        self.failfast = failfast
        self.kwargs = kwargs
        self.ensure_sequence = ensure_sequence  # 确保运行顺序
        self.check_all = check_all  # todo

    def run_with_threads(self, case, result):
        assert self.threads and isinstance(self.threads, int) and self.threads > 0
        if self.timeout:
            assert isinstance(self.timeout, (float, int)) and self.timeout > 0

        threads = []
        for i in range(self.threads):
            threads.append(threading.Thread(target=case, args=(result,)))

        [t.start() for t in threads]

        [t.join(timeout=self.timeout) for t in threads]

    def run_test(self, test, result):
        """执行单个测试"""
        if self.threads and isinstance(self.threads, int):
            print(self.threads, self.timeout)
            self.run_with_threads(test, result)
        else:
            test(result)
        interval = self.interval
        print('interval', interval)
        if interval and isinstance(interval, (int, float)):
            time.sleep(interval)

    def run_suite(self, suite, result):
        """基础运行suite方法"""
        log.info('执行测试套件:', suite)
        topLevel = False
        if getattr(result, '_testRunEntered', False) is False:
            result._testRunEntered = topLevel = True

        for index, test in enumerate(suite):
            if isnotsuite(test):
                setup_ok = run_suite_before_case(suite, test, result)
                if not setup_ok:
                    continue
            self.run_test(test, result)
            if suite._cleanup:
                suite._removeTestAtIndex(index)

        if topLevel:
            run_suite_after(suite, result)
            result._testRunEntered = False

        return result

    def run(self, suite, callback=None, interval=None):
        result = Result()
        result.failfast = self.failfast is True

        result.start_at = datetime.now()
        self.run_suite(suite, result)
        result.end_at = datetime.now()
        if callback:
            callback(result)
        return result


class HTMLRunner(Runner):
    def __init__(self, report_file=None, log_file=None,  output=None, # 报告文件, 日志文件, 自动创建路径
                 title=None, description=None, tester=None,   # 报告内容
                 template=None, lang=None,  # 模板及语言
                 verbosity=2, failfast=False,
                 threads=None, timeout=None,  # 运行选项
                 interval=None,
                 **kwargs):  # 额外信息
        self.verbosity = verbosity
        self.failfast = failfast
        self.interval = interval
        self.output = output
        self.report_file = datetime.now().strftime(report_file or DEFAULT_REPORT_FILE)
        self.log_file = log.file = datetime.now().strftime(log_file or DEFAULT_LOG_FILE)

        self.title = title or DEFAULT_REPORT_TITLE
        self.description = description
        self.tester = tester
        self.template = template or DEFAULT_TEMPLATE
        self.kwargs = kwargs
        super().__init__(threads, timeout, interval)

    def generate_report(self, result):
        template_path = os.path.join(BASEDIR, 'templates', '%s.html' % self.template)

        with open(template_path) as f:
            template_content = f.read()

        test_classes = result.sortByClass()
        # 报告配置信息
        report_config_info = {
            "title": self.title,
            "description": self.description,
            "tester": self.tester
        }
        # 结果统计
        result_stats_info = {
            "total": result.totol,
            "run_num": result.testsRun,
            "pass_num": len(result.success),
            "fail_num": len(result.failures),
            "skipped_num": len(result.skipped),
            "error_num": len(result.errors),
            "xfail_num": len(result.expectedFailures),
            "xpass_num": len(result.unexpectedSuccesses),
            "rerun_num": 0,
            "start_at": result.start_at,
            "end_at": result.end_at,
            "duration": result.end_at - result.start_at,
        }
        # 环境信息
        env_info = result.get_env_info()
        context = {
            "result": result,
            "test_cases": result.result,
            "test_classes": test_classes,
        }
        [context.update(info) for info in (report_config_info,
                                           result_stats_info,
                                           env_info,
                                           self.kwargs)]  # 额外变量

        content = Template(template_content).render(context)
        if self.output:
            if not os.path.isdir(self.output):
                os.makedirs(self.output)  # todo try
        self.report_file = os.path.join(self.output, self.report_file)
        with open(self.report_file, "w") as f:
            f.write(content)

    def run(self, suite, callback=None, interval=None, debug=False):
        result = super().run(suite, callback=self.generate_report, interval=interval)
        return result


if __name__ == "__main__":
    pass
import platform
from datetime import datetime
import os
import time
import unittest
import threading

from collections import defaultdict

from logz import log
from jinja2 import Template

from htmlrunner.result import Result
from htmlrunner.loader import Loader
from htmlrunner.utils import isnotsuite, group_test_by_class


BASEDIR = os.path.dirname(os.path.abspath(__file__))


DEFAULT_REPORT_FILE = 'report.html'

DEFAULT_LOG_FILE = 'run.log'

DEFAULT_REPORT_TITLE = 'TEST REPORT BY HTMLRUNNER'

DEFAULT_TEMPLATE = 'default'


def run_suite_after(suite, result):  # todo
    suite._tearDownPreviousClass(None, result)
    suite._handleModuleTearDown(result)


def run_suite_before_case(suite, case, result):  # todo
    suite._tearDownPreviousClass(case, result)
    suite._handleModuleFixture(case, result)
    suite._handleClassSetUp(case, result)
    result._previousTestClass = case.__class__
    if (getattr(case.__class__, '_classSetupFailed', False) or getattr(result, '_moduleSetUpFailed', False)):
        return False
    return True


class Runner(object):
    def __init__(self,
                 threads=None,
                 timeout=None,
                 interval=None,
                 failfast=False,
                 ensure_sequence=True,
                 check_all=False,
                 **kwargs):
        self.threads = threads
        self.interval = interval
        self.reruns = False  # todo
        self.timeout = timeout   # 每个用例的执行时间
        self.failfast = failfast
        self.kwargs = kwargs
        self.ensure_sequence = ensure_sequence  # 确保运行顺序
        self.check_all = check_all  # todo

    def run_with_threads(self, case, result):
        assert self.threads and isinstance(self.threads, int) and self.threads > 0
        if self.timeout:
            assert isinstance(self.timeout, (float, int)) and self.timeout > 0

        threads = []
        for i in range(self.threads):
            threads.append(threading.Thread(target=case, args=(result,)))

        [t.start() for t in threads]

        [t.join(timeout=self.timeout) for t in threads]

    def run_test(self, test, result):
        """执行单个测试"""
        if self.threads and isinstance(self.threads, int):
            print(self.threads, self.timeout)
            self.run_with_threads(test, result)
        else:
            test(result)
        interval = self.interval
        print('interval', interval)
        if interval and isinstance(interval, (int, float)):
            time.sleep(interval)

    def run_suite(self, suite, result):
        """基础运行suite方法"""
        log.info('执行测试套件:', suite)
        topLevel = False
        if getattr(result, '_testRunEntered', False) is False:
            result._testRunEntered = topLevel = True

        for index, test in enumerate(suite):
            if isnotsuite(test):
                setup_ok = run_suite_before_case(suite, test, result)
                if not setup_ok:
                    continue
            self.run_test(test, result)
            if suite._cleanup:
                suite._removeTestAtIndex(index)

        if topLevel:
            run_suite_after(suite, result)
            result._testRunEntered = False

        return result

    def run(self, suite, callback=None, interval=None):
        result = Result()
        result.failfast = self.failfast is True

        result.start_at = datetime.now()
        self.run_suite(suite, result)
        result.end_at = datetime.now()
        if callback:
            callback(result)
        return result


class HTMLRunner(Runner):
    def __init__(self, report_file=None, log_file=None,  output=None, # 报告文件, 日志文件, 自动创建路径
                 title=None, description=None, tester=None,   # 报告内容
                 template=None, lang=None,  # 模板及语言
                 verbosity=2, failfast=False,
                 threads=None, timeout=None,  # 运行选项
                 interval=None,
                 **kwargs):  # 额外信息
        self.verbosity = verbosity
        self.failfast = failfast
        self.interval = interval
        self.output = output
        self.report_file = datetime.now().strftime(report_file or DEFAULT_REPORT_FILE)
        self.log_file = log.file = datetime.now().strftime(log_file or DEFAULT_LOG_FILE)

        self.title = title or DEFAULT_REPORT_TITLE
        self.description = description
        self.tester = tester
        self.template = template or DEFAULT_TEMPLATE
        self.kwargs = kwargs
        super().__init__(threads, timeout, interval)

    def generate_report(self, result):
        template_path = os.path.join(BASEDIR, 'templates', '%s.html' % self.template)

        with open(template_path) as f:
            template_content = f.read()

        test_classes = result.sortByClass()
        # 报告配置信息
        report_config_info = {
            "title": self.title,
            "description": self.description,
            "tester": self.tester
        }
        # 结果统计
        result_stats_info = {
            "total": result.totol,
            "run_num": result.testsRun,
            "pass_num": len(result.success),
            "fail_num": len(result.failures),
            "skipped_num": len(result.skipped),
            "error_num": len(result.errors),
            "xfail_num": len(result.expectedFailures),
            "xpass_num": len(result.unexpectedSuccesses),
            "rerun_num": 0,
            "start_at": result.start_at,
            "end_at": result.end_at,
            "duration": result.end_at - result.start_at,
        }
        # 环境信息
        env_info = result.get_env_info()
        context = {
            "result": result,
            "test_cases": result.result,
            "test_classes": test_classes,
        }
        [context.update(info) for info in (report_config_info,
                                           result_stats_info,
                                           env_info,
                                           self.kwargs)]  # 额外变量

        content = Template(template_content).render(context)
        if self.output:
            if not os.path.isdir(self.output):
                os.makedirs(self.output)  # todo try
        self.report_file = os.path.join(self.output, self.report_file)
        with open(self.report_file, "w") as f:
            f.write(content)

    def run(self, suite, callback=None, interval=None, debug=False):
        result = super().run(suite, callback=self.generate_report, interval=interval)
        return result


if __name__ == "__main__":
    pass
# todo # todo # todo # 每个用例的执行时间 # 确保运行顺序 # todo 执行单个测试 基础运行suite方法 # 报告文件, 日志文件, 自动创建路径 # 报告内容 # 模板及语言 # 运行选项 # 额外信息 # 报告配置信息 # 结果统计 # 环境信息 # 额外变量 # todo try