utf8-locale 1.0.0

Detect a UTF-8-capable locale for running child processes in
Documentation
/*
 * Copyright (c) 2022  Peter Pentchev <roam@ringlet.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#![allow(clippy::panic_in_result_fn)]

use std::collections::HashMap;
use std::fs;
use std::io::Error as IoError;

use anyhow::{anyhow, Context, Result as AnyResult};
use once_cell::sync::Lazy;
use serde::Deserialize;
use serde_json::Error as SerdeJsonError;
use thiserror::Error;

use super::LanguagesDetect;

#[derive(Debug, Error)]
enum TestError {
    #[error("Could not read tests/data.json")]
    FileRead(#[source] IoError),

    #[error("Could not parse tests/data.json")]
    FileParse(#[source] SerdeJsonError),
}

#[derive(Debug, Deserialize)]
struct TDataLang {
    env: HashMap<String, String>,
    expected: Vec<String>,
}

#[derive(Debug, Deserialize)]
struct TData {
    languages: Vec<TDataLang>,
}

fn load_test_data() -> Result<TData, TestError> {
    let contents: String = fs::read_to_string("tests/data.json").map_err(TestError::FileRead)?;
    serde_json::from_str(&contents).map_err(TestError::FileParse)
}

fn get_test_data() -> AnyResult<&'static TData> {
    static TEST_DATA: Lazy<Result<TData, TestError>> = Lazy::new(load_test_data);
    TEST_DATA
        .as_ref()
        .map_err(|err| anyhow!("Could not load the test data: {}", err))
}

#[test]
fn test_preferred() -> AnyResult<()> {
    for tcase in &get_test_data()?.languages {
        assert_eq!(
            LanguagesDetect::new()
                .with_env(tcase.env.clone())
                .detect()
                .with_context(|| format!(
                    "Could not determine the list of preferred languages for {:?}",
                    tcase
                ))?,
            tcase.expected
        );
    }
    Ok(())
}