...
 
Commits (2)
open Core
type t =
| AddPublicKey of {
algorithm : string;
key : string;
power : Power.t }
algorithm : PublicKeyAlgorithm.t;
power : Power.t;
key : string }
| RemovePublicKey of {
fingerprint : string }
| UpdatePower of {
......@@ -12,3 +14,91 @@ type t =
protocol : string;
body : string }
| Halt
let format = function
| AddPublicKey { algorithm; power; key } ->
Format.sprintf "\
add\n\
%s\n\
%d\n\
%s"
(PublicKeyAlgorithm.to_string algorithm) (Power.to_int power) key
| RemovePublicKey { fingerprint } ->
Format.sprintf "\
remove\n\
%s"
fingerprint
| UpdatePower { fingerprint; power; } ->
Format.sprintf "\
update\n\
%s\n\
%d"
fingerprint (Power.to_int power)
| Halt ->
"halt"
| UserCommand { protocol; body } ->
Format.sprintf "\
user\n\
%s\n\
%s"
protocol body
let combine3 r1 r2 r3 ~ok ~err =
Result.combine
(Result.combine r1 r2 ~ok:(fun r1 r2 -> r1, r2) ~err)
r3 ~ok:(fun (r1, r2) r3 -> ok r1 r2 r3) ~err
let parse_power str =
Power.parse str
|> Result.of_option ~error:"failed to parse power"
let parse_fingerprint fingerprint =
if String.is_empty fingerprint then Error "fingerprint is blank" else
Ok fingerprint
let parse_add = function
| algorithm :: power :: key when key <> [] ->
let algorithm = PublicKeyAlgorithm.of_string(algorithm) in
let power = parse_power power in
let key = String.concat ~sep:"\n" key in
combine3
(Result.of_option algorithm ~error:"failed to parse algorithm")
power
(if String.is_empty key then Error "key is blank" else Ok key)
~ok:(fun algorithm power key -> AddPublicKey { algorithm; power; key })
~err:(fun a b -> a ^ "\n" ^ b)
| _ -> Error "wrong format"
let parse_remove = function
| [fingerprint] ->
Result.map (parse_fingerprint fingerprint)
~f:(fun fingerprint -> RemovePublicKey { fingerprint })
| _ -> Error "wrong format"
let parse_update = function
| [fingerprint; power] ->
let fingerprint = parse_fingerprint fingerprint in
let power = parse_power power in
Result.combine fingerprint power
~ok:(fun fingerprint power -> UpdatePower { fingerprint; power })
~err:(fun a b -> a ^ "\n" ^ b)
| _ -> Error "wrong format"
let parse_halt = function
| [] -> Ok Halt
| _ -> Error "wrong format"
let parse_user = function
| protocol :: body ->
if String.is_empty protocol then Error "protocol is blank" else
Ok (UserCommand { protocol; body = String.concat ~sep:"\n" body })
| _ -> Error "wrong format"
let parse command body =
match command with
| "add" -> parse_add body
| "remove" -> parse_remove body
| "update" -> parse_update body
| "halt" -> parse_halt body
| "user" -> parse_user body
| _ -> Error "unknown command"
type t =
| AddPublicKey of {
algorithm : string;
key : string;
power : Power.t }
algorithm : PublicKeyAlgorithm.t;
power : Power.t;
key : string }
| RemovePublicKey of {
fingerprint : string }
| UpdatePower of {
......@@ -12,3 +12,7 @@ type t =
protocol : string;
body : string }
| Halt
val format : t -> string
val parse : string -> string list -> (t, string) result
open Core
type t = Time.t
let of_string date_time =
try Ok (Time.parse date_time ~fmt:"%Y%m%d%H%M%S" ~zone:Time.Zone.utc) with
| Failure reason -> Error reason
let to_string date_time = Time.format date_time "%Y%m%d%H%M%S" ~zone:Time.Zone.utc
let pp ppf value = Time.pp ppf value
let to_time value = (value :> Time.t)
open Core
type t
val of_string : string -> (t, string) result
val to_string : t -> string
val pp : Format.formatter -> t -> unit
val to_time : t -> Time.t
......@@ -6,3 +6,7 @@ let of_int value =
Some { value = value }
let to_int { value } = value
let parse str =
try of_int (int_of_string str) with
| _ -> None
......@@ -5,3 +5,6 @@ val of_int : int -> t option
val to_int : t -> int
(** converts Power.t to power. *)
val parse : string -> t option
(** parse the given string *)
open Core
open YayakaChain
module Test = Alcotest
let test_format () =
Test.(check string) "add" "\
add\n\
rsa\n\
2\n\
-----BEGIN PUBLIC KEY-----\n\
MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=\n\
-----END PUBLIC KEY-----\n"
(Command.(format (AddPublicKey {
algorithm = PublicKeyAlgorithm.RSA;
power = Option.value_exn (Power.of_int 2);
key = "\
-----BEGIN PUBLIC KEY-----\n\
MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=\n\
-----END PUBLIC KEY-----\n" })));
Test.(check string) "remove" "\
remove\n\
+gf0YWKHMzO0/mCFlB9AivKRlD0="
(Command.(format (RemovePublicKey {
fingerprint = "+gf0YWKHMzO0/mCFlB9AivKRlD0=" })));
Test.(check string) "update" "\
update\n\
+gf0YWKHMzO0/mCFlB9AivKRlD0=\n\
3"
(Command.(format (UpdatePower {
fingerprint = "+gf0YWKHMzO0/mCFlB9AivKRlD0=";
power = Option.value_exn (Power.of_int 3) })));
Test.(check string) "halt" "\
halt"
(Command.(format (Halt)));
Test.(check string) "user" "\
user\n\
some-protocol\n\
some-command\n\
some-body"
(Command.(format (UserCommand {
protocol = "some-protocol";
body = "\
some-command\n\
some-body" })))
let pp ppf command = Fmt.pf ppf "%s" (Command.format command)
let command = Test.testable pp ( = )
let test_parse_unknown () =
Test.(check (result command string)) "unknown"
(Error "unknown command")
(Command.parse "Add" [
"rsa";
"2";
"-----BEGIN PUBLIC KEY-----";
"MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=";
"-----END PUBLIC KEY-----\n"])
let test_parse_add () =
Test.(check (result command string)) "add"
(Ok (AddPublicKey {
algorithm = PublicKeyAlgorithm.RSA;
power = Option.value_exn (Power.of_int 2);
key = "\
-----BEGIN PUBLIC KEY-----\n\
MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=\n\
-----END PUBLIC KEY-----\n" }))
(Command.parse "add" [
"rsa";
"2";
"-----BEGIN PUBLIC KEY-----";
"MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=";
"-----END PUBLIC KEY-----\n"]);
Test.(check (result command string)) "failed to parse algorithm"
(Error "failed to parse algorithm")
(Command.parse "add" [
"RSA";
"2";
"-----BEGIN PUBLIC KEY-----";
"MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=";
"-----END PUBLIC KEY-----\n"]);
Test.(check (result command string)) "failed to parse power"
(Error "failed to parse power")
(Command.parse "add" [
"rsa";
"-1";
"-----BEGIN PUBLIC KEY-----";
"MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAOCHAgMBAAE=";
"-----END PUBLIC KEY-----\n"]);
Test.(check (result command string)) "key is blank"
(Error "key is blank")
(Command.parse "add" ["rsa"; "1"; ""]);
Test.(check (result command string)) "failed to parse algorithm\nfailed to parse power"
(Error "failed to parse algorithm\nkey is blank")
(Command.parse "add" ["Rsa"; "3"; ""]);
Test.(check (result command string)) "failed to parse algorithm\nfailed to parse power"
(Error "failed to parse algorithm\nfailed to parse power\nkey is blank")
(Command.parse "add" ["Rsa"; "1."; ""]);
Test.(check (result command string)) "wrong format"
(Error "wrong format")
(Command.parse "add" ["rsa"; "3"])
let test_parse_remove () =
Test.(check (result command string)) "remove"
(Ok (RemovePublicKey {
fingerprint = "+gf0YWKHMzO0/mCFlB9AivKRlD0=" }))
(Command.parse "remove" ["+gf0YWKHMzO0/mCFlB9AivKRlD0="]);
Test.(check (result command string)) "wrong format"
(Error "wrong format")
(Command.parse "remove" ["+gf0YWK"; "HMzO0/mCFlB9AivKRlD0="]);
Test.(check (result command string)) "fingerprint is blank"
(Error "fingerprint is blank")
(Command.parse "remove" [""])
let test_parse_update () =
Test.(check (result command string)) "update"
(Ok (UpdatePower {
fingerprint = "+gf0YWKHMzO0/mCFlB9AivKRlD0=";
power = Option.value_exn (Power.of_int 3)
}))
(Command.parse "update" [
"+gf0YWKHMzO0/mCFlB9AivKRlD0=";
"3"]);
Test.(check (result command string)) "fingerprint is blank"
(Error "fingerprint is blank")
(Command.parse "update" [
"";
"3"]);
Test.(check (result command string)) "failed to parse power"
(Error "failed to parse power")
(Command.parse "update" [
"+gf0YWKHMzO0/mCFlB9AivKRlD0=";
"3e"]);
Test.(check (result command string)) "fingerprint is blank\nfailed to parse power"
(Error "fingerprint is blank\nfailed to parse power")
(Command.parse "update" [
"";
"3e"]);
Test.(check (result command string)) "wrong format"
(Error "wrong format")
(Command.parse "update" ["+gf0YWKHMzO0/mCFlB9AivKRlD0="])
let test_parse_halt () =
Test.(check (result command string)) "halt"
(Ok Halt)
(Command.parse "halt" []);
Test.(check (result command string)) "wrong format"
(Error "wrong format")
(Command.parse "halt" ["a"])
let test_parse_user () =
Test.(check (result command string)) "user"
(Ok (UserCommand {
protocol = "some-protocol";
body = "\
some-command\n\
some-body" }))
(Command.parse "user" ["some-protocol"; "some-command"; "some-body"]);
Test.(check (result command string)) "only protocol name"
(Ok (UserCommand {
protocol = "some-protocol";
body = "" }))
(Command.parse "user" ["some-protocol"]);
Test.(check (result command string)) "protocol is blank"
(Error "protocol is blank")
(Command.parse "user" [""; "some-command"; "some-body"]);
Test.(check (result command string)) "wrong format"
(Error "wrong format")
(Command.parse "user" [])
let command_tests = [
"format", `Quick, test_format;
"parse unknown", `Quick, test_parse_unknown;
"parse add", `Quick, test_parse_add;
"parse remove", `Quick, test_parse_remove;
"parse update", `Quick, test_parse_update;
"parse halt", `Quick, test_parse_halt;
"parse user", `Quick, test_parse_user;
]
let () =
Test.run "Command" [
"Command", command_tests;
]
(tests
(names power_test hash_test hashAlgorithm_test publicKey_test publicKeyAlgorithm_test)
(names
power_test
hash_test
hashAlgorithm_test
publicKey_test
publicKeyAlgorithm_test
expirationDateTime_test
command_test)
(libraries alcotest yayakaChain))
open Core
open YayakaChain
module Test = Alcotest
let to_string time =
Result.map time ~f: (fun time -> (time |> ExpirationDateTime.to_time |> Time.format) "%Y%m%d%H%M%S" ~zone:Time.Zone.utc)
let test_of_string () =
Test.(check (result string string)) "20180207091315" (Ok "20180207091315")
(to_string (ExpirationDateTime.of_string "20180207091315"));
Test.(check (result string string)) "wrong format" (Error "unix_strptime: match failed")
(to_string (ExpirationDateTime.of_string "2018020091315"))
let test_to_string () =
Test.(check string) "20180207091315" "20180207091315"
("20180207091315"
|> ExpirationDateTime.of_string
|> Result.ok_or_failwith
|> ExpirationDateTime.to_string)
let expiration_date_time_tests = [
"of_string", `Quick, test_of_string;
"to_string", `Quick, test_to_string;
]
let () =
Test.run "ExpirationDateTime" [
"ExpirationDateTime", expiration_date_time_tests;
]
......@@ -18,9 +18,19 @@ let test_to_int () =
Test.(check int) "1,000,000" 1000000 (Power.to_int (to_power 1000000));
Test.(check int) "2 ^ 31 - 1" 2147483647 (Power.to_int (to_power 2147483647))
let test_parse () =
Test.(check (option int)) "0" (Some 0) (to_int_option (Power.parse "0"));
Test.(check (option int)) "1,000,000" (Some 1000000) (to_int_option (Power.parse "1000000"));
Test.(check (option int)) "2 ^ 31 - 1" (Some 2147483647) (to_int_option (Power.parse "2147483647"));
Test.(check (option int)) "2 ^ 31" None (to_int_option (Power.parse "2147483648"));
Test.(check (option int)) "-1" None (to_int_option (Power.parse "-1"));
Test.(check (option int)) "-1,000,000" None (to_int_option (Power.parse "-1000000"));
Test.(check (option int)) "1.3" None (to_int_option (Power.parse "1.3"))
let power_tests = [
"of_int", `Quick, test_of_int;
"to_int", `Quick, test_to_int;
"parse", `Quick, test_parse;
]
let () =
......
open Core
open YayakaChain
let to_power value =
match (Power.of_int value) with
| Some power -> power
| _ -> raise (Failure "")
let to_power value = Option.value_exn (Power.of_int value)