chore: add group unit test

This commit is contained in:
appflowy 2022-08-18 21:43:05 +08:00
parent af23e3e803
commit 0680b20579
20 changed files with 192 additions and 55 deletions

View File

@ -1,10 +1,8 @@
import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
class BoardTextCell extends StatefulWidget {
final GridCellControllerBuilder cellControllerBuilder;

View File

@ -1,5 +1,5 @@
pub use crate::entities::view::ViewDataTypePB;
use crate::entities::{ViewInfoPB, ViewLayoutTypePB};
use crate::entities::ViewInfoPB;
use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
use crate::{
dart_notification::{send_dart_notification, FolderNotification},

View File

@ -1,6 +1,7 @@
use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
use flowy_folder::entities::view::ViewDataTypePB;
use flowy_folder::entities::workspace::CreateWorkspacePayloadPB;
use flowy_folder::entities::ViewLayoutTypePB;
use flowy_revision::disk::RevisionState;
use flowy_test::{event_builder::*, FlowySDKTest};
@ -135,11 +136,13 @@ async fn app_create_with_view() {
name: "View A".to_owned(),
desc: "View A description".to_owned(),
data_type: ViewDataTypePB::Text,
layout: ViewLayoutTypePB::Document,
},
CreateView {
name: "Grid".to_owned(),
desc: "Grid description".to_owned(),
data_type: ViewDataTypePB::Database,
layout: ViewLayoutTypePB::Document,
},
ReadApp(app.id),
])
@ -199,11 +202,13 @@ async fn view_delete_all() {
name: "View A".to_owned(),
desc: "View A description".to_owned(),
data_type: ViewDataTypePB::Text,
layout: ViewLayoutTypePB::Document,
},
CreateView {
name: "Grid".to_owned(),
desc: "Grid description".to_owned(),
data_type: ViewDataTypePB::Database,
layout: ViewLayoutTypePB::Document,
},
ReadApp(app.id.clone()),
])
@ -232,6 +237,7 @@ async fn view_delete_all_permanent() {
name: "View A".to_owned(),
desc: "View A description".to_owned(),
data_type: ViewDataTypePB::Text,
layout: ViewLayoutTypePB::Document,
},
ReadApp(app.id.clone()),
])
@ -331,6 +337,7 @@ async fn folder_sync_revision_with_new_view() {
name: view_name.clone(),
desc: view_desc.clone(),
data_type: ViewDataTypePB::Text,
layout: ViewLayoutTypePB::Document,
},
AssertCurrentRevId(3),
AssertNextSyncRevId(Some(3)),

View File

@ -28,7 +28,20 @@ impl std::convert::From<&GroupConfigurationRevision> for GridGroupConfigurationP
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridGroupPB {
#[pb(index = 1)]
pub(crate) items: Vec<GroupPB>,
pub items: Vec<GroupPB>,
}
impl std::ops::Deref for RepeatedGridGroupPB {
type Target = Vec<GroupPB>;
fn deref(&self) -> &Self::Target {
&self.items
}
}
impl std::ops::DerefMut for RepeatedGridGroupPB {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.items
}
}
#[derive(ProtoBuf, Debug, Default, Clone)]

View File

@ -9,9 +9,7 @@ use crate::services::field::{default_type_option_builder_from_type, type_option_
use crate::services::filter::GridFilterService;
use crate::services::grid_view_manager::GridViewManager;
use crate::services::persistence::block_index::BlockIndexCache;
use crate::services::row::{
make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder,
};
use crate::services::row::{make_grid_blocks, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder};
use bytes::Bytes;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::*;

View File

@ -13,6 +13,7 @@ use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
use flowy_sync::entities::grid::GridSettingChangesetParams;
use flowy_sync::entities::revision::Revision;
use lib_infra::future::{wrap_future, AFFuture, FutureResult};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
@ -26,6 +27,7 @@ pub struct GridViewRevisionEditor {
row_delegate: Arc<dyn GridViewRowDelegate>,
group_service: Arc<RwLock<GroupService>>,
scheduler: Arc<dyn GridServiceTaskScheduler>,
did_load_group: AtomicBool,
}
impl GridViewRevisionEditor {
@ -46,6 +48,7 @@ impl GridViewRevisionEditor {
let rev_manager = Arc::new(rev_manager);
let group_service = GroupService::new(Box::new(pad.clone())).await;
let user_id = user_id.to_owned();
let did_load_group = AtomicBool::new(false);
Ok(Self {
pad,
user_id,
@ -55,6 +58,7 @@ impl GridViewRevisionEditor {
field_delegate,
row_delegate,
group_service: Arc::new(RwLock::new(group_service)),
did_load_group,
})
}
@ -140,19 +144,25 @@ impl GridViewRevisionEditor {
}
pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
let field_revs = self.field_delegate.get_field_revs().await;
let row_revs = self.row_delegate.gv_row_revs().await;
let groups = if !self.did_load_group.load(Ordering::SeqCst) {
self.did_load_group.store(true, Ordering::SeqCst);
let field_revs = self.field_delegate.get_field_revs().await;
let row_revs = self.row_delegate.gv_row_revs().await;
match self
.group_service
.write()
.await
.load_groups(&field_revs, row_revs)
.await
{
None => vec![],
Some(groups) => groups,
}
} else {
self.group_service.read().await.groups().await
};
match self
.group_service
.write()
.await
.load_groups(&field_revs, row_revs)
.await
{
None => Ok(vec![]),
Some(groups) => Ok(groups.into_iter().map(GroupPB::from).collect()),
}
Ok(groups.into_iter().map(GroupPB::from).collect())
}
pub(crate) async fn get_setting(&self) -> GridSettingPB {

View File

@ -37,9 +37,9 @@ impl Groupable for CheckboxGroupController {
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
_field_rev: &FieldRevision,
_row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
_row_changeset: &mut RowChangeset,
_cell_data: &Self::CellDataType,
_to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> {

View File

@ -47,7 +47,7 @@ pub trait GroupController: GroupControllerSharedAction + Send + Sync {
pub trait GroupControllerSharedAction: Send + Sync {
// The field that is used for grouping the rows
fn field_id(&self) -> &str;
fn build_groups(&self) -> Vec<Group>;
fn groups(&self) -> Vec<Group>;
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
fn did_update_row(
&mut self,
@ -194,7 +194,7 @@ where
&self.field_id
}
fn build_groups(&self) -> Vec<Group> {
fn groups(&self) -> Vec<Group> {
let default_group = self.default_group.clone();
let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
if !default_group.rows.is_empty() {

View File

@ -249,11 +249,9 @@ fn move_row(
) {
cell_data.select_options.iter().for_each(|option| {
// Remove the row in which group contains the row
if option.id == group.id {
if group.contains_row(&row_rev.id) {
group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
if option.id == group.id && group.contains_row(&row_rev.id) {
group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
// Find the inserted group

View File

@ -7,7 +7,9 @@ use crate::services::group::{
};
use bytes::Bytes;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision, RowChangeset};
use flowy_grid_data_model::revision::{
gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision,
};
use lib_infra::future::AFFuture;
use std::future::Future;
use std::sync::Arc;
@ -18,7 +20,6 @@ pub trait GroupConfigurationDelegate: Send + Sync + 'static {
}
pub(crate) struct GroupService {
pub groups: Vec<Group>,
delegate: Box<dyn GroupConfigurationDelegate>,
group_controller: Option<Arc<RwLock<dyn GroupController>>>,
}
@ -26,12 +27,19 @@ pub(crate) struct GroupService {
impl GroupService {
pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self {
Self {
groups: vec![],
delegate,
group_controller: None,
}
}
pub(crate) async fn groups(&self) -> Vec<Group> {
if let Some(group_action_handler) = self.group_controller.as_ref() {
group_action_handler.read().await.groups()
} else {
vec![]
}
}
pub(crate) async fn load_groups(
&mut self,
field_revs: &[Arc<FieldRevision>],
@ -44,10 +52,7 @@ impl GroupService {
.build_groups(&field_type, &field_rev, row_revs, configuration)
.await
{
Ok(groups) => {
self.groups = groups.clone();
Some(groups)
}
Ok(groups) => Some(groups),
Err(_) => None,
}
}
@ -183,7 +188,7 @@ impl GroupService {
if let Some(group_action_handler) = self.group_controller.as_ref() {
let mut write_guard = group_action_handler.write().await;
let _ = write_guard.group_rows(&row_revs, field_rev)?;
groups = write_guard.build_groups();
groups = write_guard.groups();
drop(write_guard);
}

View File

@ -56,7 +56,7 @@ pub struct GridRowTest {
impl GridRowTest {
pub async fn new() -> Self {
let editor_test = GridEditorTest::new().await;
let editor_test = GridEditorTest::new_table().await;
Self { inner: editor_test }
}

View File

@ -11,7 +11,7 @@ pub struct GridCellTest {
impl GridCellTest {
pub async fn new() -> Self {
let inner = GridEditorTest::new().await;
let inner = GridEditorTest::new_table().await;
Self { inner }
}

View File

@ -26,7 +26,7 @@ pub struct GridFieldTest {
impl GridFieldTest {
pub async fn new() -> Self {
let editor_test = GridEditorTest::new().await;
let editor_test = GridEditorTest::new_table().await;
Self { inner: editor_test }
}

View File

@ -36,7 +36,7 @@ pub struct GridFilterTest {
impl GridFilterTest {
pub async fn new() -> Self {
let editor_test = GridEditorTest::new().await;
let editor_test = GridEditorTest::new_table().await;
Self {
inner: editor_test
}

View File

@ -36,12 +36,25 @@ pub struct GridEditorTest {
}
impl GridEditorTest {
pub async fn new() -> Self {
pub async fn new_table() -> Self {
Self::new(GridLayout::Table).await
}
pub async fn new_board() -> Self {
Self::new(GridLayout::Board).await
}
pub async fn new(layout: GridLayout) -> Self {
let sdk = FlowySDKTest::default();
let _ = sdk.init_user().await;
let build_context = make_test_grid();
let view_data: Bytes = build_context.into();
let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await;
let test = match layout {
GridLayout::Table => ViewTest::new_grid_view(&sdk, view_data.to_vec()).await,
GridLayout::Board => ViewTest::new_board_view(&sdk, view_data.to_vec()).await,
};
let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
let field_revs = editor.get_field_revs(None).await.unwrap();
let block_meta_revs = editor.get_block_meta_revs().await.unwrap();

View File

@ -1 +1,2 @@
mod script;
mod test;

View File

@ -1,9 +1,23 @@
use crate::grid::grid_editor::GridEditorTest;
use flowy_grid::entities::MoveRowParams;
use flowy_grid::entities::{GroupPB, MoveRowParams, RowPB};
pub enum GroupScript {
MoveCard { from_row_id: String, to_row_id: String },
AssertGroup {
group_index: usize,
row_count: usize,
},
AssertGroupCount(usize),
AssertGroupRow {
group_index: usize,
row_index: usize,
row: RowPB,
},
MoveRow {
from_group_index: usize,
from_row_index: usize,
to_group_index: usize,
to_row_index: usize,
},
}
pub struct GridGroupTest {
@ -12,7 +26,7 @@ pub struct GridGroupTest {
impl GridGroupTest {
pub async fn new() -> Self {
let editor_test = GridEditorTest::new().await;
let editor_test = GridEditorTest::new_board().await;
Self { inner: editor_test }
}
@ -24,19 +38,48 @@ impl GridGroupTest {
pub async fn run_script(&mut self, script: GroupScript) {
match script {
GroupScript::MoveCard { from_row_id, to_row_id } => {
let params = MoveRowParams {
view_id: self.inner.grid_id.clone(),
from_row_id,
to_row_id,
};
let _ = self.editor.move_row(params).await.unwrap();
GroupScript::AssertGroup { group_index, row_count } => {
assert_eq!(row_count, self.group_at_index(group_index).await.rows.len());
}
GroupScript::AssertGroupCount(count) => {
let groups = self.editor.load_groups().await.unwrap();
assert_eq!(count, groups.len());
}
GroupScript::MoveRow {
from_group_index,
from_row_index,
to_group_index,
to_row_index,
} => {
let groups: Vec<GroupPB> = self.editor.load_groups().await.unwrap().items;
let from_row = groups.get(from_group_index).unwrap().rows.get(from_row_index).unwrap();
let to_row = groups.get(to_group_index).unwrap().rows.get(to_row_index).unwrap();
let params = MoveRowParams {
view_id: self.inner.grid_id.clone(),
from_row_id: from_row.id.clone(),
to_row_id: to_row.id.clone(),
};
self.editor.move_row(params).await.unwrap();
}
GroupScript::AssertGroupRow {
group_index,
row_index,
row,
} => {
//
let group = self.group_at_index(group_index).await;
let compare_row = group.rows.get(row_index).unwrap().clone();
assert_eq!(row.id, compare_row.id);
}
}
}
pub async fn group_at_index(&self, index: usize) -> GroupPB {
let groups = self.editor.load_groups().await.unwrap().items;
groups.get(index).unwrap().clone()
}
}
impl std::ops::Deref for GridGroupTest {

View File

@ -0,0 +1,51 @@
use crate::grid::group_test::script::GridGroupTest;
use crate::grid::group_test::script::GroupScript::*;
#[tokio::test]
async fn board_init_test() {
let mut test = GridGroupTest::new().await;
let scripts = vec![
AssertGroupCount(3),
AssertGroup {
group_index: 0,
row_count: 2,
},
AssertGroup {
group_index: 1,
row_count: 2,
},
AssertGroup {
group_index: 2,
row_count: 1,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn board_move_row_test() {
let mut test = GridGroupTest::new().await;
let group = test.group_at_index(0).await;
let scripts = vec![
MoveRow {
from_group_index: 0,
from_row_index: 0,
to_group_index: 1,
to_row_index: 1,
},
AssertGroup {
group_index: 0,
row_count: 1,
},
AssertGroup {
group_index: 1,
row_count: 3,
},
AssertGroupRow {
group_index: 1,
row_index: 1,
row: group.rows.get(0).unwrap().clone(),
},
];
test.run_scripts(scripts).await;
}

View File

@ -184,7 +184,7 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
&self,
user_id: &str,
view_id: &str,
sub_data_type: ViewLayoutTypePB,
_sub_data_type: ViewLayoutTypePB,
) -> FutureResult<Bytes, FlowyError> {
let user_id = user_id.to_string();
let view_id = view_id.to_string();

View File

@ -275,7 +275,7 @@ impl std::default::Default for GridBlockRevisionPad {
#[cfg(test)]
mod tests {
use crate::client_grid::GridBlockRevisionPad;
use flowy_grid_data_model::revision::{RowMetaChangeset, RowRevision};
use flowy_grid_data_model::revision::{RowChangeset, RowRevision};
use lib_ot::core::TextDelta;
use std::borrow::Cow;
@ -400,7 +400,7 @@ mod tests {
visibility: false,
};
let changeset = RowMetaChangeset {
let changeset = RowChangeset {
row_id: row.id.clone(),
height: Some(100),
visibility: Some(true),