Skip to main content

rain_metadata/cli/schema/
show.rs

1use clap::Parser;
2use std::path::PathBuf;
3use schemars::schema_for;
4use crate::meta::KnownMeta;
5use crate::cli::output::SupportedOutputEncoding;
6
7#[derive(Parser)]
8pub struct Show {
9    /// One of a set of known JSON schemas that can be produced to match a subset
10    /// of the validation performed on known metas. Additional validation beyond
11    /// what can be expressed by JSON schema is performed when parsing and
12    /// validating metadata.
13    #[arg(value_parser = clap::value_parser!(KnownMeta))]
14    schema: KnownMeta,
15    /// If provided the schema will be written to the given path instead of
16    /// stdout.
17    #[arg(short, long)]
18    output_path: Option<PathBuf>,
19    /// If true the schema will be pretty printed. Defaults to false.
20    #[arg(short, long)]
21    pretty_print: bool,
22}
23
24pub fn show(s: Show) -> anyhow::Result<()> {
25    let schema_json = match s.schema {
26        KnownMeta::AuthoringMetaV1 => schema_for!(crate::meta::types::authoring::v1::AuthoringMeta),
27        KnownMeta::SolidityAbiV2 => {
28            schema_for!(crate::meta::types::solidity_abi::v2::SolidityAbiMeta)
29        }
30        KnownMeta::InterpreterCallerMetaV1 => {
31            schema_for!(crate::meta::types::interpreter_caller::v1::InterpreterCallerMeta)
32        }
33        other => return Err(anyhow::anyhow!("Unsupported for {} meta", other)),
34    };
35    let schema_string = if s.pretty_print {
36        serde_json::to_string_pretty(&schema_json)?
37    } else {
38        serde_json::to_string(&schema_json)?
39    };
40
41    crate::cli::output::output(
42        &s.output_path,
43        SupportedOutputEncoding::Binary,
44        schema_string.as_bytes(),
45    )
46}
47
48#[cfg(all(test, not(target_family = "wasm")))]
49mod tests {
50    use super::*;
51
52    fn show_to_string(schema: KnownMeta, pretty_print: bool) -> anyhow::Result<String> {
53        let file = tempfile::NamedTempFile::new().unwrap();
54        let path = file.path().to_path_buf();
55        show(Show {
56            schema,
57            output_path: Some(path.clone()),
58            pretty_print,
59        })?;
60        Ok(std::fs::read_to_string(&path).unwrap())
61    }
62
63    /// Each supported meta produces its own schema; compact output by
64    /// default (no newlines).
65    #[test]
66    fn test_show_authoring_v1_schema_compact() {
67        let s = show_to_string(KnownMeta::AuthoringMetaV1, false).unwrap();
68        let v: serde_json::Value = serde_json::from_str(&s).unwrap();
69        assert!(s.contains("AuthoringMeta"), "{}", v["title"]);
70        assert!(!s.contains('\n'));
71    }
72
73    /// OpV1 is a known meta with no schema here, so show refuses it rather
74    /// than producing one.
75    #[test]
76    fn test_show_refuses_op_v1() {
77        assert!(show_to_string(KnownMeta::OpV1, false).is_err());
78    }
79
80    /// The pretty flag pretty-prints the same schema.
81    #[test]
82    fn test_show_pretty_print() {
83        let s = show_to_string(KnownMeta::AuthoringMetaV1, true).unwrap();
84        assert!(s.starts_with("{\n"));
85        let v: serde_json::Value = serde_json::from_str(&s).unwrap();
86        assert!(v["title"].is_string());
87    }
88
89    /// All three supported arms return the schema of their own meta type.
90    #[test]
91    fn test_show_supported_schemas_are_distinct() {
92        let authoring = show_to_string(KnownMeta::AuthoringMetaV1, false).unwrap();
93        assert!(authoring.contains("AuthoringMeta"));
94        let solidity = show_to_string(KnownMeta::SolidityAbiV2, false).unwrap();
95        assert!(solidity.contains("SolidityAbi"));
96        let caller = show_to_string(KnownMeta::InterpreterCallerMetaV1, false).unwrap();
97        assert!(caller.contains("InterpreterCallerMeta"));
98        for pair in [
99            (&authoring, &solidity),
100            (&authoring, &caller),
101            (&solidity, &caller),
102        ] {
103            assert_ne!(pair.0, pair.1);
104        }
105    }
106
107    /// Metas without a JSON schema error with the exact unsupported
108    /// message.
109    #[test]
110    fn test_show_unsupported_meta_error() {
111        let file = tempfile::NamedTempFile::new().unwrap();
112        let err = show(Show {
113            schema: KnownMeta::DotrainV1,
114            output_path: Some(file.path().to_path_buf()),
115            pretty_print: false,
116        })
117        .unwrap_err();
118        assert_eq!(err.to_string(), "Unsupported for dotrain-v1 meta");
119    }
120}