use std::sync::OnceLock;
use tera::{Context, Tera};
static REDACTION_TERA: OnceLock<Tera> = OnceLock::new();
const REDACTION_TEMPLATE: &str = "<redacted:{{secret_type}}>";
const TEMPLATE_NAME: &str = "redaction";
pub fn init_redaction_templating() -> Result<(), tera::Error> {
let _tera = REDACTION_TERA.get_or_init(|| {
let mut tera = Tera::default();
let _ = tera.add_raw_template(TEMPLATE_NAME, REDACTION_TEMPLATE);
tera
});
Ok(())
}
fn generate_redacted_string(secret_string: Option<&str>, secret_type: &str) -> String {
generate_redacted_string_with_length(secret_string, secret_type, None)
}
fn generate_redacted_string_with_length(
secret_string: Option<&str>,
secret_type: &str,
secret_length: Option<usize>,
) -> String {
let template = REDACTION_TEMPLATE.to_string();
let mut tera = Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
if tera.add_raw_template(TEMPLATE_NAME, &template).is_err() {
return format!("<redacted:{}>", secret_type);
}
let mut context = Context::new();
context.insert("secret_type", secret_type);
if let Some(secret_str) = secret_string {
context.insert("secret_string", secret_str);
}
if let Some(length) = secret_length {
context.insert("secret_length", &length);
}
tera.render(TEMPLATE_NAME, &context)
.unwrap_or_else(|_| format!("<redacted:{}>", secret_type))
}
pub fn get_cached_redacted_string(secret_string: Option<&str>, secret_type: &str) -> String {
generate_redacted_string(secret_string, secret_type)
}
pub fn get_cached_redacted_string_with_length(
secret_string: Option<&str>,
secret_type: &str,
secret_length: Option<usize>,
) -> String {
generate_redacted_string_with_length(secret_string, secret_type, secret_length)
}
pub fn get_redacted_string_with_value<T: std::fmt::Display + ?Sized>(
secret_type: &str,
_context: crate::config::RedactionContext,
actual_value: Option<&T>,
) -> String {
let secret_length = actual_value.map(|v| v.to_string().len());
if let Some(value) = actual_value {
let value_str = value.to_string();
get_cached_redacted_string_with_length(Some(&value_str), secret_type, secret_length)
} else {
get_cached_redacted_string_with_length(None, secret_type, secret_length)
}
}
pub fn get_redacted_string_with_length(secret_type: &str, secret_length: Option<usize>) -> String {
get_cached_redacted_string_with_length(None, secret_type, secret_length)
}
pub fn generate_redacted_string_with_custom_template(
custom_template: &str,
secret_type: &str,
secret_length: Option<usize>,
) -> String {
generate_redacted_string_with_custom_template_and_value(
custom_template,
secret_type,
secret_length,
None,
)
}
pub fn generate_redacted_string_with_custom_template_and_value(
custom_template: &str,
secret_type: &str,
secret_length: Option<usize>,
secret_value: Option<String>,
) -> String {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
let effective_secret_value = secret_value;
if tera
.add_raw_template(TEMPLATE_NAME, custom_template)
.is_err()
{
return format!("<redacted:{}>", secret_type);
}
let mut context = tera::Context::new();
context.insert("secret_type", secret_type);
if let Some(length) = secret_length {
context.insert("secret_length", &length);
}
if let Some(value) = &effective_secret_value {
context.insert("secret_string", value);
}
tera.render(TEMPLATE_NAME, &context)
.unwrap_or_else(|_| format!("<redacted:{}>", secret_type))
}
pub fn get_redacted_string_with_custom_template_and_value<T: std::fmt::Display + ?Sized>(
custom_template: &str,
secret_type: &str,
_context: crate::config::RedactionContext,
actual_value: Option<&T>,
) -> String {
let (secret_length, secret_string_value) = if let Some(value) = actual_value {
let string_value = value.to_string();
(Some(string_value.len()), Some(string_value))
} else {
(None, None)
};
generate_redacted_string_with_custom_template_and_value(
custom_template,
secret_type,
secret_length,
secret_string_value,
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_redaction_template_initialization() {
let result = init_redaction_templating();
assert!(
result.is_ok(),
"Failed to initialize Tera templating: {:?}",
result
);
}
#[test]
fn test_tera_template_rendering() {
assert_eq!(
super::generate_redacted_string(None, "string"),
"<redacted:string>"
);
assert_eq!(
super::generate_redacted_string(None, "float"),
"<redacted:float>"
);
assert_eq!(
super::generate_redacted_string(None, "custom_type"),
"<redacted:custom_type>"
);
}
#[test]
fn test_redacted_string_format() {
assert_eq!(
get_cached_redacted_string(None, "string"),
"<redacted:string>"
);
assert_eq!(
get_cached_redacted_string(None, "float"),
"<redacted:float>"
);
assert_eq!(
get_cached_redacted_string(None, "custom_type"),
"<redacted:custom_type>"
);
}
#[test]
fn test_cached_redacted_strings() {
assert_eq!(
get_cached_redacted_string(None, "string"),
"<redacted:string>"
);
assert_eq!(get_cached_redacted_string(None, "int"), "<redacted:int>");
assert_eq!(
get_cached_redacted_string(None, "unusual_type"),
"<redacted:unusual_type>"
);
}
#[test]
fn test_configurable_template_usage() {
use crate::config::PluginConfig;
let mut config = PluginConfig::default();
config.redaction.redaction_template = Some("[SECRET:{{secret_type}}]".to_string());
assert_eq!(
config.redaction.get_redaction_template(),
"[SECRET:{{secret_type}}]"
);
let default_config = PluginConfig::default();
assert_eq!(
default_config.redaction.get_redaction_template(),
"<redacted:{{secret_type}}>"
);
}
#[test]
fn test_template_rendering_formats() {
let mut tera = tera::Tera::default();
let mut context = tera::Context::new();
context.insert("secret_type", "string");
tera.add_raw_template("default", "<redacted:{{secret_type}}>")
.unwrap();
assert_eq!(
tera.render("default", &context).unwrap(),
"<redacted:string>"
);
tera.add_raw_template("custom", "[HIDDEN:{{secret_type}}]")
.unwrap();
assert_eq!(tera.render("custom", &context).unwrap(), "[HIDDEN:string]");
tera.add_raw_template("simple", "{{secret_type}}_redacted")
.unwrap();
assert_eq!(tera.render("simple", &context).unwrap(), "string_redacted");
}
#[test]
fn test_redacted_string_with_value() {
use crate::config::RedactionContext;
let result =
get_redacted_string_with_value("string", RedactionContext::Display, Some(&"secret"));
assert_eq!(result, "<redacted:string>");
let result = get_redacted_string_with_value("int", RedactionContext::Display, Some(&42));
assert_eq!(result, "<redacted:int>");
let result = get_redacted_string_with_value(
"float",
RedactionContext::Display,
Some(&std::f64::consts::PI),
);
assert_eq!(result, "<redacted:float>");
let result = get_redacted_string_with_value("bool", RedactionContext::Display, Some(&true));
assert_eq!(result, "<redacted:bool>");
}
#[test]
fn test_redacted_string_with_length() {
let result = get_redacted_string_with_length("string", Some(10));
assert_eq!(result, "<redacted:string>");
let result = get_redacted_string_with_length("string", None);
assert_eq!(result, "<redacted:string>");
}
#[test]
fn test_template_with_secret_length() {
let mut tera = tera::Tera::default();
tera.add_raw_template("length_test", "{{secret_type}}({{secret_length}})")
.unwrap();
let mut context = tera::Context::new();
context.insert("secret_type", "password");
context.insert("secret_length", &8);
let result = tera.render("length_test", &context).unwrap();
assert_eq!(result, "password(8)");
}
#[test]
fn test_replicate_function() {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
tera.add_raw_template("replicate_test", "{{replicate(s='*', n=5)}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("replicate_test", &context).unwrap();
assert_eq!(result, "*****");
}
#[test]
fn test_replicate_function_different_characters() {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
tera.add_raw_template("replicate_x", "{{replicate(s='X', n=3)}}")
.unwrap();
tera.add_raw_template("replicate_dash", "{{replicate(s='-', n=7)}}")
.unwrap();
tera.add_raw_template("replicate_dot", "{{replicate(s='.', n=4)}}")
.unwrap();
let context = tera::Context::new();
assert_eq!(tera.render("replicate_x", &context).unwrap(), "XXX");
assert_eq!(tera.render("replicate_dash", &context).unwrap(), "-------");
assert_eq!(tera.render("replicate_dot", &context).unwrap(), "....");
}
#[test]
fn test_replicate_function_negative_length() {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
tera.add_raw_template("replicate_negative", "{{replicate(s='*', n=-1)}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("replicate_negative", &context).unwrap();
assert_eq!(result, "");
}
#[test]
fn test_replicate_function_zero_length() {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
tera.add_raw_template("replicate_zero", "{{replicate(s='*', n=0)}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("replicate_zero", &context).unwrap();
assert_eq!(result, "");
}
#[test]
fn test_template_with_length_and_replicate() {
let mut tera = tera::Tera::default();
crate::tera_functions::register_all_standard_functions(&mut tera);
tera.add_raw_template(
"complex",
"<{{secret_type}}:{{replicate(s='*', n=secret_length)}}>",
)
.unwrap();
let mut context = tera::Context::new();
context.insert("secret_type", "password");
context.insert("secret_length", &8);
let result = tera.render("complex", &context).unwrap();
assert_eq!(result, "<password:********>");
}
#[test]
fn test_redacted_string_with_value_includes_length() {
use crate::config::RedactionContext;
let test_value = "secret123";
let result =
get_redacted_string_with_value("string", RedactionContext::Display, Some(&test_value));
assert_eq!(result, "<redacted:string>");
}
#[test]
fn test_generate_redacted_string_with_custom_template() {
let result = generate_redacted_string_with_custom_template(
"[HIDDEN:{{secret_type}}]",
"password",
None,
);
assert_eq!(result, "[HIDDEN:password]");
let result = generate_redacted_string_with_custom_template(
"{{secret_type}}({{secret_length}})",
"password",
Some(8),
);
assert_eq!(result, "password(8)");
let result = generate_redacted_string_with_custom_template(
"{{replicate(s='*', n=5)}}",
"secret",
None,
);
assert_eq!(result, "*****");
}
#[test]
fn test_get_redacted_string_with_custom_template_and_value() {
use crate::config::RedactionContext;
let result = get_redacted_string_with_custom_template_and_value(
"[SECRET:{{secret_type}}]",
"password",
RedactionContext::Display,
Some(&"test123"),
);
assert_eq!(result, "[SECRET:password]");
let result = get_redacted_string_with_custom_template_and_value(
"{{replicate(s='*', n=secret_length)}}",
"password",
RedactionContext::Display,
Some(&"test123"),
);
assert_eq!(result, "*******");
let result = get_redacted_string_with_custom_template_and_value(
"moo:{{secret_string}}",
"string",
RedactionContext::Display,
Some(&"abcdf"),
);
assert_eq!(result, "moo:abcdf");
let result = get_redacted_string_with_custom_template_and_value(
"simple_test",
"string",
RedactionContext::Display,
Some(&"abcdf"),
);
assert_eq!(result, "simple_test");
}
#[test]
fn test_reverse_function() {
let result =
generate_redacted_string_with_custom_template("{{reverse(s='hello')}}", "test", None);
assert_eq!(result, "olleh");
let result =
generate_redacted_string_with_custom_template("{{reverse(s='world')}}", "test", None);
assert_eq!(result, "dlrow");
let result =
generate_redacted_string_with_custom_template("{{reverse(s='')}}", "test", None);
assert_eq!(result, "");
let result =
generate_redacted_string_with_custom_template("{{reverse(s='🚀🎉')}}", "test", None);
assert_eq!(result, "🎉🚀");
}
#[test]
fn test_reverse_function_error_handling() {
let result =
generate_redacted_string_with_custom_template("{{reverse()}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template(
"{{reverse(s=nonexistent_var)}}",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
}
#[test]
fn test_take_function() {
let result = generate_redacted_string_with_custom_template(
"{{take(n=3, s='hello world')}}",
"test",
None,
);
assert_eq!(result, "hel");
let result = generate_redacted_string_with_custom_template(
"{{take(n=5, s='testing')}}",
"test",
None,
);
assert_eq!(result, "testi");
let result = generate_redacted_string_with_custom_template(
"{{take(n=10, s='short')}}",
"test",
None,
);
assert_eq!(result, "short");
let result = generate_redacted_string_with_custom_template(
"{{take(n=0, s='anything')}}",
"test",
None,
);
assert_eq!(result, "");
let result =
generate_redacted_string_with_custom_template("{{take(n=-1, s='test')}}", "test", None);
assert_eq!(result, "");
let result = generate_redacted_string_with_custom_template(
"{{take(n=2, s='🚀🎉🌟⭐')}}",
"test",
None,
);
assert_eq!(result, "🚀🎉");
let result =
generate_redacted_string_with_custom_template("{{take(n=5, s='')}}", "test", None);
assert_eq!(result, "");
}
#[test]
fn test_take_function_error_handling() {
let result =
generate_redacted_string_with_custom_template("{{take(s='test')}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result =
generate_redacted_string_with_custom_template("{{take(n=5)}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template("{{take()}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
}
#[test]
fn test_secret_string_variable() {
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_string}}",
"test",
None,
Some("secret_value".to_string()),
);
assert_eq!(result, "secret_value");
let result = generate_redacted_string_with_custom_template_and_value(
"prefix:{{secret_string}}:suffix",
"test",
None,
Some("middle".to_string()),
);
assert_eq!(result, "prefix:middle:suffix");
let result =
generate_redacted_string_with_custom_template("{{secret_string}}", "test", None);
assert_eq!(result, "<redacted:test>");
let result = generate_redacted_string_with_custom_template_and_value(
"value:{{secret_string}}",
"test",
None,
None,
);
assert_eq!(result, "<redacted:test>");
}
#[test]
fn test_template_error_fallback_handling() {
let result = generate_redacted_string_with_custom_template(
"{{invalid syntax without closing",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template(
"{{undefined_variable}}",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template(
"{{nonexistent_function()}}",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
}
#[test]
fn test_replicate_function_error_handling() {
let result =
generate_redacted_string_with_custom_template("{{replicate(n=5)}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template(
"{{replicate(s='*')}}",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
let result =
generate_redacted_string_with_custom_template("{{replicate()}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result =
generate_redacted_string_with_custom_template("{{replicate(s='', n=3)}}", "test", None);
assert_eq!(result, "");
}
#[test]
fn test_complex_template_combinations() {
let result = generate_redacted_string_with_custom_template_and_value(
"[{{replicate(s='-', n=secret_length)}}]",
"secret",
Some(4), Some("test".to_string()),
);
assert_eq!(result, "[----]");
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_type}}:{{secret_length}}",
"complex",
Some(6), Some("abcdef".to_string()),
);
assert_eq!(result, "complex:6");
let result = generate_redacted_string_with_custom_template_and_value(
"value={{secret_string}}",
"test",
None,
Some("secret123".to_string()),
);
assert_eq!(result, "value=secret123");
let result = generate_redacted_string_with_custom_template_and_value(
"{{reverse(s=secret_string)}}",
"test",
None,
Some("hello".to_string()),
);
assert_eq!(result, "olleh");
let result = generate_redacted_string_with_custom_template_and_value(
"{{take(n=3, s=secret_string)}}",
"test",
None,
Some("abcdef".to_string()),
);
assert_eq!(result, "abc");
}
#[test]
fn test_secret_string_integration_with_none() {
let result = generate_redacted_string_with_length(None, "test", None);
assert_eq!(result, "<redacted:test>");
let result =
generate_redacted_string_with_custom_template("value:{{secret_string}}", "test", None);
assert_eq!(result, "<redacted:test>");
let result =
generate_redacted_string_with_custom_template("{{secret_string}}", "test", None);
assert_eq!(result, "<redacted:test>");
}
#[test]
fn test_secret_string_integration_with_some() {
let result = generate_redacted_string_with_length(Some("mysecret"), "test", None);
assert_eq!(result, "<redacted:test>");
let result = generate_redacted_string_with_custom_template_and_value(
"value:{{secret_string}}",
"test",
None,
Some("mysecret".to_string()),
);
assert_eq!(result, "value:mysecret");
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_string}}",
"test",
None,
Some("direct_access".to_string()),
);
assert_eq!(result, "direct_access");
}
#[test]
fn test_secret_string_cached_functions_integration() {
let result = get_cached_redacted_string(None, "string");
assert_eq!(result, "<redacted:string>");
let result = get_cached_redacted_string(Some("secret"), "string");
assert_eq!(result, "<redacted:string>");
let result = get_cached_redacted_string_with_length(None, "string", Some(8));
assert_eq!(result, "<redacted:string>");
let result = get_cached_redacted_string_with_length(Some("mysecret"), "string", Some(8));
assert_eq!(result, "<redacted:string>");
}
#[test]
fn test_strlen_function() {
let result =
generate_redacted_string_with_custom_template("{{strlen(s='hello')}}", "test", None);
assert_eq!(result, "5");
let result =
generate_redacted_string_with_custom_template("{{strlen(s='world!')}}", "test", None);
assert_eq!(result, "6");
let result =
generate_redacted_string_with_custom_template("{{strlen(s='')}}", "test", None);
assert_eq!(result, "0");
let result =
generate_redacted_string_with_custom_template("{{strlen(s='🚀🎉🌟')}}", "test", None);
assert_eq!(result, "3");
let result =
generate_redacted_string_with_custom_template("{{strlen(s='café')}}", "test", None);
assert_eq!(result, "4");
let result =
generate_redacted_string_with_custom_template("{{strlen(s='testing')}}", "test", None);
assert_eq!(result, "7");
let result = generate_redacted_string_with_custom_template(
"{{strlen(s='This is a longer test string!')}}",
"test",
None,
);
assert_eq!(result, "29");
}
#[test]
fn test_strlen_function_error_handling() {
let result =
generate_redacted_string_with_custom_template("{{strlen()}}", "test_type", None);
assert_eq!(result, "<redacted:test_type>");
let result = generate_redacted_string_with_custom_template(
"{{strlen(s=nonexistent_var)}}",
"test_type",
None,
);
assert_eq!(result, "<redacted:test_type>");
}
#[test]
fn test_strlen_function_with_template_variables() {
let result = generate_redacted_string_with_custom_template_and_value(
"{{strlen(s=secret_string)}}",
"test",
None,
Some("secret123".to_string()),
);
assert_eq!(result, "9");
let result = generate_redacted_string_with_custom_template_and_value(
"Length: {{strlen(s=secret_string)}}, First 3: {{take(n=3, s=secret_string)}}",
"test",
None,
Some("password".to_string()),
);
assert_eq!(result, "Length: 8, First 3: pas");
let result = generate_redacted_string_with_custom_template(
"{{strlen(s=reverse(s='hello'))}}",
"test",
None,
);
assert_eq!(result, "5"); }
#[test]
fn test_strlen_function_complex_templates() {
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_type}}[{{strlen(s=secret_string)}}]: {{replicate(s='*', n=strlen(s=secret_string))}}",
"password",
None,
Some("test123".to_string()),
);
assert_eq!(result, "password[7]: *******");
let result = generate_redacted_string_with_custom_template_and_value(
"Original: {{strlen(s=secret_string)}}, Reversed: {{strlen(s=reverse(s=secret_string))}}",
"test",
None,
Some("hello".to_string()),
);
assert_eq!(result, "Original: 5, Reversed: 5");
}
#[test]
fn test_mask_secret_functionality() {
let test_secret = "password123";
let expected_mask = "*".repeat(test_secret.len());
assert_eq!(expected_mask, "***********");
let short_secret = "abc";
let short_mask = "*".repeat(short_secret.len());
assert_eq!(short_mask, "***");
let long_secret = "this_is_a_very_long_secret_string";
let long_mask = "*".repeat(long_secret.len());
assert_eq!(long_mask, "*".repeat(33));
let empty_secret = "";
let empty_mask = "*".repeat(empty_secret.len());
assert_eq!(empty_mask, "");
let binary_repr = "[1, 2]";
let binary_mask = "*".repeat(binary_repr.len());
assert_eq!(binary_mask, "******");
let number_repr = "42";
let number_mask = "*".repeat(number_repr.len());
assert_eq!(number_mask, "**");
}
#[test]
fn test_mask_secret_config_structure() {
use crate::config::PluginConfig;
let mut config = PluginConfig::default();
assert!(!config.redaction.mask_secret);
config.redaction.mask_secret = true;
assert!(config.redaction.mask_secret);
config.redaction.show_unredacted = true;
config.redaction.redaction_template = Some("custom_template".to_string());
assert!(config.redaction.mask_secret);
assert!(config.redaction.show_unredacted);
assert_eq!(
config.redaction.redaction_template,
Some("custom_template".to_string())
);
}
#[test]
fn test_secret_string_template_context_integration() {
let result = generate_redacted_string_with_custom_template_and_value(
"prefix_{{secret_string}}_suffix",
"test",
None,
Some("middle".to_string()),
);
assert_eq!(result, "prefix_middle_suffix");
let result = generate_redacted_string_with_custom_template(
"prefix_{{secret_string}}_suffix",
"test",
None,
);
assert_eq!(result, "<redacted:test>");
}
#[test]
fn test_secret_string_with_other_template_variables() {
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_type}}:{{secret_string}}",
"password",
None,
Some("secret123".to_string()),
);
assert_eq!(result, "password:secret123");
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_string}}({{secret_length}})",
"password",
Some(9),
Some("secret123".to_string()),
);
assert_eq!(result, "secret123(9)");
let result = generate_redacted_string_with_custom_template_and_value(
"{{secret_type}}:{{secret_string}}:{{secret_length}}",
"token",
Some(10),
Some("abcdef1234".to_string()),
);
assert_eq!(result, "token:abcdef1234:10");
}
#[test]
fn test_secret_string_function_registration_conditional() {
let mut tera = tera::Tera::default();
let secret_value = "test_secret";
let captured_secret = secret_value.to_string();
tera.register_function(
"secret_string",
move |_args: &std::collections::HashMap<String, tera::Value>| -> tera::Result<tera::Value> {
Ok(tera::Value::String(captured_secret.clone()))
},
);
tera.add_raw_template("test", "func:{{secret_string()}}")
.unwrap();
let context = tera::Context::new();
let result = tera.render("test", &context).unwrap();
assert_eq!(result, "func:test_secret");
let mut tera2 = tera::Tera::default();
tera2
.add_raw_template("test2", "func:{{secret_string()}}")
.unwrap();
let context2 = tera::Context::new();
let result2 = tera2.render("test2", &context2);
assert!(result2.is_err()); }
}