[SHELL32_APITEST]
[reactos.git] / rostests / apitests / shell32 / CShellDesktop.cpp
index c11348b..5a3a0d8 100644 (file)
  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
  * PURPOSE:         Test for CShellDesktop
  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
+ *                  Mark Jansen
  */
 
 #include "shelltest.h"
 #include <atlbase.h>
 #include <atlcom.h>
 #include <strsafe.h>
+#include <ndk/rtlfuncs.h>
 
 #define NDEBUG
 #include <debug.h>
 #include <shellutils.h>
 
+
+// We would normally use S_LESSTHAN and S_GREATERTHAN, but w2k3 returns numbers like 3 and -3...
+// So instead we check on the sign bit (compare result is the low word of the hresult).
+#define SHORT_SIGN_BIT  0x8000
+
+static
+VOID
+compare_imp(IShellFolder* psf, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, HRESULT expected)
+{
+    HRESULT hr;
+    _SEH2_TRY
+    {
+        hr = psf->CompareIDs(0, pidl1, pidl2);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        winetest_ok(0, "Exception %lx!\n", _SEH2_GetExceptionCode());
+        hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
+    }
+    _SEH2_END;
+    if (expected == S_LESSTHAN)
+        winetest_ok(SUCCEEDED(hr) && (hr & SHORT_SIGN_BIT), "hr = %lx\n", hr);
+    else if (expected == S_EQUAL)
+        winetest_ok(hr == S_EQUAL, "hr = %lx\n", hr);
+    else if (expected == S_GREATERTHAN)
+        winetest_ok(SUCCEEDED(hr) && !(hr & SHORT_SIGN_BIT), "hr = %lx\n", hr);
+    else
+        winetest_ok(hr == expected, "hr = %lx\n", hr);
+}
+
+// make the winetest_ok look like it came from the line where the compare function was called, and not from inside the compare_imp function :)
+#define compare         (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : compare_imp
+
+static
+VOID
+TestCompareIDList(IShellFolder* psf)
+{
+    compare(psf, NULL, NULL, E_INVALIDARG);
+
+    CComHeapPtr<ITEMIDLIST> desktop;
+    HRESULT hr = SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, NULL, &desktop);
+    ok(hr == S_OK, "hr = %lx\n", hr);
+    compare(psf, desktop, NULL, E_INVALIDARG);
+    compare(psf, NULL, desktop, E_INVALIDARG);
+    compare(psf, desktop, desktop, S_EQUAL);
+
+    // First check the ordering of some special folders against eachother
+    CComHeapPtr<ITEMIDLIST> internet;
+    hr = SHGetFolderLocation(NULL, CSIDL_INTERNET, NULL, NULL, &internet);
+    ok(hr == S_OK, "hr = %lx\n", hr);
+    compare(psf, internet, desktop, S_LESSTHAN);
+    compare(psf, desktop, internet, S_GREATERTHAN);
+
+    CComHeapPtr<ITEMIDLIST> programs;
+    hr = SHGetFolderLocation(NULL, CSIDL_PROGRAMS, NULL, NULL, &programs);
+    ok(hr == S_OK, "hr = %lx\n", hr);
+    compare(psf, programs, desktop, S_LESSTHAN);
+    compare(psf, desktop, programs, S_GREATERTHAN);
+    compare(psf, internet, programs, S_GREATERTHAN);
+    compare(psf, programs, internet, S_LESSTHAN);
+
+    // Verify that an idlist retrieved from GetCurFolder is equal to the original one.
+    CComPtr<IPersistFolder2> persist;
+    hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &persist));
+    ok(hr == S_OK, "hr = %lx\n", hr);
+    if (hr == S_OK)
+    {
+        CComHeapPtr<ITEMIDLIST> cur;
+        hr = persist->GetCurFolder(&cur);
+        ok(hr == S_OK, "hr = %lx\n", hr);
+        compare(psf, cur, desktop, S_EQUAL);
+        compare(psf, desktop, cur, S_EQUAL);
+    }
+
+    // Compare special folders against full paths
+    CComHeapPtr<ITEMIDLIST> dir1, dir2;
+    PathToIDList(L"A:\\AAA.AAA", &dir1);
+    PathToIDList(L"A:\\ZZZ.ZZZ", &dir2);
+
+    compare(psf, dir1, desktop, S_LESSTHAN);
+    compare(psf, desktop, dir1, S_GREATERTHAN);
+    compare(psf, dir1, programs, S_LESSTHAN);
+    compare(psf, programs, dir1, S_GREATERTHAN);
+    compare(psf, dir1, dir1, S_EQUAL);
+
+    compare(psf, dir2, desktop, S_LESSTHAN);
+    compare(psf, desktop, dir2, S_GREATERTHAN);
+    compare(psf, dir2, programs, S_LESSTHAN);
+    compare(psf, programs, dir2, S_GREATERTHAN);
+    compare(psf, dir2, dir2, S_EQUAL);
+
+    CComHeapPtr<ITEMIDLIST> dir3, dir4;
+    PathToIDList(L"Z:\\AAA.AAA", &dir3);
+    PathToIDList(L"Z:\\ZZZ.ZZZ", &dir4);
+
+    compare(psf, dir3, desktop, S_LESSTHAN);
+    compare(psf, desktop, dir3, S_GREATERTHAN);
+    compare(psf, dir3, programs, S_GREATERTHAN);
+    compare(psf, programs, dir3, S_LESSTHAN);
+    compare(psf, dir3, dir3, S_EQUAL);
+
+    compare(psf, dir4, desktop, S_LESSTHAN);
+    compare(psf, desktop, dir4, S_GREATERTHAN);
+    compare(psf, dir4, programs, S_GREATERTHAN);
+    compare(psf, programs, dir4, S_LESSTHAN);
+    compare(psf, dir4, dir4, S_EQUAL);
+
+    // Now compare the paths against eachother.
+    compare(psf, dir1, dir2, S_LESSTHAN);
+    compare(psf, dir2, dir1, S_GREATERTHAN);
+
+    compare(psf, dir2, dir3, S_LESSTHAN);
+    compare(psf, dir3, dir2, S_GREATERTHAN);
+
+    compare(psf, dir3, dir4, S_LESSTHAN);
+    compare(psf, dir4, dir3, S_GREATERTHAN);
+
+    // Check that comparing desktop pidl with another one with another IShellFolder fails
+    CComPtr<IShellFolder> psf2;
+    hr = psf->BindToObject(programs, NULL, IID_IShellFolder, reinterpret_cast<void**>(&psf2));
+    ok(hr == S_OK, "Impossible to bind to Programs pidl");
+    if (hr == S_OK)
+    {
+        // Compare desktop pidl in programs scope should fail since it's relative pidl
+        compare(psf2, desktop, programs, E_INVALIDARG);
+        compare(psf2, programs, desktop, E_INVALIDARG);
+        // For the same reasons, filesystem paths can't be compared with special shell
+        // folders that don't have CFSFolder in children
+        compare(psf2, dir1, dir2, E_INVALIDARG);
+        compare(psf2, dir2, dir1, E_INVALIDARG);
+    }
+}
+
 static
 VOID
 TestShellFolder(
@@ -83,4 +218,5 @@ START_TEST(CShellDesktop)
     ok(psf == static_cast<IShellFolder *>(psf2), "Expected %p == %p\n", static_cast<PVOID>(psf), static_cast<PVOID>(psf2));
 
     TestShellFolder(psf2);
+    TestCompareIDList(psf);
 }