#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include <utility>
#include <vector>
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "chrome/browser/media/webrtc/desktop_media_list.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "content/public/browser/desktop_capture.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/strings/string_util_win.h"
#endif
DesktopMediaID;
_;
DoAll;
namespace {
static const int kDefaultWindowCount = …;
#if defined(ENABLE_AURA_WINDOW_TESTS)
static const int kDefaultAuraCount = 1;
#else
static const int kDefaultAuraCount = …;
#endif
#if BUILDFLAG(IS_WIN)
constexpr char kWindowTitle[] = "NativeDesktopMediaList Test Window";
constexpr wchar_t kWideWindowTitle[] = L"NativeDesktopMediaList Test Window";
constexpr wchar_t kWindowClass[] = L"NativeDesktopMediaListTestWindowClass";
struct WindowInfo {
HWND hwnd;
HINSTANCE window_instance;
ATOM window_class;
};
WindowInfo CreateTestWindow() {
WindowInfo info;
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&DefWindowProc),
&info.window_instance);
WNDCLASS window_class = {};
window_class.hInstance = info.window_instance;
window_class.lpfnWndProc = &DefWindowProc;
window_class.lpszClassName = kWindowClass;
info.window_class = ::RegisterClass(&window_class);
info.hwnd =
::CreateWindow(kWindowClass, kWideWindowTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 100,
100, nullptr,
nullptr, info.window_instance,
nullptr);
::ShowWindow(info.hwnd, SW_SHOWNORMAL);
::UpdateWindow(info.hwnd);
return info;
}
void DestroyTestWindow(WindowInfo info) {
::DestroyWindow(info.hwnd);
::UnregisterClass(MAKEINTATOM(info.window_class), info.window_instance);
}
#endif
int WindowIndex(int index) { … }
class MockObserver : public DesktopMediaListObserver { … };
class FakeScreenCapturer : public ThumbnailCapturer { … };
class FakeWindowCapturer : public ThumbnailCapturer { … };
}
ACTION_P2(CheckListSize, model, expected_list_size) { … }
ACTION_P2(QuitRunLoop, task_runner, run_loop) { … }
class NativeDesktopMediaListTest : public ChromeViewsTestBase { … };
TEST_F(NativeDesktopMediaListTest, Windows) { … }
TEST_F(NativeDesktopMediaListTest, ScreenOnly) { … }
TEST_F(NativeDesktopMediaListTest, WindowFiltering) { … }
TEST_F(NativeDesktopMediaListTest, AddNativeWindow) { … }
#if defined(ENABLE_AURA_WINDOW_TESTS)
TEST_F(NativeDesktopMediaListTest, AddAuraWindow) {
AddWindowsAndVerify(false);
base::RunLoop run_loop;
const int index = kDefaultWindowCount;
EXPECT_CALL(observer_, OnSourceAdded(index))
.WillOnce(
DoAll(CheckListSize(kDefaultWindowCount + 1),
QuitRunLoop(base::SingleThreadTaskRunner::GetCurrentDefault(),
&run_loop)));
AddAuraWindow();
window_capturer_->SetWindowList(window_list_);
run_loop.Run();
int native_id = window_list_.back().id;
EXPECT_EQ(model_->GetSource(index).id.type, DesktopMediaID::TYPE_WINDOW);
EXPECT_EQ(model_->GetSource(index).id.id, native_id);
EXPECT_EQ(model_->GetSource(index).id.window_id,
native_aura_id_map_[native_id]);
}
#endif
TEST_F(NativeDesktopMediaListTest, RemoveNativeWindow) { … }
#if defined(ENABLE_AURA_WINDOW_TESTS)
TEST_F(NativeDesktopMediaListTest, RemoveAuraWindow) {
AddWindowsAndVerify(false);
base::RunLoop run_loop;
int aura_window_start_index = kDefaultWindowCount - kDefaultAuraCount;
EXPECT_CALL(observer_, OnSourceRemoved(aura_window_start_index))
.WillOnce(
DoAll(CheckListSize(model_.get(), kDefaultWindowCount - 1),
QuitRunLoop(base::SingleThreadTaskRunner::GetCurrentDefault(),
&run_loop)));
RemoveAuraWindow(0);
window_capturer_->SetWindowList(window_list_);
run_loop.Run();
}
#endif
TEST_F(NativeDesktopMediaListTest, RemoveAllWindows) { … }
TEST_F(NativeDesktopMediaListTest, UpdateTitle) { … }
TEST_F(NativeDesktopMediaListTest, UpdateThumbnail) { … }
TEST_F(NativeDesktopMediaListTest, MoveWindow) { … }
TEST_F(NativeDesktopMediaListTest, EmptyThumbnail) { … }
#if BUILDFLAG(IS_WIN)
TEST_F(NativeDesktopMediaListTest, GetSourceListAvoidsDeadlock) {
base::Thread window_thread("GetSourceListDeadlockTestWindowThread");
window_thread.Start();
base::RunLoop run_loop;
WindowInfo info;
window_thread.task_runner()->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&CreateTestWindow),
base::BindLambdaForTesting([&](WindowInfo window_info) {
info = window_info;
run_loop.Quit();
}));
run_loop.Run();
EXPECT_NE(info.hwnd, static_cast<HWND>(0));
webrtc::DesktopCaptureOptions options =
content::desktop_capture::CreateDesktopCaptureOptions();
EXPECT_FALSE(options.enumerate_current_process_windows());
auto window_capturer = std::make_unique<FakeWindowCapturer>(options);
window_capturer->SetWindowList(
{{reinterpret_cast<intptr_t>(info.hwnd), kWindowTitle}});
webrtc::DesktopCapturer::SourceList source_list;
EXPECT_TRUE(window_capturer->GetSourceList(&source_list));
window_thread.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&DestroyTestWindow, info));
window_thread.Stop();
}
TEST_F(NativeDesktopMediaListTest, CollectsCurrentProcessWindows) {
CreateRealWindow();
CreateCapturerAndModel();
UpdateModel();
webrtc::DesktopCapturer::SourceList source_list;
EXPECT_TRUE(window_capturer_->GetSourceList(&source_list));
EXPECT_EQ(source_list.size(), 0ull);
content::DesktopMediaID::Id window_id =
reinterpret_cast<intptr_t>(window_info_.hwnd);
DesktopMediaList::Source source = GetSourceFromModel(window_id);
EXPECT_EQ(source.id.id, window_id);
EXPECT_STREQ(base::as_wcstr(source.name.c_str()), kWideWindowTitle);
}
TEST_F(NativeDesktopMediaListTest, MinimizedCurrentProcessWindows) {
CreateRealWindow();
CreateCapturerAndModel();
webrtc::DesktopCapturer::SourceList source_list;
EXPECT_TRUE(window_capturer_->GetSourceList(&source_list));
EXPECT_EQ(source_list.size(), 0ull);
::ShowWindow(window_info_.hwnd, SW_MINIMIZE);
UpdateModel();
DesktopMediaList::Source source =
GetSourceFromModel(reinterpret_cast<intptr_t>(window_info_.hwnd));
EXPECT_EQ(source.id.id, content::DesktopMediaID::kNullId);
}
#endif
class DelegatedFakeScreenCapturer
: public FakeScreenCapturer,
public webrtc::DelegatedSourceListController { … };
class NativeDesktopMediaListDelegatedTest : public ChromeViewsTestBase { … };
TEST_F(NativeDesktopMediaListDelegatedTest, Selection) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, Cancelled) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, Error) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, ShowRepeatedlyNotForced) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, HideRepeatedly) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, FocusAfterSelect) { … }
TEST_F(NativeDesktopMediaListDelegatedTest, ClearSelectionNoOp) { … }