tangled
alpha
login
or
join now
anil.recoil.org
/
ocaml-jsonfeed
3
fork
atom
OCaml library for JSONfeed parsing and creation
3
fork
atom
overview
issues
pulls
pipelines
tests for the roundtripping
anil.recoil.org
4 months ago
8fbd095d
64ff2827
1/1
build.yml
success
51s
+189
-4
4 changed files
expand all
collapse all
unified
split
CHANGES.md
dune-project
jsonfeed.opam
test
test_jsonfeed.ml
+7
-2
CHANGES.md
···
1
1
-
v1.0.0
2
2
-
------
1
1
+
v1.1.0 (dev)
2
2
+
------------
3
3
+
4
4
+
- Simplify round trip processing of unknown messages using Jsont combinators (@avsm).
5
5
+
6
6
+
v1.0.0 (2025-11-12)
7
7
+
-------------------
3
8
4
9
- Initial public release (@avsm)
5
10
+1
-1
dune-project
···
25
25
(ptime (>= 1.2.0))
26
26
bytesrw
27
27
(odoc :with-doc)
28
28
-
(alcotest (and :with-test (>= 1.9.0)))))
28
28
+
(alcotest (and :with-test (>= 1.8.0)))))
+1
-1
jsonfeed.opam
···
15
15
"ptime" {>= "1.2.0"}
16
16
"bytesrw"
17
17
"odoc" {with-doc}
18
18
-
"alcotest" {with-test & >= "1.9.0"}
18
18
+
"alcotest" {with-test & >= "1.8.0"}
19
19
]
20
20
build: [
21
21
["dune" "subst"] {dev}
+180
test/test_jsonfeed.ml
···
370
370
test_feed_parse_invalid_missing_content );
371
371
]
372
372
373
373
+
(* Unknown fields preservation tests *)
374
374
+
375
375
+
let test_author_unknown_roundtrip () =
376
376
+
let json =
377
377
+
{|{
378
378
+
"name": "Test Author",
379
379
+
"custom_field": "custom value",
380
380
+
"another_extension": 42
381
381
+
}|}
382
382
+
in
383
383
+
match Jsont_bytesrw.decode_string' Author.jsont json with
384
384
+
| Error e ->
385
385
+
Alcotest.fail
386
386
+
(Printf.sprintf "Parse failed: %s" (Jsont.Error.to_string e))
387
387
+
| Ok author ->
388
388
+
(* Check that unknown fields are preserved *)
389
389
+
let unknown = Author.unknown author in
390
390
+
Alcotest.(check bool)
391
391
+
"has unknown fields" false
392
392
+
(Jsonfeed.Unknown.is_empty unknown);
393
393
+
(* Encode and decode again *)
394
394
+
(match Jsont_bytesrw.encode_string' Author.jsont author with
395
395
+
| Error e ->
396
396
+
Alcotest.fail
397
397
+
(Printf.sprintf "Encode failed: %s" (Jsont.Error.to_string e))
398
398
+
| Ok json2 -> (
399
399
+
match Jsont_bytesrw.decode_string' Author.jsont json2 with
400
400
+
| Error e ->
401
401
+
Alcotest.fail
402
402
+
(Printf.sprintf "Re-parse failed: %s" (Jsont.Error.to_string e))
403
403
+
| Ok author2 ->
404
404
+
(* Verify unknown fields survive roundtrip *)
405
405
+
let unknown2 = Author.unknown author2 in
406
406
+
Alcotest.(check bool)
407
407
+
"unknown fields preserved" false
408
408
+
(Jsonfeed.Unknown.is_empty unknown2)))
409
409
+
410
410
+
let test_item_unknown_roundtrip () =
411
411
+
let json =
412
412
+
{|{
413
413
+
"id": "https://example.com/1",
414
414
+
"content_html": "<p>Test</p>",
415
415
+
"custom_metadata": "some custom data",
416
416
+
"x_custom_number": 123.45
417
417
+
}|}
418
418
+
in
419
419
+
match Jsont_bytesrw.decode_string' Item.jsont json with
420
420
+
| Error e ->
421
421
+
Alcotest.fail
422
422
+
(Printf.sprintf "Parse failed: %s" (Jsont.Error.to_string e))
423
423
+
| Ok item ->
424
424
+
(* Check that unknown fields are preserved *)
425
425
+
let unknown = Item.unknown item in
426
426
+
Alcotest.(check bool)
427
427
+
"has unknown fields" false
428
428
+
(Jsonfeed.Unknown.is_empty unknown);
429
429
+
(* Encode and decode again *)
430
430
+
(match Jsont_bytesrw.encode_string' Item.jsont item with
431
431
+
| Error e ->
432
432
+
Alcotest.fail
433
433
+
(Printf.sprintf "Encode failed: %s" (Jsont.Error.to_string e))
434
434
+
| Ok json2 -> (
435
435
+
match Jsont_bytesrw.decode_string' Item.jsont json2 with
436
436
+
| Error e ->
437
437
+
Alcotest.fail
438
438
+
(Printf.sprintf "Re-parse failed: %s" (Jsont.Error.to_string e))
439
439
+
| Ok item2 ->
440
440
+
let unknown2 = Item.unknown item2 in
441
441
+
Alcotest.(check bool)
442
442
+
"unknown fields preserved" false
443
443
+
(Jsonfeed.Unknown.is_empty unknown2)))
444
444
+
445
445
+
let test_feed_unknown_roundtrip () =
446
446
+
let json =
447
447
+
{|{
448
448
+
"version": "https://jsonfeed.org/version/1.1",
449
449
+
"title": "Test Feed",
450
450
+
"items": [],
451
451
+
"custom_extension": "custom value",
452
452
+
"x_another_field": {"nested": "data"}
453
453
+
}|}
454
454
+
in
455
455
+
match Jsonfeed.of_string json with
456
456
+
| Error e ->
457
457
+
Alcotest.fail
458
458
+
(Printf.sprintf "Parse failed: %s" (Jsont.Error.to_string e))
459
459
+
| Ok feed ->
460
460
+
(* Check that unknown fields are preserved *)
461
461
+
let unknown = Jsonfeed.unknown feed in
462
462
+
Alcotest.(check bool)
463
463
+
"has unknown fields" false
464
464
+
(Jsonfeed.Unknown.is_empty unknown);
465
465
+
(* Encode and decode again *)
466
466
+
(match Jsonfeed.to_string feed with
467
467
+
| Error e ->
468
468
+
Alcotest.fail
469
469
+
(Printf.sprintf "Encode failed: %s" (Jsont.Error.to_string e))
470
470
+
| Ok json2 -> (
471
471
+
match Jsonfeed.of_string json2 with
472
472
+
| Error e ->
473
473
+
Alcotest.fail
474
474
+
(Printf.sprintf "Re-parse failed: %s" (Jsont.Error.to_string e))
475
475
+
| Ok feed2 ->
476
476
+
let unknown2 = Jsonfeed.unknown feed2 in
477
477
+
Alcotest.(check bool)
478
478
+
"unknown fields preserved" false
479
479
+
(Jsonfeed.Unknown.is_empty unknown2)))
480
480
+
481
481
+
let test_hub_unknown_roundtrip () =
482
482
+
let json = {|{
483
483
+
"type": "WebSub",
484
484
+
"url": "https://example.com/hub",
485
485
+
"custom_field": "test"
486
486
+
}|} in
487
487
+
match Jsont_bytesrw.decode_string' Hub.jsont json with
488
488
+
| Error e ->
489
489
+
Alcotest.fail
490
490
+
(Printf.sprintf "Parse failed: %s" (Jsont.Error.to_string e))
491
491
+
| Ok hub ->
492
492
+
let unknown = Hub.unknown hub in
493
493
+
Alcotest.(check bool)
494
494
+
"has unknown fields" false
495
495
+
(Jsonfeed.Unknown.is_empty unknown);
496
496
+
(match Jsont_bytesrw.encode_string' Hub.jsont hub with
497
497
+
| Error e ->
498
498
+
Alcotest.fail
499
499
+
(Printf.sprintf "Encode failed: %s" (Jsont.Error.to_string e))
500
500
+
| Ok json2 -> (
501
501
+
match Jsont_bytesrw.decode_string' Hub.jsont json2 with
502
502
+
| Error e ->
503
503
+
Alcotest.fail
504
504
+
(Printf.sprintf "Re-parse failed: %s" (Jsont.Error.to_string e))
505
505
+
| Ok hub2 ->
506
506
+
let unknown2 = Hub.unknown hub2 in
507
507
+
Alcotest.(check bool)
508
508
+
"unknown fields preserved" false
509
509
+
(Jsonfeed.Unknown.is_empty unknown2)))
510
510
+
511
511
+
let test_attachment_unknown_roundtrip () =
512
512
+
let json =
513
513
+
{|{
514
514
+
"url": "https://example.com/file.mp3",
515
515
+
"mime_type": "audio/mpeg",
516
516
+
"x_custom": "value"
517
517
+
}|}
518
518
+
in
519
519
+
match Jsont_bytesrw.decode_string' Attachment.jsont json with
520
520
+
| Error e ->
521
521
+
Alcotest.fail
522
522
+
(Printf.sprintf "Parse failed: %s" (Jsont.Error.to_string e))
523
523
+
| Ok att ->
524
524
+
let unknown = Attachment.unknown att in
525
525
+
Alcotest.(check bool)
526
526
+
"has unknown fields" false
527
527
+
(Jsonfeed.Unknown.is_empty unknown);
528
528
+
(match Jsont_bytesrw.encode_string' Attachment.jsont att with
529
529
+
| Error e ->
530
530
+
Alcotest.fail
531
531
+
(Printf.sprintf "Encode failed: %s" (Jsont.Error.to_string e))
532
532
+
| Ok json2 -> (
533
533
+
match Jsont_bytesrw.decode_string' Attachment.jsont json2 with
534
534
+
| Error e ->
535
535
+
Alcotest.fail
536
536
+
(Printf.sprintf "Re-parse failed: %s" (Jsont.Error.to_string e))
537
537
+
| Ok att2 ->
538
538
+
let unknown2 = Attachment.unknown att2 in
539
539
+
Alcotest.(check bool)
540
540
+
"unknown fields preserved" false
541
541
+
(Jsonfeed.Unknown.is_empty unknown2)))
542
542
+
543
543
+
let unknown_fields_tests =
544
544
+
[
545
545
+
("author unknown roundtrip", `Quick, test_author_unknown_roundtrip);
546
546
+
("item unknown roundtrip", `Quick, test_item_unknown_roundtrip);
547
547
+
("feed unknown roundtrip", `Quick, test_feed_unknown_roundtrip);
548
548
+
("hub unknown roundtrip", `Quick, test_hub_unknown_roundtrip);
549
549
+
("attachment unknown roundtrip", `Quick, test_attachment_unknown_roundtrip);
550
550
+
]
551
551
+
373
552
(* Main test suite *)
374
553
375
554
let () =
···
380
559
("Hub", hub_tests);
381
560
("Item", item_tests);
382
561
("Jsonfeed", jsonfeed_tests);
562
562
+
("Unknown Fields", unknown_fields_tests);
383
563
]