tinc_build/codegen/cel/functions/
ends_with.rs1use syn::parse_quote;
2use tinc_cel::CelValue;
3
4use super::Function;
5use crate::codegen::cel::compiler::{CompileError, CompiledExpr, CompilerCtx, ConstantCompiledExpr};
6use crate::codegen::cel::types::CelType;
7use crate::types::{ProtoType, ProtoValueType};
8
9#[derive(Debug, Clone, Default)]
10pub(crate) struct EndsWith;
11
12impl Function for EndsWith {
14 fn name(&self) -> &'static str {
15 "endsWith"
16 }
17
18 fn syntax(&self) -> &'static str {
19 "<this>.endsWith(<arg>)"
20 }
21
22 fn compile(&self, ctx: CompilerCtx) -> Result<CompiledExpr, CompileError> {
23 let Some(this) = &ctx.this else {
24 return Err(CompileError::syntax("missing this", self));
25 };
26
27 if ctx.args.len() != 1 {
28 return Err(CompileError::syntax("takes exactly one argument", self));
29 }
30
31 let arg = ctx.resolve(&ctx.args[0])?.into_cel()?;
32 let this = this.clone().into_cel()?;
33
34 match (this, arg) {
35 (
36 CompiledExpr::Constant(ConstantCompiledExpr { value: this }),
37 CompiledExpr::Constant(ConstantCompiledExpr { value: arg }),
38 ) => Ok(CompiledExpr::constant(CelValue::cel_ends_with(this, arg)?)),
39 (this, arg) => Ok(CompiledExpr::runtime(
40 CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
41 parse_quote! {
42 ::tinc::__private::cel::CelValue::cel_ends_with(
43 #this,
44 #arg,
45 )?
46 },
47 )),
48 }
49 }
50}
51
52#[cfg(test)]
53#[cfg(feature = "prost")]
54#[cfg_attr(coverage_nightly, coverage(off))]
55mod tests {
56 use syn::parse_quote;
57 use tinc_cel::CelValue;
58
59 use crate::codegen::cel::compiler::{CompiledExpr, Compiler, CompilerCtx};
60 use crate::codegen::cel::functions::{EndsWith, Function};
61 use crate::codegen::cel::types::CelType;
62 use crate::types::{ProtoType, ProtoTypeRegistry, ProtoValueType};
63
64 #[test]
65 fn test_ends_with_syntax() {
66 let registry = ProtoTypeRegistry::new(crate::Mode::Prost, crate::extern_paths::ExternPaths::new(crate::Mode::Prost));
67 let compiler = Compiler::new(®istry);
68 insta::assert_debug_snapshot!(EndsWith.compile(CompilerCtx::new(compiler.child(), None, &[])), @r#"
69 Err(
70 InvalidSyntax {
71 message: "missing this",
72 syntax: "<this>.endsWith(<arg>)",
73 },
74 )
75 "#);
76
77 insta::assert_debug_snapshot!(EndsWith.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::String("13.2".into()))), &[])), @r#"
78 Err(
79 InvalidSyntax {
80 message: "takes exactly one argument",
81 syntax: "<this>.endsWith(<arg>)",
82 },
83 )
84 "#);
85
86 insta::assert_debug_snapshot!(EndsWith.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant("some string")), &[
87 cel_parser::parse("'ing'").unwrap(), ])), @r"
89 Ok(
90 Constant(
91 ConstantCompiledExpr {
92 value: Bool(
93 true,
94 ),
95 },
96 ),
97 )
98 ");
99 }
100
101 #[test]
102 #[cfg(not(valgrind))]
103 fn test_ends_with_runtime() {
104 let registry = ProtoTypeRegistry::new(crate::Mode::Prost, crate::extern_paths::ExternPaths::new(crate::Mode::Prost));
105 let compiler = Compiler::new(®istry);
106
107 let string_value =
108 CompiledExpr::runtime(CelType::Proto(ProtoType::Value(ProtoValueType::String)), parse_quote!(input));
109
110 let output = EndsWith
111 .compile(CompilerCtx::new(
112 compiler.child(),
113 Some(string_value),
114 &[
115 cel_parser::parse("'ing'").unwrap(), ],
117 ))
118 .unwrap();
119
120 insta::assert_snapshot!(postcompile::compile_str!(
121 postcompile::config! {
122 test: true,
123 dependencies: vec![
124 postcompile::Dependency::version("tinc", "*"),
125 ],
126 },
127 quote::quote! {
128 fn ends_with(input: &str) -> Result<bool, ::tinc::__private::cel::CelError<'_>> {
129 Ok(#output)
130 }
131
132 #[test]
133 fn test_to_double() {
134 assert_eq!(ends_with("testing").unwrap(), true);
135 assert_eq!(ends_with("smile").unwrap(), false);
136 }
137 },
138 ));
139 }
140}