#!/usr/bin/env python3
"""
Generate a test EPUB for
section-break rendering.
Tests that a bare
element between paragraphs produces a visible blank-line
gap (section separator), while a
inside a paragraph only produces a line
break with no extra spacing.
Also tests that
renders the bullet inline with the paragraph
text, not on a separate line (GitHub issue #956).
Cases covered:
1. Standalone
between paragraphs (section break — must show gap).
2.
with a CSS class (calibre-style section break).
3. Multiple consecutive
elements (each adds one line of spacing).
4. Inline
inside a
(line break only — no extra gap).
5.
at start of chapter (no gap before first paragraph).
6.
following a heading.
7.
with bold+italic text (bullet must be inline with text). 8.
with nested
wrapper — baseline, already works). Visual verification instructions are embedded as the first paragraph of each chapter so a human tester can confirm the expected result on device. """ import os import zipfile from pathlib import Path OUTPUT_DIR = Path(__file__).parent.parent / "test" / "epubs" OUTPUT_PATH = OUTPUT_DIR / "test_br_section_break.epub" FILLER = ( "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " "tempor incididunt ut labore et dolore magna aliqua." ) CSS = """\ body { margin: 0; padding: 0; } p { margin-top: 1pt; margin-bottom: 0; text-indent: 1em; text-align: justify; } h1 { text-align: center; margin-top: 0.5em; margin-bottom: 0.5em; } h2 { text-align: center; margin-top: 0.5em; margin-bottom: 0.5em; } .section-br { display: block; } .list-simple1 { margin-left: 1em; } .list-item1 { text-indent: 0; } .list-bullet { margin-left: 1em; } .list-bullet2 { margin-left: 2em; } .list { text-indent: 0; } .list-item { text-indent: 0; } """ def xhtml(title, body): return f"""\
PASS: A visible blank-line gap should appear between the two sections below.
{FILLER}
{FILLER}
PASS: The gap above should be roughly one line tall (same as a blank line).
""") # --------------------------------------------------------------------------- # Chapter 2 —PASS: A blank-line gap should appear between the two sections below, identical to Ch 1, even though the <br> carries a CSS class.
{FILLER}
{FILLER}
""") # --------------------------------------------------------------------------- # Chapter 3 — multiple consecutivePASS: Two blank lines should appear between the sections (one per <br>).
{FILLER}
{FILLER}
PASS: Three blank lines should appear below.
{FILLER}
{FILLER}
""") # --------------------------------------------------------------------------- # Chapter 4 — inlinePASS: The two lines below should be adjacent with NO extra gap between them. The <br> is inside the paragraph and must only break the line.
First line of the paragraph.
Second line of the paragraph — directly below, no gap.
PASS: Above should look like two closely-spaced lines, not like two paragraphs separated by a blank line.
""") # --------------------------------------------------------------------------- # Chapter 5 —PASS: There should be a blank-line gap between the heading above and this paragraph.
{FILLER}
PASS: There should be a blank-line gap between the section heading and this paragraph.
""") # --------------------------------------------------------------------------- # Chapter 6 —PASS: This heading should appear near the top of the page with no large blank area above it despite the <br> being the very first element.
{FILLER}
""") # --------------------------------------------------------------------------- # Chapter 7 —with bold+italic (issue #956 example 1) # --------------------------------------------------------------------------- ch7 = xhtml("Ch7: li>p bold italic", """
PASS: Each bullet below must be on the SAME line as its text, not on a separate line above it. The bullet and text are inline.
Sketching User Experiences by Bill Buxton. This book examines the notion of sketching (Hint: prototypes are a kind of sketch) across a wide variety of disciplines, with eye-opening results.
Have Paper, Will Prototype by Bill Lucas. This lecture is a series of case studies about how to successfully create paper prototypes of computer interfaces.
The Kobold Guide to Board Game Design by Mike Selinker. The very best book there is on how to design great board games.
PASS: All three bullets above should be inline with their respective text.
""") # --------------------------------------------------------------------------- # Chapter 8 —with nested
PASS: Each bullet must be inline with its text. The nested list should be indented further with its own bullets also inline.
Problem statement: Design a flying dino game where dinosaurs race in and above the water.
Detailed problem statements
We need to figure out if we can schedule all the animation time needed for the dinosaurs.
We need to develop the right number of levels for this game.
We need to figure out all the power-ups that will go into this game.
PASS: All bullets above should be inline with their text, including the nested ones.
""") # --------------------------------------------------------------------------- # Chapter 9 —wrapper, baseline) # --------------------------------------------------------------------------- ch9 = xhtml("Ch9: li direct text", """
PASS: Each bullet below must be inline with its text. This is the baseline case that already works — no <p> wrapper inside <li>.
PASS: All three bullets above should be inline with their text.
""") CHAPTERS = [ ("ch1", "chapter1.xhtml", "Chapter 1: Standalone br", ch1), ("ch2", "chapter2.xhtml", "Chapter 2: Classed br", ch2), ("ch3", "chapter3.xhtml", "Chapter 3: Multiple br", ch3), ("ch4", "chapter4.xhtml", "Chapter 4: Inline br", ch4), ("ch5", "chapter5.xhtml", "Chapter 5: br after heading", ch5), ("ch6", "chapter6.xhtml", "Chapter 6: br at start", ch6), ("ch7", "chapter7.xhtml", "Chapter 7: li>p bold italic", ch7), ("ch8", "chapter8.xhtml", "Chapter 8: li>p nested ul", ch8), ("ch9", "chapter9.xhtml", "Chapter 9: li direct text", ch9), ] def build_epub(path): os.makedirs(os.path.dirname(path), exist_ok=True) with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as epub: # mimetype must be first and uncompressed epub.writestr("mimetype", "application/epub+zip", compress_type=zipfile.ZIP_STORED) epub.writestr("META-INF/container.xml", """\