<commit_before>#  Copyright 2008-2011 Nokia Siemens Networks Oyj
#
#  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.

import os
import tempfile
import time

from robot import utils
from robot.common import Statistics
from robot.output import LOGGER, process_outputs

from outputwriter import OutputWriter
from xunitwriter import XUnitWriter
from writer import serialize_log, serialize_report
import jsparser


class ResultWriter(object):

    def __init__(self, settings):
        self._robot_test_output_cached = None
        self._temp_file = None
        self._suite = None
        self._settings = settings

    def write_robot_results(self, data_source):
        data_model = jsparser.create_datamodel_from(data_source)
        data_model.set_generated(time.localtime())
        LogBuilder(data_model, self._settings).create()
        data_model.remove_keywords()
        ReportBuilder(data_model, self._settings).create()
        self._make_xunit(data_source)

    def _make_xunit(self, data_source):
        xunit_path = self._settings['XUnitFile']
        if xunit_path != 'NONE':
            self._robot_test_output([data_source]).serialize_xunit(xunit_path)

    def _robot_test_output(self, data_sources):
        if self._robot_test_output_cached is None:
            self._suite, exec_errors = process_outputs(data_sources, self._settings)
            self._suite.set_options(self._settings)
            self._robot_test_output_cached = RobotTestOutput(self._suite, exec_errors, self._settings)
        return self._robot_test_output_cached

    def write_rebot_results(self, *data_sources):
        combined = self._combine_outputs(data_sources)
        self.write_robot_results(combined)
        if self._temp_file:
            os.remove(self._temp_file)
        return self._suite

    def _combine_outputs(self, data_sources):
        output_file = self._settings['Output']
        if output_file == 'NONE':
            handle, output_file = tempfile.mkstemp(suffix='.xml', prefix='rebot-')
            os.close(handle)
            self._temp_file = output_file
        self._robot_test_output(data_sources).serialize_output(output_file, log=not self._temp_file)
        return output_file


class _Builder(object):

    def __init__(self, data_model, settings):
        self._settings = settings
        self._path = self._parse_file(self._type)
        self._data_model = data_model

    def create(self):
        if self._path:
            self._data_model.set_settings(self._get_settings())
            self._create()
            LOGGER.output_file(self._type, self._path)

    def _parse_file(self, name):
        value = self._settings[name]
        return value if value != 'NONE' else None

    def _url_from_path(self, source, dest):
        if not dest:
            return None
        return utils.get_link_path(dest, os.path.dirname(source))


class LogBuilder(_Builder):
    _type = 'Log'

    def _create(self):
        serialize_log(self._data_model, self._path)

    def _get_settings(self):
        return {
            'title': self._settings['LogTitle'],
            'reportURL': self._url_from_path(self._path,
                                             self._parse_file('Report'))
        }


class ReportBuilder(_Builder):
    _type = 'Report'

    def _create(self):
        serialize_report(self._data_model, self._path)

    def _get_settings(self):
        return {
            'title': self._settings['ReportTitle'],
            'background' : self._resolve_background_colors(),
            'logURL': self._url_from_path(self._path,
                                          self._parse_file('Log'))
        }

    def _resolve_background_colors(self):
        color_str = self._settings['ReportBackground']
        if color_str and color_str.count(':') not in [1, 2]:
            LOGGER.error("Invalid background color '%s'." % color_str)
            color_str = None
        if not color_str:
            color_str = '#99FF66:#FF3333'
        colors = color_str.split(':', 2)
        if len(colors) == 2:
            colors.insert(1, colors[0])
        return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail': colors[2]}


class RobotTestOutput:

    def __init__(self, suite, exec_errors, settings=None):
        self.suite = suite
        self.exec_errors = exec_errors
        if settings:
            params = (settings['SuiteStatLevel'], settings['TagStatInclude'],
                      settings['TagStatExclude'], settings['TagStatCombine'],
                      settings['TagDoc'], settings['TagStatLink'])
        else:
            params = ()
        self.statistics = Statistics(suite, *params)
        self._generator = 'Robot'

    def serialize_output(self, path, log=True):
        if path == 'NONE':
            return
        serializer = OutputWriter(path)
        self.suite.serialize(serializer)
        self.statistics.serialize(serializer)
        self.exec_errors.serialize(serializer)
        serializer.close()
        if log:
            LOGGER.output_file('Output', path)<commit_msg>resultwriter: extracted classes for output and xunit building<commit_after>#  Copyright 2008-2011 Nokia Siemens Networks Oyj
#
#  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.

import os
import tempfile
import time

from robot import utils
from robot.common import Statistics
from robot.output import LOGGER, process_outputs

from outputwriter import OutputWriter
from xunitwriter import XUnitWriter
from writer import serialize_log, serialize_report
import jsparser


class ResultWriter(object):

    def __init__(self, settings):
        self._xml_result = None
        self._suite = None
        self._settings = settings

    def write_robot_results(self, data_source):
        data_model = jsparser.create_datamodel_from(data_source)
        data_model.set_generated(time.localtime())
        LogBuilder(data_model, self._settings).create()
        data_model.remove_keywords()
        ReportBuilder(data_model, self._settings).create()
        XUnitBuilder(self._result_from_xml([data_source]),
                     self._settings).create()

    def _result_from_xml(self, data_sources):
        if not self._xml_result:
            self._suite, errs = process_outputs(data_sources, self._settings)
            self._suite.set_options(self._settings)
            self._xml_result = ResultFromXML(self._suite, errs, self._settings)
        return self._xml_result

    def write_rebot_results(self, *data_sources):
        builder = OutputBuilder(self._result_from_xml(data_sources),
                                self._settings)
        self.write_robot_results(builder.create())
        builder.finalize()
        return self._suite


class _Builder(object):

    def __init__(self, data_model, settings):
        self._settings = settings
        self._path = self._parse_file(self._type)
        self._data_model = data_model

    def create(self):
        if self._path:
            self._data_model.set_settings(self._get_settings())
            self._create()
            LOGGER.output_file(self._type, self._path)

    def _parse_file(self, name):
        value = self._settings[name]
        return value if value != 'NONE' else None

    def _url_from_path(self, source, dest):
        if not dest:
            return None
        return utils.get_link_path(dest, os.path.dirname(source))


class LogBuilder(_Builder):
    _type = 'Log'

    def _create(self):
        serialize_log(self._data_model, self._path)

    def _get_settings(self):
        return {
            'title': self._settings['LogTitle'],
            'reportURL': self._url_from_path(self._path,
                                             self._parse_file('Report'))
        }


class ReportBuilder(_Builder):
    _type = 'Report'

    def _create(self):
        serialize_report(self._data_model, self._path)

    def _get_settings(self):
        return {
            'title': self._settings['ReportTitle'],
            'background' : self._resolve_background_colors(),
            'logURL': self._url_from_path(self._path,
                                          self._parse_file('Log'))
        }

    def _resolve_background_colors(self):
        color_str = self._settings['ReportBackground']
        if color_str and color_str.count(':') not in [1, 2]:
            LOGGER.error("Invalid background color '%s'." % color_str)
            color_str = None
        if not color_str:
            color_str = '#99FF66:#FF3333'
        colors = color_str.split(':', 2)
        if len(colors) == 2:
            colors.insert(1, colors[0])
        return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail': colors[2]}


class OutputBuilder(_Builder):
    _type = 'Output'
    _temp_file = None

    def create(self):
        output_file = self._output_file()
        self._data_model.serialize_output(output_file, log=not self._temp_file)
        return output_file

    def _output_file(self):
        if self._path:
            return self._path
        handle, output_file = tempfile.mkstemp(suffix='.xml', prefix='rebot-')
        os.close(handle)
        self._temp_file = output_file
        return output_file

    def finalize(self):
        if self._temp_file:
            os.remove(self._temp_file)


class XUnitBuilder(_Builder):
    _type = 'XUnitFile'

    def create(self):
        if self._path:
            self._data_model.serialize_xunit(self._path)


class ResultFromXML(object):

    def __init__(self, suite, exec_errors, settings=None):
        self.suite = suite
        self.exec_errors = exec_errors
        if settings:
            params = (settings['SuiteStatLevel'], settings['TagStatInclude'],
                      settings['TagStatExclude'], settings['TagStatCombine'],
                      settings['TagDoc'], settings['TagStatLink'])
        else:
            params = ()
        self.statistics = Statistics(suite, *params)
        self._generator = 'Robot'

    def serialize_output(self, path, log=True):
        if path == 'NONE':
            return
        serializer = OutputWriter(path)
        self.suite.serialize(serializer)
        self.statistics.serialize(serializer)
        self.exec_errors.serialize(serializer)
        serializer.close()
        if log:
            LOGGER.output_file('Output', path)
{'fraction_non_alphanumeric': 0.09531802120141343, 'fraction_numerical': 0.005123674911660777, 'mean_word_length': 2.620402942117045, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 9}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1189373', 'n_tokens_mistral': 3232, 'n_tokens_neox': 3133, 'n_words': 746}