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

input-output-hk / catalyst-libs / 20908186781

12 Jan 2026 04:34AM UTC coverage: 69.556% (+2.4%) from 67.194%
20908186781

push

github

web-flow
feat(rust/signed-doc): `Contest Delegation` validation (#750)

* wip

* add separate `rep_nomination_ref_check` function

* wip

* wip

* wip

* wip

* add contest_delegation test for `catalyst-contest`

* wip

* fix test

* add test case

* fix fmt, fix spelling

* fix comment

* wip

* fix clippy

* cleanup

148 of 179 new or added lines in 6 files covered. (82.68%)

204 existing lines in 26 files now uncovered.

16007 of 23013 relevant lines covered (69.56%)

2651.03 hits per line

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

87.38
/rust/signed_doc/src/validator/rules/content_encoding.rs
1
//! `content-encoding` rule type impl.
2

3
use std::string::ToString;
4

5
use catalyst_signed_doc_spec::is_required::IsRequired;
6

7
use crate::{
8
    CatalystSignedDocument, metadata::ContentEncoding, providers::Provider,
9
    validator::CatalystSignedDocumentValidationRule,
10
};
11

12
/// `content-encoding` field validation rule.
13
#[derive(Debug)]
14
pub(crate) enum ContentEncodingRule {
15
    /// Content Encoding field is optionally present in the document.
16
    Specified {
17
        /// expected `content-encoding` field.
18
        exp: Vec<ContentEncoding>,
19
        /// optional flag for the `content-encoding` field.
20
        optional: bool,
21
    },
22
    /// Content Encoding field must not be present in the document.
23
    NotSpecified,
24
}
25

26
impl CatalystSignedDocumentValidationRule for ContentEncodingRule {
27
    fn check(
137✔
28
        &self,
137✔
29
        doc: &CatalystSignedDocument,
137✔
30
        _provider: &dyn Provider,
137✔
31
    ) -> anyhow::Result<bool> {
137✔
32
        Ok(self.check_inner(doc))
137✔
33
    }
137✔
34
}
35

36
impl ContentEncodingRule {
37
    /// Create a new rule from specs.
38
    pub(crate) fn new(
2,919✔
39
        spec: &catalyst_signed_doc_spec::headers::content_encoding::ContentEncoding
2,919✔
40
    ) -> anyhow::Result<Self> {
2,919✔
41
        if let IsRequired::Excluded = spec.required {
2,919✔
UNCOV
42
            anyhow::ensure!(
×
UNCOV
43
                spec.value.is_none(),
×
44
                "'content type' field must not exist when 'required' is 'excluded'"
×
45
            );
46
            return Ok(Self::NotSpecified);
×
47
        }
2,919✔
48

49
        let optional = IsRequired::Optional == spec.required;
2,919✔
50

51
        let exp = spec
2,919✔
52
            .value
2,919✔
53
            .as_ref()
2,919✔
54
            .ok_or(anyhow::anyhow!("'content-encoding' field must have value "))?
2,919✔
55
            .iter()
2,919✔
56
            .flat_map(|encoding| encoding.parse())
2,919✔
57
            .collect();
2,919✔
58

59
        Ok(Self::Specified { exp, optional })
2,919✔
60
    }
2,919✔
61

62
    /// Field validation rule
63
    fn check_inner(
143✔
64
        &self,
143✔
65
        doc: &CatalystSignedDocument,
143✔
66
    ) -> bool {
143✔
67
        let context = "Content Encoding Rule check";
143✔
68
        match self {
143✔
69
            Self::NotSpecified => {
70
                if let Some(content_encoding) = doc.doc_content_encoding() {
2✔
71
                    doc.report().unknown_field(
1✔
72
                        "content-encoding",
1✔
73
                        &content_encoding.to_string(),
1✔
74
                        &format!(
1✔
75
                            "{context}, document does not expect to have a content-encoding field"
1✔
76
                        ),
1✔
77
                    );
78
                    return false;
1✔
79
                }
1✔
80
            },
81
            Self::Specified { exp, optional } => {
141✔
82
                if let Some(content_encoding) = doc.doc_content_encoding() {
141✔
83
                    if !exp.contains(&content_encoding) {
120✔
UNCOV
84
                        doc.report().invalid_value(
×
UNCOV
85
                            "content-encoding",
×
86
                            content_encoding.to_string().as_str(),
×
87
                            &exp.iter()
×
88
                                .map(ToString::to_string)
×
89
                                .collect::<Vec<_>>()
×
90
                                .join(", "),
×
91
                            "Invalid document content-encoding value",
×
92
                        );
93
                        return false;
×
94
                    }
120✔
95
                    if content_encoding.decode(doc.encoded_content()).is_err() {
120✔
96
                        doc.report().invalid_value(
21✔
97
                            "payload",
21✔
98
                            &hex::encode(doc.encoded_content()),
21✔
99
                            content_encoding.to_string().as_str(),
21✔
100
                            "Document content is not decodable with the expected content-encoding",
21✔
101
                        );
102
                        return false;
21✔
103
                    }
99✔
104
                } else if !optional {
21✔
105
                    doc.report().missing_field(
1✔
106
                        "content-encoding",
1✔
107
                        "Document must have a content-encoding field",
1✔
108
                    );
109
                    return false;
1✔
110
                }
20✔
111
            },
112
        }
113
        true
120✔
114
    }
143✔
115
}
116

117
#[cfg(test)]
118
mod tests {
119
    use super::*;
120
    use crate::{builder::tests::Builder, metadata::SupportedField};
121

122
    #[test]
123
    fn content_encoding_is_specified_rule_test() {
1✔
124
        let content_encoding = ContentEncoding::Brotli;
1✔
125

126
        let rule = ContentEncodingRule::Specified {
1✔
127
            exp: vec![content_encoding],
1✔
128
            optional: true,
1✔
129
        };
1✔
130

131
        let doc = Builder::new()
1✔
132
            .with_metadata_field(SupportedField::ContentEncoding(content_encoding))
1✔
133
            .with_content(content_encoding.encode(&[1, 2, 3]).unwrap())
1✔
134
            .build();
1✔
135
        assert!(rule.check_inner(&doc));
1✔
136

137
        // empty content (empty bytes) could not be brotli decoded
138
        let doc = Builder::new()
1✔
139
            .with_metadata_field(SupportedField::ContentEncoding(content_encoding))
1✔
140
            .build();
1✔
141
        assert!(!rule.check_inner(&doc));
1✔
142

143
        let doc = Builder::new().build();
1✔
144
        assert!(rule.check_inner(&doc));
1✔
145

146
        let rule = ContentEncodingRule::Specified {
1✔
147
            exp: vec![content_encoding],
1✔
148
            optional: false,
1✔
149
        };
1✔
150
        assert!(!rule.check_inner(&doc));
1✔
151
    }
1✔
152

153
    #[test]
154
    fn content_encoding_is_not_specified_rule_test() {
1✔
155
        let content_encoding = ContentEncoding::Brotli;
1✔
156

157
        let rule = ContentEncodingRule::NotSpecified;
1✔
158

159
        // With Brotli content encoding
160
        let doc = Builder::new()
1✔
161
            .with_metadata_field(SupportedField::ContentEncoding(content_encoding))
1✔
162
            .build();
1✔
163
        assert!(!rule.check_inner(&doc));
1✔
164

165
        // No content encoding
166
        let doc = Builder::new().build();
1✔
167
        assert!(rule.check_inner(&doc));
1✔
168
    }
1✔
169
}
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