普通文本  |  197行  |  7.27 KB

# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Unit tests for error_handlers.py."""


import unittest

from .. style_references import parse_patch
from checker import ProcessorOptions
from error_handlers import DefaultStyleErrorHandler
from error_handlers import PatchStyleErrorHandler


class StyleErrorHandlerTestBase(unittest.TestCase):

    def setUp(self):
        self._error_messages = ""
        self._error_count = 0

    def _mock_increment_error_count(self):
        self._error_count += 1

    def _mock_stderr_write(self, message):
        self._error_messages += message


class DefaultStyleErrorHandlerTest(StyleErrorHandlerTestBase):

    """Tests DefaultStyleErrorHandler class."""

    _file_path = "foo.h"

    _category = "whitespace/tab"

    def _error_handler(self, options):
        return DefaultStyleErrorHandler(self._file_path,
                                        options,
                                        self._mock_increment_error_count,
                                        self._mock_stderr_write)

    def _check_initialized(self):
        """Check that count and error messages are initialized."""
        self.assertEquals(0, self._error_count)
        self.assertEquals("", self._error_messages)

    def _call(self, handle_error, options, confidence):
        """Handle an error with the given error handler."""
        line_number = 100
        message = "message"

        handle_error(line_number, self._category, confidence, message)

    def _call_error_handler(self, options, confidence):
        """Handle an error using a new error handler."""
        handle_error = self._error_handler(options)
        self._call(handle_error, options, confidence)

    def test_call_non_reportable(self):
        """Test __call__() method with a non-reportable error."""
        confidence = 1
        options = ProcessorOptions(verbosity=3)
        self._check_initialized()

        # Confirm the error is not reportable.
        self.assertFalse(options.is_reportable(self._category,
                                               confidence,
                                               self._file_path))

        self._call_error_handler(options, confidence)

        self.assertEquals(0, self._error_count)
        self.assertEquals("", self._error_messages)

    def test_call_reportable_emacs(self):
        """Test __call__() method with a reportable error and emacs format."""
        confidence = 5
        options = ProcessorOptions(verbosity=3, output_format="emacs")
        self._check_initialized()

        self._call_error_handler(options, confidence)

        self.assertEquals(1, self._error_count)
        self.assertEquals(self._error_messages,
                          "foo.h:100:  message  [whitespace/tab] [5]\n")

    def test_call_reportable_vs7(self):
        """Test __call__() method with a reportable error and vs7 format."""
        confidence = 5
        options = ProcessorOptions(verbosity=3, output_format="vs7")
        self._check_initialized()

        self._call_error_handler(options, confidence)

        self.assertEquals(1, self._error_count)
        self.assertEquals(self._error_messages,
                          "foo.h(100):  message  [whitespace/tab] [5]\n")

    def test_call_max_reports_per_category(self):
        """Test error report suppression in __call__() method."""
        confidence = 5
        options = ProcessorOptions(verbosity=3,
                                   max_reports_per_category={self._category: 2})
        error_handler = self._error_handler(options)

        self._check_initialized()

        # First call: usual reporting.
        self._call(error_handler, options, confidence)
        self.assertEquals(1, self._error_count)
        self.assertEquals(self._error_messages,
                          "foo.h:100:  message  [whitespace/tab] [5]\n")

        # Second call: suppression message reported.
        self._error_messages = ""
        self._call(error_handler, options, confidence)
        self.assertEquals(2, self._error_count)
        self.assertEquals(self._error_messages,
                          "foo.h:100:  message  [whitespace/tab] [5]\n"
                          "Suppressing further [%s] reports for this file.\n"
                          % self._category)

        # Third call: no report.
        self._error_messages = ""
        self._call(error_handler, options, confidence)
        self.assertEquals(3, self._error_count)
        self.assertEquals(self._error_messages, "")


class PatchStyleErrorHandlerTest(StyleErrorHandlerTestBase):

    """Tests PatchStyleErrorHandler class."""

    _file_path = "__init__.py"

    _patch_string = """diff --git a/__init__.py b/__init__.py
index ef65bee..e3db70e 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1 +1,2 @@
 # Required for Python to search this directory for module files
+# New line

"""

    def test_call(self):
        patch_files = parse_patch(self._patch_string)
        diff = patch_files[self._file_path]

        options = ProcessorOptions(verbosity=3)

        handle_error = PatchStyleErrorHandler(diff,
                                              self._file_path,
                                              options,
                                              self._mock_increment_error_count,
                                              self._mock_stderr_write)

        category = "whitespace/tab"
        confidence = 5
        message = "message"

        # Confirm error is reportable.
        self.assertTrue(options.is_reportable(category,
                                              confidence,
                                              self._file_path))

        # Confirm error count initialized to zero.
        self.assertEquals(0, self._error_count)

        # Test error in unmodified line (error count does not increment).
        handle_error(1, category, confidence, message)
        self.assertEquals(0, self._error_count)

        # Test error in modified line (error count increments).
        handle_error(2, category, confidence, message)
        self.assertEquals(1, self._error_count)