2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Test for SHChangeNotify
5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
11 #include "SHChangeNotify.h"
13 #define DONT_SEND 0x24242424
15 static HWND s_hwnd
= NULL
;
16 static const WCHAR s_szName
[] = L
"SHChangeNotify testcase";
17 static WCHAR s_szSubProgram
[MAX_PATH
];
19 typedef void (*ACTION
)(void);
21 typedef struct TEST_ENTRY
34 DoCreateEmptyFile(LPCWSTR pszFileName
)
36 FILE *fp
= _wfopen(pszFileName
, L
"wb");
44 ok_int(CreateDirectoryW(s_dir2
, NULL
), TRUE
);
50 ok_int(RemoveDirectoryW(s_dir2
), TRUE
);
56 ok_int(MoveFileExW(s_dir2
, s_dir3
, MOVEFILE_COPY_ALLOWED
| MOVEFILE_REPLACE_EXISTING
), TRUE
);
62 ok_int(DoCreateEmptyFile(s_file1
), TRUE
);
68 ok_int(MoveFileExW(s_file1
, s_file2
, MOVEFILE_COPY_ALLOWED
| MOVEFILE_REPLACE_EXISTING
), TRUE
);
74 ok_int(DeleteFileW(s_file2
), TRUE
);
82 ok_int(RemoveDirectoryW(s_dir3
), TRUE
);
88 BOOL ret
= RemoveDirectoryW(s_dir1
);
89 ok(ret
, "RemoveDirectoryW failed. GetLastError() == %ld\n", GetLastError());
92 static const TEST_ENTRY s_TestEntriesMode0
[] =
94 {__LINE__
, SHCNE_MKDIR
, s_dir1
, NULL
, "000100000", NULL
, s_dir1
, L
""},
95 {__LINE__
, SHCNE_MKDIR
, s_dir2
, NULL
, "000100000", NULL
, s_dir2
, L
""},
96 {__LINE__
, SHCNE_RMDIR
, s_dir2
, NULL
, "000010000", NULL
, s_dir2
, L
""},
97 {__LINE__
, SHCNE_MKDIR
, s_dir2
, NULL
, "000100000", DoAction1
, s_dir2
, L
""},
98 {__LINE__
, SHCNE_RMDIR
, s_dir2
, NULL
, "000010000", NULL
, s_dir2
, L
""},
99 {__LINE__
, SHCNE_RMDIR
, s_dir2
, NULL
, "000010000", DoAction2
, s_dir2
, L
""},
100 {__LINE__
, SHCNE_MKDIR
, s_dir2
, NULL
, "000100000", DoAction1
, s_dir2
, L
""},
101 {__LINE__
, SHCNE_RENAMEFOLDER
, s_dir2
, s_dir3
, "000000010", NULL
, s_dir2
, s_dir3
},
102 {__LINE__
, SHCNE_RENAMEFOLDER
, s_dir2
, s_dir3
, "000000010", DoAction3
, s_dir2
, s_dir3
},
103 {__LINE__
, SHCNE_CREATE
, s_file1
, NULL
, "010000000", NULL
, s_file1
, L
""},
104 {__LINE__
, SHCNE_CREATE
, s_file1
, s_file2
, "010000000", NULL
, s_file1
, s_file2
},
105 {__LINE__
, SHCNE_CREATE
, s_file1
, NULL
, "010000000", DoAction4
, s_file1
, L
""},
106 {__LINE__
, SHCNE_RENAMEITEM
, s_file1
, s_file2
, "100000000", NULL
, s_file1
, s_file2
},
107 {__LINE__
, SHCNE_RENAMEITEM
, s_file1
, s_file2
, "100000000", DoAction5
, s_file1
, s_file2
},
108 {__LINE__
, SHCNE_RENAMEITEM
, s_file1
, s_file2
, "100000000", NULL
, s_file1
, s_file2
},
109 {__LINE__
, SHCNE_UPDATEITEM
, s_file1
, NULL
, "000000100", NULL
, s_file1
, L
""},
110 {__LINE__
, SHCNE_UPDATEITEM
, s_file2
, NULL
, "000000100", NULL
, s_file2
, L
""},
111 {__LINE__
, SHCNE_UPDATEITEM
, s_file1
, s_file2
, "000000100", NULL
, s_file1
, s_file2
},
112 {__LINE__
, SHCNE_UPDATEITEM
, s_file2
, s_file1
, "000000100", NULL
, s_file2
, s_file1
},
113 {__LINE__
, SHCNE_DELETE
, s_file1
, NULL
, "001000000", NULL
, s_file1
, L
""},
114 {__LINE__
, SHCNE_DELETE
, s_file2
, NULL
, "001000000", NULL
, s_file2
, L
""},
115 {__LINE__
, SHCNE_DELETE
, s_file2
, s_file1
, "001000000", NULL
, s_file2
, s_file1
},
116 {__LINE__
, SHCNE_DELETE
, s_file1
, s_file2
, "001000000", NULL
, s_file1
, s_file2
},
117 {__LINE__
, SHCNE_DELETE
, s_file2
, NULL
, "001000000", DoAction6
, s_file2
, L
""},
118 {__LINE__
, SHCNE_DELETE
, s_file2
, NULL
, "001000000", NULL
, s_file2
, L
""},
119 {__LINE__
, SHCNE_DELETE
, s_file1
, NULL
, "001000000", NULL
, s_file1
, L
""},
120 {__LINE__
, SHCNE_UPDATEDIR
, s_file1
, NULL
, "000001000", NULL
, s_file1
, L
""},
121 {__LINE__
, SHCNE_UPDATEDIR
, s_file2
, NULL
, "000001000", NULL
, s_file2
, L
""},
122 {__LINE__
, SHCNE_UPDATEDIR
, s_file1
, s_file2
, "000001000", NULL
, s_file1
, s_file2
},
123 {__LINE__
, SHCNE_UPDATEDIR
, s_file2
, s_file1
, "000001000", NULL
, s_file2
, s_file1
},
124 {__LINE__
, SHCNE_UPDATEDIR
, s_dir1
, NULL
, "000001000", NULL
, s_dir1
, L
""},
125 {__LINE__
, SHCNE_UPDATEDIR
, s_dir2
, NULL
, "000001000", NULL
, s_dir2
, L
""},
126 {__LINE__
, SHCNE_UPDATEDIR
, s_dir1
, s_dir2
, "000001000", NULL
, s_dir1
, s_dir2
},
127 {__LINE__
, SHCNE_UPDATEDIR
, s_dir2
, s_dir1
, "000001000", NULL
, s_dir2
, s_dir1
},
128 {__LINE__
, SHCNE_RMDIR
, s_dir1
, NULL
, "000010000", NULL
, s_dir1
, L
""},
129 {__LINE__
, SHCNE_RMDIR
, s_dir2
, NULL
, "000010000", NULL
, s_dir2
, L
""},
130 {__LINE__
, SHCNE_RMDIR
, s_dir3
, NULL
, "000010000", NULL
, s_dir3
, L
""},
131 {__LINE__
, SHCNE_RMDIR
, s_dir1
, s_dir2
, "000010000", NULL
, s_dir1
, s_dir2
},
132 {__LINE__
, SHCNE_RMDIR
, s_dir1
, s_dir3
, "000010000", NULL
, s_dir1
, s_dir3
},
133 {__LINE__
, SHCNE_RMDIR
, s_dir2
, s_dir1
, "000010000", NULL
, s_dir2
, s_dir1
},
134 {__LINE__
, SHCNE_RMDIR
, s_dir2
, s_dir3
, "000010000", NULL
, s_dir2
, s_dir3
},
135 {__LINE__
, SHCNE_RMDIR
, s_dir3
, NULL
, "000010000", NULL
, s_dir3
, L
""},
136 {__LINE__
, SHCNE_RMDIR
, s_dir3
, NULL
, "000010000", DoAction7
, s_dir3
, L
""},
137 {__LINE__
, SHCNE_RMDIR
, s_dir1
, NULL
, "000010000", NULL
, s_dir1
, L
""},
138 {__LINE__
, SHCNE_RMDIR
, s_dir1
, NULL
, "000010000", DoAction8
, s_dir1
, L
""},
141 #define s_TestEntriesMode1 s_TestEntriesMode0
142 #define s_TestEntriesMode2 s_TestEntriesMode0
144 LPCSTR
PatternFromFlags(DWORD flags
)
146 static char s_buf
[TYPE_FREESPACE
+ 1 + 1];
148 for (i
= 0; i
<= TYPE_FREESPACE
; ++i
)
150 s_buf
[i
] = (char)('0' + !!(flags
& (1 << i
)));
157 DoGetClipText(LPWSTR pszPath1
, LPWSTR pszPath2
)
159 pszPath1
[0] = pszPath2
[0] = 0;
161 if (!IsClipboardFormatAvailable(CF_UNICODETEXT
))
164 if (!OpenClipboard(NULL
))
167 WCHAR szText
[MAX_PATH
* 2];
168 HGLOBAL hGlobal
= GetClipboardData(CF_UNICODETEXT
);
169 LPWSTR psz
= (LPWSTR
)GlobalLock(hGlobal
);
170 lstrcpynW(szText
, psz
, _countof(szText
));
171 GlobalUnlock(hGlobal
);
174 LPWSTR pch
= wcschr(szText
, L
'|');
179 lstrcpynW(pszPath1
, szText
, MAX_PATH
);
180 lstrcpynW(pszPath2
, pch
+ 1, MAX_PATH
);
185 DoTestEntry(const TEST_ENTRY
*entry
)
192 if (entry
->event
!= DONT_SEND
)
194 SHChangeNotify(entry
->event
, SHCNF_PATHW
| SHCNF_FLUSH
, entry
->item1
, entry
->item2
);
197 DWORD flags
= SendMessageW(s_hwnd
, WM_GET_NOTIFY_FLAGS
, 0, 0);
198 LPCSTR pattern
= PatternFromFlags(flags
);
200 ok(lstrcmpA(pattern
, entry
->pattern
) == 0, "Line %d: pattern mismatch '%s'\n", entry
->line
, pattern
);
202 SendMessageW(s_hwnd
, WM_SET_PATHS
, 0, 0);
204 WCHAR szPath1
[MAX_PATH
], szPath2
[MAX_PATH
];
205 BOOL bOK
= DoGetClipText(szPath1
, szPath2
);
207 ok(bOK
&& lstrcmpiW(entry
->path1
, szPath1
) == 0,
208 "Line %d: path1 mismatch '%S' (%d)\n", entry
->line
, szPath1
, bOK
);
210 ok(bOK
&& lstrcmpiW(entry
->path2
, szPath2
) == 0,
211 "Line %d: path2 mismatch '%S' (%d)\n", entry
->line
, szPath2
, bOK
);
213 SendMessageW(s_hwnd
, WM_CLEAR_FLAGS
, 0, 0);
221 CreateDirectoryW(s_dir1
, NULL
);
223 return PathIsDirectoryW(s_dir1
);
229 DeleteFileW(s_file1
);
230 DeleteFileW(s_file2
);
231 RemoveDirectoryW(s_dir3
);
232 RemoveDirectoryW(s_dir2
);
233 RemoveDirectoryW(s_dir1
);
235 SendMessageW(s_hwnd
, WM_COMMAND
, IDOK
, 0);
239 GetSubProgramPath(void)
241 GetModuleFileNameW(NULL
, s_szSubProgram
, _countof(s_szSubProgram
));
242 PathRemoveFileSpecW(s_szSubProgram
);
243 PathAppendW(s_szSubProgram
, L
"shell-notify.exe");
245 if (!PathFileExistsW(s_szSubProgram
))
247 PathRemoveFileSpecW(s_szSubProgram
);
248 PathAppendW(s_szSubProgram
, L
"testdata\\shell-notify.exe");
250 if (!PathFileExistsW(s_szSubProgram
))
264 skip("Unable to initialize.\n");
269 wsprintfW(szParams
, L
"%u", nMode
);
271 HINSTANCE hinst
= ShellExecuteW(NULL
, NULL
, s_szSubProgram
, szParams
, NULL
, SW_SHOWNORMAL
);
272 if ((INT_PTR
)hinst
<= 32)
274 skip("Unable to run shell-notify.exe.\n");
278 for (int i
= 0; i
< 15; ++i
)
280 s_hwnd
= FindWindowW(s_szName
, s_szName
);
289 skip("Unable to find window.\n");
298 for (size_t i
= 0; i
< _countof(s_TestEntriesMode0
); ++i
)
300 DoTestEntry(&s_TestEntriesMode0
[i
]);
307 for (int i
= 0; i
< 15; ++i
)
309 s_hwnd
= FindWindowW(s_szName
, s_szName
);
317 START_TEST(SHChangeNotify
)
319 if (!GetSubProgramPath())
321 skip("shell-notify.exe not found\n");