using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using Paca.App.Utils; using Paca.Tests.Infrastructure; using Xunit; namespace Paca.Tests.App; /// /// 브라우저 상단 및 창 빈 공간 더블클릭/드래그 조작 무결성 테스트 게이트: /// 1. 버튼, 텍스트박스, 주소창, 탭 아이템 등 상호작용 요소 클릭/더블클릭 시 창 최대화 차단 검증 /// 2. 툴바, 탭 바, 북마크 바 등 '순수 빈 공간' 클릭/더블클릭 시에만 창 최대화/복원 및 드래그 허용 검증 /// 3. XAML 및 코드비하인드 이벤트 핸들링 순서 무결성 검증 (IsInteractiveElement 사전 검사 강제) /// public class WindowDragAndDoubleClickGateTests { [Fact] public void IsInteractiveElement_대화형_컨트롤_및_그_자식은_True를_반환한다() { using var sta = StaDispatcher.Start(); sta.Dispatcher.Invoke(() => { // ButtonBase 계열 Assert.True(WindowDragHelper.IsInteractiveElement(new Button())); Assert.True(WindowDragHelper.IsInteractiveElement(new ToggleButton())); Assert.True(WindowDragHelper.IsInteractiveElement(new CheckBox())); Assert.True(WindowDragHelper.IsInteractiveElement(new RepeatButton())); // 입력창 및 텍스트박스 Assert.True(WindowDragHelper.IsInteractiveElement(new TextBox())); Assert.True(WindowDragHelper.IsInteractiveElement(new PasswordBox())); Assert.True(WindowDragHelper.IsInteractiveElement(new RichTextBox())); // 콤보박스 및 선택기 Assert.True(WindowDragHelper.IsInteractiveElement(new ComboBox())); Assert.True(WindowDragHelper.IsInteractiveElement(new ComboBoxItem())); // 진행률 및 슬라이더/스크롤바 Assert.True(WindowDragHelper.IsInteractiveElement(new ProgressBar())); Assert.True(WindowDragHelper.IsInteractiveElement(new Slider())); Assert.True(WindowDragHelper.IsInteractiveElement(new ScrollBar())); Assert.True(WindowDragHelper.IsInteractiveElement(new Thumb())); // 메뉴 계열 Assert.True(WindowDragHelper.IsInteractiveElement(new Menu())); Assert.True(WindowDragHelper.IsInteractiveElement(new MenuItem())); // 특정 컨테이너 식별자 (주소창, 탭 아이템 등) Assert.True(WindowDragHelper.IsInteractiveElement(new Border { Name = "AddressBarContainer" })); Assert.True(WindowDragHelper.IsInteractiveElement(new Border { Name = "TabBg" })); Assert.True(WindowDragHelper.IsInteractiveElement(new FrameworkElement { Name = "WebStoreInstallBtn" })); Assert.True(WindowDragHelper.IsInteractiveElement(new FrameworkElement { Name = "BookmarkStarBtn" })); // 마우스 손가락 모양(Hand) 인터랙션 요소 Assert.True(WindowDragHelper.IsInteractiveElement(new Border { Cursor = System.Windows.Input.Cursors.Hand })); }); } [Fact] public void IsInteractiveElement_대화형_컨트롤_내부의_자식_요소도_True를_반환한다() { using var sta = StaDispatcher.Start(); sta.Dispatcher.Invoke(() => { // 버튼 안의 아이콘 텍스트블록 var btn = new Button(); var iconText = new TextBlock { Text = "icon" }; btn.Content = iconText; Assert.True(WindowDragHelper.IsInteractiveElement(iconText)); // 주소창 컨테이너 내부의 텍스트블록 var container = new Border { Name = "AddressBarContainer" }; var innerText = new TextBlock { Text = "https://example.com" }; container.Child = innerText; Assert.True(WindowDragHelper.IsInteractiveElement(innerText)); }); } [Fact] public void IsInteractiveElement_순수_빈_공간_컨테이너는_False를_반환한다() { using var sta = StaDispatcher.Start(); sta.Dispatcher.Invoke(() => { // 툴바 빈 공간, 탭 바 빈 공간, 일반 패널 배경 Assert.False(WindowDragHelper.IsInteractiveElement(new Border { Name = "ToolbarRow" })); Assert.False(WindowDragHelper.IsInteractiveElement(new Border { Name = "TabStripRow" })); Assert.False(WindowDragHelper.IsInteractiveElement(new Border { Name = "BookmarkBar" })); Assert.False(WindowDragHelper.IsInteractiveElement(new Grid())); Assert.False(WindowDragHelper.IsInteractiveElement(new DockPanel())); Assert.False(WindowDragHelper.IsInteractiveElement(new StackPanel())); Assert.False(WindowDragHelper.IsInteractiveElement(null)); }); } [Fact] public void MainWindow_타이틀바_핸들러는_더블클릭_전에_반드시_인터랙티브_검사를_수행해야_한다() { var cs = SourceTree.MainWindowCs; // TitleBar_PreviewMouseLeftButtonDown 내에서 // IsInteractiveTitleBarElement 또는 IsInteractiveElement 호출이 // MaximizeToggle() 호출보다 앞에 위치해야 함 (순서 역전 방지) int methodIndex = cs.IndexOf("TitleBar_PreviewMouseLeftButtonDown("); Assert.True(methodIndex > 0, "TitleBar_PreviewMouseLeftButtonDown 메서드가 존재해야 합니다."); string methodBody = cs.Substring(methodIndex, 800); int interactiveCheckIndex = methodBody.IndexOf("IsInteractive"); int maximizeToggleIndex = methodBody.IndexOf("MaximizeToggle()"); Assert.True(interactiveCheckIndex > 0, "인터랙티브 요소 검사가 존재해야 합니다."); Assert.True(maximizeToggleIndex > 0, "더블클릭 최대화 토글 호출이 존재해야 합니다."); Assert.True(interactiveCheckIndex < maximizeToggleIndex, "치명적 결함 방지: 버튼 더블클릭 시 창 최대화를 막으려면 인터랙티브 검사가 MaximizeToggle()보다 반드시 먼저 실행되어야 합니다."); } [Fact] public void MainWindow_탭바_빈공간_이벤트_핸들러가_XAML과_코드비하인드에_정의되어_있다() { var xaml = SourceTree.MainWindowXaml; var cs = SourceTree.MainWindowCs; // TabStripRow 에 빈 공간 드래그 및 더블클릭 최대화 핸들러 연결 확인 Assert.Contains("TabStripRow_PreviewMouseLeftButtonDown", xaml); Assert.Contains("TabStripRow_PreviewMouseLeftButtonDown", cs); } [Fact] public void MainWindow_북마크바_및_우측패널_헤더도_빈공간_핸들러가_연결되어_있다() { var xaml = SourceTree.MainWindowXaml; var cs = SourceTree.MainWindowCs; // BookmarkBar 연결 확인 Assert.Contains("BookmarkBar_PreviewMouseLeftButtonDown", xaml); Assert.Contains("BookmarkBar_PreviewMouseLeftButtonDown", cs); // 우측 도킹 패널 헤더의 빈 공간 드래그/더블클릭 연결 확인 Assert.Contains("PreviewMouseLeftButtonDown=\"TitleBar_PreviewMouseLeftButtonDown\"", xaml); } }