use pushkin_compiler::{compile, CompileError, CompileRequest, Target};
const USER_SCHEMA: &str = r#"{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 200 },
"email": {
"type": "string",
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
},
"role": { "default": "member", "type": "string", "enum": ["member", "admin"] }
},
"required": ["name", "email"],
"additionalProperties": false
}"#;
fn rust_binding(epoch: u32) -> Result<String, CompileError> {
compile(&CompileRequest {
contract_name: "user".to_owned(),
schema_json: USER_SCHEMA.to_owned(),
target: Target::Rust,
epoch,
})
.map(|output| output.content)
}
#[test]
fn rust_binding_is_typify_generated_with_deny_unknown_fields() {
let binding = rust_binding(1).unwrap();
assert!(
binding.contains("#[serde(deny_unknown_fields)]"),
"strictness must survive the emitter swap: {binding}"
);
assert!(
binding.contains("pub struct UserCreate"),
"root type name unchanged: {binding}"
);
assert!(
binding.contains("pub struct UserCreateName"),
"constrained strings become validated newtypes: {binding}"
);
assert!(
!binding.contains("fn default_role()"),
"the hand-rolled emitter's shape must be gone: {binding}"
);
}
#[test]
fn rust_binding_validates_length_and_pattern_in_generated_code() {
let binding = rust_binding(1).unwrap();
assert!(
binding.contains("chars().count() > 200"),
"maxLength must be enforced at construction: {binding}"
);
assert!(
binding.contains("chars().count() < 1"),
"minLength must be enforced at construction: {binding}"
);
assert!(
binding.contains("::regress::Regex::new"),
"pattern must be enforced at construction: {binding}"
);
}
#[test]
fn rust_binding_regeneration_is_byte_identical() {
assert_eq!(
rust_binding(1).unwrap(),
rust_binding(1).unwrap(),
"typify emission must stay deterministic"
);
}
#[test]
fn rust_binding_epoch_header_precedes_typify_doc_comments() {
let binding = rust_binding(9).unwrap();
let header_line = binding.lines().nth(1).unwrap_or_default();
assert!(
header_line.contains("pushkin-epoch: 9"),
"line 2 must be the epoch header, got: {header_line}"
);
}
#[test]
fn unrepresentable_constructs_still_reject_before_typify() {
let widened = r#"{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": { "age": { "type": "integer" } },
"required": ["age"],
"additionalProperties": false
}"#;
let err = compile(&CompileRequest {
contract_name: "user".to_owned(),
schema_json: widened.to_owned(),
target: Target::Rust,
epoch: 1,
})
.unwrap_err();
let message = err.to_string();
assert!(
message.contains("integer") || message.contains("age"),
"rejection must name the construct: {message}"
);
}