geochan/test/test.ml

420 lines
14 KiB
OCaml
Raw Normal View History

2024-05-29 19:16:48 +02:00
open Alcotest
open Types
open Syntax
open Util
module Test_comment = struct
let f () =
let open Comment in
let result = Alcotest.result string string in
let bool_result = Alcotest.result bool string in
let check_id s =
(check result) "to_string(of_string(s))=id" (Ok s)
(match of_string s with Ok v -> Ok (to_string v) | Error e -> Error e)
in
let check_eq expected s =
(check bool_result) "eq" (Ok true)
(match of_string s with Error e -> Error e | Ok v -> Ok (expected = v))
in
let l =
[ ("cc sava?", [ Line [ Txt "cc sava?" ] ])
; ("cc\n\n sava?", [ Line [ Txt "cc" ]; Line []; Line [ Txt " sava?" ] ])
; (">cc sava?", [ Line_quote [ Txt "cc sava?" ] ])
; (">cc sava\n?", [ Line_quote [ Txt "cc sava" ]; Line [ Txt "?" ] ])
; ("cc >>13 sava?", [ Line [ Txt "cc "; Id 13; Txt " sava?" ] ])
; (">cc >>13 sava?", [ Line_quote [ Txt "cc "; Id 13; Txt " sava?" ] ])
; (">>13 cc sava?", [ Line [ Id 13; Txt " cc sava?" ] ])
; (">>13\n cc sava?", [ Line [ Id 13 ]; Line [ Txt " cc sava?" ] ])
; (">>>13\n cc sava?", [ Line_quote [ Id 13 ]; Line [ Txt " cc sava?" ] ])
; ( ">>>>13\n cc sava?"
, [ Line_quote [ Txt ">"; Id 13 ]; Line [ Txt " cc sava?" ] ] )
; (">>13 >cc sava?", [ Line [ Id 13; Txt " >cc sava?" ] ])
; ( ">>>>13\n cc sava?"
, [ Line_quote [ Txt ">"; Id 13 ]; Line [ Txt " cc sava?" ] ] )
]
in
List.iter (fun (s, _) -> check_id s) l;
List.iter (fun (s, expected) -> check_eq expected s) l;
()
end
module Test_json_data = struct
let err () =
let err_result = Alcotest.result err string in
let check e =
(check err_result) "read(write(o))=id" (Ok e)
(Json_data.Write.err e |> Json_data.Read.err)
in
let l =
Err.
[ Internal (Db "a")
; Internal (Conan "a")
; Bad_form
; Forbidden
; Unauthorized_login "a"
]
in
List.iter check l
end
module Test_user = struct
let email = "user_1@test.com"
let nick = "user_1"
let password = "hunter2"
let bio = "hello im user_1 ~~"
let make () =
(check unit_result) "is ok" (Ok ())
(let* () = User.register ~email ~nick ~password in
Ok () );
()
let login () =
(check unit_result) "is ok" (Ok ())
(let* _ : User_private.t = User.login ~login:email ~password in
Ok () );
(check unit_result) "is ok" (Ok ())
(let* _ : User_private.t = User.login ~login:nick ~password in
Ok () );
()
let get_id () =
let* u = User.login ~login:email ~password in
Ok u.user_id
let get_user () =
(check unit_result) "is ok" (Ok ())
(let* id = get_id () in
let* _ : user = User.get_user id in
let* _ : User_private.t = User.get_user_private id in
Ok () );
()
let get_image () =
(check unit_result) "is ok" (Ok ())
(let* id = get_id () in
let* _image_data : string = User.get_image id in
Ok () );
()
let update () =
let email_2 = "user_2@test.com" in
let nick_2 = "user_2" in
let password_2 = "xXhunter2Xx" in
(check unit_result) "is ok" (Ok ())
(let* id = get_id () in
let* () = User.update_email id email_2 in
let* () = User.update_nick id nick_2 in
let* () = User.update_password id password_2 in
let* () = User.update_bio id bio in
let* () =
(* should not accept change to already taken value *)
assert_error (User.update_email id email_2)
in
(* revert changes *)
let* () = User.update_email id email in
let* () = User.update_nick id nick in
let* () = User.update_password id password in
Ok () );
()
let delete () =
(check unit_result) "is ok" (Ok ())
(let* id = get_id () in
let* () = User.delete_avatar id in
let* () = User.delete_user id in
let* () = assert_error (User.get_user id) in
let* () = assert_error (User.login ~login:email ~password) in
Ok () );
()
end
module Test_post = struct
let post_count = ref 0
let subject = "first thread"
let mk_comment =
fun () ->
incr post_count;
let s = Fmt.str "comment nb %d ^^ ~~!" !post_count in
s
let assert_post_not_found id =
match Post.get_post id with
| Ok _ -> error "post found"
| Error e -> assert_true (e = Not_found_post id)
let assert_post_image_found id =
let* _ : string = Post.get_thumbnail_data id in
let* _ : string = Post.get_image_data id in
Ok ()
let assert_post_image_not_found id =
match assert_post_image_found id with
| Ok _ -> error "post image found"
| Error e -> assert_true (e = Not_found_image id)
let get_first_thread () =
let* catalog = Post.get_catalog () in
match catalog with [] -> error "empty catalog" | hd :: _ -> Ok hd
let empty_catalog () =
(check unit_result) "is ok" (Ok ())
(let* catalog = Post.get_catalog () in
assert_true (List.is_empty catalog) );
()
let make_thread () =
(check unit_result) "is ok" (Ok ())
(let* user_id = Test_user.get_id () in
let* user = User.get_user user_id in
let lat, lng = (12.0, -13.0) in
let comment = mk_comment () in
let image_data = None in
let* thread =
Post.make_thread ~comment ~image_data ~subject ~lat ~lng user
in
let post_id = thread.op.id in
let date = thread.op.date in
let* expected_comment =
Comment.of_string comment
|> Result.map_error (fun s ->
Err.Unprocessable (Fmt.str "comment: %s" s) )
in
let expected_op =
{ id = post_id
; parent_t_id = post_id
; date
; poster_id = user_id
; poster_nick = Test_user.nick
; comment = expected_comment
; image_info = None
; backlinks = []
}
in
let expected_thread =
Thread_w_reply.
{ op = expected_op
; subject
; lat
; lng
; bump_status = Alive 0
; reply_count = 0
; reply_l = [ expected_op ]
}
in
assert_true (expected_thread = thread) );
()
let make_reply () =
(check unit_result) "is ok" (Ok ())
(let* user_id = Test_user.get_id () in
let* user = User.get_user user_id in
let* parent_thread = get_first_thread () in
let comment = mk_comment () in
let image_data = None in
let* post = Post.make_post ~comment ~image_data ~parent_thread user in
let* expected_comment =
Comment.of_string comment
|> Result.map_error (fun s ->
Err.Unprocessable (Fmt.str "comment: %s" s) )
in
let expected_post =
{ id = post.id
; parent_t_id = parent_thread.op.id
; date = post.date
; poster_id = user_id
; poster_nick = Test_user.nick
; comment = expected_comment
; image_info = None
; backlinks = []
}
in
let* () = assert_true (expected_post = post) in
let* parent_thread_updated = Post.get_thread parent_thread.op.id in
let* () = assert_true @@ (!post_count = 2) in
let* () =
assert_true
({ parent_thread with reply_count = 1 } = parent_thread_updated)
in
Ok () );
()
let make_reply_with_image () =
let f img =
let mime, name, alt, data = img in
let image_data = Some (Some name, alt, data) in
let* user_id = Test_user.get_id () in
let* user = User.get_user user_id in
let* parent_thread = get_first_thread () in
let comment = mk_comment () in
let* post = Post.make_post ~comment ~image_data ~parent_thread user in
let* expected_comment =
Comment.of_string comment
|> Result.map_error (fun s ->
Err.Unprocessable (Fmt.str "comment: %s" s) )
in
(* image read/write to file for thumbnail creation + strip exif change image data
thumbnail dimension can be <> than image dimension *)
let post_image_info = Option.get post.image_info in
let expected_image_info =
{ md5 = post_image_info.md5
; mime
; w = 1
; h = 1
; thumb_w = post_image_info.thumb_w
; thumb_h = post_image_info.thumb_h
; name
; alt
}
in
let expected_post =
{ id = post.id
; parent_t_id = parent_thread.op.id
; date = post.date
; poster_id = user_id
; poster_nick = Test_user.nick
; comment = expected_comment
; image_info = Some expected_image_info
; backlinks = []
}
in
Fmt.epr "expected --@.%s@." (Json_data.Write.post expected_post);
Fmt.epr "got --@.%s@." (Json_data.Write.post post);
let* () = assert_true (expected_post = post) in
Ok ()
in
(check unit_result) "is ok" (Ok ())
(let* () = assert_true (Array.length imgs = 4) in
let* () = array_iter f imgs in
Ok () );
()
let no_exif () =
let get_img id = Post.get_image_data id in
let get_img_name id =
let* info = Post.get_image_info id in
Ok info.name
in
(check unit_result) "is ok" (Ok ())
((* post with fff.png *)
let id1 = 3 in
(* post with fff.exif.png *)
let id2 = 6 in
let* img1 = get_img id1 in
let* img2 = get_img id2 in
let* img1_name = get_img_name id1 in
let* img2_name = get_img_name id2 in
let* () = assert_true (img1_name = "fff.png") in
let* () = assert_true (img2_name = "fff.exif.png") in
let* () =
assert_true
(let regex = Re.Posix.compile_pat "exif" in
Re.exec_opt regex img2 |> Option.is_none )
in
let* () = assert_true (img1 = img2) in
Ok () )
let gets () =
(check unit_result) "is ok" (Ok ())
(let* thread = get_first_thread () in
let* thread_w_reply = Post.get_thread_w_reply thread.op.id in
let thread' = Util.thread_w_reply_to_simple thread_w_reply in
let* () = assert_true (thread = thread') in
let count = !post_count in
let* () = assert_true @@ (count = 6) in
(* TODO remove op from thread's replies *)
(* - 1 because op does not count as a reply *)
let* () = assert_true @@ (thread.reply_count = count - 1) in
(* but not here because its in the replies list of thread *)
let* () = assert_true @@ (List.length thread_w_reply.reply_l = count) in
(* !! post id start at 1 *)
let* () = assert_error @@ Post.get_post 0 in
(* get all posts an compare them to thread replies *)
let id_l = List.init count (fun i -> i + 1) in
let* post_l = list_map Post.get_post id_l in
let* () = assert_true (thread_w_reply.reply_l = post_l) in
(* check image data *)
(* first 2 post don't have image *)
let* () = assert_post_image_not_found 1 in
let* () = assert_post_image_not_found 2 in
(* last 4 post have images *)
let* () = assert_post_image_found 3 in
let* () = assert_post_image_found 4 in
let* () = assert_post_image_found 5 in
let* () = assert_post_image_found 6 in
Ok () );
()
let post_delete id =
let* user_id = Test_user.get_id () in
let* user = User.get_user user_id in
let* () = Post.delete ~user id in
Ok ()
let delete_reply () =
(check unit_result) "is ok" (Ok ())
((* delete last post *)
let* () = post_delete !post_count in
let count = !post_count - 1 in
let* () = assert_post_not_found !post_count in
let* () = assert_post_image_not_found !post_count in
let* thread = get_first_thread () in
let* Thread_w_reply.
{ op; subject; lat; lng; bump_status; reply_count; reply_l } =
Post.get_thread_w_reply thread.op.id
in
let thread' = { op; subject; lat; lng; bump_status; reply_count } in
let* () = assert_true (thread = thread') in
let id_l = List.init count (fun i -> i + 1) in
let* post_l = list_map Post.get_post id_l in
let* () = assert_true (reply_l = post_l) in
Ok () );
()
let delete_thread () =
(check unit_result) "is ok" (Ok ())
((* delete first thread *)
let* t_info = get_first_thread () in
let* () = post_delete t_info.op.id in
let* () = assert_error @@ get_first_thread () in
(* check all posts are deleted *)
let id_l = List.init !post_count (fun i -> i + 1) in
let* () = list_iter (fun id -> assert_post_not_found id) id_l in
let* () = list_iter (fun id -> assert_post_image_not_found id) id_l in
Ok () );
()
end
let () =
run "Tests"
[ ("Comment read & write", [ test_case "comment" `Quick Test_comment.f ])
; ("Json data read & write", [ test_case "err" `Quick Test_json_data.err ])
; (* !! order of tests on database is important *)
( "User"
, Test_user.
[ test_case "make" `Quick make
; test_case "login" `Quick login
; test_case "get" `Quick get_user
; test_case "get_image" `Quick get_image
; test_case "update" `Quick update
; test_case "delete" `Quick delete
; test_case "re make user_1" `Quick make
] )
; ( "Post"
, Test_post.
[ test_case "empty catalog" `Quick empty_catalog
; test_case "make thread" `Quick make_thread
; test_case "make reply" `Quick make_reply
; test_case "make reply with image" `Quick make_reply_with_image
; test_case "gets" `Quick gets
; test_case "no exif" `Quick no_exif
; test_case "delete reply" `Quick delete_reply
; test_case "delete thread" `Quick delete_thread
] )
]