/*++

Copyright (c) 1991-1993 Microsoft Corporation

Module Name:

    TestSrv.c

Abstract:

    This module contains routines to test the RpcXlate server code.

Author:

    John Rogers (JohnRo) 03-May-1991

Environment:

    Portable to any flat, 32-bit environment.  (Uses Win32 typedefs.)
    Requires ANSI C extensions: slash-slash comments, long external names.

Revision History:

    03-May-1991 JohnRo
        Created.
    11-May-1991 JohnRo
        Added server level 402 and 403 tests.  Deleted bogus share stuff.
        Fixed bug with disk enum tests.
    15-May-1991 JohnRo
        Added native vs. RAP handling.
    04-Jun-1991 JohnRo
        Added RxNetSetServerInfo() tests.
        Allow unexpected server type bits.
        Changed FORMAT_POINTER to FORMAT_LPVOID for maximum portability.
        Added handling of sv403_autopath.
        Use TEXT() macro for UNICODE constant strings.
        Random other cleanup.
    13-Jun-1991 JohnRo
        Use DLL stubs for NetServerDiskEnum, NetServerSetInfo, NetServerGetInfo.
        Added more NetServerSetInfo() tests.
        Moved DisplayServerInfo() to NetLib.
    10-Jul-1991 JohnRo
        Added IF_DEBUG() support.
    24-Jul-1991 JohnRo
        More NetServerDiskEnum tests.
    13-Sep-1991 JohnRo
        Made changes as suggested by PC-LINT.
    25-Sep-1991 JohnRo
        Working toward UNICODE.  Fixed MIPS build problems.
    07-Oct-1991 JohnRo
        More work toward UNICODE.
    25-Oct-1991 JohnRo
        Quiet more debug output.
        Made changes suggested by PC-LINT.
    23-Sep-1992 JohnRo
        RAID 5373: server manager: _access violation changing downlevel comment.
        Finished implementing SetComment().
        Added user-mode option.
        Fixed UNICODE bugs
        Pass transport name to RxNetServerEnum().
    26-Oct-1992 JohnRo
        Allow runs against NT servers (which don't support level 402, etc).
        Domain name is optional to TestServer() and TestServerEnum().
    28-Oct-1992 JohnRo
        Use RxTestIsAccessDenied().
    10-Nov-1992 JohnRo
        Test using NetServerEnum instead of RxNetServerEnum.
    10-Dec-1992 JohnRo
        PC-LINT 5.0 found a bug (uninitialized ptr in set info test).
        Made other changes suggested by PC-LINT 5.0
    09-Feb-1993 JohnRo
        In server enum test, make sure null bufptr if success and 0 entries.
        Moved RAP tests into another routine: TestRap().
        Use NetpKdPrint() where possible.
    23-Feb-1993 JohnRo
        Added support for continuing on error.
    03-May-1993 JohnRo
        Windows for WorkGroups (WFW) seems to not think it is in a domain, so
        don't require that passing NetServerEnum() a domain name work.
        Also, WFW seems do not support some NetServerGetInfo() info levels.
        Fixed memory leak in TestServerSetInfo().
    02-Jun-1993 JohnRo
        NT's NetServerEnum2 might return ERROR_REQ_NOT_ACCEP.
    07-Jun-1993 JohnRo
        RAID 12484: Changed to include "-" in server comment.
    21-Jun-1993 JohnRo
        Pass buffer size to TestServerEnum too.
    29-Jun-1993 JohnRo
        Use assert() instead of NetpAssert(), for better use on free builds.
    29-Jun-1993 JohnRo
        NT generates ERROR_INVALID_PARAMETER instead of ERROR_INVALID_LEVEL
        sometimes; close enough.
    29-Jun-1993 JohnRo
        Use TestAssert() (which may allow continue-on-error).
    23-Jul-1993 JohnRo
        NetServerEnum() still doesn't quite play by the rules on NT.

--*/

// These must be included first:

#define NOMINMAX        // avoid stdib.h warnings.
#include <windef.h>     // IN, DWORD, etc.
#include <lmcons.h>     // MAXCOMMETNSZ, NET_API_STATUS.

// These may be included in any order:

#include <lmapibuf.h>   // NetApiBufferFree().
#include <lmserver.h>   // SERVER_INFO_100, SV_TYPE_ equates, etc.
#include <netdebug.h>   // DBGSTATIC, FORMAT_LPVOID, NetpDbg etc.
#include <rxtest.h>     // IF_DEBUG(), my prototype, TestAssert(), etc.
#include <tstr.h>       // STRLEN(), ULTOA().
#include <winerror.h>   // NO_ERROR, etc.


DBGSTATIC VOID
DisplayDiskEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN LPTSTR Info
    );

DBGSTATIC VOID
DisplayServerEnumInfo(
    IN DWORD Level,
    IN LPVOID Array,
    IN DWORD EntryCount,
    IN DWORD EntryFixedSize
    );

DBGSTATIC VOID
SetComment(
    OUT LPTSTR NewComment,
    IN LPTSTR Text,
    IN DWORD Level
    );

DBGSTATIC VOID
TestServerDiskEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN DWORD PrefMaxSize,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    );

DBGSTATIC VOID
TestServerEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD  Level,
    IN DWORD  BufferSize,
    IN DWORD  Type,
    IN LPTSTR Domain OPTIONAL,
    IN DWORD  FixedEntrySize
    );

DBGSTATIC VOID
TestServerGetInfo(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN BOOL PossibleInvalidLevel,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    );

DBGSTATIC VOID
TestServerSetInfo(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    );


VOID
TestServer(
    IN LPTSTR UncServerName OPTIONAL,
    IN LPTSTR DomainName OPTIONAL,
    IN DWORD  BufferSize,
    IN BOOL   OrdinaryUserOnly
    )
{
    IF_DEBUG(SERVER) {
        NetpKdPrint((
                "\nTestServer: first test beginning, buffer size is "
                FORMAT_DWORD "...\n",
                BufferSize ));
    }

    // See if any LMX servers out there.
    TestServerEnum(
            UncServerName,
            100,
            BufferSize,
            SV_TYPE_XENIX_SERVER,
            DomainName,
            sizeof(SERVER_INFO_100));

    //
    // Try NetServerEnum w/o domain name.
    // We'll get to other tests of this below.
    //
    TestServerEnum(
            UncServerName,
            100,
            BufferSize,
            SV_TYPE_ALL,
            NULL,                  // no domain name
            sizeof(SERVER_INFO_100));

    TestServerEnum(
            UncServerName,
            101,
            BufferSize,
            SV_TYPE_ALL,
            NULL,                  // no domain name
            sizeof(SERVER_INFO_101));

    //
    // NetServerSetInfo tests...
    //

    // Try giving all fields in info level 102.
    TestServerSetInfo(
            UncServerName,
            102,
            OrdinaryUserOnly,
            NO_ERROR );

#if 0
    // BUGBUG: downlevel and NT disagree about setinfo with just one string.
    // Try just one string parm.
    TestServerSetInfo(
            UncServerName,
            PARMNUM_BASE_INFOLEVEL + SV_COMMENT_PARMNUM,
            OrdinaryUserOnly,
            NO_ERROR );
#endif

    // Try bad info level.
    TestServerSetInfo(
            UncServerName,
            987,
            OrdinaryUserOnly,
            ERROR_INVALID_LEVEL );

    // Try giving all fields.
    TestServerSetInfo(
            UncServerName,
            101,
            OrdinaryUserOnly,
            NO_ERROR );

    // Try one numeric parm.
    TestServerSetInfo(
            UncServerName,
            PARMNUM_BASE_INFOLEVEL + SV_ANNOUNCE_PARMNUM,
            OrdinaryUserOnly,
            NO_ERROR );

    //
    // NetServerDiskEnum tests...
    //
    TestServerDiskEnum( UncServerName, 0, 2048,
            OrdinaryUserOnly,
            NO_ERROR );  // large enuf.

    TestServerDiskEnum( UncServerName, (DWORD)(-1), 2048,
            OrdinaryUserOnly,
            ERROR_INVALID_LEVEL );

    TestServerDiskEnum( UncServerName, 0, 2,
            OrdinaryUserOnly,
            NO_ERROR );  // too small, ok.

    TestServerDiskEnum( UncServerName, 0, 2048,
            OrdinaryUserOnly,
            NO_ERROR );  // large enuf.

    //
    // NetServerGetInfo tests...
    //

    TestServerGetInfo(
            UncServerName,
            987,                        // info level (invalid)
            TRUE,                       // yes, possible invalid level.
            OrdinaryUserOnly,
            ERROR_INVALID_LEVEL );

    TestServerGetInfo(
            UncServerName,
            100,                        // info level
            TRUE,                       // yes, possible invalid level.
            OrdinaryUserOnly,
            NO_ERROR );

    TestServerGetInfo(
            UncServerName,
            101,                        // info level
            FALSE,                      // no, not possible invalid level.
            OrdinaryUserOnly,
            NO_ERROR );

    TestServerGetInfo(
            UncServerName,
            102,                        // info level
            TRUE,                       // yes, possible invalid level
                                        // (WFW does not support level 2).
            OrdinaryUserOnly,
            NO_ERROR );

    TestServerGetInfo(
            UncServerName,
            402,                        // info level
            TRUE,                       // yes, possible invalid level.
            OrdinaryUserOnly,
            NO_ERROR );

    TestServerGetInfo(
            UncServerName,
            403,                        // info level
            TRUE,                       // yes, possible invalid level.
            OrdinaryUserOnly,
            NO_ERROR );

    //
    // Test NetServerEnum...
    // Note that these may fail on a Winball server (can't give domain name).
    //
    TestServerEnum(
            UncServerName,
            101,
            BufferSize,
            SV_TYPE_TIME_SOURCE,
            DomainName,
            sizeof(SERVER_INFO_101));
    TestServerEnum(
            UncServerName,
            100,
            BufferSize,
            SV_TYPE_ALL,
            DomainName,
            sizeof(SERVER_INFO_100));
    TestServerEnum(
            UncServerName,
            101,
            BufferSize,
            SV_TYPE_ALL,
            DomainName,
            sizeof(SERVER_INFO_101));
    TestServerEnum(
            UncServerName,
            101,
            BufferSize,
            SV_TYPE_PRINTQ_SERVER,
            DomainName,
            sizeof(SERVER_INFO_101));

    // BUGBUG: Add more tests here.

} // TestServer


DBGSTATIC VOID
TestServerDiskEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN DWORD PrefMaxSize,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    )
{
    LPTSTR         DiskEnumInfo = NULL;
    DWORD          EntriesRead = 150;
    NET_API_STATUS Status;
    DWORD          TotalEntries = 75;

    IF_DEBUG(SERVER) {
        NetpKdPrint(( "\nTestServerDiskEnum: trying NetServerDiskEnum...\n" ));
    }
    Status = NetServerDiskEnum(
            UncServerName,
            Level,                      // level
            /*lint -e530 */  // (We know variable isn't initialized.)
            (LPBYTE *) (LPVOID *) & DiskEnumInfo,
            /*lint +e530 */  // (Resume uninitialized variable checking.)
            PrefMaxSize,
            & EntriesRead,
            & TotalEntries,
            NULL);                      // no resume handle

    IF_DEBUG(SERVER) {
        NetpKdPrint(( "TestServerDiskEnum: back from NetServerDiskEnum, stat="
                FORMAT_API_STATUS "\n", Status ));
        NetpKdPrint(( INDENT "entries read=" FORMAT_DWORD
                ", total=" FORMAT_DWORD "\n", EntriesRead, TotalEntries ));
    }
    if (OrdinaryUserOnly && RxTestIsAccessDenied( Status ) ) {
        goto Cleanup;
    } else if (Status == ERROR_NOT_SUPPORTED) {
        goto Cleanup;  // WFW does not implement this API.
    } else if (Status != ExpectStatus) {
        NetpKdPrint(( "TestServerDiskEnum: NetServerDiskEnum failed, stat="
                FORMAT_API_STATUS "\n", Status ));
        FailGotWrongStatus( "NetServerDiskEnum", ExpectStatus, Status );
        goto Cleanup;  // if we don't exit on error, clean up this one...

    }
    if (Status != NO_ERROR) {
        goto Cleanup;  // if we don't exit on error, clean up this one...
    }
    TestAssert(EntriesRead <= TotalEntries);
    if (DiskEnumInfo == NULL) {
        FailApi( "NetServerDiskEnum returned null ptr!\n" );
        goto Cleanup;  // if we don't exit on error, clean up this one...
    }
    IF_DEBUG(SERVER) {
        DisplayDiskEnum(
                UncServerName,
                0,                                  // level
                DiskEnumInfo);
    }

Cleanup:
    if (DiskEnumInfo != NULL) {
        Status = NetApiBufferFree(DiskEnumInfo);
        if (Status != NO_ERROR) {
            FailGotWrongStatus(
                    "NetApiBufferFree(after NetServerDiskEnum)",
                    NO_ERROR,  // expected status
                    Status );
        }
    }
        

} // TestServerDiskEnum


DBGSTATIC VOID
TestServerGetInfo(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN BOOL PossibleInvalidLevel,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    )
{
    LPVOID         Info = NULL;
    NET_API_STATUS Status;

    IF_DEBUG(SERVER) {
        NetpKdPrint(( "\nTestServerGetInfo: trying level " FORMAT_DWORD ".\n",
             Level ));
    }
    Status = NetServerGetInfo(
            UncServerName,              // server name
            Level,                      // info level
            (LPBYTE *) & Info);
    IF_DEBUG(SERVER) {
        NetpKdPrint(( "TestServerGetInfo: back from NetServerGetInfo, Status="
                FORMAT_API_STATUS ".\n", Status ));
        NetpKdPrint(( "TestServerGetInfo: NetServerGetInfo alloc'ed buffer at "
                FORMAT_LPVOID ".\n", (LPVOID) Info ));
    }

    if (OrdinaryUserOnly && RxTestIsAccessDenied( Status ) ) {
        goto Cleanup;
    } else if ( PossibleInvalidLevel && (Status==ERROR_INVALID_LEVEL) ) {
        TestAssert( Info == NULL );
        goto Cleanup;
    } else if (Status != ExpectStatus) {
        FailGotWrongStatus( "NetServerGetInfo", ExpectStatus, Status );
        goto Cleanup;  // if we don't exit on error, clean up this one...
    }
    if (Status == NO_ERROR) {
        TestAssert(Info != NULL);
        IF_DEBUG(SERVER) {
            NetpDbgDisplayServerInfo(Level, Info);
        }
    }
Cleanup:
    if (Info != NULL) {
        IF_DEBUG(SERVER) {
            NetpKdPrint(( "TestServerGetInfo: Freeing buffer...\n" ));
        }
        Status = NetApiBufferFree(Info);
        if (Status != NO_ERROR) {
            FailGotWrongStatus(
                    "NetApiBufferFree(after NetServerGetInfo)",
                    NO_ERROR,  // expected status
                    Status );
        }
    }
} // TestServerGetInfo


DBGSTATIC VOID
TestServerSetInfo(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN BOOL OrdinaryUserOnly,
    IN NET_API_STATUS ExpectStatus
    )
{
    LPVOID OldInfo = NULL;
    TCHAR NewComment[MAXCOMMENTSZ+1];
    LPTSTR NewCommentPtr = &NewComment[0];
    LPVOID NewInfo = NULL;
    DWORD ParmError;
    LPSERVER_INFO_102 psv102;
    NET_API_STATUS Status;
    DWORD TempDword;

    switch (Level) {
    case 101 : /*FALLTHROUGH*/
    case 102 :
        IF_DEBUG(SERVER) {
            NetpKdPrint(( "\nTestServerSetInfo: getting old version...\n" ));
        }
        Status = NetServerGetInfo(
                UncServerName,
                Level,
                (LPBYTE *) (LPVOID) & OldInfo);
        IF_DEBUG(SERVER) {
            NetpKdPrint(( "TestServerSetInfo: back from NetServerGetInfo, "
                    "Status=" FORMAT_API_STATUS ".\n", Status ));
        }

        if (OrdinaryUserOnly && RxTestIsAccessDenied( Status ) ) {
            return;
        } else if (Status == ERROR_INVALID_LEVEL) {
            return;   // WFW does not implement this info level.
        } else if (Status != ExpectStatus) {
            FailGotWrongStatus(
                    "TestServerSetInfo: (getting old info)",
                    ExpectStatus,
                    Status );
        }
        if (Status != NO_ERROR) {
            // Couldn't get old struct, so don't try setting...
            return;
        }
        IF_DEBUG(SERVER) {
            NetpDbgDisplayServerInfo( Level, OldInfo );
            NetpKdPrint(( "TestServerSetInfo: changing ALL fields...\n" ));
        }
        psv102 = (LPSERVER_INFO_102) OldInfo;

        SetComment(
                NewComment,
                (LPTSTR) TEXT("Windows-NT changed by set all level "),
                Level );
        psv102->sv102_comment = NewComment;
        NewInfo = OldInfo;

        IF_DEBUG(SERVER) {
            NetpDbgDisplayServerInfo( Level, NewInfo );
        }
        break;

    case PARMNUM_BASE_INFOLEVEL + SV_ANNOUNCE_PARMNUM :
        TempDword = 58;
        NewInfo = (LPVOID) & TempDword;
        IF_DEBUG(SERVER) {
            NetpKdPrint((
                    "TestServerSetInfo: changing announce time only...\n" ));
        }
        break;

#if 0
    // BUGBUG: downlevel and NT disagree about setinfo with just one string.
    case PARMNUM_BASE_INFOLEVEL + SV_COMMENT_PARMNUM :
        IF_DEBUG(SERVER) {
            NetpKdPrint(( "TestServerSetInfo: changing comment only...\n" ));
        }
        SetComment(
                NewComment,
                (LPTSTR) TEXT("Windows-NT changed by set parmnum level "),
                Level );
        NewInfo = NewCommentPtr;
        break;
#endif

    default :
        // Caller is presumably just doing a bad info level test.  OK.
        // NewInfo has to point at something, why not itself?
        NewInfo = & NewInfo;
        break;
    }

    Status = NetServerSetInfo (
            UncServerName,
            Level,
            NewInfo,
            & ParmError);

    IF_DEBUG(SERVER) {
        NetpKdPrint(( "TestServerSetInfo: back from NetServerSetInfo("
                "level " FORMAT_DWORD ", Status="
                FORMAT_API_STATUS ".\n", Level, Status ));
    }

    if (OldInfo != NULL) {
        (void) NetApiBufferFree( OldInfo );
    }

    if (OrdinaryUserOnly && RxTestIsAccessDenied( Status ) ) {
        return;
    } else if (Status == ERROR_NOT_SUPPORTED) {
        return;   // WFW does not implement this API.
    } else if ( (Status==ERROR_INVALID_PARAMETER)
             && (ExpectStatus==ERROR_INVALID_LEVEL) ) {

        return;   // NT seems to generate this error; close enough.
    } else if (Status != ExpectStatus) {
        FailGotWrongStatus(
                "TestServerSetInfo: (setting...)",
                ExpectStatus,
                Status );
    }

    if (Status == NO_ERROR) {
        DWORD LevelToGet;
        if (Level < PARMNUM_BASE_INFOLEVEL) {
            LevelToGet = Level;
        } else {
            LevelToGet = 102;
        }
        IF_DEBUG(SERVER) {
            NetpKdPrint(( "\nTestServerSetInfo: getting new version (level "
                    FORMAT_DWORD ")...\n", LevelToGet ));
        }
        NewInfo = NULL;
        Status = NetServerGetInfo(
                UncServerName,
                LevelToGet,
                (LPBYTE *) (LPVOID) & NewInfo);
        TestAssert( Status == NO_ERROR );  // If we got this far...
        TestAssert( NewInfo != NULL );
        // BUGBUG;   // verify that "-" is still in place!
        IF_DEBUG(SERVER) {
            NetpDbgDisplayServerInfo( Level, NewInfo );
        }
        (void) NetApiBufferFree( NewInfo );
    }


} // TestServerSetInfo

DBGSTATIC VOID
DisplayDiskEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD Level,
    IN LPTSTR Info
    )
{
    IF_DEBUG(SERVER) {
        NetpKdPrint(( "server disk enum (level " FORMAT_DWORD ") for "
                FORMAT_LPTSTR ":\n", Level, UncServerName ));
    }
    TestAssert(Level == 0);

    while (*Info != (TCHAR)0) {
        TestAssert(Info[1] == (TCHAR)':');
        IF_DEBUG(SERVER) {
            NetpKdPrint(( INDENT  FORMAT_LPTSTR "\n", (LPTSTR) Info ));
        }
        Info += 3;
    }
} // DisplayDiskEnum


DBGSTATIC VOID
DisplayServerEnumInfo(
    IN DWORD Level,
    IN LPVOID Array,
    IN DWORD EntryCount,
    IN DWORD EntryFixedSize
    )
{
    LPBYTE CurrentEntry = Array;
    while (EntryCount >0) {
        IF_DEBUG(SERVER) {
            NetpDbgDisplayServerInfo( Level, CurrentEntry );
        }
        CurrentEntry += EntryFixedSize;
        --EntryCount;
    }
} // DisplayServerEnumInfo


DBGSTATIC VOID
TestServerEnum(
    IN LPTSTR UncServerName OPTIONAL,
    IN DWORD  Level,
    IN DWORD  BufferSize,
    IN DWORD  Type,
    IN LPTSTR Domain OPTIONAL,
    IN DWORD  FixedEntrySize
    )
{
    DWORD EntriesRead;
    LPVOID EnumArrayPtr = NULL;
    NET_API_STATUS Status;
    DWORD TotalEntries;

    IF_DEBUG(SERVER) {
        NetpKdPrint((
                "\nTestServerEnum: trying enum (level " FORMAT_DWORD "), "
                "buffer size " FORMAT_DWORD ", type " FORMAT_HEX_DWORD ", "
                "domain '" FORMAT_LPTSTR "'.\n",
                Level, BufferSize, Type,
                (Domain!=NULL) ? Domain : (LPVOID) TEXT("(none)") ));
    }
    Status = NetServerEnum (
            UncServerName,
            Level,                      // level
            (LPBYTE *) & EnumArrayPtr,  // ptr to buf (will be alloced)
            BufferSize,                 // prefered maximum length
            & EntriesRead,
            & TotalEntries,
            Type,
            Domain,
            NULL);                      // no resume handle
    IF_DEBUG(SERVER) {
        NetpKdPrint(( "TestServerEnum: back from enum, status="
                FORMAT_API_STATUS ".\n" , Status ));
        NetpKdPrint(( INDENT "alloc'ed buffer at " FORMAT_LPVOID ".\n",
                (LPVOID) EnumArrayPtr ));
        NetpKdPrint(( INDENT "entries read=" FORMAT_DWORD
                ", total=" FORMAT_DWORD "\n", EntriesRead, TotalEntries ));
    }
    if (Status == NERR_NotLocalDomain) {
        return;   // WFW seems to always return this, even if given its
                  // own workgroup name as the domain name.
    } else if (Status == ERROR_NOT_SUPPORTED) {
        return;   // WFW does not implement this API.
    } else if (Status == ERROR_REQ_NOT_ACCEP) {
        return;   // NT might return this if browser not running or wrong role.
    } else if (Status != NO_ERROR) {
        NetpKdPrint(( "TestServerEnum: NetServerEnum failed, status = "
                FORMAT_API_STATUS ".\n" , Status ));
        FailGotWrongStatus( "NetServerEnum", NO_ERROR, Status );
        goto Cleanup;  // if we don't exit on error, clean up this one...
    }
    if (EnumArrayPtr != NULL) {
        TestAssert( EntriesRead <= TotalEntries );
        // TestAssert( EntriesRead != 0 );   // BUGBUG: NT fails this!
        // TestAssert( TotalEntries != 0 );
        IF_DEBUG(SERVER) {
            if (EntriesRead != 0) {
                DisplayServerEnumInfo(
                        Level,
                        EnumArrayPtr,
                        EntriesRead,
                        FixedEntrySize);
            }
        }
    } else {
        TestAssert( EntriesRead == 0 );
        TestAssert( TotalEntries == 0 );
    }
Cleanup:
    if (EnumArrayPtr != NULL) {
        Status = NetApiBufferFree(EnumArrayPtr);
        if (Status != NO_ERROR) {
            FailGotWrongStatus(
                    "NetApiBufferFree(after NetServerEnum)",
                    NO_ERROR,  // expected status
                    Status );
        }
    }

} // TestServerEnum


DBGSTATIC VOID
SetComment(
    OUT LPTSTR NewComment,
    IN LPTSTR Text,
    IN DWORD Level
    )
{
    LPTSTR CommentEnd;

    TestAssert( NewComment != NULL );
    TestAssert( Text != NULL );
    (void) STRCPY( NewComment, Text );

    CommentEnd = NewComment + STRLEN( NewComment );
    (VOID) ULTOA(
            (unsigned long) Level,   // value to convert
            (LPVOID) CommentEnd,     // dest
            10 );                    // radix

    TestAssert( STRLEN( NewComment ) <= MAXCOMMENTSZ );

} // SetComment