use serde::{Deserialize, Serialize};
use whisker_plugin::{GenerateContext, Operation, Plugin, PluginConfig, Target};
#[derive(Default, Serialize, Deserialize)]
pub struct AndroidPermissionsConfig {
#[serde(default)]
pub permissions: Vec<String>,
}
impl AndroidPermissionsConfig {
pub fn add(&mut self, name: impl Into<String>) -> &mut Self {
self.permissions.push(name.into());
self
}
}
impl PluginConfig for AndroidPermissionsConfig {
const NAME: &'static str = "whisker-android-permissions";
}
pub struct AndroidPermissions;
impl Plugin for AndroidPermissions {
type Config = AndroidPermissionsConfig;
fn apply(
&self,
ctx: &mut GenerateContext,
cfg: &AndroidPermissionsConfig,
) -> anyhow::Result<()> {
let Some(android) = ctx.android.as_mut() else {
return Ok(());
};
if cfg.permissions.is_empty() {
return Ok(());
}
let count = cfg.permissions.len();
android.manifest.permissions.extend(cfg.permissions.clone());
ctx.journal.record(
AndroidPermissionsConfig::NAME,
Target::Android,
"manifest.permissions",
Operation::ArrayPush { count },
);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use whisker_plugin::AndroidProjectIr;
fn ctx_with_android() -> GenerateContext {
GenerateContext {
android: Some(AndroidProjectIr::default()),
..Default::default()
}
}
#[test]
fn default_config_contributes_nothing() {
let mut ctx = ctx_with_android();
AndroidPermissions
.apply(&mut ctx, &AndroidPermissionsConfig::default())
.unwrap();
assert!(ctx.android.unwrap().manifest.permissions.is_empty());
assert!(ctx.journal.records.is_empty());
}
#[test]
fn populated_config_appends_each_permission() {
let mut cfg = AndroidPermissionsConfig::default();
cfg.add("android.permission.CAMERA")
.add("android.permission.RECORD_AUDIO");
let mut ctx = ctx_with_android();
AndroidPermissions.apply(&mut ctx, &cfg).unwrap();
assert_eq!(
ctx.android.unwrap().manifest.permissions,
vec![
"android.permission.CAMERA".to_string(),
"android.permission.RECORD_AUDIO".to_string(),
],
);
}
#[test]
fn one_array_push_event_per_invocation() {
let mut cfg = AndroidPermissionsConfig::default();
cfg.add("a").add("b").add("c");
let mut ctx = ctx_with_android();
AndroidPermissions.apply(&mut ctx, &cfg).unwrap();
assert_eq!(ctx.journal.records.len(), 1);
let r = &ctx.journal.records[0];
assert_eq!(r.plugin, "whisker-android-permissions");
assert_eq!(r.target, Target::Android);
assert!(matches!(r.operation, Operation::ArrayPush { count: 3 }));
}
#[test]
fn no_android_target_means_no_op() {
let mut cfg = AndroidPermissionsConfig::default();
cfg.add("android.permission.CAMERA");
let mut ctx = GenerateContext::default();
AndroidPermissions.apply(&mut ctx, &cfg).unwrap();
assert!(ctx.journal.records.is_empty());
}
}