1use crate::common::helpers::{Context, ValidateWithContext, validate_required_string};
4use crate::v3_0::external_documentation::ExternalDocumentation;
5use crate::v3_0::spec::Spec;
6use serde::{Deserialize, Serialize};
7use std::collections::BTreeMap;
8
9#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
19#[serde(rename_all = "camelCase")]
20pub struct Tag {
21 pub name: String,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
27 pub description: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub external_docs: Option<ExternalDocumentation>,
32
33 #[serde(flatten)]
37 #[serde(with = "crate::common::extensions")]
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub extensions: Option<BTreeMap<String, serde_json::Value>>,
40}
41
42impl ValidateWithContext<Spec> for Tag {
43 fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
44 validate_required_string(&self.name, ctx, format!("{path}.name"));
45 if let Some(doc) = &self.external_docs {
46 doc.validate_with_context(ctx, format!("{path}.externalDocs"));
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn deserialize() {
57 assert_eq!(
58 serde_json::from_value::<Tag>(serde_json::json!({
59 "name": "pet",
60 "description": "Pets operations",
61 "externalDocs": {
62 "description": "Find more info here",
63 "url": "https://example.com/about"
64 },
65 }))
66 .unwrap(),
67 Tag {
68 name: String::from("pet"),
69 description: Some(String::from("Pets operations")),
70 external_docs: Some(ExternalDocumentation {
71 description: Some(String::from("Find more info here")),
72 url: String::from("https://example.com/about"),
73 ..Default::default()
74 }),
75 ..Default::default()
76 },
77 "deserialize name, description and externalDocs"
78 );
79
80 assert_eq!(
81 serde_json::from_value::<Tag>(serde_json::json!({
82 "name": "pet",
83 "description": "Pets operations",
84 }))
85 .unwrap(),
86 Tag {
87 name: String::from("pet"),
88 description: Some(String::from("Pets operations")),
89 ..Default::default()
90 },
91 "deserialize name and description"
92 );
93
94 assert_eq!(
95 serde_json::from_value::<Tag>(serde_json::json!({
96 "name": "pet",
97 }))
98 .unwrap(),
99 Tag {
100 name: String::from("pet"),
101 ..Default::default()
102 },
103 "deserialize name only"
104 );
105 }
106
107 #[test]
108 fn serialize() {
109 assert_eq!(
110 serde_json::to_value(Tag {
111 name: String::from("pet"),
112 description: Some(String::from("Pets operations")),
113 external_docs: Some(ExternalDocumentation {
114 description: Some(String::from("Find more info here")),
115 url: String::from("https://example.com/about"),
116 ..Default::default()
117 }),
118 ..Default::default()
119 })
120 .unwrap(),
121 serde_json::json!({
122 "name": "pet",
123 "description":"Pets operations",
124 "externalDocs": {
125 "description": "Find more info here",
126 "url": "https://example.com/about"
127 },
128 }),
129 "serialize name, description and externalDocs",
130 );
131
132 assert_eq!(
133 serde_json::to_value(Tag {
134 name: String::from("pet"),
135 description: Some(String::from("Pets operations")),
136 ..Default::default()
137 })
138 .unwrap(),
139 serde_json::json!({
140 "name": "pet",
141 "description":"Pets operations",
142 }),
143 "serialize name and description",
144 );
145
146 assert_eq!(
147 serde_json::to_value(Tag {
148 name: String::from("pet"),
149 ..Default::default()
150 })
151 .unwrap(),
152 serde_json::json!({
153 "name": "pet",
154 }),
155 "serialize name only",
156 );
157 }
158
159 #[test]
160 fn validate() {
161 let spec = Spec::default();
162 let mut ctx = Context::new(&spec, Default::default());
163 Tag {
164 name: String::from("pet"),
165 description: Some(String::from("Pets operations")),
166 external_docs: Some(ExternalDocumentation {
167 description: Some(String::from("Find more info here")),
168 url: String::from("https://example.com/about"),
169 ..Default::default()
170 }),
171 ..Default::default()
172 }
173 .validate_with_context(&mut ctx, String::from("tag"));
174 assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
175
176 Tag {
177 name: String::from("pet"),
178 description: Some(String::from("Pets operations")),
179 ..Default::default()
180 }
181 .validate_with_context(&mut ctx, String::from("tag"));
182 assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
183
184 Tag {
185 name: String::from("pet"),
186 ..Default::default()
187 }
188 .validate_with_context(&mut ctx, String::from("tag"));
189 assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
190
191 Tag {
192 ..Default::default()
193 }
194 .validate_with_context(&mut ctx, String::from("tag"));
195 assert_eq!(
196 ctx.errors,
197 vec!["tag.name: must not be empty"],
198 "name error: {:?}",
199 ctx.errors
200 );
201 }
202}