1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#
3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Redistribution and use in source and binary forms, with or without
4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# modification, are permitted provided that the following conditions
5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# are met:
6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 1.  Redistributions of source code must retain the above copyright
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     notice, this list of conditions and the following disclaimer.
8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 2.  Redistributions in binary form must reproduce the above copyright
9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     notice, this list of conditions and the following disclaimer in the
10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     documentation and/or other materials provided with the distribution.
11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#
12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""Contains unit tests for filereader.py."""
24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
2521939df44de1705786c545cd1bf519d47250322dBen Murdochfrom __future__ import with_statement
2621939df44de1705786c545cd1bf519d47250322dBen Murdoch
2721939df44de1705786c545cd1bf519d47250322dBen Murdochimport codecs
28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport os
29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport shutil
30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport tempfile
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport unittest
32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.common.system.logtesting import LoggingTestCase
34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.style.checker import ProcessorBase
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.style.filereader import TextFileReader
36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass TextFileReaderTest(LoggingTestCase):
39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    class MockProcessor(ProcessorBase):
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """A processor for test purposes.
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        This processor simply records the parameters passed to its process()
45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        method for later checking by the unittest test methods.
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        def __init__(self):
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self.processed = []
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            """The parameters passed for all calls to the process() method."""
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        def should_process(self, file_path):
54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return not file_path.endswith('should_not_process.txt')
55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        def process(self, lines, file_path, test_kwarg=None):
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self.processed.append((lines, file_path, test_kwarg))
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def setUp(self):
60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        LoggingTestCase.setUp(self)
61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        processor = TextFileReaderTest.MockProcessor()
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        temp_dir = tempfile.mkdtemp()
64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._file_reader = TextFileReader(processor)
66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._processor = processor
67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._temp_dir = temp_dir
68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def tearDown(self):
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        LoggingTestCase.tearDown(self)
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        shutil.rmtree(self._temp_dir)
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
7321939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _create_file(self, rel_path, text, encoding="utf-8"):
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Create a file with given text and return the path to the file."""
7521939df44de1705786c545cd1bf519d47250322dBen Murdoch        # FIXME: There are better/more secure APIs for creatin tmp file paths.
76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        file_path = os.path.join(self._temp_dir, rel_path)
7721939df44de1705786c545cd1bf519d47250322dBen Murdoch        with codecs.open(file_path, "w", encoding) as file:
7821939df44de1705786c545cd1bf519d47250322dBen Murdoch            file.write(text)
79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return file_path
80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _passed_to_processor(self):
82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Return the parameters passed to MockProcessor.process()."""
83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return self._processor.processed
84dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _assert_file_reader(self, passed_to_processor, file_count):
86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Assert the state of the file reader."""
87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.assertEquals(passed_to_processor, self._passed_to_processor())
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.assertEquals(file_count, self._file_reader.file_count)
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_process_file__does_not_exist(self):
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        try:
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self._file_reader.process_file('does_not_exist.txt')
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        except SystemExit, err:
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self.assertEquals(str(err), '1')
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else:
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self.fail('No Exception raised.')
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._assert_file_reader([], 1)
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.assertLog(["ERROR: File does not exist: 'does_not_exist.txt'\n"])
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_process_file__is_dir(self):
101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        temp_dir = os.path.join(self._temp_dir, 'test_dir')
102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        os.mkdir(temp_dir)
103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._file_reader.process_file(temp_dir)
105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # Because the log message below contains exception text, it is
107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # possible that the text varies across platforms.  For this reason,
108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # we check only the portion of the log message that we control,
109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # namely the text at the beginning.
110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        log_messages = self.logMessages()
111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # We remove the message we are looking at to prevent the tearDown()
112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # from raising an exception when it asserts that no log messages
113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # remain.
114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        message = log_messages.pop()
115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.assertTrue(message.startswith('WARNING: Could not read file. '
117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                           "Skipping: '%s'\n  " % temp_dir))
118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
119dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._assert_file_reader([], 1)
120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
12121939df44de1705786c545cd1bf519d47250322dBen Murdoch    def test_process_file__should_not_process(self):
12221939df44de1705786c545cd1bf519d47250322dBen Murdoch        file_path = self._create_file('should_not_process.txt', 'contents')
12321939df44de1705786c545cd1bf519d47250322dBen Murdoch
12421939df44de1705786c545cd1bf519d47250322dBen Murdoch        self._file_reader.process_file(file_path)
12521939df44de1705786c545cd1bf519d47250322dBen Murdoch        self._assert_file_reader([], 1)
12621939df44de1705786c545cd1bf519d47250322dBen Murdoch
127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_process_file__multiple_lines(self):
128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        file_path = self._create_file('foo.txt', 'line one\r\nline two\n')
129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._file_reader.process_file(file_path)
131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        processed = [(['line one\r', 'line two', ''], file_path, None)]
132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._assert_file_reader(processed, 1)
133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
13421939df44de1705786c545cd1bf519d47250322dBen Murdoch    def test_process_file__file_stdin(self):
13521939df44de1705786c545cd1bf519d47250322dBen Murdoch        file_path = self._create_file('-', 'file contents')
13621939df44de1705786c545cd1bf519d47250322dBen Murdoch
13721939df44de1705786c545cd1bf519d47250322dBen Murdoch        self._file_reader.process_file(file_path=file_path, test_kwarg='foo')
13821939df44de1705786c545cd1bf519d47250322dBen Murdoch        processed = [(['file contents'], file_path, 'foo')]
13921939df44de1705786c545cd1bf519d47250322dBen Murdoch        self._assert_file_reader(processed, 1)
14021939df44de1705786c545cd1bf519d47250322dBen Murdoch
141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_process_file__with_kwarg(self):
142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        file_path = self._create_file('foo.txt', 'file contents')
143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._file_reader.process_file(file_path=file_path, test_kwarg='foo')
145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        processed = [(['file contents'], file_path, 'foo')]
146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._assert_file_reader(processed, 1)
147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_process_paths(self):
149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        # We test a list of paths that contains both a file and a directory.
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        dir = os.path.join(self._temp_dir, 'foo_dir')
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        os.mkdir(dir)
152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        file_path1 = self._create_file('file1.txt', 'foo')
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rel_path = os.path.join('foo_dir', 'file2.txt')
156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        file_path2 = self._create_file(rel_path, 'bar')
157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._file_reader.process_paths([dir, file_path1])
159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        processed = [(['bar'], file_path2, None),
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                     (['foo'], file_path1, None)]
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._assert_file_reader(processed, 2)
162dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
163dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    def test_count_delete_only_file(self):
164dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        self._file_reader.count_delete_only_file()
165dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        delete_only_file_count = self._file_reader.delete_only_file_count
166dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        self.assertEquals(delete_only_file_count, 1)
167