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.
6 using System.Reflection;
7 using System.Runtime.InteropServices;
10 using Console = Internal.Console;
27 public class NativeLibraryTest
29 static string CurrentTest;
30 static bool Verbose = false;
32 public static int Main()
36 Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
37 string testBinDir = Path.GetDirectoryName(assembly.Location);
41 // -----------------------------------------------
42 // Simple LoadLibrary() API Tests
43 // -----------------------------------------------
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));
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);
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);
61 // Calls on null input
63 success &= EXPECT(LoadLibrarySimple(libName), TestResult.ArgumentNull);
64 success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ArgumentNull);
66 // -----------------------------------------------
67 // Advanced LoadLibrary() API Tests
68 // -----------------------------------------------
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));
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);
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);
88 // Calls on just Native Library name
89 libName = GetNativeLibraryPlainName();
90 success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null));
91 success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null));
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));
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);
107 if (TestLibrary.Utilities.IsWindows)
109 libName = GetWin32LibName();
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));
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);
120 // Calls with null libName input
121 success &= EXPECT(LoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull);
122 success &= EXPECT(TryLoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull);
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);
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);
135 // -----------------------------------------------
137 // -----------------------------------------------
139 libName = Path.Combine(testBinDir, GetNativeLibraryName());
140 handle = Marshal.LoadLibrary(libName);
143 success &= EXPECT(FreeLibrary(handle));
146 success &= EXPECT(FreeLibrary(handle), TestResult.InvalidOperation);
149 success &= EXPECT(FreeLibrary(IntPtr.Zero));
151 // -----------------------------------------------
152 // GetLibraryExport Tests
153 // -----------------------------------------------
154 libName = Path.Combine(testBinDir, GetNativeLibraryName());
155 handle = Marshal.LoadLibrary(libName);
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"));
161 // Call with null handle
162 success &= EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
163 success &= EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull);
165 // Call with null string
166 success &= EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull);
167 success &= EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull);
169 // Call with wrong string
170 success &= EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound);
171 success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure);
173 Marshal.FreeLibrary(handle);
175 return (success) ? 100 : -100;
178 static string GetNativeLibraryPlainName()
180 return "NativeLibrary";
183 static string GetWin32LibName()
188 static string GetNativeLibraryName()
190 string baseName = GetNativeLibraryPlainName();
192 if (TestLibrary.Utilities.IsWindows)
194 return baseName + ".dll";
196 if (TestLibrary.Utilities.IsLinux)
198 return "lib" + baseName + ".so";
200 if (TestLibrary.Utilities.IsMacOSX)
202 return "lib" + baseName + ".dylib";
208 static bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success)
210 if (actualValue == expectedValue)
213 Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue));
218 Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue));
223 static TestResult Run (Func<TestResult> test)
232 catch (ArgumentNullException e)
234 return TestResult.ArgumentNull;
236 catch (ArgumentException e)
238 return TestResult.ArgumentBad;
240 catch (DllNotFoundException e)
242 return TestResult.DllNotFound;
244 catch (BadImageFormatException e)
246 return TestResult.BadImage;
248 catch (InvalidOperationException e)
250 return TestResult.InvalidOperation;
252 catch (EntryPointNotFoundException e)
254 return TestResult.EntryPointNotFound;
258 //Console.WriteLine(e.ToString());
259 return TestResult.GenericException;
265 static TestResult LoadLibrarySimple(string libPath)
267 CurrentTest = String.Format("LoadLibrary({0})", libPath);
269 IntPtr handle = IntPtr.Zero;
271 TestResult result = Run(() => {
272 handle = Marshal.LoadLibrary(libPath);
273 if (handle == IntPtr.Zero)
274 return TestResult.ReturnNull;
275 return TestResult.Success;
278 Marshal.FreeLibrary(handle);
283 static TestResult TryLoadLibrarySimple(string libPath)
285 CurrentTest = String.Format("TryLoadLibrary({0})", libPath);
287 IntPtr handle = IntPtr.Zero;
289 TestResult result = Run(() => {
290 bool success = Marshal.TryLoadLibrary(libPath, out handle);
292 return TestResult.ReturnFailure;
294 return TestResult.ReturnNull;
295 return TestResult.Success;
298 Marshal.FreeLibrary(handle);
304 static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath)
306 CurrentTest = String.Format("LoadLibrary({0}, {1}, {2})", libName, assembly, searchPath);
308 IntPtr handle = IntPtr.Zero;
310 TestResult result = Run(() => {
311 handle = Marshal.LoadLibrary(libName, assembly, searchPath);
312 if (handle == IntPtr.Zero)
313 return TestResult.ReturnNull;
314 return TestResult.Success;
317 Marshal.FreeLibrary(handle);
322 static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath)
324 CurrentTest = String.Format("TryLoadLibrary({0}, {1}, {2})", libName, assembly, searchPath);
326 IntPtr handle = IntPtr.Zero;
328 TestResult result = Run(() => {
329 bool success = Marshal.TryLoadLibrary(libName, assembly, searchPath, out handle);
331 return TestResult.ReturnFailure;
332 if (handle == IntPtr.Zero)
333 return TestResult.ReturnNull;
334 return TestResult.Success;
337 Marshal.FreeLibrary(handle);
342 static TestResult FreeLibrary(IntPtr handle)
344 CurrentTest = String.Format("FreeLibrary({0})", handle);
347 Marshal.FreeLibrary(handle);
348 return TestResult.Success;
352 static TestResult GetLibraryExport(IntPtr handle, string name)
354 CurrentTest = String.Format("GetLibraryExport({0}, {1})", handle, name);
357 IntPtr address = Marshal.GetLibraryExport(handle, name);
359 return TestResult.ReturnNull;
360 if (RunExportedFunction(address, 1, 1) != 2)
361 return TestResult.IncorrectEvaluation;
362 return TestResult.Success;
366 static TestResult TryGetLibraryExport(IntPtr handle, string name)
368 CurrentTest = String.Format("TryGetLibraryExport({0}, {1})", handle, name);
371 IntPtr address = IntPtr.Zero;
372 bool success = Marshal.TryGetLibraryExport(handle, name, out address);
374 return TestResult.ReturnFailure;
376 return TestResult.ReturnNull;
377 if (RunExportedFunction(address, 1, 1) != 2)
378 return TestResult.IncorrectEvaluation;
379 return TestResult.Success;
383 [DllImport("NativeLibrary")]
384 static extern int RunExportedFunction(IntPtr address, int arg1, int arg2);