diff --git a/CHANGELOG.md b/CHANGELOG.md index ba328bd9a..82bcf5fa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - #119, #928 Fix IndexError in rename and find occurrences when a `from` import is the last thing in a module without a trailing newline (@mcepl) - #921 Patch the else suite of try statements that also have a finally (@marlon-costa-dc) - #937 Preserve non-ASCII argument expressions and default values when changing function signatures (@Jinyong-Li) +- #950 Reorganise projecttest.py and improve test coverages (@lieryan) # Release 1.15.1 diff --git a/rope/base/project.py b/rope/base/project.py index c7f6a2f8e..319dbb118 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -55,14 +55,14 @@ def get_resource(self, resource_name: str) -> Resource: path = self._get_resource_path(resource_name) if not os.path.exists(path): raise exceptions.ResourceNotFoundError( - "Resource <%s> does not exist" % resource_name + f"Resource <{resource_name}> does not exist" ) elif os.path.isfile(path): return File(self, resource_name) elif os.path.isdir(path): return Folder(self, resource_name) else: - raise exceptions.ResourceNotFoundError("Unknown resource " + resource_name) + raise exceptions.ResourceNotFoundError(f"Unknown resource {resource_name}") def get_python_path_folders(self) -> list[Folder]: result = [] @@ -132,7 +132,7 @@ def get_relative_module( ) -> pyobjectsdef.PyPackage | pyobjectsdef.PyModule: module = self.find_relative_module(name, folder, level) if module is None: - raise ModuleNotFoundError("Module %s not found" % name) + raise ModuleNotFoundError(f"Module {name} not found") return self.pycore.resource_to_pyobject(module) def find_relative_module( @@ -284,7 +284,7 @@ def get_module( return pymod module = self.find_module(name, folder) if module is None: - raise ModuleNotFoundError("Module %s not found" % name) + raise ModuleNotFoundError(f"Module {name} not found") return self.pycore.resource_to_pyobject(module) def get_files(self) -> list[Resource]: diff --git a/ropetest/conftest.py b/ropetest/conftest.py index 99ec1b76b..7ad7e4caa 100644 --- a/ropetest/conftest.py +++ b/ropetest/conftest.py @@ -5,6 +5,7 @@ import pytest +import rope.base.project from rope.base import resources from ropetest import testutils @@ -47,10 +48,16 @@ def session_venv_python_executable(session_venv): yield python_executable +@pytest.fixture +def no_project(): + return rope.base.project.get_no_project() + + @pytest.fixture def project(session_venv, session_venv_site_packages): project = testutils.sample_project( python_path=[str(session_venv_site_packages)], + ropefolder=None, ) yield project testutils.remove_project(project) diff --git a/ropetest/contrib/autoimport/conftest.py b/ropetest/contrib/autoimport/conftest.py index 9dca8ccf5..7a667d068 100644 --- a/ropetest/contrib/autoimport/conftest.py +++ b/ropetest/contrib/autoimport/conftest.py @@ -5,6 +5,15 @@ from ropetest import testutils +@pytest.fixture +def project(session_venv, session_venv_site_packages): + project = testutils.sample_project( + python_path=[str(session_venv_site_packages)], + ) + yield project + testutils.remove_project(project) + + @pytest.fixture def mod1(project): mod1 = testutils.create_module(project, "mod1") diff --git a/ropetest/projecttest.py b/ropetest/projecttest.py index 1f1b37d83..6b3b4a695 100644 --- a/ropetest/projecttest.py +++ b/ropetest/projecttest.py @@ -5,7 +5,9 @@ from textwrap import dedent from unittest.mock import patch -from rope.base.exceptions import ResourceNotFoundError, RopeError +import pytest + +from rope.base import exceptions from rope.base.fscommands import FileSystemCommands from rope.base.libutils import path_to_resource from rope.base.project import NoProject, Project, _realpath @@ -14,95 +16,313 @@ from ropetest import testutils -class ProjectTest(unittest.TestCase): - def setUp(self): - unittest.TestCase.setUp(self) - self.project = testutils.sample_project( - foldername="sampleproject", ropefolder=None - ) +@pytest.fixture +def sample_project(project): + """ + Sample project structure + /sample_file.txt -- "sample text\n" + /sample_folder + """ + project_root = project.address + sample_file = "sample_file.txt" + sample_path = os.path.join(project_root, "sample_file.txt") + if not os.path.exists(project_root): + os.mkdir(project_root) + sample_folder = "sample_folder" + os.mkdir(os.path.join(project_root, sample_folder)) + pathlib.Path(sample_path).write_text("sample text\n") + return project + + +class SetupSampleProject: + @pytest.fixture(autouse=True) + def setup(self, sample_project): + self.project = sample_project self.project_root = self.project.address - self._make_sample_project() - self.no_project = NoProject() - - def _make_sample_project(self): self.sample_file = "sample_file.txt" self.sample_path = os.path.join(self.project_root, "sample_file.txt") - if not os.path.exists(self.project_root): - os.mkdir(self.project_root) self.sample_folder = "sample_folder" - os.mkdir(os.path.join(self.project_root, self.sample_folder)) - sample = open(self.sample_path, "w") - sample.write("sample text\n") - sample.close() - def tearDown(self): + @pytest.fixture + def project(self): + project = testutils.sample_project( + foldername="sampleproject", ropefolder=None + ) + yield project testutils.remove_project(self.project) - unittest.TestCase.tearDown(self) + +class ProjectTest(SetupSampleProject, unittest.TestCase): def test_project_creation(self): self.assertEqual(_realpath(self.project_root), self.project.address) - def test_getting_project_file(self): - project_file = self.project.get_resource(self.sample_file) - self.assertTrue(project_file is not None) + def test_making_root_folder_if_it_does_not_exist(self): + with tempfile.TemporaryDirectory(dir=testutils.RUN_TMP_DIR) as tmpdir: + project_root = pathlib.Path(tmpdir) / "sampleproject2" + assert not project_root.exists() + + project = Project(project_root) + + assert project_root.exists() + assert project_root.is_dir() + + def test_failure_when_project_root_exists_and_is_a_file(self): + with tempfile.TemporaryDirectory(dir=testutils.RUN_TMP_DIR) as tmpdir: + project_root = pathlib.Path(tmpdir) / "sampleproject2" + project_root.touch() + assert project_root.exists() and project_root.is_file() + + with self.assertRaises(exceptions.RopeError): + Project(project_root) + + def test_project_root_is_root_folder(self): + self.assertEqual("", self.project.root.path) + + ################################ + # Project.get_source_folders() # + ################################ + + def test_getting_empty_source_folders(self): + self.assertEqual([], self.project.get_source_folders()) + + def test_root_source_folder(self): + self.project.root.create_file("sample.py") + source_folders = self.project.get_source_folders() + self.assertEqual(1, len(source_folders)) + self.assertTrue(self.project.root in source_folders) + + def test_root_source_folder2(self): + self.project.root.create_file("mod1.py") + self.project.root.create_file("mod2.py") + source_folders = self.project.get_source_folders() + self.assertEqual(1, len(source_folders)) + self.assertTrue(self.project.root in source_folders) + + def test_src_source_folder(self): + src = self.project.root.create_folder("src") + src.create_file("sample.py") + source_folders = self.project.get_source_folders() + self.assertEqual(1, len(source_folders)) + self.assertTrue(self.project.get_resource("src") in source_folders) + + def test_packages(self): + src = self.project.root.create_folder("src") + pkg = src.create_folder("package") + pkg.create_file("__init__.py") + source_folders = self.project.get_source_folders() + self.assertEqual(1, len(source_folders)) + self.assertTrue(src in source_folders) + + def test_multi_source_folders(self): + src = self.project.root.create_folder("src") + package = src.create_folder("package") + package.create_file("__init__.py") + test = self.project.root.create_folder("test") + test.create_file("alltests.py") + source_folders = self.project.get_source_folders() + self.assertEqual(2, len(source_folders)) + self.assertTrue(src in source_folders) + self.assertTrue(test in source_folders) + + def test_multi_source_folders2(self): + testutils.create_module(self.project, "mod1") + src = self.project.root.create_folder("src") + package = testutils.create_package(self.project, "package", src) + testutils.create_module(self.project, "mod2", package) + source_folders = self.project.get_source_folders() + self.assertEqual(2, len(source_folders)) + self.assertTrue(self.project.root in source_folders and src in source_folders) + + +class FileTest(SetupSampleProject, unittest.TestCase): + """ + Test cases for basic file content operations: + + - File.read + - File.read_bytes + - File.write + """ def test_project_file_reading(self): projectFile = self.project.get_resource(self.sample_file) self.assertEqual("sample text\n", projectFile.read()) - def test_getting_not_existing_project_file(self): - with self.assertRaises(ResourceNotFoundError): - self.project.get_resource("DoesNotExistFile.txt") - def test_writing_in_project_files(self): project_file = self.project.get_resource(self.sample_file) project_file.write("another text\n") self.assertEqual("another text\n", project_file.read()) + def test_file_encoding_reading(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = ( + b"# -*- coding: utf-8 -*-\n" + + br"#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" + ).decode("utf8") + file = open(sample_file.real_path, "wb") + file.write(contents.encode("utf-8")) + file.close() + self.assertEqual(contents, sample_file.read()) + + def test_file_encoding_writing(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = ( + b"# -*- coding: utf-8 -*-\n" + br"\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" + ).decode("utf8") + sample_file.write(contents) + self.assertEqual(contents, sample_file.read()) + + def test_using_utf8_when_writing_in_case_of_errors(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = br"\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n".decode("utf8") + sample_file.write(contents) + self.assertEqual(contents, sample_file.read()) + + def test_encoding_declaration_in_the_second_line(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"\n# -*- coding: latin-1 -*-\n\xa9\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertEqual(contents, sample_file.read().encode("latin-1")) + + def test_not_an_encoding_declaration(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"def my_method(self, encoding='latin-1'):\n var = {}\n\xc2\xa9\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertEqual(contents, sample_file.read().encode("utf-8")) + self.assertNotEqual(contents, sample_file.read().encode("latin-1")) + + def test_read_bytes(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"\n# -*- coding: latin-1 -*-\n\xa9\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertEqual(contents, sample_file.read_bytes()) + + def test_file_with_unix_line_ending(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"1\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertIsNone(sample_file.newlines) + self.assertEqual("1\n", sample_file.read()) + self.assertEqual("\n", sample_file.newlines) + + sample_file.write("1\n") + self.assertEqual(b"1\n", sample_file.read_bytes()) + + def test_file_with_dos_line_ending(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"1\r\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertIsNone(sample_file.newlines) + self.assertEqual("1\n", sample_file.read()) + self.assertEqual("\r\n", sample_file.newlines) + + sample_file.write("1\n") + self.assertEqual(b"1\r\n", sample_file.read_bytes()) + + def test_file_with_mac_line_ending(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"1\r" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertIsNone(sample_file.newlines) + self.assertEqual("1\n", sample_file.read()) + self.assertEqual("\r", sample_file.newlines) + + sample_file.write("1\n") + self.assertEqual(b"1\r", sample_file.read_bytes()) + + def test_file_binary(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"1\r\n" + file = open(sample_file.real_path, "wb") + file.write(contents) + file.close() + self.assertIsNone(sample_file.newlines) + self.assertEqual(b"1\r\n", sample_file.read_bytes()) + self.assertIsNone(sample_file.newlines) + + sample_file.write(b"1\nx\r") + self.assertEqual((b"1\nx\r"), sample_file.read_bytes()) + + # TODO: Detecting utf-16 encoding + def xxx_test_using_utf16(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = b"# -*- coding: utf-16 -*-\n# This is a sample file ...\n" + file = open(sample_file.real_path, "w") + file.write(contents.encode("utf-16")) + file.close() + sample_file.write(contents) + self.assertEqual(contents, sample_file.read()) + + # XXX: supporting utf_8_sig + def xxx_test_file_encoding_reading_for_notepad_styles(self): + sample_file = self.project.root.create_file("my_file.txt") + contents = "#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" + file = open(sample_file.real_path, "w") + # file.write('\xef\xbb\xbf') + file.write(contents.encode("utf-8-sig")) + file.close() + self.assertEqual(contents, sample_file.read()) + + +class FolderTest(SetupSampleProject, unittest.TestCase): + """ + Test cases for Folder operations: + + - Folder.create_file/create_folder + - File/Folder.create + - File/Folder.remove + - File/Folder.move + - File/Folder metadata (name, path) + - File/Folder introspection methods (is_folder, is_dir) + - Folder.__fspath__ + - Folder.get_children/get_files/get_folders + - Folder.get_child + """ + + #################################### + # Folder.create_file/create_folder # + #################################### + def test_creating_files(self): project_file = "newfile.txt" + self.project.root.create_file(project_file) + newFile = self.project.get_resource(project_file) self.assertTrue(newFile is not None) def test_creating_files_that_already_exist(self): - with self.assertRaises(RopeError): + with self.assertRaises(exceptions.RopeError): self.project.root.create_file(self.sample_file) - def test_making_root_folder_if_it_does_not_exist(self): - with tempfile.TemporaryDirectory(dir=testutils.RUN_TMP_DIR) as tmpdir: - project_root = pathlib.Path(tmpdir) / "sampleproject2" - assert not project_root.exists() - - project = Project(project_root) - - assert project_root.exists() - assert project_root.is_dir() - - def test_failure_when_project_root_exists_and_is_a_file(self): - with tempfile.TemporaryDirectory(dir=testutils.RUN_TMP_DIR) as tmpdir: - project_root = pathlib.Path(tmpdir) / "sampleproject2" - project_root.touch() - assert project_root.exists() and project_root.is_file() - - with self.assertRaises(RopeError): - Project(project_root) - def test_creating_folders(self): folderName = "SampleFolder" + self.project.root.create_folder(folderName) + folderPath = os.path.join(self.project.address, folderName) self.assertTrue(os.path.exists(folderPath) and os.path.isdir(folderPath)) def test_making_folder_that_already_exists(self): folderName = "SampleFolder" - with self.assertRaises(RopeError): + with self.assertRaises(exceptions.RopeError): self.project.root.create_folder(folderName) self.project.root.create_folder(folderName) def test_failing_if_creating_folder_while_file_already_exists(self): folderName = "SampleFolder" - with self.assertRaises(RopeError): + with self.assertRaises(exceptions.RopeError): self.project.root.create_file(folderName) self.project.root.create_folder(folderName) @@ -110,8 +330,10 @@ def test_creating_file_inside_folder(self): folder_name = "sampleFolder" file_name = "sample2.txt" file_path = folder_name + "/" + file_name + parent_folder = self.project.root.create_folder(folder_name) parent_folder.create_file(file_name) + file = self.project.get_resource(file_path) file.write("sample notes") self.assertEqual(file_path, file.path) @@ -120,44 +342,127 @@ def test_creating_file_inside_folder(self): ) def test_failing_when_creating_file_inside_non_existent_folder(self): - with self.assertRaises(ResourceNotFoundError): + with self.assertRaises(exceptions.ResourceNotFoundError): self.project.root.create_file("NonexistentFolder/SomeFile.txt") def test_nested_directories(self): folder_name = "SampleFolder" + parent = self.project.root.create_folder(folder_name) parent.create_folder(folder_name) + folder_path = os.path.join(self.project.address, folder_name, folder_name) self.assertTrue(os.path.exists(folder_path) and os.path.isdir(folder_path)) - def test_removing_files(self): - self.assertTrue(os.path.exists(self.sample_path)) - self.project.get_resource(self.sample_file).remove() - self.assertFalse(os.path.exists(self.sample_path)) + def test_folder_creating_files(self): + projectFile = "NewFile.txt" - def test_removing_files_invalidating_in_project_resource_pool(self): - root_folder = self.project.root - my_file = root_folder.create_file("my_file.txt") - my_file.remove() - self.assertFalse(root_folder.has_child("my_file.txt")) + self.project.root.create_file(projectFile) + + new_file = self.project.get_resource(projectFile) + self.assertTrue(new_file is not None and not new_file.is_folder()) + + def test_folder_creating_nested_files(self): + project_file = "NewFile.txt" + parent_folder = self.project.get_resource(self.sample_folder) + + parent_folder.create_file(project_file) + + new_file = self.project.get_resource(self.sample_folder + "/" + project_file) + self.assertTrue(new_file is not None and not new_file.is_folder()) + + def test_folder_creating_files2(self): + projectFile = "newfolder" + + self.project.root.create_folder(projectFile) + + new_folder = self.project.get_resource(projectFile) + self.assertTrue(new_folder is not None and new_folder.is_folder()) + + def test_folder_creating_nested_files2(self): + project_file = "newfolder" + parent_folder = self.project.get_resource(self.sample_folder) + + parent_folder.create_folder(project_file) + + new_folder = self.project.get_resource(self.sample_folder + "/" + project_file) + self.assertTrue(new_folder is not None and new_folder.is_folder()) + + + ###################### + # File/Folder.create # + ###################### + + def test_using_file_create(self): + myfile = self.project.get_file("myfile.txt") + self.assertFalse(myfile.exists()) + + myfile.create() + + self.assertTrue(myfile.exists()) + self.assertFalse(myfile.is_folder()) + + def test_using_folder_create(self): + myfolder = self.project.get_folder("myfolder") + self.assertFalse(myfolder.exists()) + + myfolder.create() + + self.assertTrue(myfolder.exists()) + self.assertTrue(myfolder.is_folder()) + + def test_exception_when_creating_twice(self): + with self.assertRaises(exceptions.RopeError): + myfile = self.project.get_file("myfile.txt") + myfile.create() + myfile.create() + + def test_exception_when_parent_does_not_exist(self): + with self.assertRaises(exceptions.ResourceNotFoundError): + myfile = self.project.get_file("myfolder/myfile.txt") + myfile.create() + + + ###################### + # File/Folder.remove # + ###################### + + def test_removing_files(self): + self.assertTrue(os.path.exists(self.sample_path)) + + self.project.get_resource(self.sample_file).remove() + + self.assertFalse(os.path.exists(self.sample_path)) + + def test_removing_files_invalidating_in_project_resource_pool(self): + root_folder = self.project.root + my_file = root_folder.create_file("my_file.txt") + + my_file.remove() + + self.assertFalse(root_folder.has_child("my_file.txt")) + + def test_removing_directories(self): + self.assertTrue( + os.path.exists(os.path.join(self.project.address, self.sample_folder)) + ) - def test_removing_directories(self): - self.assertTrue( - os.path.exists(os.path.join(self.project.address, self.sample_folder)) - ) self.project.get_resource(self.sample_folder).remove() + self.assertFalse( os.path.exists(os.path.join(self.project.address, self.sample_folder)) ) def test_removing_non_existent_files(self): - with self.assertRaises(ResourceNotFoundError): + with self.assertRaises(exceptions.ResourceNotFoundError): self.project.get_resource("NonExistentFile.txt").remove() def test_removing_nested_files(self): file_name = self.sample_folder + "/sample_file.txt" self.project.root.create_file(file_name) + self.project.get_resource(file_name).remove() + self.assertTrue( os.path.exists(os.path.join(self.project.address, self.sample_folder)) ) @@ -165,6 +470,56 @@ def test_removing_nested_files(self): not os.path.exists(os.path.join(self.project.address, file_name)) ) + + #################### + # File/Folder.move # + #################### + + def test_moving_files(self): + root_folder = self.project.root + my_file = root_folder.create_file("my_file.txt") + + my_file.move("my_other_file.txt") + + self.assertFalse(my_file.exists()) + root_folder.get_child("my_other_file.txt") + + def test_moving_folders(self): + root_folder = self.project.root + my_folder = root_folder.create_folder("my_folder") + my_file = my_folder.create_file("my_file.txt") + + my_folder.move("new_folder") + + self.assertFalse(root_folder.has_child("my_folder")) + self.assertFalse(my_file.exists()) + self.assertTrue(root_folder.get_child("new_folder") is not None) + + def test_moving_destination_folders(self): + root_folder = self.project.root + my_folder = root_folder.create_folder("my_folder") + my_file = root_folder.create_file("my_file.txt") + + my_file.move("my_folder") + + self.assertFalse(root_folder.has_child("my_file.txt")) + self.assertFalse(my_file.exists()) + my_folder.get_child("my_file.txt") + + def test_moving_files_and_resource_objects(self): + root_folder = self.project.root + my_file = root_folder.create_file("my_file.txt") + old_hash = hash(my_file) + + my_file.move("my_other_file.txt") + + self.assertEqual(old_hash, hash(my_file)) + + + ######################## + # File/Folder metadata # + ######################## + def test_file_get_name(self): file = self.project.get_resource(self.sample_file) self.assertEqual(self.sample_file, file.name) @@ -173,10 +528,12 @@ def test_file_get_name(self): filePath = self.sample_folder + "/" + file_name parent.create_file(file_name) nestedFile = self.project.get_resource(filePath) + self.assertEqual(file_name, nestedFile.name) def test_folder_get_name(self): folder = self.project.get_resource(self.sample_folder) + self.assertEqual(self.sample_folder, folder.name) def test_file_get_path(self): @@ -187,12 +544,19 @@ def test_file_get_path(self): filePath = self.sample_folder + "/" + fileName parent.create_file(fileName) nestedFile = self.project.get_resource(filePath) + self.assertEqual(filePath, nestedFile.path) def test_folder_get_path(self): folder = self.project.get_resource(self.sample_folder) + self.assertEqual(self.sample_folder, folder.path) + + ##################################### + # File/Folder introspection methods # + ##################################### + def test_is_folder(self): self.assertTrue(self.project.get_resource(self.sample_folder).is_folder()) self.assertTrue(not self.project.get_resource(self.sample_file).is_folder()) @@ -203,8 +567,31 @@ def test_is_dir(self): with patch('rope.base.resources.File.is_folder') as is_folder2: assert self.project.get_resource(self.sample_file).is_dir() == is_folder2.return_value - def testget_children(self): + + ########################## + # File/Folder.__fspath__ # + ########################## + + def test_folder_is_pathlike(self): + resource = self.project.root.create_folder("src") + self.assertIsInstance(resource, Folder) + + self.assertIsInstance(os.fspath(resource), str) + + def test_file_is_pathlike(self): + resource = self.project.root.create_file("mod.py") + self.assertIsInstance(resource, File) + + self.assertIsInstance(os.fspath(resource), str) + + + ############################################# + # Folder.get_children/get_files/get_folders # + ############################################# + + def test_get_children(self): children = self.project.get_resource(self.sample_folder).get_children() + self.assertEqual([], children) def test_nonempty_get_children(self): @@ -212,7 +599,9 @@ def test_nonempty_get_children(self): filePath = self.sample_folder + "/" + file_name parent = self.project.get_resource(self.sample_folder) parent.create_file(file_name) + children = parent.get_children() + self.assertEqual(1, len(children)) self.assertEqual(filePath, children[0].path) @@ -224,7 +613,9 @@ def test_nonempty_get_children2(self): parent = self.project.get_resource(self.sample_folder) parent.create_file(file_name) parent.create_folder(folder_name) + children = parent.get_children() + self.assertEqual(2, len(children)) self.assertTrue(filePath == children[0].path or filePath == children[1].path) self.assertTrue( @@ -244,11 +635,13 @@ def test_does_not_fail_for_permission_denied(self): def test_getting_files(self): files = self.project.root.get_files() + self.assertEqual(1, len(files)) self.assertTrue(self.project.get_resource(self.sample_file) in files) def test_getting_folders(self): folders = self.project.root.get_folders() + self.assertEqual(1, len(folders)) self.assertTrue(self.project.get_resource(self.sample_folder) in folders) @@ -256,7 +649,9 @@ def test_nested_folder_get_files(self): parent = self.project.root.create_folder("top") parent.create_file("file1.txt") parent.create_file("file2.txt") + files = parent.get_files() + self.assertEqual(2, len(files)) self.assertTrue(self.project.get_resource("top/file2.txt") in files) self.assertEqual(0, len(parent.get_folders())) @@ -265,19 +660,24 @@ def test_nested_folder_get_folders(self): parent = self.project.root.create_folder("top") parent.create_folder("dir1") parent.create_folder("dir2") + folders = parent.get_folders() + self.assertEqual(2, len(folders)) self.assertTrue(self.project.get_resource("top/dir1") in folders) self.assertEqual(0, len(parent.get_files())) def test_root_folder(self): root_folder = self.project.root + self.assertEqual(2, len(root_folder.get_children())) + self.assertEqual("", root_folder.path) self.assertEqual("", root_folder.name) def test_get_all_files(self): files = tuple(self.project.get_files()) + self.assertEqual(1, len(files)) self.assertEqual(self.sample_file, files[0].name) @@ -285,7 +685,9 @@ def test_get_all_files_after_changing(self): self.assertEqual(1, len(self.project.get_files())) myfile = self.project.root.create_file("myfile.txt") self.assertEqual(2, len(self.project.get_files())) + myfile.move("newfile.txt") + self.assertEqual(2, len(self.project.get_files())) self.project.get_file("newfile.txt").remove() self.assertEqual(1, len(self.project.get_files())) @@ -294,7 +696,9 @@ def test_multifile_get_all_files(self): fileName = "nestedFile.txt" parent = self.project.get_resource(self.sample_folder) parent.create_file(fileName) + files = list(self.project.get_files()) + self.assertEqual(2, len(files)) self.assertTrue(fileName == files[0].name or fileName == files[1].name) @@ -304,39 +708,34 @@ def test_ignoring_dot_pyc_files_in_get_files(self): os.mkdir(src_folder) test_pyc = os.path.join(src_folder, "test.pyc") open(test_pyc, "w").close() + for x in self.project.get_files(): self.assertNotEqual("src/test.pyc", x.path) - def test_folder_creating_files(self): - projectFile = "NewFile.txt" - self.project.root.create_file(projectFile) - new_file = self.project.get_resource(projectFile) - self.assertTrue(new_file is not None and not new_file.is_folder()) + @testutils.skipNotPOSIX() + def test_ignoring_symlinks_inside_project(self): + project2 = testutils.sample_project(folder_name="sampleproject2") + mod = project2.root.create_file("mod.py") + try: + path = os.path.join(self.project.address, "linkedfile.txt") + os.symlink(mod.real_path, path) - def test_folder_creating_nested_files(self): - project_file = "NewFile.txt" - parent_folder = self.project.get_resource(self.sample_folder) - parent_folder.create_file(project_file) - new_file = self.project.get_resource(self.sample_folder + "/" + project_file) - self.assertTrue(new_file is not None and not new_file.is_folder()) + files = self.project.root.get_files() - def test_folder_creating_files2(self): - projectFile = "newfolder" - self.project.root.create_folder(projectFile) - new_folder = self.project.get_resource(projectFile) - self.assertTrue(new_folder is not None and new_folder.is_folder()) + self.assertEqual(1, len(files)) + finally: + testutils.remove_project(project2) - def test_folder_creating_nested_files2(self): - project_file = "newfolder" - parent_folder = self.project.get_resource(self.sample_folder) - parent_folder.create_folder(project_file) - new_folder = self.project.get_resource(self.sample_folder + "/" + project_file) - self.assertTrue(new_folder is not None and new_folder.is_folder()) + + #################### + # Folder.get_child # + #################### def test_folder_get_child(self): folder = self.project.root folder.create_file("myfile.txt") folder.create_folder("myfolder") + self.assertEqual( self.project.get_resource("myfile.txt"), folder.get_child("myfile.txt") ) @@ -349,6 +748,7 @@ def test_folder_get_child_nested(self): folder = root.create_folder("myfolder") folder.create_file("myfile.txt") folder.create_folder("myfolder") + self.assertEqual( self.project.get_resource("myfolder/myfile.txt"), folder.get_child("myfile.txt"), @@ -357,278 +757,180 @@ def test_folder_get_child_nested(self): self.project.get_resource("myfolder/myfolder"), folder.get_child("myfolder") ) - def test_project_root_is_root_folder(self): - self.assertEqual("", self.project.root.path) - - def test_moving_files(self): - root_folder = self.project.root - my_file = root_folder.create_file("my_file.txt") - my_file.move("my_other_file.txt") - self.assertFalse(my_file.exists()) - root_folder.get_child("my_other_file.txt") - - def test_moving_folders(self): - root_folder = self.project.root - my_folder = root_folder.create_folder("my_folder") - my_file = my_folder.create_file("my_file.txt") - my_folder.move("new_folder") - self.assertFalse(root_folder.has_child("my_folder")) - self.assertFalse(my_file.exists()) - self.assertTrue(root_folder.get_child("new_folder") is not None) - - def test_moving_destination_folders(self): - root_folder = self.project.root - my_folder = root_folder.create_folder("my_folder") - my_file = root_folder.create_file("my_file.txt") - my_file.move("my_folder") - self.assertFalse(root_folder.has_child("my_file.txt")) - self.assertFalse(my_file.exists()) - my_folder.get_child("my_file.txt") - - def test_moving_files_and_resource_objects(self): - root_folder = self.project.root - my_file = root_folder.create_file("my_file.txt") - old_hash = hash(my_file) - my_file.move("my_other_file.txt") - self.assertEqual(old_hash, hash(my_file)) - - def test_file_encoding_reading(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = ( - b"# -*- coding: utf-8 -*-\n" - + br"#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" - ).decode("utf8") - file = open(sample_file.real_path, "wb") - file.write(contents.encode("utf-8")) - file.close() - self.assertEqual(contents, sample_file.read()) - - def test_file_encoding_writing(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = ( - b"# -*- coding: utf-8 -*-\n" + br"\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" - ).decode("utf8") - sample_file.write(contents) - self.assertEqual(contents, sample_file.read()) - - def test_using_utf8_when_writing_in_case_of_errors(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = br"\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n".decode("utf8") - sample_file.write(contents) - self.assertEqual(contents, sample_file.read()) - - def test_encoding_declaration_in_the_second_line(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"\n# -*- coding: latin-1 -*-\n\xa9\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertEqual(contents, sample_file.read().encode("latin-1")) - - def test_not_an_encoding_declaration(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"def my_method(self, encoding='latin-1'):\n var = {}\n\xc2\xa9\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertEqual(contents, sample_file.read().encode("utf-8")) - self.assertNotEqual(contents, sample_file.read().encode("latin-1")) - - def test_read_bytes(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"\n# -*- coding: latin-1 -*-\n\xa9\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertEqual(contents, sample_file.read_bytes()) - - def test_file_with_unix_line_ending(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"1\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertIsNone(sample_file.newlines) - self.assertEqual("1\n", sample_file.read()) - self.assertEqual("\n", sample_file.newlines) - - sample_file.write("1\n") - self.assertEqual(b"1\n", sample_file.read_bytes()) - - def test_file_with_dos_line_ending(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"1\r\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertIsNone(sample_file.newlines) - self.assertEqual("1\n", sample_file.read()) - self.assertEqual("\r\n", sample_file.newlines) - - sample_file.write("1\n") - self.assertEqual(b"1\r\n", sample_file.read_bytes()) - - def test_file_with_mac_line_ending(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"1\r" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertIsNone(sample_file.newlines) - self.assertEqual("1\n", sample_file.read()) - self.assertEqual("\r", sample_file.newlines) - - sample_file.write("1\n") - self.assertEqual(b"1\r", sample_file.read_bytes()) - - def test_file_binary(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"1\r\n" - file = open(sample_file.real_path, "wb") - file.write(contents) - file.close() - self.assertIsNone(sample_file.newlines) - self.assertEqual(b"1\r\n", sample_file.read_bytes()) - self.assertIsNone(sample_file.newlines) - - sample_file.write(b"1\nx\r") - self.assertEqual((b"1\nx\r"), sample_file.read_bytes()) - - # TODO: Detecting utf-16 encoding - def xxx_test_using_utf16(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = b"# -*- coding: utf-16 -*-\n# This is a sample file ...\n" - file = open(sample_file.real_path, "w") - file.write(contents.encode("utf-16")) - file.close() - sample_file.write(contents) - self.assertEqual(contents, sample_file.read()) - - # XXX: supporting utf_8_sig - def xxx_test_file_encoding_reading_for_notepad_styles(self): - sample_file = self.project.root.create_file("my_file.txt") - contents = "#\N{LATIN SMALL LETTER I WITH DIAERESIS}\n" - file = open(sample_file.real_path, "w") - # file.write('\xef\xbb\xbf') - file.write(contents.encode("utf-8-sig")) - file.close() - self.assertEqual(contents, sample_file.read()) - - def test_using_project_get_file(self): - myfile = self.project.get_file(self.sample_file) - self.assertTrue(myfile.exists()) - - def test_using_file_create(self): - myfile = self.project.get_file("myfile.txt") - self.assertFalse(myfile.exists()) - myfile.create() - self.assertTrue(myfile.exists()) - self.assertFalse(myfile.is_folder()) - - def test_using_folder_create(self): - myfolder = self.project.get_folder("myfolder") - self.assertFalse(myfolder.exists()) - myfolder.create() - self.assertTrue(myfolder.exists()) - self.assertTrue(myfolder.is_folder()) - - def test_exception_when_creating_twice(self): - with self.assertRaises(RopeError): - myfile = self.project.get_file("myfile.txt") - myfile.create() - myfile.create() - - def test_exception_when_parent_does_not_exist(self): - with self.assertRaises(ResourceNotFoundError): - myfile = self.project.get_file("myfolder/myfile.txt") - myfile.create() - - def test_simple_path_to_resource(self): - myfile = self.project.root.create_file("myfile.txt") - self.assertEqual(myfile, path_to_resource(self.project, myfile.real_path)) - self.assertEqual( - myfile, path_to_resource(self.project, myfile.real_path, type="file") - ) - myfolder = self.project.root.create_folder("myfolder") - self.assertEqual(myfolder, path_to_resource(self.project, myfolder.real_path)) - self.assertEqual( - myfolder, path_to_resource(self.project, myfolder.real_path, type="folder") - ) - - @testutils.skipNotPOSIX() - def test_ignoring_symlinks_inside_project(self): - project2 = testutils.sample_project(folder_name="sampleproject2") - mod = project2.root.create_file("mod.py") - try: - path = os.path.join(self.project.address, "linkedfile.txt") - os.symlink(mod.real_path, path) - files = self.project.root.get_files() - self.assertEqual(1, len(files)) - finally: - testutils.remove_project(project2) - - def test_getting_empty_source_folders(self): - self.assertEqual([], self.project.get_source_folders()) - - def test_root_source_folder(self): - self.project.root.create_file("sample.py") - source_folders = self.project.get_source_folders() - self.assertEqual(1, len(source_folders)) - self.assertTrue(self.project.root in source_folders) - - def test_root_source_folder2(self): - self.project.root.create_file("mod1.py") - self.project.root.create_file("mod2.py") - source_folders = self.project.get_source_folders() - self.assertEqual(1, len(source_folders)) - self.assertTrue(self.project.root in source_folders) - - def test_src_source_folder(self): - src = self.project.root.create_folder("src") - src.create_file("sample.py") - source_folders = self.project.get_source_folders() - self.assertEqual(1, len(source_folders)) - self.assertTrue(self.project.get_resource("src") in source_folders) - - def test_packages(self): - src = self.project.root.create_folder("src") - pkg = src.create_folder("package") - pkg.create_file("__init__.py") - source_folders = self.project.get_source_folders() - self.assertEqual(1, len(source_folders)) - self.assertTrue(src in source_folders) - - def test_multi_source_folders(self): - src = self.project.root.create_folder("src") - package = src.create_folder("package") - package.create_file("__init__.py") - test = self.project.root.create_folder("test") - test.create_file("alltests.py") - source_folders = self.project.get_source_folders() - self.assertEqual(2, len(source_folders)) - self.assertTrue(src in source_folders) - self.assertTrue(test in source_folders) - def test_multi_source_folders2(self): - testutils.create_module(self.project, "mod1") - src = self.project.root.create_folder("src") - package = testutils.create_package(self.project, "package", src) - testutils.create_module(self.project, "mod2", package) - source_folders = self.project.get_source_folders() - self.assertEqual(2, len(source_folders)) - self.assertTrue(self.project.root in source_folders and src in source_folders) - - def test_folder_is_pathlike(self): - resource = self.project.root.create_folder("src") - self.assertIsInstance(resource, Folder) - - self.assertIsInstance(os.fspath(resource), str) - - def test_file_is_pathlike(self): - resource = self.project.root.create_file("mod.py") - self.assertIsInstance(resource, File) - - self.assertIsInstance(os.fspath(resource), str) +class TestProjectGetResource: + """ + Test cases for Project methods related to getting files/folders: + + - Project.get_resource + - Project.get_file + - Project.get_folder + - libutils.path_to_resource + """ + + @pytest.fixture(params=["devnull", "mkfifo"]) + def special_file(self, request, project) -> str: + match request.param: + case "devnull": + return os.devnull + case "mkfifo": + if not hasattr(os, "mkfifo"): + pytest.skip() + fifo_path = project.address + "/fifo" + os.mkfifo(fifo_path) + return fifo_path + case _: + assert False + + @pytest.fixture + def file_outside_project(self, project): + path = "../sample_file.txt" + file = pathlib.Path(project.address) / path + file.touch() + return path + + + ######################## + # Project.get_resource # + ######################## + + def test_get_resource_getting_not_existing_project_file(self, project): + with pytest.raises( + exceptions.ResourceNotFoundError, + match="Resource does not exist", + ): + project.get_resource("DoesNotExistFile.txt") + + def test_no_project_get_resource_special_file(self, no_project, special_file): + match os.name, special_file: + case "nt", os.devnull: + expected_message = f"Unknown resource //./nul" + case _: + expected_message = f"Unknown resource {special_file}" + + with pytest.raises( + exceptions.ResourceNotFoundError, + match=expected_message, + ): + no_project.get_resource(special_file) + + def test_project_get_resource_special_file(self, project, special_file): + match os.name, special_file: + case "nt", os.devnull: + expected_message = f"Unknown resource nul" + case _: + expected_message = f"Resource <{special_file}> does not exist" + + with pytest.raises( + exceptions.ResourceNotFoundError, + match=expected_message, + ): + project.get_resource(special_file) + + def test_get_resource_getting_existing_project_file(self, sample_project): + project_file = sample_project.get_resource("sample_file.txt") + assert isinstance(project_file, File) + + def test_get_resource_getting_existing_project_folder(self, sample_project): + project_file = sample_project.get_resource("sample_folder") + assert isinstance(project_file, Folder) + + def test_project_get_resource_getting_existing_resource_with_slash( + self, sample_project + ): + """ + For Project.get_resource(), starting slashes are interpreted as + relative to project directory. + """ + project_file = sample_project.get_resource("/sample_file.txt") + assert isinstance(project_file, File) + assert project_file.pathlib.is_relative_to(sample_project.address) + + with tempfile.NamedTemporaryFile() as tmp: + abspath = str(pathlib.Path(tmp.name).absolute()) + _, slashpath = os.path.splitdrive(abspath) + assert slashpath.startswith("/") + with pytest.raises( + exceptions.ResourceNotFoundError, + match="Resource <.*> does not exist", + ): + project_file = sample_project.get_resource(slashpath) + + def test_no_project_get_resource_getting_existing_resource_with_slash( + self, no_project, file_outside_project + ): + """ + For NoProject.get_resource(), starting slashes are interpreted as + absolute path relative to project root. NoProject should be used to get + resources for files/folders that's not part of a project. + """ + with tempfile.NamedTemporaryFile() as tmp: + abspath = str(pathlib.Path(tmp.name).absolute()) + _, slashpath = os.path.splitdrive(abspath) + assert slashpath.startswith("/") + project_file = no_project.get_resource(slashpath) + assert isinstance(project_file, File) + assert project_file.exists() + + def test_get_resource_getting_existing_resource_with_double_dot_disable_projectroot_check( + self, sample_project, file_outside_project + ): + assert file_outside_project == "../sample_file.txt" + resource = sample_project.get_resource(file_outside_project) + assert isinstance(resource, File) + assert resource.path == "../sample_file.txt" + assert resource.real_path.endswith("sample_project/../sample_file.txt".replace("/", os.path.sep)) + + ############################# + # libutils.path_to_resource # + ############################# + + def test_simple_path_to_resource(self, sample_project): + myfile = sample_project.root.create_file("myfile.txt") + assert myfile == path_to_resource(sample_project, myfile.real_path) + assert myfile == path_to_resource(sample_project, myfile.real_path, type="file") + + myfolder = sample_project.root.create_folder("myfolder") + assert myfolder == path_to_resource(sample_project, myfolder.real_path) + assert myfolder == path_to_resource(sample_project, myfolder.real_path, type="folder") + + + #################### + # Project.get_file # + #################### + + def test_using_project_get_file(self, sample_project): + myfile = sample_project.get_file("sample_file.txt") + + assert myfile.exists() + + +class TestProjectGetModule: + """ + Test cases for Project methods related to getting modules: + + - Project.get_module + - Project.find_module + - Project.get_relative_module + - Project.find_relative_module + + FIXME: most of the test for these methods are in pycoretest.py + """ + + def test_get_module_non_existent_module(self, project): + with pytest.raises( + exceptions.ModuleNotFoundError, + match="Module doesnotexistmodule not found", + ): + project.get_module("doesnotexistmodule") + + def test_get_relative_module_non_existent_module(self, project): + src = project.root.create_folder("src") + with pytest.raises( + exceptions.ModuleNotFoundError, + match="Module ..doesnotexistmodule not found", + ): + project.get_relative_module("..doesnotexistmodule", folder=src, level=2) class ResourceObserverTest(unittest.TestCase): diff --git a/ropetest/pycoretest.py b/ropetest/pycoretest.py index 5ccd80d2a..15c9aa137 100644 --- a/ropetest/pycoretest.py +++ b/ropetest/pycoretest.py @@ -140,10 +140,6 @@ class InnerClass(object): var = sample_class["InnerClass"].get_object() self.assertEqual(get_base_type("Type"), var.get_type()) - def test_non_existent_module(self): - with self.assertRaises(exceptions.ModuleNotFoundError): - self.project.get_module("doesnotexistmodule") - def test_imported_names(self): testutils.create_module(self.project, "mod1") mod = testutils.create_module(self.project, "mod2")