• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gripmock / grpctestify-rust / 24368489201

13 Apr 2026 09:44PM UTC coverage: 76.048% (+0.6%) from 75.445%
24368489201

Pull #35

github

web-flow
Merge 745330ff7 into 4ba0f08f1
Pull Request #35: feat: meta section & refactoring

2754 of 3728 new or added lines in 47 files covered. (73.87%)

155 existing lines in 9 files now uncovered.

17097 of 22482 relevant lines covered (76.05%)

2480.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.33
/src/plugins/env.rs
1
// Environment variable plugin
2
// Reads environment variables: @env("VAR_NAME") or @env("VAR_NAME", "default_value")
3
// Returns: the value of the variable, or the default value if not set
4

5
use anyhow::Result;
6
use serde_json::Value;
7
use std::env;
8

9
use crate::assert::engine::AssertionResult;
10
use crate::plugins::{
11
    ArgTypeInfo, Plugin, PluginContext, PluginPurity, PluginResult, PluginSignature, TypeInfo,
12
};
13

14
/// Environment variable plugin
15
#[derive(Debug, Clone, Default)]
16
pub struct EnvPlugin;
17

18
impl Plugin for EnvPlugin {
19
    fn name(&self) -> &'static str {
239✔
20
        "env"
239✔
21
    }
239✔
22

23
    fn description(&self) -> &'static str {
2✔
24
        "Read environment variable value. Optional second argument provides a default value."
2✔
25
    }
2✔
26

27
    fn signature(&self) -> PluginSignature {
37✔
28
        PluginSignature {
37✔
29
            return_type: TypeInfo::StringOrNull,
37✔
30
            arg_types: &[
37✔
31
                ArgTypeInfo {
37✔
32
                    expected: TypeInfo::String,
37✔
33
                    required: true,
37✔
34
                    default: None,
37✔
35
                },
37✔
36
                ArgTypeInfo {
37✔
37
                    expected: TypeInfo::String,
37✔
38
                    required: false,
37✔
39
                    default: None,
37✔
40
                },
37✔
41
            ],
37✔
42
            purity: PluginPurity::Impure,
37✔
43
            deterministic: false,
37✔
44
            idempotent: false,
37✔
45
            safe_for_rewrite: false,
37✔
46
            arg_names: &["name", "default"],
37✔
47
        }
37✔
48
    }
37✔
49

50
    fn execute(&self, args: &[Value], _context: &PluginContext) -> Result<PluginResult> {
7✔
51
        // Check argument count
52
        if args.is_empty() {
7✔
53
            return Ok(PluginResult::Assertion(AssertionResult::fail(
1✔
54
                "@env requires at least 1 argument: the variable name",
1✔
55
            )));
1✔
56
        }
6✔
57

58
        if args.len() > 2 {
6✔
59
            return Ok(PluginResult::Assertion(AssertionResult::fail(
1✔
60
                "@env accepts at most 2 arguments: name and optional default value",
1✔
61
            )));
1✔
62
        }
5✔
63

64
        // Get variable name
65
        let var_name = match &args[0] {
5✔
66
            Value::String(name) => name,
4✔
67
            _ => {
68
                return Ok(PluginResult::Assertion(AssertionResult::fail(
1✔
69
                    "@env first argument must be a string (variable name)",
1✔
70
                )));
1✔
71
            }
72
        };
73

74
        // Get optional default value
75
        let default_value = if args.len() > 1 {
4✔
76
            match &args[1] {
2✔
77
                Value::String(s) => Some(s.clone()),
2✔
NEW
78
                other => Some(other.to_string()),
×
79
            }
80
        } else {
81
            None
2✔
82
        };
83

84
        // Get environment variable
85
        match env::var(var_name) {
4✔
86
            Ok(value) => Ok(PluginResult::Value(Value::String(value))),
2✔
87
            Err(_) => {
88
                if let Some(default) = default_value {
2✔
89
                    Ok(PluginResult::Value(Value::String(default)))
1✔
90
                } else {
91
                    Ok(PluginResult::Value(Value::Null))
1✔
92
                }
93
            }
94
        }
95
    }
7✔
96
}
97

98
#[cfg(test)]
99
mod tests {
100
    use super::*;
101
    use std::env;
102

103
    #[test]
104
    fn test_env_plugin_exists() {
1✔
105
        // Arrange
106
        let plugin = EnvPlugin;
1✔
107
        unsafe {
1✔
108
            env::set_var("TEST_VAR", "test_value");
1✔
109
        }
1✔
110

111
        // Act
112
        let result = plugin
1✔
113
            .execute(
1✔
114
                &[Value::String("TEST_VAR".to_string())],
1✔
115
                &PluginContext::new(&Value::Null),
1✔
116
            )
117
            .unwrap();
1✔
118

119
        // Assert
120
        assert!(matches!(result, PluginResult::Value(Value::String(s)) if s == "test_value"));
1✔
121

122
        unsafe {
1✔
123
            env::remove_var("TEST_VAR");
1✔
124
        }
1✔
125
    }
1✔
126

127
    #[test]
128
    fn test_env_plugin_not_exists() {
1✔
129
        // Arrange
130
        let plugin = EnvPlugin;
1✔
131

132
        // Act
133
        let result = plugin
1✔
134
            .execute(
1✔
135
                &[Value::String("NONEXISTENT_VAR_12345".to_string())],
1✔
136
                &PluginContext::new(&Value::Null),
1✔
137
            )
138
            .unwrap();
1✔
139

140
        // Assert
141
        assert!(matches!(result, PluginResult::Value(Value::Null)));
1✔
142
    }
1✔
143

144
    #[test]
145
    fn test_env_plugin_no_args() {
1✔
146
        // Arrange
147
        let plugin = EnvPlugin;
1✔
148

149
        // Act
150
        let result = plugin
1✔
151
            .execute(&[], &PluginContext::new(&Value::Null))
1✔
152
            .unwrap();
1✔
153

154
        // Assert
155
        assert!(matches!(
1✔
156
            result,
1✔
157
            PluginResult::Assertion(AssertionResult::Fail { .. })
158
        ));
159
    }
1✔
160

161
    #[test]
162
    fn test_env_plugin_too_many_args() {
1✔
163
        // Arrange
164
        let plugin = EnvPlugin;
1✔
165

166
        // Act — 3 args is too many (max 2)
167
        let result = plugin
1✔
168
            .execute(
1✔
169
                &[
1✔
170
                    Value::String("VAR1".to_string()),
1✔
171
                    Value::String("default".to_string()),
1✔
172
                    Value::String("extra".to_string()),
1✔
173
                ],
1✔
174
                &PluginContext::new(&Value::Null),
1✔
175
            )
176
            .unwrap();
1✔
177

178
        // Assert
179
        assert!(matches!(
1✔
180
            result,
1✔
181
            PluginResult::Assertion(AssertionResult::Fail { .. })
182
        ));
183
    }
1✔
184

185
    #[test]
186
    fn test_env_plugin_with_default_value() {
1✔
187
        // Arrange
188
        let plugin = EnvPlugin;
1✔
189

190
        // Act — var doesn't exist, should return default
191
        let result = plugin
1✔
192
            .execute(
1✔
193
                &[
1✔
194
                    Value::String("NONEXISTENT_VAR_12345".to_string()),
1✔
195
                    Value::String("/home/user".to_string()),
1✔
196
                ],
1✔
197
                &PluginContext::new(&Value::Null),
1✔
198
            )
199
            .unwrap();
1✔
200

201
        // Assert
202
        assert!(matches!(result, PluginResult::Value(Value::String(s)) if s == "/home/user"));
1✔
203
    }
1✔
204

205
    #[test]
206
    fn test_env_plugin_var_exists_ignores_default() {
1✔
207
        // Arrange
208
        let plugin = EnvPlugin;
1✔
209
        unsafe {
1✔
210
            env::set_var("TEST_VAR_DEFAULT", "actual_value");
1✔
211
        }
1✔
212

213
        // Act — var exists, should return actual value not default
214
        let result = plugin
1✔
215
            .execute(
1✔
216
                &[
1✔
217
                    Value::String("TEST_VAR_DEFAULT".to_string()),
1✔
218
                    Value::String("ignored_default".to_string()),
1✔
219
                ],
1✔
220
                &PluginContext::new(&Value::Null),
1✔
221
            )
222
            .unwrap();
1✔
223

224
        // Assert
225
        assert!(matches!(result, PluginResult::Value(Value::String(s)) if s == "actual_value"));
1✔
226

227
        unsafe {
1✔
228
            env::remove_var("TEST_VAR_DEFAULT");
1✔
229
        }
1✔
230
    }
1✔
231

232
    #[test]
233
    fn test_env_plugin_wrong_type() {
1✔
234
        // Arrange
235
        let plugin = EnvPlugin;
1✔
236

237
        // Act
238
        let result = plugin
1✔
239
            .execute(
1✔
240
                &[Value::Number(123.into())],
1✔
241
                &PluginContext::new(&Value::Null),
1✔
242
            )
243
            .unwrap();
1✔
244

245
        // Assert
246
        assert!(matches!(
1✔
247
            result,
1✔
248
            PluginResult::Assertion(AssertionResult::Fail { .. })
249
        ));
250
    }
1✔
251

252
    #[test]
253
    fn test_env_plugin_name() {
1✔
254
        let plugin = EnvPlugin;
1✔
255
        assert_eq!(plugin.name(), "env");
1✔
256
    }
1✔
257

258
    #[test]
259
    fn test_env_plugin_description() {
1✔
260
        let plugin = EnvPlugin;
1✔
261
        assert!(plugin.description().contains("environment"));
1✔
262
    }
1✔
263
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc