Skip to main content

codama_nodes/
program_node.rs

1use crate::{
2    AccountNode, CamelCaseString, DefinedTypeNode, Docs, ErrorNode, EventNode, HasName,
3    InstructionNode, PdaNode,
4};
5use codama_nodes_derive::node;
6
7#[node]
8#[derive(Default)]
9pub struct ProgramNode {
10    // Data.
11    pub name: CamelCaseString,
12    pub public_key: String,
13    pub version: String,
14    #[serde(skip_serializing_if = "crate::is_default")]
15    pub origin: Option<String>, // 'anchor' | 'shank'. Soon to be deprecated.
16    #[serde(default, skip_serializing_if = "crate::is_default")]
17    pub docs: Docs,
18
19    // Children.
20    #[serde(default)]
21    pub accounts: Vec<AccountNode>,
22    #[serde(default)]
23    pub instructions: Vec<InstructionNode>,
24    #[serde(default)]
25    pub defined_types: Vec<DefinedTypeNode>,
26    #[serde(default)]
27    pub pdas: Vec<PdaNode>,
28    #[serde(default)]
29    pub events: Vec<EventNode>,
30    #[serde(default)]
31    pub errors: Vec<ErrorNode>,
32}
33
34impl ProgramNode {
35    pub fn new<T: Into<CamelCaseString>, U: Into<String>>(name: T, public_key: U) -> Self {
36        Self {
37            name: name.into(),
38            public_key: public_key.into(),
39            ..Default::default()
40        }
41    }
42
43    pub fn set_version<T: Into<String>>(mut self, version: T) -> Self {
44        self.version = version.into();
45        self
46    }
47
48    pub fn add_account(mut self, account: AccountNode) -> Self {
49        self.accounts.push(account);
50        self
51    }
52
53    pub fn add_instruction(mut self, instruction: InstructionNode) -> Self {
54        self.instructions.push(instruction);
55        self
56    }
57
58    pub fn add_defined_type(mut self, defined_type: DefinedTypeNode) -> Self {
59        self.defined_types.push(defined_type);
60        self
61    }
62
63    pub fn add_pda(mut self, pda: PdaNode) -> Self {
64        self.pdas.push(pda);
65        self
66    }
67
68    pub fn add_event(mut self, event: EventNode) -> Self {
69        self.events.push(event);
70        self
71    }
72
73    pub fn add_error(mut self, error: ErrorNode) -> Self {
74        self.errors.push(error);
75        self
76    }
77}
78
79impl HasName for ProgramNode {
80    fn name(&self) -> &CamelCaseString {
81        &self.name
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use pretty_assertions::assert_eq;
89
90    #[test]
91    fn new() {
92        let node = ProgramNode::new("my_program", "1234..5678");
93        assert_eq!(node.name, CamelCaseString::new("myProgram"));
94        assert_eq!(node.public_key, "1234..5678".to_string());
95        assert_eq!(node.version, "".to_string());
96        assert_eq!(node.origin, None);
97        assert_eq!(node.docs, Docs::default());
98        assert_eq!(node.accounts, vec![]);
99        assert_eq!(node.instructions, vec![]);
100        assert_eq!(node.defined_types, vec![]);
101        assert_eq!(node.pdas, vec![]);
102        assert_eq!(node.events, vec![]);
103        assert_eq!(node.errors, vec![]);
104    }
105
106    #[test]
107    fn default_program() {
108        let node = ProgramNode::default();
109        assert_eq!(node.name, CamelCaseString::new(""));
110        assert_eq!(node.public_key, "".to_string());
111        assert_eq!(node.version, "".to_string());
112        assert_eq!(node.origin, None);
113        assert_eq!(node.docs, Docs::default());
114        assert_eq!(node.accounts, vec![]);
115        assert_eq!(node.instructions, vec![]);
116        assert_eq!(node.defined_types, vec![]);
117        assert_eq!(node.pdas, vec![]);
118        assert_eq!(node.events, vec![]);
119        assert_eq!(node.errors, vec![]);
120    }
121
122    #[test]
123    fn direct_instantiation() {
124        let node = ProgramNode {
125            name: "myProgram".into(),
126            public_key: "1234..5678".into(),
127            version: "1.2.3".into(),
128            ..ProgramNode::default()
129        };
130        assert_eq!(node.name, CamelCaseString::new("myProgram"));
131        assert_eq!(node.public_key, "1234..5678".to_string());
132        assert_eq!(node.version, "1.2.3".to_string());
133        assert_eq!(node.origin, None);
134        assert_eq!(node.docs, Docs::default());
135        assert_eq!(node.accounts, vec![]);
136        assert_eq!(node.instructions, vec![]);
137        assert_eq!(node.defined_types, vec![]);
138        assert_eq!(node.pdas, vec![]);
139        assert_eq!(node.events, vec![]);
140        assert_eq!(node.errors, vec![]);
141    }
142
143    #[test]
144    fn to_json() {
145        let node = ProgramNode {
146            name: "myProgram".into(),
147            public_key: "1234..5678".into(),
148            version: "1.2.3".into(),
149            ..ProgramNode::default()
150        };
151        let json = serde_json::to_string(&node).unwrap();
152        assert_eq!(
153            json,
154            r#"{"kind":"programNode","name":"myProgram","publicKey":"1234..5678","version":"1.2.3","accounts":[],"instructions":[],"definedTypes":[],"pdas":[],"events":[],"errors":[]}"#
155        );
156    }
157
158    #[test]
159    fn from_json() {
160        let json = r#"{"kind":"programNode","name":"myProgram","publicKey":"1234..5678","version":"1.2.3"}"#;
161        let node: ProgramNode = serde_json::from_str(json).unwrap();
162        assert_eq!(
163            node,
164            ProgramNode {
165                name: "myProgram".into(),
166                public_key: "1234..5678".into(),
167                version: "1.2.3".into(),
168                ..ProgramNode::default()
169            }
170        );
171    }
172}