# 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)