Files
Marcos Paulo aeac86ddd2
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: Bases model, evaluator, function library and map data model
.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>
2026-10-21 02:58:07 -03:00

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"));
}