Pārlūkot izejas kodu

add flowy-test crate

appflowy 3 gadi atpakaļ
vecāks
revīzija
dfc2cbff4f

+ 2 - 0
.idea/appflowy_client.iml

@@ -14,6 +14,8 @@
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sdk/tests" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-protobuf/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/scripts/flowy-tool/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-test/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-user/tests" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />

+ 1 - 0
rust-lib/.gitignore

@@ -9,4 +9,5 @@ Cargo.lock
 # These are backup files generated by rustfmt
 **/*.rs.bk
 **/**/*.log*
+**/**/temp
 bin/

+ 1 - 0
rust-lib/Cargo.toml

@@ -7,6 +7,7 @@ members = [
   "flowy-user",
   "flowy-ast",
   "flowy-derive",
+  "flowy-test",
 ]
 
 [profile.dev]

+ 1 - 1
rust-lib/dart-ffi/src/lib.rs

@@ -93,7 +93,7 @@ impl std::convert::From<FFIRequest> for DispatchRequest {
         } else {
             Payload::None
         };
-        let request = DispatchRequest::new(ffi_request.event, payload);
+        let request = DispatchRequest::new(ffi_request.event).payload(payload);
         request
     }
 }

+ 0 - 1
rust-lib/flowy-derive/src/lib.rs

@@ -1,5 +1,4 @@
 // https://docs.rs/syn/1.0.48/syn/struct.DeriveInput.html
-#![feature(str_split_once)]
 extern crate proc_macro;
 
 use proc_macro::TokenStream;

+ 0 - 79
rust-lib/flowy-sdk/tests/sdk/helper.rs

@@ -1,79 +0,0 @@
-pub use flowy_sdk::*;
-use flowy_sys::prelude::*;
-use std::{
-    fmt::{Debug, Display},
-    fs,
-    hash::Hash,
-    sync::Once,
-};
-
-static INIT: Once = Once::new();
-pub fn init_sdk() {
-    let root_dir = root_dir();
-
-    INIT.call_once(|| {
-        FlowySDK::init_log(&root_dir);
-    });
-    FlowySDK::init(&root_dir);
-}
-
-fn root_dir() -> String {
-    let mut path = fs::canonicalize(".").unwrap();
-    path.push("tests/temp/flowy/");
-    let path_str = path.to_str().unwrap().to_string();
-    if !std::path::Path::new(&path).exists() {
-        std::fs::create_dir_all(path).unwrap();
-    }
-    path_str
-}
-
-pub struct EventTester {
-    request: DispatchRequest,
-}
-
-impl EventTester {
-    pub fn new<E, P>(event: E, payload: P) -> Self
-    where
-        E: Eq + Hash + Debug + Clone + Display,
-        P: std::convert::Into<Payload>,
-    {
-        init_sdk();
-        Self {
-            request: DispatchRequest::new(event, payload.into()),
-        }
-    }
-
-    // #[allow(dead_code)]
-    // pub fn bytes_payload<T>(mut self, payload: T) -> Self
-    // where
-    //     T: serde::Serialize,
-    // {
-    //     let bytes: Vec<u8> = bincode::serialize(&payload).unwrap();
-    //     self.request = self.request.payload(Payload::Bytes(bytes));
-    //     self
-    // }
-    //
-    // #[allow(dead_code)]
-    // pub fn protobuf_payload<T>(mut self, payload: T) -> Self
-    // where
-    //     T: ::protobuf::Message,
-    // {
-    //     let bytes: Vec<u8> = payload.write_to_bytes().unwrap();
-    //     self.request = self.request.payload(Payload::Bytes(bytes));
-    //     self
-    // }
-
-    #[allow(dead_code)]
-    pub async fn async_send(self) -> EventResponse {
-        let resp = async_send(self.request).await;
-        dbg!(&resp);
-        resp
-    }
-
-    #[allow(dead_code)]
-    pub fn sync_send(self) -> EventResponse {
-        let resp = sync_send(self.request);
-        dbg!(&resp);
-        resp
-    }
-}

+ 0 - 2
rust-lib/flowy-sdk/tests/sdk/main.rs

@@ -1,2 +0,0 @@
-mod helper;
-mod user;

+ 0 - 23
rust-lib/flowy-sdk/tests/sdk/user/sign_in.rs

@@ -1,23 +0,0 @@
-use crate::helper::*;
-use flowy_sys::prelude::*;
-use flowy_user::prelude::*;
-use std::convert::{TryFrom, TryInto};
-
-#[test]
-fn sign_in_without_password() {
-    let params = UserSignInParams {
-        email: "[email protected]".to_string(),
-        password: "".to_string(),
-    };
-    let bytes: Vec<u8> = params.try_into().unwrap();
-    let resp = EventTester::new(SignIn, Payload::Bytes(bytes)).sync_send();
-    match resp.payload {
-        Payload::None => {},
-        Payload::Bytes(bytes) => {
-            let result = UserSignInResult::try_from(&bytes).unwrap();
-            dbg!(&result);
-        },
-    }
-
-    assert_eq!(resp.status_code, StatusCode::Ok);
-}

+ 121 - 0
rust-lib/flowy-sys/src/data.rs

@@ -0,0 +1,121 @@
+use crate::{
+    error::{InternalError, SystemError},
+    request::{unexpected_none_payload, EventRequest, FromRequest, Payload},
+    response::{EventResponse, Responder, ResponseBuilder, ToBytes},
+    util::ready::{ready, Ready},
+};
+use std::ops;
+
+pub struct Data<T>(pub T);
+
+impl<T> Data<T> {
+    pub fn into_inner(self) -> T { self.0 }
+}
+
+impl<T> ops::Deref for Data<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T { &self.0 }
+}
+
+impl<T> ops::DerefMut for Data<T> {
+    fn deref_mut(&mut self) -> &mut T { &mut self.0 }
+}
+
+pub trait FromBytes: Sized {
+    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String>;
+}
+
+#[cfg(feature = "use_protobuf")]
+impl<T> FromBytes for T
+where
+    // https://stackoverflow.com/questions/62871045/tryfromu8-trait-bound-in-trait
+    T: for<'a> std::convert::TryFrom<&'a Vec<u8>, Error = String>,
+{
+    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String> { T::try_from(bytes) }
+}
+
+#[cfg(feature = "use_serde")]
+impl<T> FromBytes for T
+where
+    T: serde::de::DeserializeOwned + 'static,
+{
+    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String> {
+        let s = String::from_utf8_lossy(bytes);
+        match serde_json::from_str::<T>(s.as_ref()) {
+            Ok(data) => Ok(data),
+            Err(e) => Err(format!("{:?}", e)),
+        }
+    }
+}
+
+impl<T> FromRequest for Data<T>
+where
+    T: FromBytes + 'static,
+{
+    type Error = SystemError;
+    type Future = Ready<Result<Self, SystemError>>;
+
+    #[inline]
+    fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
+        match payload {
+            Payload::None => ready(Err(unexpected_none_payload(req))),
+            Payload::Bytes(bytes) => match T::parse_from_bytes(bytes) {
+                Ok(data) => ready(Ok(Data(data))),
+                Err(e) => ready(Err(InternalError::new(format!("{:?}", e)).into())),
+            },
+        }
+    }
+}
+
+impl<T> Responder for Data<T>
+where
+    T: ToBytes,
+{
+    fn respond_to(self, _request: &EventRequest) -> EventResponse {
+        match self.into_inner().into_bytes() {
+            Ok(bytes) => ResponseBuilder::Ok().data(bytes.to_vec()).build(),
+            Err(e) => {
+                let system_err: SystemError = InternalError::new(format!("{:?}", e)).into();
+                system_err.into()
+            },
+        }
+    }
+}
+
+impl<T> std::convert::From<T> for Data<T>
+where
+    T: ToBytes,
+{
+    fn from(val: T) -> Self { Data(val) }
+}
+
+impl<T> std::convert::TryFrom<&Payload> for Data<T>
+where
+    T: FromBytes,
+{
+    type Error = String;
+
+    fn try_from(payload: &Payload) -> Result<Data<T>, Self::Error> {
+        match payload {
+            Payload::None => Err(format!("Expected payload")),
+            Payload::Bytes(bytes) => match T::parse_from_bytes(bytes) {
+                Ok(data) => Ok(Data(data)),
+                Err(e) => Err(e),
+            },
+        }
+    }
+}
+
+impl<T> std::convert::TryInto<Payload> for Data<T>
+where
+    T: ToBytes,
+{
+    type Error = String;
+
+    fn try_into(self) -> Result<Payload, Self::Error> {
+        let inner = self.into_inner();
+        let bytes = inner.into_bytes()?;
+        Ok(Payload::Bytes(bytes))
+    }
+}

+ 18 - 2
rust-lib/flowy-sys/src/dispatch.rs

@@ -12,6 +12,7 @@ use futures_util::task::Context;
 use lazy_static::lazy_static;
 use pin_project::pin_project;
 use std::{
+    convert::TryInto,
     fmt::{Debug, Display},
     future::Future,
     hash::Hash,
@@ -115,18 +116,33 @@ pub struct DispatchRequest {
 }
 
 impl DispatchRequest {
-    pub fn new<E>(event: E, payload: Payload) -> Self
+    pub fn new<E>(event: E) -> Self
     where
         E: Eq + Hash + Debug + Clone + Display,
     {
         Self {
-            payload,
+            payload: Payload::None,
             event: event.into(),
             id: uuid::Uuid::new_v4().to_string(),
             callback: None,
         }
     }
 
+    pub fn payload<P>(mut self, payload: P) -> Self
+    where
+        P: TryInto<Payload, Error = String>,
+    {
+        let payload = match payload.try_into() {
+            Ok(payload) => payload,
+            Err(e) => {
+                log::error!("{}", e);
+                Payload::None
+            },
+        };
+        self.payload = payload;
+        self
+    }
+
     pub fn callback(mut self, callback: BoxFutureCallback) -> Self {
         self.callback = Some(callback);
         self

+ 0 - 2
rust-lib/flowy-sys/src/error/mod.rs

@@ -1,5 +1,3 @@
 mod error;
 
-pub type ResponseResult<T, E> = std::result::Result<crate::request::Data<T>, E>;
-
 pub use error::*;

+ 2 - 1
rust-lib/flowy-sys/src/lib.rs

@@ -8,9 +8,10 @@ mod rt;
 mod service;
 mod util;
 
+mod data;
 mod dispatch;
 mod system;
 
 pub mod prelude {
-    pub use crate::{dispatch::*, error::*, module::*, request::*, response::*, rt::*};
+    pub use crate::{data::*, dispatch::*, error::*, module::*, request::*, response::*, rt::*};
 }

+ 10 - 0
rust-lib/flowy-sys/src/request/payload.rs

@@ -38,6 +38,16 @@ impl std::convert::Into<Payload> for Vec<u8> {
     fn into(self) -> Payload { Payload::Bytes(self) }
 }
 
+// = note: conflicting implementation in crate `core`:
+// - impl<T, U> TryInto<U> for T where U: TryFrom<T>;
+//
+// impl std::convert::TryInto<Payload> for Vec<u8> {
+//     type Error = String;
+//     fn try_into(self) -> Result<Payload, Self::Error> {
+//         Ok(Payload::Bytes(self))
+//     }
+// }
+
 impl std::convert::Into<Payload> for &str {
     fn into(self) -> Payload { self.to_string().into() }
 }

+ 1 - 64
rust-lib/flowy-sys/src/request/request.rs

@@ -10,7 +10,6 @@ use crate::{
 use futures_core::ready;
 use std::{
     fmt::Debug,
-    ops,
     pin::Pin,
     task::{Context, Poll},
 };
@@ -61,7 +60,7 @@ impl FromRequest for String {
     }
 }
 
-fn unexpected_none_payload(request: &EventRequest) -> SystemError {
+pub fn unexpected_none_payload(request: &EventRequest) -> SystemError {
     log::warn!("{:?} expected payload", &request.event);
     InternalError::new("Expected payload").into()
 }
@@ -99,65 +98,3 @@ where
         Poll::Ready(Ok(res))
     }
 }
-
-pub struct Data<T>(pub T);
-
-impl<T> Data<T> {
-    pub fn into_inner(self) -> T { self.0 }
-}
-
-impl<T> ops::Deref for Data<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T { &self.0 }
-}
-
-impl<T> ops::DerefMut for Data<T> {
-    fn deref_mut(&mut self) -> &mut T { &mut self.0 }
-}
-
-pub trait FromBytes: Sized {
-    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String>;
-}
-
-#[cfg(feature = "use_protobuf")]
-impl<T> FromBytes for T
-where
-    // https://stackoverflow.com/questions/62871045/tryfromu8-trait-bound-in-trait
-    T: for<'a> std::convert::TryFrom<&'a Vec<u8>, Error = String>,
-{
-    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String> { T::try_from(bytes) }
-}
-
-#[cfg(feature = "use_serde")]
-impl<T> FromBytes for T
-where
-    T: serde::de::DeserializeOwned + 'static,
-{
-    fn parse_from_bytes(bytes: &Vec<u8>) -> Result<Self, String> {
-        let s = String::from_utf8_lossy(bytes);
-        match serde_json::from_str::<T>(s.as_ref()) {
-            Ok(data) => Ok(data),
-            Err(e) => Err(format!("{:?}", e)),
-        }
-    }
-}
-
-impl<T> FromRequest for Data<T>
-where
-    T: FromBytes + 'static,
-{
-    type Error = SystemError;
-    type Future = Ready<Result<Self, SystemError>>;
-
-    #[inline]
-    fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
-        match payload {
-            Payload::None => ready(Err(unexpected_none_payload(req))),
-            Payload::Bytes(bytes) => match T::parse_from_bytes(bytes) {
-                Ok(data) => ready(Ok(Data(data))),
-                Err(e) => ready(Err(InternalError::new(format!("{:?}", e)).into())),
-            },
-        }
-    }
-}

+ 1 - 23
rust-lib/flowy-sys/src/response/responder.rs

@@ -1,7 +1,7 @@
 #[allow(unused_imports)]
 use crate::error::{InternalError, SystemError};
 use crate::{
-    request::{Data, EventRequest},
+    request::EventRequest,
     response::{EventResponse, ResponseBuilder},
 };
 use bytes::Bytes;
@@ -62,25 +62,3 @@ where
         }
     }
 }
-
-impl<T> Responder for Data<T>
-where
-    T: ToBytes,
-{
-    fn respond_to(self, _request: &EventRequest) -> EventResponse {
-        match self.into_inner().into_bytes() {
-            Ok(bytes) => ResponseBuilder::Ok().data(bytes.to_vec()).build(),
-            Err(e) => {
-                let system_err: SystemError = InternalError::new(format!("{:?}", e)).into();
-                system_err.into()
-            },
-        }
-    }
-}
-
-impl<T> std::convert::From<T> for Data<T>
-where
-    T: ToBytes,
-{
-    fn from(val: T) -> Self { Data(val) }
-}

+ 4 - 1
rust-lib/flowy-sys/src/response/response.rs

@@ -1,6 +1,7 @@
 use crate::{
+    data::Data,
     error::SystemError,
-    request::{Data, EventRequest, Payload},
+    request::{EventRequest, Payload},
     response::Responder,
 };
 use std::{fmt, fmt::Formatter};
@@ -51,6 +52,8 @@ impl Responder for EventResponse {
     fn respond_to(self, _: &EventRequest) -> EventResponse { self }
 }
 
+pub type ResponseResult<T, E> = std::result::Result<Data<T>, E>;
+
 pub fn response_ok<T, E>(data: T) -> Result<Data<T>, E>
 where
     E: Into<SystemError>,

+ 1 - 1
rust-lib/flowy-sys/tests/api/module.rs

@@ -9,7 +9,7 @@ async fn test_init() {
     let event = "1";
     init_dispatch(|| vec![Module::new().event(event, hello)]);
 
-    let request = DispatchRequest::new(event, Payload::None);
+    let request = DispatchRequest::new(event);
     let resp = async_send(request).await;
     dbg!(&resp);
 }

+ 17 - 0
rust-lib/flowy-test/Cargo.toml

@@ -0,0 +1,17 @@
+[package]
+name = "flowy-test"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+flowy-sdk = { path = "../flowy-sdk"}
+flowy-sys = { path = "../flowy-sys"}
+
+serde = { version = "1.0", features = ["derive"] }
+bincode = { version = "1.3"}
+protobuf = {version = "2.24.1"}
+claim = "0.5.0"
+tokio = { version = "1", features = ["full"]}
+futures-util = "0.3.15"

+ 105 - 0
rust-lib/flowy-test/src/lib.rs

@@ -0,0 +1,105 @@
+pub use flowy_sdk::*;
+use flowy_sys::prelude::*;
+use std::{
+    convert::TryFrom,
+    fmt::{Debug, Display},
+    fs,
+    hash::Hash,
+    path::PathBuf,
+    sync::Once,
+};
+
+pub mod prelude {
+    pub use crate::EventTester;
+    pub use flowy_sys::prelude::*;
+    pub use std::convert::TryFrom;
+}
+
+static INIT: Once = Once::new();
+pub fn init_sdk() {
+    let root_dir = root_dir();
+
+    INIT.call_once(|| {
+        FlowySDK::init_log(&root_dir);
+    });
+    FlowySDK::init(&root_dir);
+}
+
+fn root_dir() -> String {
+    // https://doc.rust-lang.org/cargo/reference/environment-variables.html
+    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or("./".to_owned());
+    let mut path_buf = fs::canonicalize(&PathBuf::from(&manifest_dir)).unwrap();
+    path_buf.pop(); // rust-lib
+    path_buf.push("flowy-test");
+    path_buf.push("temp");
+    path_buf.push("flowy");
+
+    let root_dir = path_buf.to_str().unwrap().to_string();
+    if !std::path::Path::new(&root_dir).exists() {
+        std::fs::create_dir_all(&root_dir).unwrap();
+    }
+    root_dir
+}
+
+pub struct EventTester {
+    request: DispatchRequest,
+    assert_status_code: Option<StatusCode>,
+}
+
+impl EventTester {
+    pub fn new<E>(event: E) -> Self
+    where
+        E: Eq + Hash + Debug + Clone + Display,
+    {
+        init_sdk();
+        let request = DispatchRequest::new(event);
+        Self {
+            request,
+            assert_status_code: None,
+        }
+    }
+
+    pub fn payload<P>(mut self, payload: P) -> Self
+    where
+        P: ToBytes,
+    {
+        self.request = self.request.payload(Data(payload));
+        self
+    }
+
+    pub fn assert_status_code(mut self, status_code: StatusCode) -> Self {
+        self.assert_status_code = Some(status_code);
+        self
+    }
+
+    #[allow(dead_code)]
+    pub async fn async_send<R>(self) -> R
+    where
+        R: FromBytes,
+    {
+        let resp = async_send(self.request).await;
+        dbg!(&resp);
+        data_from_response(&resp)
+    }
+
+    pub fn sync_send<R>(self) -> R
+    where
+        R: FromBytes,
+    {
+        let resp = sync_send(self.request);
+        if let Some(status_code) = self.assert_status_code {
+            assert_eq!(resp.status_code, status_code)
+        }
+
+        dbg!(&resp);
+        data_from_response(&resp)
+    }
+}
+
+fn data_from_response<R>(response: &EventResponse) -> R
+where
+    R: FromBytes,
+{
+    let result = <Data<R>>::try_from(&response.payload).unwrap().into_inner();
+    result
+}

+ 4 - 1
rust-lib/flowy-user/Cargo.toml

@@ -18,9 +18,12 @@ rand = { version = "0.8", features=["std_rng"] }
 unicode-segmentation = "1.7.1"
 log = "0.4.14"
 protobuf = {version = "2.18.0"}
+lazy_static = "1.4.0"
+fancy-regex = "0.5.0"
 
 [dev-dependencies]
 quickcheck = "0.9.2"
 quickcheck_macros = "0.9.1"
 fake = "~2.3.0"
-claim = "0.4.0"
+claim = "0.4.0"
+flowy-test = { path = "../flowy-test" }

+ 0 - 1
rust-lib/flowy-user/src/domain/user/user.rs

@@ -1,6 +1,5 @@
 use crate::domain::{UserEmail, UserName, UserPassword};
 use flowy_derive::ProtoBuf;
-use std::convert::TryInto;
 
 #[derive(ProtoBuf, Default)]
 pub struct User {

+ 5 - 1
rust-lib/flowy-user/src/domain/user/user_email.rs

@@ -5,10 +5,14 @@ pub struct UserEmail(pub String);
 
 impl UserEmail {
     pub fn parse(s: String) -> Result<UserEmail, String> {
+        if s.trim().is_empty() {
+            return Err(format!("Email can not be empty or whitespace"));
+        }
+
         if validate_email(&s) {
             Ok(Self(s))
         } else {
-            Err(format!("{} is not a valid subscriber email.", s))
+            Err(format!("{} is not a valid email.", s))
         }
     }
 }

+ 1 - 1
rust-lib/flowy-user/src/domain/user/user_name.rs

@@ -19,7 +19,7 @@ impl UserName {
         let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
 
         if is_empty_or_whitespace || is_too_long || contains_forbidden_characters {
-            Err(format!("{} is not a valid subscriber name.", s))
+            Err(format!("{} is not a valid name.", s))
         } else {
             Ok(Self(s))
         }

+ 38 - 1
rust-lib/flowy-user/src/domain/user/user_password.rs

@@ -1,6 +1,43 @@
+use fancy_regex::Regex;
+use lazy_static::lazy_static;
+use unicode_segmentation::UnicodeSegmentation;
 #[derive(Debug)]
 pub struct UserPassword(pub String);
 
 impl UserPassword {
-    pub fn parse(s: String) -> Result<UserPassword, String> { Ok(Self(s)) }
+    pub fn parse(s: String) -> Result<UserPassword, String> {
+        let is_empty_or_whitespace = s.trim().is_empty();
+        if is_empty_or_whitespace {
+            return Err(format!("Password can not be empty or whitespace."));
+        }
+        let is_too_long = s.graphemes(true).count() > 100;
+        let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
+        let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
+        let is_invalid_password = !validate_password(&s);
+
+        if is_too_long || contains_forbidden_characters || is_invalid_password {
+            Err(format!("{} is not a valid password.", s))
+        } else {
+            Ok(Self(s))
+        }
+    }
+}
+
+lazy_static! {
+    // Test it in https://regex101.com/
+    // https://stackoverflow.com/questions/2370015/regular-expression-for-password-validation/2370045
+    // Hell1!
+    // [invalid, less than 6]
+    // Hel1!
+    //
+    // Hello1!
+    // [invalid, must include number]
+    // Hello!
+    //
+    // Hello12!
+    // [invalid must include upper case]
+    // hello12!
+    static ref PASSWORD: Regex = Regex::new("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\\W]).{6,20})").unwrap();
 }
+
+pub fn validate_password(password: &str) -> bool { PASSWORD.is_match(password).is_ok() }

+ 0 - 13
rust-lib/flowy-user/src/event.rs

@@ -1,13 +0,0 @@
-use derive_more::Display;
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash)]
-pub enum UserEvent {
-    #[display(fmt = "AuthCheck")]
-    AuthCheck = 0,
-    #[display(fmt = "SignIn")]
-    SignIn    = 1,
-    #[display(fmt = "SignUp")]
-    SignUp    = 2,
-    #[display(fmt = "SignOut")]
-    SignOut   = 3,
-}

+ 1 - 6
rust-lib/flowy-user/src/lib.rs

@@ -1,14 +1,9 @@
 mod domain;
 mod error;
-pub mod event;
 mod handlers;
 pub mod module;
 mod protobuf;
 
 pub mod prelude {
-    pub use crate::{
-        domain::*,
-        event::{UserEvent::*, *},
-        handlers::auth::*,
-    };
+    pub use crate::{domain::*, handlers::auth::*, module::UserEvent::*};
 }

+ 17 - 3
rust-lib/flowy-user/src/module.rs

@@ -1,9 +1,23 @@
-use crate::{event::UserEvent::*, handlers::*};
+use crate::handlers::*;
 use flowy_sys::prelude::*;
 
+use derive_more::Display;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash)]
+pub enum UserEvent {
+    #[display(fmt = "AuthCheck")]
+    AuthCheck = 0,
+    #[display(fmt = "SignIn")]
+    SignIn    = 1,
+    #[display(fmt = "SignUp")]
+    SignUp    = 2,
+    #[display(fmt = "SignOut")]
+    SignOut   = 3,
+}
+
 pub fn create() -> Module {
     Module::new()
         .name("Flowy-User")
-        .event(SignIn, user_sign_in)
-        .event(SignUp, user_sign_up)
+        .event(UserEvent::SignIn, user_sign_in)
+        .event(UserEvent::SignUp, user_sign_up)
 }

+ 0 - 0
rust-lib/flowy-sdk/tests/sdk/user/mod.rs → rust-lib/flowy-user/tests/main.rs


+ 32 - 0
rust-lib/flowy-user/tests/sign_in.rs

@@ -0,0 +1,32 @@
+use flowy_test::prelude::*;
+use flowy_user::prelude::*;
+
+#[test]
+#[should_panic]
+fn sign_in_without_password() {
+    let params = UserSignInParams {
+        email: "[email protected]".to_string(),
+        password: "".to_string(),
+    };
+
+    let result = EventTester::new(SignIn)
+        .payload(params)
+        .assert_status_code(StatusCode::Err)
+        .sync_send::<UserSignInResult>();
+    dbg!(&result);
+}
+
+#[test]
+#[should_panic]
+fn sign_in_without_email() {
+    let params = UserSignInParams {
+        email: "".to_string(),
+        password: "HelloWorld!123".to_string(),
+    };
+
+    let result = EventTester::new(SignIn)
+        .payload(params)
+        .assert_status_code(StatusCode::Err)
+        .sync_send::<UserSignInResult>();
+    dbg!(&result);
+}