aware-tectonic 0.16.10

A modernized, complete, embeddable TeX/LaTeX engine. Tectonic is forked from the XeTeX extension to the classic "Web2C" implementation of TeX and uses the TeXLive distribution of support files. This is the Aware Software fork of tectonic 0.16.9: identical to upstream except that its bundle crate (aware-tectonic-bundles) does not contact the network when the bundle cache is warm.
Documentation
// tests/trip.rs - implemention the TRIP test for Tectonic
// Copyright 2016-2018 the Tectonic Project
// Licensed under the MIT License.

//! Our incarnation of the classic TRIP test. Unfortunately, the test is
//! defined in terms of the precise terminal output and error handling behavior
//! of the engine, so you can't do anything to improve the (incredibly poor) UX
//! of the TeX engine without having to fudge what "the TRIP test" is. That is
//! what we have done.
//!
//! Cargo tries to run tests in multiple simultaneous threads, which of course
//! totally fails for Tectonic since the engine has tons of global state. The
//! multithreading can be disabled by setting the RUST_TEST_THREADS environment
//! variable to "1", but that's an annoying solution. So, we use a global mutex
//! to achieve the same effect. Classy.

use tectonic::io::testing::SingleInputFileIo;
use tectonic::io::{FilesystemPrimaryInputIo, IoProvider, IoStack, MemoryIo};
use tectonic::TexEngine;
use tectonic_bridge_core::{CoreBridgeLauncher, MinimalDriver};
use tectonic_engine_xetex::TexOutcome;
use tectonic_status_base::NoopStatusBackend;

#[path = "util/mod.rs"]
mod util;
use crate::util::{test_path, Expected, ExpectedFile};

#[test]
fn trip_test() {
    util::set_test_root();

    let mut p = test_path(&["trip", "trip"]);

    // An IoProvider for the input file.
    p.set_extension("tex");
    let mut tex = FilesystemPrimaryInputIo::new(&p);

    // And the TFM file.
    p.set_extension("tfm");
    let mut tfm = SingleInputFileIo::new(&p);

    // Read in the expected outputs.
    let expected_log = ExpectedFile::read_with_extension(&mut p, "log");
    let expected_xdv = ExpectedFile::read_with_extension(&mut p, "xdv");
    let expected_fot = ExpectedFile::read_with_extension(&mut p, "fot");
    p.set_file_name("tripos");
    let expected_os = ExpectedFile::read_with_extension(&mut p, "tex");

    // MemoryIo layer that will accept the outputs. Save `files` since the
    // engine consumes `mem`.
    let mut mem = MemoryIo::new(true);

    // First engine pass -- make the format file.
    let res1 = {
        let io = IoStack::new(vec![&mut mem as &mut dyn IoProvider, &mut tex, &mut tfm]);
        let mut hooks = MinimalDriver::new(io);
        let mut status = NoopStatusBackend::default();
        let mut launcher = CoreBridgeLauncher::new(&mut hooks, &mut status);

        TexEngine::default()
            .halt_on_error_mode(false)
            .initex_mode(true)
            .process(&mut launcher, "INITEX", "trip")
    };

    // Second pass -- process it
    let res2 = {
        let io = IoStack::new(vec![&mut mem as &mut dyn IoProvider, &mut tex, &mut tfm]);
        let mut hooks = MinimalDriver::new(io);
        let mut status = NoopStatusBackend::default();
        let mut launcher = CoreBridgeLauncher::new(&mut hooks, &mut status);

        TexEngine::default()
            .halt_on_error_mode(false)
            .initex_mode(false)
            .process(&mut launcher, "trip.fmt", "trip")
    };

    // Check that outputs match expectations.
    let files = &*mem.files.borrow();
    Expected::new()
        .res(Ok(TexOutcome::Errors), res1)
        .res(Ok(TexOutcome::Errors), res2)
        .file(expected_log.collection(files))
        .file(expected_xdv.collection(files))
        .file(expected_os.collection(files))
        .file(expected_fot.data(&files.get("").unwrap().data))
        .finish();
}

#[test]
fn etrip_test() {
    util::set_test_root();

    let mut p = test_path(&["trip", "etrip"]);

    // An IoProvider the input file.
    p.set_extension("tex");
    let mut tex = FilesystemPrimaryInputIo::new(&p);

    // And the TFM file.
    p.set_extension("tfm");
    let mut tfm = SingleInputFileIo::new(&p);

    // Read in the expected outputs.
    let expected_log = ExpectedFile::read_with_extension(&mut p, "log");
    let expected_xdv = ExpectedFile::read_with_extension(&mut p, "xdv");
    let expected_fot = ExpectedFile::read_with_extension(&mut p, "fot");
    let expected_out = ExpectedFile::read_with_extension(&mut p, "out");

    // MemoryIo layer that will accept the outputs. Save `files` since the
    // engine consumes `mem`.
    let mut mem = MemoryIo::new(true);
    let files = mem.files.clone();

    // First engine pass -- make the format file.
    let res1 = {
        let io = IoStack::new(vec![&mut mem as &mut dyn IoProvider, &mut tex, &mut tfm]);
        let mut hooks = MinimalDriver::new(io);
        let mut status = NoopStatusBackend::default();
        let mut launcher = CoreBridgeLauncher::new(&mut hooks, &mut status);

        TexEngine::default()
            .halt_on_error_mode(false)
            .initex_mode(true)
            .process(&mut launcher, "INITEX", "etrip")
    };

    // Second pass -- process it
    let res2 = {
        let io = IoStack::new(vec![&mut mem, &mut tex, &mut tfm]);
        let mut hooks = MinimalDriver::new(io);
        let mut status = NoopStatusBackend::default();
        let mut launcher = CoreBridgeLauncher::new(&mut hooks, &mut status);

        TexEngine::default()
            .halt_on_error_mode(false)
            .initex_mode(false)
            .process(&mut launcher, "etrip.fmt", "etrip")
    };

    // Check that outputs match expectations.
    let files = &*files.borrow();
    Expected::new()
        .res(Ok(TexOutcome::Errors), res1)
        .res(Ok(TexOutcome::Errors), res2)
        .file(expected_log.collection(files))
        .file(expected_xdv.collection(files))
        .file(expected_out.collection(files))
        .file(expected_fot.data(&files.get("").unwrap().data))
        .finish();
}