elio 1.3.0

Snappy, batteries-included terminal file manager with rich previews, inline images, bulk actions, and trash support.
Documentation
use super::*;

#[test]
fn epub_preview_uses_doc_toc_role_and_normalizes_nested_labels() {
    let root = temp_path("epub-doc-toc-role");
    fs::create_dir_all(&root).expect("failed to create temp root");
    let path = root.join("story.epub");
    write_zip_entries(
        &path,
        &[
            (
                "META-INF/container.xml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
                      <rootfiles>
                        <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
                      </rootfiles>
                    </container>"#,
            ),
            (
                "OPS/package.opf",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <package xmlns="http://www.idpf.org/2007/opf" version="3.0">
                      <manifest>
                        <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
                        <item id="chapter-1" href="text/chapter-1.xhtml" media-type="application/xhtml+xml"/>
                        <item id="chapter-2" href="text/chapter-2.xhtml" media-type="application/xhtml+xml"/>
                      </manifest>
                      <spine>
                        <itemref idref="chapter-1"/>
                        <itemref idref="chapter-2"/>
                      </spine>
                    </package>"#,
            ),
            (
                "OPS/nav.xhtml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <html xmlns="http://www.w3.org/1999/xhtml">
                      <body>
                        <nav role="doc-toc">
                          <ol>
                            <li>
                              <a href="text/chapter-1.xhtml">
                                <span>Opening</span>
                                <br />
                                Move
                              </a>
                            </li>
                            <li><a href="text/chapter-2.xhtml">Deep Dive</a></li>
                          </ol>
                        </nav>
                      </body>
                    </html>"#,
            ),
            (
                "OPS/text/chapter-1.xhtml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <html xmlns="http://www.w3.org/1999/xhtml">
                      <body>
                        <p>First chapter content.</p>
                      </body>
                    </html>"#,
            ),
            (
                "OPS/text/chapter-2.xhtml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <html xmlns="http://www.w3.org/1999/xhtml">
                      <body>
                        <p>Second chapter content.</p>
                      </body>
                    </html>"#,
            ),
        ],
    );

    let preview = build_preview(&file_entry(path.clone()));
    let line_texts: Vec<_> = preview.lines.iter().map(line_text).collect();
    assert_eq!(preview.ebook_section_index, Some(0));
    assert_eq!(preview.ebook_section_count, Some(2));
    assert_eq!(preview.ebook_section_title.as_deref(), Some("Opening Move"));
    assert!(
        line_texts
            .iter()
            .any(|text| text.contains("First chapter content."))
    );

    let second_preview = build_preview_with_options(
        &file_entry(path.clone()),
        &PreviewRequestOptions::EpubSection(1),
    );
    let second_line_texts: Vec<_> = second_preview.lines.iter().map(line_text).collect();
    assert_eq!(
        second_preview.ebook_section_title.as_deref(),
        Some("Deep Dive")
    );
    assert!(
        second_line_texts
            .iter()
            .any(|text| text.contains("Second chapter content."))
    );

    fs::remove_dir_all(root).expect("failed to remove temp root");
}

#[test]
fn epub_preview_uses_ncx_toc_when_navigation_document_is_missing() {
    let root = temp_path("epub-ncx-toc");
    fs::create_dir_all(&root).expect("failed to create temp root");
    let path = root.join("story.epub");
    write_zip_entries(
        &path,
        &[
            (
                "META-INF/container.xml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
                      <rootfiles>
                        <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
                      </rootfiles>
                    </container>"#,
            ),
            (
                "OPS/package.opf",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <package xmlns="http://www.idpf.org/2007/opf" version="2.0">
                      <manifest>
                        <item id="toc" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
                        <item id="chapter-1" href="Text/chapter-1.xhtml" media-type="application/xhtml+xml"/>
                        <item id="chapter-2" href="Text/chapter-2.xhtml" media-type="application/xhtml+xml"/>
                      </manifest>
                      <spine toc="toc">
                        <itemref idref="chapter-1"/>
                        <itemref idref="chapter-2"/>
                      </spine>
                    </package>"#,
            ),
            (
                "OPS/toc.ncx",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
                      <navMap>
                        <navPoint id="chapter-1" playOrder="1">
                          <navLabel><text>Prelude</text></navLabel>
                          <content src="Text/chapter-1.xhtml"/>
                        </navPoint>
                        <navPoint id="chapter-2" playOrder="2">
                          <navLabel><text>Finale</text></navLabel>
                          <content src="Text/chapter-2.xhtml"/>
                        </navPoint>
                      </navMap>
                    </ncx>"#,
            ),
            (
                "OPS/Text/chapter-1.xhtml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <html xmlns="http://www.w3.org/1999/xhtml">
                      <body><p>Prelude text.</p></body>
                    </html>"#,
            ),
            (
                "OPS/Text/chapter-2.xhtml",
                r#"<?xml version="1.0" encoding="UTF-8"?>
                    <html xmlns="http://www.w3.org/1999/xhtml">
                      <body><p>Finale text.</p></body>
                    </html>"#,
            ),
        ],
    );

    let preview = build_preview(&file_entry(path.clone()));
    let line_texts: Vec<_> = preview.lines.iter().map(line_text).collect();
    assert_eq!(preview.ebook_section_index, Some(0));
    assert_eq!(preview.ebook_section_count, Some(2));
    assert_eq!(preview.ebook_section_title.as_deref(), Some("Prelude"));
    assert!(line_texts.iter().any(|text| text.contains("Prelude text.")));

    let second_preview = build_preview_with_options(
        &file_entry(path.clone()),
        &PreviewRequestOptions::EpubSection(1),
    );
    assert_eq!(
        second_preview.ebook_section_title.as_deref(),
        Some("Finale")
    );

    fs::remove_dir_all(root).expect("failed to remove temp root");
}