releases/tests/Paca.Tests/App/WindowDragAndDoubleClickGateTests.cs

144 lines
7.1 KiB
C#

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;
/// <summary>
/// 브라우저 상단 및 창 빈 공간 더블클릭/드래그 조작 무결성 테스트 게이트:
/// 1. 버튼, 텍스트박스, 주소창, 탭 아이템 등 상호작용 요소 클릭/더블클릭 시 창 최대화 차단 검증
/// 2. 툴바, 탭 바, 북마크 바 등 '순수 빈 공간' 클릭/더블클릭 시에만 창 최대화/복원 및 드래그 허용 검증
/// 3. XAML 및 코드비하인드 이벤트 핸들링 순서 무결성 검증 (IsInteractiveElement 사전 검사 강제)
/// </summary>
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);
}
}