#![cfg(target_os = "linux")]
#[path = "support/os.rs"]
mod os;
use std::{
collections::BTreeMap,
ffi::OsStr,
fs,
path::{Path, PathBuf},
};
fn person(root: &Path) -> BTreeMap<String, String> {
BTreeMap::from([
("PATH".into(), os::path_list([root.join("bin")])),
(
"XDG_DATA_DIRS".into(),
os::path_list([
"/usr/local/share/",
"/usr/share/",
"/var/lib/flatpak/exports/share",
]),
),
("AUTHOR_VARIABLE".into(), "from-the-terminal".into()),
(os::RECORD.into(), text(&root.join("record"))),
])
}
fn bundled(bundle: &Path, person: &BTreeMap<String, String>) -> BTreeMap<String, String> {
let b = text(bundle);
let mut environment = person.clone();
environment.extend(
[
("APPDIR", b.clone()),
("APPIMAGE", format!("{b}.AppImage")),
("ARGV0", "./Artifactize.AppImage".into()),
("OWD", "/home/someone".into()),
("GTK_THEME", "Adwaita:light".into()),
("GTK_DATA_PREFIX", b.clone()),
("GTK_EXE_PREFIX", format!("{b}//usr")),
("GTK_PATH", format!("{b}//usr/lib/gtk-3.0")),
("GIO_MODULE_DIR", format!("{b}//usr/lib/gio/modules")),
(
"GDK_PIXBUF_MODULE_FILE",
format!("{b}//usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"),
),
(
"GSETTINGS_SCHEMA_DIR",
os::path_list([
format!("{b}/usr/share/glib-2.0/schemas/"),
format!("{b}//usr/share/glib-2.0/schemas"),
]),
),
(
"XDG_DATA_DIRS",
prepended(
[
format!("{b}/usr/share/"),
format!("{b}/usr/share"),
"/usr/share".into(),
],
&person["XDG_DATA_DIRS"],
),
),
(
"PATH",
prepended(
[
format!("{b}/usr/bin/"),
format!("{b}/usr/sbin/"),
format!("{b}/bin/"),
],
&person["PATH"],
),
),
(
"LD_LIBRARY_PATH",
os::path_list([format!("{b}/usr/lib/"), format!("{b}/lib/"), String::new()]),
),
(
"PERLLIB",
os::path_list([
format!("{b}/usr/share/perl5/"),
format!("{b}/usr/lib/perl5/"),
String::new(),
]),
),
("PYTHONHOME", format!("{b}/usr/")),
("PYTHONDONTWRITEBYTECODE", "1".into()),
]
.map(|(name, value)| (name.to_owned(), value)),
);
environment
}
fn opened_with(
root: &Path,
program: &Path,
test: &str,
environment: &BTreeMap<String, String>,
) -> BTreeMap<String, String> {
os::rerun_as(program, test, environment);
os::recorded_environment(&root.join("record"))
}
struct Fixture {
root: tempfile::TempDir,
bundle: PathBuf,
inside: PathBuf,
outside: PathBuf,
}
impl Fixture {
fn new() -> Self {
let root = os::tempdir();
let bundle = root.path().join("squashfs-root");
let bin = bundle.join("usr/bin");
fs::create_dir_all(&bin).unwrap();
let inside = bin.join("artifactize-desktop");
os::copy_test_binary(&inside);
let outside = root.path().join("artifactize-desktop");
os::copy_test_binary(&outside);
fs::create_dir(root.path().join("bin")).unwrap();
os::environment_recording_program(&root.path().join("bin"), os::OPENER);
Self {
root,
bundle,
inside,
outside,
}
}
}
fn open_when_rerun() -> bool {
if os::record_path().is_none() {
return false;
}
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(artifactize_tools::opener::open(OsStr::new("notes.md")))
.unwrap();
true
}
#[test]
fn a_program_started_from_inside_an_appimage_gets_the_persons_environment() {
if open_when_rerun() {
return;
}
let fixture = Fixture::new();
let root = fixture.root.path();
let person = person(root);
let received = opened_with(
root,
&fixture.inside,
"a_program_started_from_inside_an_appimage_gets_the_persons_environment",
&bundled(&fixture.bundle, &person),
);
assert_eq!(received, person);
}
#[test]
fn without_an_appimage_a_started_program_gets_the_environment_unchanged() {
if open_when_rerun() {
return;
}
let test = "without_an_appimage_a_started_program_gets_the_environment_unchanged";
let fixture = Fixture::new();
let root = fixture.root.path();
let bundled = bundled(&fixture.bundle, &person(root));
let mut unnamed = bundled.clone();
unnamed.remove("APPDIR");
assert_eq!(opened_with(root, &fixture.inside, test, &unnamed), unnamed);
assert_eq!(opened_with(root, &fixture.outside, test, &bundled), bundled);
}
fn prepended<const N: usize>(entries: [String; N], list: &str) -> String {
os::path_list(
entries
.into_iter()
.map(PathBuf::from)
.chain(std::env::split_paths(list)),
)
}
fn text(path: &Path) -> String {
path.to_str().unwrap().to_owned()
}