#include "app_core/document_cloud.h" #include "test_harness.h" #include #include namespace { class FakeCloudServices final : public pp::app::CloudServices { public: void show_save_required_warning() override { warnings += 1; call_order += "warn;"; } void prompt_publish(bool save_before_upload) override { prompts += 1; last_save_before_upload = save_before_upload; call_order += "prompt;"; } void begin_bulk_upload(int progress_total, bool show_progress) override { bulk_begins += 1; last_progress_total = progress_total; last_show_progress = show_progress; call_order += "begin;"; } void upload_all_bulk_files() override { bulk_uploads += 1; call_order += "upload-all;"; } void end_bulk_upload() override { bulk_ends += 1; call_order += "end;"; } void show_browser() override { browsers += 1; call_order += "browse;"; } void start_download(const pp::app::CloudDownloadRequest& request) override { downloads += 1; last_selected_file = request.selected_file; last_selected_path = request.selected_path; last_selected_name = request.selected_name; call_order += "download;"; } int warnings = 0; int prompts = 0; int bulk_begins = 0; int bulk_uploads = 0; int bulk_ends = 0; int browsers = 0; int downloads = 0; int last_progress_total = 0; bool last_save_before_upload = false; bool last_show_progress = false; std::string last_selected_file; std::string last_selected_path; std::string last_selected_name; std::string call_order; }; void cloud_upload_is_unavailable_without_canvas(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload(false, false, false); PP_EXPECT(harness, plan.action == pp::app::CloudUploadAction::unavailable_no_canvas); PP_EXPECT(harness, !plan.save_before_upload); } void cloud_upload_warns_for_new_documents(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload(true, true, true); PP_EXPECT(harness, plan.action == pp::app::CloudUploadAction::show_save_required_warning); PP_EXPECT(harness, !plan.save_before_upload); } void cloud_upload_prompts_for_clean_existing_documents(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload(true, false, false); PP_EXPECT(harness, plan.action == pp::app::CloudUploadAction::prompt_publish); PP_EXPECT(harness, !plan.save_before_upload); } void cloud_upload_records_save_before_upload_for_dirty_existing_documents(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload(true, false, true); PP_EXPECT(harness, plan.action == pp::app::CloudUploadAction::prompt_publish); PP_EXPECT(harness, plan.save_before_upload); } void cloud_browse_is_unavailable_without_canvas(pp::tests::Harness& harness) { PP_EXPECT(harness, pp::app::plan_cloud_browse(false) == pp::app::CloudBrowseAction::unavailable_no_canvas); } void cloud_browse_shows_browser_with_canvas(pp::tests::Harness& harness) { PP_EXPECT(harness, pp::app::plan_cloud_browse(true) == pp::app::CloudBrowseAction::show_browser); } void cloud_download_selection_waits_for_empty_file(pp::tests::Harness& harness) { PP_EXPECT( harness, pp::app::plan_cloud_download_selection("") == pp::app::CloudDownloadSelectionAction::wait_for_selection); } void cloud_download_selection_starts_for_selected_file(pp::tests::Harness& harness) { PP_EXPECT( harness, pp::app::plan_cloud_download_selection("demo.ppi") == pp::app::CloudDownloadSelectionAction::start_download); } void cloud_bulk_upload_shows_progress_when_ui_available(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_bulk_upload(3, true); PP_EXPECT(harness, plan.file_count == 3); PP_EXPECT(harness, plan.progress_total == 3); PP_EXPECT(harness, plan.show_progress); } void cloud_bulk_upload_runs_without_progress_when_ui_unavailable(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_bulk_upload(3, false); PP_EXPECT(harness, plan.file_count == 3); PP_EXPECT(harness, plan.progress_total == 3); PP_EXPECT(harness, !plan.show_progress); } void cloud_bulk_upload_keeps_zero_file_progress_explicit(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_bulk_upload(0, true); PP_EXPECT(harness, plan.file_count == 0); PP_EXPECT(harness, plan.progress_total == 0); PP_EXPECT(harness, plan.show_progress); } void cloud_bulk_upload_clamps_progress_total(pp::tests::Harness& harness) { const auto too_many_files = static_cast(std::numeric_limits::max()) + 1U; const auto plan = pp::app::plan_cloud_bulk_upload(too_many_files, true); PP_EXPECT(harness, plan.file_count == too_many_files); PP_EXPECT(harness, plan.progress_total == std::numeric_limits::max()); PP_EXPECT(harness, plan.show_progress); } void cloud_dialog_plans_preserve_upload_prompt_metadata(pp::tests::Harness& harness) { const auto save_required = pp::app::plan_cloud_save_required_prompt(); const auto publish = pp::app::plan_cloud_publish_prompt(); const auto success = pp::app::plan_cloud_upload_success_prompt(); PP_EXPECT(harness, save_required.title == "Warning"); PP_EXPECT(harness, save_required.message == "This document needs to be saved before upload."); PP_EXPECT(harness, !save_required.show_cancel); PP_EXPECT(harness, publish.title == "Publish document"); PP_EXPECT(harness, publish.message == "Would you like to upload to the public domain?"); PP_EXPECT(harness, publish.ok_caption == "Yes"); PP_EXPECT(harness, publish.cancel_caption == "No"); PP_EXPECT(harness, publish.show_cancel); PP_EXPECT(harness, success.title == "Success"); PP_EXPECT(harness, success.message == "This document has been succesfully uploaded."); PP_EXPECT(harness, !success.show_cancel); } void cloud_progress_dialog_plans_preserve_legacy_titles(pp::tests::Harness& harness) { const auto upload = pp::app::plan_cloud_upload_progress_dialog(); const auto bulk = pp::app::plan_cloud_bulk_upload_progress_dialog(4); const auto download = pp::app::plan_cloud_download_progress_prompt(); PP_EXPECT(harness, upload.title == "Uploading"); PP_EXPECT(harness, upload.total == 0); PP_EXPECT(harness, bulk.title == "Export Pano Image"); PP_EXPECT(harness, bulk.total == 4); PP_EXPECT(harness, download.title == "Downloading"); PP_EXPECT(harness, download.message == "Download in progress"); PP_EXPECT(harness, download.show_cancel); PP_EXPECT(harness, pp::app::format_cloud_download_progress_message(0.25F) == "Download in progress 25.00%"); } void cloud_download_transfer_rejects_missing_url(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_download_transfer("", "D:/Paint/demo.ppi", true, true); PP_EXPECT(harness, plan.direction == pp::app::CloudTransferDirection::download); PP_EXPECT(harness, plan.action == pp::app::CloudTransferAction::reject_missing_source); PP_EXPECT(harness, !plan.enable_progress); PP_EXPECT(harness, !plan.disable_tls_verification); } void cloud_download_transfer_rejects_missing_destination(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_download_transfer("https://example.invalid/demo.ppi", "", true, true); PP_EXPECT(harness, plan.direction == pp::app::CloudTransferDirection::download); PP_EXPECT(harness, plan.action == pp::app::CloudTransferAction::reject_missing_destination); PP_EXPECT(harness, !plan.enable_progress); PP_EXPECT(harness, !plan.disable_tls_verification); } void cloud_download_transfer_starts_with_progress_and_tls_policy(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_download_transfer( "https://example.invalid/demo.ppi", "D:/Paint/demo.ppi", true, true); PP_EXPECT(harness, plan.direction == pp::app::CloudTransferDirection::download); PP_EXPECT(harness, plan.action == pp::app::CloudTransferAction::start_transfer); PP_EXPECT(harness, plan.enable_progress); PP_EXPECT(harness, plan.disable_tls_verification); } void cloud_upload_transfer_rejects_missing_file(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload_transfer("", true, true); PP_EXPECT(harness, plan.direction == pp::app::CloudTransferDirection::upload); PP_EXPECT(harness, plan.action == pp::app::CloudTransferAction::reject_missing_source); PP_EXPECT(harness, !plan.enable_progress); PP_EXPECT(harness, !plan.disable_tls_verification); } void cloud_upload_transfer_starts_with_progress_and_tls_policy(pp::tests::Harness& harness) { const auto plan = pp::app::plan_cloud_upload_transfer("D:/Paint/demo.ppi", true, false); PP_EXPECT(harness, plan.direction == pp::app::CloudTransferDirection::upload); PP_EXPECT(harness, plan.action == pp::app::CloudTransferAction::start_transfer); PP_EXPECT(harness, plan.enable_progress); PP_EXPECT(harness, !plan.disable_tls_verification); } void cloud_transfer_progress_ignores_unknown_total(pp::tests::Harness& harness) { const auto zero = pp::app::plan_cloud_transfer_progress(0, 4); const auto negative = pp::app::plan_cloud_transfer_progress(-10, 4); PP_EXPECT(harness, !zero.notify); PP_EXPECT(harness, zero.fraction == 0.0F); PP_EXPECT(harness, !negative.notify); PP_EXPECT(harness, negative.fraction == 0.0F); } void cloud_transfer_progress_clamps_to_valid_fraction(pp::tests::Harness& harness) { const auto before_start = pp::app::plan_cloud_transfer_progress(10, -2); const auto half = pp::app::plan_cloud_transfer_progress(10, 5); const auto after_end = pp::app::plan_cloud_transfer_progress(10, 20); PP_EXPECT(harness, before_start.notify); PP_EXPECT(harness, before_start.fraction == 0.0F); PP_EXPECT(harness, half.notify); PP_EXPECT(harness, half.fraction == 0.5F); PP_EXPECT(harness, after_end.notify); PP_EXPECT(harness, after_end.fraction == 1.0F); } void executor_dispatches_cloud_upload_variants(pp::tests::Harness& harness) { FakeCloudServices services; PP_EXPECT(harness, pp::app::execute_cloud_upload_plan(pp::app::plan_cloud_upload(false, false, false), services).ok()); PP_EXPECT(harness, pp::app::execute_cloud_upload_plan(pp::app::plan_cloud_upload(true, true, true), services).ok()); PP_EXPECT(harness, pp::app::execute_cloud_upload_plan(pp::app::plan_cloud_upload(true, false, true), services).ok()); PP_EXPECT(harness, services.warnings == 1); PP_EXPECT(harness, services.prompts == 1); PP_EXPECT(harness, services.last_save_before_upload); PP_EXPECT(harness, services.call_order == "warn;prompt;"); } void executor_dispatches_cloud_bulk_browse_and_download(pp::tests::Harness& harness) { FakeCloudServices services; const auto bulk = pp::app::plan_cloud_bulk_upload(3, true); PP_EXPECT(harness, pp::app::execute_cloud_bulk_upload_plan(bulk, services).ok()); PP_EXPECT(harness, pp::app::execute_cloud_browse_action(pp::app::plan_cloud_browse(false), services).ok()); PP_EXPECT(harness, pp::app::execute_cloud_browse_action(pp::app::plan_cloud_browse(true), services).ok()); pp::app::CloudDownloadRequest wait_request; PP_EXPECT( harness, pp::app::execute_cloud_download_selection_action( pp::app::plan_cloud_download_selection(""), services, wait_request) .ok()); pp::app::CloudDownloadRequest download_request { .selected_file = "demo.ppi", .selected_path = "D:/Paint/demo.ppi", .selected_name = "demo", }; PP_EXPECT( harness, pp::app::execute_cloud_download_selection_action( pp::app::plan_cloud_download_selection(download_request.selected_file), services, download_request) .ok()); PP_EXPECT(harness, services.bulk_begins == 1); PP_EXPECT(harness, services.last_progress_total == 3); PP_EXPECT(harness, services.last_show_progress); PP_EXPECT(harness, services.bulk_uploads == 1); PP_EXPECT(harness, services.bulk_ends == 1); PP_EXPECT(harness, services.browsers == 1); PP_EXPECT(harness, services.downloads == 1); PP_EXPECT(harness, services.last_selected_file == "demo.ppi"); PP_EXPECT(harness, services.last_selected_path == "D:/Paint/demo.ppi"); PP_EXPECT(harness, services.last_selected_name == "demo"); PP_EXPECT(harness, services.call_order == "begin;upload-all;end;browse;download;"); } void executor_rejects_mismatched_download_action(pp::tests::Harness& harness) { FakeCloudServices services; pp::app::CloudDownloadRequest empty_request; PP_EXPECT( harness, !pp::app::execute_cloud_download_selection_action( pp::app::CloudDownloadSelectionAction::start_download, services, empty_request) .ok()); PP_EXPECT(harness, services.downloads == 0); } } int main() { pp::tests::Harness harness; harness.run("cloud upload is unavailable without canvas", cloud_upload_is_unavailable_without_canvas); harness.run("cloud upload warns for new documents", cloud_upload_warns_for_new_documents); harness.run("cloud upload prompts for clean existing documents", cloud_upload_prompts_for_clean_existing_documents); harness.run("cloud upload records save before upload for dirty existing documents", cloud_upload_records_save_before_upload_for_dirty_existing_documents); harness.run("cloud browse is unavailable without canvas", cloud_browse_is_unavailable_without_canvas); harness.run("cloud browse shows browser with canvas", cloud_browse_shows_browser_with_canvas); harness.run("cloud download selection waits for empty file", cloud_download_selection_waits_for_empty_file); harness.run("cloud download selection starts for selected file", cloud_download_selection_starts_for_selected_file); harness.run("cloud bulk upload shows progress when ui available", cloud_bulk_upload_shows_progress_when_ui_available); harness.run("cloud bulk upload runs without progress when ui unavailable", cloud_bulk_upload_runs_without_progress_when_ui_unavailable); harness.run("cloud bulk upload keeps zero file progress explicit", cloud_bulk_upload_keeps_zero_file_progress_explicit); harness.run("cloud bulk upload clamps progress total", cloud_bulk_upload_clamps_progress_total); harness.run("cloud dialog plans preserve upload prompt metadata", cloud_dialog_plans_preserve_upload_prompt_metadata); harness.run("cloud progress dialog plans preserve legacy titles", cloud_progress_dialog_plans_preserve_legacy_titles); harness.run("cloud download transfer rejects missing url", cloud_download_transfer_rejects_missing_url); harness.run("cloud download transfer rejects missing destination", cloud_download_transfer_rejects_missing_destination); harness.run("cloud download transfer starts with progress and tls policy", cloud_download_transfer_starts_with_progress_and_tls_policy); harness.run("cloud upload transfer rejects missing file", cloud_upload_transfer_rejects_missing_file); harness.run("cloud upload transfer starts with progress and tls policy", cloud_upload_transfer_starts_with_progress_and_tls_policy); harness.run("cloud transfer progress ignores unknown total", cloud_transfer_progress_ignores_unknown_total); harness.run("cloud transfer progress clamps to valid fraction", cloud_transfer_progress_clamps_to_valid_fraction); harness.run("executor dispatches cloud upload variants", executor_dispatches_cloud_upload_variants); harness.run("executor dispatches cloud bulk browse and download", executor_dispatches_cloud_bulk_browse_and_download); harness.run("executor rejects mismatched download action", executor_rejects_mismatched_download_action); return harness.finish(); }