use nu_ansi_term::Style;
use uzers::{Users, Groups};
use crate::fs::fields as f;
use crate::output::cell::TextCell;
impl f::Group {
pub fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U) -> TextCell {
let style = self.style(colours, users, false);
match self.lookup_name(users) {
Some(name) => TextCell::paint(style, name),
None => TextCell::paint(style, self.0.to_string()),
}
}
pub fn render_gid<C: Colours, U: Users+Groups>(self, colours: &C, users: &U) -> TextCell {
TextCell::paint(self.style(colours, users, true), self.0.to_string())
}
fn lookup_name<U: Users+Groups>(self, users: &U) -> Option<String> {
users.get_group_by_gid(self.0)
.map(|g| g.name().to_string_lossy().into())
}
fn style<C: Colours, U: Users+Groups>(self, colours: &C, users: &U, gid_column: bool) -> Style {
use uzers::os::unix::GroupExt;
let is_member = users.get_group_by_gid(self.0).is_some_and(|group| {
let group = (*group).clone();
let current_uid = users.get_current_uid();
users.get_user_by_uid(current_uid).is_some_and(|current_user| {
current_user.primary_group_id() == group.gid()
|| group.members().iter().any(|u| u == current_user.name())
})
});
match (gid_column, is_member) {
(false, true) => colours.yours(),
(false, false) => colours.not_yours(),
(true, true) => colours.gid_yours(),
(true, false) => colours.gid_not_yours(),
}
}
}
pub trait Colours {
fn yours(&self) -> Style;
fn not_yours(&self) -> Style;
fn gid_yours(&self) -> Style;
fn gid_not_yours(&self) -> Style;
}
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use super::Colours;
use crate::fs::fields as f;
use crate::output::cell::TextCell;
use uzers::{User, Group};
use uzers::mock::MockUsers;
use uzers::os::unix::GroupExt;
use nu_ansi_term::Color::*;
use nu_ansi_term::Style;
struct TestColours;
impl Colours for TestColours {
fn yours(&self) -> Style { Fixed(80).normal() }
fn not_yours(&self) -> Style { Fixed(81).normal() }
fn gid_yours(&self) -> Style { Fixed(82).normal() }
fn gid_not_yours(&self) -> Style { Fixed(83).normal() }
}
#[test]
fn named() {
let mut users = MockUsers::with_current_uid(1000);
users.add_group(Group::new(100, "folk"));
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
assert_eq!(expected, group.render(&TestColours, &users));
let expected = TextCell::paint_str(Fixed(83).normal(), "100");
assert_eq!(expected, group.render_gid(&TestColours, &users));
}
#[test]
fn unnamed_falls_back_to_gid() {
let users = MockUsers::with_current_uid(1000);
let group = f::Group(100);
let expected_name = TextCell::paint_str(Fixed(81).normal(), "100");
assert_eq!(expected_name, group.render(&TestColours, &users));
let expected_gid = TextCell::paint_str(Fixed(83).normal(), "100");
assert_eq!(expected_gid, group.render_gid(&TestColours, &users));
}
#[test]
fn primary() {
let mut users = MockUsers::with_current_uid(2);
users.add_user(User::new(2, "eve", 100));
users.add_group(Group::new(100, "folk"));
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
assert_eq!(expected, group.render(&TestColours, &users))
}
#[test]
fn secondary() {
let mut users = MockUsers::with_current_uid(2);
users.add_user(User::new(2, "eve", 666));
let test_group = Group::new(100, "folk").add_member("eve");
users.add_group(test_group);
let group = f::Group(100);
let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
assert_eq!(expected, group.render(&TestColours, &users))
}
#[test]
fn overflow() {
let group = f::Group(2_147_483_648);
let expected = TextCell::paint_str(Fixed(83).normal(), "2147483648");
assert_eq!(expected, group.render_gid(&TestColours, &MockUsers::with_current_uid(0)));
}
}