Skip to content

Commit c436750

Browse files
committed
feat(assert): extend date format auto-detection with space-separated datetime and tz offset
1 parent ee14e7c commit c436750

6 files changed

Lines changed: 85 additions & 21 deletions

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Added
66
- Add date comparison assertions: `assert_date_equals`, `assert_date_before`, `assert_date_after`, `assert_date_within_range`, `assert_date_within_delta`
7-
- Accepts epoch seconds (integers) or ISO 8601 dates (`2023-11-14`, `2023-11-14T12:00:00`)
7+
- Accepts epoch seconds, ISO 8601 (`2023-11-14`, `2023-11-14T12:00:00`, `2023-11-14T12:00:00Z`, `2023-11-14T12:00:00+0100`), or space-separated datetime (`2023-11-14 12:00:00`)
88
- Auto-detects format and converts ISO 8601 to epoch via `bashunit::date::to_epoch`
99
- Mixed formats supported (one epoch, one ISO) in the same assertion call
1010
- Fully portable across GNU and BSD systems

docs/assertions.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,17 @@ function test_failure() {
359359
## assert_date_equals
360360
> `assert_date_equals "expected" "actual"`
361361

362-
Reports an error if the two epoch timestamps `expected` and `actual` are not equal.
362+
Reports an error if the two date values `expected` and `actual` are not equal.
363363

364-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
364+
Inputs are automatically converted to epoch seconds. Supported formats:
365+
- Epoch seconds (integers): `1700000000`
366+
- ISO 8601 date: `2023-11-14`
367+
- ISO 8601 datetime: `2023-11-14T12:00:00`
368+
- ISO 8601 datetime with UTC Z: `2023-11-14T12:00:00Z`
369+
- ISO 8601 datetime with timezone offset: `2023-11-14T12:00:00+0100`
370+
- Space-separated datetime: `2023-11-14 12:00:00`
371+
372+
You can mix formats in the same assertion (e.g., one epoch, one ISO).
365373

366374
::: code-group
367375
```bash [Example]
@@ -383,7 +391,7 @@ function test_failure() {
383391

384392
Reports an error if `actual` is not before `expected` (i.e. `actual` must be less than `expected`).
385393

386-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
394+
Inputs are automatically converted to epoch seconds. See [assert_date_equals](#assert_date_equals) for supported formats.
387395

388396
::: code-group
389397
```bash [Example]
@@ -402,7 +410,7 @@ function test_failure() {
402410

403411
Reports an error if `actual` is not after `expected` (i.e. `actual` must be greater than `expected`).
404412

405-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
413+
Inputs are automatically converted to epoch seconds. See [assert_date_equals](#assert_date_equals) for supported formats.
406414

407415
::: code-group
408416
```bash [Example]
@@ -421,7 +429,7 @@ function test_failure() {
421429

422430
Reports an error if `actual` does not fall between `from` and `to` (inclusive).
423431

424-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
432+
Inputs are automatically converted to epoch seconds. See [assert_date_equals](#assert_date_equals) for supported formats.
425433

426434
::: code-group
427435
```bash [Example]
@@ -440,7 +448,7 @@ function test_failure() {
440448

441449
Reports an error if `actual` is not within `delta` seconds of `expected`.
442450

443-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
451+
Inputs are automatically converted to epoch seconds. See [assert_date_equals](#assert_date_equals) for supported formats.
444452

445453
::: code-group
446454
```bash [Example]

src/assert_dates.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,28 @@ function bashunit::date::to_epoch() {
1212
;;
1313
esac
1414

15-
# ISO 8601 conversion (GNU vs BSD date)
15+
# Format conversion (GNU vs BSD date)
1616
local epoch
1717
# Try GNU date first (-d flag)
1818
epoch=$(date -d "$input" +%s 2>/dev/null) && {
1919
echo "$epoch"
2020
return 0
2121
}
22-
# Try BSD date (-j -f flag) with datetime format
22+
# Try BSD date (-j -f flag) with ISO 8601 datetime + timezone offset
23+
epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" "$input" +%s 2>/dev/null) && {
24+
echo "$epoch"
25+
return 0
26+
}
27+
# Try BSD date with ISO 8601 datetime format
2328
epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "$input" +%s 2>/dev/null) && {
2429
echo "$epoch"
2530
return 0
2631
}
32+
# Try BSD date with space-separated datetime format
33+
epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "$input" +%s 2>/dev/null) && {
34+
echo "$epoch"
35+
return 0
36+
}
2737
# Try BSD date with date-only format
2838
epoch=$(date -j -f "%Y-%m-%d" "$input" +%s 2>/dev/null) && {
2939
echo "$epoch"

tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_all_assert_docs.snapshot

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,17 @@ Reports an error if `actual` is not greater than or equal to `expected`.
154154
--------------
155155
> `assert_date_equals "expected" "actual"`
156156

157-
Reports an error if the two epoch timestamps `expected` and `actual` are not equal.
157+
Reports an error if the two date values `expected` and `actual` are not equal.
158158

159-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
159+
Inputs are automatically converted to epoch seconds. Supported formats:
160+
- Epoch seconds (integers): `1700000000`
161+
- ISO 8601 date: `2023-11-14`
162+
- ISO 8601 datetime: `2023-11-14T12:00:00`
163+
- ISO 8601 datetime with UTC Z: `2023-11-14T12:00:00Z`
164+
- ISO 8601 datetime with timezone offset: `2023-11-14T12:00:00+0100`
165+
- Space-separated datetime: `2023-11-14 12:00:00`
166+
167+
You can mix formats in the same assertion (e.g., one epoch, one ISO).
160168

161169

162170
## assert_date_before
@@ -165,7 +173,7 @@ All inputs are **epoch seconds** (integers), generated via `date +%s`.
165173

166174
Reports an error if `actual` is not before `expected` (i.e. `actual` must be less than `expected`).
167175

168-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
176+
Inputs are automatically converted to epoch seconds. See assert_date_equals(#assert_date_equals) for supported formats.
169177

170178

171179
## assert_date_after
@@ -174,7 +182,7 @@ All inputs are **epoch seconds** (integers), generated via `date +%s`.
174182

175183
Reports an error if `actual` is not after `expected` (i.e. `actual` must be greater than `expected`).
176184

177-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
185+
Inputs are automatically converted to epoch seconds. See assert_date_equals(#assert_date_equals) for supported formats.
178186

179187

180188
## assert_date_within_range
@@ -183,7 +191,7 @@ All inputs are **epoch seconds** (integers), generated via `date +%s`.
183191

184192
Reports an error if `actual` does not fall between `from` and `to` (inclusive).
185193

186-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
194+
Inputs are automatically converted to epoch seconds. See assert_date_equals(#assert_date_equals) for supported formats.
187195

188196

189197
## assert_date_within_delta
@@ -192,7 +200,7 @@ All inputs are **epoch seconds** (integers), generated via `date +%s`.
192200

193201
Reports an error if `actual` is not within `delta` seconds of `expected`.
194202

195-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
203+
Inputs are automatically converted to epoch seconds. See assert_date_equals(#assert_date_equals) for supported formats.
196204

197205

198206
## assert_exit_code
@@ -566,5 +574,3 @@ Reports an error if `command` completes in `threshold_ms` milliseconds or less.
566574

567575
Unambiguously reports an error message. Useful for reporting specific message
568576
when testing situations not covered by any `assert_*` functions.
569-
570-

tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_filtered_assert_docs.snapshot

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,17 @@ Reports an error if the two variables `expected` and `actual` are not equal igno
1111
--------------
1212
> `assert_date_equals "expected" "actual"`
1313

14-
Reports an error if the two epoch timestamps `expected` and `actual` are not equal.
14+
Reports an error if the two date values `expected` and `actual` are not equal.
1515

16-
All inputs are **epoch seconds** (integers), generated via `date +%s`.
16+
Inputs are automatically converted to epoch seconds. Supported formats:
17+
- Epoch seconds (integers): `1700000000`
18+
- ISO 8601 date: `2023-11-14`
19+
- ISO 8601 datetime: `2023-11-14T12:00:00`
20+
- ISO 8601 datetime with UTC Z: `2023-11-14T12:00:00Z`
21+
- ISO 8601 datetime with timezone offset: `2023-11-14T12:00:00+0100`
22+
- Space-separated datetime: `2023-11-14 12:00:00`
23+
24+
You can mix formats in the same assertion (e.g., one epoch, one ISO).
1725

1826

1927
## assert_files_equals
@@ -39,5 +47,3 @@ Reports an error if `expected` and `actual` are not equals.
3947
> `assert_json_equals "expected" "actual"`
4048

4149
Reports an error if the two JSON strings are not structurally equal. Key order is ignored. Requires `jq` to be installed; if missing the test is skipped.
42-
43-

tests/unit/assert_dates_test.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,37 @@ function test_successful_assert_date_within_delta_with_iso_datetime() {
129129
assert_empty\
130130
"$(assert_date_within_delta "2023-11-14T12:00:00" "2023-11-14T12:00:05" "10")"
131131
}
132+
133+
# Space-separated datetime format tests
134+
135+
function test_successful_assert_date_equals_with_space_separated_datetime() {
136+
assert_empty "$(assert_date_equals "2023-11-14 12:00:00" "2023-11-14 12:00:00")"
137+
}
138+
139+
function test_successful_assert_date_equals_iso_vs_space_separated() {
140+
assert_empty "$(assert_date_equals "2023-11-14T12:00:00" "2023-11-14 12:00:00")"
141+
}
142+
143+
function test_successful_assert_date_before_with_space_separated_datetime() {
144+
assert_empty "$(assert_date_before "2023-11-14 13:00:00" "2023-11-14 12:00:00")"
145+
}
146+
147+
function test_successful_assert_date_equals_epoch_vs_space_separated() {
148+
local epoch
149+
epoch=$(date -d "2023-11-14 12:00:00" +%s 2>/dev/null) \
150+
|| epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "2023-11-14 12:00:00" +%s 2>/dev/null)
151+
152+
assert_empty "$(assert_date_equals "$epoch" "2023-11-14 12:00:00")"
153+
}
154+
155+
# UTC Z suffix test (documents existing behavior)
156+
157+
function test_successful_assert_date_equals_with_utc_z_suffix() {
158+
assert_empty "$(assert_date_equals "2023-11-14T12:00:00" "2023-11-14T12:00:00Z")"
159+
}
160+
161+
# Timezone offset tests
162+
163+
function test_successful_assert_date_equals_with_tz_offset() {
164+
assert_empty "$(assert_date_equals "2023-11-14T12:00:00+0100" "2023-11-14T12:00:00+0100")"
165+
}

0 commit comments

Comments
 (0)