use pushkin_compiler::{compile, CompileError, CompileRequest, Target};
const SAFE_JS_INTEGER_MAX: i64 = 9_007_199_254_740_991;
const NEG_SAFE_JS_INTEGER_MAX: i64 = -9_007_199_254_740_991;
const FIRST_UNSAFE: i64 = 9_007_199_254_740_992; const NEG_FIRST_UNSAFE: i64 = -9_007_199_254_740_992;
fn emit(schema: &str, target: Target) -> Result<String, CompileError> {
compile(&CompileRequest {
contract_name: "integer_default_range".to_owned(),
schema_json: schema.to_owned(),
target,
epoch: 1,
})
.map(|output| output.content)
}
fn make_schema(default_expr: &str) -> String {
format!(
r#"{{
"type": "object",
"properties": {{
"big": {{ "type": "integer", "default": {default_expr} }}
}},
"additionalProperties": false
}}"#
)
}
#[test]
fn safe_max_integer_default_compiles_all_targets() {
let schema = make_schema(&SAFE_JS_INTEGER_MAX.to_string());
for target in [Target::Zod, Target::Pydantic, Target::Rust, Target::Sql] {
let out = emit(&schema, target);
assert!(
out.is_ok(),
"{target:?} must accept integer default {SAFE_JS_INTEGER_MAX}: {out:?}"
);
}
}
#[test]
fn safe_min_integer_default_compiles_all_targets() {
let schema = make_schema(&NEG_SAFE_JS_INTEGER_MAX.to_string());
for target in [Target::Zod, Target::Pydantic, Target::Rust, Target::Sql] {
let out = emit(&schema, target);
assert!(
out.is_ok(),
"{target:?} must accept integer default {NEG_SAFE_JS_INTEGER_MAX}: {out:?}"
);
}
}
#[test]
fn positive_too_large_integer_default_rejects() {
let schema = make_schema(&FIRST_UNSAFE.to_string());
for target in [Target::Zod, Target::Pydantic, Target::Rust, Target::Sql] {
let err = emit(&schema, target).expect_err("integer default above 2^53 must reject");
let msg = err.to_string();
assert!(
msg.contains("big") && msg.contains(FIRST_UNSAFE.to_string().as_str()),
"{target:?} rejection must name property 'big' and value {FIRST_UNSAFE}: {msg}"
);
}
}
#[test]
fn negative_too_large_integer_default_rejects() {
let schema = make_schema(&NEG_FIRST_UNSAFE.to_string());
for target in [Target::Zod, Target::Pydantic, Target::Rust, Target::Sql] {
let err = emit(&schema, target).expect_err("integer default below -2^53 must reject");
let msg = err.to_string();
assert!(
msg.contains("big") && msg.contains(NEG_FIRST_UNSAFE.to_string().as_str()),
"{target:?} rejection must name property 'big' and value {NEG_FIRST_UNSAFE}: {msg}"
);
}
}
#[test]
fn existing_widening_contract_still_compiles() {
const SCHEMA: &str = r#"{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"age": { "type": "integer", "default": 30 },
"ratio": { "type": "number", "default": 0.5 },
"active": { "type": "boolean", "default": true },
"score": { "type": "number" },
"count": { "type": "integer" }
},
"required": ["score"],
"additionalProperties": false
}"#;
for target in [Target::Zod, Target::Pydantic, Target::Rust, Target::Sql] {
let out = emit(SCHEMA, target);
assert!(
out.is_ok(),
"{target:?} must still compile the widening schema: {out:?}"
);
}
}