Repository: oppia/oppia
File: scripts/linters/general_purpose_linter_test.py (Python)

Code before:
                [CONSTANTS_FILEPATH], FILE_CACHE)
            lint_task_report = linter.check_bad_patterns()
        self.assertEqual(len(lint_task_report.trimmed_messages), 1)
        self.assertTrue(lint_task_report.trimmed_messages[0].endswith(
            'constants.ts --> Please set the EMULATOR_MODE variable in '
            'constants.ts to true before committing.'))

        self.assertEqual('Bad pattern', lint_task_report.name)
        self.assertTrue(lint_task_report.failed)

    def test_linter_with_no_files(self) -> None:
        lint_task_report = general_purpose_linter.GeneralPurposeLinter(
            [], FILE_CACHE).perform_all_lint_checks()
        self.assertEqual(
            [
                'There are no files to be checked.',
                'SUCCESS  General purpose lint check passed'],
            lint_task_report[0].get_report())
        self.assertEqual('General purpose lint', lint_task_report[0].name)
        self.assertFalse(lint_task_report[0].failed)

    def test_file_with_no_newline_at_eof(self) -> None:
        temp_file = tempfile.NamedTemporaryFile(
            mode='w+', suffix='.py', delete=False)

        content = """from __future__ import annotations


                    class FakeClass:
                        \"\"\"Fake docstring for valid syntax purposes.\"\"\"

                        def __init__(self, fake_arg):
                            self.fake_arg = fake_arg

                        def fake_method(self, name):
                                \"\"\"This doesn't do anything.

                                Args:
                                    name: str. Means nothing.

                                Yields:
                                    tuple(str, str).
                                \"\"\"
                                yield (name, name)
                        """
        temp_file.write(content)
        temp_file.close()
        linter = general_purpose_linter.GeneralPurposeLinter(
            [temp_file.name], FILE_CACHE)
        lint_task_report = linter.check_newline_at_eof()
        self.assert_same_list_elements(

Review comment (refactor):
Note that this only doesn't have a newline at the end of the string "by chance" -- the last line of the file is actually the string "                        " (line 349).

Could you please reformat this similar to what is done in core/controllers/editor.py (around line 370) so that this mimics an actual Python file?

If you like, you can also move this constant up to the top of this file and call it INVALID_NO_NEWLINE_FILE_CONTENT. That might be a little cleaner. You can also leave a content above the `temp_file.write(content)` line below explaining that we use a temporary file here rather than an actual one because the Black formatter auto-fixes newlines at the end of files in LINTER_TESTS_DIR when it is run.

Code after:
        self.assertEqual(len(lint_task_report.trimmed_messages), 1)
        self.assertTrue(lint_task_report.trimmed_messages[0].endswith(
            'constants.ts --> Please set the DEV_MODE variable in '
            'constants.ts to true before committing.'))

        self.assertEqual('Bad pattern', lint_task_report.name)
        self.assertTrue(lint_task_report.failed)

    def test_invalid_emulator_mode_in_constants_ts(self) -> None:
        def mock_readlines(unused_self: str) -> Tuple[str, ...]:
            return (
                'Copyright 2020 The Oppia Authors. All Rights Reserved.',
                ' * @fileoverview Initializes constants for '
                'the Oppia codebase.',
                '"DEV_MODE": true,\n'
                '"EMULATOR_MODE": false\n')

        with self.swap(FILE_CACHE, 'readlines', mock_readlines):
            linter = general_purpose_linter.GeneralPurposeLinter(
                [CONSTANTS_FILEPATH], FILE_CACHE)
            lint_task_report = linter.check_bad_patterns()
        self.assertEqual(len(lint_task_report.trimmed_messages), 1)
        self.assertTrue(lint_task_report.trimmed_messages[0].endswith(
            'constants.ts --> Please set the EMULATOR_MODE variable in '
            'constants.ts to true before committing.'))

        self.assertEqual('Bad pattern', lint_task_report.name)
        self.assertTrue(lint_task_report.failed)

    def test_linter_with_no_files(self) -> None:
        lint_task_report = general_purpose_linter.GeneralPurposeLinter(
            [], FILE_CACHE).perform_all_lint_checks()
        self.assertEqual(
            [
                'There are no files to be checked.',
                'SUCCESS  General purpose lint check passed'],
            lint_task_report[0].get_report())
        self.assertEqual('General purpose lint', lint_task_report[0].name)
        self.assertFalse(lint_task_report[0].failed)

    def test_file_with_no_newline_at_eof(self) -> None:
        temp_file = tempfile.NamedTemporaryFile(
            mode='w+', suffix='.py', delete=False)

        # We use a temporary file here instead of a real one because
        # the Black formatter auto-fixes newlines at the end of files.
        temp_file.write(INVALID_NO_NEWLINE_FILE_CONTENT)
        temp_file.close()
        linter = general_purpose_linter.GeneralPurposeLinter(
            [temp_file.name], FILE_CACHE)
        lint_task_report = linter.check_newline_at_eof()