1 /*
2  * Unit test suite for ntdll time functions
3  *
4  * Copyright 2004 Rein Klazes
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #ifndef __REACTOS__
22 #define NONAMELESSUNION
23 #endif
24 #include "ntdll_test.h"
25 #ifndef __REACTOS__
26 #include "ddk/wdm.h"
27 #else /* FIXME: Inspect */
28 
29 typedef struct _KSYSTEM_TIME {
30     ULONG LowPart;
31     LONG High1Time;
32     LONG High2Time;
33 } KSYSTEM_TIME, *PKSYSTEM_TIME;
34 
35 typedef enum _NT_PRODUCT_TYPE {
36     NtProductWinNt = 1,
37     NtProductLanManNt,
38     NtProductServer
39 } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
40 
41 #define PROCESSOR_FEATURE_MAX 64
42 
43 typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
44 {
45    StandardDesign,
46    NEC98x86,
47    EndAlternatives
48 } ALTERNATIVE_ARCHITECTURE_TYPE;
49 
50 #define MAX_WOW64_SHARED_ENTRIES 16
51 
52 typedef struct _KUSER_SHARED_DATA {
53     ULONG TickCountLowDeprecated;
54     ULONG TickCountMultiplier;
55     volatile KSYSTEM_TIME InterruptTime;
56     volatile KSYSTEM_TIME SystemTime;
57     volatile KSYSTEM_TIME TimeZoneBias;
58     USHORT ImageNumberLow;
59     USHORT ImageNumberHigh;
60     WCHAR NtSystemRoot[260];
61     ULONG MaxStackTraceDepth;
62     ULONG CryptoExponent;
63     ULONG TimeZoneId;
64     ULONG LargePageMinimum;
65     ULONG Reserved2[7];
66     NT_PRODUCT_TYPE NtProductType;
67     BOOLEAN ProductTypeIsValid;
68     ULONG NtMajorVersion;
69     ULONG NtMinorVersion;
70     BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
71     ULONG Reserved1;
72     ULONG Reserved3;
73     volatile ULONG TimeSlip;
74     ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
75     LARGE_INTEGER SystemExpirationDate;
76     ULONG SuiteMask;
77     BOOLEAN KdDebuggerEnabled;
78     UCHAR NXSupportPolicy;
79     volatile ULONG ActiveConsoleId;
80     volatile ULONG DismountCount;
81     ULONG ComPlusPackage;
82     ULONG LastSystemRITEventTickCount;
83     ULONG NumberOfPhysicalPages;
84     BOOLEAN SafeBootMode;
85     ULONG TraceLogging;
86     ULONGLONG TestRetInstruction;
87     ULONG SystemCall;
88     ULONG SystemCallReturn;
89     ULONGLONG SystemCallPad[3];
90     union {
91         volatile KSYSTEM_TIME TickCount;
92         volatile ULONG64 TickCountQuad;
93     } DUMMYUNIONNAME;
94     ULONG Cookie;
95     ULONG Wow64SharedInformation[MAX_WOW64_SHARED_ENTRIES];
96 } KSHARED_USER_DATA, *PKSHARED_USER_DATA;
97 
98 #endif /* !__REACTOS__ */
99 
100 #define TICKSPERSEC        10000000
101 #define TICKSPERMSEC       10000
102 #define SECSPERDAY         86400
103 
104 static VOID (WINAPI *pRtlTimeToTimeFields)( const LARGE_INTEGER *liTime, PTIME_FIELDS TimeFields) ;
105 static VOID (WINAPI *pRtlTimeFieldsToTime)(  PTIME_FIELDS TimeFields,  PLARGE_INTEGER Time) ;
106 static NTSTATUS (WINAPI *pNtQueryPerformanceCounter)( LARGE_INTEGER *counter, LARGE_INTEGER *frequency );
107 static NTSTATUS (WINAPI *pRtlQueryTimeZoneInformation)( RTL_TIME_ZONE_INFORMATION *);
108 static NTSTATUS (WINAPI *pRtlQueryDynamicTimeZoneInformation)( RTL_DYNAMIC_TIME_ZONE_INFORMATION *);
109 static ULONG (WINAPI *pNtGetTickCount)(void);
110 
111 static const int MonthLengths[2][12] =
112 {
113 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
114 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
115 };
116 
117 static inline BOOL IsLeapYear(int Year)
118 {
119     return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
120 }
121 
122 /* start time of the tests */
123 static TIME_FIELDS tftest = {1889,12,31,23,59,59,0,0};
124 
125 static void test_pRtlTimeToTimeFields(void)
126 {
127     LARGE_INTEGER litime , liresult;
128     TIME_FIELDS tfresult;
129     int i=0;
130     litime.QuadPart = ((ULONGLONG)0x0144017a << 32) | 0xf0b0a980;
131     while( tftest.Year < 2110 ) {
132         /* test at the last second of the month */
133         pRtlTimeToTimeFields( &litime, &tfresult);
134         ok( tfresult.Year == tftest.Year && tfresult.Month == tftest.Month &&
135             tfresult.Day == tftest.Day && tfresult.Hour == tftest.Hour &&
136             tfresult.Minute == tftest.Minute && tfresult.Second == tftest.Second,
137             "#%d expected: %d-%d-%d %d:%d:%d  got:  %d-%d-%d %d:%d:%d\n", ++i,
138             tftest.Year, tftest.Month, tftest.Day,
139             tftest.Hour, tftest.Minute,tftest.Second,
140             tfresult.Year, tfresult.Month, tfresult.Day,
141             tfresult.Hour, tfresult.Minute, tfresult.Second);
142         /* test the inverse */
143         pRtlTimeFieldsToTime( &tfresult, &liresult);
144         ok( liresult.QuadPart == litime.QuadPart," TimeFieldsToTime failed on %d-%d-%d %d:%d:%d. Error is %d ticks\n",
145             tfresult.Year, tfresult.Month, tfresult.Day,
146             tfresult.Hour, tfresult.Minute, tfresult.Second,
147             (int) (liresult.QuadPart - litime.QuadPart) );
148         /*  one second later is beginning of next month */
149         litime.QuadPart +=  TICKSPERSEC ;
150         pRtlTimeToTimeFields( &litime, &tfresult);
151         ok( tfresult.Year == tftest.Year + (tftest.Month ==12) &&
152             tfresult.Month == tftest.Month % 12 + 1 &&
153             tfresult.Day == 1 && tfresult.Hour == 0 &&
154             tfresult.Minute == 0 && tfresult.Second == 0,
155             "#%d expected: %d-%d-%d %d:%d:%d  got:  %d-%d-%d %d:%d:%d\n", ++i,
156             tftest.Year + (tftest.Month ==12),
157             tftest.Month % 12 + 1, 1, 0, 0, 0,
158             tfresult.Year, tfresult.Month, tfresult.Day,
159             tfresult.Hour, tfresult.Minute, tfresult.Second);
160         /* test the inverse */
161         pRtlTimeFieldsToTime( &tfresult, &liresult);
162         ok( liresult.QuadPart == litime.QuadPart," TimeFieldsToTime failed on %d-%d-%d %d:%d:%d. Error is %d ticks\n",
163             tfresult.Year, tfresult.Month, tfresult.Day,
164             tfresult.Hour, tfresult.Minute, tfresult.Second,
165             (int) (liresult.QuadPart - litime.QuadPart) );
166         /* advance to the end of the month */
167         litime.QuadPart -=  TICKSPERSEC ;
168         if( tftest.Month == 12) {
169             tftest.Month = 1;
170             tftest.Year += 1;
171         } else
172             tftest.Month += 1;
173         tftest.Day = MonthLengths[IsLeapYear(tftest.Year)][tftest.Month - 1];
174         litime.QuadPart +=  (LONGLONG) tftest.Day * TICKSPERSEC * SECSPERDAY;
175     }
176 }
177 
178 static void test_NtQueryPerformanceCounter(void)
179 {
180     LARGE_INTEGER counter, frequency;
181     NTSTATUS status;
182 
183     status = pNtQueryPerformanceCounter(NULL, NULL);
184     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
185     status = pNtQueryPerformanceCounter(NULL, &frequency);
186     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
187     status = pNtQueryPerformanceCounter(&counter, (void *)0xdeadbee0);
188     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
189     status = pNtQueryPerformanceCounter((void *)0xdeadbee0, &frequency);
190     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
191 
192     status = pNtQueryPerformanceCounter(&counter, NULL);
193     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
194     status = pNtQueryPerformanceCounter(&counter, &frequency);
195     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
196 }
197 
198 static void test_RtlQueryTimeZoneInformation(void)
199 {
200     RTL_DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
201     NTSTATUS status;
202 
203     /* test RtlQueryTimeZoneInformation returns an indirect string,
204        e.g. @tzres.dll,-32 (Vista or later) */
205     if (!pRtlQueryTimeZoneInformation || !pRtlQueryDynamicTimeZoneInformation)
206     {
207         win_skip("Time zone name tests requires Vista or later\n");
208         return;
209     }
210 
211     memset(&tzinfo, 0, sizeof(tzinfo));
212     status = pRtlQueryDynamicTimeZoneInformation(&tzinfo);
213     ok(status == STATUS_SUCCESS,
214        "RtlQueryDynamicTimeZoneInformation failed, got %08x\n", status);
215     todo_wine ok(tzinfo.StandardName[0] == '@',
216        "standard time zone name isn't an indirect string, got %s\n",
217        wine_dbgstr_w(tzinfo.StandardName));
218     todo_wine ok(tzinfo.DaylightName[0] == '@',
219        "daylight time zone name isn't an indirect string, got %s\n",
220        wine_dbgstr_w(tzinfo.DaylightName));
221 
222     memset(&tzinfo, 0, sizeof(tzinfo));
223     status = pRtlQueryTimeZoneInformation((RTL_TIME_ZONE_INFORMATION *)&tzinfo);
224     ok(status == STATUS_SUCCESS,
225        "RtlQueryTimeZoneInformation failed, got %08x\n", status);
226     todo_wine ok(tzinfo.StandardName[0] == '@',
227        "standard time zone name isn't an indirect string, got %s\n",
228        wine_dbgstr_w(tzinfo.StandardName));
229     todo_wine ok(tzinfo.DaylightName[0] == '@',
230        "daylight time zone name isn't an indirect string, got %s\n",
231        wine_dbgstr_w(tzinfo.DaylightName));
232 }
233 
234 static void test_NtGetTickCount(void)
235 {
236 #ifndef _WIN64
237     KSHARED_USER_DATA *user_shared_data = (void *)0x7ffe0000;
238     LONG diff;
239     int i;
240 
241     if (!pNtGetTickCount)
242     {
243         win_skip("NtGetTickCount is not available\n");
244         return;
245     }
246 
247     for (i = 0; i < 5; ++i)
248     {
249         diff = (user_shared_data->TickCountQuad * user_shared_data->TickCountMultiplier) >> 24;
250         diff = pNtGetTickCount() - diff;
251         ok(diff < 32, "NtGetTickCount - TickCountQuad too high, expected < 32 got %d\n", diff);
252         Sleep(50);
253     }
254 #endif
255 }
256 
257 START_TEST(time)
258 {
259     HMODULE mod = GetModuleHandleA("ntdll.dll");
260     pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields");
261     pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime");
262     pNtQueryPerformanceCounter = (void *)GetProcAddress(mod, "NtQueryPerformanceCounter");
263     pNtGetTickCount = (void *)GetProcAddress(mod,"NtGetTickCount");
264     pRtlQueryTimeZoneInformation =
265         (void *)GetProcAddress(mod, "RtlQueryTimeZoneInformation");
266     pRtlQueryDynamicTimeZoneInformation =
267         (void *)GetProcAddress(mod, "RtlQueryDynamicTimeZoneInformation");
268 
269     if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
270         test_pRtlTimeToTimeFields();
271     else
272         win_skip("Required time conversion functions are not available\n");
273     test_NtQueryPerformanceCounter();
274     test_NtGetTickCount();
275     test_RtlQueryTimeZoneInformation();
276 }
277