as2_vocab_test.ml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. open Seppo_lib
  2. module A = Assrt
  3. (* diaspora profile json e.g.
  4. https://pod.diaspora.software/u/hq
  5. https://pod.diaspora.software/people/7bca7c80311b01332d046c626dd55703
  6. *)
  7. let test_person () =
  8. let empty : As2_vocab.Types.person = {
  9. id = Uri.empty;
  10. inbox = Uri.empty;
  11. outbox = Uri.empty;
  12. followers = None;
  13. following = None;
  14. attachment = [];
  15. discoverable = false;
  16. generator = None;
  17. icon = None;
  18. image = None;
  19. manually_approves_followers = false;
  20. name = None;
  21. name_map = [];
  22. preferred_username = None;
  23. preferred_username_map = [];
  24. public_key = {
  25. id = Uri.empty;
  26. owner = None;
  27. pem = "";
  28. signatureAlgorithm = None;
  29. };
  30. published = Some Ptime.epoch;
  31. summary = None;
  32. summary_map = [];
  33. url = [];
  34. } in
  35. let base = (Uri.of_string "https://example.com/su/") in
  36. let context = As2_vocab.Constants.ActivityStreams.und in
  37. {empty with id=Uri.make ~path:"id/" ()}
  38. |> As2_vocab.Encode.person ~context ~base
  39. |> Ezjsonm.value_to_string ~minify:false
  40. |> Assrt.equals_string __LOC__ {|{
  41. "@context": [
  42. "https://www.w3.org/ns/activitystreams",
  43. "https://w3id.org/security/v1",
  44. {
  45. "schema": "http://schema.org#",
  46. "PropertyValue": "schema:PropertyValue",
  47. "value": "schema:value",
  48. "@language": "und"
  49. }
  50. ],
  51. "type": "Person",
  52. "id": "https://example.com/su/id/",
  53. "inbox": "https://example.com/su/",
  54. "outbox": "https://example.com/su/",
  55. "publicKey": {
  56. "@context": [
  57. {
  58. "@language": null
  59. }
  60. ],
  61. "id": "https://example.com/su/",
  62. "publicKeyPem": ""
  63. },
  64. "published": "1970-01-01T00:00:00Z",
  65. "manuallyApprovesFollowers": false,
  66. "discoverable": false,
  67. "attachment": []
  68. }|};
  69. let p = {|{
  70. "@context": [
  71. "https://www.w3.org/ns/activitystreams",
  72. "https://w3id.org/security/v1",
  73. {
  74. "schema": "http://schema.org#",
  75. "PropertyValue": "schema:PropertyValue",
  76. "value": "schema:value",
  77. "@language": "und"
  78. }
  79. ],
  80. "type": "Person",
  81. "id": "https://example.com/su/id/",
  82. "inbox": "https://example.com/su/",
  83. "outbox": "https://example.com/su/",
  84. "publicKey": {
  85. "id": "https://example.com/su/",
  86. "owner": "https://example.com/su/",
  87. "publicKeyPem": ""
  88. },
  89. "published": "1970-01-01T00:00:00Z",
  90. "manuallyApprovesFollowers": false,
  91. "discoverable": false,
  92. "attachment": []
  93. }|}
  94. |> Ezjsonm.value_from_string
  95. |> As2_vocab.Decode.person
  96. |> Result.get_ok in
  97. p.id
  98. |> Uri.to_string
  99. |> Assrt.equals_string __LOC__ "https://example.com/su/id/"
  100. let test_actor_3rd () =
  101. Logr.info (fun m -> m "%s.%s" "As2_vocab" "actor_3rd");
  102. let ok loc fn na =
  103. let j = File.in_channel fn Ezjsonm.from_channel in
  104. let p = j |> As2_vocab.Decode.person |> Result.get_ok in
  105. p.name |> Option.get |> A.equals_string loc na
  106. and err loc fn e =
  107. let j = File.in_channel fn Ezjsonm.from_channel in
  108. j |> As2_vocab.Decode.person |> Result.get_error
  109. |> Decoders_ezjsonm.Decode.string_of_error
  110. |> A.equals_string loc e
  111. and fal _loc fn =
  112. let j = File.in_channel fn Ezjsonm.from_channel in
  113. assert (j |> As2_vocab.Decode.person |> Result.is_error)
  114. in
  115. (* ok __LOC__ "data/ap/actor/lemmy.0.json" ""; *)
  116. ok __LOC__ "data/ap/actor/akkoma.0.json" "Sean Tilley";
  117. ok __LOC__ "data/ap/actor/akkoma.1.json" "Kinetix";
  118. ok __LOC__ "data/ap/actor/bonfire.0.json" "stpaultim";
  119. ok __LOC__ "data/ap/actor/bridgy.0.json" "Tantek Çelik";
  120. ok __LOC__ "data/ap/actor/friendica.0.json" "Michael Vogel";
  121. ok __LOC__ "data/ap/actor/gnusocial.0.json" "Diogo Peralta Cordeiro";
  122. ok __LOC__ "data/ap/actor/gnusocial.1.json" "admin de gnusocial.net";
  123. ok __LOC__ "data/ap/actor/gnusocial.2.json" "diogo";
  124. ok __LOC__ "data/ap/actor/gotosocial.0.json" "Gerben";
  125. ok __LOC__ "data/ap/actor/honk.0.json" "boyter";
  126. ok __LOC__ "data/ap/actor/mastodon.0.json" "Yet Another #Seppo! 🌻";
  127. ok __LOC__ "data/ap/actor/mastodon.1.json" "#Seppo";
  128. ok __LOC__ "data/ap/actor/mastodon.2.json" "Marcus Rohrmoser 🌍";
  129. ok __LOC__ "data/ap/actor/mini.0.json" "Yet Another #Seppo! 🌻";
  130. ok __LOC__ "data/ap/actor/misskey.0.json" "しゅいろ";
  131. ok __LOC__ "data/ap/actor/peertube.0.json" "edps";
  132. ok __LOC__ "data/ap/actor/peertube.2.json" {|edps|};
  133. ok __LOC__ "data/ap/actor/pixelfed.0.json" {|#Seppo|};
  134. ok __LOC__ "data/ap/actor/pleroma.0.json" "@fediverse@mro.name";
  135. ok __LOC__ "data/ap/actor/smithereen.0.json" {|Григорий Клюшников|};
  136. ok __LOC__ "data/ap/actor/snac.0.json" {|The Real Grunfink|};
  137. ok __LOC__ "data/ap/actor/threads.0.json" "Ben Savage";
  138. ok __LOC__ "data/ap/actor/tootik.0.json" {|EOIN GAIRLEOG|};
  139. ok __LOC__ "data/ap/actor/zap.0.json" "mike";
  140. ok __LOC__ "data/ap/profile/@actapopuli@fediverse.blog.json" "actapopuli";
  141. ok __LOC__ "data/ap/profile/@administrator@gnusocial.net.json" {|admin de gnusocial.net|};
  142. ok __LOC__ "data/ap/profile/@dansup@pixelfed.social.json" {|dansup|};
  143. ok __LOC__ "data/ap/profile/@gargron@mastodon.social.json" {|Eugen Rochko|};
  144. ok __LOC__ "data/ap/profile/@kainoa@calckey.social.json" {|Kainoa |};
  145. ok __LOC__ "data/ap/profile/@karolat@stereophonic.space.json" {|karolat|};
  146. ok __LOC__ "data/ap/profile/@manton@manton.org.json" {|Manton Reece|};
  147. ok __LOC__ "data/ap/profile/@matt@write.as.json" {|Matt|};
  148. ok __LOC__ "data/ap/profile/@mike@macgirvin.com.json" {|Mike Macgirvin|};
  149. ok __LOC__ "data/ap/profile/@peertube@framapiaf.org.json" {|PeerTube|};
  150. ok __LOC__ "data/ap/profile/@syuilo@misskey.io.json" {|:peroro_sama:しゅいろ:peroro_sama:|};
  151. ok __LOC__ "data/ap/profile/@tobias@friendi.ca.json" {|Tobias|};
  152. err __LOC__ "data/ap/profile/@lemmy_support@lemmy.ml.json" {|I tried the following decoders but they all failed:
  153. "type" decoder:
  154. in field "type": expected Person (received Group), but got "Group"
  155. "type" decoder:
  156. in field "type": expected Service (received Group), but got "Group" |};
  157. err __LOC__ "data/ap/actor/mobilizon.0.json" {|I tried the following decoders but they all failed:
  158. "type" decoder:
  159. in field "type": expected Person (received Group), but got "Group"
  160. "type" decoder:
  161. in field "type": expected Service (received Group), but got "Group" |};
  162. err __LOC__ "data/ap/actor/peertube.1.json" {|in field "summary": Expected a string, but got null|};
  163. fal __LOC__ "data/ap/actor/diaspora.0.json";
  164. ()
  165. (*
  166. ok __LOC__ "data/ap/actor/natur.0.json" "しゅいろ";
  167. ok __LOC__ "data/ap/actor/natur.1.json" "しゅいろ";
  168. ok __LOC__ "data/ap/actor/sharkey.0.json" {||};
  169. ok __LOC__ "data/ap/actor/sharkey.1.json" {||};
  170. ok __LOC__ "data/ap/profile/@framasoft@mobilizon.fr.json" {||};
  171. ok __LOC__ "data/ap/profile/@Greensky@open.audio.json" {||};
  172. *)
  173. let test_note_decode () =
  174. Logr.info (fun m -> m "%s.%s" "As2_vocab" "note_decode");
  175. let j = File.in_channel "data/ap/note/mastodon.json" Ezjsonm.from_channel in
  176. let n = j |> As2_vocab.Decode.note |> Result.get_ok in
  177. n.id |> Uri.to_string |> Assrt.equals_string __LOC__ "https://digitalcourage.social/users/mro/statuses/111403080326863922";
  178. match n.in_reply_to with
  179. | [u] -> u |> Uri.to_string |> Assrt.equals_string __LOC__ "https://chaos.social/users/qyliss/statuses/111403054651938519"
  180. | _ -> failwith "none"
  181. let test_webfinger_sunshine () =
  182. let q = File.in_channel "data/webfinger/mini.json" Ezjsonm.from_channel
  183. |> As2_vocab.Activitypub.Decode.Webfinger.query_result
  184. |> Result.get_ok in
  185. q.subject |> Assrt.equals_string __LOC__ "acct:ursi@example.com";
  186. q.links |> List.length |> Assrt.equals_int __LOC__ 3;
  187. let q = File.in_channel "data/webfinger/zap.json" Ezjsonm.from_channel
  188. |> As2_vocab.Activitypub.Decode.Webfinger.query_result
  189. |> Result.get_ok in
  190. q.subject |> Assrt.equals_string __LOC__ "acct:mike@macgirvin.com";
  191. q.links |> List.length |> Assrt.equals_int __LOC__ 3;
  192. let q = File.in_channel "data/webfinger/atom.json" Ezjsonm.from_channel
  193. |> As2_vocab.Activitypub.Decode.Webfinger.query_result
  194. |> Result.get_ok in
  195. q.subject |> Assrt.equals_string __LOC__ "acct:ursi@example.com";
  196. q.links |> List.length |> Assrt.equals_int __LOC__ 3
  197. let test_profile_sunshine () =
  198. let q = File.in_channel "data/ap/actor/mini.0.json" Ezjsonm.from_channel
  199. |> As2_vocab.Activitypub.Decode.person
  200. |> Result.get_ok in
  201. q.name |> Option.get |> Assrt.equals_string __LOC__ "Yet Another #Seppo! 🌻";
  202. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "ursi";
  203. q.attachment |> List.length |> Assrt.equals_int "" 0;
  204. let q = File.in_channel "data/ap/actor/mastodon.0.json" Ezjsonm.from_channel
  205. |> As2_vocab.Activitypub.Decode.person
  206. |> Result.get_ok in
  207. (match q.attachment with
  208. | [a;b;_] ->
  209. a.name |> Assrt.equals_string __LOC__ "Support";
  210. b.value |> Assrt.equals_string __LOC__ {|<a href="https://seppo.social">Seppo.Social</a>|};
  211. | _ -> Assrt.equals_int "" 0 1
  212. );
  213. q.image |> Option.get |> Uri.to_string |> Assrt.equals_string __LOC__ "https://example.com/me-banner.jpg";
  214. "" |> Assrt.equals_string __LOC__ "";
  215. let q = File.in_channel "data/ap/actor/akkoma.0.json" Ezjsonm.from_channel
  216. |> As2_vocab.Activitypub.Decode.person
  217. |> Result.get_ok in
  218. q.name |> Option.get |> Assrt.equals_string __LOC__ "Sean Tilley";
  219. let q = File.in_channel "data/ap/actor/gnusocial.0.json" Ezjsonm.from_channel
  220. |> As2_vocab.Activitypub.Decode.person
  221. |> Result.get_ok in
  222. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "diogo";
  223. let q = File.in_channel "data/ap/actor/lemmy.0.json" Ezjsonm.from_channel
  224. |> As2_vocab.Activitypub.Decode.person
  225. |> Result.get_ok in
  226. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "nutomic";
  227. let q = File.in_channel "data/ap/actor/mastodon.0.json" Ezjsonm.from_channel
  228. |> As2_vocab.Activitypub.Decode.person
  229. |> Result.get_ok in
  230. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "ursi";
  231. let q = File.in_channel "data/ap/actor/peertube.0.json" Ezjsonm.from_channel
  232. |> As2_vocab.Activitypub.Decode.person
  233. |> Result.get_ok in
  234. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "edps";
  235. let q = File.in_channel "data/ap/actor/zap.0.json" Ezjsonm.from_channel
  236. |> As2_vocab.Activitypub.Decode.person
  237. |> Result.get_ok in
  238. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "mike";
  239. let q = File.in_channel "data/ap/actor/bridgy.0.json" Ezjsonm.from_channel
  240. |> As2_vocab.Activitypub.Decode.person
  241. |> Result.get_ok in
  242. q.preferred_username |> Option.get |> Assrt.equals_string __LOC__ "tantek.com";
  243. assert true
  244. let test_encode () =
  245. let minify = false in
  246. let base = Uri.of_string "http://example.com/foo/" in
  247. let module E = Decoders_ezjsonm.Encode in
  248. E.encode_string E.obj [("k", `String "v")]
  249. |> Assrt.equals_string __LOC__ {|{"k":"v"}|};
  250. Ezjsonm.value_to_string (E.obj [("k", `String "v")])
  251. |> Assrt.equals_string __LOC__ {|{"k":"v"}|};
  252. let e : Rfc4287.Entry.t = {
  253. id = Uri.make ~path:"a/b/" ?fragment:(Some "c") ();
  254. in_reply_to = [];
  255. lang = Rfc4287.Rfc4646 "de";
  256. author = Uri.make ~userinfo:"bar" ();
  257. title = "uhu";
  258. published = (Rfc3339.T "2023-03-07T01:23:45Z") ;
  259. updated = (Rfc3339.T "2023-03-07T01:23:46Z");
  260. links = [];
  261. categories = [
  262. ((Label (Single "lbl")),(Term (Single "term")),Uri.make ~path:"t/" ());
  263. ];
  264. content = "Das war aber einfach";
  265. } in
  266. let n = Ap.Note.of_rfc4287 e in
  267. let j = n |> As2_vocab.Encode.note ~base in
  268. j |> Ezjsonm.value_to_string ~minify
  269. |> Assrt.equals_string __LOC__ {|{
  270. "type": "Note",
  271. "id": "http://example.com/foo/a/b/#c",
  272. "actor": "http://example.com/foo/activitypub/actor.jsa",
  273. "to": [
  274. "https://www.w3.org/ns/activitystreams#Public"
  275. ],
  276. "cc": [
  277. "http://example.com/foo/activitypub/notify/index.jsa"
  278. ],
  279. "mediaType": "text/plain; charset=utf8",
  280. "content": "Das war aber einfach",
  281. "sensitive": false,
  282. "summary": "uhu",
  283. "published": "2023-03-07T01:23:45Z",
  284. "tags": [
  285. {
  286. "type": "Hashtag",
  287. "href": "http://example.com/foo/t/term/",
  288. "name": "#lbl"
  289. }
  290. ],
  291. "url": []
  292. }|};
  293. let co : 'a As2_vocab.Types.collection_page = {
  294. id = Uri.of_string "http://example.com/foo/";
  295. current = None;
  296. first = None;
  297. is_ordered = true;
  298. items = [Ap.Note.Create.make n];
  299. last = None;
  300. next = None;
  301. part_of = None;
  302. prev = None;
  303. total_items= None;
  304. } in
  305. let j = As2_vocab.Encode.collection_page ~base
  306. (As2_vocab.Encode.create ~base
  307. (As2_vocab.Encode.note ~base))
  308. co in
  309. j |> Ezjsonm.value_to_string ~minify
  310. |> Assrt.equals_string __LOC__ {|{
  311. "@context": [
  312. "https://www.w3.org/ns/activitystreams",
  313. "https://w3id.org/security/v1",
  314. {
  315. "schema": "http://schema.org#",
  316. "PropertyValue": "schema:PropertyValue",
  317. "value": "schema:value",
  318. "@language": "und"
  319. }
  320. ],
  321. "type": "OrderedCollectionPage",
  322. "id": "http://example.com/foo/",
  323. "orderedItems": [
  324. {
  325. "type": "Create",
  326. "id": "http://example.com/foo/a/b/#c/Create",
  327. "actor": "http://example.com/foo/activitypub/actor.jsa",
  328. "published": "2023-03-07T01:23:45Z",
  329. "to": [
  330. "https://www.w3.org/ns/activitystreams#Public"
  331. ],
  332. "cc": [
  333. "http://example.com/foo/activitypub/notify/index.jsa"
  334. ],
  335. "directMessage": false,
  336. "object": {
  337. "type": "Note",
  338. "id": "http://example.com/foo/a/b/#c",
  339. "actor": "http://example.com/foo/activitypub/actor.jsa",
  340. "to": [
  341. "https://www.w3.org/ns/activitystreams#Public"
  342. ],
  343. "cc": [
  344. "http://example.com/foo/activitypub/notify/index.jsa"
  345. ],
  346. "mediaType": "text/plain; charset=utf8",
  347. "content": "Das war aber einfach",
  348. "sensitive": false,
  349. "summary": "uhu",
  350. "published": "2023-03-07T01:23:45Z",
  351. "tags": [
  352. {
  353. "type": "Hashtag",
  354. "href": "http://example.com/foo/t/term/",
  355. "name": "#lbl"
  356. }
  357. ],
  358. "url": []
  359. }
  360. }
  361. ]
  362. }|};
  363. assert true
  364. (* https://www.w3.org/TR/activitystreams-core/#ex17-jsonld *)
  365. let test_ex15_note () =
  366. let j = File.in_channel "data/ap/note/as2_core.ex15.json" Ezjsonm.value_from_channel in
  367. (match j with
  368. | `O [
  369. "@context", _ ;
  370. "summary", _ ;
  371. "type", `String "Create" ;
  372. "actor", _ ;
  373. "object", `O [
  374. "type", `String "Note" ;
  375. _]
  376. ] -> assert true
  377. | _ -> assert false);
  378. let p = j
  379. |> As2_vocab.Decode.(create note)
  380. |> Result.is_error in
  381. assert p
  382. (*
  383. _p.obj.summary |> Option.get |> Assrt.equals_string "" "";
  384. *)
  385. (* https://github.com/mattjbray/ocaml-decoders *)
  386. type role = Admin | User
  387. type user =
  388. { lang : string
  389. ; txt : role list
  390. }
  391. let test_example() =
  392. Logr.info (fun m -> m "%s.%s" "As2_vocab" "example");
  393. let module My_encoders(E : Decoders.Encode.S) = struct
  394. open E
  395. let user : role encoder =
  396. function
  397. | Admin -> string "ADMIN"
  398. | User -> string "USER"
  399. let user : user encoder =
  400. fun u ->
  401. obj
  402. [ ("name", string u.lang)
  403. ; ("roles", list user u.txt)
  404. ]
  405. end in
  406. let module E = Decoders_ezjsonm.Encode in
  407. let module My_ezjson_encoders = My_encoders(Decoders_ezjsonm.Encode) in
  408. let open My_ezjson_encoders in
  409. let users =
  410. [ {lang = "Alice"; txt = [Admin; User]}
  411. ; {lang = "Bob"; txt = [User]}
  412. ] in
  413. E.encode_string E.obj [("users", E.list user users)]
  414. |> Assrt.equals_string __LOC__ {|{"users":[{"name":"Alice","roles":["ADMIN","USER"]},{"name":"Bob","roles":["USER"]}]}|}
  415. type _i18n =
  416. { lang : string
  417. ; txt : string
  418. }
  419. let test_encode_content_map () =
  420. Logr.info (fun m -> m "%s.%s" "As2_vocab" "encode_content_map");
  421. let l = [("a","A");("b","B")] in
  422. let module E = Decoders_ezjsonm.Encode in
  423. let j = l |> List.map (fun (k,v) -> (k,E.string v)) in
  424. E.encode_string E.obj j
  425. |> Assrt.equals_string __LOC__ {|{"a":"A","b":"B"}|}
  426. let test_decode_content_map () =
  427. Logr.info (fun m -> m "%s.%s" "As2_vocab" "decode_content_map");
  428. let s = Ezjsonm.value_from_string {|{"a":"A","b":"B"}|} in
  429. let module D = Decoders_ezjsonm.Decode in
  430. let l = D.key_value_pairs D.string s
  431. |> Result.get_ok in
  432. (match l with
  433. | [("a","A");("b","B")] -> ()
  434. | _ -> "" |> Assrt.equals_string __LOC__ {|{"a":"A","b":"B"}|});
  435. let s = Ezjsonm.value_from_string {|{"contentMap":{"a":"A","b":"B","b":"C"}}|} in
  436. let l = D.field "contentMap" (D.key_value_pairs D.string) s
  437. |> Result.get_ok in
  438. match l with
  439. | [("a","A");("b","B");("b","C")] -> ()
  440. | _ -> "" |> Assrt.equals_string __LOC__ {|{"a":"A","b":"B"}|}
  441. let test_decode_natur () =
  442. (* https://codeberg.org/seppo/seppo/issues/5 *)
  443. Logr.info (fun m -> m "%s.%s" "As2_vocab" "decode_natur");
  444. let j = File.in_channel "data/ap/actor/natur.0.json" Ezjsonm.from_channel in
  445. let e = j |> As2_vocab.Decode.person |> Result.get_error in
  446. let s = e |> Decoders_ezjsonm.Decode.string_of_error in
  447. s |> Assrt.equals_string __LOC__ {|Expected an object with an attribute "publicKey", but got
  448. {"id":"https://dev.rdf-pub.org/d613b246-8984-4654-903d-8d44143aca40","type":"Person","inboxSparql":"https://dev.rdf-pub.org/d613b246-8984-4654-903d-8d44143aca40/inbox/sparql","rdfpub:oauth2Issuer":"https://login.m4h.network/auth/realms/LOA","rdfpub:oauth2IssuerPreferredUserName":"max@login.m4h.network","rdfpub:oauth2IssuerUserId":"1813bdc1-152c-4c27-92a6-6cdfe401ef3d@login.m4h.network","outboxSparql":"https://dev.rdf-pub.org/d613b246-8984-4654-903d-8d44143aca40/outbox/sparql","identifier":"52ff7eb2-0b7c-4388-9894-b40a27714c1b","version":{"type":"xsd:integer","@value":"1"},"owl:sameAs":{"id":"https://dev.rdf-pub.org/05a75688-c517-4ae1-842c-5da3d8460627"},"inbox":"https://dev.rdf-pub.org/d613b246-8984-4654-903d-8d44143aca40/inbox","endpoints":{"oauthAuthorizationEndpoint":"https://dev.rdf-pub.org/oauth/oauthAuthorizationEndpoint","oauthTokenEndpoint":"https://dev.rdf-pub.org/oauth/oauthTokenEndpoint"},"name":"max","outbox":"https://dev.rdf-pub.org/d613b246-8984-4654-903d-8d44143aca40/outbox","published":"2024-01-14T15:59:42.102+01:00","@context":["https://schema.org/docs/jsonldcontext.json","https://rdf-pub.org/schema/rdf-pub-context.json","https://www.w3.org/ns/activitystreams"]}|}
  449. let test_decode_sharkey() =
  450. (* https://joinsharkey.org *)
  451. Logr.info (fun m -> m "%s.%s" "As2_vocab" "decode_sharkey");
  452. let j = File.in_channel "data/ap/actor/sharkey.0.json" Ezjsonm.from_channel in
  453. let p = j |> As2_vocab.Decode.person |> Result.get_ok in
  454. p.name
  455. |> Option.value ~default:"-"
  456. |> Assrt.equals_string __LOC__ {|-|};
  457. (File.in_channel "data/ap/actor/sharkey.1.json" Ezjsonm.from_channel
  458. |> As2_vocab.Decode.person
  459. |> Result.get_ok)
  460. .name
  461. |> Option.value ~default:"-"
  462. |> Assrt.equals_string __LOC__ {|wakest the shark possum|}
  463. let () =
  464. Unix.chdir "../../../test/";
  465. test_person ();
  466. test_actor_3rd ();
  467. test_note_decode ();
  468. test_webfinger_sunshine ();
  469. test_profile_sunshine ();
  470. test_encode ();
  471. test_ex15_note ();
  472. test_example ();
  473. test_encode_content_map ();
  474. test_decode_content_map ();
  475. test_decode_natur ();
  476. test_decode_sharkey();
  477. assert true