#![allow(dead_code, deprecated)]
use indexmap::{IndexMap, IndexSet};
use schematic::schema::{SchemaGenerator, TemplateOptions};
use schematic::*;
use starbase_sandbox::{assert_snapshot, create_empty_sandbox};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
derive_enum!(
#[derive(ConfigEnum, Default)]
pub enum BasicEnum {
#[default]
Foo,
Bar,
Baz,
}
);
derive_enum!(
#[derive(ConfigEnum, Default)]
pub enum FallbackEnum {
#[default]
Foo,
Bar,
Baz,
#[variant(fallback)]
Other(String),
}
);
#[derive(Clone, Config)]
pub struct AnotherConfig {
opt: Option<String>,
enums: Option<BasicEnum>,
}
#[derive(Clone, Config)]
#[deprecated]
struct GenConfig {
boolean: bool,
string: String,
number: usize,
float32: f32,
float64: f64,
vector: Vec<String>,
map: HashMap<String, u64>,
enums: BasicEnum,
fallback_enum: FallbackEnum,
#[setting(nested)]
nested: AnotherConfig,
#[setting(flatten)]
flattened: HashMap<String, serde_json::Value>,
date: chrono::NaiveDate,
datetime: chrono::NaiveDateTime,
decimal: rust_decimal::Decimal,
time: chrono::NaiveTime,
path: PathBuf,
regex: RegexSetting,
rel_path: relative_path::RelativePathBuf,
url: Option<url::Url>,
uuid: uuid::Uuid,
version: Option<semver::Version>,
version2: VersionSetting,
version_req: semver::VersionReq,
json_value: serde_json::Value,
toml_value: Option<toml::Value>,
yaml_value: serde_norway::Value,
indexmap: IndexMap<String, String>,
indexset: Option<IndexSet<String>>,
}
#[derive(Clone, Config)]
#[config(env_prefix = "ENV_PREFIX_")]
pub struct TwoDepthConfig {
opt: Option<String>,
skipped: String,
}
#[derive(Clone, Config)]
pub struct OneDepthConfig {
#[setting(nested)]
two: TwoDepthConfig,
#[setting(skip)]
skipped: String,
}
#[derive(Clone, Config)]
struct TemplateConfig {
#[setting(env = "TEMPLATE_BOOLEAN")]
boolean: bool,
#[setting(default = "abc")]
string: String,
number: usize,
#[deprecated]
float32: f32,
#[setting(default = 1.23)]
float64: f64,
vector: Vec<String>,
map: HashMap<String, u64>,
#[deprecated = "Dont use enums!"]
enums: BasicEnum,
fallback_enum: FallbackEnum,
#[setting(nested)]
nested: AnotherConfig,
#[setting(nested)]
one: OneDepthConfig,
skipped: String,
#[setting(nested)]
expand_array: Vec<AnotherConfig>,
expand_array_primitive: Vec<usize>,
empty_array: Vec<usize>,
#[setting(nested)]
expand_object: HashMap<String, AnotherConfig>,
expand_object_primitive: HashMap<String, usize>,
empty_object: HashMap<String, usize>,
}
fn create_generator() -> SchemaGenerator {
let mut generator = SchemaGenerator::default();
generator.add::<GenConfig>();
generator
}
fn create_template_generator() -> SchemaGenerator {
let mut generator = SchemaGenerator::default();
generator.add::<TemplateConfig>();
generator
}
fn create_template_options() -> TemplateOptions {
TemplateOptions {
comment_fields: vec!["float32".into(), "map".into()],
expand_fields: vec![
"expandArray".into(),
"expandArrayPrimitive".into(),
"expandObject".into(),
"expandObjectPrimitive".into(),
],
hide_fields: vec!["skipped".into(), "one.two.skipped".into()],
..TemplateOptions::default()
}
}
#[cfg(feature = "renderer_json_schema")]
mod json_schema {
use super::*;
use schematic::schema::json_schema::*;
#[test]
fn defaults() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_generator()
.generate(&file, JsonSchemaRenderer::default())
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn partials() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
let mut generator = create_generator();
generator.add::<PartialGenConfig>();
generator
.generate(&file, JsonSchemaRenderer::default())
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn not_required() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_generator()
.generate(
&file,
JsonSchemaRenderer::new(JsonSchemaOptions {
mark_struct_fields_required: false,
..JsonSchemaOptions::default()
}),
)
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn with_titles() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_generator()
.generate(
&file,
JsonSchemaRenderer::new(JsonSchemaOptions {
set_field_name_as_title: true,
..JsonSchemaOptions::default()
}),
)
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn with_markdown_descs() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_generator()
.generate(
&file,
JsonSchemaRenderer::new(JsonSchemaOptions {
markdown_description: true,
..JsonSchemaOptions::default()
}),
)
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
}
#[cfg(all(feature = "renderer_template", feature = "json"))]
mod template_json {
use super::*;
use schematic::schema::*;
#[test]
fn defaults() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_template_generator()
.generate(&file, JsoncTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn without_comments() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_template_generator()
.generate(&file, JsonTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn only_fields() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_template_generator()
.generate(
&file,
JsoncTemplateRenderer::new({
let mut options = create_template_options();
options.only_fields.push("float32".into());
options.only_fields.push("string".into());
options
}),
)
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn custom_values() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.json");
create_template_generator()
.generate(
&file,
JsoncTemplateRenderer::new({
let mut options = create_template_options();
options.custom_values.insert(
"expandArrayPrimitive".into(),
Schema::array(ArrayType::new(Schema::integer(IntegerType::new_unsigned(
IntegerKind::Usize,
123456,
)))),
);
options.custom_values.insert(
"nested.opt".into(),
Schema::union(UnionType::new_any([
Schema::string(StringType::new("custom nested value")),
Schema::null(),
])),
);
options.custom_values.insert(
"string".into(),
Schema::string(StringType::new("custom value")),
);
options
}),
)
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
}
#[cfg(all(feature = "renderer_template", feature = "pkl"))]
mod template_pkl {
use super::*;
use schematic::schema::*;
#[test]
fn defaults() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.pkl");
create_template_generator()
.generate(&file, PklTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
}
#[cfg(all(feature = "renderer_template", feature = "toml"))]
mod template_toml {
use super::*;
use schematic::schema::*;
#[test]
fn defaults() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.toml");
create_template_generator()
.generate(&file, TomlTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
}
#[cfg(all(feature = "renderer_template", feature = "yaml"))]
mod template_yaml {
use super::*;
use schematic::schema::*;
#[test]
fn defaults() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.yaml");
create_template_generator()
.generate(&file, YamlTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn issue_139() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("schema.yaml");
#[derive(Debug, Clone, Config)]
pub struct ProjectConfig {
#[setting(nested)]
pub nested: NestedConfig,
}
#[derive(Debug, Clone, Config)]
pub struct NestedConfig {
#[setting(default = true)]
pub one: bool,
}
let mut generator = SchemaGenerator::default();
generator.add::<ProjectConfig>();
generator
.generate(&file, YamlTemplateRenderer::new(create_template_options()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
}
#[cfg(feature = "renderer_typescript")]
mod typescript {
use super::*;
use schematic::schema::typescript::*;
fn generate(options: TypeScriptOptions) -> String {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("types.ts");
create_generator()
.generate(&file, TypeScriptRenderer::new(options))
.unwrap();
fs::read_to_string(file).unwrap()
}
#[test]
fn defaults() {
assert_snapshot!(generate(TypeScriptOptions::default()));
}
#[test]
fn partials() {
let sandbox = create_empty_sandbox();
let file = sandbox.path().join("types.ts");
let mut generator = create_generator();
generator.add::<PartialGenConfig>();
generator
.generate(&file, TypeScriptRenderer::new(TypeScriptOptions::default()))
.unwrap();
assert_snapshot!(fs::read_to_string(file).unwrap());
}
#[test]
fn enums() {
assert_snapshot!(generate(TypeScriptOptions {
enum_format: EnumFormat::Enum,
..TypeScriptOptions::default()
}));
}
#[test]
fn value_enums() {
assert_snapshot!(generate(TypeScriptOptions {
enum_format: EnumFormat::ValuedEnum,
..TypeScriptOptions::default()
}));
}
#[test]
fn const_enums() {
assert_snapshot!(generate(TypeScriptOptions {
const_enum: true,
enum_format: EnumFormat::Enum,
..TypeScriptOptions::default()
}));
}
#[test]
fn object_aliases() {
assert_snapshot!(generate(TypeScriptOptions {
object_format: ObjectFormat::Type,
..TypeScriptOptions::default()
}));
}
#[test]
fn props_optional() {
assert_snapshot!(generate(TypeScriptOptions {
property_format: PropertyFormat::Optional,
..TypeScriptOptions::default()
}));
}
#[test]
fn props_optional_undefined() {
assert_snapshot!(generate(TypeScriptOptions {
property_format: PropertyFormat::OptionalUndefined,
..TypeScriptOptions::default()
}));
}
#[test]
fn exclude_refs() {
assert_snapshot!(generate(TypeScriptOptions {
exclude_references: vec!["BasicEnum".into(), "AnotherType".into()],
..TypeScriptOptions::default()
}));
}
#[test]
fn external_types() {
assert_snapshot!(generate(TypeScriptOptions {
external_types: HashMap::from_iter([(
"./externals".into(),
vec!["BasicEnum".into(), "AnotherType".into()]
)]),
..TypeScriptOptions::default()
}));
}
#[test]
fn no_refs() {
assert_snapshot!(generate(TypeScriptOptions {
disable_references: true,
indent_char: " ".into(),
..TypeScriptOptions::default()
}));
}
}