class TestImporter (TestCase): def setUp(self): TestCase.setUp(self) self.fs = TempFS() self.importer = Importer() def test_finds_index_file_in_a_subdirectory(self): self.fs.makedir("directory") self.fs.setcontents("directory/file.txt", "test") index_file = self.importer._find_index_file(self.fs, ["*.txt"]) assert_equals("directory/file.txt", index_file)
class TestFUSE(unittest.TestCase,FSTestCases): def setUp(self): self.temp_fs = TempFS() self.temp_fs.makedir("root") self.temp_fs.makedir("mount") self.mounted_fs = self.temp_fs.opendir("root") self.mount_point = self.temp_fs.getsyspath("mount") self.fs = OSFS(self.temp_fs.getsyspath("mount")) self.mount_proc = fuse.mount(self.mounted_fs,self.mount_point) def tearDown(self): self.mount_proc.unmount() self.temp_fs.close() def check(self,p): return self.mounted_fs.exists(p)
def test_remove_all(self): """Test remove_all function""" fs = TempFS() fs.setcontents("f1", "file 1") fs.setcontents("f2", "file 2") fs.setcontents("f3", "file 3") fs.makedir("foo/bar", recursive=True) fs.setcontents("foo/bar/fruit", "apple") fs.setcontents("foo/baz", "baz") utils.remove_all(fs, "foo/bar") self.assert_(not fs.exists("foo/bar/fruit")) self.assert_(fs.exists("foo/bar")) self.assert_(fs.exists("foo/baz")) utils.remove_all(fs, "") self.assert_(not fs.exists("foo/bar/fruit")) self.assert_(not fs.exists("foo/bar/baz")) self.assert_(not fs.exists("foo/baz")) self.assert_(not fs.exists("foo")) self.assert_(not fs.exists("f1")) self.assert_(fs.isdirempty('/'))
class TestFUSE(unittest.TestCase, FSTestCases, ThreadingTestCases): def setUp(self): self.temp_fs = TempFS() self.temp_fs.makedir("root") self.temp_fs.makedir("mount") self.mounted_fs = self.temp_fs.opendir("root") self.mount_point = self.temp_fs.getsyspath("mount") self.fs = OSFS(self.temp_fs.getsyspath("mount")) self.mount_proc = fuse.mount(self.mounted_fs, self.mount_point) def tearDown(self): self.mount_proc.unmount() try: self.temp_fs.close() except OSError: # Sometimes FUSE hangs onto the mountpoint if mount_proc is # forcibly killed. Shell out to fusermount to make sure. fuse.unmount(self.mount_point) self.temp_fs.close() def check(self, p): return self.mounted_fs.exists(p)
class TestFUSE(unittest.TestCase,FSTestCases,ThreadingTestCases): def setUp(self): self.temp_fs = TempFS() self.temp_fs.makedir("root") self.temp_fs.makedir("mount") self.mounted_fs = self.temp_fs.opendir("root") self.mount_point = self.temp_fs.getsyspath("mount") self.fs = OSFS(self.temp_fs.getsyspath("mount")) self.mount_proc = fuse.mount(self.mounted_fs,self.mount_point) def tearDown(self): self.mount_proc.unmount() try: self.temp_fs.close() except OSError: # Sometimes FUSE hangs onto the mountpoint if mount_proc is # forcibly killed. Shell out to fusermount to make sure. fuse.unmount(self.mount_point) self.temp_fs.close() def check(self,p): return self.mounted_fs.exists(p)
#write(wrap_prefix(prefix[:-1] + ' ') + wrap_error('max recursion levels reached')) else: print_dir(fs, pathjoin(path, item), levels[:] + [is_last_item]) else: write('%s %s' % (wrap_prefix(prefix + char_line), wrap_filename(item))) return len(dir_listing) print_dir(fs, path) return dircount[0], filecount[0] if __name__ == "__main__": from fs.tempfs import TempFS from six import b t1 = TempFS() t1.setcontents("foo", b("test")) t1.makedir("bar") t1.setcontents("bar/baz", b("another test")) t1.tree() t2 = TempFS() print t2.listdir() movedir(t1, t2) print t2.listdir() t1.tree() t2.tree()
else: print_dir(fs, pathjoin(path, item), levels[:] + [is_last_item]) else: write('%s %s' % (wrap_prefix(prefix + char_line), wrap_filename(item))) return len(dir_listing) print_dir(fs, path) return dircount[0], filecount[0] if __name__ == "__main__": from fs.tempfs import TempFS from six import b t1 = TempFS() t1.setcontents("foo", b("test")) t1.makedir("bar") t1.setcontents("bar/baz", b("another test")) t1.tree() t2 = TempFS() print t2.listdir() movedir(t1, t2) print t2.listdir() t1.tree() t2.tree()
class TestCOWFS(FSTestCases, unittest.TestCase): def make_fs(self) -> COWFS: self.tempfs = TempFS() return COWFS(self.tempfs) def test_makedir_bug(self) -> None: # These two commands disclosed a bug in COWFS.makedir(). This # serves as a regression test. self.tempfs.makedir("/b$") self.fs.makedir("/b$/c$") self.fs.invariant() def test_openbin_bug(self) -> None: # These two commands disclosed a bug in COWFS.openbin(). This # serves as a regression test. self.tempfs.makedir("/b$") self.fs.writetext("/b$/c.txt", "Buggy?") self.fs.invariant() def test_listdir_bug(self) -> None: # Removing a file disclosed a bug in COWFS.listdir(). This # serves as a regression test. self.tempfs.makedirs("/b/d") self.tempfs.writetext("/b/d/c1.txt", "hmmm") self.tempfs.writetext("/b/d/c2.txt", "hmmm") self.tempfs.writetext("/b/d/c3.txt", "hmmm") self.fs.remove("/b/d/c1.txt") self.assertEqual({"c2.txt", "c3.txt"}, set(self.fs.listdir("/b/d"))) def test_listdir(self) -> None: fs = MemoryFS() fs.makedirs("/b$") fs.makedirs("/b$/dir1") fs.makedirs("/b$/dir2") fs.writetext("/b$/file1.txt", "file1") fs.writetext("/b$/file2.txt", "file2") fs.writetext("/b$/dir1/file1.txt", "file1") fs.writetext("/b$/dir1/file2.txt", "file2") fs.writetext("/b$/dir2/file1.txt", "file1") fs.writetext("/b$/dir2/file2.txt", "file2") c = COWFS(fs) path = "/b$/dir1/file2.txt" c.writetext(path, "xxxx") # Now the COW version is different. But it should still have # the old unchanged files. self.assertTrue(c.exists("/b$/dir1/file1.txt")) # Yes, but... self.assertEqual({"dir1", "dir2", "file1.txt", "file2.txt"}, set(c.listdir("/b$"))) def test_getsyspath(self) -> None: dirpath = "/b$/dir1" self.tempfs.makedirs(dirpath) filepath = fs.path.join(dirpath, "foo.txt") self.tempfs.writetext(filepath, "original contents") # syspath for a filepath is the same as the syspath in the # basefs. self.assertEqual(self.fs.base_fs.getsyspath(filepath), self.fs.getsyspath(filepath)) # After writing to it, the syspath is now the same as the # syspath in the additions_fs. self.fs.writetext(filepath, "replacement contents") self.assertEqual(self.fs.additions_fs.getsyspath(filepath), self.fs.getsyspath(filepath)) # root raises an exception with self.assertRaises(fs.errors.NoSysPath): self.fs.getsyspath("/")
class COWFS(FS): def __init__( self, base_fs: FS, additions_fs: Optional[FS] = None, deletions_fs: Optional[FS] = None, ) -> None: FS.__init__(self) if additions_fs: self.additions_fs = additions_fs else: self.additions_fs = TempFS() if deletions_fs: _deletions_invariant(deletions_fs) self.deletions_fs = deletions_fs else: self.deletions_fs = TempFS() self.original_base_fs = base_fs self.base_fs = fs.wrap.read_only(base_fs) self.invariant() @staticmethod def create_cowfs(base_fs: FS, read_write_layer: FS, recreate: bool = False) -> "COWFS": additions_fs = read_write_layer.makedir("/additions", recreate=recreate) deletions_fs = read_write_layer.makedir("/deletions", recreate=recreate) return COWFS(base_fs, additions_fs, deletions_fs) def __str__(self) -> str: return (f"COWFS({self.original_base_fs}, " f"{self.additions_fs}, " f"{self.deletions_fs})") def __repr__(self) -> str: return (f"COWFS({self.original_base_fs!r}, " f"{self.additions_fs!r}, " f"{self.deletions_fs!r})") ############################################################ def invariant(self) -> bool: if not self.additions_fs: raise ValueError(f"Invalid additions_fs: {self.additions_fs}.") if not self.deletions_fs: raise ValueError(f"Invalid deletions_fs: {self.additions_fs}.") if not self.base_fs: raise ValueError(f"Invalid base_fs: {self.base_fs}.") _deletions_invariant(self.deletions_fs) additions_paths = set(paths(self.additions_fs)) deletions_paths = { fs.path.dirname(file) for file in self.deletions_fs.walk.files() } if additions_paths > deletions_paths: raise ValueError(f"Additions_paths {additions_paths} " + "is not a subset of deletions_path " + f"{deletions_paths}. Extras are " + f"{additions_paths - deletions_paths}.") return True def is_deletion(self, path: str) -> bool: """ Is the path marked in the deletions_fs" """ return self.deletions_fs.exists(del_path(path)) def mark_deletion(self, path: str) -> None: """ Mark the path in the deletions_fs. """ self.deletions_fs.makedirs(path, None, True) self.deletions_fs.touch(del_path(path)) def makedirs_mark_deletion( self, path: str, permissions: Optional[Permissions] = None, recreate: bool = False, ) -> None: for p in fs.path.recursepath(path)[:-1]: self.additions_fs.makedirs(p, permissions=permissions, recreate=True) self.mark_deletion(p) self.additions_fs.makedir(path, permissions=permissions, recreate=recreate) self.mark_deletion(path) def layer(self, path: str) -> int: """ Get the layer on which the file lives, or ROOT_LAYER if it's the root path. """ if path == "/": return ROOT_LAYER if self.additions_fs.exists(path): return ADD_LAYER elif self.is_deletion(path): return NO_LAYER elif self.base_fs.exists(path): return BASE_LAYER else: return NO_LAYER def copy_up(self, path: str) -> None: """ Copy the file from the base_fs to additions_fs. """ self.makedirs_mark_deletion(fs.path.dirname(path)) self.mark_deletion(path) fs.copy.copy_file(self.base_fs, path, self.additions_fs, path) def triple_tree(self) -> None: print("base_fs ------------------------------") self.base_fs.tree() print("additions_fs ------------------------------") self.additions_fs.tree() print("deletions_fs ------------------------------") self.deletions_fs.tree() ############################################################ def getmeta(self, namespace: str = "standard") -> Mapping[str, object]: return self.base_fs.getmeta(namespace) def getinfo(self, path: str, namespaces: Optional[Collection[str]] = None) -> Info: self.check() self.validatepath(path) layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.ResourceNotFound(path) elif layer == BASE_LAYER: return self.base_fs.getinfo(path, namespaces) elif layer == ADD_LAYER: return self.additions_fs.getinfo(path, namespaces) elif layer == ROOT_LAYER: # TODO implement this raw_info = {} if namespaces is None or "basic" in namespaces: raw_info["basic"] = {"name": "", "is_dir": True} return Info(raw_info) else: raise RuntimeError(f"Unknown layer {layer}.") def getsyspath(self, path: str) -> str: self.check() # self.validatepath(path) layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.NoSysPath(path=path) elif layer == BASE_LAYER: return self.base_fs.getsyspath(path) elif layer == ADD_LAYER: return self.additions_fs.getsyspath(path) elif layer == ROOT_LAYER: raise fs.errors.NoSysPath(path=path) else: raise RuntimeError(f"Unknown layer {layer}.") def listdir(self, path: str) -> List[str]: self.check() self.validatepath(path) layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.ResourceNotFound(path) elif layer == BASE_LAYER: return [ name for name in self.base_fs.listdir(path) if self.layer(fs.path.join(path, name)) != NO_LAYER ] elif layer == ADD_LAYER: # Get the listing on the additions layer names = set(self.additions_fs.listdir(path)) # Add in the listing on the base layer (if it exists) if self.base_fs.isdir(path): names |= set(self.base_fs.listdir(path)) # Return the entries that actually exist return [ name for name in list(names) if self.layer(fs.path.join(path, name)) != NO_LAYER ] elif layer == ROOT_LAYER: # Get the listing of the root on the additions layer and # the base layer. names = set(self.additions_fs.listdir("/")) names |= set(self.base_fs.listdir("/")) # Return the entries that actually exist. return [ name for name in list(names) if self.layer(name) != NO_LAYER ] else: raise RuntimeError(f"Unknown layer {layer}.") def makedir( self, path: str, permissions: Optional[Permissions] = None, recreate: bool = False, ) -> SubFS["COWFS"]: self.check() self.validatepath(path) # Check if it *can* be created. # get a normalized parent_dir path. parent_dir = fs.path.dirname(fs.path.forcedir(path)[:-1]) if not parent_dir: parent_dir = "/" if not self.isdir(parent_dir): raise fs.errors.ResourceNotFound(path) layer = self.layer(path) if layer == NO_LAYER: self.makedirs_mark_deletion(path, permissions=permissions, recreate=recreate) return SubFS(self, path) elif layer in [BASE_LAYER, ADD_LAYER, ROOT_LAYER]: if recreate: return SubFS(self, path) else: # I think this is wrong. What if it's a file? raise fs.errors.DirectoryExists(path) else: raise RuntimeError(f"Unknown layer {layer}.") def openbin(self, path: str, mode: str = "r", buffering: int = -1, **options: Any) -> BinaryIO: self.check() self.validatepath(path) parent_dir = fs.path.dirname(fs.path.forcedir(path)[:-1]) if not parent_dir: parent_dir = "/" if not self.isdir(parent_dir): raise fs.errors.ResourceNotFound(path) mode_obj = Mode(mode) layer = self.layer(path) if layer == NO_LAYER: if mode_obj.create: for p in fs.path.recursepath(path)[:-1]: self.additions_fs.makedirs(p, recreate=True) self.mark_deletion(p) self.mark_deletion(path) return self.additions_fs.openbin(path, mode, buffering, **options) else: raise fs.errors.ResourceNotFound(path) elif layer == ADD_LAYER: self.mark_deletion(path) return self.additions_fs.openbin(path, mode, buffering, **options) elif layer == BASE_LAYER: if mode_obj.writing: self.copy_up(path) return self.additions_fs.openbin(path, mode, buffering, **options) else: return self.base_fs.openbin(path, mode, buffering, **options) elif layer == ROOT_LAYER: raise fs.errors.FileExpected(path) else: raise RuntimeError(f"Unknown layer {layer}.") def remove(self, path: str) -> None: self.check() self.validatepath(path) layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.ResourceNotFound(path) elif layer == BASE_LAYER: if self.base_fs.isfile(path): self.mark_deletion(path) else: raise fs.errors.FileExpected(path) elif layer == ADD_LAYER: self.additions_fs.remove(path) self.mark_deletion(path) elif layer == ROOT_LAYER: raise fs.errors.FileExpected(path) else: raise RuntimeError(f"Unknown layer {layer}.") def removedir(self, path: str) -> None: self.check() layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.ResourceNotFound(path) elif layer == BASE_LAYER: if self.base_fs.isdir(path): self.mark_deletion(path) else: raise fs.errors.FileExpected(path) elif layer == ADD_LAYER: if self.additions_fs.isdir(path): self.additions_fs.removedir(path) self.mark_deletion(path) else: raise fs.errors.DirectoryExpected(path) elif layer == ROOT_LAYER: raise fs.errors.RemoveRootError(path) else: raise RuntimeError(f"Unknown layer {layer}.") def setinfo(self, path: str, info: _INFO_DICT) -> None: self.check() self.validatepath(path) layer = self.layer(path) if layer == NO_LAYER: raise fs.errors.ResourceNotFound(path) elif layer == BASE_LAYER: self.copy_up(path) self.additions_fs.setinfo(path, info) elif layer == ADD_LAYER: self.additions_fs.setinfo(path, info) elif layer == ROOT_LAYER: pass else: raise RuntimeError(f"Unknown layer {layer}.") ############################################################ def makedirs( self, path: str, permissions: Optional[Permissions] = None, recreate: bool = False, ) -> SubFS[FS]: return FS.makedirs(self, path, permissions=permissions, recreate=recreate)
class TestSuperMemoQAImport (TestCase): def setUp(self): TestCase.setUp(self) self.fs = TempFS() factory = m.ImportedInstanceFactory(self, field_types={ 'question': 'html', 'answer': 'html' }) self.importer = SuperMemoQAImporter(self.fs, factory, m.HTMLMarkupImporter(self)) self.cos = [] self.images = [] self.sounds = [] def test_single_card(self): data = u"Q: question 1\nA: answer 1" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(unicode, type(self.cos[0]['question'])) assert_equals(unicode, type(self.cos[0]['answer'])) assert_equals(u"question 1", self.cos[0]['question']) assert_equals(u"answer 1", self.cos[0]['answer']) def test_windows_line_endings(self): data = u"Q: question 1\r\nA: answer 1" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question 1", self.cos[0]['question']) assert_equals(u"answer 1", self.cos[0]['answer']) def test_multiple_cards(self): data = """Q: question A: answer Q: question 2 A: answer 2""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(2, len(self.cos)) assert_equals(u"question", self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(u"question 2", self.cos[1]['question']) assert_equals(u"answer 2", self.cos[1]['answer']) def test_content_is_right_trimmed(self): data = u"Q: question \nA: answer \n" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question", self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) def test_multiline_question_and_answer(self): data = """Q: question Q: end of question A: answer A: end of answer""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question\nend of question", self.cos[0]['question']) assert_equals(u"answer\nend of answer", self.cos[0]['answer']) def test_multiline_question_and_answer_lines_are_rtrimmed(self): data = "Q: question \nQ: end of question \nA: answer \nA: end of answer " self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question\nend of question", self.cos[0]['question']) assert_equals(u"answer\nend of answer", self.cos[0]['answer']) def test_custom_encoding(self): data = (u"Q: być szczerym\nA: to be frank").encode('cp1250') self.fs.setcontents('cards.txt', data) self.importer.encoding = 'cp1250' self.importer() assert_equals(1, len(self.cos)) assert_equals(unicode, type(self.cos[0]['question'])) assert_equals(unicode, type(self.cos[0]['answer'])) assert_equals(u"być szczerym", self.cos[0]['question']) assert_equals(u"to be frank", self.cos[0]['answer']) def test_html_tags_are_preserved(self): data = """Q: hist: When did we <b>land on the moon</b>? A: 1969 <i>(July 20)</i>""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(u"hist: When did we <b>land on the moon</b>?", self.cos[0]['question']) assert_equals(u"1969 <i>(July 20)</i>", self.cos[0]['answer']) def test_card_with_image(self): data = u"""Q: <img src="image.jpg" /> A: answer""" self.fs.setcontents('index.txt', data) image_data = self.data.getcontents('small.jpg') self.fs.setcontents('image.jpg', image_data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u'<img src="/images/image.jpg"/>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.images)) assert_equals('image.jpg', self.images[0]['filename']) assert_equals('image/jpeg', self.images[0]['mime_type']) assert_true(image_data == self.images[0]['data']) def test_card_with_index_in_subdirectory_and_image(self): data = u'Q: <img src="image.jpg" />\nA: answer' self.fs.makedir('dir') self.fs.setcontents('dir/index.txt', data) image_data = self.data.getcontents('small.jpg') self.fs.setcontents('dir/image.jpg', image_data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u'<img src="/images/image.jpg"/>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.images)) assert_equals('image.jpg', self.images[0]['filename']) assert_equals('image/jpeg', self.images[0]['mime_type']) assert_true(image_data == self.images[0]['data']) def test_card_with_audio(self): data = u"""Q: <span class="audio autoplay"><a href="button.mp3" /></span> A: answer""" self.fs.setcontents('index.txt', data) sound_data = self.data.getcontents('button.mp3') self.fs.setcontents('button.mp3', sound_data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u'<span class="audio autoplay"><a href="/sounds/button.mp3"/></span>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.sounds)) assert_equals('button.mp3', self.sounds[0]['filename']) assert_equals('audio/mpeg', self.sounds[0]['mime_type']) assert_true(sound_data == self.sounds[0]['data']) def test_byte_order_mark_in_utf8_files_is_removed(self): data = u'\ufeffQ: \uac00\uac8c\r\nA: store' self.fs.setcontents('index.txt', data.encode('utf8')) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"\uac00\uac8c", self.cos[0]['question']) assert_equals(u"store", self.cos[0]['answer']) def test_invalid_xml_results_in_input_error(self): data = u'Q: <b>question\nA: answer' self.fs.setcontents('index.txt', data) assert_raises(ConversionFailure, self.importer) def test_invalid_fields_number_in_input_error(self): data = u'Q: question' self.fs.setcontents('index.txt', data) assert_raises(ConversionFailure, self.importer)
class TestSuperMemoQAImport(TestCase): def setUp(self): TestCase.setUp(self) self.fs = TempFS() factory = m.ImportedInstanceFactory(self, field_types={ 'question': 'html', 'answer': 'html' }) self.importer = SuperMemoQAImporter(self.fs, factory, m.HTMLMarkupImporter(self)) self.cos = [] self.images = [] self.sounds = [] def test_single_card(self): data = u"Q: question 1\nA: answer 1" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(unicode, type(self.cos[0]['question'])) assert_equals(unicode, type(self.cos[0]['answer'])) assert_equals(u"question 1", self.cos[0]['question']) assert_equals(u"answer 1", self.cos[0]['answer']) def test_windows_line_endings(self): data = u"Q: question 1\r\nA: answer 1" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question 1", self.cos[0]['question']) assert_equals(u"answer 1", self.cos[0]['answer']) def test_multiple_cards(self): data = """Q: question A: answer Q: question 2 A: answer 2""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(2, len(self.cos)) assert_equals(u"question", self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(u"question 2", self.cos[1]['question']) assert_equals(u"answer 2", self.cos[1]['answer']) def test_content_is_right_trimmed(self): data = u"Q: question \nA: answer \n" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question", self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) def test_multiline_question_and_answer(self): data = """Q: question Q: end of question A: answer A: end of answer""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question\nend of question", self.cos[0]['question']) assert_equals(u"answer\nend of answer", self.cos[0]['answer']) def test_multiline_question_and_answer_lines_are_rtrimmed(self): data = "Q: question \nQ: end of question \nA: answer \nA: end of answer " self.fs.setcontents('cards.txt', data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"question\nend of question", self.cos[0]['question']) assert_equals(u"answer\nend of answer", self.cos[0]['answer']) def test_custom_encoding(self): data = (u"Q: być szczerym\nA: to be frank").encode('cp1250') self.fs.setcontents('cards.txt', data) self.importer.encoding = 'cp1250' self.importer() assert_equals(1, len(self.cos)) assert_equals(unicode, type(self.cos[0]['question'])) assert_equals(unicode, type(self.cos[0]['answer'])) assert_equals(u"być szczerym", self.cos[0]['question']) assert_equals(u"to be frank", self.cos[0]['answer']) def test_html_tags_are_preserved(self): data = """Q: hist: When did we <b>land on the moon</b>? A: 1969 <i>(July 20)</i>""" self.fs.setcontents('cards.txt', data) self.importer() assert_equals(u"hist: When did we <b>land on the moon</b>?", self.cos[0]['question']) assert_equals(u"1969 <i>(July 20)</i>", self.cos[0]['answer']) def test_card_with_image(self): data = u"""Q: <img src="image.jpg" /> A: answer""" self.fs.setcontents('index.txt', data) image_data = self.data.getcontents('small.jpg') self.fs.setcontents('image.jpg', image_data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u'<img src="/images/image.jpg"/>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.images)) assert_equals('image.jpg', self.images[0]['filename']) assert_equals('image/jpeg', self.images[0]['mime_type']) assert_true(image_data == self.images[0]['data']) def test_card_with_index_in_subdirectory_and_image(self): data = u'Q: <img src="image.jpg" />\nA: answer' self.fs.makedir('dir') self.fs.setcontents('dir/index.txt', data) image_data = self.data.getcontents('small.jpg') self.fs.setcontents('dir/image.jpg', image_data) self.importer() assert_equals(1, len(self.cos)) assert_equals(u'<img src="/images/image.jpg"/>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.images)) assert_equals('image.jpg', self.images[0]['filename']) assert_equals('image/jpeg', self.images[0]['mime_type']) assert_true(image_data == self.images[0]['data']) def test_card_with_audio(self): data = u"""Q: <span class="audio autoplay"><a href="button.mp3" /></span> A: answer""" self.fs.setcontents('index.txt', data) sound_data = self.data.getcontents('button.mp3') self.fs.setcontents('button.mp3', sound_data) self.importer() assert_equals(1, len(self.cos)) assert_equals( u'<span class="audio autoplay"><a href="/sounds/button.mp3"/></span>', self.cos[0]['question']) assert_equals(u"answer", self.cos[0]['answer']) assert_equals(1, len(self.sounds)) assert_equals('button.mp3', self.sounds[0]['filename']) assert_equals('audio/mpeg', self.sounds[0]['mime_type']) assert_true(sound_data == self.sounds[0]['data']) def test_byte_order_mark_in_utf8_files_is_removed(self): data = u'\ufeffQ: \uac00\uac8c\r\nA: store' self.fs.setcontents('index.txt', data.encode('utf8')) self.importer() assert_equals(1, len(self.cos)) assert_equals(u"\uac00\uac8c", self.cos[0]['question']) assert_equals(u"store", self.cos[0]['answer']) def test_invalid_xml_results_in_input_error(self): data = u'Q: <b>question\nA: answer' self.fs.setcontents('index.txt', data) assert_raises(ConversionFailure, self.importer) def test_invalid_fields_number_in_input_error(self): data = u'Q: question' self.fs.setcontents('index.txt', data) assert_raises(ConversionFailure, self.importer)