Files
core/test/rust/native/calendar.rs
T
2026-11-03 03:32:07 +00:00

123 lines
4.7 KiB
Rust

use super::{Directory, fixture};
use dever::{
compiler::{build, project::Project},
syntax::source::Source,
};
#[test]
fn native_calendar_and_clocks_keep_values_and_error_identity() {
let directory = Directory::new();
let project = Project::load(&fixture().with_file_name("calendar.dever")).unwrap();
let program = project.check().unwrap();
for entry in ["verify", "clocks", "invalid"] {
let binary =
build::build(&program, &project.sources, entry, &directory.0.join(entry)).unwrap();
let result = std::process::Command::new(binary).output().unwrap();
if entry == "invalid" {
assert!(!result.status.success());
let error = String::from_utf8(result.stderr).unwrap();
assert!(
error.contains("DateResult.Failed")
&& error.contains("lib/dever/time/calendar.dever:"),
"{error}"
);
} else {
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(result.stdout, b"true\n");
}
}
}
#[test]
fn temporal_command_fields_round_trip_and_reject_invalid_wire_values() {
let directory = Directory::new();
let mut project = Project::load(&fixture().with_file_name("application")).unwrap();
let source = project
.sources
.iter_mut()
.find(|source| source.path.ends_with("greeting/app.dever"))
.unwrap();
let start = source.text.find("type Profile").unwrap();
let end = source.text.find("type Problem").unwrap();
let fields = [
("instant", "DateTime"),
("date", "Date"),
("time", "Time"),
("elapsed", "Duration"),
("optional", "DateTime?"),
];
let mut record = "type Profile {\n".to_owned();
for (name, kind) in fields {
record.push_str(&format!(" {name}: {kind}\n"));
}
record.push_str("}\n\n");
let mut text = format!("{}{}{}", &source.text[..start], record, &source.text[end..]);
let start = text.find("double(").unwrap();
let end = text.find("echo(").unwrap();
let replacement = r#"double(value: Duration) (answer: DateTime) { answer = domain.double(value) }
"#;
text.replace_range(start..end, replacement);
*source = Source::new(source.id, source.path.clone(), text);
let source = project
.sources
.iter_mut()
.find(|source| source.path.ends_with("greeting/domain.dever"))
.unwrap();
let start = source.text.find("double(").unwrap();
let end = source.text.find("positive(").unwrap();
let replacement = replacement.replace(
"answer = domain.double(value)",
"answer = dever.time.add(dever.time.parseDatetime(\"1970-01-01T00:00:00Z\"), value)",
);
let mut text = source.text.clone();
text.replace_range(start..end, &replacement);
*source = Source::new(source.id, source.path.clone(), text);
let program = project.check().unwrap();
let binary = build::build(
&program,
&project.sources,
"main",
&directory.0.join("commands"),
)
.unwrap();
let input = r#"{"value":{"instant":"2024-02-29T12:34:56.12+08:00","date":"2024-02-29","time":"12:34:56.000","elapsed":-3}}"#;
let result = std::process::Command::new(&binary)
.args(["demo.greeting.echo", input])
.output()
.unwrap();
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(
String::from_utf8(result.stdout).unwrap(),
"{\"code\":0,\"message\":\"ok\",\"data\":{\"instant\":\"2024-02-29T04:34:56.120Z\",\"date\":\"2024-02-29\",\"time\":\"12:34:56\",\"elapsed\":-3,\"optional\":null}}\n"
);
for invalid in [
input.replace("12:34:56.000", "12:34:56.1"),
input.replace("2024-02-29\",\"time", "2023-02-29\",\"time"),
input.replace("\"elapsed\":-3", "\"elapsed\":-3.0"),
input.replace(".12+08:00", ".1234+08:00"),
] {
let result = std::process::Command::new(&binary)
.args(["demo.greeting.echo", &invalid])
.output()
.unwrap();
assert!(!result.status.success(), "{invalid}");
assert!(result.stdout.is_empty());
assert!(String::from_utf8_lossy(&result.stderr).contains("invalid command input"));
}
let result = std::process::Command::new(&binary)
.args(["demo.greeting.double", r#"{"value":9223372036854775807}"#])
.output()
.unwrap();
assert!(!result.status.success());
assert!(result.stdout.is_empty());
assert!(String::from_utf8_lossy(&result.stderr).contains("four-digit UTC calendar range"));
}