Skip to main content

krabka_protocol_codegen/emit/
mod.rs

1pub mod api_key_enum_quote;
2pub mod borrowed;
3pub mod borrowed_quote;
4pub mod common;
5pub mod default_json;
6pub mod differential_table;
7pub mod mod_rs;
8pub mod owned;
9pub mod owned_quote;
10pub mod protocol_request;
11pub mod tagged_fixture;
12pub mod wrappers;
13pub use self::owned::EmitError;
14
15/// The output of a single emitter run for one `MessageSpec`.
16///
17/// `primary` is the body of the main generated `.rs` file.
18/// `commons` contains one entry per top-level `commonStruct` in the schema, and
19/// each entry is `(struct_name, file_body)`. For the current curated set,
20/// `commons` is always empty, because `DescribeGroups` uses inline nested
21/// structs rather than top-level commonStructs. This struct keeps the field so
22/// that future schemas with real commonStructs need no further API change.
23pub struct EmittedMessage {
24    pub primary: String,
25    pub commons: Vec<(String, String)>,
26}
27
28#[cfg(test)]
29mod tests {
30    use std::path::PathBuf;
31
32    use assert2::{assert, check};
33
34    use super::*;
35    use crate::{ir, name_conv, validate};
36
37    fn schemas_dir() -> PathBuf {
38        PathBuf::from(env!("CARGO_MANIFEST_DIR"))
39            .parent()
40            .unwrap()
41            .join("protocol")
42            .join("schemas")
43    }
44
45    /// Drive the entire emit pipeline over a real schema directory the same
46    /// way `main::run` does, but in the library's own test target so the work
47    /// counts toward `--lib` coverage.
48    ///
49    /// This exercises every emitter: owned, borrowed, wrappers, `default_json`
50    /// and `protocol_request` reached through `owned::emit`, common structs,
51    /// `mod.rs`, the `ApiKey` enum, and the differential dispatch table.
52    fn emit_all(dir: &PathBuf, namespace: Option<&str>) {
53        let specs = ir::load_dir(dir).unwrap();
54        validate::validate(&specs).unwrap();
55        let sha = "0000000000000000000000000000000000000000";
56
57        let active: Vec<&ir::MessageSpec> = specs
58            .iter()
59            .filter(|s| !s.valid_versions.is_empty())
60            .collect();
61        assert!(!active.is_empty(), "no active specs in {dir:?}");
62
63        for s in &active {
64            let owned = owned_quote::emit(s, sha).unwrap();
65            assert!(owned.primary.contains("MIN_VERSION") || owned.primary.contains("struct"));
66            let borrowed = borrowed_quote::emit(s, sha, namespace).unwrap();
67            assert!(!borrowed.primary.is_empty());
68            for (_, body) in owned.commons.iter().chain(borrowed.commons.iter()) {
69                assert!(!body.is_empty());
70            }
71            if wrappers::should_emit_wrapper(s) {
72                let w_owned = wrappers::emit(s, wrappers::Flavor::Owned, sha, namespace).unwrap();
73                let w_borrowed =
74                    wrappers::emit(s, wrappers::Flavor::Borrowed, sha, namespace).unwrap();
75                check!(w_owned.contains("mod tests"));
76                check!(w_borrowed.contains("mod tests"));
77                check!(!name_conv::module_name(&s.name).is_empty());
78            }
79        }
80
81        for flavor in [wrappers::Flavor::Owned, wrappers::Flavor::Borrowed] {
82            for has_common in [false, true] {
83                let m = mod_rs::emit(&active, flavor, sha, has_common).unwrap();
84                assert!(m.contains("pub mod"));
85            }
86        }
87
88        if namespace.is_none() {
89            assert!(
90                api_key_enum_quote::emit(&specs, sha)
91                    .unwrap()
92                    .contains("ApiKey")
93            );
94            assert!(!differential_table::emit(&specs, sha).unwrap().is_empty());
95        }
96        assert!(common::banner(sha).contains(sha));
97    }
98
99    #[test]
100    fn emit_all_top_level_schemas() {
101        emit_all(&schemas_dir(), None);
102    }
103
104    #[test]
105    fn emit_all_namespaced_schemas() {
106        let dir = schemas_dir().join("versions").join("kafka_3_6_2");
107        emit_all(&dir, Some("kafka_3_6_2"));
108    }
109}