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

gripmock / grpctestify-rust / 24369349915

13 Apr 2026 10:06PM UTC coverage: 76.457% (+1.0%) from 75.445%
24369349915

Pull #35

github

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

2929 of 3902 new or added lines in 48 files covered. (75.06%)

155 existing lines in 9 files now uncovered.

17309 of 22639 relevant lines covered (76.46%)

2463.13 hits per line

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

98.76
/src/execution/validator.rs
1
// Test validation logic
2

3
#[cfg(test)]
4
use crate::execution::TestExecutionResult;
5
#[cfg(test)]
6
use crate::parser::ast::GctfDocument;
7

8
/// Test validator — only compiled in test builds
9
#[cfg(test)]
10
pub struct TestValidator;
11

12
#[cfg(test)]
13
impl TestValidator {
14
    /// Validate execution plan
15
    pub fn validate(document: &GctfDocument) -> Result<(), String> {
4✔
16
        Self::validate_required_sections(document)?;
4✔
17
        Self::validate_no_conflicts(document)?;
2✔
18
        Self::validate_extract(document)?;
1✔
19
        Self::validate_asserts(document)?;
1✔
20
        Ok(())
1✔
21
    }
4✔
22

23
    fn validate_required_sections(document: &GctfDocument) -> Result<(), String> {
4✔
24
        let has_endpoint = document
4✔
25
            .sections
4✔
26
            .iter()
4✔
27
            .any(|s| matches!(s.section_type, crate::parser::ast::SectionType::Endpoint));
4✔
28
        if !has_endpoint {
4✔
29
            return Err("Missing required ENDPOINT section".to_string());
1✔
30
        }
3✔
31
        let has_request = document
3✔
32
            .sections
3✔
33
            .iter()
3✔
34
            .any(|s| matches!(s.section_type, crate::parser::ast::SectionType::Request));
5✔
35
        if !has_request {
3✔
36
            return Err("Missing required REQUEST section".to_string());
1✔
37
        }
2✔
38
        Ok(())
2✔
39
    }
4✔
40

41
    fn validate_no_conflicts(document: &GctfDocument) -> Result<(), String> {
2✔
42
        let has_response = document
2✔
43
            .sections
2✔
44
            .iter()
2✔
45
            .any(|s| matches!(s.section_type, crate::parser::ast::SectionType::Response));
5✔
46
        let has_error = document
2✔
47
            .sections
2✔
48
            .iter()
2✔
49
            .any(|s| matches!(s.section_type, crate::parser::ast::SectionType::Error));
6✔
50
        if has_response && has_error {
2✔
51
            return Err("Cannot have both RESPONSE and ERROR sections".to_string());
1✔
52
        }
1✔
53
        Ok(())
1✔
54
    }
2✔
55

56
    fn validate_extract(document: &GctfDocument) -> Result<(), String> {
1✔
57
        let extract_sections: Vec<_> = document
1✔
58
            .sections
1✔
59
            .iter()
1✔
60
            .filter(|s| matches!(s.section_type, crate::parser::ast::SectionType::Extract))
2✔
61
            .collect();
1✔
62
        if extract_sections.len() > 1 {
1✔
UNCOV
63
            return Err("Multiple EXTRACT sections found".to_string());
×
64
        }
1✔
65
        Ok(())
1✔
66
    }
1✔
67

68
    fn validate_asserts(document: &GctfDocument) -> Result<(), String> {
1✔
69
        let asserts_sections: Vec<_> = document
1✔
70
            .sections
1✔
71
            .iter()
1✔
72
            .filter(|s| matches!(s.section_type, crate::parser::ast::SectionType::Asserts))
2✔
73
            .collect();
1✔
74
        if asserts_sections.len() > 1 {
1✔
UNCOV
75
            return Err("Multiple ASSERTS sections found".to_string());
×
76
        }
1✔
77
        Ok(())
1✔
78
    }
1✔
79

80
    /// Validate test result after execution
81
    pub fn validate_result(result: &TestExecutionResult) -> bool {
2✔
82
        matches!(result.status, crate::execution::TestExecutionStatus::Pass)
2✔
83
    }
2✔
84

85
    /// Get result summary
86
    pub fn get_result_summary(result: &TestExecutionResult) -> String {
2✔
87
        let duration = result.grpc_duration_ms.unwrap_or(0);
2✔
88
        match &result.status {
2✔
89
            crate::execution::TestExecutionStatus::Pass => {
90
                format!("✓ Passed ({}ms)", duration)
1✔
91
            }
92
            crate::execution::TestExecutionStatus::Fail(msg) => {
1✔
93
                format!("✗ Failed: {} ({}ms)", msg, duration)
1✔
94
            }
95
        }
96
    }
2✔
97
}
98

99
#[cfg(test)]
100
mod tests {
101
    use super::*;
102
    use crate::parser::ast::{GctfDocument, Section, SectionContent, SectionType};
103
    use serde_json::json;
104

105
    fn create_test_document() -> GctfDocument {
4✔
106
        GctfDocument {
4✔
107
            file_path: "test.gctf".to_string(),
4✔
108
            sections: vec![
4✔
109
                Section {
4✔
110
                    section_type: SectionType::Endpoint,
4✔
111
                    content: SectionContent::Single("test.Service/Method".to_string()),
4✔
112
                    inline_options: Default::default(),
4✔
113
                    raw_content: "test.Service/Method".to_string(),
4✔
114
                    start_line: 1,
4✔
115
                    end_line: 2,
4✔
116
                },
4✔
117
                Section {
4✔
118
                    section_type: SectionType::Request,
4✔
119
                    content: SectionContent::Json(json!({"id": 123})),
4✔
120
                    inline_options: Default::default(),
4✔
121
                    raw_content: r#"{"id": 123}"#.to_string(),
4✔
122
                    start_line: 3,
4✔
123
                    end_line: 5,
4✔
124
                },
4✔
125
            ],
4✔
126
            metadata: crate::parser::ast::DocumentMetadata {
4✔
127
                source: None,
4✔
128
                mtime: None,
4✔
129
                parsed_at: 0,
4✔
130
            },
4✔
131
            next_document: None,
4✔
132
        }
4✔
133
    }
4✔
134

135
    #[test]
136
    fn test_validate_required_sections() {
1✔
137
        let doc = create_test_document();
1✔
138
        let result = TestValidator::validate(&doc);
1✔
139
        assert!(result.is_ok());
1✔
140
    }
1✔
141

142
    #[test]
143
    fn test_validate_missing_endpoint() {
1✔
144
        let mut doc = create_test_document();
1✔
145
        doc.sections
1✔
146
            .retain(|s| !matches!(s.section_type, SectionType::Endpoint));
2✔
147
        let result = TestValidator::validate(&doc);
1✔
148
        assert!(result.is_err());
1✔
149
        assert!(result.unwrap_err().contains("ENDPOINT"));
1✔
150
    }
1✔
151

152
    #[test]
153
    fn test_validate_missing_request() {
1✔
154
        let mut doc = create_test_document();
1✔
155
        doc.sections
1✔
156
            .retain(|s| !matches!(s.section_type, SectionType::Request));
2✔
157
        let result = TestValidator::validate(&doc);
1✔
158
        assert!(result.is_err());
1✔
159
        assert!(result.unwrap_err().contains("REQUEST"));
1✔
160
    }
1✔
161

162
    #[test]
163
    fn test_validate_no_conflicts() {
1✔
164
        let mut doc = create_test_document();
1✔
165
        doc.sections.push(Section {
1✔
166
            section_type: SectionType::Response,
1✔
167
            content: SectionContent::Json(json!({"result": "ok"})),
1✔
168
            inline_options: Default::default(),
1✔
169
            raw_content: r#"{"result": "ok"}"#.to_string(),
1✔
170
            start_line: 6,
1✔
171
            end_line: 8,
1✔
172
        });
1✔
173
        doc.sections.push(Section {
1✔
174
            section_type: SectionType::Error,
1✔
175
            content: SectionContent::Json(json!({"code": 5})),
1✔
176
            inline_options: Default::default(),
1✔
177
            raw_content: r#"{"code": 5}"#.to_string(),
1✔
178
            start_line: 9,
1✔
179
            end_line: 11,
1✔
180
        });
1✔
181
        let result = TestValidator::validate(&doc);
1✔
182
        assert!(result.is_err());
1✔
183
        assert!(result.unwrap_err().contains("RESPONSE"));
1✔
184
    }
1✔
185

186
    #[test]
187
    fn test_validate_result_pass() {
1✔
188
        let result = TestExecutionResult::pass(Some(100));
1✔
189
        assert!(TestValidator::validate_result(&result));
1✔
190
    }
1✔
191

192
    #[test]
193
    fn test_validate_result_fail() {
1✔
194
        let result = TestExecutionResult::fail("Assertion failed".to_string(), Some(100));
1✔
195
        assert!(!TestValidator::validate_result(&result));
1✔
196
    }
1✔
197

198
    #[test]
199
    fn test_get_result_summary_pass() {
1✔
200
        let result = TestExecutionResult::pass(Some(100));
1✔
201
        let summary = TestValidator::get_result_summary(&result);
1✔
202
        assert!(summary.contains("Passed"));
1✔
203
        assert!(summary.contains("100ms"));
1✔
204
    }
1✔
205

206
    #[test]
207
    fn test_get_result_summary_fail() {
1✔
208
        let result = TestExecutionResult::fail("Error".to_string(), Some(100));
1✔
209
        let summary = TestValidator::get_result_summary(&result);
1✔
210
        assert!(summary.contains("Failed"));
1✔
211
    }
1✔
212
}
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