get_env 0.1.0

Get argv and envp by hook or by crook. This library goes further than the stdlib to get arguments and environment variables, including reading from /proc/self/cmdline and similar.
Documentation
extern crate assert_cmd;
extern crate get_env;
extern crate serde_json;

use std::{collections::HashMap, env, ffi, path, process};

#[test]
fn echo() {
	let echo = assert_cmd::cargo::cargo_example_path("echo").unwrap();
	let echo_no_main = assert_cmd::cargo::cargo_example_path("echo_no_main").unwrap();
	run_echo(&echo, vec![], vec![]);
	run_echo(
		&echo,
		vec!["abc".into()],
		vec![("GET_ENV_LKJHGFDSA".into(), "get_env_asdfghjkl".into())],
	);
	run_echo(
		&echo,
		vec!["abc".into(), "ZA̡͊͠͝LGΌ".into()],
		vec![
			("GET_ENV_LKJHGFDSA".into(), "get_env_asdfghjkl".into()),
			(
				"GET_ENV_ZA̡͊͠͝LGΌ".into(),
				"get_env_ZA̡͊͠͝LGΌ".into(),
			),
		],
	);
	run_echo(&echo_no_main, vec![], vec![]);
	run_echo(
		&echo_no_main,
		vec!["abc".into()],
		vec![("GET_ENV_LKJHGFDSA".into(), "get_env_asdfghjkl".into())],
	);
	run_echo(
		&echo_no_main,
		vec!["abc".into(), "ZA̡͊͠͝LGΌ".into()],
		vec![
			("GET_ENV_LKJHGFDSA".into(), "get_env_asdfghjkl".into()),
			(
				"GET_ENV_ZA̡͊͠͝LGΌ".into(),
				"get_env_ZA̡͊͠͝LGΌ".into(),
			),
		],
	);
}

#[test]
fn same_as_rust() {
	assert!(get_env::args_os().unwrap().into_iter().eq(env::args_os()));
	assert_eq!(
		hash_env(get_env::vars_os().unwrap()),
		hash_env(env::vars_os())
	);
}

fn run_echo(
	echo: &path::PathBuf, args: Vec<ffi::OsString>, vars: Vec<(ffi::OsString, ffi::OsString)>,
) {
	let output = process::Command::new(echo)
		.args(&args)
		.envs(vars.iter().cloned())
		.output()
		.unwrap()
		.stdout;
	let (arg, env): (
		Option<Vec<ffi::OsString>>,
		Option<Vec<(ffi::OsString, ffi::OsString)>>,
	) = serde_json::from_slice(&output).unwrap();
	let (arg, env) = (arg.unwrap(), env.unwrap());
	assert!(arg.iter().skip(1).eq(&args));
	assert_eq!(
		hash_env(env),
		hash_env(env::vars_os().chain(vars.into_iter()))
	);
}

fn hash_env<I: IntoIterator<Item = (ffi::OsString, ffi::OsString)>>(
	env: I,
) -> HashMap<ffi::OsString, ffi::OsString> {
	let mut vars = HashMap::new();
	for (key, val) in env {
		let x = vars.insert(key, val);
		assert!(x.is_none()); // TODO handle collision
	}
	vars
}