You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
512 lines
14 KiB
512 lines
14 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: tutils.cxx
|
|
//
|
|
// Contents: Generic utilities for tests
|
|
//
|
|
// History: 06-Aug-93 DrewB Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.cxx"
|
|
#pragma hdrstop
|
|
|
|
static BOOL fExitOnFail = TRUE;
|
|
|
|
BOOL GetExitOnFail(void)
|
|
{
|
|
return fExitOnFail;
|
|
}
|
|
|
|
void SetExitOnFail(BOOL set)
|
|
{
|
|
fExitOnFail = set;
|
|
}
|
|
|
|
// Print out an error message and terminate
|
|
void Fail(char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
|
|
args = va_start(args, fmt);
|
|
fprintf(stderr, "** Fatal error **: ");
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
EndTest(1);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
SCODE sc;
|
|
char *text;
|
|
} StatusCodeText;
|
|
|
|
static StatusCodeText scodes[] =
|
|
{
|
|
S_OK, "S_OK",
|
|
S_FALSE, "S_FALSE",
|
|
STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
|
|
STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
|
|
STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND",
|
|
STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
|
|
STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
|
|
STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
|
|
STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
|
|
STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
|
|
STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
|
|
STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED",
|
|
STG_E_SEEKERROR, "STG_E_SEEKERROR",
|
|
STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
|
|
STG_E_READFAULT, "STG_E_READFAULT",
|
|
STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION",
|
|
STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
|
|
STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
|
|
STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
|
|
STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
|
|
STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
|
|
STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
|
|
STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
|
|
STG_E_UNKNOWN, "STG_E_UNKNOWN",
|
|
STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
|
|
STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
|
|
STG_E_INUSE, "STG_E_INUSE",
|
|
STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
|
|
STG_E_REVERTED, "STG_E_REVERTED",
|
|
STG_E_CANTSAVE, "STG_E_CANTSAVE",
|
|
STG_E_OLDFORMAT, "STG_E_OLDFORMAT",
|
|
STG_E_OLDDLL, "STG_E_OLDDLL",
|
|
STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED",
|
|
STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE",
|
|
STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS",
|
|
STG_S_CONVERTED, "STG_S_CONVERTED"
|
|
};
|
|
#define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
|
|
|
|
// Convert a status code to text
|
|
char *ScText(SCODE sc)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i<NSCODETEXT; i++)
|
|
if (scodes[i].sc == sc)
|
|
return scodes[i].text;
|
|
return "<Unknown SCODE>";
|
|
}
|
|
|
|
// Output a call result and check for failure
|
|
HRESULT Result(HRESULT hr, char *fmt, ...)
|
|
{
|
|
SCODE sc;
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vprintf(fmt, args);
|
|
va_end(args);
|
|
sc = GetScode(hr);
|
|
printf(" - %s (0x%lX)\n", ScText(sc), sc);
|
|
if (FAILED(sc) && fExitOnFail)
|
|
Fail("Unexpected call failure\n");
|
|
return hr;
|
|
}
|
|
|
|
// Perform Result() when the expectation is failure
|
|
HRESULT IllResult(HRESULT hr, char *fmt, ...)
|
|
{
|
|
SCODE sc;
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vprintf(fmt, args);
|
|
va_end(args);
|
|
sc = GetScode(hr);
|
|
printf(" - %s (0x%lX)\n", ScText(sc), sc);
|
|
if (SUCCEEDED(sc) && fExitOnFail)
|
|
Fail("Unexpected call success\n");
|
|
return hr;
|
|
}
|
|
|
|
char *TcsText(TCHAR *ptcs)
|
|
{
|
|
static char buf[256];
|
|
|
|
TTOA(ptcs, buf, 256);
|
|
return buf;
|
|
}
|
|
|
|
char *FileTimeText(FILETIME *pft)
|
|
{
|
|
static char buf[80];
|
|
struct tm ctm;
|
|
#ifndef FLAT
|
|
WORD dosdate, dostime;
|
|
|
|
if (CoFileTimeToDosDateTime(pft, &dosdate, &dostime))
|
|
{
|
|
ctm.tm_sec = (dostime & 31)*2;
|
|
ctm.tm_min = (dostime >> 5) & 63;
|
|
ctm.tm_hour = dostime >> 11;
|
|
ctm.tm_mday = dosdate & 31;
|
|
ctm.tm_mon = ((dosdate >> 5) & 15)-1;
|
|
ctm.tm_year = (dosdate >> 9)+80;
|
|
ctm.tm_wday = 0;
|
|
#else
|
|
SYSTEMTIME st;
|
|
|
|
if (FileTimeToSystemTime(pft, &st))
|
|
{
|
|
ctm.tm_sec = st.wSecond;
|
|
ctm.tm_min = st.wMinute;
|
|
ctm.tm_hour = st.wHour;
|
|
ctm.tm_mday = st.wDay;
|
|
ctm.tm_mon = st.wMonth-1;
|
|
ctm.tm_year = st.wYear-1900;
|
|
ctm.tm_wday = st.wDayOfWeek;
|
|
#endif
|
|
ctm.tm_yday = 0;
|
|
ctm.tm_isdst = 0;
|
|
strcpy(buf, asctime(&ctm));
|
|
buf[strlen(buf)-1] = 0;
|
|
}
|
|
else
|
|
sprintf(buf, "<FILETIME %08lX:%08lX>", pft->dwHighDateTime,
|
|
pft->dwLowDateTime);
|
|
return buf;
|
|
}
|
|
|
|
#pragma pack(1)
|
|
struct SplitGuid
|
|
{
|
|
DWORD dw1;
|
|
WORD w1;
|
|
WORD w2;
|
|
BYTE b[8];
|
|
};
|
|
#pragma pack()
|
|
|
|
char *GuidText(GUID *pguid)
|
|
{
|
|
static char buf[39];
|
|
SplitGuid *psg = (SplitGuid *)pguid;
|
|
|
|
sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
|
psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
|
|
psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
|
|
return buf;
|
|
}
|
|
|
|
#define CROW 16
|
|
|
|
void BinText(ULONG cbSize, BYTE *pb)
|
|
{
|
|
ULONG cb, i;
|
|
|
|
while (cbSize > 0)
|
|
{
|
|
cb = min(CROW, cbSize);
|
|
cbSize -= cb;
|
|
for (i = 0; i<cb; i++)
|
|
printf(" %02X", pb[i]);
|
|
for (i = cb; i<CROW; i++)
|
|
printf(" ");
|
|
printf(" '");
|
|
for (i = 0; i<cb; i++)
|
|
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
|
|
putchar(pb[i]);
|
|
else
|
|
putchar('.');
|
|
pb += cb;
|
|
printf("'\n");
|
|
}
|
|
}
|
|
|
|
TCHAR *TestFile(TCHAR *ptcsName, char *pszFile)
|
|
{
|
|
char achFn[MAX_PATH];
|
|
char *dir, *file;
|
|
int len;
|
|
|
|
dir = getenv("DFDATA");
|
|
if (dir)
|
|
strcpy(achFn, dir);
|
|
else
|
|
strcpy(achFn, ".");
|
|
len = strlen(achFn);
|
|
if (achFn[len-1] != '\\')
|
|
achFn[len++] = '\\';
|
|
|
|
if (pszFile)
|
|
{
|
|
strcpy(achFn+len, pszFile);
|
|
}
|
|
else
|
|
{
|
|
file = getenv("DFFILE");
|
|
if (file)
|
|
strcpy(achFn+len, file);
|
|
else
|
|
strcpy(achFn+len, "TEST.DFL");
|
|
}
|
|
|
|
ATOT(achFn, ptcsName, MAX_PATH);
|
|
return ptcsName+len;
|
|
}
|
|
|
|
#if WIN32 == 300
|
|
char *TestFormat(DWORD *pdwFmt, DWORD *pgrfMode)
|
|
{
|
|
char *fmt;
|
|
|
|
fmt = getenv("STGFMT");
|
|
if (fmt == NULL || !strcmp(fmt, "doc"))
|
|
{
|
|
fmt = "document";
|
|
*pdwFmt = STGFMT_DOCUMENT;
|
|
}
|
|
else if (!strcmp(fmt, "file"))
|
|
{
|
|
fmt = "file";
|
|
*pdwFmt = STGFMT_FILE;
|
|
}
|
|
else
|
|
{
|
|
fmt = "directory";
|
|
*pdwFmt = STGFMT_DIRECTORY;
|
|
*pgrfMode &= ~STGM_CREATE;
|
|
}
|
|
return fmt;
|
|
}
|
|
#endif
|
|
|
|
BOOL CompareStatStg(STATSTG *pstat1, STATSTG *pstat2)
|
|
{
|
|
if (wcscmp(pstat1->pwcsName, pstat2->pwcsName) != 0)
|
|
{
|
|
printf("Names compared wrong: %ws and %ws\n",
|
|
pstat1->pwcsName, pstat2->pwcsName);
|
|
return FALSE;
|
|
}
|
|
if (pstat1->type != pstat2->type)
|
|
{
|
|
printf("Types compares wrong on %ws and %ws: %lu and %lu\n",
|
|
pstat1->pwcsName,
|
|
pstat2->pwcsName,
|
|
pstat2->type,
|
|
pstat2->type);
|
|
|
|
return FALSE;
|
|
}
|
|
if (!IsEqualIID(pstat1->clsid, pstat2->clsid))
|
|
{
|
|
printf("Class IDs for %ws and %ws compared bad\n",
|
|
pstat1->pwcsName,
|
|
pstat2->pwcsName);
|
|
return FALSE;
|
|
}
|
|
if (pstat1->type == STGTY_STREAM)
|
|
{
|
|
if ((pstat1->cbSize).QuadPart != (pstat2->cbSize).QuadPart)
|
|
{
|
|
printf("Sizes for %ws and %ws compared bad: %lu and %lu\n",
|
|
pstat1->pwcsName,
|
|
pstat2->pwcsName,
|
|
(pstat1->cbSize).LowPart,
|
|
(pstat2->cbSize).LowPart);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
//Also check statebits and timestamps?
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CompareStreams(IStream *pstm1, IStream *pstm2)
|
|
{
|
|
const ULONG BUFSIZE = 4096;
|
|
BYTE buffer1[BUFSIZE];
|
|
BYTE buffer2[BUFSIZE];
|
|
ULONG cbRead1;
|
|
ULONG cbRead2;
|
|
STATSTG stat1;
|
|
STATSTG stat2;
|
|
LARGE_INTEGER li;
|
|
li.QuadPart = 0;
|
|
|
|
pstm1->Seek(li, STREAM_SEEK_SET, NULL);
|
|
pstm2->Seek(li, STREAM_SEEK_SET, NULL);
|
|
|
|
do
|
|
{
|
|
SCODE sc;
|
|
sc = pstm1->Read(buffer1, BUFSIZE, &cbRead1);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("Read failed with %lx\n", sc);
|
|
return FALSE;
|
|
}
|
|
sc = pstm2->Read(buffer2, BUFSIZE, &cbRead2);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("Read failed with %lx\n", sc);
|
|
return FALSE;
|
|
}
|
|
if ((cbRead1 != cbRead2) || (memcmp(buffer1, buffer2, cbRead1) != 0))
|
|
{
|
|
if (cbRead1 != cbRead2)
|
|
{
|
|
printf("Stream compare returned different bytes read: %lu and %lu\n",
|
|
cbRead1,
|
|
cbRead2);
|
|
}
|
|
else
|
|
{
|
|
printf("Data mismatch.\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (cbRead1 == BUFSIZE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CompareStorages(IStorage *pstg1, IStorage *pstg2)
|
|
{
|
|
SCODE sc1, sc2, sc;
|
|
IStorage *pstgChild1, *pstgChild2;
|
|
IStream *pstmChild1, *pstmChild2;
|
|
IEnumSTATSTG *penum1, *penum2;
|
|
STATSTG stat1, stat2;
|
|
|
|
pstg1->EnumElements(0, 0, 0, &penum1);
|
|
pstg2->EnumElements(0, 0, 0, &penum2);
|
|
|
|
do
|
|
{
|
|
ULONG celtFetched1, celtFetched2;
|
|
|
|
sc1 = penum1->Next(1, &stat1, &celtFetched1);
|
|
if (FAILED(sc1))
|
|
{
|
|
printf("EnumElements 1 failed with %lx\n", sc1);
|
|
return FALSE;
|
|
}
|
|
sc2 = penum2->Next(1, &stat2, &celtFetched2);
|
|
if (FAILED(sc2) || (celtFetched1 != celtFetched2) || (sc1 != sc2))
|
|
{
|
|
if (FAILED(sc2))
|
|
{
|
|
printf("EnumElements 2 failed with %lx\n", sc2);
|
|
}
|
|
else
|
|
{
|
|
printf("Return code mismatch: %lx and %lx\n", sc1, sc2);
|
|
}
|
|
return FALSE;
|
|
}
|
|
if (celtFetched1 == 0)
|
|
{
|
|
//We're done.
|
|
return TRUE;
|
|
}
|
|
|
|
if (!CompareStatStg(&stat1, &stat2))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//Items have compared OK so far. Now compare contents.
|
|
if (stat1.type == STGTY_STREAM)
|
|
{
|
|
sc = pstg1->OpenStream(stat1.pwcsName,
|
|
0,
|
|
STGM_DIRECT |
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
0,
|
|
&pstmChild1);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("OpenStream on pstg1 for %ws failed with %lx\n",
|
|
stat1.pwcsName,
|
|
sc);
|
|
return FALSE;
|
|
}
|
|
sc = pstg2->OpenStream(stat2.pwcsName,
|
|
0,
|
|
STGM_DIRECT |
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
0,
|
|
&pstmChild2);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("OpenStream on pstg2 for %ws failed with %lx\n",
|
|
stat2.pwcsName,
|
|
sc);
|
|
return FALSE;
|
|
}
|
|
if (!CompareStreams(pstmChild1, pstmChild2))
|
|
{
|
|
printf("Stream compare on %ws and %ws failed.\n",
|
|
stat1.pwcsName,
|
|
stat2.pwcsName);
|
|
return FALSE;
|
|
}
|
|
pstmChild1->Release();
|
|
pstmChild2->Release();
|
|
}
|
|
else
|
|
{
|
|
//Compare storages
|
|
sc = pstg1->OpenStorage(stat1.pwcsName,
|
|
NULL,
|
|
STGM_DIRECT | STGM_READ |
|
|
STGM_SHARE_EXCLUSIVE,
|
|
NULL,
|
|
0,
|
|
&pstgChild1);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("OpenStorage on pstg1 for %ws failed with %lx\n",
|
|
stat1.pwcsName,
|
|
sc);
|
|
return FALSE;
|
|
}
|
|
|
|
sc = pstg2->OpenStorage(stat2.pwcsName,
|
|
NULL,
|
|
STGM_DIRECT | STGM_READ |
|
|
STGM_SHARE_EXCLUSIVE,
|
|
NULL,
|
|
0,
|
|
&pstgChild2);
|
|
if (FAILED(sc))
|
|
{
|
|
printf("OpenStorage on pstg2 for %ws failed with %lx\n",
|
|
stat2.pwcsName,
|
|
sc);
|
|
return FALSE;
|
|
}
|
|
if (!CompareStorages(pstgChild1, pstgChild2))
|
|
{
|
|
printf("CompareStorages failed for %ws and %ws\n",
|
|
stat1.pwcsName,
|
|
stat2.pwcsName);
|
|
return FALSE;
|
|
}
|
|
pstgChild1->Release();
|
|
pstgChild2->Release();
|
|
}
|
|
|
|
//printf("Object %ws compared OK.\n", stat1.pwcsName);
|
|
CoTaskMemFree(stat1.pwcsName);
|
|
CoTaskMemFree(stat2.pwcsName);
|
|
|
|
} while (sc1 != S_FALSE);
|
|
|
|
return TRUE;
|
|
}
|