use std::collections::HashSet;
use std::sync::{Mutex, OnceLock};
pub const LIST_SEP: &str = ", ";
pub fn generic_keys() -> &'static HashSet<&'static str> {
static S: OnceLock<HashSet<&'static str>> = OnceLock::new();
S.get_or_init(|| {
let mut s = HashSet::new();
s.insert("exclude_modes");
s.insert("include_modes");
s.insert("exclude_function");
s.insert("include_function");
s.insert("width");
s.insert("align");
s.insert("name");
s.insert("draw_soft_divider");
s.insert("draw_hard_divider");
s.insert("priority");
s.insert("after");
s.insert("before");
s.insert("display");
s
})
}
pub fn type_keys() -> &'static std::collections::HashMap<&'static str, HashSet<&'static str>> {
static M: OnceLock<std::collections::HashMap<&'static str, HashSet<&'static str>>> =
OnceLock::new();
M.get_or_init(|| {
let mut m = std::collections::HashMap::new();
let mut function_keys = HashSet::new();
function_keys.insert("function");
function_keys.insert("args");
function_keys.insert("draw_inner_divider");
m.insert("function", function_keys);
let mut string_keys = HashSet::new();
string_keys.insert("contents");
string_keys.insert("type");
string_keys.insert("highlight_groups");
string_keys.insert("divider_highlight_group");
m.insert("string", string_keys);
let mut segment_list_keys = HashSet::new();
segment_list_keys.insert("function");
segment_list_keys.insert("segments");
segment_list_keys.insert("args");
segment_list_keys.insert("type");
m.insert("segment_list", segment_list_keys);
m
})
}
pub fn required_keys() -> &'static std::collections::HashMap<&'static str, HashSet<&'static str>> {
static M: OnceLock<std::collections::HashMap<&'static str, HashSet<&'static str>>> =
OnceLock::new();
M.get_or_init(|| {
let mut m = std::collections::HashMap::new();
let mut function_req = HashSet::new();
function_req.insert("function");
m.insert("function", function_req);
m.insert("string", HashSet::new());
let mut segment_list_req = HashSet::new();
segment_list_req.insert("function");
segment_list_req.insert("segments");
m.insert("segment_list", segment_list_req);
m
})
}
pub fn highlight_keys() -> &'static HashSet<&'static str> {
static S: OnceLock<HashSet<&'static str>> = OnceLock::new();
S.get_or_init(|| {
let mut s = HashSet::new();
s.insert("highlight_groups");
s.insert("name");
s
})
}
pub fn get_function_strings(function_name: &str, default_module: &str) -> (String, String) {
if let Some(dot_idx) = function_name.rfind('.') {
let (module, rest) = function_name.split_at(dot_idx);
let function = &rest[1..];
(module.to_string(), function.to_string())
} else {
(default_module.to_string(), function_name.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LintResult {
pub proceed: bool,
pub echo: bool,
pub hadproblem: bool,
}
impl LintResult {
pub fn ok() -> Self {
Self {
proceed: true,
echo: false,
hadproblem: false,
}
}
pub fn failed() -> Self {
Self {
proceed: false,
echo: true,
hadproblem: true,
}
}
pub fn warned() -> Self {
Self {
proceed: true,
echo: true,
hadproblem: true,
}
}
}
pub fn common_names() -> &'static Mutex<std::collections::HashMap<String, HashSet<(String, String)>>>
{
static M: OnceLock<Mutex<std::collections::HashMap<String, HashSet<(String, String)>>>> =
OnceLock::new();
M.get_or_init(|| Mutex::new(std::collections::HashMap::new()))
}
pub fn register_common_name(
name: impl Into<String>,
cmodule: impl Into<String>,
cname: impl Into<String>,
) {
let mut map = common_names().lock().unwrap_or_else(|e| e.into_inner());
map.entry(name.into())
.or_default()
.insert((cmodule.into(), cname.into()));
}
pub fn check_log_file_level(this_level: &str, top_level: &str) -> LintResult {
let log_levels: std::collections::HashMap<&str, i32> = [
("CRITICAL", 50),
("ERROR", 40),
("WARNING", 30),
("INFO", 20),
("DEBUG", 10),
("NOTSET", 0),
]
.into_iter()
.collect();
let top_val = match log_levels.get(top_level) {
Some(v) => *v,
None => return LintResult::ok(),
};
let this_val = match log_levels.get(this_level) {
Some(v) => *v,
None => return LintResult::ok(),
};
if this_val < top_val {
LintResult::warned()
} else {
LintResult::ok()
}
}
pub fn check_logging_handler(handler_name: &str) -> LintResult {
let known_handlers: HashSet<&str> = [
"StreamHandler",
"FileHandler",
"NullHandler",
"WatchedFileHandler",
"BaseRotatingHandler",
"RotatingFileHandler",
"TimedRotatingFileHandler",
"SocketHandler",
"DatagramHandler",
"SysLogHandler",
"SMTPHandler",
"NTEventLogHandler",
"HTTPHandler",
"BufferingHandler",
"MemoryHandler",
"QueueHandler",
"QueueListener",
]
.into_iter()
.collect();
if known_handlers.contains(handler_name) {
LintResult::ok()
} else {
LintResult::failed()
}
}
pub fn check_full_segment_data(segment: &serde_json::Map<String, serde_json::Value>) -> LintResult {
if !segment.contains_key("name") && !segment.contains_key("function") {
return LintResult::ok();
}
LintResult::ok()
}
pub fn check_segment_function(_function_name: &str) -> LintResult {
LintResult::ok()
}
pub fn check_segment_data_key(_key: &str) -> LintResult {
LintResult::ok()
}
pub fn check_args_variant(_args: &serde_json::Map<String, serde_json::Value>) -> LintResult {
LintResult::ok()
}
pub fn check_args(_args: &serde_json::Map<String, serde_json::Value>) -> LintResult {
LintResult::ok()
}
pub fn check_color(color: &str) -> LintResult {
if color.is_empty() || color.contains(char::is_whitespace) {
LintResult::failed()
} else {
LintResult::ok()
}
}
pub fn check_hl_group_name(hl_group: &str) -> LintResult {
if hl_group.is_empty() {
return LintResult::failed();
}
let first = hl_group.chars().next().unwrap();
if !first.is_ascii_alphabetic() && first != '_' {
return LintResult::failed();
}
for c in hl_group.chars().skip(1) {
if !c.is_ascii_alphanumeric() && c != '_' && c != ':' {
return LintResult::failed();
}
}
LintResult::ok()
}
pub fn check_ext(
ext: &str,
available_exts: &HashSet<&str>,
has_themes_for_ext: bool,
has_colorschemes_for_ext: bool,
has_top_themes: bool,
has_top_colorschemes: bool,
) -> (bool, bool) {
if !available_exts.contains(ext) {
return (false, true);
}
let mut hadsomedirs = false;
let mut hadproblem = false;
if !has_themes_for_ext && !has_top_themes {
hadproblem = true;
} else {
hadsomedirs = true;
}
if !has_colorschemes_for_ext && !has_top_colorschemes {
hadproblem = true;
} else {
hadsomedirs = true;
}
(hadsomedirs, hadproblem)
}
pub fn check_config(
d: &str,
theme: &str,
ext: &str,
available_exts: &HashSet<&str>,
has_theme_for_ext: bool,
has_top_theme: bool,
) -> LintResult {
if !available_exts.contains(ext) {
return LintResult::warned();
}
let _ = (d, theme);
if has_theme_for_ext || has_top_theme {
LintResult::ok()
} else {
LintResult {
proceed: true,
echo: false,
hadproblem: true,
}
}
}
pub fn check_top_theme(theme: &str, top_themes: &HashSet<&str>) -> LintResult {
if top_themes.contains(theme) {
LintResult::ok()
} else {
LintResult {
proceed: true,
echo: false,
hadproblem: true,
}
}
}
pub fn check_translated_group_name(group: &str, defined_groups: &HashSet<&str>) -> LintResult {
check_group(group, defined_groups)
}
pub fn check_group(group: &str, defined_groups: &HashSet<&str>) -> LintResult {
if defined_groups.contains(group) {
LintResult::ok()
} else {
LintResult {
proceed: true,
echo: false,
hadproblem: true,
}
}
}
pub fn check_key_compatibility(segment_keys: &HashSet<&str>, segment_type: &str) -> LintResult {
let tk = match type_keys().get(segment_type) {
Some(s) => s,
None => {
return LintResult {
proceed: false,
echo: false,
hadproblem: true,
}
}
};
let mut hadproblem = false;
let gk = generic_keys();
for k in segment_keys.iter() {
if !gk.contains(k) && !tk.contains(k) {
hadproblem = true;
break;
}
}
if let Some(rk) = required_keys().get(segment_type) {
for k in rk.iter() {
if !segment_keys.contains(k) {
hadproblem = true;
break;
}
}
}
if segment_type != "function" {
let hk = highlight_keys();
let mut has_hl = false;
for k in segment_keys.iter() {
if hk.contains(k) {
has_hl = true;
break;
}
}
if !has_hl {
hadproblem = true;
}
}
LintResult {
proceed: true,
echo: false,
hadproblem,
}
}
pub fn check_segment_module(module: &str, is_importable: impl Fn(&str) -> bool) -> LintResult {
if is_importable(module) {
LintResult::ok()
} else {
LintResult {
proceed: true,
echo: false,
hadproblem: true,
}
}
}
pub fn check_exinclude_function(name: &str, ext: &str) -> (String, String) {
let (module, function) = match name.rfind('.') {
Some(idx) => (name[..idx].to_string(), name[idx + 1..].to_string()),
None => (String::new(), name.to_string()),
};
let module = if module.is_empty() {
format!("powerline.selectors.{}", ext)
} else {
module
};
(module, function)
}
pub fn get_one_segment_function(
function_name: Option<&str>,
ext: &str,
) -> Option<(String, String)> {
let function_name = function_name?;
let default_module = format!("powerline.segments.{}", ext);
Some(get_function_strings(function_name, &default_module))
}
pub fn check_matcher_func(ext: &str, match_name: &str) -> (String, String) {
match match_name.rfind('.') {
Some(idx) => (
match_name[..idx].to_string(),
match_name[idx + 1..].to_string(),
),
None => (
format!("powerline.matchers.{}", ext),
match_name.to_string(),
),
}
}
pub fn check_highlight_group(hl_group: &str, available_groups: &HashSet<&str>) -> LintResult {
if available_groups.contains(hl_group) {
LintResult::ok()
} else {
LintResult {
proceed: true,
echo: false,
hadproblem: true,
}
}
}
pub fn check_highlight_groups(hl_groups: &[&str], available_groups: &HashSet<&str>) -> LintResult {
let mut hadproblem = false;
for hl in hl_groups {
if !available_groups.contains(hl) {
hadproblem = true;
break;
}
}
LintResult {
proceed: true,
echo: false,
hadproblem,
}
}
pub fn listed_key(
d: &serde_json::Map<String, serde_json::Value>,
k: &str,
) -> Vec<serde_json::Value> {
match d.get(k) {
Some(v) => vec![v.clone()],
None => Vec::new(),
}
}
pub fn hl_group_in_colorscheme(
hl_group: &str,
groups: &HashSet<&str>,
colors: &HashSet<&str>,
gradients: &HashSet<&str>,
group_fg: Option<&str>,
group_bg: Option<&str>,
allow_gradients: AllowGradients,
) -> bool {
if !groups.contains(hl_group) {
return false;
}
if matches!(allow_gradients, AllowGradients::Yes) {
return true;
}
let mut hadgradient = false;
for color in [group_fg, group_bg].into_iter().flatten() {
let hascolor = colors.contains(color);
let hasgradient = gradients.contains(color);
if hasgradient {
hadgradient = true;
}
if matches!(allow_gradients, AllowGradients::No) && !hascolor && hasgradient {
return false;
}
}
if matches!(allow_gradients, AllowGradients::Force) && !hadgradient {
return false;
}
true
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AllowGradients {
No,
Yes,
Force,
}
pub fn hl_exists(hl_group: &str, colorscheme_membership: &[(String, bool)]) -> Vec<String> {
if colorscheme_membership.is_empty() {
return Vec::new();
}
let _ = hl_group;
let mut r: Vec<String> = Vec::new();
let mut found = false;
for (name, present) in colorscheme_membership {
if *present {
found = true;
} else {
r.push(name.clone());
}
}
let _ = found;
r
}
pub fn get_all_possible_functions(name: &str) -> Vec<(String, String)> {
let (module, fname) = match name.rfind('.') {
Some(idx) => (name[..idx].to_string(), name[idx + 1..].to_string()),
None => (String::new(), name.to_string()),
};
let mut out: Vec<(String, String)> = Vec::new();
if !module.is_empty() {
out.push((module, fname));
return out;
}
let map = common_names().lock().unwrap_or_else(|e| e.into_inner());
if let Some(entries) = map.get(&fname) {
for (cmodule, cname) in entries {
out.push((cmodule.clone(), cname.clone()));
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
static TEST_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
macro_rules! lock_globals {
() => {{
TEST_LOCK
.get_or_init(|| Mutex::new(()))
.lock()
.unwrap_or_else(|e| e.into_inner())
}};
}
fn reset_common_names() {
let mut map = common_names().lock().unwrap_or_else(|e| e.into_inner());
map.clear();
}
#[test]
fn list_sep_matches_upstream() {
assert_eq!(LIST_SEP, ", ");
}
#[test]
fn generic_keys_has_13_entries() {
let g = generic_keys();
assert_eq!(g.len(), 13);
assert!(g.contains("exclude_modes"));
assert!(g.contains("priority"));
assert!(g.contains("display"));
}
#[test]
fn type_keys_function_includes_args() {
let t = type_keys();
let function_keys = t.get("function").unwrap();
assert!(function_keys.contains("function"));
assert!(function_keys.contains("args"));
assert!(function_keys.contains("draw_inner_divider"));
}
#[test]
fn type_keys_string_includes_contents() {
let t = type_keys();
let string_keys = t.get("string").unwrap();
assert!(string_keys.contains("contents"));
assert!(string_keys.contains("highlight_groups"));
assert!(string_keys.contains("divider_highlight_group"));
}
#[test]
fn type_keys_segment_list_includes_segments() {
let t = type_keys();
let sl_keys = t.get("segment_list").unwrap();
assert!(sl_keys.contains("function"));
assert!(sl_keys.contains("segments"));
}
#[test]
fn required_keys_function_requires_function() {
let r = required_keys();
let fn_req = r.get("function").unwrap();
assert!(fn_req.contains("function"));
assert_eq!(fn_req.len(), 1);
}
#[test]
fn required_keys_string_has_no_required() {
let r = required_keys();
let str_req = r.get("string").unwrap();
assert!(str_req.is_empty());
}
#[test]
fn required_keys_segment_list_requires_function_and_segments() {
let r = required_keys();
let sl_req = r.get("segment_list").unwrap();
assert!(sl_req.contains("function"));
assert!(sl_req.contains("segments"));
assert_eq!(sl_req.len(), 2);
}
#[test]
fn highlight_keys_contains_highlight_groups_and_name() {
let h = highlight_keys();
assert!(h.contains("highlight_groups"));
assert!(h.contains("name"));
}
#[test]
fn get_function_strings_dotted_name_splits() {
let (m, f) = get_function_strings("foo.bar.baz", "powerline.segments.shell");
assert_eq!(m, "foo.bar");
assert_eq!(f, "baz");
}
#[test]
fn get_function_strings_undotted_uses_default_module() {
let (m, f) = get_function_strings("plain", "powerline.segments.shell");
assert_eq!(m, "powerline.segments.shell");
assert_eq!(f, "plain");
}
#[test]
fn lint_result_ok_is_proceed_true_no_echo_no_problem() {
let r = LintResult::ok();
assert!(r.proceed);
assert!(!r.echo);
assert!(!r.hadproblem);
}
#[test]
fn lint_result_failed_is_proceed_false_echo_true_problem() {
let r = LintResult::failed();
assert!(!r.proceed);
assert!(r.echo);
assert!(r.hadproblem);
}
#[test]
fn lint_result_warned_proceeds_but_echoes_problem() {
let r = LintResult::warned();
assert!(r.proceed);
assert!(r.echo);
assert!(r.hadproblem);
}
#[test]
fn register_common_name_inserts_into_registry() {
let _g = lock_globals!();
reset_common_names();
register_common_name("uptime", "powerline.segments.common.sys", "uptime");
let map = common_names().lock().unwrap_or_else(|e| e.into_inner());
assert!(map.contains_key("uptime"));
let entries = map.get("uptime").unwrap();
assert_eq!(entries.len(), 1);
let pair = entries.iter().next().unwrap();
assert_eq!(pair.0, "powerline.segments.common.sys");
assert_eq!(pair.1, "uptime");
}
#[test]
fn register_common_name_dedupes_duplicates() {
let _g = lock_globals!();
reset_common_names();
register_common_name("x", "a", "b");
register_common_name("x", "a", "b");
let map = common_names().lock().unwrap_or_else(|e| e.into_inner());
let entries = map.get("x").unwrap();
assert_eq!(entries.len(), 1);
}
#[test]
fn register_common_name_supports_multiple_aliases() {
let _g = lock_globals!();
reset_common_names();
register_common_name("x", "mod1", "fn_a");
register_common_name("x", "mod2", "fn_b");
let map = common_names().lock().unwrap_or_else(|e| e.into_inner());
let entries = map.get("x").unwrap();
assert_eq!(entries.len(), 2);
}
#[test]
fn check_log_file_level_below_top_warns() {
let r = check_log_file_level("DEBUG", "WARNING");
assert!(r.hadproblem);
assert!(r.proceed);
}
#[test]
fn check_log_file_level_at_or_above_top_is_ok() {
let r = check_log_file_level("ERROR", "WARNING");
assert!(!r.hadproblem);
let r = check_log_file_level("WARNING", "WARNING");
assert!(!r.hadproblem);
}
#[test]
fn check_log_file_level_invalid_level_is_ok() {
let r = check_log_file_level("BOGUS", "WARNING");
assert!(!r.hadproblem);
let r = check_log_file_level("DEBUG", "BOGUS");
assert!(!r.hadproblem);
}
#[test]
fn check_logging_handler_known_handler_is_ok() {
let r = check_logging_handler("StreamHandler");
assert!(r.proceed);
assert!(!r.hadproblem);
}
#[test]
fn check_logging_handler_unknown_handler_fails() {
let r = check_logging_handler("BogusHandler");
assert!(r.hadproblem);
}
#[test]
fn check_color_accepts_simple_name() {
let r = check_color("solarized_red");
assert!(!r.hadproblem);
}
#[test]
fn check_color_rejects_empty() {
let r = check_color("");
assert!(r.hadproblem);
}
#[test]
fn check_color_rejects_whitespace() {
let r = check_color("red blue");
assert!(r.hadproblem);
let r = check_color("red\t");
assert!(r.hadproblem);
}
#[test]
fn check_hl_group_name_accepts_identifier() {
let r = check_hl_group_name("branch_clean");
assert!(!r.hadproblem);
}
#[test]
fn check_hl_group_name_accepts_colon() {
let r = check_hl_group_name("workspace:focused");
assert!(!r.hadproblem);
}
#[test]
fn check_hl_group_name_rejects_empty() {
let r = check_hl_group_name("");
assert!(r.hadproblem);
}
#[test]
fn check_hl_group_name_rejects_leading_digit() {
let r = check_hl_group_name("123foo");
assert!(r.hadproblem);
}
#[test]
fn check_hl_group_name_accepts_underscore_prefix() {
let r = check_hl_group_name("_private");
assert!(!r.hadproblem);
}
#[test]
fn check_ext_known_ext_with_themes_is_ok() {
let exts: HashSet<&str> = ["shell", "tmux", "vim"].into_iter().collect();
let (had_dirs, had_problem) = check_ext("shell", &exts, true, true, false, false);
assert!(had_dirs);
assert!(!had_problem);
}
#[test]
fn check_ext_unknown_ext_returns_problem() {
let exts: HashSet<&str> = ["shell"].into_iter().collect();
let (had_dirs, had_problem) = check_ext("bogus", &exts, false, false, false, false);
assert!(!had_dirs);
assert!(had_problem);
}
#[test]
fn check_ext_falls_back_to_top_themes() {
let exts: HashSet<&str> = ["shell"].into_iter().collect();
let (had_dirs, _) = check_ext("shell", &exts, false, false, true, true);
assert!(had_dirs);
}
#[test]
fn check_config_known_ext_with_theme_ok() {
let exts: HashSet<&str> = ["shell"].into_iter().collect();
let r = check_config("themes", "default", "shell", &exts, true, false);
assert!(!r.hadproblem);
}
#[test]
fn check_config_unknown_ext_warns() {
let exts: HashSet<&str> = ["shell"].into_iter().collect();
let r = check_config("themes", "default", "bogus", &exts, false, false);
assert!(r.hadproblem);
}
#[test]
fn check_config_missing_theme_emits_problem() {
let exts: HashSet<&str> = ["shell"].into_iter().collect();
let r = check_config("themes", "missing", "shell", &exts, false, false);
assert!(r.hadproblem);
}
#[test]
fn check_top_theme_known_theme_is_ok() {
let themes: HashSet<&str> = ["default", "tmux"].into_iter().collect();
let r = check_top_theme("default", &themes);
assert!(!r.hadproblem);
}
#[test]
fn check_top_theme_unknown_theme_has_problem() {
let themes: HashSet<&str> = ["default"].into_iter().collect();
let r = check_top_theme("bogus", &themes);
assert!(r.hadproblem);
}
#[test]
fn check_group_known_group_is_ok() {
let groups: HashSet<&str> = ["branch", "background"].into_iter().collect();
let r = check_group("branch", &groups);
assert!(!r.hadproblem);
}
#[test]
fn check_group_unknown_group_has_problem() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let r = check_group("nonexistent", &groups);
assert!(r.hadproblem);
}
#[test]
fn check_translated_group_name_delegates_to_check_group() {
let groups: HashSet<&str> = ["foo"].into_iter().collect();
let r1 = check_translated_group_name("foo", &groups);
let r2 = check_group("foo", &groups);
assert_eq!(r1, r2);
}
#[test]
fn check_key_compatibility_function_segment_with_valid_keys() {
let keys: HashSet<&str> = ["function", "args", "name", "priority"]
.into_iter()
.collect();
let r = check_key_compatibility(&keys, "function");
assert!(!r.hadproblem);
}
#[test]
fn check_key_compatibility_string_segment_requires_highlight() {
let keys: HashSet<&str> = ["contents"].into_iter().collect();
let r = check_key_compatibility(&keys, "string");
assert!(r.hadproblem);
}
#[test]
fn check_key_compatibility_string_segment_with_name_ok() {
let keys: HashSet<&str> = ["contents", "name"].into_iter().collect();
let r = check_key_compatibility(&keys, "string");
assert!(!r.hadproblem);
}
#[test]
fn check_key_compatibility_function_missing_function_key() {
let keys: HashSet<&str> = ["args"].into_iter().collect();
let r = check_key_compatibility(&keys, "function");
assert!(r.hadproblem);
}
#[test]
fn check_key_compatibility_unknown_segment_type_fails() {
let keys: HashSet<&str> = ["function"].into_iter().collect();
let r = check_key_compatibility(&keys, "bogus_type");
assert!(!r.proceed);
assert!(r.hadproblem);
}
#[test]
fn check_key_compatibility_unknown_key_emits_problem() {
let keys: HashSet<&str> = ["function", "bogus_key"].into_iter().collect();
let r = check_key_compatibility(&keys, "function");
assert!(r.hadproblem);
}
#[test]
fn check_segment_module_importable_is_ok() {
let r = check_segment_module("powerline.segments.shell", |_| true);
assert!(!r.hadproblem);
}
#[test]
fn check_segment_module_unimportable_has_problem() {
let r = check_segment_module("definitely.not.a.real.module", |_| false);
assert!(r.hadproblem);
}
#[test]
fn check_exinclude_function_dotted_name_splits() {
let (m, n) = check_exinclude_function("powerline.selectors.vim.in_help", "vim");
assert_eq!(m, "powerline.selectors.vim");
assert_eq!(n, "in_help");
}
#[test]
fn check_exinclude_function_undotted_defaults_module() {
let (m, n) = check_exinclude_function("in_help", "vim");
assert_eq!(m, "powerline.selectors.vim");
assert_eq!(n, "in_help");
}
#[test]
fn get_one_segment_function_returns_pair_when_set() {
let r = get_one_segment_function(Some("powerline.segments.shell.uptime"), "shell");
assert_eq!(
r,
Some(("powerline.segments.shell".to_string(), "uptime".to_string()))
);
}
#[test]
fn get_one_segment_function_returns_none_when_unset() {
assert_eq!(get_one_segment_function(None, "shell"), None);
}
#[test]
fn get_one_segment_function_undotted_defaults_module() {
let r = get_one_segment_function(Some("uptime"), "shell");
assert_eq!(
r,
Some(("powerline.segments.shell".to_string(), "uptime".to_string()))
);
}
#[test]
fn check_matcher_func_dotted_name_splits() {
let (m, n) = check_matcher_func("vim", "powerline.matchers.vim.help");
assert_eq!(m, "powerline.matchers.vim");
assert_eq!(n, "help");
}
#[test]
fn check_matcher_func_undotted_defaults_module() {
let (m, n) = check_matcher_func("vim", "help");
assert_eq!(m, "powerline.matchers.vim");
assert_eq!(n, "help");
}
#[test]
fn check_highlight_group_known_group_ok() {
let groups: HashSet<&str> = ["background", "branch"].into_iter().collect();
let r = check_highlight_group("background", &groups);
assert!(!r.hadproblem);
}
#[test]
fn check_highlight_group_unknown_group_has_problem() {
let groups: HashSet<&str> = ["background"].into_iter().collect();
let r = check_highlight_group("nonexistent", &groups);
assert!(r.hadproblem);
}
#[test]
fn check_highlight_groups_all_known_is_ok() {
let groups: HashSet<&str> = ["a", "b", "c"].into_iter().collect();
let r = check_highlight_groups(&["a", "b"], &groups);
assert!(!r.hadproblem);
}
#[test]
fn check_highlight_groups_any_missing_has_problem() {
let groups: HashSet<&str> = ["a"].into_iter().collect();
let r = check_highlight_groups(&["a", "b"], &groups);
assert!(r.hadproblem);
}
#[test]
fn hl_group_in_colorscheme_missing_group_returns_false() {
let groups: HashSet<&str> = HashSet::new();
let colors: HashSet<&str> = HashSet::new();
let gradients: HashSet<&str> = HashSet::new();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
None,
None,
AllowGradients::Yes,
);
assert!(!r);
}
#[test]
fn hl_group_in_colorscheme_allow_gradients_yes_returns_true_if_present() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let colors: HashSet<&str> = HashSet::new();
let gradients: HashSet<&str> = HashSet::new();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
None,
None,
AllowGradients::Yes,
);
assert!(r);
}
#[test]
fn hl_group_in_colorscheme_no_gradients_with_gradient_color_fails() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let colors: HashSet<&str> = HashSet::new();
let gradients: HashSet<&str> = ["my_gradient"].into_iter().collect();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
Some("my_gradient"),
None,
AllowGradients::No,
);
assert!(!r);
}
#[test]
fn hl_group_in_colorscheme_no_gradients_with_real_color_passes() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let colors: HashSet<&str> = ["solarized_red"].into_iter().collect();
let gradients: HashSet<&str> = HashSet::new();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
Some("solarized_red"),
Some("solarized_red"),
AllowGradients::No,
);
assert!(r);
}
#[test]
fn hl_group_in_colorscheme_force_gradient_without_gradient_fails() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let colors: HashSet<&str> = ["red"].into_iter().collect();
let gradients: HashSet<&str> = HashSet::new();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
Some("red"),
Some("red"),
AllowGradients::Force,
);
assert!(!r);
}
#[test]
fn hl_group_in_colorscheme_force_gradient_with_gradient_passes() {
let groups: HashSet<&str> = ["branch"].into_iter().collect();
let colors: HashSet<&str> = HashSet::new();
let gradients: HashSet<&str> = ["my_gradient"].into_iter().collect();
let r = hl_group_in_colorscheme(
"branch",
&groups,
&colors,
&gradients,
Some("my_gradient"),
None,
AllowGradients::Force,
);
assert!(r);
}
#[test]
fn hl_exists_empty_input_returns_empty() {
let r = hl_exists("branch", &[]);
assert!(r.is_empty());
}
#[test]
fn hl_exists_returns_list_of_missing_colorschemes() {
let cs = vec![
("default".to_string(), true),
("solarized".to_string(), false),
("monokai".to_string(), false),
];
let r = hl_exists("branch", &cs);
assert_eq!(r.len(), 2);
assert!(r.contains(&"solarized".to_string()));
assert!(r.contains(&"monokai".to_string()));
}
#[test]
fn hl_exists_all_present_returns_empty() {
let cs = vec![
("default".to_string(), true),
("solarized".to_string(), true),
];
let r = hl_exists("branch", &cs);
assert!(r.is_empty());
}
#[test]
fn get_all_possible_functions_dotted_name_yields_module_function_pair() {
let r = get_all_possible_functions("powerline.segments.shell.uptime");
assert_eq!(r.len(), 1);
assert_eq!(r[0].0, "powerline.segments.shell");
assert_eq!(r[0].1, "uptime");
}
#[test]
fn get_all_possible_functions_undotted_walks_common_names() {
let _g = lock_globals!();
reset_common_names();
register_common_name("uptime", "powerline.segments.common.sys", "uptime_impl");
let r = get_all_possible_functions("uptime");
assert!(!r.is_empty());
let pair = r
.iter()
.find(|(m, n)| m == "powerline.segments.common.sys" && n == "uptime_impl");
assert!(pair.is_some());
}
#[test]
fn get_all_possible_functions_undotted_unknown_returns_empty() {
let _g = lock_globals!();
reset_common_names();
let r = get_all_possible_functions("nonexistent_segment");
assert!(r.is_empty());
}
#[test]
fn check_full_segment_data_empty_segment_returns_ok() {
let seg = serde_json::Map::new();
let r = check_full_segment_data(&seg);
assert!(!r.hadproblem);
}
#[test]
fn check_full_segment_data_with_name_returns_ok() {
let mut seg = serde_json::Map::new();
seg.insert("name".into(), serde_json::json!("powerline_test"));
let r = check_full_segment_data(&seg);
assert!(!r.hadproblem);
}
#[test]
fn check_segment_function_returns_ok() {
let r = check_segment_function("powerline.segments.common.time.fuzzy_time");
assert!(!r.hadproblem);
}
#[test]
fn check_segment_data_key_returns_ok() {
let r = check_segment_data_key("hostname");
assert!(!r.hadproblem);
}
#[test]
fn check_args_variant_returns_ok() {
let r = check_args_variant(&serde_json::Map::new());
assert!(!r.hadproblem);
}
#[test]
fn check_args_returns_ok() {
let mut args = serde_json::Map::new();
args.insert("interval".into(), serde_json::json!(60.0));
let r = check_args(&args);
assert!(!r.hadproblem);
}
}