| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 | use flowy_folder2::entities::icon::{UpdateViewIconPayloadPB, ViewIconPB, ViewIconTypePB};use flowy_folder2::entities::*;use flowy_test::event_builder::EventBuilder;use flowy_test::FlowyCoreTest;use flowy_user::errors::ErrorCode;#[tokio::test]async fn create_workspace_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let request = CreateWorkspacePayloadPB {    name: "my second workspace".to_owned(),    desc: "".to_owned(),  };  let resp = EventBuilder::new(test)    .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)    .payload(request)    .async_send()    .await    .parse::<flowy_folder2::entities::WorkspacePB>();  assert_eq!(resp.name, "my second workspace");}#[tokio::test]async fn open_workspace_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let payload = CreateWorkspacePayloadPB {    name: "my second workspace".to_owned(),    desc: "".to_owned(),  };  // create a workspace  let resp_1 = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)    .payload(payload)    .async_send()    .await    .parse::<flowy_folder2::entities::WorkspacePB>();  // open the workspace  let payload = WorkspaceIdPB {    value: Some(resp_1.id.clone()),  };  let resp_2 = EventBuilder::new(test)    .event(flowy_folder2::event_map::FolderEvent::OpenWorkspace)    .payload(payload)    .async_send()    .await    .parse::<flowy_folder2::entities::WorkspacePB>();  assert_eq!(resp_1.id, resp_2.id);  assert_eq!(resp_1.name, resp_2.name);}#[tokio::test]async fn create_view_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  assert_eq!(view.parent_view_id, current_workspace.id);  assert_eq!(view.name, "My first view");  assert_eq!(view.layout, ViewLayoutPB::Document);}#[tokio::test]async fn update_view_event_with_name_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  let error = test    .update_view(UpdateViewPayloadPB {      view_id: view.id.clone(),      name: Some("My second view".to_string()),      ..Default::default()    })    .await;  assert!(error.is_none());  let view = test.get_view(&view.id).await;  assert_eq!(view.name, "My second view");}#[tokio::test]async fn update_view_icon_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  let new_icon = ViewIconPB {    ty: ViewIconTypePB::Emoji,    value: "👍".to_owned(),  };  let error = test    .update_view_icon(UpdateViewIconPayloadPB {      view_id: view.id.clone(),      icon: Some(new_icon.clone()),    })    .await;  assert!(error.is_none());  let view = test.get_view(&view.id).await;  assert_eq!(view.icon, Some(new_icon));}#[tokio::test]async fn delete_view_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  test.delete_view(&view.id).await;  // Try the read the view  let payload = ViewIdPB {    value: view.id.clone(),  };  let error = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadView)    .payload(payload)    .async_send()    .await    .error()    .unwrap();  assert_eq!(error.code, ErrorCode::RecordNotFound);}#[tokio::test]async fn put_back_trash_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  test.delete_view(&view.id).await;  // After delete view, the view will be moved to trash  let payload = ViewIdPB {    value: view.id.clone(),  };  let error = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadView)    .payload(payload)    .async_send()    .await    .error()    .unwrap();  assert_eq!(error.code, ErrorCode::RecordNotFound);  let payload = TrashIdPB {    id: view.id.clone(),  };  EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::PutbackTrash)    .payload(payload)    .async_send()    .await;  let payload = ViewIdPB {    value: view.id.clone(),  };  let error = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadView)    .payload(payload)    .async_send()    .await    .error();  assert!(error.is_none());}#[tokio::test]async fn delete_view_permanently_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let view = test    .create_view(¤t_workspace.id, "My first view".to_string())    .await;  let payload = RepeatedViewIdPB {    items: vec![view.id.clone()],  };  // delete the view. the view will be moved to trash  EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::DeleteView)    .payload(payload)    .async_send()    .await;  let trash = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadTrash)    .async_send()    .await    .parse::<flowy_folder2::entities::RepeatedTrashPB>()    .items;  assert_eq!(trash.len(), 1);  assert_eq!(trash[0].id, view.id);  // delete the view from trash  let payload = RepeatedTrashIdPB {    items: vec![TrashIdPB {      id: view.id.clone(),    }],  };  EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::DeleteTrash)    .payload(payload)    .async_send()    .await;  // After delete the last view, the trash should be empty  let trash = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadTrash)    .async_send()    .await    .parse::<flowy_folder2::entities::RepeatedTrashPB>()    .items;  assert!(trash.is_empty());}#[tokio::test]async fn delete_all_trash_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  for i in 0..3 {    let view = test      .create_view(¤t_workspace.id, format!("My {} view", i))      .await;    let payload = RepeatedViewIdPB {      items: vec![view.id.clone()],    };    // delete the view. the view will be moved to trash    EventBuilder::new(test.clone())      .event(flowy_folder2::event_map::FolderEvent::DeleteView)      .payload(payload)      .async_send()      .await;  }  let trash = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadTrash)    .async_send()    .await    .parse::<flowy_folder2::entities::RepeatedTrashPB>()    .items;  assert_eq!(trash.len(), 3);  // Delete all the trash  EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::DeleteAllTrash)    .async_send()    .await;  // After delete the last view, the trash should be empty  let trash = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::ReadTrash)    .async_send()    .await    .parse::<flowy_folder2::entities::RepeatedTrashPB>()    .items;  assert!(trash.is_empty());}#[tokio::test]async fn multiple_hierarchy_view_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  for i in 1..4 {    let parent = test      .create_view(¤t_workspace.id, format!("My {} view", i))      .await;    for j in 1..3 {      let child = test        .create_view(&parent.id, format!("My {}-{} view", i, j))        .await;      for k in 1..2 {        let _sub_child = test          .create_view(&child.id, format!("My {}-{}-{} view", i, j, k))          .await;      }    }  }  let mut views = test.get_all_workspace_views().await;  // There will be one default view when AppFlowy is initialized. So there will be 4 views in total  assert_eq!(views.len(), 4);  views.remove(0);  // workspace  //   - view1  //     - view1-1  //       - view1-1-1  //     - view1-2  //       - view1-2-1  //   - view2  //     - view2-1  //       - view2-1-1  //     - view2-2  //       - view2-2-1  //   - view3  //     - view3-1  //       - view3-1-1  //     - view3-2  //       - view3-2-1  assert_eq!(views[0].name, "My 1 view");  assert_eq!(views[1].name, "My 2 view");  assert_eq!(views[2].name, "My 3 view");  assert_eq!(views[0].child_views.len(), 2);  // By default only the first level of child views will be loaded  assert!(views[0].child_views[0].child_views.is_empty());  for (i, view) in views.into_iter().enumerate() {    for (j, child_view) in view.child_views.into_iter().enumerate() {      let payload = ViewIdPB {        value: child_view.id.clone(),      };      let child = EventBuilder::new(test.clone())        .event(flowy_folder2::event_map::FolderEvent::ReadView)        .payload(payload)        .async_send()        .await        .parse::<flowy_folder2::entities::ViewPB>();      assert_eq!(child.name, format!("My {}-{} view", i + 1, j + 1));      assert_eq!(child.child_views.len(), 1);      // By default only the first level of child views will be loaded      assert!(child.child_views[0].child_views.is_empty());      for (k, _child_view) in child_view.child_views.into_iter().enumerate() {        // Get the last level view        let sub_child = test.get_view(&child.id).await;        assert_eq!(child.name, format!("My {}-{}-{} view", i + 1, j + 1, k + 1));        assert!(sub_child.child_views.is_empty());      }    }  }}#[tokio::test]async fn move_view_event_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  for i in 1..4 {    let parent = test      .create_view(¤t_workspace.id, format!("My {} view", i))      .await;    for j in 1..3 {      let _ = test        .create_view(&parent.id, format!("My {}-{} view", i, j))        .await;    }  }  let views = test.get_all_workspace_views().await;  // There will be one default view when AppFlowy is initialized. So there will be 4 views in total  assert_eq!(views.len(), 4);  assert_eq!(views[1].name, "My 1 view");  assert_eq!(views[2].name, "My 2 view");  assert_eq!(views[3].name, "My 3 view");  let payload = MoveViewPayloadPB {    view_id: views[1].id.clone(),    from: 1,    to: 2,  };  let _ = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::MoveView)    .payload(payload)    .async_send()    .await;  let views = test.get_all_workspace_views().await;  assert_eq!(views[1].name, "My 2 view");  assert_eq!(views[2].name, "My 1 view");  assert_eq!(views[3].name, "My 3 view");}#[tokio::test]async fn move_view_event_after_delete_view_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  for i in 1..6 {    let _ = test      .create_view(¤t_workspace.id, format!("My {} view", i))      .await;  }  let views = test.get_all_workspace_views().await;  assert_eq!(views[1].name, "My 1 view");  assert_eq!(views[2].name, "My 2 view");  assert_eq!(views[3].name, "My 3 view");  assert_eq!(views[4].name, "My 4 view");  assert_eq!(views[5].name, "My 5 view");  test.delete_view(&views[3].id).await;  // There will be one default view when AppFlowy is initialized. So there will be 4 views in total  let views = test.get_all_workspace_views().await;  assert_eq!(views[1].name, "My 1 view");  assert_eq!(views[2].name, "My 2 view");  assert_eq!(views[3].name, "My 4 view");  assert_eq!(views[4].name, "My 5 view");  let payload = MoveViewPayloadPB {    view_id: views[1].id.clone(),    from: 1,    to: 3,  };  let _ = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::MoveView)    .payload(payload)    .async_send()    .await;  let views = test.get_all_workspace_views().await;  assert_eq!(views[1].name, "My 2 view");  assert_eq!(views[2].name, "My 4 view");  assert_eq!(views[3].name, "My 1 view");  assert_eq!(views[4].name, "My 5 view");}#[tokio::test]async fn move_view_event_after_delete_view_test2() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let parent = test    .create_view(¤t_workspace.id, "My view".to_string())    .await;  for j in 1..6 {    let _ = test      .create_view(&parent.id, format!("My 1-{} view", j))      .await;  }  let views = test.get_view(&parent.id).await.child_views;  assert_eq!(views.len(), 5);  assert_eq!(views[0].name, "My 1-1 view");  assert_eq!(views[1].name, "My 1-2 view");  assert_eq!(views[2].name, "My 1-3 view");  assert_eq!(views[3].name, "My 1-4 view");  assert_eq!(views[4].name, "My 1-5 view");  test.delete_view(&views[2].id).await;  let payload = MoveViewPayloadPB {    view_id: views[0].id.clone(),    from: 0,    to: 2,  };  let _ = EventBuilder::new(test.clone())    .event(flowy_folder2::event_map::FolderEvent::MoveView)    .payload(payload)    .async_send()    .await;  let views = test.get_view(&parent.id).await.child_views;  assert_eq!(views[0].name, "My 1-2 view");  assert_eq!(views[1].name, "My 1-4 view");  assert_eq!(views[2].name, "My 1-1 view");  assert_eq!(views[3].name, "My 1-5 view");}#[tokio::test]async fn create_parent_view_with_invalid_name() {  for (name, code) in invalid_workspace_name_test_case() {    let sdk = FlowyCoreTest::new();    let request = CreateWorkspacePayloadPB {      name,      desc: "".to_owned(),    };    assert_eq!(      EventBuilder::new(sdk)        .event(flowy_folder2::event_map::FolderEvent::CreateWorkspace)        .payload(request)        .async_send()        .await        .error()        .unwrap()        .code,      code    )  }}fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {  vec![    ("".to_owned(), ErrorCode::WorkspaceNameInvalid),    ("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),  ]}#[tokio::test]async fn move_view_across_parent_test() {  let test = FlowyCoreTest::new_with_guest_user().await;  let current_workspace = test.get_current_workspace().await.workspace;  let parent_1 = test    .create_view(¤t_workspace.id, "My view 1".to_string())    .await;  let parent_2 = test    .create_view(¤t_workspace.id, "My view 2".to_string())    .await;  for j in 1..6 {    let _ = test      .create_view(&parent_1.id, format!("My 1-{} view 1", j))      .await;  }  let views = test.get_view(&parent_1.id).await.child_views;  // Move `My 1-1 view 1` to `My view 2`  let move_view_id = views[0].id.clone();  let new_parent_id = parent_2.id.clone();  let prev_id = None;  move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;  let parent1_views = test.get_view(&parent_1.id).await.child_views;  let parent2_views = test.get_view(&parent_2.id).await.child_views;  assert_eq!(parent2_views.len(), 1);  assert_eq!(parent2_views[0].name, "My 1-1 view 1");  assert_eq!(parent1_views[0].name, "My 1-2 view 1");  // Move My 1-2 view 1 from My view 1 to the current workspace and insert it after My view 1.  let move_view_id = parent1_views[0].id.clone();  let new_parent_id = current_workspace.id.clone();  let prev_id = Some(parent_1.id.clone());  move_folder_nested_view(test.clone(), move_view_id, new_parent_id, prev_id).await;  let parent1_views = test.get_view(&parent_1.id).await.child_views;  let workspace_views = test.get_all_workspace_views().await;  let workspace_views_len = workspace_views.len();  assert_eq!(parent1_views[0].name, "My 1-3 view 1");  assert_eq!(workspace_views[workspace_views_len - 3].name, "My view 1");  assert_eq!(    workspace_views[workspace_views_len - 2].name,    "My 1-2 view 1"  );  assert_eq!(workspace_views[workspace_views_len - 1].name, "My view 2");}async fn move_folder_nested_view(  sdk: FlowyCoreTest,  view_id: String,  new_parent_id: String,  prev_view_id: Option<String>,) {  let payload = MoveNestedViewPayloadPB {    view_id,    new_parent_id,    prev_view_id,  };  EventBuilder::new(sdk)    .event(flowy_folder2::event_map::FolderEvent::MoveNestedView)    .payload(payload)    .async_send()    .await;}
 |