Skip to main content

meta_ast/model/
output.rs

1use serde::Serialize;
2
3use crate::model::{SourceRange, Visibility};
4
5#[derive(Debug, Clone, Serialize)]
6pub struct FuncEntry {
7    pub name: String,
8    pub source_range: SourceRange,
9    pub visibility: Option<Visibility>,
10    pub signature: Option<String>,
11    pub docstring: Option<String>,
12    #[serde(rename = "async")]
13    pub is_async: bool,
14}
15
16#[derive(Debug, Clone, Serialize)]
17pub struct ClassEntry {
18    pub name: String,
19    pub source_range: SourceRange,
20    pub visibility: Option<Visibility>,
21    pub signature: Option<String>,
22    pub docstring: Option<String>,
23}
24
25#[derive(Debug, Clone, Serialize)]
26pub struct ObjectEntry {
27    pub name: String,
28    pub source_range: SourceRange,
29    pub visibility: Option<Visibility>,
30    pub signature: Option<String>,
31    pub docstring: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize)]
35pub struct InspectOutput {
36    pub funcs: Vec<FuncEntry>,
37    pub classes: Vec<ClassEntry>,
38    pub objects: Vec<ObjectEntry>,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44    use crate::model::{LineColumn, SourceRange, Visibility};
45    use serde_json;
46
47    fn sample_source_range() -> SourceRange {
48        SourceRange {
49            byte_start: 0,
50            byte_end: 5,
51            start: LineColumn { line: 1, column: 0 },
52            end: LineColumn { line: 1, column: 5 },
53        }
54    }
55
56    #[test]
57    fn inspect_output_empty_serializes() {
58        let output = InspectOutput {
59            funcs: vec![],
60            classes: vec![],
61            objects: vec![],
62        };
63        let json = serde_json::to_string(&output).unwrap();
64        assert_eq!(json, "{\"funcs\":[],\"classes\":[],\"objects\":[]}");
65    }
66
67    #[test]
68    fn func_entry_has_required_keys() {
69        let entry = FuncEntry {
70            name: "f".into(),
71            source_range: sample_source_range(),
72            visibility: None,
73            signature: None,
74            docstring: None,
75            is_async: false,
76        };
77        let val: serde_json::Value = serde_json::to_value(&entry).unwrap();
78        let obj = val.as_object().unwrap();
79        let expected_keys = [
80            "name",
81            "source_range",
82            "async",
83            "visibility",
84            "signature",
85            "docstring",
86        ];
87        for key in &expected_keys {
88            assert!(obj.contains_key(*key), "missing key: {key}");
89        }
90    }
91
92    #[test]
93    fn func_entry_async_field_renamed() {
94        let entry = FuncEntry {
95            name: "g".into(),
96            source_range: sample_source_range(),
97            visibility: None,
98            signature: None,
99            docstring: None,
100            is_async: true,
101        };
102        let val: serde_json::Value = serde_json::to_value(&entry).unwrap();
103        assert_eq!(val["async"], true);
104        assert!(val.get("is_async").is_none());
105    }
106
107    #[test]
108    fn class_entry_serialization() {
109        let entry = ClassEntry {
110            name: "MyClass".into(),
111            source_range: sample_source_range(),
112            visibility: Some(Visibility::Public),
113            signature: Some("class MyClass".into()),
114            docstring: Some("a class".into()),
115        };
116        let val: serde_json::Value = serde_json::to_value(&entry).unwrap();
117        assert_eq!(val["name"], "MyClass");
118        assert_eq!(val["visibility"], "public");
119        assert_eq!(val["signature"], "class MyClass");
120        assert_eq!(val["docstring"], "a class");
121        assert!(val["source_range"].is_object());
122    }
123
124    #[test]
125    fn object_entry_serialization() {
126        let entry = ObjectEntry {
127            name: "obj".into(),
128            source_range: sample_source_range(),
129            visibility: Some(Visibility::Private),
130            signature: None,
131            docstring: None,
132        };
133        let val: serde_json::Value = serde_json::to_value(&entry).unwrap();
134        assert_eq!(val["name"], "obj");
135        assert_eq!(val["visibility"], "private");
136        assert!(val["signature"].is_null());
137        assert!(val["docstring"].is_null());
138    }
139
140    #[test]
141    fn inspect_output_serde_roundtrip() {
142        let output = InspectOutput {
143            funcs: vec![FuncEntry {
144                name: "fn1".into(),
145                source_range: sample_source_range(),
146                visibility: Some(Visibility::Public),
147                signature: None,
148                docstring: None,
149                is_async: false,
150            }],
151            classes: vec![ClassEntry {
152                name: "Cls".into(),
153                source_range: sample_source_range(),
154                visibility: None,
155                signature: None,
156                docstring: None,
157            }],
158            objects: vec![ObjectEntry {
159                name: "obj".into(),
160                source_range: sample_source_range(),
161                visibility: None,
162                signature: None,
163                docstring: None,
164            }],
165        };
166        let json = serde_json::to_string(&output).unwrap();
167        let val: serde_json::Value = serde_json::from_str(&json).unwrap();
168        assert_eq!(val["funcs"][0]["name"], "fn1");
169        assert_eq!(val["classes"][0]["name"], "Cls");
170        assert_eq!(val["objects"][0]["name"], "obj");
171    }
172
173    #[test]
174    fn inspect_output_json_keys() {
175        let output = InspectOutput {
176            funcs: vec![],
177            classes: vec![],
178            objects: vec![],
179        };
180        let val: serde_json::Value = serde_json::to_value(&output).unwrap();
181        let keys: std::collections::HashSet<&str> = val
182            .as_object()
183            .unwrap()
184            .keys()
185            .map(|s| s.as_str())
186            .collect();
187        let expected: std::collections::HashSet<&str> =
188            ["funcs", "classes", "objects"].into_iter().collect();
189        assert_eq!(keys, expected);
190    }
191}