chore: revamp test helper

This commit is contained in:
nathan 2024-12-25 16:50:38 +08:00
parent f03d8d35ef
commit 56bbe29058
17 changed files with 448 additions and 509 deletions

View File

@ -9,7 +9,7 @@ use flowy_database2::entities::{
use tokio::time::sleep;
#[tokio::test]
async fn calculation_integration_test1() {
async fn get_calculate_after_edit_cell_test() {
let test = EventIntegrationTest::new().await;
test.sign_up_as_anon().await;
@ -17,17 +17,8 @@ async fn calculation_integration_test1() {
let payload = gen_csv_import_data("project.csv", &workspace_id);
let view = test.import_data(payload).await.pop().unwrap();
let database = test.open_database(&view.id).await;
let database_view_id = &view.id;
average_calculation(test, database, &view.id).await;
}
// Tests for the CalculationType::Average
// Is done on the Delay column in the project.csv
async fn average_calculation(
test: EventIntegrationTest,
database: DatabasePB,
database_view_id: &str,
) {
// Delay column is the 11th column (index 10) in the project.csv
let delay_field = database.fields.get(10).unwrap();
@ -54,6 +45,7 @@ async fn average_calculation(
);
// Update a cell in the delay column at fourth row (3rd index)
// edit the Delay column in the project.csv
let cell_changeset = CellChangesetPB {
view_id: database_view_id.to_string(),
row_id: database.rows.get(3).unwrap().id.clone(),

View File

@ -329,7 +329,7 @@ impl DatabaseEditor {
.database_views
.get_or_init_view_editor(&update.view_id)
.await?;
view_editor.v_update_calculations(update).await?;
view_editor.v_edit_calculations(update).await?;
Ok(())
}

View File

@ -693,41 +693,7 @@ impl DatabaseViewEditor {
Ok(())
}
pub async fn v_update_calculate(&self, field_id: &str) -> Option<()> {
let field = self.delegate.get_field(field_id).await?;
let cal = self
.delegate
.get_calculation(&self.view_id, &field.id)
.await?;
let cells = self
.delegate
.get_cells_for_field(&self.view_id, field_id)
.await
.into_iter()
.flat_map(|row_cell| row_cell.cell.map(Arc::new))
.collect::<Vec<_>>();
let changes = self
.calculations_controller
.handle_cells_changed(&field, &cal, cells)
.await;
if !changes.is_empty() {
let notification = CalculationChangesetNotificationPB::from_update(&self.view_id, changes);
if let Err(_err) = self
.notifier
.send(DatabaseViewChanged::CalculationValueNotification(
notification,
))
{
error!("Failed to send CalculationValueNotification");
}
}
None
}
#[instrument(level = "trace", skip_all)]
pub async fn v_calculate_rows(&self, fields: Vec<Field>, rows: Vec<Arc<Row>>) -> FlowyResult<()> {
let mut updates = vec![];
// Filter fields to only those with calculations
@ -768,6 +734,7 @@ impl DatabaseViewEditor {
}
// Send notification if updates were made
trace!("Calculations updates: {:?}", updates);
if !updates.is_empty() {
let notification = CalculationChangesetNotificationPB::from_update(&self.view_id, updates);
if let Err(_err) = self
@ -798,10 +765,42 @@ impl DatabaseViewEditor {
self.delegate.get_all_calculations(&self.view_id).await
}
pub async fn v_update_calculations(
&self,
params: UpdateCalculationChangesetPB,
) -> FlowyResult<()> {
pub async fn v_update_calculate(&self, field_id: &str) -> Option<()> {
let field = self.delegate.get_field(field_id).await?;
let cal = self
.delegate
.get_calculation(&self.view_id, &field.id)
.await?;
let cells = self
.delegate
.get_cells_for_field(&self.view_id, field_id)
.await
.into_iter()
.flat_map(|row_cell| row_cell.cell.map(Arc::new))
.collect::<Vec<_>>();
let changes = self
.calculations_controller
.handle_cells_changed(&field, &cal, cells)
.await;
if !changes.is_empty() {
let notification = CalculationChangesetNotificationPB::from_update(&self.view_id, changes);
if let Err(_err) = self
.notifier
.send(DatabaseViewChanged::CalculationValueNotification(
notification,
))
{
error!("Failed to send CalculationValueNotification");
}
}
None
}
pub async fn v_edit_calculations(&self, params: UpdateCalculationChangesetPB) -> FlowyResult<()> {
let calculation_id = params
.calculation_id
.unwrap_or_else(gen_database_calculation_id);

View File

@ -1,13 +1,35 @@
use std::sync::Arc;
use crate::database::calculations_test::script::DatabaseCalculationTest;
use crate::database::database_editor::DatabaseEditorTest;
use collab_database::fields::Field;
use flowy_database2::entities::{CalculationType, FieldType, UpdateCalculationChangesetPB};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn calculations_test() {
let mut test = DatabaseCalculationTest::new().await;
async fn calculate_with_filter_test() {
let mut test = DatabaseEditorTest::new_grid().await;
// let sub = test.sdk.notification_sender.subscribe().await.unwrap();
// Create Number "Equal" filter
// test
// .create_data_filter(
// None,
// FieldType::Number,
// BoxAny::new(NumberFilterPB {
// condition: NumberFilterConditionPB::Equal,
// content: "1".to_string(),
// }),
// Some(FilterRowChanged {
// showing_num_of_rows: 0,
// hiding_num_of_rows: row_count - expected,
// }),
// )
// .await;
}
#[tokio::test]
async fn insert_delete_calculate_test() {
let mut test = DatabaseEditorTest::new_grid().await;
let expected_sum = 25.00;
let expected_min = 1.00;
@ -89,7 +111,7 @@ async fn calculations_test() {
#[tokio::test]
async fn calculations_empty_test() {
let mut test = DatabaseCalculationTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let view_id = &test.view_id();
let text_fields = test
@ -128,7 +150,7 @@ async fn calculations_empty_test() {
#[tokio::test]
async fn calculations_non_empty_test() {
let mut test = DatabaseCalculationTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let view_id = &test.view_id();
let text_fields = test
@ -167,7 +189,7 @@ async fn calculations_non_empty_test() {
#[tokio::test]
async fn calculations_count_test() {
let mut test = DatabaseCalculationTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let view_id = &test.view_id();
let text_fields = test

View File

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

View File

@ -1,71 +0,0 @@
use collab_database::rows::RowId;
use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::UpdateCalculationChangesetPB;
use flowy_database2::services::database_view::DatabaseViewChanged;
use crate::database::database_editor::DatabaseEditorTest;
pub struct DatabaseCalculationTest {
inner: DatabaseEditorTest,
recv: Option<Receiver<DatabaseViewChanged>>,
}
impl DatabaseCalculationTest {
pub async fn new() -> Self {
let editor_test = DatabaseEditorTest::new_grid().await;
Self {
inner: editor_test,
recv: None,
}
}
pub fn view_id(&self) -> String {
self.view_id.clone()
}
pub async fn insert_calculation(&mut self, payload: UpdateCalculationChangesetPB) {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.editor.update_calculation(payload).await.unwrap();
}
pub async fn assert_calculation_float_value(&mut self, expected: f64) {
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
let calculation = calculations.items.first().unwrap();
assert_eq!(calculation.value, format!("{:.2}", expected));
}
pub async fn assert_calculation_value(&mut self, expected: &str) {
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
let calculation = calculations.items.first().unwrap();
assert_eq!(calculation.value, expected);
}
pub async fn duplicate_row(&self, row_id: &RowId) {
self
.editor
.duplicate_row(&self.view_id, row_id)
.await
.unwrap();
}
}
impl std::ops::Deref for DatabaseCalculationTest {
type Target = DatabaseEditorTest;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for DatabaseCalculationTest {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

View File

@ -1,6 +1,3 @@
use std::collections::HashMap;
use std::sync::Arc;
use collab_database::database::gen_database_view_id;
use collab_database::fields::checkbox_type_option::CheckboxTypeOption;
use collab_database::fields::checklist_type_option::ChecklistTypeOption;
@ -9,16 +6,24 @@ use collab_database::fields::select_type_option::{
};
use collab_database::fields::Field;
use collab_database::rows::{Row, RowId};
use lib_infra::box_any::BoxAny;
use strum::EnumCount;
use event_integration_test::folder_event::ViewTest;
use event_integration_test::EventIntegrationTest;
use flowy_database2::entities::{DatabasePB, FieldType, FilterPB, RowMetaPB};
use flowy_database2::entities::{
DatabasePB, DatabaseViewSettingPB, FieldType, FilterPB, FilterType, RowMetaPB,
TextFilterConditionPB, TextFilterPB, UpdateCalculationChangesetPB,
};
use lib_infra::box_any::BoxAny;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use strum::EnumCount;
use tokio::sync::broadcast::Receiver;
use flowy_database2::services::database::DatabaseEditor;
use flowy_database2::services::database_view::DatabaseViewChanged;
use flowy_database2::services::field::checklist_filter::ChecklistCellChangeset;
use flowy_database2::services::field::SelectOptionCellChangeset;
use flowy_database2::services::filter::{FilterChangeset, FilterInner};
use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
use flowy_error::FlowyResult;
@ -34,6 +39,7 @@ pub struct DatabaseEditorTest {
pub rows: Vec<Arc<Row>>,
pub field_count: usize,
pub row_by_row_id: HashMap<String, RowMetaPB>,
view_change_recv: Option<Receiver<DatabaseViewChanged>>,
}
impl DatabaseEditorTest {
@ -101,6 +107,7 @@ impl DatabaseEditorTest {
rows,
field_count: FieldType::COUNT,
row_by_row_id: HashMap::default(),
view_change_recv: None,
};
this.get_database_data(&view_id).await;
this
@ -297,4 +304,318 @@ impl DatabaseEditorTest {
.await
.ok()
}
pub async fn insert_calculation(&mut self, payload: UpdateCalculationChangesetPB) {
self.view_change_recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.editor.update_calculation(payload).await.unwrap();
}
pub async fn assert_calculation_float_value(&mut self, expected: f64) {
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
let calculation = calculations.items.first().unwrap();
assert_eq!(calculation.value, format!("{:.2}", expected));
}
pub async fn assert_calculation_value(&mut self, expected: &str) {
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
let calculation = calculations.items.first().unwrap();
assert_eq!(calculation.value, expected);
}
pub async fn duplicate_row(&self, row_id: &RowId) {
self
.editor
.duplicate_row(&self.view_id, row_id)
.await
.unwrap();
}
pub fn view_id(&self) -> String {
self.view_id.clone()
}
pub async fn get_all_filters(&self) -> Vec<FilterPB> {
self.editor.get_all_filters(&self.view_id).await.items
}
pub async fn get_filter(
&self,
filter_type: FilterType,
field_type: Option<FieldType>,
) -> Option<FilterPB> {
let filters = self.editor.get_all_filters(&self.view_id).await;
for filter in filters.items.iter() {
let result = Self::find_filter(filter, filter_type, field_type);
if result.is_some() {
return result;
}
}
None
}
fn find_filter(
filter: &FilterPB,
filter_type: FilterType,
field_type: Option<FieldType>,
) -> Option<FilterPB> {
match &filter.filter_type {
FilterType::And | FilterType::Or if filter.filter_type == filter_type => Some(filter.clone()),
FilterType::And | FilterType::Or => {
for child_filter in filter.children.iter() {
if let Some(result) = Self::find_filter(child_filter, filter_type, field_type) {
return Some(result);
}
}
None
},
FilterType::Data
if filter.filter_type == filter_type
&& field_type.map_or(false, |field_type| {
field_type == filter.data.clone().unwrap().field_type
}) =>
{
Some(filter.clone())
},
_ => None,
}
}
pub async fn update_text_cell_with_change(
&mut self,
row_id: RowId,
text: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
self.update_text_cell(row_id, &text).await.unwrap();
}
pub async fn update_checklist_cell(&mut self, row_id: RowId, selected_option_ids: Vec<String>) {
self
.set_checklist_cell(row_id, selected_option_ids)
.await
.unwrap();
}
pub async fn update_single_select_cell_with_change(
&mut self,
row_id: RowId,
option_id: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
self
.update_single_select_cell(row_id, &option_id)
.await
.unwrap();
}
pub async fn create_data_filter(
&mut self,
parent_filter_id: Option<String>,
field_type: FieldType,
data: BoxAny,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let field = self.get_first_field(field_type).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::Data {
field_id: field.id,
field_type,
condition_and_content: data,
},
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn update_text_filter(
&mut self,
filter: FilterPB,
condition: TextFilterConditionPB,
content: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let current_filter = filter.data.unwrap();
let params = FilterChangeset::UpdateData {
filter_id: filter.id,
data: FilterInner::Data {
field_id: current_filter.field_id,
field_type: current_filter.field_type,
condition_and_content: BoxAny::new(TextFilterPB { condition, content }),
},
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn create_and_filter(
&mut self,
parent_filter_id: Option<String>,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::And { children: vec![] },
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn create_or_filter(
&mut self,
parent_filter_id: Option<String>,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::Or { children: vec![] },
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn delete_filter(&mut self, filter_id: String, changed: Option<FilterRowChanged>) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Delete { filter_id };
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn assert_filter_count(&self, count: usize) {
let filters = self.editor.get_all_filters(&self.view_id).await.items;
assert_eq!(count, filters.len());
}
pub async fn assert_grid_setting(&self, expected_setting: DatabaseViewSettingPB) {
let setting = self
.editor
.get_database_view_setting(&self.view_id)
.await
.unwrap();
assert_eq!(expected_setting, setting);
}
pub async fn assert_filters(&self, expected: Vec<FilterPB>) {
let actual = self.get_all_filters().await;
for (actual_filter, expected_filter) in actual.iter().zip(expected.iter()) {
Self::assert_filter(actual_filter, expected_filter);
}
}
pub async fn assert_number_of_visible_rows(&self, expected: usize) {
let (tx, rx) = tokio::sync::oneshot::channel();
let _ = self
.editor
.open_database_view(&self.view_id, Some(tx))
.await
.unwrap();
rx.await.unwrap();
let rows = self.editor.get_all_rows(&self.view_id).await.unwrap();
assert_eq!(rows.len(), expected);
}
pub async fn wait(&self, millisecond: u64) {
tokio::time::sleep(Duration::from_millis(millisecond)).await;
}
async fn subscribe_view_changed(&mut self) {
self.view_change_recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id)
.await
.unwrap(),
);
}
async fn assert_future_changed(&mut self, change: Option<FilterRowChanged>) {
if change.is_none() {
return;
}
let change = change.unwrap();
let mut receiver = self.view_change_recv.take().unwrap();
tokio::spawn(async move {
match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await {
Ok(changed) => {
if let DatabaseViewChanged::FilterNotification(notification) = changed.unwrap() {
assert_eq!(
notification.visible_rows.len(),
change.showing_num_of_rows,
"visible rows not match"
);
assert_eq!(
notification.invisible_rows.len(),
change.hiding_num_of_rows,
"invisible rows not match"
);
}
},
Err(e) => {
panic!("Process filter task timeout: {:?}", e);
},
}
});
}
fn assert_filter(actual: &FilterPB, expected: &FilterPB) {
assert_eq!(actual.filter_type, expected.filter_type);
assert_eq!(actual.children.is_empty(), expected.children.is_empty());
assert_eq!(actual.data.is_some(), expected.data.is_some());
match actual.filter_type {
FilterType::Data => {
let actual_data = actual.data.clone().unwrap();
let expected_data = expected.data.clone().unwrap();
assert_eq!(actual_data.field_type, expected_data.field_type);
assert_eq!(actual_data.data, expected_data.data);
},
FilterType::And | FilterType::Or => {
for (actual_child, expected_child) in actual.children.iter().zip(expected.children.iter()) {
Self::assert_filter(actual_child, expected_child);
}
},
}
}
}
pub struct FilterRowChanged {
pub(crate) showing_num_of_rows: usize,
pub(crate) hiding_num_of_rows: usize,
}

View File

@ -1,4 +1,4 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use bytes::Bytes;
use flowy_database2::entities::{
CheckboxFilterConditionPB, CheckboxFilterPB, DateFilterConditionPB, DateFilterPB, FieldType,
@ -16,7 +16,7 @@ use std::convert::TryInto;
///
#[tokio::test]
async fn create_advanced_filter_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let create_checkbox_filter = || -> CheckboxFilterPB {
CheckboxFilterPB {
@ -189,7 +189,7 @@ async fn create_advanced_filter_test() {
///
#[tokio::test]
async fn create_advanced_filter_with_conversion_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let create_checkbox_filter = || -> CheckboxFilterPB {
CheckboxFilterPB {

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{CheckboxFilterConditionPB, CheckboxFilterPB, FieldType};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_checkbox_is_check_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let expected = 3;
let row_count = test.rows.len();
@ -29,7 +29,7 @@ async fn grid_filter_checkbox_is_check_test() {
#[tokio::test]
async fn grid_filter_checkbox_is_uncheck_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let expected = 4;
let row_count = test.rows.len();

View File

@ -1,11 +1,11 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use collab_database::template::check_list_parse::ChecklistCellData;
use flowy_database2::entities::{ChecklistFilterConditionPB, ChecklistFilterPB, FieldType};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_checklist_is_incomplete_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let expected = 5;
let row_count = test.rows.len();
let option_ids = get_checklist_cell_options(&test).await;
@ -36,7 +36,7 @@ async fn grid_filter_checklist_is_incomplete_test() {
#[tokio::test]
async fn grid_filter_checklist_is_complete_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let expected = 2;
let row_count = test.rows.len();
let option_ids = get_checklist_cell_options(&test).await;
@ -65,7 +65,7 @@ async fn grid_filter_checklist_is_complete_test() {
test.assert_number_of_visible_rows(expected).await;
}
async fn get_checklist_cell_options(test: &DatabaseFilterTest) -> Vec<String> {
async fn get_checklist_cell_options(test: &DatabaseEditorTest) -> Vec<String> {
let field = test.get_first_field(FieldType::Checklist).await;
let row_cell = test.editor.get_cell(&field.id, &test.rows[0].id).await;
row_cell

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{DateFilterConditionPB, DateFilterPB, FieldType};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_date_is_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 3;
@ -32,7 +32,7 @@ async fn grid_filter_date_is_test() {
#[tokio::test]
async fn grid_filter_date_after_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 3;
@ -60,7 +60,7 @@ async fn grid_filter_date_after_test() {
#[tokio::test]
async fn grid_filter_date_on_or_after_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 3;
@ -88,7 +88,7 @@ async fn grid_filter_date_on_or_after_test() {
#[tokio::test]
async fn grid_filter_date_on_or_before_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 4;
@ -116,7 +116,7 @@ async fn grid_filter_date_on_or_before_test() {
#[tokio::test]
async fn grid_filter_date_within_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 5;

View File

@ -3,7 +3,7 @@ mod checkbox_filter_test;
mod checklist_filter_test;
mod date_filter_test;
mod number_filter_test;
mod script;
// mod script;
mod select_option_filter_test;
mod text_filter_test;
mod time_filter_test;

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{FieldType, NumberFilterConditionPB, NumberFilterPB};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_number_is_equal_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 1;
@ -30,7 +30,7 @@ async fn grid_filter_number_is_equal_test() {
#[tokio::test]
async fn grid_filter_number_is_less_than_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 2;
@ -57,7 +57,7 @@ async fn grid_filter_number_is_less_than_test() {
#[tokio::test]
#[should_panic]
async fn grid_filter_number_is_less_than_test2() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 2;
@ -83,7 +83,7 @@ async fn grid_filter_number_is_less_than_test2() {
#[tokio::test]
async fn grid_filter_number_is_less_than_or_equal_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 3;
@ -109,7 +109,7 @@ async fn grid_filter_number_is_less_than_or_equal_test() {
#[tokio::test]
async fn grid_filter_number_is_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 2;
@ -135,7 +135,7 @@ async fn grid_filter_number_is_empty_test() {
#[tokio::test]
async fn grid_filter_number_is_not_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 5;

View File

@ -1,323 +0,0 @@
#![allow(dead_code)]
use std::time::Duration;
use collab_database::rows::RowId;
use flowy_database2::services::filter::{FilterChangeset, FilterInner};
use lib_infra::box_any::BoxAny;
use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::{
DatabaseViewSettingPB, FieldType, FilterPB, FilterType, TextFilterConditionPB, TextFilterPB,
};
use flowy_database2::services::database_view::DatabaseViewChanged;
use crate::database::database_editor::DatabaseEditorTest;
pub struct FilterRowChanged {
pub(crate) showing_num_of_rows: usize,
pub(crate) hiding_num_of_rows: usize,
}
pub struct DatabaseFilterTest {
inner: DatabaseEditorTest,
recv: Option<Receiver<DatabaseViewChanged>>,
}
impl DatabaseFilterTest {
pub async fn new() -> Self {
let editor_test = DatabaseEditorTest::new_grid().await;
Self {
inner: editor_test,
recv: None,
}
}
pub async fn get_all_filters(&self) -> Vec<FilterPB> {
self.editor.get_all_filters(&self.view_id).await.items
}
pub async fn get_filter(
&self,
filter_type: FilterType,
field_type: Option<FieldType>,
) -> Option<FilterPB> {
let filters = self.inner.editor.get_all_filters(&self.view_id).await;
for filter in filters.items.iter() {
let result = Self::find_filter(filter, filter_type, field_type);
if result.is_some() {
return result;
}
}
None
}
fn find_filter(
filter: &FilterPB,
filter_type: FilterType,
field_type: Option<FieldType>,
) -> Option<FilterPB> {
match &filter.filter_type {
FilterType::And | FilterType::Or if filter.filter_type == filter_type => Some(filter.clone()),
FilterType::And | FilterType::Or => {
for child_filter in filter.children.iter() {
if let Some(result) = Self::find_filter(child_filter, filter_type, field_type) {
return Some(result);
}
}
None
},
FilterType::Data
if filter.filter_type == filter_type
&& field_type.map_or(false, |field_type| {
field_type == filter.data.clone().unwrap().field_type
}) =>
{
Some(filter.clone())
},
_ => None,
}
}
pub async fn update_text_cell_with_change(
&mut self,
row_id: RowId,
text: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
self.update_text_cell(row_id, &text).await.unwrap();
}
pub async fn update_checklist_cell(&mut self, row_id: RowId, selected_option_ids: Vec<String>) {
self
.set_checklist_cell(row_id, selected_option_ids)
.await
.unwrap();
}
pub async fn update_single_select_cell_with_change(
&mut self,
row_id: RowId,
option_id: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
self
.update_single_select_cell(row_id, &option_id)
.await
.unwrap();
}
pub async fn create_data_filter(
&mut self,
parent_filter_id: Option<String>,
field_type: FieldType,
data: BoxAny,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let field = self.get_first_field(field_type).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::Data {
field_id: field.id,
field_type,
condition_and_content: data,
},
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn update_text_filter(
&mut self,
filter: FilterPB,
condition: TextFilterConditionPB,
content: String,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let current_filter = filter.data.unwrap();
let params = FilterChangeset::UpdateData {
filter_id: filter.id,
data: FilterInner::Data {
field_id: current_filter.field_id,
field_type: current_filter.field_type,
condition_and_content: BoxAny::new(TextFilterPB { condition, content }),
},
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn create_and_filter(
&mut self,
parent_filter_id: Option<String>,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::And { children: vec![] },
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn create_or_filter(
&mut self,
parent_filter_id: Option<String>,
changed: Option<FilterRowChanged>,
) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Insert {
parent_filter_id,
data: FilterInner::Or { children: vec![] },
};
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn delete_filter(&mut self, filter_id: String, changed: Option<FilterRowChanged>) {
self.subscribe_view_changed().await;
self.assert_future_changed(changed).await;
let params = FilterChangeset::Delete { filter_id };
self
.editor
.modify_view_filters(&self.view_id, params)
.await
.unwrap();
}
pub async fn assert_filter_count(&self, count: usize) {
let filters = self.editor.get_all_filters(&self.view_id).await.items;
assert_eq!(count, filters.len());
}
pub async fn assert_grid_setting(&self, expected_setting: DatabaseViewSettingPB) {
let setting = self
.editor
.get_database_view_setting(&self.view_id)
.await
.unwrap();
assert_eq!(expected_setting, setting);
}
pub async fn assert_filters(&self, expected: Vec<FilterPB>) {
let actual = self.get_all_filters().await;
for (actual_filter, expected_filter) in actual.iter().zip(expected.iter()) {
Self::assert_filter(actual_filter, expected_filter);
}
}
pub async fn assert_number_of_visible_rows(&self, expected: usize) {
let (tx, rx) = tokio::sync::oneshot::channel();
let _ = self
.editor
.open_database_view(&self.view_id, Some(tx))
.await
.unwrap();
rx.await.unwrap();
let rows = self.editor.get_all_rows(&self.view_id).await.unwrap();
assert_eq!(rows.len(), expected);
}
pub async fn wait(&self, millisecond: u64) {
tokio::time::sleep(Duration::from_millis(millisecond)).await;
}
async fn subscribe_view_changed(&mut self) {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id)
.await
.unwrap(),
);
}
async fn assert_future_changed(&mut self, change: Option<FilterRowChanged>) {
if change.is_none() {
return;
}
let change = change.unwrap();
let mut receiver = self.recv.take().unwrap();
tokio::spawn(async move {
match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await {
Ok(changed) => {
if let DatabaseViewChanged::FilterNotification(notification) = changed.unwrap() {
assert_eq!(
notification.visible_rows.len(),
change.showing_num_of_rows,
"visible rows not match"
);
assert_eq!(
notification.invisible_rows.len(),
change.hiding_num_of_rows,
"invisible rows not match"
);
}
},
Err(e) => {
panic!("Process filter task timeout: {:?}", e);
},
}
});
}
fn assert_filter(actual: &FilterPB, expected: &FilterPB) {
assert_eq!(actual.filter_type, expected.filter_type);
assert_eq!(actual.children.is_empty(), expected.children.is_empty());
assert_eq!(actual.data.is_some(), expected.data.is_some());
match actual.filter_type {
FilterType::Data => {
let actual_data = actual.data.clone().unwrap();
let expected_data = expected.data.clone().unwrap();
assert_eq!(actual_data.field_type, expected_data.field_type);
assert_eq!(actual_data.data, expected_data.data);
},
FilterType::And | FilterType::Or => {
for (actual_child, expected_child) in actual.children.iter().zip(expected.children.iter()) {
Self::assert_filter(actual_child, expected_child);
}
},
}
}
}
impl std::ops::Deref for DatabaseFilterTest {
type Target = DatabaseEditorTest;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for DatabaseFilterTest {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{FieldType, SelectOptionFilterConditionPB, SelectOptionFilterPB};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_multi_select_is_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Multi-Select "Is Empty" filter
test
@ -25,7 +25,7 @@ async fn grid_filter_multi_select_is_empty_test() {
#[tokio::test]
async fn grid_filter_multi_select_is_not_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Multi-Select "Is Not Empty" filter
test
@ -46,7 +46,7 @@ async fn grid_filter_multi_select_is_not_empty_test() {
#[tokio::test]
async fn grid_filter_single_select_is_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let expected = 3;
let row_count = test.rows.len();
@ -72,7 +72,7 @@ async fn grid_filter_single_select_is_empty_test() {
#[tokio::test]
async fn grid_filter_single_select_is_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let field = test.get_first_field(FieldType::SingleSelect).await;
let mut options = test.get_single_select_type_option(&field.id).await;
let expected = 2;
@ -100,7 +100,7 @@ async fn grid_filter_single_select_is_test() {
#[tokio::test]
async fn grid_filter_single_select_is_test2() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let field = test.get_first_field(FieldType::SingleSelect).await;
let row_details = test.get_rows().await;
let mut options = test.get_single_select_type_option(&field.id).await;
@ -147,7 +147,7 @@ async fn grid_filter_single_select_is_test2() {
#[tokio::test]
async fn grid_filter_multi_select_contains_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let field = test.get_first_field(FieldType::MultiSelect).await;
let mut options = test.get_multi_select_type_option(&field.id).await;
@ -170,7 +170,7 @@ async fn grid_filter_multi_select_contains_test() {
#[tokio::test]
async fn grid_filter_multi_select_contains_test2() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let field = test.get_first_field(FieldType::MultiSelect).await;
let mut options = test.get_multi_select_type_option(&field.id).await;

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{FieldType, TextFilterConditionPB, TextFilterPB};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_text_is_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Is Empty" filter
test
@ -28,7 +28,7 @@ async fn grid_filter_text_is_empty_test() {
#[tokio::test]
async fn grid_filter_text_is_not_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Is Not Empty" filter
test
@ -67,7 +67,7 @@ async fn grid_filter_text_is_not_empty_test() {
#[tokio::test]
async fn grid_filter_is_text_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Is" filter
test
@ -88,7 +88,7 @@ async fn grid_filter_is_text_test() {
#[tokio::test]
async fn grid_filter_contain_text_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Contains" filter
test
@ -109,7 +109,7 @@ async fn grid_filter_contain_text_test() {
#[tokio::test]
async fn grid_filter_contain_text_test2() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_detail = test.rows.clone();
// Create Text "Contains" filter
@ -143,7 +143,7 @@ async fn grid_filter_contain_text_test2() {
#[tokio::test]
async fn grid_filter_does_not_contain_text_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Does Not Contain" filter
test
@ -164,7 +164,7 @@ async fn grid_filter_does_not_contain_text_test() {
#[tokio::test]
async fn grid_filter_start_with_text_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Starts With" filter
test
@ -185,7 +185,7 @@ async fn grid_filter_start_with_text_test() {
#[tokio::test]
async fn grid_filter_ends_with_text_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Ends With" filter
test
@ -206,7 +206,7 @@ async fn grid_filter_ends_with_text_test() {
#[tokio::test]
async fn grid_update_text_filter_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Ends With" filter
test
@ -248,7 +248,7 @@ async fn grid_update_text_filter_test() {
#[tokio::test]
async fn grid_filter_delete_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
// Create Text "Is Empty" filter
test
@ -278,7 +278,7 @@ async fn grid_filter_delete_test() {
#[tokio::test]
async fn grid_filter_update_empty_text_cell_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row = test.rows.clone();
// Create Text "Is Empty" filter

View File

@ -1,10 +1,10 @@
use crate::database::filter_test::script::{DatabaseFilterTest, FilterRowChanged};
use crate::database::database_editor::{DatabaseEditorTest, FilterRowChanged};
use flowy_database2::entities::{FieldType, NumberFilterConditionPB, TimeFilterPB};
use lib_infra::box_any::BoxAny;
#[tokio::test]
async fn grid_filter_time_is_equal_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 1;
@ -30,7 +30,7 @@ async fn grid_filter_time_is_equal_test() {
#[tokio::test]
async fn grid_filter_time_is_less_than_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 1;
@ -56,7 +56,7 @@ async fn grid_filter_time_is_less_than_test() {
#[tokio::test]
async fn grid_filter_time_is_less_than_or_equal_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 1;
@ -82,7 +82,7 @@ async fn grid_filter_time_is_less_than_or_equal_test() {
#[tokio::test]
async fn grid_filter_time_is_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 6;
@ -108,7 +108,7 @@ async fn grid_filter_time_is_empty_test() {
#[tokio::test]
async fn grid_filter_time_is_not_empty_test() {
let mut test = DatabaseFilterTest::new().await;
let mut test = DatabaseEditorTest::new_grid().await;
let row_count = test.rows.len();
let expected = 1;