blob: fed7473d5784a6bfcf14ce2aa797e8d4dcb672f5 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use cm_json::Error;
use serde::ser::Serialize;
use serde_json::ser::{CompactFormatter, PrettyFormatter, Serializer};
use serde_json::Value;
use std::fs;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::from_utf8;
/// read in the json file from the given path, minify it if pretty is false or pretty-ify it if
/// pretty is true, and then write the results to stdout if output is None or to the given path if
/// output is Some.
pub fn format(file: &PathBuf, pretty: bool, output: Option<PathBuf>) -> Result<(), Error> {
let mut buffer = String::new();
fs::File::open(&file)?.read_to_string(&mut buffer)?;
let v: Value = serde_json::from_str(&buffer)
.map_err(|e| Error::parse(format!("Couldn't read input as JSON: {}", e)))?;
let mut res = Vec::new();
if pretty {
let mut ser = Serializer::with_formatter(&mut res, PrettyFormatter::with_indent(b" "));
v.serialize(&mut ser)
.map_err(|e| Error::parse(format!("Couldn't serialize JSON: {}", e)))?;
} else {
let mut ser = Serializer::with_formatter(&mut res, CompactFormatter {});
v.serialize(&mut ser)
.map_err(|e| Error::parse(format!("Couldn't serialize JSON: {}", e)))?;
}
if let Some(output_path) = output {
fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(output_path)?
.write_all(&res)?;
} else {
println!("{}", from_utf8(&res)?);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::Write;
use tempfile::TempDir;
fn count_num_newlines(input: &str) -> usize {
let mut ret = 0;
for c in input.chars() {
if c == '\n' {
ret += 1;
}
}
ret
}
#[test]
fn test_format_json() {
let example_json = r#"{ "program": { "binary": "bin/app"
}, "sandbox": {
"dev": [
"class/camera" ], "features": [ "deprecated-all-services",
"persistent-storage", "vulkan"] } }"#;
let tmp_dir = TempDir::new().unwrap();
let tmp_file_path = tmp_dir.path().join("input.json");
File::create(&tmp_file_path)
.unwrap()
.write_all(example_json.as_bytes())
.unwrap();
let output_file_path = tmp_dir.path().join("output.json");
// format as not-pretty
let result = format(&tmp_file_path, false, Some(output_file_path.clone()));
assert!(result.is_ok());
let mut buffer = String::new();
File::open(&output_file_path)
.unwrap()
.read_to_string(&mut buffer)
.unwrap();
assert_eq!(0, count_num_newlines(&buffer));
// format as pretty
let result = format(&tmp_file_path, true, Some(output_file_path.clone()));
assert!(result.is_ok());
let mut buffer = String::new();
File::open(&output_file_path)
.unwrap()
.read_to_string(&mut buffer)
.unwrap();
assert_eq!(14, count_num_newlines(&buffer));
}
#[test]
fn test_format_invalid_json_fails() {
let example_json = "{\"foo\": 1,}";
let tmp_dir = TempDir::new().unwrap();
let tmp_file_path = tmp_dir.path().join("input.json");
File::create(&tmp_file_path)
.unwrap()
.write_all(example_json.as_bytes())
.unwrap();
// format as not-pretty
let result = format(&tmp_file_path, false, None);
assert!(result.is_err());
}
}