#!/usr/bin/env python
"""Test suite for autoflake."""
import contextlib
import functools
import io
import os
import re
import shutil
import subprocess
import sys
import tempfile
import unittest

import autoflake


ROOT_DIRECTORY = os.path.abspath(os.path.dirname(__file__))


AUTOFLAKE_COMMAND = [
    sys.executable,
    os.path.join(
        ROOT_DIRECTORY,
        "autoflake.py",
    ),
]


class UnitTests(unittest.TestCase):

    """Unit tests."""

    def test_imports(self):
        self.assertGreater(len(autoflake.SAFE_IMPORTS), 0)

    def test_unused_import_line_numbers(self):
        self.assertEqual(
            [1],
            list(
                autoflake.unused_import_line_numbers(
                    autoflake.check("import os\n"),
                ),
            ),
        )

    def test_unused_import_line_numbers_with_from(self):
        self.assertEqual(
            [1],
            list(
                autoflake.unused_import_line_numbers(
                    autoflake.check("from os import path\n"),
                ),
            ),
        )

    def test_unused_import_line_numbers_with_dot(self):
        self.assertEqual(
            [1],
            list(
                autoflake.unused_import_line_numbers(
                    autoflake.check("import os.path\n"),
                ),
            ),
        )

    def test_extract_package_name(self):
        self.assertEqual("os", autoflake.extract_package_name("import os"))
        self.assertEqual(
            "os",
            autoflake.extract_package_name("from os import path"),
        )
        self.assertEqual(
            "os",
            autoflake.extract_package_name("import os.path"),
        )

    def test_extract_package_name_should_ignore_doctest_for_now(self):
        self.assertFalse(autoflake.extract_package_name(">>> import os"))

    def test_standard_package_names(self):
        self.assertIn("os", list(autoflake.standard_package_names()))
        self.assertIn("subprocess", list(autoflake.standard_package_names()))
        self.assertIn("urllib", list(autoflake.standard_package_names()))

        self.assertNotIn("autoflake", list(autoflake.standard_package_names()))
        self.assertNotIn("pep8", list(autoflake.standard_package_names()))

    def test_get_line_ending(self):
        self.assertEqual("\n", autoflake.get_line_ending("\n"))
        self.assertEqual("\n", autoflake.get_line_ending("abc\n"))
        self.assertEqual("\t  \t\n", autoflake.get_line_ending("abc\t  \t\n"))

        self.assertEqual("", autoflake.get_line_ending("abc"))
        self.assertEqual("", autoflake.get_line_ending(""))

    def test_get_indentation(self):
        self.assertEqual("", autoflake.get_indentation(""))
        self.assertEqual("    ", autoflake.get_indentation("    abc"))
        self.assertEqual("    ", autoflake.get_indentation("    abc  \n\t"))
        self.assertEqual("\t", autoflake.get_indentation("\tabc  \n\t"))
        self.assertEqual(" \t ", autoflake.get_indentation(" \t abc  \n\t"))
        self.assertEqual("", autoflake.get_indentation("    "))

    def test_filter_star_import(self):
        self.assertEqual(
            "from math import cos",
            autoflake.filter_star_import(
                "from math import *",
                ["cos"],
            ),
        )

        self.assertEqual(
            "from math import cos, sin",
            autoflake.filter_star_import(
                "from math import *",
                ["sin", "cos"],
            ),
        )

    def test_filter_unused_variable(self):
        self.assertEqual(
            "foo()",
            autoflake.filter_unused_variable("x = foo()"),
        )

        self.assertEqual(
            "    foo()",
            autoflake.filter_unused_variable("    x = foo()"),
        )

    def test_filter_unused_variable_with_literal_or_name(self):
        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = 1"),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = y"),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = {}"),
        )

    def test_filter_unused_variable_with_basic_data_structures(self):
        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = dict()"),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = list()"),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = set()"),
        )

    def test_filter_unused_variable_should_ignore_multiline(self):
        self.assertEqual(
            "x = foo()\\",
            autoflake.filter_unused_variable("x = foo()\\"),
        )

    def test_filter_unused_variable_should_multiple_assignments(self):
        self.assertEqual(
            "x = y = foo()",
            autoflake.filter_unused_variable("x = y = foo()"),
        )

    def test_filter_unused_variable_with_exception(self):
        self.assertEqual(
            "except Exception:",
            autoflake.filter_unused_variable("except Exception as exception:"),
        )

        self.assertEqual(
            "except (ImportError, ValueError):",
            autoflake.filter_unused_variable(
                "except (ImportError, ValueError) as foo:",
            ),
        )

    def test_filter_unused_variable_drop_rhs(self):
        self.assertEqual(
            "",
            autoflake.filter_unused_variable(
                "x = foo()",
                drop_rhs=True,
            ),
        )

        self.assertEqual(
            "",
            autoflake.filter_unused_variable(
                "    x = foo()",
                drop_rhs=True,
            ),
        )

    def test_filter_unused_variable_with_literal_or_name_drop_rhs(self):
        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = 1", drop_rhs=True),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = y", drop_rhs=True),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = {}", drop_rhs=True),
        )

    def test_filter_unused_variable_with_basic_data_structures_drop_rhs(self):
        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = dict()", drop_rhs=True),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = list()", drop_rhs=True),
        )

        self.assertEqual(
            "pass",
            autoflake.filter_unused_variable("x = set()", drop_rhs=True),
        )

    def test_filter_unused_variable_should_ignore_multiline_drop_rhs(self):
        self.assertEqual(
            "x = foo()\\",
            autoflake.filter_unused_variable("x = foo()\\", drop_rhs=True),
        )

    def test_filter_unused_variable_should_multiple_assignments_drop_rhs(self):
        self.assertEqual(
            "x = y = foo()",
            autoflake.filter_unused_variable("x = y = foo()", drop_rhs=True),
        )

    def test_filter_unused_variable_with_exception_drop_rhs(self):
        self.assertEqual(
            "except Exception:",
            autoflake.filter_unused_variable(
                "except Exception as exception:",
                drop_rhs=True,
            ),
        )

        self.assertEqual(
            "except (ImportError, ValueError):",
            autoflake.filter_unused_variable(
                "except (ImportError, ValueError) as foo:",
                drop_rhs=True,
            ),
        )

    def test_filter_code(self):
        self.assertEqual(
            """\
import os
pass
os.foo()
""",
            "".join(
                autoflake.filter_code(
                    """\
import os
import re
os.foo()
""",
                ),
            ),
        )

    def test_filter_code_with_indented_import(self):
        self.assertEqual(
            """\
import os
if True:
    pass
os.foo()
""",
            "".join(
                autoflake.filter_code(
                    """\
import os
if True:
    import re
os.foo()
""",
                ),
            ),
        )

    def test_filter_code_with_from(self):
        self.assertEqual(
            """\
pass
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
from os import path
x = 1
""",
                ),
            ),
        )

    def test_filter_code_with_not_from(self):
        self.assertEqual(
            """\
pass
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
import frommer
x = 1
""",
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_with_used_from(self):
        self.assertEqual(
            """\
import frommer
print(frommer)
""",
            "".join(
                autoflake.filter_code(
                    """\
import frommer
print(frommer)
""",
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_with_ambiguous_from(self):
        self.assertEqual(
            """\
pass
""",
            "".join(
                autoflake.filter_code(
                    """\
from frommer import abc, frommer, xyz
""",
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_should_avoid_inline_except(self):
        line = """\
try: from zap import foo
except: from zap import bar
"""
        self.assertEqual(
            line,
            "".join(
                autoflake.filter_code(
                    line,
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_should_avoid_escaped_newlines(self):
        line = """\
try:\\
from zap import foo
except:\\
from zap import bar
"""
        self.assertEqual(
            line,
            "".join(
                autoflake.filter_code(
                    line,
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_with_remove_all_unused_imports(self):
        self.assertEqual(
            """\
pass
pass
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
import foo
import zap
x = 1
""",
                    remove_all_unused_imports=True,
                ),
            ),
        )

    def test_filter_code_with_additional_imports(self):
        self.assertEqual(
            """\
pass
import zap
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
import foo
import zap
x = 1
""",
                    additional_imports=["foo", "bar"],
                ),
            ),
        )

    def test_filter_code_should_ignore_imports_with_inline_comment(self):
        self.assertEqual(
            """\
from os import path  # foo
pass
from fake_foo import z  # foo, foo, zap
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
from os import path  # foo
from os import path
from fake_foo import z  # foo, foo, zap
x = 1
""",
                ),
            ),
        )

    def test_filter_code_should_respect_noqa(self):
        self.assertEqual(
            """\
pass
import re  # noqa
from subprocess import Popen  # NOQA
x = 1
""",
            "".join(
                autoflake.filter_code(
                    """\
from os import path
import re  # noqa
from subprocess import Popen  # NOQA
x = 1
""",
                ),
            ),
        )

    def test_filter_code_expand_star_imports(self):
        self.assertEqual(
            """\
from math import sin
sin(1)
""",
            "".join(
                autoflake.filter_code(
                    """\
from math import *
sin(1)
""",
                    expand_star_imports=True,
                ),
            ),
        )

        self.assertEqual(
            """\
from math import cos, sin
sin(1)
cos(1)
""",
            "".join(
                autoflake.filter_code(
                    """\
from math import *
sin(1)
cos(1)
""",
                    expand_star_imports=True,
                ),
            ),
        )

    def test_filter_code_ignore_multiple_star_import(self):
        self.assertEqual(
            """\
from math import *
from re import *
sin(1)
cos(1)
""",
            "".join(
                autoflake.filter_code(
                    """\
from math import *
from re import *
sin(1)
cos(1)
""",
                    expand_star_imports=True,
                ),
            ),
        )

    def test_filter_code_with_special_re_symbols_in_key(self):
        self.assertEqual(
            """\
a = {
  '????': 2,
}
print(a)
""",
            "".join(
                autoflake.filter_code(
                    """\
a = {
  '????': 3,
  '????': 2,
}
print(a)
""",
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_multiline_import(self):
        self.assertTrue(
            autoflake.multiline_import(
                r"""\
import os, \
    math, subprocess
""",
            ),
        )

        self.assertFalse(
            autoflake.multiline_import(
                """\
import os, math, subprocess
""",
            ),
        )

        self.assertTrue(
            autoflake.multiline_import(
                """\
import os, math, subprocess
""",
                previous_line="if: \\\n",
            ),
        )

        self.assertTrue(
            autoflake.multiline_import("from os import (path, sep)"),
        )

    def test_multiline_statement(self):
        self.assertFalse(autoflake.multiline_statement("x = foo()"))

        self.assertTrue(autoflake.multiline_statement("x = 1;"))
        self.assertTrue(autoflake.multiline_statement("import os, \\"))
        self.assertTrue(autoflake.multiline_statement("foo("))
        self.assertTrue(
            autoflake.multiline_statement(
                "1",
                previous_line="x = \\",
            ),
        )

    def test_break_up_import(self):
        self.assertEqual(
            "import abc\nimport math\nimport subprocess\n",
            autoflake.break_up_import("import abc, subprocess, math\n"),
        )

    def test_break_up_import_with_indentation(self):
        self.assertEqual(
            "    import abc\n    import math\n    import subprocess\n",
            autoflake.break_up_import("    import abc, subprocess, math\n"),
        )

    def test_break_up_import_should_do_nothing_on_no_line_ending(self):
        self.assertEqual(
            "import abc, subprocess, math",
            autoflake.break_up_import("import abc, subprocess, math"),
        )

    def test_filter_from_import_no_remove(self):
        self.assertEqual(
            """\
    from foo import abc, math, subprocess\n""",
            autoflake.filter_from_import(
                "    from foo import abc, subprocess, math\n",
                unused_module=[],
            ),
        )

    def test_filter_from_import_remove_module(self):
        self.assertEqual(
            """\
    from foo import math, subprocess\n""",
            autoflake.filter_from_import(
                "    from foo import abc, subprocess, math\n",
                unused_module=["foo.abc"],
            ),
        )

    def test_filter_from_import_remove_all(self):
        self.assertEqual(
            "    pass\n",
            autoflake.filter_from_import(
                "    from foo import abc, subprocess, math\n",
                unused_module=[
                    "foo.abc",
                    "foo.subprocess",
                    "foo.math",
                ],
            ),
        )

    def test_filter_code_multiline_imports(self):
        self.assertEqual(
            r"""\
import os
pass
import os
os.foo()
""",
            "".join(
                autoflake.filter_code(
                    r"""\
import os
import re
import os, \
    math, subprocess
os.foo()
""",
                ),
            ),
        )

    def test_filter_code_multiline_from_imports(self):
        self.assertEqual(
            r"""\
import os
pass
from os.path import (
    join,
)
join('a', 'b')
pass
os.foo()
from os.path import \
    isdir
isdir('42')
""",
            "".join(
                autoflake.filter_code(
                    r"""\
import os
import re
from os.path import (
    exists,
    join,
)
join('a', 'b')
from os.path import \
    abspath, basename, \
    commonpath
os.foo()
from os.path import \
    isfile \
    , isdir
isdir('42')
""",
                ),
            ),
        )

    def test_filter_code_should_ignore_semicolons(self):
        self.assertEqual(
            r"""\
import os
pass
import os; import math, subprocess
os.foo()
""",
            "".join(
                autoflake.filter_code(
                    r"""\
import os
import re
import os; import math, subprocess
os.foo()
""",
                ),
            ),
        )

    def test_filter_code_should_ignore_non_standard_library(self):
        self.assertEqual(
            """\
import os
import my_own_module
pass
from my_package import another_module
from my_package import subprocess
from my_blah.my_blah_blah import blah
os.foo()
""",
            "".join(
                autoflake.filter_code(
                    """\
import os
import my_own_module
import re
from my_package import another_module
from my_package import subprocess
from my_blah.my_blah_blah import blah
os.foo()
""",
                ),
            ),
        )

    def test_filter_code_should_ignore_unsafe_imports(self):
        self.assertEqual(
            """\
import rlcompleter
pass
pass
pass
print(1)
""",
            "".join(
                autoflake.filter_code(
                    """\
import rlcompleter
import sys
import io
import os
print(1)
""",
                ),
            ),
        )

    def test_filter_code_should_ignore_docstring(self):
        line = """
def foo():
    '''
    >>> import math
    '''
"""
        self.assertEqual(line, "".join(autoflake.filter_code(line)))

    def test_with_ignore_init_module_imports_flag(self):
        # Need a temp directory in order to specify file name as __init__.py
        temp_directory = tempfile.mkdtemp(dir=".")
        temp_file = os.path.join(temp_directory, "__init__.py")
        try:
            with open(temp_file, "w") as output:
                output.write("import re\n")

            p = subprocess.Popen(
                list(AUTOFLAKE_COMMAND) + ["--ignore-init-module-imports", temp_file],
                stdout=subprocess.PIPE,
            )
            result = p.communicate()[0].decode("utf-8")

            self.assertNotIn("import re", result)
        finally:
            shutil.rmtree(temp_directory)

    def test_without_ignore_init_module_imports_flag(self):
        # Need a temp directory in order to specify file name as __init__.py
        temp_directory = tempfile.mkdtemp(dir=".")
        temp_file = os.path.join(temp_directory, "__init__.py")
        try:
            with open(temp_file, "w") as output:
                output.write("import re\n")

            p = subprocess.Popen(
                list(AUTOFLAKE_COMMAND) + [temp_file],
                stdout=subprocess.PIPE,
            )
            result = p.communicate()[0].decode("utf-8")

            self.assertIn("import re", result)
        finally:
            shutil.rmtree(temp_directory)

    def test_fix_code(self):
        self.assertEqual(
            """\
import os
import math
from sys import version
os.foo()
math.pi
x = version
""",
            autoflake.fix_code(
                """\
import os
import re
import abc, math, subprocess
from sys import exit, version
os.foo()
math.pi
x = version
""",
            ),
        )

    def test_fix_code_with_from_and_as(self):
        self.assertEqual(
            """\
from collections import namedtuple as xyz
xyz
""",
            autoflake.fix_code(
                """\
from collections import defaultdict, namedtuple as xyz
xyz
""",
            ),
        )

        self.assertEqual(
            """\
from collections import namedtuple as xyz
xyz
""",
            autoflake.fix_code(
                """\
from collections import defaultdict as abc, namedtuple as xyz
xyz
""",
            ),
        )

        self.assertEqual(
            """\
from collections import namedtuple
namedtuple
""",
            autoflake.fix_code(
                """\
from collections import defaultdict as abc, namedtuple
namedtuple
""",
            ),
        )

        self.assertEqual(
            """\
""",
            autoflake.fix_code(
                """\
from collections import defaultdict as abc, namedtuple as xyz
""",
            ),
        )

    def test_fix_code_with_from_with_and_without_remove_all(self):
        code = """\
from x import a as b, c as d
"""

        self.assertEqual(
            """\
""",
            autoflake.fix_code(code, remove_all_unused_imports=True),
        )

        self.assertEqual(
            code,
            autoflake.fix_code(code, remove_all_unused_imports=False),
        )

    def test_fix_code_with_from_and_depth_module(self):
        self.assertEqual(
            """\
from distutils.version import StrictVersion
StrictVersion('1.0.0')
""",
            autoflake.fix_code(
                """\
from distutils.version import LooseVersion, StrictVersion
StrictVersion('1.0.0')
""",
            ),
        )

        self.assertEqual(
            """\
from distutils.version import StrictVersion as version
version('1.0.0')
""",
            autoflake.fix_code(
                """\
from distutils.version import LooseVersion, StrictVersion as version
version('1.0.0')
""",
            ),
        )

    def test_fix_code_with_indented_from(self):
        self.assertEqual(
            """\
def z():
    from ctypes import POINTER, byref
    POINTER, byref
    """,
            autoflake.fix_code(
                """\
def z():
    from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
    POINTER, byref
    """,
            ),
        )

        self.assertEqual(
            """\
def z():
    pass
""",
            autoflake.fix_code(
                """\
def z():
    from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
""",
            ),
        )

    def test_fix_code_with_empty_string(self):
        self.assertEqual(
            "",
            autoflake.fix_code(""),
        )

    def test_fix_code_with_from_and_as_and_escaped_newline(self):
        """Make sure stuff after escaped newline is not lost."""
        result = autoflake.fix_code(
            """\
from collections import defaultdict, namedtuple \\
    as xyz
xyz
""",
        )
        # We currently leave lines with escaped newlines as is. But in the
        # future this we may parse them and remove unused import accordingly.
        # For now, we'll work around it here.
        result = re.sub(r" *\\\n *as ", " as ", result)

        self.assertEqual(
            """\
from collections import namedtuple as xyz
xyz
""",
            autoflake.fix_code(result),
        )

    def test_fix_code_with_unused_variables(self):
        self.assertEqual(
            """\
def main():
    y = 11
    print(y)
""",
            autoflake.fix_code(
                """\
def main():
    x = 10
    y = 11
    print(y)
""",
                remove_unused_variables=True,
            ),
        )

    def test_fix_code_with_unused_variables_drop_rhs(self):
        self.assertEqual(
            """\
def main():
    y = 11
    print(y)
""",
            autoflake.fix_code(
                """\
def main():
    x = 10
    y = 11
    print(y)
""",
                remove_unused_variables=True,
                remove_rhs_for_unused_variables=True,
            ),
        )

    def test_fix_code_with_unused_variables_should_skip_nonlocal(self):
        """pyflakes does not handle nonlocal correctly."""
        code = """\
def bar():
    x = 1

    def foo():
        nonlocal x
        x = 2
"""
        self.assertEqual(
            code,
            autoflake.fix_code(
                code,
                remove_unused_variables=True,
            ),
        )

    def test_fix_code_with_unused_variables_should_skip_nonlocal_drop_rhs(
        self,
    ):
        """pyflakes does not handle nonlocal correctly."""
        code = """\
def bar():
    x = 1

    def foo():
        nonlocal x
        x = 2
"""
        self.assertEqual(
            code,
            autoflake.fix_code(
                code,
                remove_unused_variables=True,
                remove_rhs_for_unused_variables=True,
            ),
        )

    def test_detect_encoding_with_bad_encoding(self):
        with temporary_file("# -*- coding: blah -*-\n") as filename:
            self.assertEqual(
                "latin-1",
                autoflake.detect_encoding(filename),
            )

    def test_fix_code_with_comma_on_right(self):
        """pyflakes does not handle nonlocal correctly."""
        self.assertEqual(
            """\
def main():
    pass
""",
            autoflake.fix_code(
                """\
def main():
    x = (1, 2, 3)
""",
                remove_unused_variables=True,
            ),
        )

    def test_fix_code_with_comma_on_right_drop_rhs(self):
        """pyflakes does not handle nonlocal correctly."""
        self.assertEqual(
            """\
def main():
    pass
""",
            autoflake.fix_code(
                """\
def main():
    x = (1, 2, 3)
""",
                remove_unused_variables=True,
                remove_rhs_for_unused_variables=True,
            ),
        )

    def test_fix_code_with_unused_variables_should_skip_multiple(self):
        code = """\
def main():
    (x, y, z) = (1, 2, 3)
    print(z)
"""
        self.assertEqual(
            code,
            autoflake.fix_code(
                code,
                remove_unused_variables=True,
            ),
        )

    def test_fix_code_with_unused_variables_should_skip_multiple_drop_rhs(
        self,
    ):
        code = """\
def main():
    (x, y, z) = (1, 2, 3)
    print(z)
"""
        self.assertEqual(
            code,
            autoflake.fix_code(
                code,
                remove_unused_variables=True,
                remove_rhs_for_unused_variables=True,
            ),
        )

    def test_fix_code_should_handle_pyflakes_recursion_error_gracefully(self):
        code = "x = [{}]".format("+".join(["abc" for _ in range(2000)]))
        self.assertEqual(
            code,
            autoflake.fix_code(code),
        )

    def test_fix_code_with_duplicate_key(self):
        self.assertEqual(
            """\
a = {
  (0,1): 3,
}
print(a)
""",
            "".join(
                autoflake.fix_code(
                    """\
a = {
  (0,1): 1,
  (0, 1): 'two',
  (0,1): 3,
}
print(a)
""",
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_with_duplicate_key_longer(self):
        self.assertEqual(
            """\
{
    'a': 0,
    'c': 2,
    'd': 3,
    'e': 4,
    'f': 5,
    'b': 6,
}
""",
            "".join(
                autoflake.fix_code(
                    """\
{
    'a': 0,
    'b': 1,
    'c': 2,
    'd': 3,
    'e': 4,
    'f': 5,
    'b': 6,
}
""",
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_with_duplicate_key_with_many_braces(self):
        self.assertEqual(
            """\
a = None

{None: {None: None},
 }

{
    None: a.b,
}
""",
            "".join(
                autoflake.fix_code(
                    """\
a = None

{None: {None: None},
 }

{
    None: a.a,
    None: a.b,
}
""",
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_complex_case_of_duplicate_key(self):
        """We only handle simple cases."""
        code = """\
a = {(0,1): 1, (0, 1): 'two',
  (0,1): 3,
}
print(a)
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_complex_case_of_duplicate_key_comma(self):
        """We only handle simple cases."""
        code = """\
{
    1: {0,
    },
    1: {2,
    },
}
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_complex_case_of_duplicate_key_partially(
        self,
    ):
        """We only handle simple cases."""
        code = """\
a = {(0,1): 1, (0, 1): 'two',
  (0,1): 3,
  (2,3): 4,
  (2,3): 4,
  (2,3): 5,
}
print(a)
"""

        self.assertEqual(
            """\
a = {(0,1): 1, (0, 1): 'two',
  (0,1): 3,
  (2,3): 5,
}
print(a)
""",
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_more_cases_of_duplicate_key(self):
        """We only handle simple cases."""
        code = """\
a = {
    (0,1):
    1,
    (0, 1): 'two',
  (0,1): 3,
}
print(a)
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_duplicate_key_with_comments(self):
        """We only handle simple cases."""
        code = """\
a = {
    (0,1)  # : f
    :
    1,
    (0, 1): 'two',
  (0,1): 3,
}
print(a)
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

        code = """\
{
    1: {0,
    },
    1: #{2,
    #},
    0
}
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_duplicate_key_with_multiline_key(self):
        """We only handle simple cases."""
        code = """\
a = {
    (0,1
    ): 1,
    (0, 1): 'two',
  (0,1): 3,
}
print(a)
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_should_ignore_duplicate_key_with_no_comma(self):
        """We don't want to delete the line and leave a lone comma."""
        code = """\
a = {
    (0,1) : 1
    ,
    (0, 1): 'two',
  (0,1): 3,
}
print(a)
"""

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    remove_duplicate_keys=True,
                ),
            ),
        )

    def test_fix_code_keeps_pass_statements(self):
        code = """\
    if True:
        pass
    else:
        def foo():
            \"\"\" A docstring. \"\"\"
            pass
        def foo2():
            \"\"\" A docstring. \"\"\"

            pass
        def foo3():
            \"\"\" A docstring. \"\"\"


            pass
        def bar():
            # abc
            pass
        def blah():
            123
            pass
            pass  # Nope.
            pass
    """

        self.assertEqual(
            code,
            "".join(
                autoflake.fix_code(
                    code,
                    ignore_pass_statements=True,
                ),
            ),
        )

    def test_fix_code_keeps_passes_after_docstrings(self):
        actual = autoflake.fix_code(
            """\
    if True:
        pass
    else:
        def foo():
            \"\"\" A docstring. \"\"\"
            pass
        def foo2():
            \"\"\" A docstring. \"\"\"

            pass
        def foo3():
            \"\"\" A docstring. \"\"\"


            pass
        def bar():
            # abc
            pass
        def blah():
            123
            pass
            pass  # Nope.
            pass
    """,
            ignore_pass_after_docstring=True,
        )

        expected = """\
    if True:
        pass
    else:
        def foo():
            \"\"\" A docstring. \"\"\"
            pass
        def foo2():
            \"\"\" A docstring. \"\"\"

            pass
        def foo3():
            \"\"\" A docstring. \"\"\"


            pass
        def bar():
            # abc
            pass
        def blah():
            123
            pass  # Nope.
    """

        self.assertEqual(actual, expected)

    def test_useless_pass_line_numbers(self):
        self.assertEqual(
            [1],
            list(
                autoflake.useless_pass_line_numbers(
                    "pass\n",
                ),
            ),
        )

        self.assertEqual(
            [],
            list(
                autoflake.useless_pass_line_numbers(
                    "if True:\n    pass\n",
                ),
            ),
        )

    def test_useless_pass_line_numbers_with_escaped_newline(self):
        self.assertEqual(
            [],
            list(
                autoflake.useless_pass_line_numbers(
                    "if True:\\\n    pass\n",
                ),
            ),
        )

    def test_useless_pass_line_numbers_with_more_complex(self):
        self.assertEqual(
            [6],
            list(
                autoflake.useless_pass_line_numbers(
                    """\
if True:
    pass
else:
    True
    x = 1
    pass
""",
                ),
            ),
        )

    def test_useless_pass_line_numbers_after_docstring(self):
        actual_pass_line_numbers = list(
            autoflake.useless_pass_line_numbers(
                """\
    @abc.abstractmethod
    def some_abstract_method():
        \"\"\"Some docstring.\"\"\"
        pass
    """,
            ),
        )

        expected_pass_line_numbers = [4]
        self.assertEqual(expected_pass_line_numbers, actual_pass_line_numbers)

    def test_useless_pass_line_numbers_keep_pass_after_docstring(self):
        actual_pass_line_numbers = list(
            autoflake.useless_pass_line_numbers(
                """\
    @abc.abstractmethod
    def some_abstract_method():
        \"\"\"Some docstring.\"\"\"
        pass
    """,
                ignore_pass_after_docstring=True,
            ),
        )

        expected_pass_line_numbers = []
        self.assertEqual(expected_pass_line_numbers, actual_pass_line_numbers)

    def test_filter_useless_pass(self):
        self.assertEqual(
            """\
if True:
    pass
else:
    True
    x = 1
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
if True:
    pass
else:
    True
    x = 1
    pass
""",
                ),
            ),
        )

    def test_filter_useless_pass_with_syntax_error(self):
        source = """\
if True:
if True:
            if True:
    if True:

if True:
    pass
else:
    True
    pass
    pass
    x = 1
"""

        self.assertEqual(
            source,
            "".join(autoflake.filter_useless_pass(source)),
        )

    def test_filter_useless_pass_more_complex(self):
        self.assertEqual(
            """\
if True:
    pass
else:
    def foo():
        pass
        # abc
    def bar():
        # abc
        pass
    def blah():
        123
        pass  # Nope.
    True
    x = 1
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
if True:
    pass
else:
    def foo():
        pass
        # abc
    def bar():
        # abc
        pass
    def blah():
        123
        pass
        pass  # Nope.
        pass
    True
    x = 1
    pass
""",
                ),
            ),
        )

    def test_filter_useless_pass_keep_pass_after_docstring(self):
        source = """\
    def foo():
        \"\"\" This is not a useless 'pass'. \"\"\"
        pass

    @abc.abstractmethod
    def bar():
        \"\"\"
            Also this is not a useless 'pass'.
        \"\"\"
        pass
    """
        self.assertEqual(
            source,
            "".join(
                autoflake.filter_useless_pass(
                    source,
                    ignore_pass_after_docstring=True,
                ),
            ),
        )

    def test_filter_useless_pass_keeps_pass_statements(self):
        source = """\
    if True:
        pass
        pass
        pass
        pass
    else:
        pass
        True
        x = 1
        pass
    """

        self.assertEqual(
            source,
            "".join(
                autoflake.filter_useless_pass(
                    source,
                    ignore_pass_statements=True,
                ),
            ),
        )

    def test_filter_useless_paspasss_with_try(self):
        self.assertEqual(
            """\
import os
os.foo()
try:
    pass
except ImportError:
    pass
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
import os
os.foo()
try:
    pass
    pass
except ImportError:
    pass
""",
                ),
            ),
        )

    def test_filter_useless_pass_leading_pass(self):
        self.assertEqual(
            """\
if True:
    pass
else:
    True
    x = 1
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
if True:
    pass
    pass
    pass
    pass
else:
    pass
    True
    x = 1
    pass
""",
                ),
            ),
        )

    def test_filter_useless_pass_leading_pass_with_number(self):
        self.assertEqual(
            """\
def func11():
    0, 11 / 2
    return 1
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
def func11():
    pass
    0, 11 / 2
    return 1
""",
                ),
            ),
        )

    def test_filter_useless_pass_leading_pass_with_string(self):
        self.assertEqual(
            """\
def func11():
    'hello'
    return 1
""",
            "".join(
                autoflake.filter_useless_pass(
                    """\
def func11():
    pass
    'hello'
    return 1
""",
                ),
            ),
        )

    def test_check(self):
        self.assertTrue(autoflake.check("import os"))

    def test_check_with_bad_syntax(self):
        self.assertFalse(autoflake.check("foo("))

    def test_check_with_unicode(self):
        self.assertFalse(autoflake.check('print("∑")'))

        self.assertTrue(autoflake.check("import os  # ∑"))

    def test_get_diff_text(self):
        # We ignore the first two lines since it differs on Python 2.6.
        self.assertEqual(
            """\
-foo
+bar
""",
            "\n".join(
                autoflake.get_diff_text(["foo\n"], ["bar\n"], "").split(
                    "\n",
                )[3:],
            ),
        )

    def test_get_diff_text_without_newline(self):
        # We ignore the first two lines since it differs on Python 2.6.
        self.assertEqual(
            """\
-foo
\\ No newline at end of file
+foo
""",
            "\n".join(
                autoflake.get_diff_text(["foo"], ["foo\n"], "").split(
                    "\n",
                )[3:],
            ),
        )

    def test_is_literal_or_name(self):
        self.assertTrue(autoflake.is_literal_or_name("123"))
        self.assertTrue(autoflake.is_literal_or_name("[1, 2, 3]"))
        self.assertTrue(autoflake.is_literal_or_name("xyz"))

        self.assertFalse(autoflake.is_literal_or_name("xyz.prop"))
        self.assertFalse(autoflake.is_literal_or_name(" "))

    def test_is_python_file(self):
        self.assertTrue(
            autoflake.is_python_file(
                os.path.join(ROOT_DIRECTORY, "autoflake.py"),
            ),
        )

        with temporary_file("#!/usr/bin/env python", suffix="") as filename:
            self.assertTrue(autoflake.is_python_file(filename))

        with temporary_file("#!/usr/bin/python", suffix="") as filename:
            self.assertTrue(autoflake.is_python_file(filename))

        with temporary_file("#!/usr/bin/python3", suffix="") as filename:
            self.assertTrue(autoflake.is_python_file(filename))

        with temporary_file("#!/usr/bin/pythonic", suffix="") as filename:
            self.assertFalse(autoflake.is_python_file(filename))

        with temporary_file("###!/usr/bin/python", suffix="") as filename:
            self.assertFalse(autoflake.is_python_file(filename))

        self.assertFalse(autoflake.is_python_file(os.devnull))
        self.assertFalse(autoflake.is_python_file("/bin/bash"))

    def test_is_exclude_file(self):
        self.assertTrue(
            autoflake.is_exclude_file(
                "1.py",
                ["test*", "1*"],
            ),
        )

        self.assertFalse(
            autoflake.is_exclude_file(
                "2.py",
                ["test*", "1*"],
            ),
        )

        # folder glob
        self.assertTrue(
            autoflake.is_exclude_file(
                "test/test.py",
                ["test/**.py"],
            ),
        )

        self.assertTrue(
            autoflake.is_exclude_file(
                "test/auto_test.py",
                ["test/*_test.py"],
            ),
        )

        self.assertFalse(
            autoflake.is_exclude_file(
                "test/auto_auto.py",
                ["test/*_test.py"],
            ),
        )

    def test_match_file(self):
        with temporary_file("", suffix=".py", prefix=".") as filename:
            self.assertFalse(
                autoflake.match_file(filename, exclude=[]),
                msg=filename,
            )

        self.assertFalse(autoflake.match_file(os.devnull, exclude=[]))

        with temporary_file("", suffix=".py", prefix="") as filename:
            self.assertTrue(
                autoflake.match_file(filename, exclude=[]),
                msg=filename,
            )

    def test_find_files(self):
        temp_directory = tempfile.mkdtemp()
        try:
            target = os.path.join(temp_directory, "dir")
            os.mkdir(target)
            with open(os.path.join(target, "a.py"), "w"):
                pass

            exclude = os.path.join(target, "ex")
            os.mkdir(exclude)
            with open(os.path.join(exclude, "b.py"), "w"):
                pass

            sub = os.path.join(exclude, "sub")
            os.mkdir(sub)
            with open(os.path.join(sub, "c.py"), "w"):
                pass

            # FIXME: Avoid changing directory. This may interfere with parallel
            # test runs.
            cwd = os.getcwd()
            os.chdir(temp_directory)
            try:
                files = list(
                    autoflake.find_files(
                        ["dir"],
                        True,
                        [os.path.join("dir", "ex")],
                    ),
                )
            finally:
                os.chdir(cwd)

            file_names = [os.path.basename(f) for f in files]
            self.assertIn("a.py", file_names)
            self.assertNotIn("b.py", file_names)
            self.assertNotIn("c.py", file_names)
        finally:
            shutil.rmtree(temp_directory)

    def test_exclude(self):
        temp_directory = tempfile.mkdtemp(dir=".")
        try:
            with open(os.path.join(temp_directory, "a.py"), "w") as output:
                output.write("import re\n")

            os.mkdir(os.path.join(temp_directory, "d"))
            with open(
                os.path.join(temp_directory, "d", "b.py"),
                "w",
            ) as output:
                output.write("import os\n")

            p = subprocess.Popen(
                list(AUTOFLAKE_COMMAND)
                + [temp_directory, "--recursive", "--exclude=a*"],
                stdout=subprocess.PIPE,
            )
            result = p.communicate()[0].decode("utf-8")

            self.assertNotIn("import re", result)
            self.assertIn("import os", result)
        finally:
            shutil.rmtree(temp_directory)


class SystemTests(unittest.TestCase):

    """System tests."""

    def test_diff(self):
        with temporary_file(
            """\
import re
import os
import my_own_module
x = 1
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                """\
-import re
-import os
 import my_own_module
 x = 1
""",
                "\n".join(output_file.getvalue().split("\n")[3:]),
            )

    def test_diff_with_nonexistent_file(self):
        output_file = io.StringIO()
        autoflake._main(
            argv=["my_fake_program", "nonexistent_file"],
            standard_out=output_file,
            standard_error=output_file,
        )
        self.assertIn("no such file", output_file.getvalue().lower())

    def test_diff_with_encoding_declaration(self):
        with temporary_file(
            """\
# coding: iso-8859-1
import re
import os
import my_own_module
x = 1
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                """\
 # coding: iso-8859-1
-import re
-import os
 import my_own_module
 x = 1
""",
                "\n".join(output_file.getvalue().split("\n")[3:]),
            )

    def test_in_place(self):
        with temporary_file(
            """\
import foo
x = foo
import subprocess
x()

try:
    import os
except ImportError:
    import os
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--in-place", filename],
                standard_out=output_file,
                standard_error=None,
            )
            with open(filename) as f:
                self.assertEqual(
                    """\
import foo
x = foo
x()

try:
    pass
except ImportError:
    pass
""",
                    f.read(),
                )

    def test_check_with_empty_file(self):
        line = ""

        with temporary_file(line) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--check", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                f"{filename}: No issues detected!{os.linesep}",
                output_file.getvalue(),
            )

    def test_check_correct_file(self):
        with temporary_file(
            """\
import foo
x = foo.bar
print(x)
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--check", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                f"{filename}: No issues detected!{os.linesep}",
                output_file.getvalue(),
            )

    def test_check_correct_file_with_quiet(self):
        with temporary_file(
            """\
import foo
x = foo.bar
print(x)
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=[
                    "my_fake_program",
                    "--check",
                    "--quiet",
                    filename,
                ],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual("", output_file.getvalue())

    def test_check_useless_pass(self):
        with temporary_file(
            """\
import foo
x = foo
import subprocess
x()

try:
    pass
    import os
except ImportError:
    pass
    import os
    import sys
""",
        ) as filename:
            output_file = io.StringIO()
            exit_status = autoflake._main(
                argv=["my_fake_program", "--check", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(exit_status, 1)
            self.assertEqual(
                f"{filename}: Unused imports/variables detected{os.linesep}",
                output_file.getvalue(),
            )

    def test_check_with_multiple_files(self):
        with temporary_file("import sys") as file1:
            with temporary_file("import sys") as file2:
                output_file = io.StringIO()
                exit_status = autoflake._main(
                    argv=["my_fake_program", "--check", file1, file2],
                    standard_out=output_file,
                    standard_error=None,
                )
                self.assertEqual(exit_status, 1)
                self.assertEqual(
                    {
                        f"{file1}: Unused imports/variables detected",
                        f"{file2}: Unused imports/variables detected",
                    },
                    set(output_file.getvalue().strip().split(os.linesep)),
                )

    def test_check_diff_with_empty_file(self):
        line = ""

        with temporary_file(line) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--check-diff", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                f"{filename}: No issues detected!{os.linesep}",
                output_file.getvalue(),
            )

    def test_check_diff_correct_file(self):
        with temporary_file(
            """\
import foo
x = foo.bar
print(x)
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--check-diff", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(
                f"{filename}: No issues detected!{os.linesep}",
                output_file.getvalue(),
            )

    def test_check_diff_correct_file_with_quiet(self):
        with temporary_file(
            """\
import foo
x = foo.bar
print(x)
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=[
                    "my_fake_program",
                    "--check-diff",
                    "--quiet",
                    filename,
                ],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual("", output_file.getvalue())

    def test_check_diff_useless_pass(self):
        with temporary_file(
            """\
import foo
x = foo
import subprocess
x()
try:
    pass
    import os
except ImportError:
    pass
    import os
    import sys
""",
        ) as filename:
            output_file = io.StringIO()
            exit_status = autoflake._main(
                argv=["my_fake_program", "--check-diff", filename],
                standard_out=output_file,
                standard_error=None,
            )
            self.assertEqual(exit_status, 1)
            self.assertEqual(
                """\
 import foo
 x = foo
-import subprocess
 x()
 try:
     pass
-    import os
 except ImportError:
     pass
-    import os
-    import sys
""",
                "\n".join(output_file.getvalue().split("\n")[3:]),
            )

    def test_in_place_with_empty_file(self):
        line = ""

        with temporary_file(line) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--in-place", filename],
                standard_out=output_file,
                standard_error=None,
            )
            with open(filename) as f:
                self.assertEqual(line, f.read())

    def test_in_place_with_with_useless_pass(self):
        with temporary_file(
            """\
import foo
x = foo
import subprocess
x()

try:
    pass
    import os
except ImportError:
    pass
    import os
    import sys
""",
        ) as filename:
            output_file = io.StringIO()
            autoflake._main(
                argv=["my_fake_program", "--in-place", filename],
                standard_out=output_file,
                standard_error=None,
            )
            with open(filename) as f:
                self.assertEqual(
                    """\
import foo
x = foo
x()

try:
    pass
except ImportError:
    pass
""",
                    f.read(),
                )

    def test_with_missing_file(self):
        output_file = io.StringIO()
        ignore = StubFile()
        autoflake._main(
            argv=["my_fake_program", "--in-place", ".fake"],
            standard_out=output_file,
            standard_error=ignore,
        )
        self.assertFalse(output_file.getvalue())

    def test_ignore_hidden_directories(self):
        with temporary_directory() as directory:
            with temporary_directory(
                prefix=".",
                directory=directory,
            ) as inner_directory:

                with temporary_file(
                    """\
import re
import os
""",
                    directory=inner_directory,
                ):

                    output_file = io.StringIO()
                    autoflake._main(
                        argv=[
                            "my_fake_program",
                            "--recursive",
                            directory,
                        ],
                        standard_out=output_file,
                        standard_error=None,
                    )
                    self.assertEqual(
                        "",
                        output_file.getvalue().strip(),
                    )

    def test_in_place_and_stdout(self):
        output_file = io.StringIO()
        self.assertRaises(
            SystemExit,
            autoflake._main,
            argv=["my_fake_program", "--in-place", "--stdout", __file__],
            standard_out=output_file,
            standard_error=output_file,
        )

    def test_end_to_end(self):
        with temporary_file(
            """\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--imports=fake_foo,fake_bar",
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                """\
-import fake_fake, fake_foo, fake_bar, fake_zoo
-import re, os
+import fake_fake
+import fake_zoo
+import os
 x = os.sep
 print(x)
""",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )

    def test_end_to_end_multiple_files(self):
        with temporary_file(
            """\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
        ) as filename1:
            with temporary_file(
                """\
import os
x = os.sep
print(x)
""",
            ) as filename2:
                process = subprocess.Popen(
                    AUTOFLAKE_COMMAND
                    + [
                        "--imports=fake_foo,fake_bar",
                        "--check",
                        "--jobs=2",
                        filename1,
                        filename2,
                    ],
                    stdout=subprocess.PIPE,
                )

                status_code = process.wait()
                self.assertEqual(1, status_code)

    def test_end_to_end_with_remove_all_unused_imports(self):
        with temporary_file(
            """\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--remove-all",
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                """\
-import fake_fake, fake_foo, fake_bar, fake_zoo
-import re, os
+import os
 x = os.sep
 print(x)
""",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )

    def test_end_to_end_with_remove_duplicate_keys_multiple_lines(self):
        with temporary_file(
            """\
a = {
    'b': 456,
    'a': 123,
    'b': 7834,
    'a': 'wow',
    'b': 456,
    'c': 'hello',
    'c': 'hello2',
    'b': 'hiya',
}
print(a)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--remove-duplicate-keys",
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                """\
 a = {
-    'b': 456,
-    'a': 123,
-    'b': 7834,
     'a': 'wow',
-    'b': 456,
-    'c': 'hello',
     'c': 'hello2',
     'b': 'hiya',
 }
""",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )

    def test_end_to_end_with_remove_duplicate_keys_and_other_errors(self):
        with temporary_file(
            """\
from math import *
print(sin(4))
a = { # Hello
    'b': 456,
    'a': 123,
    'b': 7834,
    'a': 'wow',
    'b': 456,
    'c': 'hello',
    'c': 'hello2',
    'b': 'hiya',
}
print(a)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--remove-duplicate-keys",
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                """\
 from math import *
 print(sin(4))
 a = { # Hello
-    'b': 456,
-    'a': 123,
-    'b': 7834,
     'a': 'wow',
-    'b': 456,
-    'c': 'hello',
     'c': 'hello2',
     'b': 'hiya',
 }
""",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )

    def test_end_to_end_with_remove_duplicate_keys_tuple(self):
        with temporary_file(
            """\
a = {
  (0,1): 1,
  (0, 1): 'two',
  (0,1): 3,
}
print(a)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--remove-duplicate-keys",
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                """\
 a = {
-  (0,1): 1,
-  (0, 1): 'two',
   (0,1): 3,
 }
 print(a)
""",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )

    def test_end_to_end_with_error(self):
        with temporary_file(
            """\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    "--imports=fake_foo,fake_bar",
                    "--remove-all",
                    filename,
                ],
                stderr=subprocess.PIPE,
            )
            self.assertIn(
                "not allowed with argument",
                process.communicate()[1].decode(),
            )

    def test_end_to_end_from_stdin(self):
        stdin_data = b"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
"""
        process = subprocess.Popen(
            AUTOFLAKE_COMMAND + ["--remove-all", "-"],
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
        )
        stdout, _ = process.communicate(stdin_data)
        self.assertEqual(
            """\
import os
x = os.sep
print(x)
""",
            "\n".join(stdout.decode().split(os.linesep)),
        )

    def test_end_to_end_from_stdin_with_in_place(self):
        stdin_data = b"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os, sys
x = os.sep
print(x)
"""
        process = subprocess.Popen(
            AUTOFLAKE_COMMAND + ["--remove-all", "--in-place", "-"],
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
        )
        stdout, _ = process.communicate(stdin_data)
        self.assertEqual(
            """\
import os
x = os.sep
print(x)
""",
            "\n".join(stdout.decode().split(os.linesep)),
        )

    def test_end_to_end_dont_remove_unused_imports_when_not_using_flag(self):
        with temporary_file(
            """\
from . import fake_bar
from . import fake_foo
fake_foo.fake_function()
""",
        ) as filename:
            process = subprocess.Popen(
                AUTOFLAKE_COMMAND
                + [
                    filename,
                ],
                stdout=subprocess.PIPE,
            )
            self.assertEqual(
                "",
                "\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
            )


class MultilineFromImportTests(unittest.TestCase):
    def test_is_over(self):
        filt = autoflake.FilterMultilineImport("from . import (\n")
        self.assertTrue(filt.is_over("module)\n"))
        self.assertTrue(filt.is_over("  )\n"))
        self.assertTrue(filt.is_over("  )  # comment\n"))
        self.assertTrue(filt.is_over("from module import (a, b)\n"))
        self.assertFalse(filt.is_over("#  )"))
        self.assertFalse(filt.is_over("module\n"))
        self.assertFalse(filt.is_over("module, \\\n"))
        self.assertFalse(filt.is_over("\n"))

        filt = autoflake.FilterMultilineImport("from . import module, \\\n")
        self.assertTrue(filt.is_over("module\n"))
        self.assertTrue(filt.is_over("\n"))
        self.assertTrue(filt.is_over("m1, m2  # comment with \\\n"))
        self.assertFalse(filt.is_over("m1, m2 \\\n"))
        self.assertFalse(filt.is_over("m1, m2 \\  #\n"))
        self.assertFalse(filt.is_over("m1, m2 \\  # comment with \\\n"))
        self.assertFalse(filt.is_over("\\\n"))

        # "Multiline" imports that are not really multiline
        filt = autoflake.FilterMultilineImport(
            "import os; " "import math, subprocess",
        )
        self.assertTrue(filt.is_over())

    unused = ()

    def assert_fix(self, lines, result, remove_all=True):
        fixer = autoflake.FilterMultilineImport(
            lines[0],
            remove_all_unused_imports=remove_all,
            unused_module=self.unused,
        )
        fixed = functools.reduce(lambda acc, x: acc(x), lines[1:], fixer())
        self.assertEqual(fixed, result)

    def test_fix(self):
        self.unused = ["third_party.lib" + str(x) for x in (1, 3, 4)]

        # Example m0 (isort)
        self.assert_fix(
            [
                "from third_party import (lib1, lib2, lib3,\n",
                "                         lib4, lib5, lib6)\n",
            ],
            "from third_party import (lib2, lib5, lib6)\n",
        )

        # Example m1(isort)
        self.assert_fix(
            [
                "from third_party import (lib1,\n",
                "                         lib2,\n",
                "                         lib3,\n",
                "                         lib4,\n",
                "                         lib5,\n",
                "                         lib6)\n",
            ],
            "from third_party import (lib2,\n"
            "                         lib5,\n"
            "                         lib6)\n",
        )

        # Variation m1(isort)
        self.assert_fix(
            [
                "from third_party import (lib1\n",
                "                        ,lib2\n",
                "                        ,lib3\n",
                "                        ,lib4\n",
                "                        ,lib5\n",
                "                        ,lib6)\n",
            ],
            "from third_party import (lib2\n"
            "                        ,lib5\n"
            "                        ,lib6)\n",
        )

        # Example m2 (isort)
        self.assert_fix(
            [
                "from third_party import \\\n",
                "    lib1, lib2, lib3, \\\n",
                "    lib4, lib5, lib6\n",
            ],
            "from third_party import \\\n" "    lib2, lib5, lib6\n",
        )

        # Example m3 (isort)
        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1,\n",
                "    lib2,\n",
                "    lib3,\n",
                "    lib4,\n",
                "    lib5\n",
                ")\n",
            ],
            "from third_party import (\n" "    lib2,\n" "    lib5\n" ")\n",
        )

        # Example m4 (isort)
        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1, lib2, lib3, lib4,\n",
                "    lib5, lib6)\n",
            ],
            "from third_party import (\n" "    lib2, lib5, lib6)\n",
        )

        # Example m5 (isort)
        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1, lib2, lib3, lib4,\n",
                "    lib5, lib6\n",
                ")\n",
            ],
            "from third_party import (\n" "    lib2, lib5, lib6\n" ")\n",
        )

        # Some Deviations
        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1\\\n",  # only unused + line continuation
                "    ,lib2, \n",
                "    libA\n",  # used import with no commas
                "    ,lib3, \n",  # leading and trailing commas + unused import
                "    libB, \n",
                "    \\\n",  # empty line with continuation
                "    lib4,\n",  # unused import with comment
                ")\n",
            ],
            "from third_party import (\n"
            "    lib2\\\n"
            "    ,libA, \n"
            "    libB,\n"
            ")\n",
        )

        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1\n",
                ",\n",
                "    lib2\n",
                ",\n",
                "    lib3\n",
                ",\n",
                "    lib4\n",
                ",\n",
                "    lib5\n",
                ")\n",
            ],
            "from third_party import (\n" "    lib2\n" ",\n" "    lib5\n" ")\n",
        )

        self.assert_fix(
            [
                "from third_party import (\n",
                "    lib1 \\\n",
                ", \\\n",
                "    lib2 \\\n",
                ",\\\n",
                "    lib3\n",
                ",\n",
                "    lib4\n",
                ",\n",
                "    lib5 \\\n",
                ")\n",
            ],
            "from third_party import (\n"
            "    lib2 \\\n"
            ", \\\n"
            "    lib5 \\\n"
            ")\n",
        )

    def test_indentation(self):
        # Some weird indentation examples
        self.unused = ["third_party.lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "    from third_party import (\n",
                "            lib1, lib2, lib3, lib4,\n",
                "    lib5, lib6\n",
                ")\n",
            ],
            "    from third_party import (\n" "            lib2, lib5, lib6\n" ")\n",
        )
        self.assert_fix(
            [
                "\tfrom third_party import \\\n",
                "\t\tlib1, lib2, lib3, \\\n",
                "\t\tlib4, lib5, lib6\n",
            ],
            "\tfrom third_party import \\\n" "\t\tlib2, lib5, lib6\n",
        )

    def test_fix_relative(self):
        # Example m0 (isort)
        self.unused = [".lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "from . import (lib1, lib2, lib3,\n",
                "               lib4, lib5, lib6)\n",
            ],
            "from . import (lib2, lib5, lib6)\n",
        )

        # Example m1(isort)
        self.unused = ["..lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "from .. import (lib1,\n",
                "                lib2,\n",
                "                lib3,\n",
                "                lib4,\n",
                "                lib5,\n",
                "                lib6)\n",
            ],
            "from .. import (lib2,\n"
            "                lib5,\n"
            "                lib6)\n",
        )

        # Example m2 (isort)
        self.unused = ["...lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "from ... import \\\n",
                "    lib1, lib2, lib3, \\\n",
                "    lib4, lib5, lib6\n",
            ],
            "from ... import \\\n" "    lib2, lib5, lib6\n",
        )

        # Example m3 (isort)
        self.unused = [".parent.lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "from .parent import (\n",
                "    lib1,\n",
                "    lib2,\n",
                "    lib3,\n",
                "    lib4,\n",
                "    lib5\n",
                ")\n",
            ],
            "from .parent import (\n" "    lib2,\n" "    lib5\n" ")\n",
        )

    def test_fix_without_from(self):
        self.unused = ["lib" + str(x) for x in (1, 3, 4)]

        # Multiline but not "from"
        self.assert_fix(
            [
                "import \\\n",
                "    lib1, lib2, lib3 \\\n",
                "    ,lib4, lib5, lib6\n",
            ],
            "import \\\n" "    lib2, lib5, lib6\n",
        )
        self.assert_fix(
            [
                "import lib1, lib2, lib3, \\\n",
                "       lib4, lib5, lib6\n",
            ],
            "import lib2, lib5, lib6\n",
        )

        # Problematic example without "from"
        self.assert_fix(
            [
                "import \\\n",
                "    lib1,\\\n",
                "    lib2, \\\n",
                "    libA\\\n",  # used import with no commas
                "    ,lib3, \\\n",  # leading and trailing commas with unused
                "    libB, \\\n",
                "    \\  \n",  # empty line with continuation
                "    lib4\\\n",  # unused import with comment
                "\n",
            ],
            "import \\\n" "    lib2,\\\n" "    libA, \\\n" "    libB\\\n" "\n",
        )

        self.unused = [f"lib{x}.x.y.z" for x in (1, 3, 4)]
        self.assert_fix(
            [
                "import \\\n",
                "    lib1.x.y.z \\",
                "    , \\\n",
                "    lib2.x.y.z \\\n",
                "    , \\\n",
                "    lib3.x.y.z \\\n",
                "    , \\\n",
                "    lib4.x.y.z \\\n",
                "    , \\\n",
                "    lib5.x.y.z\n",
            ],
            "import \\\n" "    lib2.x.y.z \\" "    , \\\n" "    lib5.x.y.z\n",
        )

    def test_give_up(self):
        # Semicolon
        self.unused = ["lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "import \\\n",
                "    lib1, lib2, lib3, \\\n",
                "    lib4, lib5; import lib6\n",
            ],
            "import \\\n" "    lib1, lib2, lib3, \\\n" "    lib4, lib5; import lib6\n",
        )
        # Comments
        self.unused = [".lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "from . import ( # comment\n",
                "    lib1,\\\n",  # only unused + line continuation
                "    lib2, \n",
                "    libA\n",  # used import with no commas
                "    ,lib3, \n",  # leading and trailing commas + unused import
                "    libB, \n",
                "    \\  \n",  # empty line with continuation
                "    lib4,  # noqa \n",  # unused import with comment
                ") ; import sys\n",
            ],
            "from . import ( # comment\n"
            "    lib1,\\\n"
            "    lib2, \n"
            "    libA\n"
            "    ,lib3, \n"
            "    libB, \n"
            "    \\  \n"
            "    lib4,  # noqa \n"
            ") ; import sys\n",
        )

    def test_just_one_import_used(self):
        self.unused = ["lib2"]
        self.assert_fix(
            [
                "import \\\n",
                "    lib1\n",
            ],
            "import \\\n" "    lib1\n",
        )
        self.assert_fix(
            [
                "import \\\n",
                "    lib2\n",
            ],
            "pass\n",
        )
        # Example from issue #8
        self.unused = ["re.subn"]
        self.assert_fix(
            [
                "\tfrom re import (subn)\n",
            ],
            "\tpass\n",
        )

    def test_just_one_import_left(self):
        # Examples from issue #8
        self.unused = ["math.sqrt"]
        self.assert_fix(
            [
                "from math import (\n",
                "        sqrt,\n",
                "        log\n",
                "    )\n",
            ],
            "from math import (\n" "        log\n" "    )\n",
        )
        self.unused = ["module.b"]
        self.assert_fix(
            [
                "from module import (a, b)\n",
            ],
            "from module import a\n",
        )
        self.assert_fix(
            [
                "from module import (a,\n",
                "                    b)\n",
            ],
            "from module import a\n",
        )
        self.unused = []
        self.assert_fix(
            [
                "from re import (subn)\n",
            ],
            "from re import (subn)\n",
        )

    def test_no_empty_imports(self):
        self.unused = ["lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "import \\\n",
                "    lib1, lib3, \\\n",
                "    lib4 \n",
            ],
            "pass \n",
        )

        # Indented parenthesized block
        self.unused = [".parent.lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "\t\tfrom .parent import (\n",
                "    lib1,\n",
                "    lib3,\n",
                "    lib4,\n",
                ")\n",
            ],
            "\t\tpass\n",
        )

    def test_without_remove_all(self):
        self.unused = ["lib" + str(x) for x in (1, 3, 4)]
        self.assert_fix(
            [
                "import \\\n",
                "    lib1,\\\n",
                "    lib3,\\\n",
                "    lib4\n",
            ],
            "import \\\n" "    lib1,\\\n" "    lib3,\\\n" "    lib4\n",
            remove_all=False,
        )

        self.unused += ["os.path." + x for x in ("dirname", "isdir", "join")]
        self.assert_fix(
            [
                "from os.path import (\n",
                "    dirname,\n",
                "    isdir,\n",
                "    join,\n",
                ")\n",
            ],
            "pass\n",
            remove_all=False,
        )
        self.assert_fix(
            [
                "import \\\n",
                "    os.path.dirname, \\\n",
                "    lib1, \\\n",
                "    lib3\n",
            ],
            "import \\\n" "    lib1, \\\n" "    lib3\n",
            remove_all=False,
        )


class ConfigFileTest(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="autoflake.")

    def tearDown(self):
        if self.tmpdir is not None:
            shutil.rmtree(self.tmpdir)
        self.tmpdir = None

    def effective_path(self, path, is_file=True):
        path = os.path.normpath(path)
        if os.path.isabs(path):
            raise ValueError("Should not create an absolute test path")
        effective_path = os.path.sep.join([self.tmpdir, path])
        if not effective_path.startswith(
            f"{self.tmpdir}{os.path.sep}",
        ) and (effective_path != self.tmpdir or is_file):
            raise ValueError("Should create a path within the tmp dir only")
        return effective_path

    def create_dir(self, path):
        effective_path = self.effective_path(path, False)
        if sys.version_info >= (3, 2, 0):
            os.makedirs(effective_path, exist_ok=True)
        else:
            if os.path.exists(effective_path):
                return
            try:
                os.mkdir(effective_path)
            except OSError:
                parent = os.path.split(path)[0]
                if not parent:
                    raise
                self.create_dir(parent)
                os.mkdir(effective_path)

    def create_file(self, path, contents=""):
        effective_path = self.effective_path(path)
        self.create_dir(os.path.split(path)[0])
        with open(effective_path, "w") as f:
            f.write(contents)

    def with_defaults(self, **kwargs):
        return {
            "check": False,
            "check_diff": False,
            "expand_star_imports": False,
            "ignore_init_module_imports": False,
            "ignore_pass_after_docstring": False,
            "ignore_pass_statements": False,
            "in_place": False,
            "quiet": False,
            "recursive": False,
            "remove_all_unused_imports": False,
            "remove_duplicate_keys": False,
            "remove_rhs_for_unused_variables": False,
            "remove_unused_variables": False,
            "write_to_stdout": False,
            **kwargs,
        }

    def test_no_config_file(self):
        self.create_file("test_me.py")
        original_args = {
            "files": [self.effective_path("test_me.py")],
        }
        args, success = autoflake.merge_configuration_file(original_args)
        assert success is True
        assert args == self.with_defaults(**original_args)

    def test_non_nested_pyproject_toml_empty(self):
        self.create_file("test_me.py")
        self.create_file("pyproject.toml", '[tool.other]\nprop="value"\n')
        files = [self.effective_path("test_me.py")]
        original_args = {"files": files}
        args, success = autoflake.merge_configuration_file(original_args)
        assert success is True
        assert args == self.with_defaults(**original_args)

    def test_non_nested_pyproject_toml_non_empty(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports=true\n",
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=True,
        )

    def test_non_nested_setup_cfg_non_empty(self):
        self.create_file("test_me.py")
        self.create_file(
            "setup.cfg",
            "[other]\nexpand-star-imports = yes\n",
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(files=files)

    def test_non_nested_setup_cfg_empty(self):
        self.create_file("test_me.py")
        self.create_file(
            "setup.cfg",
            "[autoflake]\nexpand-star-imports = yes\n",
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=True,
        )

    def test_nested_file(self):
        self.create_file("nested/file/test_me.py")
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports=true\n",
        )
        files = [self.effective_path("nested/file/test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=True,
        )

    def test_common_path_nested_file_do_not_load(self):
        self.create_file("nested/file/test_me.py")
        self.create_file("nested/other/test_me.py")
        self.create_file(
            "nested/file/pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports=true\n",
        )
        files = [
            self.effective_path("nested/file/test_me.py"),
            self.effective_path("nested/other/test_me.py"),
        ]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(files=files)

    def test_common_path_nested_file_do_load(self):
        self.create_file("nested/file/test_me.py")
        self.create_file("nested/other/test_me.py")
        self.create_file(
            "nested/pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports=true\n",
        )
        files = [
            self.effective_path("nested/file/test_me.py"),
            self.effective_path("nested/other/test_me.py"),
        ]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=True,
        )

    def test_common_path_instead_of_common_prefix(self):
        """Using common prefix would result in a failure."""
        self.create_file("nested/file-foo/test_me.py")
        self.create_file("nested/file-bar/test_me.py")
        self.create_file(
            "nested/file/pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports=true\n",
        )
        files = [
            self.effective_path("nested/file-foo/test_me.py"),
            self.effective_path("nested/file-bar/test_me.py"),
        ]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(files=files)

    def test_continue_search_if_no_config_found(self):
        self.create_file("nested/test_me.py")
        self.create_file(
            "nested/pyproject.toml",
            '[tool.other]\nprop = "value"\n',
        )
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports = true\n",
        )
        files = [self.effective_path("nested/test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=True,
        )

    def test_stop_search_if_config_found(self):
        self.create_file("nested/test_me.py")
        self.create_file(
            "nested/pyproject.toml",
            "[tool.autoflake]\n",
        )
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\nexpand-star-imports = true\n",
        )
        files = [self.effective_path("nested/test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(files=files)

    def test_config_option(self):
        with temporary_file(
            suffix=".ini",
            contents=("[autoflake]\n" "check = True\n"),
        ) as temp_config:
            self.create_file("test_me.py")
            files = [self.effective_path("test_me.py")]

            args, success = autoflake.merge_configuration_file(
                {
                    "files": files,
                    "config_file": temp_config,
                },
            )
            assert success is True
            assert args == self.with_defaults(
                files=files,
                config_file=temp_config,
                check=True,
            )

    def test_load_false(self):
        self.create_file("test_me.py")
        self.create_file(
            "setup.cfg",
            "[autoflake]\nexpand-star-imports = no\n",
        )
        files = [self.effective_path("test_me.py")]

        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            expand_star_imports=False,
        )

    def test_list_value_pyproject_toml(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            '[tool.autoflake]\nimports=["my_lib", "other_lib"]\n',
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            imports="my_lib,other_lib",
        )

    def test_list_value_comma_sep_string_pyproject_toml(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            '[tool.autoflake]\nimports="my_lib,other_lib"\n',
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            imports="my_lib,other_lib",
        )

    def test_list_value_setup_cfg(self):
        self.create_file("test_me.py")
        self.create_file(
            "setup.cfg",
            "[autoflake]\nimports=my_lib,other_lib\n",
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file({"files": files})
        assert success is True
        assert args == self.with_defaults(
            files=files,
            imports="my_lib,other_lib",
        )

    def test_non_bool_value_for_bool_property(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            '[tool.autoflake]\nexpand-star-imports="invalid"\n',
        )
        files = [self.effective_path("test_me.py")]
        _, success = autoflake.merge_configuration_file({"files": files})
        assert success is False

    def test_non_bool_value_for_bool_property_in_setup_cfg(self):
        self.create_file("test_me.py")
        self.create_file(
            "setup.cfg",
            "[autoflake]\nexpand-star-imports=ok\n",
        )
        files = [self.effective_path("test_me.py")]
        _, success = autoflake.merge_configuration_file({"files": files})
        assert success is False

    def test_non_list_value_for_list_property(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\nexclude=true\n",
        )
        files = [self.effective_path("test_me.py")]
        _, success = autoflake.merge_configuration_file({"files": files})
        assert success is False

    def test_merge_with_cli_set_list_property(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            '[tool.autoflake]\nimports=["my_lib"]\n',
        )
        files = [self.effective_path("test_me.py")]
        args, success = autoflake.merge_configuration_file(
            {"files": files, "imports": "other_lib"},
        )
        assert success is True
        assert args == self.with_defaults(
            files=files,
            imports="my_lib,other_lib",
        )

    def test_merge_prioritizes_flags(self):
        self.create_file("test_me.py")
        self.create_file(
            "pyproject.toml",
            "[tool.autoflake]\ncheck = false\n",
        )
        files = [self.effective_path("test_me.py")]
        flag_args = {
            "files": files,
            "imports": "other_lib",
            "check": True,
        }
        args, success = autoflake.merge_configuration_file(flag_args)
        assert success is True
        assert args == self.with_defaults(
            files=files,
            imports="other_lib",
            check=True,
        )


@contextlib.contextmanager
def temporary_file(contents, directory=".", suffix=".py", prefix=""):
    """Write contents to temporary file and yield it."""
    f = tempfile.NamedTemporaryFile(
        suffix=suffix,
        prefix=prefix,
        delete=False,
        dir=directory,
    )
    try:
        f.write(contents.encode())
        f.close()
        yield f.name
    finally:
        os.remove(f.name)


@contextlib.contextmanager
def temporary_directory(directory=".", prefix="tmp."):
    """Create temporary directory and yield its path."""
    temp_directory = tempfile.mkdtemp(prefix=prefix, dir=directory)
    try:
        yield temp_directory
    finally:
        shutil.rmtree(temp_directory)


class StubFile:

    """Fake file that ignores everything."""

    def write(*_):
        """Ignore."""


if __name__ == "__main__":
    unittest.main()
