Fix #21209 (#21237)
[platform/upstream/coreclr.git] / tests / src / Interop / MarshalAPI / NativeLibrary / NativeLibraryTests.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 using System;
5 using System.IO;
6 using System.Reflection;
7 using System.Runtime.InteropServices;
8 using TestLibrary;
9
10 using Console = Internal.Console;
11
12 enum TestResult {
13     Success,
14     ReturnFailure,
15     ReturnNull,
16     IncorrectEvaluation,
17     ArgumentNull,
18     ArgumentBad,
19
20     DllNotFound,
21     BadImage,
22     InvalidOperation,
23     EntryPointNotFound,
24     GenericException
25     };
26
27 public class NativeLibraryTest
28 {
29     static string CurrentTest;
30     static bool Verbose = false;
31  
32     public static int Main()
33     {
34         bool success = true;
35
36         Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
37         string testBinDir = Path.GetDirectoryName(assembly.Location);
38         string libName;
39         IntPtr handle;
40
41         // -----------------------------------------------
42         //         Simple LoadLibrary() API Tests
43         // -----------------------------------------------
44
45         // Calls on correct full-path to native lib
46         libName = Path.Combine(testBinDir, GetNativeLibraryName());
47         success &= EXPECT(LoadLibrarySimple(libName));
48         success &= EXPECT(TryLoadLibrarySimple(libName));
49
50         // Calls on non-existant file
51         libName = Path.Combine(testBinDir, "notfound");
52         success &= EXPECT(LoadLibrarySimple(libName), TestResult.DllNotFound);
53         success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure);
54
55         // Calls on an invalid file
56         libName = Path.Combine(testBinDir, "NativeLibrary.cpp");
57         success &= EXPECT(LoadLibrarySimple(libName), 
58             (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound);
59         success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure);
60
61         // Calls on null input
62         libName = null;
63         success &= EXPECT(LoadLibrarySimple(libName), TestResult.ArgumentNull);
64         success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ArgumentNull);
65
66         // -----------------------------------------------
67         //         Advanced LoadLibrary() API Tests
68         // -----------------------------------------------
69
70         // Advanced LoadLibrary() API Tests
71         // Calls on correct full-path to native lib
72         libName = Path.Combine(testBinDir, GetNativeLibraryName());
73         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null));
74         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null));
75
76         // Calls on non-existant file
77         libName = Path.Combine(testBinDir, "notfound");
78         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), TestResult.DllNotFound);
79         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure);
80
81         // Calls on an invalid file
82         libName = Path.Combine(testBinDir, "NativeLibrary.cpp");
83         // The VM can only distinguish BadImageFormatException from DllNotFoundException on Windows.
84         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), 
85             (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound);
86         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure);
87
88         // Calls on just Native Library name
89         libName = GetNativeLibraryPlainName();
90         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null));
91         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null));
92
93         // Calls on Native Library name with correct prefix-suffix
94         libName = GetNativeLibraryName();
95         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null));
96         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null));
97
98         // Calls on full path without prefix-siffix
99         libName = Path.Combine(testBinDir, GetNativeLibraryPlainName());
100         // DllImport doesn't add a prefix if the name is preceeded by a path specification.
101         // Windows only needs a suffix, but Linux and Mac need both prefix and suffix
102         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null),
103             (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.DllNotFound);
104         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null),
105             (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.ReturnFailure);
106
107         if (TestLibrary.Utilities.IsWindows)
108         {
109             libName = GetWin32LibName();
110
111             // Calls on a valid library from System32 directory
112             success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32));
113             success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32));
114
115             // Calls on a valid library from application directory
116             success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.DllNotFound);
117             success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.ReturnFailure);
118         }
119
120         // Calls with null libName input
121         success &= EXPECT(LoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull);
122         success &= EXPECT(TryLoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull);
123
124         // Calls with null assembly
125         libName = GetNativeLibraryPlainName();
126         success &= EXPECT(LoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull);
127         success &= EXPECT(TryLoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull);
128
129         // Ensure that a lib is not picked up from current directory when
130         // a different full-path is specified.
131         libName = Path.Combine(testBinDir, Path.Combine("lib", GetNativeLibraryPlainName()));
132         success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound);
133         success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure);
134
135         // -----------------------------------------------
136         //         FreeLibrary Tests
137         // -----------------------------------------------
138
139         libName = Path.Combine(testBinDir, GetNativeLibraryName());
140         handle = Marshal.LoadLibrary(libName);
141
142         // Valid Free
143         success &= EXPECT(FreeLibrary(handle));
144
145         // Double Free
146         success &= EXPECT(FreeLibrary(handle), TestResult.InvalidOperation);
147
148         // Null Free
149         success &= EXPECT(FreeLibrary(IntPtr.Zero));
150
151         // -----------------------------------------------
152         //         GetLibraryExport Tests
153         // -----------------------------------------------
154         libName = Path.Combine(testBinDir, GetNativeLibraryName());
155         handle = Marshal.LoadLibrary(libName);
156
157         // Valid Call (with some hard-coded name mangling)
158         success &= EXPECT(GetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum"));
159         success &= EXPECT(TryGetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum"));
160
161         // Call with null handle
162         success &= EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
163         success &= EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
164
165         // Call with null string
166         success &= EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull);
167         success &= EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull);
168
169         // Call with wrong string
170         success &= EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound);
171         success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure);
172
173         Marshal.FreeLibrary(handle);
174
175         return (success) ? 100 : -100;
176     }
177
178     static string GetNativeLibraryPlainName()
179     {
180         return "NativeLibrary";
181     }
182
183     static string GetWin32LibName()
184     {
185         return "msi.dll";
186     }
187
188     static string GetNativeLibraryName()
189     {
190         string baseName = GetNativeLibraryPlainName();
191
192         if (TestLibrary.Utilities.IsWindows)
193         {
194             return baseName + ".dll";
195         }
196         if (TestLibrary.Utilities.IsLinux)
197         {
198             return "lib" + baseName + ".so";
199         }
200         if (TestLibrary.Utilities.IsMacOSX)
201         {
202             return "lib" + baseName + ".dylib";
203         }
204
205         return "ERROR";
206     }
207
208     static bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success)
209     {
210         if (actualValue == expectedValue)
211         {
212             if (Verbose)
213                 Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue));
214             return true;
215         }
216         else
217         {
218             Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue));
219             return false;
220         }
221     }
222
223     static TestResult Run (Func<TestResult> test)
224     {
225
226         TestResult result;
227
228         try
229         {
230             result = test();
231         }
232         catch (ArgumentNullException e)
233         {
234             return  TestResult.ArgumentNull;
235         }
236         catch (ArgumentException e)
237         {
238             return TestResult.ArgumentBad;
239         }
240         catch (DllNotFoundException e)
241         {
242             return TestResult.DllNotFound;
243         }
244         catch (BadImageFormatException e)
245         {
246             return TestResult.BadImage;
247         }
248         catch (InvalidOperationException e)
249         {
250             return TestResult.InvalidOperation;
251         }
252         catch (EntryPointNotFoundException e)
253         {
254             return TestResult.EntryPointNotFound;
255         }
256         catch (Exception e)
257         {
258             //Console.WriteLine(e.ToString());
259             return TestResult.GenericException;
260         }
261
262         return result;
263     }
264
265     static TestResult LoadLibrarySimple(string libPath)
266     {
267         CurrentTest = String.Format("LoadLibrary({0})", libPath);
268
269         IntPtr handle = IntPtr.Zero;
270
271         TestResult result = Run(() => {
272             handle = Marshal.LoadLibrary(libPath);
273             if (handle == IntPtr.Zero)
274                 return  TestResult.ReturnNull;
275             return TestResult.Success;
276         });
277
278         Marshal.FreeLibrary(handle);
279
280         return result;
281     }
282
283     static TestResult TryLoadLibrarySimple(string libPath)
284     {
285         CurrentTest = String.Format("TryLoadLibrary({0})", libPath);
286
287         IntPtr handle = IntPtr.Zero;
288
289         TestResult result = Run(() => {
290             bool success = Marshal.TryLoadLibrary(libPath, out handle);
291             if(!success)
292                 return TestResult.ReturnFailure;
293             if (handle == null)
294                 return  TestResult.ReturnNull;
295             return TestResult.Success;
296         });
297
298         Marshal.FreeLibrary(handle);
299
300         return result;
301     }
302
303
304     static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath)
305     {
306         CurrentTest = String.Format("LoadLibrary({0}, {1}, {2})", libName, assembly, searchPath);
307
308         IntPtr handle = IntPtr.Zero;
309
310         TestResult result = Run(() => {
311             handle = Marshal.LoadLibrary(libName, assembly, searchPath);
312             if (handle == IntPtr.Zero)
313                 return  TestResult.ReturnNull;
314             return TestResult.Success;
315         });
316
317         Marshal.FreeLibrary(handle);
318
319         return result;
320     }
321
322     static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath)
323     {
324         CurrentTest = String.Format("TryLoadLibrary({0}, {1}, {2})", libName, assembly, searchPath);
325
326         IntPtr handle = IntPtr.Zero;
327
328         TestResult result = Run(() => {
329             bool success = Marshal.TryLoadLibrary(libName, assembly, searchPath, out handle);
330             if (!success)
331                 return  TestResult.ReturnFailure;
332             if (handle == IntPtr.Zero)
333                 return  TestResult.ReturnNull;
334             return TestResult.Success;
335         });
336
337         Marshal.FreeLibrary(handle);
338
339         return result;
340     }
341
342     static TestResult FreeLibrary(IntPtr handle)
343     {
344         CurrentTest = String.Format("FreeLibrary({0})", handle);
345
346         return Run(() => {
347             Marshal.FreeLibrary(handle);
348             return TestResult.Success;
349         });
350     }
351
352     static TestResult GetLibraryExport(IntPtr handle, string name)
353     {
354         CurrentTest = String.Format("GetLibraryExport({0}, {1})", handle, name);
355
356         return Run(() => {
357             IntPtr address = Marshal.GetLibraryExport(handle, name);
358             if (address == null)
359                 return  TestResult.ReturnNull;
360             if (RunExportedFunction(address, 1, 1) != 2)
361                 return TestResult.IncorrectEvaluation;
362             return TestResult.Success;
363         });
364     }
365
366     static TestResult TryGetLibraryExport(IntPtr handle, string name)
367     {
368         CurrentTest = String.Format("TryGetLibraryExport({0}, {1})", handle, name);
369
370         return Run(() => {
371             IntPtr address = IntPtr.Zero;
372             bool success = Marshal.TryGetLibraryExport(handle, name, out address);
373             if (!success)
374                 return  TestResult.ReturnFailure;
375             if (address == null)
376                 return  TestResult.ReturnNull;
377             if (RunExportedFunction(address, 1, 1) != 2)
378                 return TestResult.IncorrectEvaluation;
379             return TestResult.Success;
380         });
381     }
382  
383     [DllImport("NativeLibrary")]
384     static extern int RunExportedFunction(IntPtr address, int arg1, int arg2);
385 }