# Path: pre_commit_hooks/end_of_file_fixer.py
# def fix_file(file_obj: IO[bytes]) -> int:
#     # Test for newline at end of file
#     # Empty files will throw IOError here
#     try:
#         file_obj.seek(-1, os.SEEK_END)
#     except OSError:
#         return 0
#     last_character = file_obj.read(1)
#     # last_character will be '' for an empty file
#     if last_character not in {b'\n', b'\r'} and last_character != b'':
#         # Needs this seek for windows, otherwise IOError
#         file_obj.seek(0, os.SEEK_END)
#         file_obj.write(b'\n')
#         return 1
# 
#     while last_character in {b'\n', b'\r'}:
#         # Deal with the beginning of the file
#         if file_obj.tell() == 1:
#             # If we've reached the beginning of the file and it is all
#             # linebreaks then we can make this file empty
#             file_obj.seek(0)
#             file_obj.truncate()
#             return 1
# 
#         # Go back two bytes and read a character
#         file_obj.seek(-2, os.SEEK_CUR)
#         last_character = file_obj.read(1)
# 
#     # Our current position is at the end of the file just before any amount of
#     # newlines.  If we find extraneous newlines, then backtrack and trim them.
#     position = file_obj.tell()
#     remaining = file_obj.read()
#     for sequence in (b'\n', b'\r\n', b'\r'):
#         if remaining == sequence:
#             return 0
#         elif remaining.startswith(sequence):
#             file_obj.seek(position + len(sequence))
#             file_obj.truncate()
#             return 1
# 
#     return 0
# 
# Path: pre_commit_hooks/end_of_file_fixer.py
# def main(argv: Sequence[str] | None = None) -> int:
#     parser = argparse.ArgumentParser()
#     parser.add_argument('filenames', nargs='*', help='Filenames to fix')
#     args = parser.parse_args(argv)
# 
#     retv = 0
# 
#     for filename in args.filenames:
#         # Read as binary so we can read byte-by-byte
#         with open(filename, 'rb+') as file_obj:
#             ret_for_file = fix_file(file_obj)
#             if ret_for_file:
#                 print(f'Fixing {filename}')
#             retv |= ret_for_file
# 
#     return retv


import io
import pytest
from pre_commit_hooks.end_of_file_fixer import fix_file
from pre_commit_hooks.end_of_file_fixer import main
from __future__ import annotations





# Input, expected return value, expected output
TESTS = (
    (b'foo\n', 0, b'foo\n'),
    (b'', 0, b''),
    (b'\n\n', 1, b''),
    (b'\n\n\n\n', 1, b''),
    (b'foo', 1, b'foo\n'),
    (b'foo\n\n\n', 1, b'foo\n'),
    (b'\xe2\x98\x83', 1, b'\xe2\x98\x83\n'),
    (b'foo\r\n', 0, b'foo\r\n'),
    (b'foo\r\n\r\n\r\n', 1, b'foo\r\n'),
    (b'foo\r', 0, b'foo\r'),
    (b'foo\r\r\r\r', 1, b'foo\r'),
)


@pytest.mark.parametrize(('input_s', 'expected_retval', 'output'), TESTS)
def test_fix_file(input_s, expected_retval, output):
    file_obj = io.BytesIO(input_s)

# Path: pre_commit_hooks/end_of_file_fixer.py
# def fix_file(file_obj: IO[bytes]) -> int:
#     # Test for newline at end of file
#     # Empty files will throw IOError here
#     try:
#         file_obj.seek(-1, os.SEEK_END)
#     except OSError:
#         return 0
#     last_character = file_obj.read(1)
#     # last_character will be '' for an empty file
#     if last_character not in {b'\n', b'\r'} and last_character != b'':
#         # Needs this seek for windows, otherwise IOError
#         file_obj.seek(0, os.SEEK_END)
#         file_obj.write(b'\n')
#         return 1
# 
#     while last_character in {b'\n', b'\r'}:
#         # Deal with the beginning of the file
#         if file_obj.tell() == 1:
#             # If we've reached the beginning of the file and it is all
#             # linebreaks then we can make this file empty
#             file_obj.seek(0)
#             file_obj.truncate()
#             return 1
# 
#         # Go back two bytes and read a character
#         file_obj.seek(-2, os.SEEK_CUR)
#         last_character = file_obj.read(1)
# 
#     # Our current position is at the end of the file just before any amount of
#     # newlines.  If we find extraneous newlines, then backtrack and trim them.
#     position = file_obj.tell()
#     remaining = file_obj.read()
#     for sequence in (b'\n', b'\r\n', b'\r'):
#         if remaining == sequence:
#             return 0
#         elif remaining.startswith(sequence):
#             file_obj.seek(position + len(sequence))
#             file_obj.truncate()
#             return 1
# 
#     return 0
# 
# Path: pre_commit_hooks/end_of_file_fixer.py
# def main(argv: Sequence[str] | None = None) -> int:
#     parser = argparse.ArgumentParser()
#     parser.add_argument('filenames', nargs='*', help='Filenames to fix')
#     args = parser.parse_args(argv)
# 
#     retv = 0
# 
#     for filename in args.filenames:
#         # Read as binary so we can read byte-by-byte
#         with open(filename, 'rb+') as file_obj:
#             ret_for_file = fix_file(file_obj)
#             if ret_for_file:
#                 print(f'Fixing {filename}')
#             retv |= ret_for_file
# 
#     return retv


# Path: tests/end_of_file_fixer_test.py
import io
import pytest
from pre_commit_hooks.end_of_file_fixer import fix_file
from pre_commit_hooks.end_of_file_fixer import main

from __future__ import annotations





# Input, expected return value, expected output
TESTS = (
    (b'foo\n', 0, b'foo\n'),
    (b'', 0, b''),
    (b'\n\n', 1, b''),
    (b'\n\n\n\n', 1, b''),
    (b'foo', 1, b'foo\n'),
    (b'foo\n\n\n', 1, b'foo\n'),
    (b'\xe2\x98\x83', 1, b'\xe2\x98\x83\n'),
    (b'foo\r\n', 0, b'foo\r\n'),
    (b'foo\r\n\r\n\r\n', 1, b'foo\r\n'),
    (b'foo\r', 0, b'foo\r'),
    (b'foo\r\r\r\r', 1, b'foo\r'),
)


@pytest.mark.parametrize(('input_s', 'expected_retval', 'output'), TESTS)
def test_fix_file(input_s, expected_retval, output):
    file_obj = io.BytesIO(input_s)

    ret = fix_file(file_obj)