Skip to content

Commit 009fc62

Browse files
committed
Menu Manager tests for findMenuCommand and findPluginCommand
1 parent c0ab566 commit 009fc62

File tree

2 files changed

+251
-3
lines changed

2 files changed

+251
-3
lines changed

PythonScript.Tests/tests/TestMenuManager.cpp

Lines changed: 241 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,256 @@
33

44
#include <gtest/gtest.h>
55
#include "MenuManager.h"
6+
#include <Notepad_plus_msgs.h>
67

78
namespace NppPythonScript
89
{
9-
10+
11+
static volatile HMENU g_hPluginMenu;
12+
13+
static LRESULT dummyWindowProc(HWND /* hWnd */, UINT message, WPARAM /* wParam */, LPARAM /* lParam */)
14+
{
15+
switch(message)
16+
{
17+
case WM_CREATE:
18+
return FALSE;
19+
20+
case NPPM_GETMENUHANDLE:
21+
return reinterpret_cast<LRESULT>(g_hPluginMenu);
22+
23+
default:
24+
return TRUE;
25+
}
26+
}
27+
28+
29+
#define UNIT_TEST_WINDOW_CLASS L"UnitTestDummy"
30+
31+
32+
enum MenuIds {
33+
MENUID_FILE_OPEN = 1000,
34+
MENUID_FILE_CLOSE,
35+
MENUID_FILE_RECENT,
36+
MENUID_FILE_EXIT,
37+
MENUID_FILE_RECENT_1,
38+
MENUID_FILE_RECENT_2,
39+
MENUID_FILE_RECENT_3,
40+
MENUID_EDIT_COPY,
41+
MENUID_EDIT_PASTE,
42+
MENUID_XMLTOOLS_PRETTYPRINT,
43+
MENUID_XMLTOOLS_OPEN,
44+
MENUID_XMLTOOLS_RECENT_1,
45+
MENUID_XMLTOOLS_ABOUT,
46+
MENUID_SECONDPLUGIN_PRETTYPRINT,
47+
MENUID_SECONDPLUGIN_OPEN,
48+
MENUID_SECONDPLUGIN_ABOUT,
49+
MENUID_SECONDPLUGIN_RECENT_1,
50+
MENUID_SECONDPLUGIN_RECENT_2
51+
};
52+
1053
class MenuManagerTest : public ::testing::Test {
1154
virtual void SetUp() {
55+
m_hModule = ::GetModuleHandle(NULL);
56+
57+
RegisterTestWindowClass();
58+
CreateTestMenu();
59+
CreateTestWindow();
60+
ASSERT_NE(0, (LONG)m_hWindow);
61+
MenuManager::create(m_hWindow, reinterpret_cast<HINSTANCE>(m_hModule), NULL);
62+
m_menuManager = MenuManager::getInstance();
63+
}
64+
65+
virtual void TearDown() {
66+
DestroyWindow(m_hWindow);
67+
UnregisterClass(UNIT_TEST_WINDOW_CLASS, m_hModule);
68+
DestroyMenu(m_hMenu);
69+
MenuManager::destroyForTests();
70+
}
71+
72+
73+
74+
protected:
75+
HMENU m_hMenu;
76+
HWND m_hWindow;
77+
HMODULE m_hModule;
78+
MenuManager* m_menuManager;
79+
80+
81+
void RegisterTestWindowClass() {
82+
WNDCLASS wndClass;
83+
memset(&wndClass, 0, sizeof(WNDCLASS));
84+
85+
wndClass.lpfnWndProc = (WNDPROC)&dummyWindowProc;
86+
wndClass.hInstance = m_hModule;
87+
wndClass.lpszClassName = UNIT_TEST_WINDOW_CLASS;
88+
wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
89+
90+
91+
::RegisterClassW(&wndClass);
92+
}
93+
94+
95+
/*
96+
Menu Structure:
97+
98+
File
99+
--> Open
100+
--> Close
101+
--> Recent
102+
--> Recent 1
103+
--> Recent 2
104+
--> Recent 3
105+
--> Exit
106+
107+
Edit
108+
--> Copy
109+
--> Paste
110+
111+
Plugins
112+
--> XML Tools
113+
--> Pretty Print
114+
--> Open
115+
--> Recent 1
116+
--> About
117+
--> Second Plugin
118+
--> Pretty Print
119+
--> Open
120+
--> Recent
121+
--> Recent 1
122+
--> Recent 2
123+
--> About
124+
12125
126+
127+
128+
*/
129+
130+
void CreateTestMenu() {
131+
m_hMenu = ::CreateMenu();
132+
133+
HMENU fileMenu = ::CreateMenu();
134+
::AppendMenu(m_hMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(fileMenu), L"File");
135+
::AppendMenu(fileMenu, MF_STRING, MENUID_FILE_OPEN, L"Open\tCtrl-O");
136+
::AppendMenu(fileMenu, MF_STRING, MENUID_FILE_CLOSE, L"Close\tCtrl-F4");
137+
138+
HMENU recentMenu = ::CreateMenu();
139+
::AppendMenu(recentMenu, MF_STRING, MENUID_FILE_RECENT_1, L"Recent 1");
140+
::AppendMenu(recentMenu, MF_STRING, MENUID_FILE_RECENT_2, L"Recent 2");
141+
::AppendMenu(recentMenu, MF_STRING, MENUID_FILE_RECENT_3, L"Recent 3");
142+
::AppendMenu(fileMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(recentMenu), L"Recent");
143+
144+
::AppendMenu(fileMenu, MF_STRING, MENUID_FILE_CLOSE, L"Exit\tAlt-F4");
145+
146+
HMENU editMenu = ::CreateMenu();
147+
::AppendMenu(m_hMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(editMenu), L"Edit");
148+
::AppendMenu(editMenu, MF_STRING, MENUID_EDIT_COPY, L"Copy");
149+
::AppendMenu(editMenu, MF_STRING, MENUID_EDIT_PASTE, L"Paste\tCtrl-V");
150+
151+
g_hPluginMenu = ::CreateMenu();
152+
::AppendMenu(m_hMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(g_hPluginMenu), L"Plugins");
153+
154+
HMENU xmlToolsPluginMenu = ::CreateMenu();
155+
::AppendMenu(g_hPluginMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(xmlToolsPluginMenu), L"XML Tools");
156+
::AppendMenu(xmlToolsPluginMenu, MF_STRING, MENUID_XMLTOOLS_PRETTYPRINT, L"Pretty Print\tCtrl-Alt-Shift-B");
157+
::AppendMenu(xmlToolsPluginMenu, MF_STRING, MENUID_XMLTOOLS_OPEN, L"Open\tCtrl-O");
158+
::AppendMenu(xmlToolsPluginMenu, MF_STRING, MENUID_XMLTOOLS_RECENT_1, L"Recent 1");
159+
::AppendMenu(xmlToolsPluginMenu, MF_STRING, MENUID_XMLTOOLS_ABOUT, L"A&bout");
160+
161+
HMENU secondPluginMenu = ::CreateMenu();
162+
163+
::AppendMenu(g_hPluginMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(secondPluginMenu), L"Second Plugin");
164+
::AppendMenu(secondPluginMenu, MF_STRING, MENUID_SECONDPLUGIN_PRETTYPRINT, L"Pretty Print\tCtrl-Alt-Shift-B");
165+
::AppendMenu(secondPluginMenu, MF_STRING, MENUID_SECONDPLUGIN_OPEN, L"Open\tCtrl-O");
166+
HMENU secondPluginRecentMenu = ::CreateMenu();
167+
::AppendMenu(secondPluginMenu, MF_POPUP, reinterpret_cast<UINT_PTR>(secondPluginRecentMenu), L"Recent");
168+
::AppendMenu(secondPluginRecentMenu, MF_STRING, MENUID_SECONDPLUGIN_RECENT_1, L"Recent 1");
169+
::AppendMenu(secondPluginRecentMenu, MF_STRING, MENUID_SECONDPLUGIN_RECENT_2, L"Recent 2");
170+
171+
::AppendMenu(secondPluginMenu, MF_STRING, MENUID_SECONDPLUGIN_ABOUT, L"A&bout");
172+
173+
}
174+
175+
void CreateTestWindow() {
176+
m_hWindow = ::CreateWindow(
177+
UNIT_TEST_WINDOW_CLASS, /* Class name */
178+
L"Test window",
179+
WS_OVERLAPPEDWINDOW,
180+
0, 0, 100, 100, /* x, y, width, heigth */
181+
NULL, /* hWndParent */
182+
m_hMenu,
183+
m_hModule,
184+
NULL /* lpParam */
185+
);
13186
}
187+
188+
189+
};
190+
191+
struct MenuTestCase {
192+
MenuTestCase() {}
193+
MenuTestCase(const TCHAR *pmenuName, const TCHAR *poptionName, int pexpectedID)
194+
: menuName(pmenuName),
195+
optionName(poptionName),
196+
expectedID(pexpectedID)
197+
{}
198+
199+
const TCHAR *menuName;
200+
const TCHAR *optionName;
201+
int expectedID;
202+
};
203+
204+
205+
206+
class MenuManagerFindMenuCommandTest : public MenuManagerTest,
207+
public ::testing::WithParamInterface<MenuTestCase> {
208+
209+
};
210+
211+
TEST_P(MenuManagerFindMenuCommandTest, testFindOptionFindsCorrectOption) {
212+
MenuTestCase testCase = GetParam();
213+
LONG_PTR windowWndProc = GetWindowLongPtr(m_hWindow, GWLP_WNDPROC);
214+
LONG_PTR dummyProc = reinterpret_cast<LONG_PTR>(&dummyWindowProc);
215+
ASSERT_EQ(windowWndProc, dummyProc);
216+
int foundMenuId = m_menuManager->findMenuCommand(m_hMenu, NULL, testCase.menuName, testCase.optionName);
217+
ASSERT_EQ(testCase.expectedID, foundMenuId);
218+
}
219+
220+
221+
INSTANTIATE_TEST_CASE_P(findMenuCommand, MenuManagerFindMenuCommandTest,
222+
::testing::Values(MenuTestCase(L"File", L"Open", MENUID_FILE_OPEN), // First option
223+
MenuTestCase(L"File", L"Close", MENUID_FILE_CLOSE), // First menu, middle option
224+
MenuTestCase(L"Edit", L"Copy", MENUID_EDIT_COPY), // Mid menu, first option
225+
MenuTestCase(L"Edit", L"Paste", MENUID_EDIT_PASTE), // Mid menu, last option
226+
MenuTestCase(L"Recent", L"Recent 1", MENUID_FILE_RECENT_1), // Sub menu, first option
227+
MenuTestCase(L"Recent", L"Recent 2", MENUID_FILE_RECENT_2),
228+
MenuTestCase(L"Recent", L"Recent 3", MENUID_FILE_RECENT_3), // Sub menu, last option
229+
MenuTestCase(L"File", L"Recent 2", 0), // Shouldn't find Recent 2 directly under the File menu
230+
MenuTestCase(L"XML Tools", L"Open", MENUID_XMLTOOLS_OPEN), // Repeated option name, on third menu
231+
MenuTestCase(L"Second Plugin", L"About", MENUID_SECONDPLUGIN_ABOUT), // Repeated option name, with & in title
232+
MenuTestCase(L"Second Plugin", L"Not found", 0), // Non existent option
233+
MenuTestCase(L"Not exists", L"Open", 0) // Non existent menu
234+
));
235+
236+
class MenuManagerFindPluginCommandTest : public MenuManagerTest,
237+
public ::testing::WithParamInterface<MenuTestCase> {
238+
14239
};
15240

16-
TEST_F(MenuManagerTest, testDummy) {
17-
ASSERT_EQ(0, 0);
241+
TEST_P(MenuManagerFindPluginCommandTest, testFindPluginCommand) {
242+
MenuTestCase testCase = GetParam();
243+
int foundMenuId = m_menuManager->findPluginCommand(testCase.menuName, testCase.optionName, false);
244+
ASSERT_EQ(testCase.expectedID, foundMenuId);
18245
}
246+
19247

248+
INSTANTIATE_TEST_CASE_P(findPluginMenuCommand, MenuManagerFindPluginCommandTest,
249+
::testing::Values(MenuTestCase(L"XML Tools", L"About", MENUID_XMLTOOLS_ABOUT), // First plugin, last option
250+
MenuTestCase(L"Second Plugin", L"About", MENUID_SECONDPLUGIN_ABOUT), // Second plugin, repeated option name from other plugin
251+
MenuTestCase(L"XML Tools", L"Recent 1", MENUID_XMLTOOLS_RECENT_1), // First plugin, repeated option name from main menu
252+
MenuTestCase(L"Second Plugin", L"Recent 1", MENUID_SECONDPLUGIN_RECENT_1), // Second plugin, sub menu option
253+
MenuTestCase(L"Second Plugin", L"Recent 2", MENUID_SECONDPLUGIN_RECENT_2), // Second plugin, sub menu option
254+
MenuTestCase(L"Second Plugin", L"Not exists", 0), // Plugin option doesn't exist
255+
MenuTestCase(L"New Plugin", L"Open", 0) // Plugin doesn't exist
256+
));
257+
20258
}

PythonScript/src/MenuManager.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ class MenuManager
2929
typedef void(*runScriptFunc)(const char *, bool, HANDLE, bool);
3030

3131
static MenuManager* create(HWND hNotepad, HINSTANCE hInst, runScriptFunc runScript);
32+
33+
/** Destroys the static instance. Must be recreated with create() after usage.
34+
* Designed for use in the tests
35+
*/
36+
static void destroyForTests()
37+
{
38+
delete s_menuManager;
39+
s_menuManager = NULL;
40+
};
41+
3242
static MenuManager* getInstance();
3343
static void deleteInstance();
3444

0 commit comments

Comments
 (0)