1use crate::{Format, Result, TestBuffers, ToolIO, Writer};
6use serde::Serialize;
7use std::fmt::Display;
8use std::io::Write;
9
10pub struct JsonWriter<T> {
12 format: Option<Format>,
13 simple_writer: Writer,
14 _p: std::marker::PhantomData<fn(T)>,
15}
16
17impl<T> JsonWriter<T> {
18 pub fn new_buffers<'a, O, E>(format: Option<Format>, stdout: O, stderr: E) -> Self
21 where
22 O: Write + 'static,
23 E: Write + 'static,
24 {
25 let simple_writer = Writer::new_buffers(stdout, stderr);
26 let _p = Default::default();
27 Self { format, simple_writer, _p }
28 }
29
30 pub fn new(format: Option<Format>) -> Self {
34 let simple_writer = Writer::new();
35 let _p = Default::default();
36 Self { format, simple_writer, _p }
37 }
38
39 pub fn new_test(format: Option<Format>, test_buffers: &TestBuffers) -> Self {
42 Self::new_buffers(format, test_buffers.stdout.clone(), test_buffers.stderr.clone())
43 }
44
45 pub fn simple_writer(self) -> Writer {
48 self.simple_writer
49 }
50
51 pub fn stderr(&mut self) -> &'_ mut Box<dyn Write> {
52 self.simple_writer.stderr()
53 }
54}
55
56impl<T> JsonWriter<T>
57where
58 T: Serialize,
59{
60 pub fn machine_many<I: IntoIterator<Item = T>>(&mut self, output: I) -> Result<()> {
64 if self.format.is_some() {
65 for output in output {
66 self.machine(&output)?;
67 }
68 }
69 Ok(())
70 }
71
72 pub fn machine(&mut self, output: &T) -> Result<()> {
76 if let Some(format) = self.format {
77 format_output(format, &mut self.simple_writer, output)
78 } else {
79 Ok(())
80 }
81 }
82
83 pub fn machine_or<D: Display>(&mut self, value: &T, or: D) -> Result<()> {
86 match self.format {
87 Some(format) => format_output(format, &mut self.simple_writer, value)?,
88 None => writeln!(self, "{or}")?,
89 }
90 Ok(())
91 }
92
93 pub fn machine_or_write<D: Display>(&mut self, value: &T, or: D) -> Result<()> {
96 match self.format {
97 Some(format) => format_output(format, &mut self.simple_writer, value)?,
98 None => write!(self, "{or}")?,
99 }
100 Ok(())
101 }
102
103 pub fn machine_or_else<F, R>(&mut self, value: &T, f: F) -> Result<()>
107 where
108 F: FnOnce() -> R,
109 R: Display,
110 {
111 match self.format {
112 Some(format) => format_output(format, &mut self.simple_writer, value)?,
113 None => writeln!(self, "{}", f())?,
114 }
115 Ok(())
116 }
117
118 pub fn format(&self) -> Option<Format> {
119 self.format
120 }
121
122 pub fn formatted<J: Serialize>(&mut self, output: &J) -> Result<()> {
123 if let Some(format) = self.format {
124 format_output(format, &mut self.simple_writer, output)
125 } else {
126 Ok(())
127 }
128 }
129}
130
131pub fn format_output<W: Write, T>(format: Format, mut out: W, output: &T) -> Result<()>
132where
133 T: Serialize,
134{
135 match format {
136 Format::Json => {
137 serde_json::to_writer(&mut out, output)?;
138 writeln!(out)?;
139 out.flush()?;
140 }
141 Format::JsonPretty => {
142 serde_json::to_writer_pretty(&mut out, output)?;
143 }
144 }
145 Ok(())
146}
147
148impl<T> ToolIO for JsonWriter<T>
149where
150 T: Serialize,
151{
152 type OutputItem = T;
153
154 fn is_machine_supported() -> bool {
155 true
156 }
157
158 fn is_machine(&self) -> bool {
159 self.format.is_some()
160 }
161
162 fn stderr(&mut self) -> &'_ mut Box<dyn Write> {
163 self.stderr()
164 }
165
166 fn item(&mut self, value: &T) -> Result<()>
167 where
168 T: Display,
169 {
170 if self.is_machine() {
171 self.machine(value)
172 } else {
173 self.line(value)
174 }
175 }
176}
177
178impl<T> Write for JsonWriter<T>
179where
180 T: Serialize,
181{
182 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
183 if self.format.is_some() {
184 Ok(buf.len())
185 } else {
186 self.simple_writer.write(buf)
187 }
188 }
189
190 fn flush(&mut self) -> std::io::Result<()> {
191 if self.format.is_some() {
192 Ok(())
193 } else {
194 self.simple_writer.flush()
195 }
196 }
197}
198#[cfg(test)]
199mod test {
200 use super::*;
201
202 #[test]
203 fn test_not_machine_is_ok() {
204 let test_buffers = TestBuffers::default();
205 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
206 let res = writer.machine(&"ehllo");
207 assert!(res.is_ok());
208 }
209
210 #[test]
211 fn test_machine_valid_json_is_ok() {
212 let test_buffers = TestBuffers::default();
213 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
214 let res = writer.machine(&"ehllo");
215 assert!(res.is_ok());
216 }
217
218 #[test]
219 fn writer_implements_write() {
220 let test_buffers = TestBuffers::default();
221 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
222 writer.write_all(b"foobar").unwrap();
223
224 let (stdout, stderr) = test_buffers.into_strings();
225 assert_eq!(stdout, "foobar");
226 assert_eq!(stderr, "");
227 }
228
229 #[test]
230 fn writer_implements_write_ignored_on_machine() {
231 let test_buffers = TestBuffers::default();
232 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
233 writer.write_all(b"foobar").unwrap();
234
235 let (stdout, stderr) = test_buffers.into_strings();
236 assert_eq!(stdout, "");
237 assert_eq!(stderr, "");
238 }
239
240 #[test]
241 fn test_item_for_test_as_machine() {
242 let test_buffers = TestBuffers::default();
243 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
244 writer.item(&"hello").unwrap();
245 writer.machine_or(&"hello again", "but what if").unwrap();
246 writer.machine_or_else(&"hello forever", || "but what if else").unwrap();
247
248 assert_eq!(
249 test_buffers.into_stdout_str(),
250 "\"hello\"\n\"hello again\"\n\"hello forever\"\n"
251 );
252 }
253
254 #[test]
255 fn test_item_for_test_as_not_machine() {
256 let test_buffers = TestBuffers::default();
257 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
258 writer.item(&"hello").unwrap();
259 writer.machine_or(&"hello again", "but what if").unwrap();
260 writer.machine_or_else(&"hello forever", || "but what if else").unwrap();
261
262 assert_eq!(test_buffers.into_stdout_str(), "hello\nbut what if\nbut what if else\n");
263 }
264
265 #[test]
266 fn test_machine_for_test() {
267 let test_buffers = TestBuffers::default();
268 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
269 writer.machine(&"hello").unwrap();
270
271 assert_eq!(test_buffers.into_stdout_str(), "\"hello\"\n");
272 }
273
274 #[test]
275 fn test_not_machine_for_test_is_empty() {
276 let test_buffers = TestBuffers::default();
277 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
278 writer.machine(&"hello").unwrap();
279
280 assert!(test_buffers.into_stdout_str().is_empty());
281 }
282
283 #[test]
284 fn test_machine_makes_is_machine_true() {
285 let test_buffers = TestBuffers::default();
286 let writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
287 assert!(writer.is_machine());
288 }
289
290 #[test]
291 fn test_not_machine_makes_is_machine_false() {
292 let test_buffers = TestBuffers::default();
293 let writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
294 assert!(!writer.is_machine());
295 }
296
297 #[test]
298 fn line_writer_for_machine_is_ok() {
299 let test_buffers = TestBuffers::default();
300 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
301 writer.line("hello").unwrap();
302
303 let (stdout, stderr) = test_buffers.into_strings();
304 assert_eq!(stdout, "");
305 assert_eq!(stderr, "");
306 }
307
308 #[test]
309 fn writer_write_for_machine_is_ok() {
310 let test_buffers = TestBuffers::default();
311 let mut writer: JsonWriter<&str> = JsonWriter::new_test(Some(Format::Json), &test_buffers);
312 writer.print("foobar").unwrap();
313
314 let (stdout, stderr) = test_buffers.into_strings();
315 assert_eq!(stdout, "");
316 assert_eq!(stderr, "");
317 }
318
319 #[test]
320 fn writer_print_output_has_no_newline() {
321 let test_buffers = TestBuffers::default();
322 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
323 writer.print("foobar").unwrap();
324
325 let (stdout, stderr) = test_buffers.into_strings();
326 assert_eq!(stdout, "foobar");
327 assert_eq!(stderr, "");
328 }
329
330 #[test]
331 fn writing_errors_goes_to_the_right_stream() {
332 let test_buffers = TestBuffers::default();
333 let mut writer: JsonWriter<&str> = JsonWriter::new_test(None, &test_buffers);
334 writeln!(writer.stderr(), "hello").unwrap();
335
336 let (stdout, stderr) = test_buffers.into_strings();
337 assert_eq!(stdout, "");
338 assert_eq!(stderr, "hello\n");
339 }
340
341 #[test]
342 fn test_machine_writes_pretty_json() {
343 let test_buffers = TestBuffers::default();
344 let mut writer: JsonWriter<serde_json::Value> =
345 JsonWriter::new_test(Some(Format::JsonPretty), &test_buffers);
346 let test_input = serde_json::json!({
347 "object1": {
348 "line1": "hello",
349 "line2": "foobar"
350 }
351 });
352 writer.machine(&test_input).unwrap();
353
354 assert_eq!(
355 test_buffers.into_stdout_str(),
356 r#"{
357 "object1": {
358 "line1": "hello",
359 "line2": "foobar"
360 }
361}"#
362 );
363 }
364}