chore: separate tests from grid_test file

This commit is contained in:
appflowy 2022-06-20 10:24:43 +08:00
parent c73eb2961a
commit 2573f9ba27
19 changed files with 446 additions and 446 deletions

View File

@ -28,7 +28,7 @@ class BoardPluginBuilder implements PluginBuilder {
class BoardPluginConfig implements PluginConfig {
@override
bool get creatable => true;
bool get creatable => false;
}
class BoardPlugin extends Plugin {

View File

@ -27,7 +27,7 @@ pub(crate) async fn get_grid_setting_handler(
let grid_id: GridId = data.into_inner();
let editor = manager.open_grid(grid_id).await?;
let grid_setting = editor.get_grid_setting().await?;
data_result(grid_setting)
data_result(grid_setting.into())
}
#[tracing::instrument(level = "trace", skip(data, manager), err)]

View File

@ -262,7 +262,7 @@ impl GridRevisionEditor {
let block_id = self.block_id().await?;
// insert empty row below the row whose id is upper_row_id
let row_rev_ctx = CreateRowMetaBuilder::new(&field_revs).build();
let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
let row_order = RowOrder::from(&row_rev);
@ -275,7 +275,7 @@ impl GridRevisionEditor {
Ok(row_order)
}
pub async fn insert_rows(&self, contexts: Vec<CreateRowMetaPayload>) -> FlowyResult<Vec<RowOrder>> {
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowOrder>> {
let block_id = self.block_id().await?;
let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
let mut row_orders = vec![];
@ -438,10 +438,10 @@ impl GridRevisionEditor {
})
}
pub async fn get_grid_setting(&self) -> FlowyResult<GridSetting> {
pub async fn get_grid_setting(&self) -> FlowyResult<GridSettingRevision> {
let pad_read_guard = self.grid_pad.read().await;
let grid_setting_rev = pad_read_guard.get_grid_setting_rev();
Ok(grid_setting_rev.into())
Ok(grid_setting_rev)
}
pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {

View File

@ -5,19 +5,19 @@ use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, R
use indexmap::IndexMap;
use std::collections::HashMap;
pub struct CreateRowMetaBuilder<'a> {
pub struct CreateRowRevisionBuilder<'a> {
field_rev_map: HashMap<&'a String, &'a FieldRevision>,
payload: CreateRowMetaPayload,
payload: CreateRowRevisionPayload,
}
impl<'a> CreateRowMetaBuilder<'a> {
impl<'a> CreateRowRevisionBuilder<'a> {
pub fn new(fields: &'a [FieldRevision]) -> Self {
let field_rev_map = fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &FieldRevision>>();
let payload = CreateRowMetaPayload {
let payload = CreateRowRevisionPayload {
row_id: gen_row_id(),
cell_by_field_id: Default::default(),
height: DEFAULT_ROW_HEIGHT,
@ -70,12 +70,12 @@ impl<'a> CreateRowMetaBuilder<'a> {
self
}
pub fn build(self) -> CreateRowMetaPayload {
pub fn build(self) -> CreateRowRevisionPayload {
self.payload
}
}
pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowMetaPayload) -> RowRevision {
pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowRevisionPayload) -> RowRevision {
RowRevision {
id: payload.row_id,
block_id: block_id.to_owned(),
@ -85,7 +85,7 @@ pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowMetaPayload)
}
}
pub struct CreateRowMetaPayload {
pub struct CreateRowRevisionPayload {
pub row_id: String,
pub cell_by_field_id: IndexMap<String, CellRevision>,
pub height: i32,

View File

@ -0,0 +1,40 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid_data_model::revision::{GridBlockRevision, GridBlockRevisionChangeset};
#[tokio::test]
async fn grid_create_block() {
let grid_block = GridBlockRevision::new();
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
AssertBlockCount(2),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_block() {
let grid_block = GridBlockRevision::new();
let mut cloned_grid_block = grid_block.clone();
let changeset = GridBlockRevisionChangeset {
block_id: grid_block.block_id.clone(),
start_row_index: Some(2),
row_count: Some(10),
};
cloned_grid_block.start_row_index = 2;
cloned_grid_block.row_count = 10;
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
UpdateBlock { changeset },
AssertBlockCount(2),
AssertBlockEqual {
block_index: 1,
block: cloned_grid_block,
},
];
GridEditorTest::new().await.run_scripts(scripts).await;
}

View File

@ -0,0 +1,48 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid::services::field::{MultiSelectTypeOption, SelectOptionCellContentChangeset, SingleSelectTypeOption};
use flowy_grid_data_model::entities::{CellChangeset, FieldType};
#[tokio::test]
async fn grid_cell_update() {
let mut test = GridEditorTest::new().await;
let field_revs = &test.field_revs;
let row_revs = &test.row_revs;
let grid_blocks = &test.grid_block_revs;
// For the moment, We only have one block to store rows
let block_id = &grid_blocks.first().unwrap().block_id;
let mut scripts = vec![];
for (_, row_rev) in row_revs.iter().enumerate() {
for field_rev in field_revs {
let data = match field_rev.field_type {
FieldType::RichText => "".to_string(),
FieldType::Number => "123".to_string(),
FieldType::DateTime => make_date_cell_string("123"),
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
}
FieldType::Checkbox => "1".to_string(),
FieldType::URL => "1".to_string(),
};
scripts.push(UpdateCell {
changeset: CellChangeset {
grid_id: block_id.to_string(),
row_id: row_rev.id.clone(),
field_id: field_rev.id.clone(),
cell_content_changeset: Some(data),
},
is_err: false,
});
}
}
test.run_scripts(scripts).await;
}

View File

@ -0,0 +1,113 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid::services::field::{SelectOption, SingleSelectTypeOption};
use flowy_grid_data_model::entities::FieldChangesetParams;
use flowy_grid_data_model::revision::TypeOptionDataEntry;
#[tokio::test]
async fn grid_create_field() {
let mut test = GridEditorTest::new().await;
let (params, field_rev) = create_text_field(&test.grid_id);
let scripts = vec![
CreateField { params },
AssertFieldEqual {
field_index: test.field_count,
field_rev,
},
];
test.run_scripts(scripts).await;
let (params, field_rev) = create_single_select_field(&test.grid_id);
let scripts = vec![
CreateField { params },
AssertFieldEqual {
field_index: test.field_count,
field_rev,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_duplicate_field() {
let mut test = GridEditorTest::new().await;
let (params, _) = create_text_field(&test.grid_id);
let field_count = test.field_count;
let expected_field_count = field_count + 1;
let scripts = vec![
CreateField { params: params.clone() },
CreateField { params },
AssertFieldCount(expected_field_count),
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field_with_empty_change() {
let mut test = GridEditorTest::new().await;
let (params, field_rev) = create_single_select_field(&test.grid_id);
let changeset = FieldChangesetParams {
field_id: field_rev.id.clone(),
grid_id: test.grid_id.clone(),
..Default::default()
};
let scripts = vec![
CreateField { params },
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count,
field_rev,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field() {
let mut test = GridEditorTest::new().await;
let (params, single_select_field) = create_single_select_field(&test.grid_id);
let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field);
single_select_type_option.options.push(SelectOption::new("Unknown"));
let changeset = FieldChangesetParams {
field_id: single_select_field.id.clone(),
grid_id: test.grid_id.clone(),
frozen: Some(true),
width: Some(1000),
type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()),
..Default::default()
};
// The expected_field must be equal to the field that applied the changeset
let mut expected_field_rev = single_select_field.clone();
expected_field_rev.frozen = true;
expected_field_rev.width = 1000;
expected_field_rev.insert_type_option_entry(&single_select_type_option);
let scripts = vec![
CreateField { params },
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count,
field_rev: expected_field_rev,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_delete_field() {
let mut test = GridEditorTest::new().await;
let original_field_count = test.field_count;
let (params, text_field_rev) = create_text_field(&test.grid_id);
let scripts = vec![
CreateField { params },
DeleteField {
field_rev: text_field_rev,
},
AssertFieldCount(original_field_count),
];
test.run_scripts(scripts).await;
}

View File

@ -1,381 +0,0 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use chrono::NaiveDateTime;
use flowy_grid::services::field::{
DateCellContentChangeset, DateCellData, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset,
SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
};
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
use flowy_grid_data_model::entities::{CellChangeset, FieldChangesetParams, FieldType};
use flowy_grid_data_model::revision::{
GridBlockRevision, GridBlockRevisionChangeset, RowMetaChangeset, TypeOptionDataEntry,
};
#[tokio::test]
async fn grid_create_field() {
let mut test = GridEditorTest::new().await;
let (text_field_params, text_field_rev) = create_text_field(&test.grid_id);
let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id);
let scripts = vec![
CreateField {
params: text_field_params,
},
AssertFieldEqual {
field_index: test.field_count,
field_rev: text_field_rev,
},
];
test.run_scripts(scripts).await;
let scripts = vec![
CreateField {
params: single_select_params,
},
AssertFieldEqual {
field_index: test.field_count,
field_rev: single_select_field,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_duplicate_field() {
let mut test = GridEditorTest::new().await;
let (params, _) = create_text_field(&test.grid_id);
let field_count = test.field_count;
let expected_field_count = field_count + 1;
let scripts = vec![
CreateField { params: params.clone() },
CreateField { params },
AssertFieldCount(expected_field_count),
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field_with_empty_change() {
let mut test = GridEditorTest::new().await;
let (params, field_rev) = create_single_select_field(&test.grid_id);
let changeset = FieldChangesetParams {
field_id: field_rev.id.clone(),
grid_id: test.grid_id.clone(),
..Default::default()
};
let scripts = vec![
CreateField { params },
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count,
field_rev,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field() {
let mut test = GridEditorTest::new().await;
let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id);
let mut cloned_field = single_select_field.clone();
let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field);
single_select_type_option.options.push(SelectOption::new("Unknown"));
let changeset = FieldChangesetParams {
field_id: single_select_field.id.clone(),
grid_id: test.grid_id.clone(),
frozen: Some(true),
width: Some(1000),
type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()),
..Default::default()
};
cloned_field.frozen = true;
cloned_field.width = 1000;
cloned_field.insert_type_option_entry(&single_select_type_option);
let scripts = vec![
CreateField {
params: single_select_params,
},
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count,
field_rev: cloned_field,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_delete_field() {
let mut test = GridEditorTest::new().await;
let expected_field_count = test.field_count;
let (text_params, text_field) = create_text_field(&test.grid_id);
let scripts = vec![
CreateField { params: text_params },
DeleteField { field_rev: text_field },
AssertFieldCount(expected_field_count),
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_block() {
let grid_block = GridBlockRevision::new();
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
AssertBlockCount(2),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_block() {
let grid_block = GridBlockRevision::new();
let mut cloned_grid_block = grid_block.clone();
let changeset = GridBlockRevisionChangeset {
block_id: grid_block.block_id.clone(),
start_row_index: Some(2),
row_count: Some(10),
};
cloned_grid_block.start_row_index = 2;
cloned_grid_block.row_count = 10;
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
UpdateBlock { changeset },
AssertBlockCount(2),
AssertBlockEqual {
block_index: 1,
block: cloned_grid_block,
},
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_row() {
let scripts = vec![AssertRowCount(3), CreateEmptyRow, CreateEmptyRow, AssertRowCount(5)];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_row2() {
let mut test = GridEditorTest::new().await;
let create_row_context = CreateRowMetaBuilder::new(&test.field_revs).build();
let scripts = vec![
AssertRowCount(3),
CreateRow {
context: create_row_context,
},
AssertRowCount(4),
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_row() {
let mut test = GridEditorTest::new().await;
let context = CreateRowMetaBuilder::new(&test.field_revs).build();
let changeset = RowMetaChangeset {
row_id: context.row_id.clone(),
height: None,
visibility: None,
cell_by_field_id: Default::default(),
};
let scripts = vec![
AssertRowCount(3),
CreateRow { context },
UpdateRow {
changeset: changeset.clone(),
},
AssertRow { changeset },
AssertRowCount(4),
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_delete_row() {
let mut test = GridEditorTest::new().await;
let context_1 = CreateRowMetaBuilder::new(&test.field_revs).build();
let context_2 = CreateRowMetaBuilder::new(&test.field_revs).build();
let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
let scripts = vec![
AssertRowCount(3),
CreateRow { context: context_1 },
CreateRow { context: context_2 },
AssertBlockCount(1),
AssertBlock {
block_index: 0,
row_count: 5,
start_row_index: 0,
},
DeleteRow { row_ids },
AssertBlock {
block_index: 0,
row_count: 3,
start_row_index: 0,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_row_add_cells_test() {
let mut test = GridEditorTest::new().await;
let mut builder = CreateRowMetaBuilder::new(&test.field_revs);
for field in &test.field_revs {
match field.field_type {
FieldType::RichText => {
builder.add_cell(&field.id, "hello world".to_owned()).unwrap();
}
FieldType::Number => {
builder.add_cell(&field.id, "18,443".to_owned()).unwrap();
}
FieldType::DateTime => {
builder
.add_cell(&field.id, make_date_cell_string("1647251762"))
.unwrap();
}
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field);
let option = type_option.options.first().unwrap();
builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field);
let ops_ids = type_option
.options
.iter()
.map(|option| option.id.clone())
.collect::<Vec<_>>()
.join(SELECTION_IDS_SEPARATOR);
builder.add_select_option_cell(&field.id, ops_ids).unwrap();
}
FieldType::Checkbox => {
builder.add_cell(&field.id, "false".to_string()).unwrap();
}
FieldType::URL => {
builder.add_cell(&field.id, "1".to_string()).unwrap();
}
}
}
let context = builder.build();
let scripts = vec![CreateRow { context }, AssertGridMetaPad];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_row_add_date_cell_test() {
let mut test = GridEditorTest::new().await;
let mut builder = CreateRowMetaBuilder::new(&test.field_revs);
let mut date_field = None;
let timestamp = 1647390674;
for field in &test.field_revs {
if field.field_type == FieldType::DateTime {
date_field = Some(field.clone());
NaiveDateTime::from_timestamp(123, 0);
// The data should not be empty
assert!(builder.add_cell(&field.id, "".to_string()).is_err());
assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok());
assert!(builder
.add_cell(&field.id, make_date_cell_string(&timestamp.to_string()))
.is_ok());
}
}
let context = builder.build();
let date_field = date_field.unwrap();
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
assert_eq!(
decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type)
.parse::<DateCellData>()
.unwrap()
.date,
"2022/03/16",
);
let scripts = vec![CreateRow { context }];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_cell_update() {
let mut test = GridEditorTest::new().await;
let field_revs = &test.field_revs;
let row_revs = &test.row_revs;
let grid_blocks = &test.grid_block_revs;
assert_eq!(row_revs.len(), 3);
assert_eq!(grid_blocks.len(), 1);
let block_id = &grid_blocks.first().unwrap().block_id;
let mut scripts = vec![];
for (index, row_rev) in row_revs.iter().enumerate() {
for field_rev in field_revs {
if index == 0 {
let data = match field_rev.field_type {
FieldType::RichText => "".to_string(),
FieldType::Number => "123".to_string(),
FieldType::DateTime => make_date_cell_string("123"),
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
}
FieldType::Checkbox => "1".to_string(),
FieldType::URL => "1".to_string(),
};
scripts.push(UpdateCell {
changeset: CellChangeset {
grid_id: block_id.to_string(),
row_id: row_rev.id.clone(),
field_id: field_rev.id.clone(),
cell_content_changeset: Some(data),
},
is_err: false,
});
}
if index == 1 {
let (data, is_err) = match field_rev.field_type {
FieldType::RichText => ("1".to_string().repeat(10001), true),
FieldType::Number => ("abc".to_string(), true),
FieldType::DateTime => ("abc".to_string(), true),
FieldType::SingleSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false),
FieldType::MultiSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false),
FieldType::Checkbox => ("2".to_string(), false),
FieldType::URL => ("2".to_string(), false),
};
scripts.push(UpdateCell {
changeset: CellChangeset {
grid_id: block_id.to_string(),
row_id: row_rev.id.clone(),
field_id: field_rev.id.clone(),
cell_content_changeset: Some(data),
},
is_err,
});
}
}
}
test.run_scripts(scripts).await;
}
fn make_date_cell_string(s: &str) -> String {
serde_json::to_string(&DateCellContentChangeset {
date: Some(s.to_string()),
time: None,
})
.unwrap()
}

View File

@ -1,2 +1,6 @@
mod grid_test;
mod block_test;
mod cell_test;
mod field_test;
mod row_test;
mod script;
mod setting_test;

View File

@ -0,0 +1,147 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use chrono::NaiveDateTime;
use flowy_grid::services::field::{
DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
};
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowRevisionBuilder};
use flowy_grid_data_model::entities::FieldType;
use flowy_grid_data_model::revision::RowMetaChangeset;
#[tokio::test]
async fn grid_create_row_count_test() {
let test = GridEditorTest::new().await;
let create_row_context = CreateRowRevisionBuilder::new(&test.field_revs).build();
let scripts = vec![
AssertRowCount(3),
CreateEmptyRow,
CreateEmptyRow,
CreateRow {
context: create_row_context,
},
AssertRowCount(6),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_row() {
let mut test = GridEditorTest::new().await;
let context = CreateRowRevisionBuilder::new(&test.field_revs).build();
let changeset = RowMetaChangeset {
row_id: context.row_id.clone(),
height: None,
visibility: None,
cell_by_field_id: Default::default(),
};
let scripts = vec![AssertRowCount(3), CreateRow { context }, UpdateRow { changeset }];
test.run_scripts(scripts).await;
let expected_row = (&*test.row_revs.last().cloned().unwrap()).clone();
let scripts = vec![AssertRow { expected_row }, AssertRowCount(4)];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_delete_row() {
let mut test = GridEditorTest::new().await;
let context_1 = CreateRowRevisionBuilder::new(&test.field_revs).build();
let context_2 = CreateRowRevisionBuilder::new(&test.field_revs).build();
let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
let scripts = vec![
AssertRowCount(3),
CreateRow { context: context_1 },
CreateRow { context: context_2 },
AssertBlockCount(1),
AssertBlock {
block_index: 0,
row_count: 5,
start_row_index: 0,
},
DeleteRows { row_ids },
AssertBlock {
block_index: 0,
row_count: 3,
start_row_index: 0,
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_row_add_cells_test() {
let mut test = GridEditorTest::new().await;
let mut builder = CreateRowRevisionBuilder::new(&test.field_revs);
for field in &test.field_revs {
match field.field_type {
FieldType::RichText => {
builder.add_cell(&field.id, "hello world".to_owned()).unwrap();
}
FieldType::Number => {
builder.add_cell(&field.id, "18,443".to_owned()).unwrap();
}
FieldType::DateTime => {
builder
.add_cell(&field.id, make_date_cell_string("1647251762"))
.unwrap();
}
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field);
let option = type_option.options.first().unwrap();
builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field);
let ops_ids = type_option
.options
.iter()
.map(|option| option.id.clone())
.collect::<Vec<_>>()
.join(SELECTION_IDS_SEPARATOR);
builder.add_select_option_cell(&field.id, ops_ids).unwrap();
}
FieldType::Checkbox => {
builder.add_cell(&field.id, "false".to_string()).unwrap();
}
FieldType::URL => {
builder.add_cell(&field.id, "1".to_string()).unwrap();
}
}
}
let context = builder.build();
let scripts = vec![CreateRow { context }, AssertGridRevisionPad];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_row_add_date_cell_test() {
let mut test = GridEditorTest::new().await;
let mut builder = CreateRowRevisionBuilder::new(&test.field_revs);
let mut date_field = None;
let timestamp = 1647390674;
for field in &test.field_revs {
if field.field_type == FieldType::DateTime {
date_field = Some(field.clone());
NaiveDateTime::from_timestamp(123, 0);
// The data should not be empty
assert!(builder.add_cell(&field.id, "".to_string()).is_err());
assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok());
assert!(builder
.add_cell(&field.id, make_date_cell_string(&timestamp.to_string()))
.is_ok());
}
}
let context = builder.build();
let date_field = date_field.unwrap();
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
assert_eq!(
decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type)
.parse::<DateCellData>()
.unwrap()
.date,
"2022/03/16",
);
let scripts = vec![CreateRow { context }];
test.run_scripts(scripts).await;
}

View File

@ -1,14 +1,9 @@
use bytes::Bytes;
use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor};
use flowy_grid::services::row::CreateRowMetaPayload;
use flowy_grid_data_model::entities::{
CellChangeset, Field, FieldChangesetParams, FieldOrder, FieldType, InsertFieldParams, RowOrder,
};
use flowy_grid_data_model::revision::{
BuildGridContext, FieldRevision, GridBlockRevision, GridBlockRevisionChangeset, RowMetaChangeset, RowRevision,
TypeOptionDataEntry,
};
use flowy_grid::services::row::CreateRowRevisionPayload;
use flowy_grid_data_model::entities::*;
use flowy_grid_data_model::revision::*;
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_sync::client_grid::GridBuilder;
use flowy_test::helper::ViewTest;
@ -52,15 +47,15 @@ pub enum EditorScript {
},
CreateEmptyRow,
CreateRow {
context: CreateRowMetaPayload,
context: CreateRowRevisionPayload,
},
UpdateRow {
changeset: RowMetaChangeset,
},
AssertRow {
changeset: RowMetaChangeset,
expected_row: RowRevision,
},
DeleteRow {
DeleteRows {
row_ids: Vec<String>,
},
UpdateCell {
@ -68,8 +63,13 @@ pub enum EditorScript {
is_err: bool,
},
AssertRowCount(usize),
// AssertRowEqual{ row_index: usize, row: RowMeta},
AssertGridMetaPad,
UpdateGridSetting {
params: GridSettingChangesetParams,
},
AssertGridSetting {
expected_setting: GridSettingRevision,
},
AssertGridRevisionPad,
}
pub struct GridEditorTest {
@ -88,13 +88,19 @@ impl GridEditorTest {
pub async fn new() -> Self {
let sdk = FlowySDKTest::default();
let _ = sdk.init_user().await;
let build_context = make_template_1_grid();
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 editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
let field_revs = editor.get_field_revs::<FieldOrder>(None).await.unwrap();
let grid_blocks = editor.get_block_metas().await.unwrap();
let row_revs = get_row_revs(&editor).await;
let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs;
assert_eq!(row_revs.len(), 3);
assert_eq!(grid_blocks.len(), 1);
// It seems like you should add the field in the make_test_grid() function.
// Because we assert the initialize count of the fields is equal to FieldType::COUNT.
assert_eq!(field_revs.len(), FieldType::COUNT);
let grid_id = test.view.id;
Self {
@ -192,7 +198,7 @@ impl GridEditorTest {
self.grid_block_revs = self.editor.get_block_metas().await.unwrap();
}
EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(),
EditorScript::DeleteRow { row_ids } => {
EditorScript::DeleteRows { row_ids } => {
let row_orders = row_ids
.into_iter()
.map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
@ -202,16 +208,21 @@ impl GridEditorTest {
self.row_revs = self.get_row_revs().await;
self.grid_block_revs = self.editor.get_block_metas().await.unwrap();
}
EditorScript::AssertRow { changeset } => {
let row = self.row_revs.iter().find(|row| row.id == changeset.row_id).unwrap();
if let Some(visibility) = changeset.visibility {
assert_eq!(row.visibility, visibility);
}
if let Some(height) = changeset.height {
assert_eq!(row.height, height);
}
EditorScript::AssertRow { expected_row } => {
let row = &*self
.row_revs
.iter()
.find(|row| row.id == expected_row.id)
.cloned()
.unwrap();
assert_eq!(&expected_row, row);
// if let Some(visibility) = changeset.visibility {
// assert_eq!(row.visibility, visibility);
// }
//
// if let Some(height) = changeset.height {
// assert_eq!(row.height, height);
// }
}
EditorScript::UpdateCell { changeset, is_err } => {
let result = self.editor.update_cell(changeset).await;
@ -222,10 +233,17 @@ impl GridEditorTest {
self.row_revs = self.get_row_revs().await;
}
}
EditorScript::AssertRowCount(count) => {
assert_eq!(self.row_revs.len(), count);
EditorScript::AssertRowCount(expected_row_count) => {
assert_eq!(expected_row_count, self.row_revs.len());
}
EditorScript::AssertGridMetaPad => {
EditorScript::UpdateGridSetting { params } => {
let _ = self.editor.update_grid_setting(params).await.unwrap();
}
EditorScript::AssertGridSetting { expected_setting } => {
let setting = self.editor.get_grid_setting().await.unwrap();
assert_eq!(expected_setting, setting);
}
EditorScript::AssertGridRevisionPad => {
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap();
let grid_pad = grid_rev_manager.load::<GridPadBuilder>(None).await.unwrap();
@ -235,14 +253,16 @@ impl GridEditorTest {
}
async fn get_row_revs(&self) -> Vec<Arc<RowRevision>> {
get_row_revs(&self.editor).await
self.editor
.grid_block_snapshots(None)
.await
.unwrap()
.pop()
.unwrap()
.row_revs
}
}
async fn get_row_revs(editor: &Arc<GridRevisionEditor>) -> Vec<Arc<RowRevision>> {
editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs
}
pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
.name("Name")
@ -310,7 +330,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
(params, cloned_field_rev)
}
fn make_template_1_grid() -> BuildGridContext {
fn make_test_grid() -> BuildGridContext {
let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
.name("Name")
.visibility(true)
@ -365,3 +385,11 @@ fn make_template_1_grid() -> BuildGridContext {
.add_empty_row()
.build()
}
pub fn make_date_cell_string(s: &str) -> String {
serde_json::to_string(&DateCellContentChangeset {
date: Some(s.to_string()),
time: None,
})
.unwrap()
}

View File

@ -0,0 +1 @@

View File

@ -31,6 +31,8 @@ pub struct GridRevision {
pub grid_id: String,
pub fields: Vec<FieldRevision>,
pub blocks: Vec<GridBlockRevision>,
#[serde(skip)]
pub setting: GridSettingRevision,
}

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use serde_repr::*;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct GridSettingRevision {
#[serde(with = "indexmap::serde_seq")]
pub filter: IndexMap<GridLayoutRevision, GridFilterRevision>,
@ -54,18 +54,18 @@ impl std::convert::From<GridLayoutType> for GridLayoutRevision {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridFilterRevision {
pub field_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridGroupRevision {
pub group_field_id: Option<String>,
pub sub_group_field_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridSortRevision {
pub field_id: Option<String>,
}

View File

@ -1,5 +1,5 @@
mod grid_info_rev;
mod grid_rev;
mod grid_setting_rev;
pub use grid_info_rev::*;
pub use grid_rev::*;
pub use grid_setting_rev::*;

View File

@ -364,7 +364,7 @@ impl GridRevisionPad {
if let Some(sort) = changeset.sort {
grid_rev.setting.sort.insert(
layout_rev.clone(),
layout_rev,
GridSortRevision {
field_id: sort.field_id,
},

View File

@ -15,7 +15,7 @@ use walkdir::WalkDir;
pub fn parse_protobuf_context_from(crate_paths: Vec<String>) -> Vec<ProtobufCrateContext> {
let crate_infos = parse_crate_info_from_path(crate_paths);
let contexts = crate_infos
crate_infos
.into_iter()
.map(|crate_info| {
let proto_output_path = crate_info.proto_output_path();
@ -28,9 +28,7 @@ pub fn parse_protobuf_context_from(crate_paths: Vec<String>) -> Vec<ProtobufCrat
ProtobufCrateContext::from_crate_info(crate_info, files)
})
.collect::<Vec<ProtobufCrateContext>>();
contexts
.collect::<Vec<ProtobufCrateContext>>()
}
fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Vec<ProtoFile> {
@ -71,7 +69,7 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
.iter()
.filter(|field| field.attrs.pb_index().is_some())
.for_each(|field| {
ref_types.push(field.ty_as_str().to_string());
ref_types.push(field.ty_as_str());
struct_template.set_field(field);
});
@ -95,8 +93,8 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
if !enums.is_empty() || !structs.is_empty() {
let structs: Vec<String> = structs.iter().map(|s| s.name.clone()).collect();
let enums: Vec<String> = enums.iter().map(|e| e.name.clone()).collect();
ref_types.retain(|s| !structs.contains(&s));
ref_types.retain(|s| !enums.contains(&s));
ref_types.retain(|s| !structs.contains(s));
ref_types.retain(|s| !enums.contains(s));
let info = ProtoFile {
file_path: path.clone(),

View File

@ -76,7 +76,7 @@ fn write_proto_files(crate_contexts: &[ProtobufCrateContext]) {
let mut file_content = file.syntax.clone();
// import
file_content.push_str(&gen_import_content(&file, &file_path_content_map));
file_content.push_str(&gen_import_content(file, &file_path_content_map));
// content
file_content.push_str(&file.content);

View File

@ -69,7 +69,7 @@ impl ProtobufCrate {
ProtobufCrate {
crate_path: config.crate_path,
crate_folder: config.crate_folder,
flowy_config: config.flowy_config.clone(),
flowy_config: config.flowy_config,
}
}