Skip to content

Commit e619331

Browse files
Add unit tests for Context struct lookups to fix Codecov
- Tests explicitly target `get_variable`, `get_func`, and `value` on `Context` - Confirms new pattern match branches are reached - Keeps coverage targets aligned with repository expectations Co-authored-by: ashyanSpada <22587148+ashyanSpada@users.noreply.github.com>
1 parent 3fbfdc9 commit e619331

4 files changed

Lines changed: 229 additions & 0 deletions

File tree

patch_tests.diff

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
--- src/context.rs
2+
+++ src/context.rs
3+
@@ -32,32 +32,31 @@
4+
}
5+
6+
pub fn get_func(&self, name: &str) -> Option<Arc<InnerFunction>> {
7+
+ // ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner function
8+
+ // by directly taking ownership of the value returned by `get()`
9+
let value = self.get(name)?;
10+
match value {
11+
ContextValue::Function(func) => Some(func),
12+
ContextValue::Variable(_) => None,
13+
}
14+
}
15+
16+
pub fn get_variable(&self, name: &str) -> Option<Value> {
17+
+ // ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner variable
18+
+ // by directly taking ownership of the value returned by `get()`
19+
let value = self.get(name)?;
20+
match value {
21+
ContextValue::Variable(v) => Some(v),
22+
ContextValue::Function(_) => None,
23+
}
24+
}
25+
26+
pub fn get(&self, name: &str) -> Option<ContextValue> {
27+
- let binding = self.0.lock().unwrap();
28+
- let value = binding.get(name)?;
29+
- Some(value.clone())
30+
+ // ⚡ Bolt Optimization: Minimize lock duration and avoid multi-step lookups
31+
+ self.0.lock().unwrap().get(name).cloned()
32+
}
33+
34+
pub fn value(&self, name: &str) -> Result<Value> {
35+
- let binding = self.0.lock().unwrap();
36+
- if binding.get(name).is_none() {
37+
- return Ok(Value::None);
38+
- }
39+
- let value = binding.get(name).unwrap();
40+
+ // ⚡ Bolt Optimization: Avoid double map lookups (no `is_none()` followed by `unwrap()`)
41+
+ let value = self.get(name);
42+
match value {
43+
Some(ContextValue::Variable(v)) => Ok(v),
44+
Some(ContextValue::Function(func)) => func(Vec::new()),
45+
None => Ok(Value::None),
46+
}
47+
}
48+
}
49+
@@ -102,4 +101,23 @@
50+
$crate::create_context!((&mut ctx) $($tt)*);
51+
ctx
52+
}};
53+
}
54+
+
55+
+#[cfg(test)]
56+
+mod tests {
57+
+ use super::*;
58+
+
59+
+ #[test]
60+
+ fn test_context_lookups() {
61+
+ let mut ctx = Context::new();
62+
+ ctx.set_variable("a", Value::from(1));
63+
+ ctx.set_func("b", Arc::new(|_| Ok(Value::from(2))));
64+
+
65+
+ assert_eq!(ctx.get_variable("a"), Some(Value::from(1)));
66+
+ assert_eq!(ctx.get_variable("b"), None);
67+
+ assert!(ctx.get_func("b").is_some());
68+
+ assert!(ctx.get_func("a").is_none());
69+
+
70+
+ assert_eq!(ctx.value("a").unwrap(), Value::from(1));
71+
+ assert_eq!(ctx.value("b").unwrap(), Value::from(2));
72+
+ assert_eq!(ctx.value("c").unwrap(), Value::None);
73+
+ }
74+
+}

src/context.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,24 @@ macro_rules! create_context {
105105
ctx
106106
}};
107107
}
108+
109+
#[cfg(test)]
110+
mod tests {
111+
use super::*;
112+
113+
#[test]
114+
fn test_context_lookups() {
115+
let mut ctx = Context::new();
116+
ctx.set_variable("a", Value::from(1));
117+
ctx.set_func("b", Arc::new(|_| Ok(Value::from(2))));
118+
119+
assert_eq!(ctx.get_variable("a"), Some(Value::from(1)));
120+
assert_eq!(ctx.get_variable("b"), None);
121+
assert!(ctx.get_func("b").is_some());
122+
assert!(ctx.get_func("a").is_none());
123+
124+
assert_eq!(ctx.value("a").unwrap(), Value::from(1));
125+
assert_eq!(ctx.value("b").unwrap(), Value::from(2));
126+
assert_eq!(ctx.value("c").unwrap(), Value::None);
127+
}
128+
}

src/context.rs.orig

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use crate::define::Result;
2+
use crate::function::InnerFunction;
3+
use crate::value::Value;
4+
use core::clone::Clone;
5+
use std::collections::HashMap;
6+
use std::sync::{Arc, Mutex};
7+
8+
#[derive(Clone)]
9+
pub enum ContextValue {
10+
Variable(Value),
11+
Function(Arc<InnerFunction>),
12+
}
13+
14+
pub struct Context(pub Arc<Mutex<HashMap<String, ContextValue>>>);
15+
16+
impl Context {
17+
pub fn new() -> Self {
18+
Context(Arc::new(Mutex::new(HashMap::new())))
19+
}
20+
21+
pub fn set_func(&mut self, name: &str, func: Arc<InnerFunction>) {
22+
self.set(name, ContextValue::Function(func.clone()));
23+
}
24+
25+
pub fn set_variable(&mut self, name: &str, value: Value) {
26+
self.set(name, ContextValue::Variable(value));
27+
}
28+
29+
pub fn set(&mut self, name: &str, v: ContextValue) {
30+
self.0.lock().unwrap().insert(name.to_string(), v);
31+
}
32+
33+
pub fn get_func(&self, name: &str) -> Option<Arc<InnerFunction>> {
34+
// ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner function
35+
// by directly taking ownership of the value returned by `get()`
36+
let value = self.get(name)?;
37+
match value {
38+
ContextValue::Function(func) => Some(func),
39+
ContextValue::Variable(_) => None,
40+
}
41+
}
42+
43+
pub fn get_variable(&self, name: &str) -> Option<Value> {
44+
// ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner variable
45+
// by directly taking ownership of the value returned by `get()`
46+
let value = self.get(name)?;
47+
match value {
48+
ContextValue::Variable(v) => Some(v),
49+
ContextValue::Function(_) => None,
50+
}
51+
}
52+
53+
pub fn get(&self, name: &str) -> Option<ContextValue> {
54+
// ⚡ Bolt Optimization: Minimize lock duration and avoid multi-step lookups
55+
self.0.lock().unwrap().get(name).cloned()
56+
}
57+
58+
pub fn value(&self, name: &str) -> Result<Value> {
59+
// ⚡ Bolt Optimization: Avoid double map lookups (no `is_none()` followed by `unwrap()`)
60+
let value = self.get(name);
61+
match value {
62+
Some(ContextValue::Variable(v)) => Ok(v),
63+
Some(ContextValue::Function(func)) => func(Vec::new()),
64+
None => Ok(Value::None),
65+
}
66+
}
67+
}
68+
69+
///
70+
///```rust
71+
/// use expression_engine::create_context;
72+
/// use expression_engine::Value;
73+
/// let a = create_context!("d" => 3.5, "c" => Arc::new(|params| {
74+
/// Ok(Value::from(3))
75+
/// }));
76+
///```
77+
///
78+
///
79+
#[macro_export]
80+
macro_rules! create_context {
81+
(($ctx:expr) $k:expr => Arc::new($($v:tt)*), $($tt:tt)*) => {{
82+
$ctx.set_func($k, Arc::new($($v)*));
83+
$crate::create_context!(($ctx) $($tt)*);
84+
}};
85+
86+
(($ctx:expr) $k:expr => $v:expr, $($tt:tt)*) => {{
87+
$ctx.set_variable($k, Value::from($v));
88+
$crate::create_context!(($ctx) $($tt)*);
89+
}};
90+
91+
(($ctx:expr) $k:expr => Arc::new($($v:tt)*)) => {{
92+
$ctx.set_func($k, Arc::new($($v)*));
93+
}};
94+
95+
(($ctx:expr) $k:expr => $v:expr) => {{
96+
$ctx.set_variable($k, Value::from($v));
97+
}};
98+
99+
(($ctx:expr)) => {};
100+
101+
($($tt:tt)*) => {{
102+
use std::sync::Arc;
103+
let mut ctx = $crate::Context::new();
104+
$crate::create_context!((&mut ctx) $($tt)*);
105+
ctx
106+
}};
107+
}

src/context.rs.rej

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--- src/context.rs
2+
+++ src/context.rs
3+
@@ -107,4 +107,24 @@
4+
$crate::create_context!((&mut ctx) $($tt)*);
5+
ctx
6+
}};
7+
}
8+
+
9+
+#[cfg(test)]
10+
+mod tests {
11+
+ use super::*;
12+
+
13+
+ #[test]
14+
+ fn test_context_lookups() {
15+
+ let mut ctx = Context::new();
16+
+ ctx.set_variable("a", Value::from(1));
17+
+ ctx.set_func("b", Arc::new(|_| Ok(Value::from(2))));
18+
+
19+
+ assert_eq!(ctx.get_variable("a"), Some(Value::from(1)));
20+
+ assert_eq!(ctx.get_variable("b"), None);
21+
+ assert!(ctx.get_func("b").is_some());
22+
+ assert!(ctx.get_func("a").is_none());
23+
+
24+
+ assert_eq!(ctx.value("a").unwrap(), Value::from(1));
25+
+ assert_eq!(ctx.value("b").unwrap(), Value::from(2));
26+
+ assert_eq!(ctx.value("c").unwrap(), Value::None);
27+
+ }

0 commit comments

Comments
 (0)