epub_tools 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/add_chapters_to_epub'
3
+ require 'nokogiri'
4
+
5
+ class AddChaptersToEpubTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ # Directories for chapters and EPUB OEBPS
9
+ @chapters_dir = File.join(@tmp, 'chapters')
10
+ @epub_dir = File.join(@tmp, 'OEBPS')
11
+ Dir.mkdir(@chapters_dir)
12
+ Dir.mkdir(@epub_dir)
13
+
14
+ # Create sample chapter files
15
+ @chap0 = File.join(@chapters_dir, 'chapter_0.xhtml')
16
+ @chap1 = File.join(@chapters_dir, 'chapter_1.xhtml')
17
+ File.write(@chap0, '<html><body><p>Prologue</p></body></html>')
18
+ File.write(@chap1, '<html><body><p>First</p></body></html>')
19
+
20
+ # Create minimal package.opf
21
+ @opf_file = File.join(@epub_dir, 'package.opf')
22
+ opf_content = <<~XML
23
+ <?xml version="1.0"?>
24
+ <package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="pub-id" xml:lang="en">
25
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
26
+ </metadata>
27
+ <manifest>
28
+ </manifest>
29
+ <spine>
30
+ </spine>
31
+ </package>
32
+ XML
33
+ File.write(@opf_file, opf_content)
34
+
35
+ # Create minimal nav.xhtml
36
+ @nav_file = File.join(@epub_dir, 'nav.xhtml')
37
+ nav_content = <<~XHTML
38
+ <?xml version="1.0" encoding="utf-8"?>
39
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
40
+ <body>
41
+ <nav epub:type="toc" id="toc">
42
+ <ol>
43
+ </ol>
44
+ </nav>
45
+ </body>
46
+ </html>
47
+ XHTML
48
+ File.write(@nav_file, nav_content)
49
+ end
50
+
51
+ def teardown
52
+ FileUtils.remove_entry(@tmp)
53
+ end
54
+
55
+ def test_run_moves_files_and_updates_opf_and_nav
56
+ # Run the add chapters task
57
+ EpubTools::AddChaptersToEpub.new(@chapters_dir, @epub_dir).run
58
+
59
+ # Original chapter files should be moved
60
+ assert_empty Dir.glob(File.join(@chapters_dir, '*.xhtml'))
61
+ assert File.exist?(File.join(@epub_dir, 'chapter_0.xhtml'))
62
+ assert File.exist?(File.join(@epub_dir, 'chapter_1.xhtml'))
63
+
64
+ # package.opf should include manifest items and spine refs
65
+ doc = Nokogiri::XML(File.read(@opf_file)) { |cfg| cfg.default_xml.noblanks }
66
+ items = doc.xpath('//xmlns:manifest/xmlns:item')
67
+ idrefs = doc.xpath('//xmlns:spine/xmlns:itemref')
68
+ hrefs = items.map { |i| i['href'] }
69
+ ids = items.map { |i| i['id'] }
70
+ refs = idrefs.map { |ir| ir['idref'] }
71
+
72
+ assert_includes hrefs, 'chapter_0.xhtml'
73
+ assert_includes hrefs, 'chapter_1.xhtml'
74
+ assert_includes ids, 'chap0'
75
+ assert_includes ids, 'chap1'
76
+ assert_includes refs, 'chap0'
77
+ assert_includes refs, 'chap1'
78
+
79
+ # nav.xhtml should have list entries for each chapter
80
+ nav_doc = Nokogiri::XML(File.read(@nav_file))
81
+ # strip namespaces for easy querying
82
+ nav_doc.remove_namespaces!
83
+ links = nav_doc.xpath('//nav/ol/li/a')
84
+ assert_equal 2, links.size
85
+ # First is Prologue (chapter_0)
86
+ assert_equal 'chapter_0.xhtml', links[0]['href']
87
+ assert_equal 'Prologue', links[0].text
88
+ # Second is Chapter 1
89
+ assert_equal 'chapter_1.xhtml', links[1]['href']
90
+ assert_equal 'Chapter 1', links[1].text
91
+ end
92
+ end
@@ -0,0 +1,193 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/compile_book'
3
+
4
+ class CompileBookTest < Minitest::Test
5
+ def setup
6
+ @tmp = Dir.mktmpdir
7
+ @title = 'My Title'
8
+ @author = 'Me'
9
+ @source = File.join(@tmp, 'src')
10
+ FileUtils.mkdir_p(@source)
11
+ end
12
+
13
+ def teardown
14
+ FileUtils.remove_entry(@tmp)
15
+ end
16
+
17
+ def test_default_output_file
18
+ cb = EpubTools::CompileBook.new(
19
+ title: @title,
20
+ author: @author,
21
+ source_dir: @source,
22
+ build_dir: @tmp
23
+ )
24
+ assert_equal 'My_Title.epub', cb.output_file
25
+ end
26
+
27
+ def test_override_output_file
28
+ cb = EpubTools::CompileBook.new(
29
+ title: @title,
30
+ author: @author,
31
+ source_dir: @source,
32
+ output_file: 'custom.epub',
33
+ build_dir: @tmp
34
+ )
35
+ assert_equal 'custom.epub', cb.output_file
36
+ end
37
+
38
+ def test_default_build_dir
39
+ cb = EpubTools::CompileBook.new(
40
+ title: @title,
41
+ author: @author,
42
+ source_dir: @source
43
+ )
44
+ assert cb.build_dir.end_with?('.epub_tools_build')
45
+ end
46
+
47
+ def test_initialize_assigns_attributes
48
+ cb = EpubTools::CompileBook.new(
49
+ title: @title,
50
+ author: @author,
51
+ source_dir: @source,
52
+ cover_image: 'cover.png',
53
+ output_file: 'o.epub',
54
+ build_dir: 'bd',
55
+ verbose: false
56
+ )
57
+ assert_equal @title, cb.title
58
+ assert_equal @author, cb.author
59
+ assert_equal @source, cb.source_dir
60
+ assert_equal 'cover.png', cb.cover_image
61
+ assert_equal 'o.epub', cb.output_file
62
+ assert_equal 'bd', cb.build_dir
63
+ refute cb.verbose
64
+ end
65
+
66
+ def test_clean_build_dir_removes_directory
67
+ build = File.join(@tmp, 'build')
68
+ FileUtils.mkdir_p(build)
69
+ File.write(File.join(build, 'foo'), 'bar')
70
+ cb = EpubTools::CompileBook.new(
71
+ title: @title,
72
+ author: @author,
73
+ source_dir: @source,
74
+ build_dir: build
75
+ )
76
+ assert Dir.exist?(build)
77
+ cb.send(:clean_build_dir)
78
+ refute Dir.exist?(build)
79
+ end
80
+
81
+ def test_prepare_dirs_creates_xhtml_and_chapters_directories
82
+ build = File.join(@tmp, 'build')
83
+ cb = EpubTools::CompileBook.new(
84
+ title: @title,
85
+ author: @author,
86
+ source_dir: @source,
87
+ build_dir: build
88
+ )
89
+ cb.send(:prepare_dirs)
90
+ xhtml_dir = cb.send(:xhtml_dir)
91
+ chapters_dir = cb.send(:chapters_dir)
92
+ assert Dir.exist?(xhtml_dir)
93
+ assert Dir.exist?(chapters_dir)
94
+ end
95
+
96
+ def test_log_outputs_when_verbose
97
+ cb = EpubTools::CompileBook.new(
98
+ title: @title,
99
+ author: @author,
100
+ source_dir: @source,
101
+ build_dir: @tmp,
102
+ verbose: true
103
+ )
104
+ assert_output("hello\n") { cb.send(:log, 'hello') }
105
+ end
106
+
107
+ def test_log_silent_when_not_verbose
108
+ cb = EpubTools::CompileBook.new(
109
+ title: @title,
110
+ author: @author,
111
+ source_dir: @source,
112
+ build_dir: @tmp,
113
+ verbose: false
114
+ )
115
+ assert_silent { cb.send(:log, 'hello') }
116
+ end
117
+
118
+ def test_validate_sequence_raises_when_no_chapters
119
+ cb = EpubTools::CompileBook.new(
120
+ title: @title,
121
+ author: @author,
122
+ source_dir: @source,
123
+ build_dir: @tmp
124
+ )
125
+ FileUtils.mkdir_p(cb.send(:chapters_dir))
126
+ err = assert_raises(RuntimeError) { cb.send(:validate_sequence) }
127
+ assert_match(/No chapter files found/, err.message)
128
+ end
129
+
130
+ def test_validate_sequence_raises_on_missing_chapters
131
+ build = File.join(@tmp, 'build')
132
+ cb = EpubTools::CompileBook.new(
133
+ title: @title,
134
+ author: @author,
135
+ source_dir: @source,
136
+ build_dir: build
137
+ )
138
+ chapters = cb.send(:chapters_dir)
139
+ FileUtils.mkdir_p(chapters)
140
+ File.write(File.join(chapters, 'chap_1.xhtml'), '')
141
+ File.write(File.join(chapters, 'chap_3.xhtml'), '')
142
+ err = assert_raises(RuntimeError) { cb.send(:validate_sequence) }
143
+ assert_match(/Missing chapter numbers: 2/, err.message)
144
+ end
145
+
146
+ def test_validate_sequence_succeeds_on_complete_sequence
147
+ build = File.join(@tmp, 'build')
148
+ cb = EpubTools::CompileBook.new(
149
+ title: @title,
150
+ author: @author,
151
+ source_dir: @source,
152
+ build_dir: build
153
+ )
154
+ chapters = cb.send(:chapters_dir)
155
+ FileUtils.mkdir_p(chapters)
156
+ File.write(File.join(chapters, 'chap_1.xhtml'), '')
157
+ File.write(File.join(chapters, 'chap_2.xhtml'), '')
158
+ File.write(File.join(chapters, 'chap_3.xhtml'), '')
159
+ assert_nil cb.send(:validate_sequence)
160
+ end
161
+
162
+ def test_run_calls_all_steps_in_order
163
+ cb = EpubTools::CompileBook.new(
164
+ title: @title,
165
+ author: @author,
166
+ source_dir: @source,
167
+ build_dir: @tmp,
168
+ output_file: 'o.epub'
169
+ )
170
+ seq = []
171
+ cb.define_singleton_method(:clean_build_dir) { seq << :clean }
172
+ cb.define_singleton_method(:prepare_dirs) { seq << :prepare }
173
+ cb.define_singleton_method(:extract_xhtmls) { seq << :extract }
174
+ cb.define_singleton_method(:split_xhtmls) { seq << :split }
175
+ cb.define_singleton_method(:validate_sequence) { seq << :validate }
176
+ cb.define_singleton_method(:initialize_epub) { seq << :init }
177
+ cb.define_singleton_method(:add_chapters) { seq << :add }
178
+ cb.define_singleton_method(:pack_epub) { seq << :pack }
179
+ cb.define_singleton_method(:log) { |msg| seq << [:log, msg] }
180
+ cb.run
181
+ expected = [
182
+ :clean, :prepare, :extract, :split,
183
+ :validate, :init, :add, :pack,
184
+ [:log, /Done\. Output EPUB: .*o\.epub/],
185
+ :clean
186
+ ]
187
+ assert_equal expected[0..7], seq[0..7]
188
+ assert seq[8].is_a?(Array)
189
+ assert_equal :log, seq[8][0]
190
+ assert_match expected[8][1], seq[8][1]
191
+ assert_equal expected[9], seq[9]
192
+ end
193
+ end
@@ -0,0 +1,55 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/epub_initializer'
3
+
4
+ class EpubInitializerTest < Minitest::Test
5
+ def setup
6
+ @tmp = Dir.mktmpdir
7
+ @dest = File.join(@tmp, 'book_out')
8
+ @title = 'My Title'
9
+ @author = 'Me'
10
+ end
11
+
12
+ def teardown
13
+ FileUtils.remove_entry(@tmp)
14
+ end
15
+
16
+ def test_run_creates_basic_structure
17
+ EpubTools::EpubInitializer.new(@title, @author, @dest).run
18
+ # Check directories
19
+ assert Dir.exist?(@dest)
20
+ assert File.directory?(File.join(@dest, 'META-INF'))
21
+ assert File.directory?(File.join(@dest, 'OEBPS'))
22
+ # Check files
23
+ mimetype = File.join(@dest, 'mimetype')
24
+ assert File.exist?(mimetype)
25
+ assert_equal 'application/epub+zip', File.read(mimetype)
26
+ assert File.exist?(File.join(@dest, 'META-INF', 'container.xml'))
27
+ assert File.exist?(File.join(@dest, 'OEBPS', 'title.xhtml'))
28
+ assert File.exist?(File.join(@dest, 'OEBPS', 'nav.xhtml'))
29
+ assert File.exist?(File.join(@dest, 'OEBPS', 'package.opf'))
30
+ assert File.exist?(File.join(@dest, 'OEBPS', 'style.css'))
31
+ # Check content of title.xhtml
32
+ title_page = File.read(File.join(@dest, 'OEBPS', 'title.xhtml'))
33
+ assert_includes title_page, "<h1 class=\"title\">#{@title}</h1>"
34
+ assert_includes title_page, "<p class=\"author\">by #{@author}</p>"
35
+ # Check package.opf metadata
36
+ opf = File.read(File.join(@dest, 'OEBPS', 'package.opf'))
37
+ assert_includes opf, "<dc:title>#{@title}</dc:title>"
38
+ assert_includes opf, "<dc:creator>#{@author}</dc:creator>"
39
+ refute_includes opf, 'cover.xhtml'
40
+ end
41
+
42
+ def test_run_with_cover_image
43
+ # create dummy image
44
+ cover = File.join(@tmp, 'cover.png')
45
+ File.write(cover, 'PNGDATA')
46
+ EpubTools::EpubInitializer.new(@title, @author, @dest, cover).run
47
+ # Check cover file and page
48
+ assert File.exist?(File.join(@dest, 'OEBPS', 'cover.png'))
49
+ assert File.exist?(File.join(@dest, 'OEBPS', 'cover.xhtml'))
50
+ opf = File.read(File.join(@dest, 'OEBPS', 'package.opf'))
51
+ assert_includes opf, 'cover-image'
52
+ assert_includes opf, '<item id="cover-page"'
53
+ assert_includes opf, '<itemref idref="cover-page"'
54
+ end
55
+ end
@@ -0,0 +1,68 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/pack_ebook'
3
+ require 'zip'
4
+
5
+ class PackEbookTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ @epub_dir = File.join(@tmp, 'my_epub')
9
+ Dir.mkdir(@epub_dir)
10
+ end
11
+
12
+ def teardown
13
+ FileUtils.remove_entry(@tmp)
14
+ end
15
+
16
+ def test_run_creates_epub_with_expected_entries
17
+ # Create minimal EPUB directory
18
+ File.write(File.join(@epub_dir, 'mimetype'), 'application/epub+zip')
19
+ FileUtils.mkdir_p(File.join(@epub_dir, 'META-INF'))
20
+ File.write(File.join(@epub_dir, 'META-INF', 'container.xml'), '<container/>' )
21
+ FileUtils.mkdir_p(File.join(@epub_dir, 'OEBPS'))
22
+ File.write(File.join(@epub_dir, 'OEBPS', 'title.xhtml'), '<html/>' )
23
+
24
+ output = File.join(@tmp, 'out.epub')
25
+ EpubTools::PackEbook.new(@epub_dir, output).run
26
+
27
+ assert File.exist?(output), 'Expected output EPUB to exist'
28
+ entries = []
29
+ Zip::File.open(output) do |zip|
30
+ zip.each do |entry|
31
+ entries << { name: entry.name, compression: entry.compression_method }
32
+ end
33
+ end
34
+
35
+ # First entry should be mimetype, stored without compression
36
+ assert_equal 'mimetype', entries.first[:name]
37
+ assert_equal 0, entries.first[:compression]
38
+
39
+ # Check presence of other files
40
+ names = entries.map { |e| e[:name] }
41
+ assert_includes names, 'META-INF/container.xml'
42
+ assert_includes names, 'OEBPS/title.xhtml'
43
+ end
44
+
45
+ def test_missing_input_dir_raises_error
46
+ assert_raises(ArgumentError) do
47
+ EpubTools::PackEbook.new(File.join(@tmp, 'nonexistent'), 'out.epub').run
48
+ end
49
+ end
50
+
51
+ def test_missing_mimetype_raises_error
52
+ # Directory exists but no mimetype file
53
+ dir = File.join(@tmp, 'no_mime')
54
+ Dir.mkdir(dir)
55
+ assert_raises(ArgumentError) do
56
+ EpubTools::PackEbook.new(dir, 'out.epub').run
57
+ end
58
+ end
59
+
60
+ def test_default_output_file_name
61
+ # Setup minimal structure with mimetype
62
+ File.write(File.join(@epub_dir, 'mimetype'), 'application/epub+zip')
63
+ # Run without specifying output; default is "<basename>.epub" in parent
64
+ EpubTools::PackEbook.new(@epub_dir).run
65
+ default_path = File.join(@tmp, 'my_epub.epub')
66
+ assert File.exist?(default_path), "Expected default EPUB at \\#{default_path}"
67
+ end
68
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/split_chapters'
3
+
4
+ class SplitChaptersTest < Minitest::Test
5
+ def setup
6
+ @tmp = Dir.mktmpdir
7
+ @input = File.join(@tmp, 'input.xhtml')
8
+ @out = File.join(@tmp, 'out')
9
+ content = <<~HTML
10
+ <?xml version="1.0"?>
11
+ <html xmlns="http://www.w3.org/1999/xhtml">
12
+ <body>
13
+ <h3>Prologue</h3>
14
+ <p>Intro text</p>
15
+ <p>Chapter 1</p>
16
+ <p>First paragraph</p>
17
+ <p>Chapter 2</p>
18
+ <p>Second paragraph</p>
19
+ </body>
20
+ </html>
21
+ HTML
22
+ File.write(@input, content)
23
+ end
24
+
25
+ def teardown
26
+ FileUtils.remove_entry(@tmp)
27
+ end
28
+
29
+ def test_run_generates_chapter_files
30
+ EpubTools::SplitChapters.new(@input, 'BookTitle', @out, 'chap').run
31
+ files = Dir.children(@out)
32
+ assert_includes files, 'chap_0.xhtml'
33
+ assert_includes files, 'chap_1.xhtml'
34
+ assert_includes files, 'chap_2.xhtml'
35
+
36
+ # Prologue
37
+ prologue = File.read(File.join(@out, 'chap_0.xhtml'))
38
+ assert_includes prologue, '<h1>Prologue</h1>'
39
+ assert_includes prologue, 'Intro text'
40
+ refute_includes prologue, 'Chapter 1'
41
+
42
+ # Chapter 1
43
+ ch1 = File.read(File.join(@out, 'chap_1.xhtml'))
44
+ assert_includes ch1, '<h1>Chapter 1</h1>'
45
+ assert_includes ch1, 'First paragraph'
46
+ refute_includes ch1, 'Chapter 2'
47
+
48
+ # Chapter 2
49
+ ch2 = File.read(File.join(@out, 'chap_2.xhtml'))
50
+ assert_includes ch2, '<h1>Chapter 2</h1>'
51
+ assert_includes ch2, 'Second paragraph'
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ if ENV['COVERAGE']
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter '/test/'
5
+ end
6
+ end
7
+ require 'minitest/autorun'
8
+ require 'tmpdir'
9
+ require 'fileutils'
@@ -0,0 +1,40 @@
1
+ require 'yaml'
2
+ require_relative 'test_helper'
3
+ require_relative '../lib/epub_tools/text_style_class_finder'
4
+
5
+ class TextStyleClassFinderTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ @xhtml = File.join(@tmp, 'doc.xhtml')
9
+ content = <<~HTML
10
+ <html><head><style>
11
+ .c1 { font-style: italic; }
12
+ .c2 { font-weight: 700; }
13
+ .other { color: red; }
14
+ </style></head><body></body></html>
15
+ HTML
16
+ File.write(@xhtml, content)
17
+ @yaml = File.join(@tmp, 'classes.yaml')
18
+ end
19
+
20
+ def teardown
21
+ FileUtils.remove_entry(@tmp)
22
+ end
23
+
24
+ def test_finds_italic_and_bold_classes
25
+ EpubTools::TextStyleClassFinder.new(@xhtml, @yaml).call
26
+ data = YAML.load_file(@yaml)
27
+ assert_equal ['c1'], data['italics']
28
+ assert_equal ['c2'], data['bolds']
29
+ end
30
+
31
+ def test_verbose_mode
32
+ text = <<~OUTPUT
33
+ Classes with font-style: italic: c1
34
+ Classes with font-weight: 700: c2
35
+ OUTPUT
36
+ assert_output(text) do
37
+ EpubTools::TextStyleClassFinder.new(@xhtml, @yaml, verbose: true).call
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/epub_tools/unpack_ebook'
3
+ require 'zip'
4
+
5
+ class UnpackEbookTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ # Build a minimal EPUB directory for zipping
9
+ @build_dir = File.join(@tmp, 'build')
10
+ FileUtils.mkdir_p(File.join(@build_dir, 'META-INF'))
11
+ FileUtils.mkdir_p(File.join(@build_dir, 'OEBPS'))
12
+ File.write(File.join(@build_dir, 'mimetype'), 'application/epub+zip')
13
+ File.write(File.join(@build_dir, 'META-INF', 'container.xml'), '<container/>')
14
+ File.write(File.join(@build_dir, 'OEBPS', 'title.xhtml'), '<html/>')
15
+
16
+ # Create .epub zip file
17
+ @epub_file = File.join(@tmp, 'test.epub')
18
+ # Create .epub zip file with absolute src paths to avoid cwd issues
19
+ Zip::File.open(@epub_file, Zip::File::CREATE) do |zip|
20
+ # Add mimetype first, uncompressed
21
+ mime_src = File.join(@build_dir, 'mimetype')
22
+ zip.add_stored('mimetype', mime_src)
23
+ # Add directories and files
24
+ Dir.glob(File.join(@build_dir, '**', '*'), File::FNM_DOTMATCH).sort.each do |src_path|
25
+ rel_path = src_path.sub(%r{^#{Regexp.escape(@build_dir)}/?}, '')
26
+ next if rel_path.empty? || rel_path == 'mimetype'
27
+ if File.directory?(src_path)
28
+ zip.mkdir(rel_path)
29
+ else
30
+ zip.add(rel_path, src_path)
31
+ end
32
+ end
33
+ end
34
+
35
+ @dest_dir = File.join(@tmp, 'output')
36
+ end
37
+
38
+ def teardown
39
+ FileUtils.remove_entry(@tmp)
40
+ end
41
+
42
+ def test_run_extracts_all_entries
43
+ EpubTools::UnpackEbook.new(@epub_file, @dest_dir).run
44
+ # Check extracted files
45
+ assert Dir.exist?(@dest_dir)
46
+ assert_equal 'application/epub+zip', File.read(File.join(@dest_dir, 'mimetype'))
47
+ assert File.exist?(File.join(@dest_dir, 'META-INF', 'container.xml'))
48
+ assert File.exist?(File.join(@dest_dir, 'OEBPS', 'title.xhtml'))
49
+ end
50
+
51
+ def test_missing_epub_raises_error
52
+ missing = File.join(@tmp, 'nope.epub')
53
+ error = assert_raises(ArgumentError) do
54
+ EpubTools::UnpackEbook.new(missing, @dest_dir).run
55
+ end
56
+ assert_includes error.message, "does not exist"
57
+ end
58
+ end
@@ -0,0 +1,39 @@
1
+ require 'yaml'
2
+ require_relative 'test_helper'
3
+ require_relative '../lib/epub_tools/xhtml_cleaner'
4
+
5
+ class XHTMLCleanerTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ @config = File.join(@tmp, 'config.yaml')
9
+ File.write(@config, { 'italics' => ['itclass'], 'bolds' => ['boldclass'] }.to_yaml)
10
+ @file = File.join(@tmp, 'test.xhtml')
11
+ content = <<~HTML
12
+ <?xml version="1.0" encoding="UTF-8"?>
13
+ <html xmlns="http://www.w3.org/1999/xhtml">
14
+ <body>
15
+ <p><span class="itclass">ItalicsOnly</span></p>
16
+ <p>Keep<span class="plain">This</span></p>
17
+ <p><span class="boldclass">RemoveMe</span></p>
18
+ <hr style="page-break-before:always"/>
19
+ <p class="empty"></p>
20
+ </body>
21
+ </html>
22
+ HTML
23
+ File.write(@file, content)
24
+ end
25
+
26
+ def teardown
27
+ FileUtils.remove_entry(@tmp)
28
+ end
29
+
30
+ def test_cleaner_removes_and_transforms_tags
31
+ EpubTools::XHTMLCleaner.new(@file, @config).call
32
+ result = File.read(@file)
33
+ assert_includes result, '<i>ItalicsOnly</i>'
34
+ assert_includes result, 'KeepThis'
35
+ refute_includes result, '<span'
36
+ refute_includes result, '<hr'
37
+ refute_includes result, 'RemoveMe'
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'test_helper'
2
+ require 'zip'
3
+ require_relative '../lib/epub_tools/xhtml_extractor'
4
+
5
+ class XHTMLExtractorTest < Minitest::Test
6
+ def setup
7
+ @tmp = Dir.mktmpdir
8
+ @src = File.join(@tmp, 'src')
9
+ @tgt = File.join(@tmp, 'tgt')
10
+ Dir.mkdir(@src)
11
+ @file = File.join(@src, 'sample.epub')
12
+ Zip::File.open(@file, Zip::File::CREATE) do |zip|
13
+ zip.get_output_stream('chapter1.xhtml') { |f| f.write '<html><body><p>One</p></body></html>' }
14
+ zip.get_output_stream('nav.xhtml') { |f| f.write '<html><body>Nav</body></html>' }
15
+ zip.get_output_stream('folder/ch2.xhtml') { |f| f.write '<html><body><p>Two</p></body></html>' }
16
+ end
17
+ @extractor = EpubTools::XHTMLExtractor.new(source_dir: @src, target_dir: @tgt)
18
+ end
19
+
20
+ def teardown
21
+ FileUtils.remove_entry(@tmp)
22
+ end
23
+
24
+ def test_extracts_xhtml_excluding_nav
25
+ @extractor.extract_all
26
+ files = Dir.children(@tgt)
27
+ assert_includes files, 'sample_chapter1.xhtml'
28
+ assert_includes files, 'sample_ch2.xhtml'
29
+ refute_includes files, 'nav.xhtml'
30
+ end
31
+ end