1use std::collections::HashMap;
7use std::fmt;
8use std::sync::Arc;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum AbbrevError {
13 Conflict {
15 short_name: String,
16 existing: String,
17 new: String,
18 },
19 InvalidName(String),
21}
22
23impl fmt::Display for AbbrevError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 AbbrevError::Conflict {
27 short_name,
28 existing,
29 new,
30 } => {
31 write!(
32 f,
33 "abbreviation conflict: '{}' already maps to '{}', cannot map to '{}'",
34 short_name, existing, new
35 )
36 }
37 AbbrevError::InvalidName(name) => {
38 write!(f, "invalid qualified name: '{}'", name)
39 }
40 }
41 }
42}
43
44impl std::error::Error for AbbrevError {}
45
46#[derive(Debug, Clone, Default)]
65pub struct Abbreviations {
66 map: HashMap<String, String>, }
68
69impl Abbreviations {
70 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn with_abbreviation(mut self, qualified_name: &str) -> Result<Self, AbbrevError> {
91 if qualified_name.is_empty() {
92 return Err(AbbrevError::InvalidName(qualified_name.to_string()));
93 }
94
95 let short_name = qualified_name
96 .rsplit('.')
97 .next()
98 .unwrap_or(qualified_name)
99 .to_string();
100
101 if short_name.is_empty() {
102 return Err(AbbrevError::InvalidName(qualified_name.to_string()));
103 }
104
105 if let Some(existing) = self.map.get(&short_name) {
106 if existing != qualified_name {
107 return Err(AbbrevError::Conflict {
108 short_name,
109 existing: existing.clone(),
110 new: qualified_name.to_string(),
111 });
112 }
113 } else {
115 self.map.insert(short_name, qualified_name.to_string());
116 }
117
118 Ok(self)
119 }
120
121 pub fn from_qualified_names(names: &[&str]) -> Result<Self, AbbrevError> {
134 let mut abbrevs = Self::new();
135 for name in names {
136 abbrevs = abbrevs.with_abbreviation(name)?;
137 }
138 Ok(abbrevs)
139 }
140
141 pub fn as_map(&self) -> &HashMap<String, String> {
143 &self.map
144 }
145
146 pub fn resolve(&self, short_name: &str) -> Option<&str> {
150 self.map.get(short_name).map(|s| s.as_str())
151 }
152
153 pub fn is_empty(&self) -> bool {
155 self.map.is_empty()
156 }
157
158 pub fn len(&self) -> usize {
160 self.map.len()
161 }
162}
163
164use crate::ast::Ast;
165use crate::checker::{
166 check, check_with_abbreviations, check_with_type_resolver,
167 check_with_type_resolver_and_abbreviations, CheckError, CheckResult, STANDARD_LIBRARY,
168};
169use crate::eval::{Function, FunctionRegistry, Overload, Program, ProtoRegistry};
170use crate::ext;
171use crate::parser::{self, ParseError, ParseResult};
172use crate::types::{CelType, FunctionDecl, SpannedExpr};
173
174#[derive(Debug, Clone)]
176pub enum CompileError {
177 Parse(Vec<ParseError>),
179 Check(Vec<CheckError>),
181 NoAst,
183}
184
185impl std::fmt::Display for CompileError {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 match self {
188 CompileError::Parse(errors) => {
189 write!(f, "parse errors: ")?;
190 for (i, e) in errors.iter().enumerate() {
191 if i > 0 {
192 write!(f, "; ")?;
193 }
194 write!(f, "{}", e.message)?;
195 }
196 Ok(())
197 }
198 CompileError::Check(errors) => {
199 write!(f, "check errors: ")?;
200 for (i, e) in errors.iter().enumerate() {
201 if i > 0 {
202 write!(f, "; ")?;
203 }
204 write!(f, "{}", e.message())?;
205 }
206 Ok(())
207 }
208 CompileError::NoAst => write!(f, "no AST produced"),
209 }
210 }
211}
212
213impl std::error::Error for CompileError {}
214
215#[derive(Debug, Clone)]
237pub struct Env {
238 variables: HashMap<String, CelType>,
240 functions: HashMap<String, FunctionDecl>,
242 container: String,
244 proto_registry: Option<Arc<dyn ProtoRegistry>>,
246 abbreviations: Abbreviations,
248 strong_enums: bool,
251}
252
253impl Env {
254 pub fn new() -> Self {
259 Self {
260 variables: HashMap::new(),
261 functions: HashMap::new(),
262 container: String::new(),
263 proto_registry: None,
264 abbreviations: Abbreviations::new(),
265 strong_enums: true,
266 }
267 }
268
269 pub fn with_standard_library() -> Self {
273 let mut env = Self::new();
274
275 for func in STANDARD_LIBRARY.iter() {
277 env.functions.insert(func.name.clone(), func.clone());
278 }
279
280 env.add_type_constant("bool", CelType::Bool);
282 env.add_type_constant("int", CelType::Int);
283 env.add_type_constant("uint", CelType::UInt);
284 env.add_type_constant("double", CelType::Double);
285 env.add_type_constant("string", CelType::String);
286 env.add_type_constant("bytes", CelType::Bytes);
287 env.add_type_constant("list", CelType::list(CelType::Dyn));
288 env.add_type_constant("map", CelType::map(CelType::Dyn, CelType::Dyn));
289 env.add_type_constant("null_type", CelType::Null);
290 env.add_type_constant("type", CelType::type_of(CelType::Dyn));
291 env.add_type_constant("dyn", CelType::Dyn);
292
293 env
294 }
295
296 fn add_type_constant(&mut self, name: &str, cel_type: CelType) {
298 self.variables
299 .insert(name.to_string(), CelType::type_of(cel_type));
300 }
301
302 pub fn with_variable(mut self, name: impl Into<String>, cel_type: CelType) -> Self {
315 self.variables.insert(name.into(), cel_type);
316 self
317 }
318
319 pub fn add_variable(&mut self, name: impl Into<String>, cel_type: CelType) {
321 self.variables.insert(name.into(), cel_type);
322 }
323
324 pub fn with_function(mut self, decl: FunctionDecl) -> Self {
326 self.add_function(decl);
327 self
328 }
329
330 pub fn add_function(&mut self, decl: FunctionDecl) {
334 if let Some(existing) = self.functions.get_mut(&decl.name) {
335 existing.overloads.extend(decl.overloads);
337 } else {
338 self.functions.insert(decl.name.clone(), decl);
339 }
340 }
341
342 pub fn with_container(mut self, container: impl Into<String>) -> Self {
346 self.container = container.into();
347 self
348 }
349
350 pub fn set_container(&mut self, container: impl Into<String>) {
352 self.container = container.into();
353 }
354
355 pub fn container(&self) -> &str {
357 &self.container
358 }
359
360 pub fn with_proto_registry(mut self, registry: Arc<dyn ProtoRegistry>) -> Self {
366 self.proto_registry = Some(registry);
367 self
368 }
369
370 pub fn proto_registry(&self) -> Option<&dyn ProtoRegistry> {
372 self.proto_registry.as_ref().map(|r| r.as_ref())
373 }
374
375 pub fn with_abbreviations(mut self, abbreviations: Abbreviations) -> Self {
393 self.abbreviations = abbreviations;
394 self
395 }
396
397 pub fn abbreviations(&self) -> &Abbreviations {
399 &self.abbreviations
400 }
401
402 pub fn with_legacy_enums(mut self) -> Self {
408 self.strong_enums = false;
409 self
410 }
411
412 pub fn strong_enums(&self) -> bool {
414 self.strong_enums
415 }
416
417 pub fn with_extension(mut self, extension: impl IntoIterator<Item = FunctionDecl>) -> Self {
432 for decl in extension {
433 self.add_function(decl);
434 }
435 self
436 }
437
438 pub fn with_all_extensions(mut self) -> Self {
455 self = self
456 .with_extension(ext::string_extension())
457 .with_extension(ext::math_extension())
458 .with_extension(ext::encoders_extension())
459 .with_extension(ext::optionals_extension());
460
461 self.add_type_constant("optional_type", CelType::optional(CelType::Dyn));
463
464 self
465 }
466
467 pub fn variables(&self) -> &HashMap<String, CelType> {
469 &self.variables
470 }
471
472 pub fn functions(&self) -> &HashMap<String, FunctionDecl> {
474 &self.functions
475 }
476
477 pub fn methods_for_type(&self, receiver: &CelType) -> Vec<(&str, &crate::types::OverloadDecl)> {
483 let mut results = Vec::new();
484 for func in self.functions.values() {
485 if !func.has_member_overloads() {
486 continue;
487 }
488 for overload in &func.overloads {
489 if !overload.is_member {
490 continue;
491 }
492 if let Some(recv_type) = overload.receiver_type() {
493 if type_compatible_for_completion(recv_type, receiver) {
494 results.push((func.name.as_str(), overload));
495 break; }
497 }
498 }
499 }
500 results
501 }
502
503 pub fn standalone_functions(&self) -> Vec<&str> {
508 self.functions
509 .values()
510 .filter(|f| {
511 f.has_standalone_overloads() && !f.name.starts_with('_') && !f.name.contains('@')
512 })
513 .map(|f| f.name.as_str())
514 .collect()
515 }
516
517 pub fn parse(&self, source: &str) -> ParseResult {
522 parser::parse(source)
523 }
524
525 pub fn check(&self, expr: &SpannedExpr) -> CheckResult {
530 let has_proto_registry = self.proto_registry.is_some();
531 let has_abbreviations = !self.abbreviations.is_empty();
532
533 match (has_proto_registry, has_abbreviations) {
534 (true, true) => check_with_type_resolver_and_abbreviations(
535 expr,
536 &self.variables,
537 &self.functions,
538 &self.container,
539 self.proto_registry.as_ref().unwrap().as_ref(),
540 self.abbreviations.as_map(),
541 ),
542 (true, false) => check_with_type_resolver(
543 expr,
544 &self.variables,
545 &self.functions,
546 &self.container,
547 self.proto_registry.as_ref().unwrap().as_ref(),
548 ),
549 (false, true) => check_with_abbreviations(
550 expr,
551 &self.variables,
552 &self.functions,
553 &self.container,
554 self.abbreviations.as_map(),
555 ),
556 (false, false) => check(expr, &self.variables, &self.functions, &self.container),
557 }
558 }
559
560 pub fn compile(&self, source: &str) -> Result<Ast, CompileError> {
579 let parse_result = self.parse(source);
580
581 if !parse_result.errors.is_empty() {
582 return Err(CompileError::Parse(parse_result.errors));
583 }
584
585 let expr = parse_result.ast.ok_or(CompileError::NoAst)?;
586 let check_result = self.check(&expr);
587
588 if !check_result.errors.is_empty() {
589 return Err(CompileError::Check(check_result.errors));
590 }
591
592 Ok(Ast::new_checked(expr, source, check_result))
593 }
594
595 pub fn parse_only(&self, source: &str) -> Result<Ast, CompileError> {
612 let parse_result = self.parse(source);
613
614 if !parse_result.errors.is_empty() {
615 return Err(CompileError::Parse(parse_result.errors));
616 }
617
618 let expr = parse_result.ast.ok_or(CompileError::NoAst)?;
619 Ok(Ast::new_unchecked(expr, source))
620 }
621
622 pub fn program(&self, ast: &Ast) -> Result<Program, CompileError> {
646 let registry = self.build_function_registry();
647 let has_proto_registry = self.proto_registry.is_some();
648 let has_abbreviations = !self.abbreviations.is_empty();
649
650 let mut program = match (has_proto_registry, has_abbreviations) {
651 (true, true) => Program::with_proto_registry_and_abbreviations(
652 Arc::new(ast.clone()),
653 Arc::new(registry),
654 Arc::clone(self.proto_registry.as_ref().unwrap()),
655 self.abbreviations.as_map().clone(),
656 ),
657 (true, false) => Program::with_proto_registry(
658 Arc::new(ast.clone()),
659 Arc::new(registry),
660 Arc::clone(self.proto_registry.as_ref().unwrap()),
661 ),
662 (false, true) => Program::with_abbreviations(
663 Arc::new(ast.clone()),
664 Arc::new(registry),
665 self.abbreviations.as_map().clone(),
666 ),
667 (false, false) => Program::new(Arc::new(ast.clone()), Arc::new(registry)),
668 };
669
670 if !self.strong_enums {
671 program = program.with_legacy_enums();
672 }
673
674 Ok(program)
675 }
676
677 fn build_function_registry(&self) -> FunctionRegistry {
679 let mut registry = FunctionRegistry::new();
680
681 for func_decl in self.functions.values() {
682 let mut function = Function::new(&func_decl.name);
683
684 for overload_decl in &func_decl.overloads {
685 if let Some(ref impl_fn) = overload_decl.implementation {
687 let overload = Overload::new(
688 &overload_decl.id,
689 overload_decl.is_member,
690 overload_decl.params.len(),
691 impl_fn.clone(),
692 );
693 function = function.with_overload(overload);
694 }
695 }
696
697 if !function.overloads.is_empty() {
699 registry.register(function);
700 }
701 }
702
703 registry
704 }
705}
706
707fn type_compatible_for_completion(declared: &CelType, concrete: &CelType) -> bool {
713 if declared.is_assignable_from(concrete) {
715 return true;
716 }
717 match (declared, concrete) {
718 (CelType::TypeParam(_), _) | (_, CelType::TypeParam(_)) => true,
720 (CelType::List(d), CelType::List(c)) => type_compatible_for_completion(d, c),
722 (CelType::Map(dk, dv), CelType::Map(ck, cv)) => {
724 type_compatible_for_completion(dk, ck) && type_compatible_for_completion(dv, cv)
725 }
726 (CelType::Optional(d), CelType::Optional(c)) => type_compatible_for_completion(d, c),
728 _ => false,
729 }
730}
731
732impl Default for Env {
733 fn default() -> Self {
734 Self::new()
735 }
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741 use crate::checker::CheckErrorKind;
742 use crate::types::OverloadDecl;
743
744 #[test]
745 fn test_new_env() {
746 let env = Env::new();
747 assert!(env.variables().is_empty());
748 assert!(env.functions().is_empty());
749 }
750
751 #[test]
752 fn test_with_standard_library() {
753 let env = Env::with_standard_library();
754
755 assert!(env.functions().contains_key("_+_"));
757 assert!(env.functions().contains_key("size"));
758 assert!(env.functions().contains_key("contains"));
759
760 assert!(env.variables().contains_key("bool"));
762 assert!(env.variables().contains_key("int"));
763 }
764
765 #[test]
766 fn test_with_variable() {
767 let env = Env::with_standard_library().with_variable("x", CelType::Int);
768
769 assert!(env.variables().contains_key("x"));
770 assert_eq!(env.variables().get("x"), Some(&CelType::Int));
771 }
772
773 #[test]
774 fn test_parse() {
775 let env = Env::new();
776 let result = env.parse("1 + 2");
777
778 assert!(result.ast.is_some());
779 assert!(result.errors.is_empty());
780 }
781
782 #[test]
783 fn test_check() {
784 let env = Env::with_standard_library().with_variable("x", CelType::Int);
785
786 let parse_result = env.parse("x + 1");
787 let ast = parse_result.ast.unwrap();
788
789 let check_result = env.check(&ast);
790 assert!(check_result.is_ok());
791 }
792
793 #[test]
794 fn test_check_undefined_variable() {
795 let env = Env::with_standard_library();
796
797 let parse_result = env.parse("x + 1");
798 let ast = parse_result.ast.unwrap();
799
800 let check_result = env.check(&ast);
801 assert!(!check_result.is_ok());
802 assert!(check_result.errors.iter().any(|e| matches!(
803 &e.kind,
804 CheckErrorKind::UndeclaredReference { name, .. } if name == "x"
805 )));
806 }
807
808 #[test]
809 fn test_compile_success() {
810 let env = Env::with_standard_library().with_variable("x", CelType::Int);
811
812 let ast = env.compile("x + 1").unwrap();
813 assert!(ast.is_checked());
814 }
815
816 #[test]
817 fn test_compile_parse_error() {
818 let env = Env::with_standard_library();
819
820 let result = env.compile("1 +");
821 assert!(result.is_err());
822 }
823
824 #[test]
825 fn test_container() {
826 let env = Env::with_standard_library().with_container("google.protobuf");
827
828 assert_eq!(env.container(), "google.protobuf");
829 }
830
831 #[test]
832 fn test_add_function() {
833 let mut env = Env::new();
834
835 let func = FunctionDecl::new("custom").with_overload(OverloadDecl::function(
836 "custom_int",
837 vec![CelType::Int],
838 CelType::Bool,
839 ));
840
841 env.add_function(func);
842
843 assert!(env.functions().contains_key("custom"));
844 }
845
846 #[test]
847 fn test_with_extension() {
848 let env = Env::with_standard_library().with_extension(ext::string_extension());
849
850 assert!(env.functions().contains_key("charAt"));
852 assert!(env.functions().contains_key("indexOf"));
853 assert!(env.functions().contains_key("substring"));
854 }
855
856 #[test]
857 fn test_with_all_extensions() {
858 let env = Env::with_standard_library().with_all_extensions();
859
860 assert!(env.functions().contains_key("charAt"));
862 assert!(env.functions().contains_key("indexOf"));
863 assert!(env.functions().contains_key("join"));
864 assert!(env.functions().contains_key("strings.quote"));
865
866 assert!(env.functions().contains_key("math.greatest"));
868 assert!(env.functions().contains_key("math.least"));
869 assert!(env.functions().contains_key("math.abs"));
870 assert!(env.functions().contains_key("math.bitAnd"));
871
872 assert!(env.functions().contains_key("base64.encode"));
874 assert!(env.functions().contains_key("base64.decode"));
875
876 assert!(env.functions().contains_key("optional.of"));
878 assert!(env.functions().contains_key("optional.none"));
879 assert!(env.functions().contains_key("optional.ofNonZeroValue"));
880 assert!(env.functions().contains_key("hasValue"));
881 assert!(env.functions().contains_key("value"));
882 assert!(env.functions().contains_key("or"));
883 assert!(env.functions().contains_key("orValue"));
884 }
885
886 #[test]
887 fn test_encoders_extension_base64() {
888 let env = Env::with_standard_library()
889 .with_all_extensions()
890 .with_variable("data", CelType::Bytes)
891 .with_variable("encoded", CelType::String);
892
893 let result = env.compile("base64.encode(data)");
895 assert!(result.is_ok(), "base64.encode should compile: {:?}", result);
896
897 let result = env.compile("base64.decode(encoded)");
899 assert!(result.is_ok(), "base64.decode should compile: {:?}", result);
900 }
901
902 #[test]
903 fn test_string_extension_char_at() {
904 let env = Env::with_standard_library()
905 .with_all_extensions()
906 .with_variable("s", CelType::String);
907
908 let result = env.compile("s.charAt(0)");
909 assert!(result.is_ok(), "charAt should compile: {:?}", result);
910 }
911
912 #[test]
913 fn test_string_extension_index_of() {
914 let env = Env::with_standard_library()
915 .with_all_extensions()
916 .with_variable("s", CelType::String);
917
918 assert!(env.compile("s.indexOf(\"a\")").is_ok());
920
921 assert!(env.compile("s.indexOf(\"a\", 2)").is_ok());
923 }
924
925 #[test]
926 fn test_string_extension_substring() {
927 let env = Env::with_standard_library()
928 .with_all_extensions()
929 .with_variable("s", CelType::String);
930
931 assert!(env.compile("s.substring(1)").is_ok());
933
934 assert!(env.compile("s.substring(1, 5)").is_ok());
936 }
937
938 #[test]
939 fn test_string_extension_split() {
940 let env = Env::with_standard_library()
941 .with_all_extensions()
942 .with_variable("s", CelType::String);
943
944 let ast = env.compile("s.split(\",\")").unwrap();
945 assert!(ast.is_checked());
946
947 }
950
951 #[test]
952 fn test_string_extension_join() {
953 let env = Env::with_standard_library()
954 .with_all_extensions()
955 .with_variable("parts", CelType::list(CelType::String));
956
957 assert!(env.compile("parts.join()").is_ok());
959
960 assert!(env.compile("parts.join(\",\")").is_ok());
962 }
963
964 #[test]
965 fn test_math_extension_greatest() {
966 let env = Env::with_standard_library().with_all_extensions();
967
968 assert!(env.compile("math.greatest(1, 2)").is_ok());
970
971 assert!(env.compile("math.greatest(1, 2, 3)").is_ok());
973
974 assert!(env.compile("math.greatest([1, 2, 3])").is_ok());
976 }
977
978 #[test]
979 fn test_math_extension_least() {
980 let env = Env::with_standard_library().with_all_extensions();
981 assert!(env.compile("math.least(1, 2)").is_ok());
982 }
983
984 #[test]
985 fn test_math_extension_abs() {
986 let env = Env::with_standard_library()
987 .with_all_extensions()
988 .with_variable("x", CelType::Int);
989
990 assert!(env.compile("math.abs(x)").is_ok());
991 }
992
993 #[test]
994 fn test_math_extension_bit_operations() {
995 let env = Env::with_standard_library()
996 .with_all_extensions()
997 .with_variable("a", CelType::Int)
998 .with_variable("b", CelType::Int);
999
1000 assert!(env.compile("math.bitAnd(a, b)").is_ok());
1001 assert!(env.compile("math.bitOr(a, b)").is_ok());
1002 assert!(env.compile("math.bitNot(a)").is_ok());
1003 }
1004
1005 #[test]
1006 fn test_optionals_extension_of_and_none() {
1007 let env = Env::with_standard_library()
1008 .with_all_extensions()
1009 .with_variable("x", CelType::Int);
1010
1011 let result = env.compile("optional.of(x)");
1013 assert!(result.is_ok(), "optional.of should compile: {:?}", result);
1014
1015 let result = env.compile("optional.none()");
1017 assert!(result.is_ok(), "optional.none should compile: {:?}", result);
1018
1019 let result = env.compile("optional.ofNonZeroValue(x)");
1021 assert!(
1022 result.is_ok(),
1023 "optional.ofNonZeroValue should compile: {:?}",
1024 result
1025 );
1026 }
1027
1028 #[test]
1029 fn test_cel_bind_macro() {
1030 let env = Env::with_standard_library().with_all_extensions();
1031
1032 let result = env.compile("cel.bind(x, 10, x + 1)");
1034 assert!(result.is_ok(), "cel.bind should compile: {:?}", result);
1035
1036 let result = env.compile("cel.bind(msg, \"hello\", msg + msg)");
1038 assert!(
1039 result.is_ok(),
1040 "cel.bind with string should compile: {:?}",
1041 result
1042 );
1043
1044 let result = env.compile("cel.bind(x, 1, cel.bind(y, 2, x + y))");
1046 assert!(
1047 result.is_ok(),
1048 "nested cel.bind should compile: {:?}",
1049 result
1050 );
1051 }
1052
1053 #[test]
1054 fn test_optionals_extension_methods() {
1055 let env = Env::with_standard_library()
1056 .with_all_extensions()
1057 .with_variable("opt", CelType::optional(CelType::Int))
1058 .with_variable("opt2", CelType::optional(CelType::Int));
1059
1060 let result = env.compile("opt.hasValue()");
1062 assert!(result.is_ok(), "hasValue should compile: {:?}", result);
1063
1064 let result = env.compile("opt.value()");
1066 assert!(result.is_ok(), "value should compile: {:?}", result);
1067
1068 let result = env.compile("opt.or(opt2)");
1070 assert!(result.is_ok(), "or should compile: {:?}", result);
1071
1072 let result = env.compile("opt.orValue(42)");
1074 assert!(result.is_ok(), "orValue should compile: {:?}", result);
1075 }
1076
1077 #[test]
1082 fn test_abbreviations_new() {
1083 let abbrevs = Abbreviations::new();
1084 assert!(abbrevs.is_empty());
1085 assert_eq!(abbrevs.len(), 0);
1086 }
1087
1088 #[test]
1089 fn test_abbreviations_add() {
1090 let abbrevs = Abbreviations::new()
1091 .with_abbreviation("my.package.Foo")
1092 .unwrap();
1093
1094 assert_eq!(abbrevs.resolve("Foo"), Some("my.package.Foo"));
1095 assert_eq!(abbrevs.len(), 1);
1096 }
1097
1098 #[test]
1099 fn test_abbreviations_multiple() {
1100 let abbrevs = Abbreviations::new()
1101 .with_abbreviation("my.package.Foo")
1102 .unwrap()
1103 .with_abbreviation("other.package.Bar")
1104 .unwrap();
1105
1106 assert_eq!(abbrevs.resolve("Foo"), Some("my.package.Foo"));
1107 assert_eq!(abbrevs.resolve("Bar"), Some("other.package.Bar"));
1108 assert_eq!(abbrevs.len(), 2);
1109 }
1110
1111 #[test]
1112 fn test_abbreviations_unqualified_name() {
1113 let abbrevs = Abbreviations::new().with_abbreviation("Foo").unwrap();
1115 assert_eq!(abbrevs.resolve("Foo"), Some("Foo"));
1116 }
1117
1118 #[test]
1119 fn test_abbreviations_conflict() {
1120 let result = Abbreviations::new()
1121 .with_abbreviation("my.package.Foo")
1122 .unwrap()
1123 .with_abbreviation("other.package.Foo"); assert!(result.is_err());
1126 match result {
1127 Err(AbbrevError::Conflict {
1128 short_name,
1129 existing,
1130 new,
1131 }) => {
1132 assert_eq!(short_name, "Foo");
1133 assert_eq!(existing, "my.package.Foo");
1134 assert_eq!(new, "other.package.Foo");
1135 }
1136 _ => panic!("Expected Conflict error"),
1137 }
1138 }
1139
1140 #[test]
1141 fn test_abbreviations_idempotent() {
1142 let abbrevs = Abbreviations::new()
1144 .with_abbreviation("my.package.Foo")
1145 .unwrap()
1146 .with_abbreviation("my.package.Foo") .unwrap();
1148
1149 assert_eq!(abbrevs.resolve("Foo"), Some("my.package.Foo"));
1150 assert_eq!(abbrevs.len(), 1);
1151 }
1152
1153 #[test]
1154 fn test_abbreviations_empty_name() {
1155 let result = Abbreviations::new().with_abbreviation("");
1156 assert!(result.is_err());
1157 match result {
1158 Err(AbbrevError::InvalidName(name)) => {
1159 assert_eq!(name, "");
1160 }
1161 _ => panic!("Expected InvalidName error"),
1162 }
1163 }
1164
1165 #[test]
1166 fn test_abbreviations_trailing_dot() {
1167 let result = Abbreviations::new().with_abbreviation("my.package.");
1169 assert!(result.is_err());
1170 match result {
1171 Err(AbbrevError::InvalidName(_)) => {}
1172 _ => panic!("Expected InvalidName error"),
1173 }
1174 }
1175
1176 #[test]
1177 fn test_abbreviations_from_qualified_names() {
1178 let abbrevs =
1179 Abbreviations::from_qualified_names(&["my.package.Foo", "other.package.Bar"]).unwrap();
1180
1181 assert_eq!(abbrevs.resolve("Foo"), Some("my.package.Foo"));
1182 assert_eq!(abbrevs.resolve("Bar"), Some("other.package.Bar"));
1183 }
1184
1185 #[test]
1186 fn test_abbreviations_resolve_nonexistent() {
1187 let abbrevs = Abbreviations::new()
1188 .with_abbreviation("my.package.Foo")
1189 .unwrap();
1190
1191 assert_eq!(abbrevs.resolve("Bar"), None);
1192 }
1193
1194 #[test]
1195 fn test_methods_for_type_string() {
1196 let env = Env::with_standard_library();
1197 let methods = env.methods_for_type(&CelType::String);
1198 let names: Vec<&str> = methods.iter().map(|(name, _)| *name).collect();
1199 assert!(names.contains(&"contains"));
1200 assert!(names.contains(&"startsWith"));
1201 assert!(names.contains(&"endsWith"));
1202 assert!(names.contains(&"matches"));
1203 assert!(names.contains(&"size"));
1204 assert!(!names.contains(&"_+_"));
1206 assert!(!names.contains(&"_==_"));
1207 }
1208
1209 #[test]
1210 fn test_methods_for_type_list() {
1211 let env = Env::with_standard_library();
1212 let methods = env.methods_for_type(&CelType::list(CelType::Int));
1213 let names: Vec<&str> = methods.iter().map(|(name, _)| *name).collect();
1214 assert!(names.contains(&"size"));
1215 }
1216
1217 #[test]
1218 fn test_standalone_functions() {
1219 let env = Env::with_standard_library();
1220 let funcs = env.standalone_functions();
1221 assert!(funcs.contains(&"size"));
1222 assert!(funcs.contains(&"int"));
1223 assert!(funcs.contains(&"string"));
1224 assert!(funcs.contains(&"bool"));
1225 assert!(!funcs.contains(&"_+_"));
1227 assert!(!funcs.contains(&"_-_"));
1228 assert!(!funcs.contains(&"_==_"));
1229 }
1230
1231 #[test]
1232 fn test_env_with_abbreviations() {
1233 let abbrevs = Abbreviations::new()
1234 .with_abbreviation("my.package.Foo")
1235 .unwrap();
1236
1237 let env = Env::with_standard_library().with_abbreviations(abbrevs);
1238
1239 assert!(!env.abbreviations().is_empty());
1240 assert_eq!(env.abbreviations().resolve("Foo"), Some("my.package.Foo"));
1241 }
1242
1243 #[test]
1244 fn test_abbrev_error_display() {
1245 let err = AbbrevError::Conflict {
1246 short_name: "Foo".to_string(),
1247 existing: "a.Foo".to_string(),
1248 new: "b.Foo".to_string(),
1249 };
1250 assert_eq!(
1251 err.to_string(),
1252 "abbreviation conflict: 'Foo' already maps to 'a.Foo', cannot map to 'b.Foo'"
1253 );
1254
1255 let err = AbbrevError::InvalidName("".to_string());
1256 assert_eq!(err.to_string(), "invalid qualified name: ''");
1257 }
1258}