diff --git a/tests/unit/codegen/sdk/python/function/test_function_move_to_file.py b/tests/unit/codegen/sdk/python/function/test_function_move_to_file.py index 779a3e5e6..0b50c3f26 100644 --- a/tests/unit/codegen/sdk/python/function/test_function_move_to_file.py +++ b/tests/unit/codegen/sdk/python/function/test_function_move_to_file.py @@ -1,15 +1,19 @@ +import pytest + from codegen.sdk.codebase.factory.get_session import get_codebase_session from codegen.sdk.core.function import Function -def test_move_to_file_add_back_edge(tmpdir) -> None: +def test_move_to_file_update_all_imports(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=python - content1 = """ + FILE_1_CONTENT = """ def external_dep(): return 42 """ + # language=python - content2 = """ + FILE_2_CONTENT = """ from file1 import external_dep def foo(): @@ -24,26 +28,24 @@ def bar(): def bar_dep(): return 2 """ + # language=python - content3 = """ + FILE_3_CONTENT = """ from file2 import bar def baz(): return bar() + 1 """ - with get_codebase_session(tmpdir=tmpdir, files={"file1.py": content1, "file2.py": content2, "file3.py": content3}) as codebase: - file1 = codebase.get_file("file1.py") - file2 = codebase.get_file("file2.py") - file3 = codebase.get_file("file3.py") - bar = file2.get_function("bar") - bar.move_to_file(file3, include_dependencies=True, strategy="add_back_edge") + # ========== [ AFTER ] ========== + # language=python + EXPECTED_FILE_1_CONTENT = """ +def external_dep(): + return 42 +""" - assert file1.content == content1 # language=python - assert ( - file2.content - == """ + EXPECTED_FILE_2_CONTENT = """ from file1 import external_dep def foo(): @@ -52,12 +54,9 @@ def foo(): def foo_dep(): return 24 """ - ) # language=python - assert ( - file3.content - == """ + EXPECTED_FILE_3_CONTENT = """ from file1 import external_dep def baz(): return bar() + 1 @@ -68,17 +67,228 @@ def bar_dep(): def bar(): return external_dep() + bar_dep() """ - ) + # =============================== + # TODO: [low] Should maybe remove unused external_dep? + # TODO: [low] Missing newline after import + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") -def test_move_to_file_update_all_imports(tmpdir) -> None: + bar = file2.get_function("bar") + bar.move_to_file(file3, include_dependencies=True, strategy="update_all_imports") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + +def test_move_to_file_update_all_imports_include_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ +def foo(): + return 1 +""" + + # language=python + FILE_2_CONTENT = """ +def abc(): + '''dependency, gets moved''' + return 'abc' + +@my_decorator +def bar(): + '''gets moved''' + return abc() + +def xyz(): + '''should stay''' + return 3 +""" + + # language=python + FILE_3_CONTENT = """ +from file2 import bar + +def baz(): + '''uses bar''' + return bar() +""" + + # ========== [ AFTER ] ========== # language=python - content1 = """ + EXPECTED_FILE_1_CONTENT = """ +def foo(): + return 1 + +def abc(): + '''dependency, gets moved''' + return 'abc' + +@my_decorator +def bar(): + '''gets moved''' + return abc() +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +def xyz(): + '''should stay''' + return 3 +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +from file1 import bar +def baz(): + '''uses bar''' + return bar() +""" + + # =============================== + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=True) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + +def test_move_to_file_update_all_imports_without_include_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ +def foo(): + return 1 +""" + + # language=python + FILE_2_CONTENT = """ +def abc(): + '''dependency, DOES NOT GET MOVED''' + return 'abc' + +@my_decorator +def bar(): + '''gets moved''' + return abc() + +def xyz(): + '''should stay''' + return 3 +""" + + # language=python + FILE_3_CONTENT = """ +from file2 import bar + +def baz(): + '''uses bar''' + return bar() +""" + + # ========== [ AFTER ] ========== + # language=python + EXPECTED_FILE_1_CONTENT = """ +from file2 import abc + +def foo(): + return 1 + +@my_decorator +def bar(): + '''gets moved''' + return abc() +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +def abc(): + '''dependency, DOES NOT GET MOVED''' + return 'abc' + +def xyz(): + '''should stay''' + return 3 +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +from file1 import bar +def baz(): + '''uses bar''' + return bar() +""" + + # =============================== + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=False) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + +def test_move_to_file_add_back_edge(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ def external_dep(): return 42 """ + # language=python - content2 = """ + FILE_2_CONTENT = """ from file1 import external_dep def foo(): @@ -93,26 +303,24 @@ def bar(): def bar_dep(): return 2 """ + # language=python - content3 = """ + FILE_3_CONTENT = """ from file2 import bar def baz(): return bar() + 1 """ - with get_codebase_session(tmpdir=tmpdir, files={"file1.py": content1, "file2.py": content2, "file3.py": content3}) as codebase: - file1 = codebase.get_file("file1.py") - file2 = codebase.get_file("file2.py") - file3 = codebase.get_file("file3.py") - bar = file2.get_function("bar") - bar.move_to_file(file3, include_dependencies=True, strategy="update_all_imports") + # ========== [ AFTER ] ========== + # language=python + EXPECTED_FILE_1_CONTENT = """ +def external_dep(): + return 42 +""" - assert file1.content == content1 # language=python - assert ( - file2.content - == """ + EXPECTED_FILE_2_CONTENT = """ from file1 import external_dep def foo(): @@ -121,11 +329,9 @@ def foo(): def foo_dep(): return 24 """ - ) + # language=python - assert ( - file3.content - == """ + EXPECTED_FILE_3_CONTENT = """ from file1 import external_dep def baz(): return bar() + 1 @@ -136,22 +342,41 @@ def bar_dep(): def bar(): return external_dep() + bar_dep() """ - ) + # =============================== + # TODO: [low] Should maybe remove unused external_dep? + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + + bar = file2.get_function("bar") + bar.move_to_file(file3, include_dependencies=True, strategy="add_back_edge") -def test_move_to_file_backedge_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.py" - BAR_FILENAME = "bar_test_move_to_file.py" - BAZ_FILENAME = "baz_test_move_to_file.py" + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + +def test_move_to_file_add_back_edge_including_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=python - FOO_FILE_CONTENT = """ + FILE_1_CONTENT = """ def foo(): return 1 - """ +""" # language=python - BAR_FILE_CONTENT = """ + FILE_2_CONTENT = """ def abc(): '''dependency, gets moved''' return 'abc' @@ -164,120 +389,89 @@ def bar(): def xyz(): '''should stay''' return 3 - """ +""" # language=python - BAZ_FILE_CONTENT = """ -from bar_test_move_to_file import bar + FILE_3_CONTENT = """ +from file2 import bar def baz(): '''uses bar''' return bar() - """ +""" + + # ========== [ AFTER ] ========== + # language=python + EXPECTED_FILE_1_CONTENT = """ +def foo(): + return 1 + +def abc(): + '''dependency, gets moved''' + return 'abc' + +@my_decorator +def bar(): + '''gets moved''' + return abc() +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +from file1 import bar + +def xyz(): + '''should stay''' + return 3 +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +from file2 import bar + +def baz(): + '''uses bar''' + return bar() +""".strip() + + # =============================== - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.py - # -------------------------------------- - # - # def foo(): - # return 1 - # - # def abc(): - # '''dependency, gets moved''' - # return 'abc' - # - # @my_decorator - # def bar(): - # '''gets moved''' - # return abc() - # - - # -------------------------------------- - # bar_test_move_to_file.py - # -------------------------------------- - # - # - # def xyz(): - # '''should stay''' - # return 3 - # - - # -------------------------------------- - # baz_test_move_to_file.py - # -------------------------------------- - # - # from bar_test_move_to_file import bar - # - # def baz(): - # '''uses bar''' - # return bar() - # with get_codebase_session( tmpdir=tmpdir, files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, - BAZ_FILENAME: BAZ_FILE_CONTENT, + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, }, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="add_back_edge", include_dependencies=True) - - # Check foo_test_move_to_file - assert "def foo():" in foo_file.content - assert "def abc():" in foo_file.content - assert "@my_decorator" in foo_file.content - assert "def bar():" in foo_file.content - assert "return abc()" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("abc").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - - # Check bar_test_move_to_file - assert "def abc():" not in bar_file.content - assert "@my_decorator" not in bar_file.content - assert "def bar():" not in bar_file.content - assert "return abc()" not in bar_file.content - assert "def xyz():" in bar_file.content - assert codebase.get_symbol("xyz").file == bar_file - assert "from foo_test_move_to_file import bar" in bar_file.content - assert "from foo_test_move_to_file import abc" not in bar_file.content - - # check baz_test_move_to_file - assert "from bar_test_move_to_file import bar" in baz_file.content - assert "from foo_test_move_to_file import bar" not in baz_file.content - assert "def baz():" in baz_file.content - assert "return bar()" in baz_file.content - assert codebase.get_symbol("baz").file == baz_file + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="add_back_edge", include_dependencies=True) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() # Check new symbol - new_symbol = foo_file.get_symbol("bar") - assert new_symbol.file == foo_file + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 assert new_symbol.name == "bar" assert isinstance(new_symbol, Function) -def test_move_to_file_update_imports_without_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.py" - BAR_FILENAME = "bar_test_move_to_file.py" - BAZ_FILENAME = "baz_test_move_to_file.py" - +def test_move_to_file_add_back_edge_without_including_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=python - FOO_FILE_CONTENT = """ + FILE_1_CONTENT = """ def foo(): return 1 - """ +""" # language=python - BAR_FILE_CONTENT = """ + FILE_2_CONTENT = """ def abc(): '''dependency, DOES NOT GET MOVED''' return 'abc' @@ -290,38 +484,21 @@ def bar(): def xyz(): '''should stay''' return 3 - """ +""" # language=python - BAZ_FILE_CONTENT = """ -from bar_test_move_to_file import bar + FILE_3_CONTENT = """ +from file2 import bar def baz(): '''uses bar''' return bar() - """ - - with get_codebase_session( - tmpdir=tmpdir, - files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, - BAZ_FILENAME: BAZ_FILE_CONTENT, - }, - ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=False) +""" - # Check foo_test_move_to_file + # ========== [ AFTER ] ========== # language=python - assert ( - foo_file.content.strip() - == """ -from bar_test_move_to_file import abc + EXPECTED_FILE_1_CONTENT = """ +from file2 import abc def foo(): return 1 @@ -330,12 +507,12 @@ def foo(): def bar(): '''gets moved''' return abc() -""".strip() - ) +""" + # language=python - assert ( - bar_file.content - == """ + EXPECTED_FILE_2_CONTENT = """ +from file1 import bar + def abc(): '''dependency, DOES NOT GET MOVED''' return 'abc' @@ -343,449 +520,366 @@ def abc(): def xyz(): '''should stay''' return 3 - """ - ) +""" + # language=python - assert ( - baz_file.content - == """ -from foo_test_move_to_file import bar + EXPECTED_FILE_3_CONTENT = """ +from file2 import bar + def baz(): '''uses bar''' return bar() - """ - ) +""" + + # =============================== + + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="add_back_edge", include_dependencies=False) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) def test_move_global_var(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.py" - BAR_FILENAME = "bar_test_move_to_file.py" + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ +""" # language=python - FOO_FILE_CONTENT = """ - """ + FILE_2_CONTENT = """ +from import1 import thing1 +from import2 import thing2, thing3 + +GLOBAL = thing1(thing2, arg=thing3) +""" + # ========== [ AFTER ] ========== # language=python - BAR_FILE_CONTENT = """ - from import1 import thing1 - from import2 import thing2, thing3 + EXPECTED_FILE_1_CONTENT = """ +from import1 import thing1 +from import2 import thing2, thing3 - GLOBAL = thing1(thing2, arg=thing3) - """ - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.py - # -------------------------------------- - # - # from import2 import thing2, thing3 - # from import1 import thing1 - # - # GLOBAL = thing1(thing2, arg=thing3) - # - - # -------------------------------------- - # bar_test_move_to_file.py - # -------------------------------------- - # - # + +GLOBAL = thing1(thing2, arg=thing3) +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +from import1 import thing1 +from import2 import thing2, thing3 +""" + + # =============================== + # TODO: [medium] Space messed up in file1 + # TODO: [low] Dangling / unused import in file2 with get_codebase_session( tmpdir=tmpdir, files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, }, - commit=True, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - - global_symbol = bar_file.get_symbol("GLOBAL") - global_symbol.move_to_file(foo_file, strategy="add_back_edge", include_dependencies=True) + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") - # Check foo_test_move_to_file - assert "from import2 import thing2, thing3" in foo_file.content - assert "from import1 import thing1" in foo_file.content - assert "GLOBAL = thing1(thing2, arg=thing3)" in foo_file.content - assert codebase.get_symbol("GLOBAL").file == foo_file + global_symbol = file2.get_symbol("GLOBAL") + global_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=True) - # Check bar_test_move_to_file - assert "from foo_test_move_to_file import GLOBAL" not in bar_file.content - # We don't automatically remove unusued imports so lets leaf - assert "from import1 import thing1" in bar_file.content - assert "from import2 import thing2, thing3" in bar_file.content - assert "GLOBAL = thing1(thing2, arg=thing3)" not in bar_file.content + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() def test_move_to_file_with_imports(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.py" - BAR_FILENAME = "bar_test_move_to_file.py" - + # ========== [ BEFORE ] ========== # language=python - FOO_FILE_CONTENT = """ - def foo(): - return 1 - """ + FILE_1_CONTENT = """ +def foo(): + return 1 +""" # language=python - BAR_FILE_CONTENT = """ - from import1 import thing1 - from import2 import thing2 - - GLOBAL = thing1() + FILE_2_CONTENT = """ +from import1 import thing1 +from import2 import thing2 - def bar(): - return GLOBAL - - def baz(): - return thing1() + thing2() - """ +GLOBAL = thing1() - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.py - # -------------------------------------- - # - # from import1 import thing1 - # - # def foo(): - # return 1 - # - # GLOBAL = thing1() - # - # def bar(): - # return GLOBAL - # - - # -------------------------------------- - # bar_test_move_to_file.py - # -------------------------------------- - # - # from import1 import thing1 - # from import2 import thing2 - # - # def baz(): - # return thing1() + thing2() - # +def bar(): + return GLOBAL - with get_codebase_session( - tmpdir=tmpdir, - files={FOO_FILENAME: FOO_FILE_CONTENT, BAR_FILENAME: BAR_FILE_CONTENT}, - ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="add_back_edge", include_dependencies=True) - - # Check foo_test_move_to_file - assert "from import1 import thing1" in foo_file.content - assert "def foo():" in foo_file.content - assert "GLOBAL = thing1()" in foo_file.content - assert "def bar():" in foo_file.content - assert "return GLOBAL" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("GLOBAL").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - - # Check bar_test_move_to_file - assert "from foo_test_move_to_file import bar" not in bar_file.content - assert "from foo_test_move_to_file import GLOBAL" not in bar_file.content - assert "from import1 import thing1" in bar_file.content - assert "from import2 import thing2" in bar_file.content - assert "def baz():" in bar_file.content - assert "return thing1() + thing2()" in bar_file.content - assert codebase.get_symbol("baz").file == bar_file - assert codebase.get_symbol("bar").file != bar_file - assert codebase.get_symbol("GLOBAL").file != bar_file - assert "def bar():" not in bar_file.content - assert "return GLOBAL" not in bar_file.content - assert "GLOBAL = thing1()" not in bar_file.content - - -def test_move_to_file_update_imports_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.py" - BAR_FILENAME = "bar_test_move_to_file.py" - BAZ_FILENAME = "baz_test_move_to_file.py" - - # language=python - FOO_FILE_CONTENT = """ - def foo(): - return 1 - """ +def baz(): + return thing1() + thing2() +""" + # ========== [ AFTER ] ========== # language=python - BAR_FILE_CONTENT = """ - def abc(): - '''dependency, gets moved''' - return 'abc' + EXPECTED_FILE_1_CONTENT = """ +from import1 import thing1 - @my_decorator - def bar(): - '''gets moved''' - return abc() +def foo(): + return 1 - def xyz(): - '''should stay''' - return 3 - """ +GLOBAL = thing1() + +def bar(): + return GLOBAL +""" # language=python - BAZ_FILE_CONTENT = """ - from bar_test_move_to_file import bar + EXPECTED_FILE_2_CONTENT = """ +from import1 import thing1 +from import2 import thing2 - def baz(): - '''uses bar''' - return bar() - """ +def baz(): + return thing1() + thing2() +""" - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.py - # -------------------------------------- - # - # def foo(): - # return 1 - # - # def abc(): - # '''dependency, gets moved''' - # return 'abc' - # - # @my_decorator - # def bar(): - # '''gets moved''' - # return abc() - # - - # -------------------------------------- - # bar_test_move_to_file.py - # -------------------------------------- - # - # def xyz(): - # '''should stay''' - # return 3 - # - - # -------------------------------------- - # baz_test_move_to_file.py - # -------------------------------------- - # - # from foo_test_move_to_file import bar - # - # def baz(): - # '''uses bar''' - # return bar() - # + # =============================== + # TODO: [low] Global vars should be inserted at the top of the file with get_codebase_session( tmpdir=tmpdir, files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, - BAZ_FILENAME: BAZ_FILE_CONTENT, + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, }, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=True) - - # Check foo_test_move_to_file - assert "def foo():" in foo_file.content - assert "def abc():" in foo_file.content - assert "@my_decorator" in foo_file.content - assert "def bar():" in foo_file.content - assert "return abc()" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("abc").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - - # Check bar_test_move_to_file - assert "def abc():" not in bar_file.content - assert "@my_decorator" not in bar_file.content - assert "def bar():" not in bar_file.content - assert "return abc()" not in bar_file.content - assert "def xyz():" in bar_file.content - assert codebase.get_symbol("xyz").file == bar_file - assert "from foo_test_move_to_file import bar" not in bar_file.content - assert "from foo_test_move_to_file import abc" not in bar_file.content - - # check baz_test_move_to_file - assert "from foo_test_move_to_file import bar" in baz_file.content - assert "from bar_test_move_to_file import bar" not in baz_file.content - assert "def baz():" in baz_file.content - assert "return bar()" in baz_file.content - assert codebase.get_symbol("baz").file == baz_file + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") - # Check new symbol - new_symbol = foo_file.get_symbol("bar") - assert new_symbol.file == foo_file - assert new_symbol.name == "bar" - assert isinstance(new_symbol, Function) + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="add_back_edge", include_dependencies=True) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() def test_move_to_file_module_import(tmpdir) -> None: - FOO_FILENAME = "app/foo.py" - BAR_FILENAME = "app/bar.py" - BAZ_FILENAME = "app/baz.py" + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ +def foo_func(): + return 1 +""" # language=python - FOO_FILE_CONTENT = """ - def foo_func(): - return 1 - """ + FILE_2_CONTENT = """ +@my_decorator +def bar_func(): + print("I'm getting moved") +""" # language=python - BAR_FILE_CONTENT = """ - @my_decorator - def bar_func(): - print("I'm getting moved") - """ + FILE_3_CONTENT = """ +# module import of symbol to move +from app import file2 +def baz(): + # usage of bar_func + return file2.bar_func() +""" + + # ========== [ AFTER ] ========== # language=python - BAZ_FILE_CONTENT = """ - # module import of symbol to move - from app import bar + EXPECTED_FILE_1_CONTENT = """ +def foo_func(): + return 1 - def baz(): - # usage of bar_func - return bar.bar_func() - """ +@my_decorator +def bar_func(): + print("I'm getting moved") +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +# module import of symbol to move +from app.file1 import bar_func +from app import file2 + +def baz(): + # usage of bar_func + return bar_func() +""" + + # =============================== + # TODO: [medium] Module import changed to absolute import. Is this intended? + # TODO: [low] Unused app import in file3 with get_codebase_session( tmpdir=tmpdir, files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, - BAZ_FILENAME: BAZ_FILE_CONTENT, + "app/file1.py": FILE_1_CONTENT, + "app/file2.py": FILE_2_CONTENT, + "app/file3.py": FILE_3_CONTENT, }, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) + file1 = codebase.get_file("app/file1.py") + file2 = codebase.get_file("app/file2.py") + file3 = codebase.get_file("app/file3.py") - bar_func_symbol = bar_file.get_symbol("bar_func") + bar_func_symbol = file2.get_symbol("bar_func") assert bar_func_symbol - bar_func_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=True) + bar_func_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=True) - # Check app/foo.py - assert "def foo_func():" in foo_file.content - assert "def bar_func():" in foo_file.content - assert "@my_decorator" not in bar_file.content - assert codebase.get_symbol("foo_func").file == foo_file - assert codebase.get_symbol("bar_func").file == foo_file - - # Check app/bar.py - assert "@my_decorator" not in bar_file.content - assert "def bar_func():" not in bar_file.content - - # check baz_test_move_to_file - assert "from app.foo import bar_func" in baz_file.content # module import converted to symbol import - assert "bar_func()" in baz_file.content - assert "bar.bar_func()" not in baz_file.content - assert codebase.get_symbol("baz").file == baz_file + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() # Check new symbol - new_symbol = foo_file.get_symbol("bar_func") - assert new_symbol.file == foo_file + new_symbol = file1.get_symbol("bar_func") + assert new_symbol.file == file1 assert new_symbol.name == "bar_func" assert isinstance(new_symbol, Function) +@pytest.mark.skip(reason="Broken!!!") def test_move_to_file_external_module_dependency(tmpdir) -> None: - FOO_FILENAME = "app/foo.py" - BAR_FILENAME = "app/bar.py" - BAZ_FILENAME = "app/baz.py" + # ========== [ BEFORE ] ========== + # language=python + FILE_1_CONTENT = """ +def foo_func(): + return 1 +""" # language=python - FOO_FILE_CONTENT = """ - def foo_func(): - return 1 - """ + FILE_2_CONTENT = """ +from app.file1 import foo_func +from typing import Optional + +@my_decorator +def bar_func(): + foo_func() + print(f"I'm getting moved") +""" # language=python - BAR_FILE_CONTENT = """ - from app.foo import foo_func - from typing import Optional + FILE_3_CONTENT = """ +# module import of symbol to move +from app.file2 import bar_func - @my_decorator - def bar_func(): - foo_func() - print(f"I'm getting moved") - """ +def baz(): + # usage of bar_func + return bar_func() +""" + # ========== [ AFTER ] ========== # language=python - BAZ_FILE_CONTENT = """ - # module import of symbol to move - from app.bar import bar_func + EXPECTED_FILE_1_CONTENT = """ +from app.file1 import foo_func - def baz(): - # usage of bar_func - return bar_func() - """ +def foo_func(): + return 1 + +@my_decorator +def bar_func(): + foo_func() + print(f"I'm getting moved") +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +from app.file1 import foo_func +from typing import Optional +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +# module import of symbol to movefrom app.file1 import bar_func + + +def baz(): + # usage of bar_func + return bar_func() +""" + + # =============================== + # TODO: [!HIGH!] Corrupted output in file3 + # TODO: [low] Unused imports in file2 with get_codebase_session( tmpdir=tmpdir, files={ - FOO_FILENAME: FOO_FILE_CONTENT, - BAR_FILENAME: BAR_FILE_CONTENT, - BAZ_FILENAME: BAZ_FILE_CONTENT, + "app/file1.py": FILE_1_CONTENT, + "app/file2.py": FILE_2_CONTENT, + "app/file3.py": FILE_3_CONTENT, }, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) + file1 = codebase.get_file("app/file1.py") + file2 = codebase.get_file("app/file2.py") + file3 = codebase.get_file("app/file3.py") - bar_func_symbol = bar_file.get_symbol("bar_func") + bar_func_symbol = file2.get_symbol("bar_func") assert bar_func_symbol - bar_func_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=True) - - # Check app/foo.py - assert "def foo_func():" in foo_file.content - assert "def bar_func():" in foo_file.content - assert "@my_decorator" not in bar_file.content - assert codebase.get_symbol("foo_func").file == foo_file - assert codebase.get_symbol("bar_func").file == foo_file + bar_func_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=True) - # Check app/bar.py - assert "@my_decorator" not in bar_file.content - assert "def bar_func():" not in bar_file.content - - # check baz_test_move_to_file - assert "from app.foo import bar_func" in baz_file.content # module import converted to symbol import - assert "bar_func()" in baz_file.content - assert "bar.bar_func()" not in baz_file.content - assert codebase.get_symbol("baz").file == baz_file + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() # Check new symbol - new_symbol = foo_file.get_symbol("bar_func") - assert new_symbol.file == foo_file + new_symbol = file1.get_symbol("bar_func") + assert new_symbol.file == file1 assert new_symbol.name == "bar_func" assert isinstance(new_symbol, Function) def test_function_move_to_file_circular_dependency(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=python - content1 = """ + FILE_1_CONTENT = """ def foo(): return bar() + 1 def bar(): return foo() + 1 """ - with get_codebase_session(tmpdir, files={"file1.py": content1}) as codebase: + + # ========== [ AFTER ] ========== + # language=python + EXPECTED_FILE_1_CONTENT = """ +""" + + # language=python + EXPECTED_FILE_2_CONTENT = """ +def bar(): + return foo() + 1 + +def foo(): + return bar() + 1 +""" + + # =============================== + + with get_codebase_session( + tmpdir, + files={"file1.py": FILE_1_CONTENT}, + ) as codebase: file1 = codebase.get_file("file1.py") foo = file1.get_function("foo") bar = file1.get_function("bar") @@ -795,31 +889,23 @@ def bar(): file2 = codebase.create_file("file2.py", "") foo.move_to_file(file2, include_dependencies=True, strategy="add_back_edge") - # language=python - assert ( - file2.content.strip() - == """ -def bar(): - return foo() + 1 - -def foo(): - return bar() + 1 -""".strip() - ) - assert file1.content.strip() == "" + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() def test_move_to_file_update_all_imports_multi(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=python - content1 = """ + FILE_1_CONTENT = """ def external_dep(): return 42 def external_dep2(): return 42 """ + # language=python - content2 = """ + FILE_2_CONTENT = """ from file1 import external_dep, external_dep2 def foo(): @@ -834,51 +920,22 @@ def bar(): def bar_dep(): return 2 """ - file3_name = "file3.py" + # language=python - content3 = """ + FILE_3_CONTENT = """ """ - file4_name = "file4.py" + # language=python - content4 = """ + FILE_4_CONTENT = """ """ - with get_codebase_session(tmpdir=tmpdir, files={"file1.py": content1, "file2.py": content2, file3_name: content3, file4_name: content4}) as codebase: - file1 = codebase.get_file("file1.py") - file2 = codebase.get_file("file2.py") - file3 = codebase.get_file(file3_name) - file4 = codebase.get_file(file4_name) - d1 = file1.get_function("external_dep") - d2 = file1.get_function("external_dep2") - d1.move_to_file(file3, include_dependencies=True, strategy="update_all_imports") - d2.move_to_file(file4, include_dependencies=True, strategy="update_all_imports") - - # language=python - assert ( - file1.content.strip() - == """ - """.strip() - ) - # language=python - assert ( - file3.content.strip() - == """ -def external_dep(): - return 42 -""".strip() - ) + # ========== [ AFTER ] ========== # language=python - assert ( - file4.content.strip() - == """ -def external_dep2(): - return 42 - """.strip() - ) + EXPECTED_FILE_1_CONTENT = """ +""" + # language=python - assert ( - file2.content.strip() - == """ + EXPECTED_FILE_2_CONTENT = """ from file3 import external_dep from file4 import external_dep2 def foo(): @@ -892,5 +949,42 @@ def bar(): def bar_dep(): return 2 - """.strip() - ) +""" + + # language=python + EXPECTED_FILE_3_CONTENT = """ +def external_dep(): + return 42 +""" + + # language=python + EXPECTED_FILE_4_CONTENT = """ +def external_dep2(): + return 42 +""" + + # =============================== + + with get_codebase_session( + tmpdir=tmpdir, + files={ + "file1.py": FILE_1_CONTENT, + "file2.py": FILE_2_CONTENT, + "file3.py": FILE_3_CONTENT, + "file4.py": FILE_4_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.py") + file2 = codebase.get_file("file2.py") + file3 = codebase.get_file("file3.py") + file4 = codebase.get_file("file4.py") + + d1 = file1.get_function("external_dep") + d2 = file1.get_function("external_dep2") + d1.move_to_file(file3, include_dependencies=True, strategy="update_all_imports") + d2.move_to_file(file4, include_dependencies=True, strategy="update_all_imports") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + assert file4.content.strip() == EXPECTED_FILE_4_CONTENT.strip() diff --git a/tests/unit/codegen/sdk/typescript/function/test_function_move_to_file.py b/tests/unit/codegen/sdk/typescript/function/test_function_move_to_file.py index 138244999..c73cdee5e 100644 --- a/tests/unit/codegen/sdk/typescript/function/test_function_move_to_file.py +++ b/tests/unit/codegen/sdk/typescript/function/test_function_move_to_file.py @@ -1,4 +1,3 @@ -# TODO: SCRUB import platform import pytest @@ -35,34 +34,661 @@ # const module = await import("./module"); +def test_move_to_file_update_all_imports(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +export function externalDep() { + return 42; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +import { externalDep } from 'file1'; + +function foo() { + return fooDep() + 1; +} + +function fooDep() { + return 24; +} + +export function bar() { + return externalDep() + barDep(); +} + +function barDep() { + return 2; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +export function baz() { + return bar() + 1; +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +export function externalDep() { + return 42; +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +import { externalDep } from 'file1'; + +function foo() { + return fooDep() + 1; +} + +function fooDep() { + return 24; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { externalDep } from 'file1'; +import { bar } from 'file3'; +export function baz() { + return bar() + 1; +} + +export function barDep() { + return 2; +} + +export function bar() { + return externalDep() + barDep(); +} +""" + + # =============================== + # TODO: [!HIGH!] Self import of bar in file3 + # TODO: [medium] Why is barDep exported? + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar = file2.get_function("bar") + bar.move_to_file(file3, include_dependencies=True, strategy="update_all_imports") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + +def test_move_to_file_update_all_imports_include_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +function foo(): number { + return 1; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +function foo(): number { + return 1; +} + +export function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { bar } from 'file1'; +function baz(): string { + // uses bar + return bar(); +} +""" + + # =============================== + # TODO: [medium] Why is abc exported? + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=True) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + +def test_move_to_file_update_all_imports_without_include_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +function foo(): number { + return 1; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +import { abc } from 'file2'; + +function foo(): number { + return 1; +} + +export function bar(): string { + // gets moved + return abc(); +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +export function abc(): string { + // dependency, gets moved + return 'abc'; +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { bar } from 'file1'; +function baz(): string { + // uses bar + return bar(); +} +""" + + # =============================== + # TODO: [low] Missing newline after import + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="update_all_imports", include_dependencies=False) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + +def test_move_to_file_add_back_edge(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +export function externalDep() { + return 42; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +import { externalDep } from 'file1'; + +function foo() { + return fooDep() + 1; +} + +function fooDep() { + return 24; +} + +export function bar() { + return externalDep() + barDep(); +} + +function barDep() { + return 2; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +export function baz() { + return bar() + 1; +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +export function externalDep() { + return 42; +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +export { bar } from 'file3' +import { externalDep } from 'file1'; + +function foo() { + return fooDep() + 1; +} + +function fooDep() { + return 24; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { externalDep } from 'file1'; +import { bar } from 'file2'; + +export function baz() { + return bar() + 1; +} + +export function barDep() { + return 2; +} + +export function bar() { + return externalDep() + barDep(); +} +""" + + # =============================== + # TODO: [!HIGH!] Creates circular import for bar between file2 and file3 + # TODO: [medium] Missing semicolon in import on file3 + # TODO: [medium] Why did barDep get changed to export? + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar = file2.get_function("bar") + bar.move_to_file(file3, include_dependencies=True, strategy="add_back_edge") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + +def test_move_to_file_add_back_edge_including_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +function foo(): number { + return 1; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +function foo(): number { + return 1; +} + +export function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +export { bar } from 'file1' + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # =============================== + # TODO: [medium] Missing semicolon in import on file2 + # TODO: [medium] Why is abc exported? + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="add_back_edge", include_dependencies=True) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + +def test_move_to_file_add_back_edge_without_including_dependencies(tmpdir) -> None: + # ========== [ BEFORE ] ========== + # language=typescript + FILE_1_CONTENT = """ +function foo(): number { + return 1; +} +""" + + # language=typescript + FILE_2_CONTENT = """ +function abc(): string { + // dependency, gets moved + return 'abc'; +} + +export function bar(): string { + // gets moved + return abc(); +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +import { abc } from 'file2'; + +function foo(): number { + return 1; +} + +export function bar(): string { + // gets moved + return abc(); +} +""" + + # language=typescript + EXPECTED_FILE_2_CONTENT = """ +export { bar } from 'file1' + +export function abc(): string { + // dependency, gets moved + return 'abc'; +} + +function xyz(): number { + // should stay + return 3; +} +""" + + # language=typescript + EXPECTED_FILE_3_CONTENT = """ +import { bar } from 'file2'; + +function baz(): string { + // uses bar + return bar(); +} +""" + + # =============================== + # TODO: [medium] Missing semicolon in import on file2 + + with get_codebase_session( + tmpdir=tmpdir, + programming_language=ProgrammingLanguage.TYPESCRIPT, + files={ + "file1.ts": FILE_1_CONTENT, + "file2.ts": FILE_2_CONTENT, + "file3.ts": FILE_3_CONTENT, + }, + ) as codebase: + file1 = codebase.get_file("file1.ts") + file2 = codebase.get_file("file2.ts") + file3 = codebase.get_file("file3.ts") + + bar_symbol = file2.get_symbol("bar") + bar_symbol.move_to_file(file1, strategy="add_back_edge", include_dependencies=False) + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() + assert file3.content.strip() == EXPECTED_FILE_3_CONTENT.strip() + + # Check new symbol + new_symbol = file1.get_symbol("bar") + assert new_symbol.file == file1 + assert new_symbol.name == "bar" + assert isinstance(new_symbol, Function) + + def test_move_to_file_import_star(tmpdir) -> None: """Test moving a symbol to a new file, where consumers import it via import * and also import other pieces from the original module which aren't moving """ - source_filename = "source.ts" + # ========== [ BEFORE ] ========== # language=typescript - source_content = """ + SOURCE_FILE_CONTENT = """ export function targetFunction() { return "Hello World"; } """ - dest_filename = "destination.ts" # language=typescript - dest_content = """ + DEST_FILE_CONTENT = """ """ - usage_filename = "usage.ts" # language=typescript - usage_content = """ + USAGE_FILE_CONTENT = """ import * as source from "./source"; const value1 = source.targetFunction(); const value2 = source.otherFunction(); const value3 = source.targetFunction(); """ + # ========== [ AFTER ] ========== # language=typescript - expected_updated_usage_content = """ + EXPECTED_USAGE_FILE_CONTENT = """ import { targetFunction } from 'destination'; import * as source from "./source"; const value1 = targetFunction(); @@ -70,123 +696,127 @@ def test_move_to_file_import_star(tmpdir) -> None: const value3 = targetFunction(); """ + # =============================== + files = { - source_filename: source_content, - dest_filename: dest_content, - usage_filename: usage_content, + "source.ts": SOURCE_FILE_CONTENT, + "destination.ts": DEST_FILE_CONTENT, + "usage.ts": USAGE_FILE_CONTENT, } with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files=files) as codebase: - source_file = codebase.get_file(source_filename) - dest_file = codebase.get_file(dest_filename) - usage_file = codebase.get_file(usage_filename) + source_file = codebase.get_file("source.ts") + dest_file = codebase.get_file("destination.ts") + usage_file = codebase.get_file("usage.ts") target_function = source_file.get_function("targetFunction") target_function.move_to_file(dest_file, include_dependencies=False, strategy="update_all_imports") - assert usage_file.content.strip() == expected_updated_usage_content.strip() + assert usage_file.content.strip() == EXPECTED_USAGE_FILE_CONTENT.strip() def test_move_to_file_named_import(tmpdir) -> None: """Test moving a symbol to a new file, where consumers import it via import { name } and also import other pieces from the original module which aren't moving """ - source_filename = "source.ts" + # ========== [ BEFORE ] ========== # language=typescript - source_content = """ + SOURCE_FILE_CONTENT = """ export function targetFunction() { return "Hello World"; } """ - dest_filename = "destination.ts" # language=typescript - dest_content = """ + DEST_FILE_CONTENT = """ """ - usage_filename = "usage.ts" # language=typescript - usage_content = """ + USAGE_FILE_CONTENT = """ import { targetFunction, otherFunction } from "./source"; const value = targetFunction(); """ + # ========== [ AFTER ] ========== # language=typescript - expected_updated_usage_content = """ + EXPECTED_USAGE_FILE_CONTENT = """ import { targetFunction } from 'destination'; import { otherFunction } from "./source"; const value = targetFunction(); """ + # =============================== + files = { - source_filename: source_content, - dest_filename: dest_content, - usage_filename: usage_content, + "source.ts": SOURCE_FILE_CONTENT, + "destination.ts": DEST_FILE_CONTENT, + "usage.ts": USAGE_FILE_CONTENT, } with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files=files) as codebase: - source_file = codebase.get_file(source_filename) - dest_file = codebase.get_file(dest_filename) - usage_file = codebase.get_file(usage_filename) + source_file = codebase.get_file("source.ts") + dest_file = codebase.get_file("destination.ts") + usage_file = codebase.get_file("usage.ts") target_function = source_file.get_function("targetFunction") target_function.move_to_file(dest_file, include_dependencies=False, strategy="update_all_imports") - assert usage_file.content.strip() == expected_updated_usage_content.strip() + assert usage_file.content.strip() == EXPECTED_USAGE_FILE_CONTENT.strip() def test_move_to_file_only_named_import(tmpdir) -> None: """Test moving a symbol to a new file, where consumers import it via import {name} and don't import anything else removes that whole import line """ - source_filename = "source.ts" + # ========== [ BEFORE ] ========== # language=typescript - source_content = """ + SOURCE_FILE_CONTENT = """ export function targetFunction() { return "Hello World"; } """ - dest_filename = "destination.ts" # language=typescript - dest_content = """ + DEST_FILE_CONTENT = """ """ - usage_filename = "usage.ts" # language=typescript - usage_content = """ + USAGE_FILE_CONTENT = """ import { targetFunction } from "./source"; const value = targetFunction(); """ + # ========== [ AFTER ] ========== # language=typescript - expected_updated_usage_content = """ + EXPECTED_USAGE_FILE_CONTENT = """ import { targetFunction } from 'destination'; const value = targetFunction(); """ + # =============================== + files = { - source_filename: source_content, - dest_filename: dest_content, - usage_filename: usage_content, + "source.ts": SOURCE_FILE_CONTENT, + "destination.ts": DEST_FILE_CONTENT, + "usage.ts": USAGE_FILE_CONTENT, } with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files=files) as codebase: - source_file = codebase.get_file(source_filename) - dest_file = codebase.get_file(dest_filename) - usage_file = codebase.get_file(usage_filename) + source_file = codebase.get_file("source.ts") + dest_file = codebase.get_file("destination.ts") + usage_file = codebase.get_file("usage.ts") target_function = source_file.get_function("targetFunction") target_function.move_to_file(dest_file, include_dependencies=False, strategy="update_all_imports") - assert usage_file.content.strip() == expected_updated_usage_content.strip() + assert usage_file.content.strip() == EXPECTED_USAGE_FILE_CONTENT.strip() def test_move_to_file_include_type_import_dependencies(tmpdir) -> None: """Test moving a symbol to a new file with type dependencies""" - types_filename = "types.ts" + # ========== [ BEFORE ] ========== # language=typescript - types_content = """ + TYPES_FILE_CONTENT = """ export type TypeA = { prop: string; } @@ -204,9 +834,9 @@ def test_move_to_file_include_type_import_dependencies(tmpdir) -> None: } """ - source_filename = "source.ts" + # ========== [ BEFORE ] ========== # language=typescript - source_content = """ + SOURCE_FILE_CONTENT = """ import type { TypeA, TypeB, TypeC } from "types"; import { helper } from "types"; @@ -218,14 +848,13 @@ def test_move_to_file_include_type_import_dependencies(tmpdir) -> None: } """ - dest_filename = "destination.ts" # language=typescript - dest_content = """ + DEST_FILE_CONTENT = """ """ - # TODO: Is the extra new lines here expected behavior? + # ========== [ AFTER ] ========== # language=typescript - expected_updated_dest_content = """ + EXPECTED_DEST_FILE_CONTENT = """ import type { TypeA } from 'types'; import { helper } from 'types'; import type { TypeB } from 'types'; @@ -240,27 +869,30 @@ def test_move_to_file_include_type_import_dependencies(tmpdir) -> None: } """ + # =============================== + # TODO: [medium] Is the extra new lines here expected behavior? + files = { - types_filename: types_content, - source_filename: source_content, - dest_filename: dest_content, + "types.ts": TYPES_FILE_CONTENT, + "source.ts": SOURCE_FILE_CONTENT, + "destination.ts": DEST_FILE_CONTENT, } with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files=files) as codebase: - source_file = codebase.get_file(source_filename) - dest_file = codebase.get_file(dest_filename) + source_file = codebase.get_file("source.ts") + dest_file = codebase.get_file("destination.ts") target_function = source_file.get_function("targetFunction") target_function.move_to_file(dest_file, include_dependencies=False, strategy="update_all_imports") - assert normalize_imports(dest_file.content.strip()) == normalize_imports(expected_updated_dest_content.strip()) + assert normalize_imports(dest_file.content.strip()) == normalize_imports(EXPECTED_DEST_FILE_CONTENT.strip()) def test_move_to_file_imports_local_deps(tmpdir) -> None: """Test moving a symbol that has dependencies on local symbols in the same file""" - source_filename = "source.ts" + # ========== [ BEFORE ] ========== # language=typescript - source_content = """ + SOURCE_FILE_CONTENT = """ export function targetFunction(value: number): number { return helperFunction(value) * 2; } @@ -270,14 +902,13 @@ def test_move_to_file_imports_local_deps(tmpdir) -> None: } """ - dest_filename = "destination.ts" # language=typescript - dest_content = """ + DEST_FILE_CONTENT = """ """ - # TODO: Is the extra new lines here expected behavior? + # ========== [ AFTER ] ========== # language=typescript - expected_updated_dest_content = """ + EXPECTED_DEST_FILE_CONTENT = """ import { helperFunction } from 'source'; @@ -288,445 +919,87 @@ def test_move_to_file_imports_local_deps(tmpdir) -> None: """ # language=typescript - expected_source_content = """ + EXPECTED_SOURCE_FILE_CONTENT = """ export function helperFunction(x: number): number { return x + 1; } """ + # =============================== + # TODO: [medium] Is the extra new lines here expected behavior? + files = { - source_filename: source_content, - dest_filename: dest_content, + "source.ts": SOURCE_FILE_CONTENT, + "destination.ts": DEST_FILE_CONTENT, } with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files=files) as codebase: - source_file = codebase.get_file(source_filename) - dest_file = codebase.get_file(dest_filename) + source_file = codebase.get_file("source.ts") + dest_file = codebase.get_file("destination.ts") target_function = source_file.get_function("targetFunction") target_function.move_to_file(dest_file, include_dependencies=False, strategy="update_all_imports") - assert normalize_imports(dest_file.content.strip()) == normalize_imports(expected_updated_dest_content.strip()) - assert normalize_imports(source_file.content.strip()) == normalize_imports(expected_source_content.strip()) - + assert normalize_imports(dest_file.content.strip()) == normalize_imports(EXPECTED_DEST_FILE_CONTENT.strip()) + assert normalize_imports(source_file.content.strip()) == normalize_imports(EXPECTED_SOURCE_FILE_CONTENT.strip()) -# ED_TODO: Check if this test needs fixing -@pytest.mark.skip(reason="Broken. TODO: @edward will fix") -def test_move_to_file_backedge_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.ts" - BAR_FILENAME = "bar_test_move_to_file.ts" - BAZ_FILENAME = "baz_test_move_to_file.ts" - - # language=typescript - FOO_FILE_CONTENT = """ -function foo(): number { - return 1; -} - """ +def test_function_move_to_file_circular_dependency(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=typescript - BAR_FILE_CONTENT = """ -function abc(): string { - /*dependency, gets moved*/ - return 'abc'; -} - -/** - * Example function to move - * - * @param {number[]} numbers - An array of numerical values. - */ -function bar(): string { - /*gets moved*/ - return abc(); -} - -function xyz(): number { - /*should stay*/ - return 3; + FILE_1_CONTENT = """ +export function foo(): number { + return bar() + 1; } - """ - - # language=typescript - BAZ_FILE_CONTENT = """ -import { bar } from './bar_test_move_to_file'; -function baz(): string { - /*uses bar*/ - return bar(); +export function bar(): number { + return foo() + 1; } """ - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.ts - # -------------------------------------- - # - # function foo(): number { - # return 1; - # } - # - # function abc(): string { - # /*dependency, gets moved*/ - # return 'abc'; - # } - # - # @my_decorator - # function bar(): string { - # /*gets moved*/ - # return abc(); - # } - # - - # -------------------------------------- - # bar_test_move_to_file.ts - # -------------------------------------- - # - # import { bar } from './foo_test_move_to_file'; - # import { abc } from './foo_test_move_to_file'; - # - # function xyz(): number { - # /*should stay*/ - # return 3; - # } - # - - # -------------------------------------- - # baz_test_move_to_file.ts - # -------------------------------------- - # - # import { bar } from './bar_test_move_to_file'; - # - # function baz(): string { - # /*uses bar*/ - # return bar(); - # } - # - - with get_codebase_session( - tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files={FOO_FILENAME: FOO_FILE_CONTENT, BAR_FILENAME: BAR_FILE_CONTENT, BAZ_FILENAME: BAZ_FILE_CONTENT} - ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="add_back_edge", include_dependencies=True) - - new_symbol = foo_file.get_symbol("bar") - - # Check foo_test_move_to_file - # language=typescript - docstring = """/** - * Example function to move - * - * @param {number[]} numbers - An array of numerical values. - */""" - assert "function foo(): number {" in foo_file.content - assert "function abc(): string {" in foo_file.content - assert docstring in foo_file.content - assert "function bar(): string {" in foo_file.content - assert "return abc();" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("abc").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - - # Check bar_test_move_to_file - assert "function abc(): string {" not in bar_file.content - assert docstring not in bar_file.content - assert "function bar(): string {" not in bar_file.content - assert "return abc();" not in bar_file.content - assert "function xyz(): number {" in bar_file.content - assert codebase.get_symbol("xyz").file == bar_file - assert "import { bar } from './foo_test_move_to_file';" in bar_file.content - assert "import { abc } from './foo_test_move_to_file';" in bar_file.content - - # check baz_test_move_to_file - assert "import { bar } from './bar_test_move_to_file';" in baz_file.content - assert "import { bar } from './foo_test_move_to_file';" not in baz_file.content - assert "function baz(): string {" in baz_file.content - assert "return bar();" in baz_file.content - assert codebase.get_symbol("baz").file == baz_file - - # Check new symbol - assert new_symbol.file == foo_file - assert new_symbol.name == "bar" - assert isinstance(new_symbol, Function) - - -# ED_TODO: Check if this test needs fixing -@pytest.mark.skip(reason="Broken. TODO: @edward will fix") -def test_move_to_file_update_imports_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.ts" - BAR_FILENAME = "bar_test_move_to_file.ts" - BAZ_FILENAME = "baz_test_move_to_file.ts" - - # language=typescript - FOO_FILE_CONTENT = """ - function foo(): number { - return 1; - } - """ - + # ========== [ AFTER ] ========== # language=typescript - BAR_FILE_CONTENT = """ - function abc(): string { - /*dependency, gets moved*/ - return 'abc'; - } - - @my_decorator - function bar(): string { - /*gets moved*/ - return abc(); - } - - function xyz(): number { - /*should stay*/ - return 3; - } - """ - + EXPECTED_FILE_1_CONTENT = """ +export { bar } from 'file2' +export { foo } from 'file2' +""" # language=typescript - BAZ_FILE_CONTENT = """ - import { bar } from './bar_test_move_to_file'; + EXPECTED_FILE_2_CONTENT = """ +export function bar(): number { + return foo() + 1; +} - function baz(): string { - /*uses bar*/ - return bar(); - } - """ +export function foo(): number { + return bar() + 1; +} +""" - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.ts - # -------------------------------------- - # - # function foo(): number { - # return 1; - # } - # - # function abc(): string { - # /*dependency, gets moved*/ - # return 'abc'; - # } - # - # @my_decorator - # function bar(): string { - # /*gets moved*/ - # return abc(); - # } - # - - # -------------------------------------- - # bar_test_move_to_file.ts - # -------------------------------------- - # - # function xyz(): number { - # /*should stay*/ - # return 3; - # } - # - - # -------------------------------------- - # baz_test_move_to_file.ts - # -------------------------------------- - # - # import { bar } from './foo_test_move_to_file'; - # - # function baz(): string { - # /*uses bar*/ - # return bar(); - # } - # + # =============================== + # TODO: [low] Missing semicolons with get_codebase_session( - tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files={FOO_FILENAME: FOO_FILE_CONTENT, BAR_FILENAME: BAR_FILE_CONTENT, BAZ_FILENAME: BAZ_FILE_CONTENT} + tmpdir=tmpdir, + files={"file1.ts": FILE_1_CONTENT}, + programming_language=ProgrammingLanguage.TYPESCRIPT, ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=True) - - new_symbol = foo_file.get_symbol("bar") - - # Check foo_test_move_to_file - assert "function foo(): number {" in foo_file.content - assert "function abc(): string {" in foo_file.content - assert "@my_decorator" in foo_file.content - assert "function bar(): string {" in foo_file.content - assert "return abc();" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("abc").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - - # Check bar_test_move_to_file - assert "function abc(): string {" not in bar_file.content - assert "@my_decorator" not in bar_file.content - assert "function bar(): string {" not in bar_file.content - assert "return abc();" not in bar_file.content - assert "function xyz(): number {" in bar_file.content - assert codebase.get_symbol("xyz").file == bar_file - assert "import { bar } from './foo_test_move_to_file';" not in bar_file.content - assert "import { abc } from './foo_test_move_to_file';" not in bar_file.content - - # check baz_test_move_to_file - assert "import { bar } from './foo_test_move_to_file';" in baz_file.content - assert "function baz(): string {" in baz_file.content - assert "return bar();" in baz_file.content - assert codebase.get_symbol("baz").file == baz_file - - # Check new symbol - assert new_symbol.file == foo_file - assert new_symbol.name == "bar" - assert isinstance(new_symbol, Function) - - -# ED_TODO: Check if this test needs fixing -@pytest.mark.skip(reason="Not supported yet") -def test_move_to_file_update_imports_without_include_deps(tmpdir) -> None: - FOO_FILENAME = "foo_test_move_to_file.ts" - BAR_FILENAME = "bar_test_move_to_file.ts" - BAZ_FILENAME = "baz_test_move_to_file.ts" - - # language=typescript - FOO_FILE_CONTENT = """ - function foo(): number { - return 1; - } - """ - - # language=typescript - BAR_FILE_CONTENT = """ - function abc(): string { - /*dependency, DOES NOT GET MOVED*/ - return 'abc'; - } - - @my_decorator - function bar(): string { - /*gets moved*/ - return abc(); - } - - function xyz(): number { - /*should stay*/ - return 3; - } - """ - - # language=typescript - BAZ_FILE_CONTENT = """ - import { bar } from './bar_test_move_to_file'; - - function baz(): string { - /*uses bar*/ - return bar(); - } - """ + file1 = codebase.get_file("file1.ts") + foo = file1.get_function("foo") + bar = file1.get_function("bar") + assert bar in foo.dependencies + assert foo in bar.dependencies - ######################################## - # Intended Files After Move - ######################################## - - # -------------------------------------- - # foo_test_move_to_file.ts - # -------------------------------------- - # - # import { abc } from './bar_test_move_to_file'; - # - # function foo(): number { - # return 1; - # } - # - # @my_decorator - # function bar(): string { - # /*gets moved*/ - # return abc(); - # } - # - - # -------------------------------------- - # bar_test_move_to_file.ts - # -------------------------------------- - # - # function abc(): string { - # /*dependency, gets moved*/ - # return 'abc'; - # } - # - # function xyz(): number { - # /*should stay*/ - # return 3; - # } - # - - # -------------------------------------- - # baz_test_move_to_file.ts - # -------------------------------------- - # - # import { bar } from './foo_test_move_to_file'; - # - # function baz(): string { - # /*uses bar*/ - # return bar(); - # } - # + file2 = codebase.create_file("file2.ts", "") + foo.move_to_file(file2, include_dependencies=True, strategy="add_back_edge") - with get_codebase_session( - tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files={FOO_FILENAME: FOO_FILE_CONTENT, BAR_FILENAME: BAR_FILE_CONTENT, BAZ_FILENAME: BAZ_FILE_CONTENT} - ) as codebase: - foo_file = codebase.get_file(FOO_FILENAME) - bar_file = codebase.get_file(BAR_FILENAME) - baz_file = codebase.get_file(BAZ_FILENAME) - - bar_symbol = bar_file.get_symbol("bar") - bar_symbol.move_to_file(foo_file, strategy="update_all_imports", include_dependencies=False) - - # Check foo_test_move_to_file - assert "function foo(): number {" in foo_file.content - assert "function abc(): string {" not in foo_file.content - assert "@my_decorator" in foo_file.content - assert "function bar(): string {" in foo_file.content - assert "return abc();" in foo_file.content - assert codebase.get_symbol("foo").file == foo_file - assert codebase.get_symbol("bar").file == foo_file - assert "import { abc } from './bar_test_move_to_file';" in foo_file.content - - # Check bar_test_move_to_file - assert "function abc(): string {" in bar_file.content - assert "@my_decorator" not in bar_file.content - assert "function bar(): string {" not in bar_file.content - assert "function xyz(): number {" in bar_file.content - assert codebase.get_symbol("abc").file == foo_file - assert codebase.get_symbol("xyz").file == bar_file - assert "import { bar } from './foo_test_move_to_file';" not in bar_file.content - assert "import { abc } from './foo_test_move_to_file';" not in bar_file.content - - # check baz_test_move_to_file - assert "import { bar } from './foo_test_move_to_file';" in baz_file.content - assert "function baz(): string {" in baz_file.content - assert "return bar();" in baz_file.content - assert codebase.get_symbol("baz").file == baz_file - - # Check new symbol - new_symbol = foo_file.get_symbol("bar") - assert new_symbol.file == foo_file - assert new_symbol.name == "bar" - assert isinstance(new_symbol, Function) + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() -def test_function_move_to_file_circular_dependency(tmpdir) -> None: +@pytest.mark.skipif(condition=platform.system() != "Linux", reason="Only works on case-sensitive file systems") +def test_function_move_to_file_lower_upper(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=typescript - content1 = """ + FILE_1_CONTENT = """ export function foo(): number { return bar() + 1; } @@ -735,20 +1008,16 @@ def test_function_move_to_file_circular_dependency(tmpdir) -> None: return foo() + 1; } """ - with get_codebase_session(tmpdir, files={"file1.ts": content1}, programming_language=ProgrammingLanguage.TYPESCRIPT) as codebase: - file1 = codebase.get_file("file1.ts") - foo = file1.get_function("foo") - bar = file1.get_function("bar") - assert bar in foo.dependencies - assert foo in bar.dependencies - file2 = codebase.create_file("file2.ts", "") - foo.move_to_file(file2, include_dependencies=True, strategy="add_back_edge") + # ========== [ AFTER ] ========== + # language=typescript + EXPECTED_FILE_1_CONTENT = """ +export { bar } from 'File1' +export { foo } from 'File1' +""" # language=typescript - assert ( - file2.content.strip() - == """ + EXPECTED_FILE_2_CONTENT = """ export function bar(): number { return foo() + 1; } @@ -756,24 +1025,16 @@ def test_function_move_to_file_circular_dependency(tmpdir) -> None: export function foo(): number { return bar() + 1; } -""".strip() - ) - assert file1.content.strip() == "export { bar } from 'file2'\nexport { foo } from 'file2'" - +""" -@pytest.mark.skipif(condition=platform.system() != "Linux", reason="Only works on case-sensitive file systems") -def test_function_move_to_file_lower_upper(tmpdir) -> None: - # language=typescript - content1 = """ -export function foo(): number { - return bar() + 1; -} + # =============================== + # TODO: [low] Missing semicolons -export function bar(): number { - return foo() + 1; -} - """ - with get_codebase_session(tmpdir, files={"file1.ts": content1}, programming_language=ProgrammingLanguage.TYPESCRIPT) as codebase: + with get_codebase_session( + tmpdir=tmpdir, + files={"file1.ts": FILE_1_CONTENT}, + programming_language=ProgrammingLanguage.TYPESCRIPT, + ) as codebase: file1 = codebase.get_file("file1.ts") foo = file1.get_function("foo") bar = file1.get_function("bar") @@ -783,25 +1044,14 @@ def test_function_move_to_file_lower_upper(tmpdir) -> None: file2 = codebase.create_file("File1.ts", "") foo.move_to_file(file2, include_dependencies=True, strategy="add_back_edge") - # language=typescript - assert ( - file2.content.strip() - == """ -export function bar(): number { - return foo() + 1; -} - -export function foo(): number { - return bar() + 1; -} -""".strip() - ) - assert file1.content.strip() == "export { bar } from 'File1'\nexport { foo } from 'File1'" + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() def test_function_move_to_file_no_deps(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=typescript - content1 = """ + FILE_1_CONTENT = """ export function foo(): number { return bar() + 1; } @@ -810,45 +1060,55 @@ def test_function_move_to_file_no_deps(tmpdir) -> None: return foo() + 1; } """ - with get_codebase_session(tmpdir, files={"file1.ts": content1}, programming_language=ProgrammingLanguage.TYPESCRIPT) as codebase: - file1 = codebase.get_file("file1.ts") - foo = file1.get_function("foo") - bar = file1.get_function("bar") - assert bar in foo.dependencies - assert foo in bar.dependencies - - file2 = codebase.create_file("File2.ts", "") - foo.move_to_file(file2, include_dependencies=False, strategy="add_back_edge") + # ========== [ AFTER ] ========== # language=typescript - assert ( - file1.content.strip() - == """import { foo } from 'File2'; + EXPECTED_FILE_1_CONTENT = """ +import { foo } from 'File2'; export { foo } export function bar(): number { return foo() + 1; -}""" - ) +} +""" # language=typescript - assert ( - file2.content.strip() - == """ + EXPECTED_FILE_2_CONTENT = """ import { bar } from 'file1'; export function foo(): number { return bar() + 1; } +""" + + # =============================== + # TODO: [medium] Is the extra new lines here expected behavior? + # TODO: [low] Missing semicolons + # TOOD: [low] Import and export should be changed to a re-export + + with get_codebase_session( + tmpdir=tmpdir, + files={"file1.ts": FILE_1_CONTENT}, + programming_language=ProgrammingLanguage.TYPESCRIPT, + ) as codebase: + file1 = codebase.get_file("file1.ts") + foo = file1.get_function("foo") + bar = file1.get_function("bar") + assert bar in foo.dependencies + assert foo in bar.dependencies -""".strip() - ) + file2 = codebase.create_file("File2.ts", "") + foo.move_to_file(file2, include_dependencies=False, strategy="add_back_edge") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() @pytest.mark.skipif(condition=platform.system() != "Linux", reason="Only works on case-sensitive file systems") def test_function_move_to_file_lower_upper_no_deps(tmpdir) -> None: + # ========== [ BEFORE ] ========== # language=typescript - content1 = """ + FILE_1_CONTENT = """ export function foo(): number { return bar() + 1; } @@ -857,35 +1117,46 @@ def test_function_move_to_file_lower_upper_no_deps(tmpdir) -> None: return foo() + 1; } """ - with get_codebase_session(tmpdir, files={"file1.ts": content1}, programming_language=ProgrammingLanguage.TYPESCRIPT) as codebase: - file1 = codebase.get_file("file1.ts") - foo = file1.get_function("foo") - bar = file1.get_function("bar") - assert bar in foo.dependencies - assert foo in bar.dependencies - - file2 = codebase.create_file("File1.ts", "") - foo.move_to_file(file2, include_dependencies=False, strategy="add_back_edge") + # ========== [ AFTER ] ========== # language=typescript - assert ( - file1.content.strip() - == """import { foo } from 'File1'; + EXPECTED_FILE_1_CONTENT = """ +import { foo } from 'File1'; export { foo } export function bar(): number { return foo() + 1; -}""" - ) +} +""" + # language=typescript - assert ( - file2.content.strip() - == """ + EXPECTED_FILE_2_CONTENT = """ import { bar } from 'file1'; export function foo(): number { return bar() + 1; } -""".strip() - ) +""" + + # =============================== + # TODO: [medium] Is the extra new lines here expected behavior? + # TODO: [low] Missing semicolons + # TOOD: [low] Import and export should be changed to a re-export + + with get_codebase_session( + tmpdir=tmpdir, + files={"file1.ts": FILE_1_CONTENT}, + programming_language=ProgrammingLanguage.TYPESCRIPT, + ) as codebase: + file1 = codebase.get_file("file1.ts") + foo = file1.get_function("foo") + bar = file1.get_function("bar") + assert bar in foo.dependencies + assert foo in bar.dependencies + + file2 = codebase.create_file("File1.ts", "") + foo.move_to_file(file2, include_dependencies=False, strategy="add_back_edge") + + assert file1.content.strip() == EXPECTED_FILE_1_CONTENT.strip() + assert file2.content.strip() == EXPECTED_FILE_2_CONTENT.strip() diff --git a/tests/unit/codegen/sdk/typescript/global_var/test_global_var_move_to_file.py b/tests/unit/codegen/sdk/typescript/global_var/test_global_var_move_to_file.py deleted file mode 100644 index c8f3d2fa8..000000000 --- a/tests/unit/codegen/sdk/typescript/global_var/test_global_var_move_to_file.py +++ /dev/null @@ -1,22 +0,0 @@ -from codegen.sdk.codebase.factory.get_session import get_codebase_session -from codegen.sdk.enums import ProgrammingLanguage - - -def test_global_var_move_to_file_global_var_deps_does_not_throw(tmpdir) -> None: - # language=typescript - src = """ -let b: number = 1; - -let a: number = b + 1 -""" - # language=typescript - dest = """ -""" - # TODO: fix this test - with get_codebase_session(tmpdir=tmpdir, programming_language=ProgrammingLanguage.TYPESCRIPT, files={"src.ts": src, "dest.ts": dest}, verify_output=False) as codebase: - src = codebase.get_file("src.ts") - dest = codebase.get_file("dest.ts") - a_symbol = src.get_symbol("a") - b_symbol = src.get_symbol("b") - assert b_symbol in a_symbol.dependencies - a_symbol.move_to_file(dest, include_dependencies=True)