use super::{
MethodError, MethodResult, PsString, RuntimeTypeTrait, StaticFnCallType, Val,
runtime_object::RuntimeResult, val_type::ObjectType,
};
use crate::parser::MethodName;
#[derive(Debug, Clone)]
pub(crate) struct Convert {}
impl RuntimeTypeTrait for Convert {
fn static_method(&self, name: MethodName) -> RuntimeResult<StaticFnCallType> {
match name.name() {
"frombase64string" => Ok(Box::new(from_base_64_string)),
_ => Err(MethodError::MethodNotFound(name.name().into()).into()),
}
}
fn base_type(&self) -> Box<dyn RuntimeTypeTrait> {
Box::new(ObjectType {})
}
fn name(&self) -> String {
"Convert".to_string()
}
fn full_name(&self) -> String {
format!("System.{}", self.name())
}
fn clone_rt(&self) -> Box<dyn RuntimeTypeTrait> {
Box::new(self.clone())
}
}
fn from_base_64_string(args: Vec<Val>) -> MethodResult<Val> {
use base64::prelude::*;
if args.len() != 1 {
return Err(MethodError::new_incorrect_args("FromBase64String", args));
}
let arg = args[0].clone();
let Val::String(PsString(s)) = arg else {
return Err(MethodError::new_incorrect_args("FromBase64String", args));
};
let x = BASE64_STANDARD
.decode(s)
.map_err(|e| MethodError::RuntimeError(e.to_string()))?;
Ok(Val::Array(x.iter().map(|b| Val::Char(*b as u32)).collect()))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{PowerShellSession, PsValue};
#[test]
fn test_from_base64_string() {
let input = "SGVsbG8gV29ybGQh"; let args = vec![Val::String(PsString(input.to_string()))];
let result = from_base_64_string(args).unwrap();
if let Val::Array(arr) = result {
let decoded: String = arr
.iter()
.map(|v| {
if let Val::Char(c) = v {
*c as u8 as char
} else {
'\0'
}
})
.collect();
assert_eq!(decoded, "Hello World!");
} else {
panic!("Expected Val::Array");
}
}
#[test]
fn test_builtint_objects() {
let mut p = PowerShellSession::new();
assert_eq!(
p.parse_script(r#" [system.convert].name "#)
.unwrap()
.result(),
PsValue::String("Convert".into())
);
assert_eq!(
p.parse_script(r#" [system.convert] "#).unwrap().result(),
PsValue::String(
"IsPublic\tIsSerial\tName\tBaseType\n--------\t--------\t----\t--------\n \
true\t true\tConvert\tSystem.Object"
.into()
)
);
let script_res = p.parse_script(r#" [system.convert]0 "#).unwrap();
assert_eq!(script_res.result(), PsValue::Null);
assert_eq!(
script_res.errors()[0].to_string(),
String::from("ValError: Failed to convert value Int32 to type RuntimeObject")
);
}
}