Sweden-Number/dlls/ntdll/tests/rtl.c

336 lines
12 KiB
C
Raw Normal View History

/* Unit test suite for Rtl* API functions
*
* Copyright 2003 Thomas Mertes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTES
* We use function pointers here as there is no import library for NTDLL on
* windows.
*/
#include <stdlib.h>
#include "winbase.h"
#include "wine/test.h"
#include "winnt.h"
#include "winnls.h"
#include "winternl.h"
/* Function ptrs for ntdll calls */
static HMODULE hntdll = 0;
static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG);
static ULONG (WINAPI *pRtlUniform)(PULONG);
static void InitFunctionPtrs(void)
{
hntdll = LoadLibraryA("ntdll.dll");
ok(hntdll != 0, "LoadLibrary failed");
if (hntdll) {
pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong");
pRtlUniform = (void *)GetProcAddress(hntdll, "RtlUniform");
} /* if */
}
static void test_RtlCompareMemoryUlong(void)
{
ULONG a[10];
ULONG result;
a[0]= 0x0123;
a[1]= 0x4567;
a[2]= 0x89ab;
a[3]= 0xcdef;
result = pRtlCompareMemoryUlong(a, 0, 0x0123);
ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %lu, expected 0\n", a, result);
result = pRtlCompareMemoryUlong(a, 3, 0x0123);
ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result);
result = pRtlCompareMemoryUlong(a, 4, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 5, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 7, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 8, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 9, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 4, 0x0127);
ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %lu, expected 0\n", a, result);
result = pRtlCompareMemoryUlong(a, 4, 0x7123);
ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %lu, expected 0\n", a, result);
result = pRtlCompareMemoryUlong(a, 16, 0x4567);
ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %lu, expected 0\n", a, result);
a[1]= 0x0123;
result = pRtlCompareMemoryUlong(a, 3, 0x0123);
ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result);
result = pRtlCompareMemoryUlong(a, 4, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 5, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 7, 0x0123);
ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result);
result = pRtlCompareMemoryUlong(a, 8, 0x0123);
ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 8\n", a, result);
result = pRtlCompareMemoryUlong(a, 9, 0x0123);
ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 8\n", a, result);
}
static void test_RtlUniform(void)
{
ULONGLONG num;
ULONG seed;
ULONG seed_bak;
ULONG expected;
ULONG result;
/*
* According to the documentation RtlUniform is using D.H. Lehmer's 1948
* algorithm. This algorithm is:
*
* seed = (seed * const_1 + const_2) % const_3;
*
* According to the documentation the random number is distributed over
* [0..MAXLONG]. Therefore const_3 is MAXLONG + 1:
*
* seed = (seed * const_1 + const_2) % (MAXLONG + 1);
*
* Because MAXLONG is 0xfffffff (which is 0x10000000 - 1) the algorithm
* can be expressed as:
*
* seed = (seed * const_1 + const_2) & MAXLONG;
*
* To find out const_2 we just call RtlUniform with seed set to 0:
*/
seed = 0;
expected = 0x7fffffc3;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0)) returns %lx, expected %lx",
result, expected);
/*
* The algorithm is now:
*
* seed = (seed * const_1 + 0x7fffffc3) & MAXLONG;
*
* To find out const_1 we can use:
*
* const_1 = RtlUniform(1) - 0x7fffffc3;
*
* If that does not work a search loop can try all possible values of
* const_1 and compare to the result to RtlUniform(1).
* This way we find out that const_1 is 0xffffffed.
*
* For seed = 1 the const_2 is 0x7fffffc4:
*/
seed = 1;
expected = seed * 0xffffffed + 0x7fffffc3 + 1;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 1)) returns %lx, expected %lx",
result, expected);
/*
* For seed = 2 the const_2 is 0x7fffffc3:
*/
seed = 2;
expected = seed * 0xffffffed + 0x7fffffc3;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 2)) returns %lx, expected %lx",
result, expected);
/*
* More tests show that if seed is odd the result must be incremented by 1:
*/
seed = 3;
expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1);
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 2)) returns %lx, expected %lx",
result, expected);
seed = 0x6bca1aa;
expected = seed * 0xffffffed + 0x7fffffc3;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0x6bca1aa)) returns %lx, expected %lx",
result, expected);
seed = 0x6bca1ab;
expected = seed * 0xffffffed + 0x7fffffc3 + 1;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0x6bca1ab)) returns %lx, expected %lx",
result, expected);
/*
* When seed is 0x6bca1ac there is an exception:
*/
seed = 0x6bca1ac;
expected = seed * 0xffffffed + 0x7fffffc3 + 2;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0x6bca1ac)) returns %lx, expected %lx",
result, expected);
/*
* Note that up to here const_3 is not used
* (the highest bit of the result is not set).
*
* Starting with 0x6bca1ad: If seed is even the result must be incremented by 1:
*/
seed = 0x6bca1ad;
expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0x6bca1ad)) returns %lx, expected %lx",
result, expected);
seed = 0x6bca1ae;
expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG;
result = pRtlUniform(&seed);
ok(result == expected,
"RtlUniform(&seed (seed == 0x6bca1ae)) returns %lx, expected %lx",
result, expected);
/*
* There are several ranges where for odd or even seed the result must be
* incremented by 1. You can see this ranges in the following test.
*
* For a full test use one of the following loop heads:
*
* for (num = 0; num <= 0xffffffff; num++) {
* seed = num;
* ...
*
* seed = 0;
* for (num = 0; num <= 0xffffffff; num++) {
* ...
*/
seed = 0;
for (num = 0; num <= 100000; num++) {
expected = seed * 0xffffffed + 0x7fffffc3;
if (seed < 0x6bca1ac) {
expected = expected + (seed & 1);
} else if (seed == 0x6bca1ac) {
expected = (expected + 2) & MAXLONG;
} else if (seed < 0xd79435c) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x1435e50b) {
expected = expected + (seed & 1);
} else if (seed < 0x1af286ba) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x21af2869) {
expected = expected + (seed & 1);
} else if (seed < 0x286bca18) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x2f286bc7) {
expected = expected + (seed & 1);
} else if (seed < 0x35e50d77) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x3ca1af26) {
expected = expected + (seed & 1);
} else if (seed < 0x435e50d5) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x4a1af284) {
expected = expected + (seed & 1);
} else if (seed < 0x50d79433) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x579435e2) {
expected = expected + (seed & 1);
} else if (seed < 0x5e50d792) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x650d7941) {
expected = expected + (seed & 1);
} else if (seed < 0x6bca1af0) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x7286bc9f) {
expected = expected + (seed & 1);
} else if (seed < 0x79435e4e) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x7ffffffd) {
expected = expected + (seed & 1);
} else if (seed < 0x86bca1ac) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed == 0x86bca1ac) {
expected = (expected + 1) & MAXLONG;
} else if (seed < 0x8d79435c) {
expected = expected + (seed & 1);
} else if (seed < 0x9435e50b) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0x9af286ba) {
expected = expected + (seed & 1);
} else if (seed < 0xa1af2869) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xa86bca18) {
expected = expected + (seed & 1);
} else if (seed < 0xaf286bc7) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed == 0xaf286bc7) {
expected = (expected + 2) & MAXLONG;
} else if (seed < 0xb5e50d77) {
expected = expected + (seed & 1);
} else if (seed < 0xbca1af26) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xc35e50d5) {
expected = expected + (seed & 1);
} else if (seed < 0xca1af284) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xd0d79433) {
expected = expected + (seed & 1);
} else if (seed < 0xd79435e2) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xde50d792) {
expected = expected + (seed & 1);
} else if (seed < 0xe50d7941) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xebca1af0) {
expected = expected + (seed & 1);
} else if (seed < 0xf286bc9f) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else if (seed < 0xf9435e4e) {
expected = expected + (seed & 1);
} else if (seed < 0xfffffffd) {
expected = (expected + (~seed & 1)) & MAXLONG;
} else {
expected = expected + (seed & 1);
} /* if */
seed_bak = seed;
result = pRtlUniform(&seed);
ok(result == expected,
"test: %llu RtlUniform(&seed (seed == %lx)) returns %lx, expected %lx",
num, seed_bak, result, expected);
ok(seed == expected,
"test: %llu RtlUniform(&seed (seed == %lx)) sets seed to %lx, expected %lx",
num, seed_bak, seed, expected);
} /* for */
/*
* Further investigation shows: In the different regions the highest bit
* is set or cleared when even or odd seeds need an increment by 1.
* This leads to the simplified RtlUniform of wine (see dlls/ntdll/rtl.c).
*/
}
START_TEST(rtl)
{
InitFunctionPtrs();
test_RtlCompareMemoryUlong();
test_RtlUniform();
}