blob: d09d683f575421f1ad3cd2bceb6eace4613826a1 [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 crate::error::Error;
use crate::util;
use cml::format_cml;
use std::fs;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::from_utf8;
/// Formats a CML file.
///
/// The file must be valid JSON5, but does not have to be valid CML.
///
/// If `output` is not given, prints the result to stdout.
///
/// See [format_cml] for current style conventions.
pub(crate) fn format(file: &PathBuf, output: Option<PathBuf>) -> Result<(), Error> {
let mut buffer = String::new();
fs::File::open(&file)?.read_to_string(&mut buffer)?;
let res = format_cml(&buffer, &file)?;
if let Some(output_path) = output {
util::ensure_directory_exists(&output_path)?;
fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(output_path)?
.write_all(&res)?;
} else {
// Print without a newline because the formatters should have already added a final newline
// (required by most software style guides).
print!("{}", from_utf8(&res)?);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use tempfile::TempDir;
#[test]
fn test_format_cml() {
let example_cml = r##"{
offer: [
{
runner: "elf",
},
{
from: "framework",
to: "#elements",
protocol: "/svc/fuchsia.component.Realm",
},
{
to: "#elements",
protocol: [
"/svc/fuchsia.logger.LogSink",
"/svc/fuchsia.cobalt.LoggerFactory",
],
from: "realm",
},
],
collections: [
{
durability: "transient",
name: "elements",
}
],
use: [
{
protocol: "/svc/fuchsia.component.Realm",
from: "framework",
},
{
from: "realm",
to: "#elements",
protocol: [
"/svc/fuchsia.logger.LogSink",
"/svc/fuchsia.cobalt.LoggerFactory",
],
},
],
children: [
],
program: {
args: [ "--zarg_first", "zoo_opt", "--arg3", "and_arg3_value" ],
binary: "bin/session_manager",
runner: "elf",
},
}"##;
let expected = r##"{
program: {
runner: "elf",
binary: "bin/session_manager",
args: [
"--zarg_first",
"zoo_opt",
"--arg3",
"and_arg3_value",
],
},
children: [],
collections: [
{
name: "elements",
durability: "transient",
},
],
use: [
{
protocol: "/svc/fuchsia.component.Realm",
from: "framework",
},
{
protocol: [
"/svc/fuchsia.cobalt.LoggerFactory",
"/svc/fuchsia.logger.LogSink",
],
from: "realm",
to: "#elements",
},
],
offer: [
{ runner: "elf" },
{
protocol: "/svc/fuchsia.component.Realm",
from: "framework",
to: "#elements",
},
{
protocol: [
"/svc/fuchsia.cobalt.LoggerFactory",
"/svc/fuchsia.logger.LogSink",
],
from: "realm",
to: "#elements",
},
],
}
"##;
let tmp_dir = TempDir::new().unwrap();
let tmp_file_path = tmp_dir.path().join("input.cml");
File::create(&tmp_file_path).unwrap().write_all(example_cml.as_bytes()).unwrap();
let output_file_path = tmp_dir.path().join("output.cml");
let result = format(&tmp_file_path, 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!(buffer, expected);
}
#[test]
fn test_format_cml_with_environments() {
let example_cml = r##"{
include: [ "src/sys/test_manager/meta/common.shard.cml" ],
environments: [
{
name: "test-env",
extends: "realm",
runners: [
{
from: "#elf_test_runner",
runner: "elf_test_runner",
},
{
from: "#gtest_runner",
runner: "gtest_runner",
},
{
from: "#rust_test_runner",
runner: "rust_test_runner",
},
{
from: "#go_test_runner",
runner: "go_test_runner",
},
{
from: "#fuchsia_component_test_framework_intermediary",
runner: "fuchsia_component_test_mocks",
},
],
resolvers: [
{
from: "#fuchsia_component_test_framework_intermediary",
resolver: "fuchsia_component_test_registry",
scheme: "fuchsia-component-test-registry",
},
],
},
],
}
"##;
let expected = r##"{
include: [ "src/sys/test_manager/meta/common.shard.cml" ],
environments: [
{
name: "test-env",
extends: "realm",
runners: [
{
runner: "elf_test_runner",
from: "#elf_test_runner",
},
{
runner: "gtest_runner",
from: "#gtest_runner",
},
{
runner: "rust_test_runner",
from: "#rust_test_runner",
},
{
runner: "go_test_runner",
from: "#go_test_runner",
},
{
runner: "fuchsia_component_test_mocks",
from: "#fuchsia_component_test_framework_intermediary",
},
],
resolvers: [
{
resolver: "fuchsia_component_test_registry",
from: "#fuchsia_component_test_framework_intermediary",
scheme: "fuchsia-component-test-registry",
},
],
},
],
}
"##;
let tmp_dir = TempDir::new().unwrap();
let tmp_file_path = tmp_dir.path().join("input.cml");
File::create(&tmp_file_path).unwrap().write_all(example_cml.as_bytes()).unwrap();
let output_file_path = tmp_dir.path().join("output.cml");
let result = format(&tmp_file_path, 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!(buffer, expected);
}
#[test]
fn test_format_valid_json5() {
let example_json5 = "{\"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_json5.as_bytes()).unwrap();
let result = format(&tmp_file_path, None);
assert!(result.is_ok());
}
#[test]
fn test_format_invalid_json5() {
let invalid_json5 = "{\"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(invalid_json5.as_bytes()).unwrap();
let result = format(&tmp_file_path, None);
assert!(result.is_err());
}
}