aeac86ddd2
.base model (filters, formulas, properties, views; unknown keys kept in order; limits and invalid-value errors), evaluator with the D5 type rules, lazy if and boolean operators, memoised formulas with cycle errors, depth cap 200, string/number/object/list/date/link/file/regexp functions with lambdas (regex through notescraft-regex), and the map model (Web Mercator, tile ids, viewport tiles, grid clustering, coordinate and colour parsing, OSM attribution constants; Paris z10 is tile 518/352). Bases tasks 2, 5, 6 (Claude Sonnet) and 8 (MiniMax M3.1 Flash, OpenCode Zen free route). Verified: notescraft-bases suites all pass, clippy -D warnings, xtask layers and tree clean. Known gaps: toFixed rounds ties to even, list.unique is quadratic. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.8 KiB
Rust
72 lines
2.8 KiB
Rust
//! Date fields and methods.
|
|
|
|
mod common;
|
|
|
|
use common::{NOW, TestRow, cases, ev, is_error, n, run, s};
|
|
use notescraft_bases::Value;
|
|
|
|
#[test]
|
|
fn date_fields() {
|
|
let d = "date(\"2024-12-31 23:59:58.250\")";
|
|
for (field, want) in [("year", 2024.0), ("month", 12.0), ("day", 31.0), ("hour", 23.0), ("minute", 59.0), ("second", 58.0), ("millisecond", 250.0)] {
|
|
assert_eq!(ev(&format!("{d}.{field}")), n(want), "{field}");
|
|
}
|
|
assert!(is_error(&ev(&format!("{d}.nosuch"))));
|
|
assert_eq!(ev("null.year"), Value::Null);
|
|
}
|
|
|
|
#[test]
|
|
fn date_methods() {
|
|
cases(&[
|
|
("now().date().format(\"YYYY-MM-DD HH:mm:ss\")", s("2024-12-01 00:00:00")),
|
|
("now().time()", s("12:00:00")),
|
|
("date(\"2025-05-27\").format(\"YYYY-MM-DD\")", s("2025-05-27")),
|
|
("date(\"2025-05-27 14:05:09\").format(\"HH:mm:ss\")", s("14:05:09")),
|
|
("date(\"2025-05-27\").time()", s("00:00:00")),
|
|
("date(\"2025-05-27\").format(\"dddd, MMMM Do YYYY\")", s("Tuesday, May 27th 2025")),
|
|
("date(\"2025-05-01\").format(\"ddd MMM D YY\")", s("Thu May 1 25")),
|
|
("date(\"2025-05-02\").format(\"[Year] YYYY\")", s("Year 2025")),
|
|
("date(\"1970-01-01\").format(\"d dddd\")", s("4 Thursday")),
|
|
("date(\"1969-12-31\").format(\"dddd\")", s("Wednesday")),
|
|
("date(\"2025-05-27 00:30:00\").format(\"h:mm A\")", s("12:30 AM")),
|
|
("date(\"2025-05-27 15:30:00\").format(\"hh:mm a\")", s("03:30 pm")),
|
|
("date(\"2025-05-27 15:30:00.007\").format(\"ss.SSS\")", s("00.007")),
|
|
("date(\"2025-05-27\").format(\"[open\")", s("[open")),
|
|
("date(\"2025-05-27\").format(\"\")", s("")),
|
|
("date(\"2025-05-27\").isEmpty()", Value::Bool(false)),
|
|
("null.format(\"YYYY\")", Value::Null),
|
|
("date(\"2025-05-27 04:03:00\").date().toString()", s("2025-05-27")),
|
|
]);
|
|
for src in ["date(\"2025-05-27\").format(1)", "date(\"2025-05-27\").format()", "date(\"2025-05-27\").time(1)", "date(\"2025-05-27\").nosuch()"] {
|
|
assert!(is_error(&ev(src)), "{src}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn relative_reads_like_moment() {
|
|
let ago = |ms: i64| {
|
|
run(
|
|
"file.mtime.relative()",
|
|
&{
|
|
let mut r = TestRow::new("a.md");
|
|
r.mtime = NOW - ms;
|
|
r
|
|
},
|
|
&[],
|
|
None,
|
|
None,
|
|
)
|
|
};
|
|
let day = 86_400_000;
|
|
assert_eq!(ago(3 * day), s("3 days ago"));
|
|
assert_eq!(ago(day), s("a day ago"));
|
|
assert_eq!(ago(10_000), s("a few seconds ago"));
|
|
assert_eq!(ago(5 * 60_000), s("5 minutes ago"));
|
|
assert_eq!(ago(3 * 3_600_000), s("3 hours ago"));
|
|
assert_eq!(ago(60 * day), s("2 months ago"));
|
|
assert_eq!(ago(30 * day), s("a month ago"));
|
|
assert_eq!(ago(800 * day), s("2 years ago"));
|
|
assert_eq!(ago(-2 * day), s("in 2 days"));
|
|
assert_eq!(ago(-3 * 3_600_000), s("in 3 hours"));
|
|
}
|