You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnitTest.cs 20 kB

10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. using System;
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;
  3. using Shadowsocks.Controller;
  4. using Shadowsocks.Encryption;
  5. using GlobalHotKey;
  6. using System.Windows.Input;
  7. using System.Threading;
  8. using System.Collections.Generic;
  9. using Shadowsocks.Controller.Hotkeys;
  10. using Shadowsocks.Encryption.Stream;
  11. using Shadowsocks.Model;
  12. namespace test
  13. {
  14. [TestClass]
  15. public class UnitTest
  16. {
  17. [TestMethod]
  18. public void TestCompareVersion()
  19. {
  20. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("2.3.1.0", "2.3.1") == 0);
  21. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.2", "1.3") < 0);
  22. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3", "1.2") > 0);
  23. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3", "1.3") == 0);
  24. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.2.1", "1.2") > 0);
  25. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("2.3.1", "2.4") < 0);
  26. Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3.2", "1.3.1") > 0);
  27. }
  28. [TestMethod]
  29. public void TestHotKey2Str()
  30. {
  31. Assert.AreEqual("Ctrl+A", HotKeys.HotKey2Str(Key.A, ModifierKeys.Control));
  32. Assert.AreEqual("Ctrl+Alt+D2", HotKeys.HotKey2Str(Key.D2, (ModifierKeys.Alt | ModifierKeys.Control)));
  33. Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
  34. Assert.AreEqual("Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
  35. Assert.AreNotEqual("Ctrl+Shift+Alt+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
  36. }
  37. [TestMethod]
  38. public void TestStr2HotKey()
  39. {
  40. Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+A").Equals(new HotKey(Key.A, ModifierKeys.Control)));
  41. Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt))));
  42. Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Shift))));
  43. Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
  44. HotKey testKey0 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+A");
  45. Assert.IsTrue(testKey0 != null && testKey0.Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
  46. HotKey testKey1 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+F2");
  47. Assert.IsTrue(testKey1 != null && testKey1.Equals(new HotKey(Key.F2, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
  48. HotKey testKey2 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+D7");
  49. Assert.IsTrue(testKey2 != null && testKey2.Equals(new HotKey(Key.D7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
  50. HotKey testKey3 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+NumPad7");
  51. Assert.IsTrue(testKey3 != null && testKey3.Equals(new HotKey(Key.NumPad7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
  52. }
  53. [TestMethod]
  54. public void TestMD5()
  55. {
  56. for (int len = 1; len < 64; len++)
  57. {
  58. System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
  59. byte[] bytes = new byte[len];
  60. var random = new Random();
  61. random.NextBytes(bytes);
  62. string md5str = Convert.ToBase64String(md5.ComputeHash(bytes));
  63. string md5str2 = Convert.ToBase64String(MbedTLS.MD5(bytes));
  64. Assert.IsTrue(md5str == md5str2);
  65. }
  66. }
  67. private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor)
  68. {
  69. RNG.Reload();
  70. byte[] plain = new byte[16384];
  71. byte[] cipher = new byte[plain.Length + 16];
  72. byte[] plain2 = new byte[plain.Length + 16];
  73. int outLen = 0;
  74. int outLen2 = 0;
  75. var random = new Random();
  76. random.NextBytes(plain);
  77. encryptor.Encrypt(plain, plain.Length, cipher, out outLen);
  78. decryptor.Decrypt(cipher, outLen, plain2, out outLen2);
  79. Assert.AreEqual(plain.Length, outLen2);
  80. for (int j = 0; j < plain.Length; j++)
  81. {
  82. Assert.AreEqual(plain[j], plain2[j]);
  83. }
  84. encryptor.Encrypt(plain, 1000, cipher, out outLen);
  85. decryptor.Decrypt(cipher, outLen, plain2, out outLen2);
  86. Assert.AreEqual(1000, outLen2);
  87. for (int j = 0; j < outLen2; j++)
  88. {
  89. Assert.AreEqual(plain[j], plain2[j]);
  90. }
  91. encryptor.Encrypt(plain, 12333, cipher, out outLen);
  92. decryptor.Decrypt(cipher, outLen, plain2, out outLen2);
  93. Assert.AreEqual(12333, outLen2);
  94. for (int j = 0; j < outLen2; j++)
  95. {
  96. Assert.AreEqual(plain[j], plain2[j]);
  97. }
  98. }
  99. private static bool encryptionFailed = false;
  100. private static object locker = new object();
  101. [TestMethod]
  102. public void TestMbedTLSEncryption()
  103. {
  104. // run it once before the multi-threading test to initialize global tables
  105. RunSingleMbedTLSEncryptionThread();
  106. List<Thread> threads = new List<Thread>();
  107. for (int i = 0; i < 10; i++)
  108. {
  109. Thread t = new Thread(new ThreadStart(RunSingleMbedTLSEncryptionThread));
  110. threads.Add(t);
  111. t.Start();
  112. }
  113. foreach (Thread t in threads)
  114. {
  115. t.Join();
  116. }
  117. RNG.Close();
  118. Assert.IsFalse(encryptionFailed);
  119. }
  120. private void RunSingleMbedTLSEncryptionThread()
  121. {
  122. try
  123. {
  124. for (int i = 0; i < 100; i++)
  125. {
  126. IEncryptor encryptor;
  127. IEncryptor decryptor;
  128. encryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!");
  129. decryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!");
  130. RunEncryptionRound(encryptor, decryptor);
  131. }
  132. }
  133. catch
  134. {
  135. encryptionFailed = true;
  136. throw;
  137. }
  138. }
  139. [TestMethod]
  140. public void TestRC4Encryption()
  141. {
  142. // run it once before the multi-threading test to initialize global tables
  143. RunSingleRC4EncryptionThread();
  144. List<Thread> threads = new List<Thread>();
  145. for (int i = 0; i < 10; i++)
  146. {
  147. Thread t = new Thread(new ThreadStart(RunSingleRC4EncryptionThread));
  148. threads.Add(t);
  149. t.Start();
  150. }
  151. foreach (Thread t in threads)
  152. {
  153. t.Join();
  154. }
  155. RNG.Close();
  156. Assert.IsFalse(encryptionFailed);
  157. }
  158. private void RunSingleRC4EncryptionThread()
  159. {
  160. try
  161. {
  162. for (int i = 0; i < 100; i++)
  163. {
  164. var random = new Random();
  165. IEncryptor encryptor;
  166. IEncryptor decryptor;
  167. encryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!");
  168. decryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!");
  169. RunEncryptionRound(encryptor, decryptor);
  170. }
  171. }
  172. catch
  173. {
  174. encryptionFailed = true;
  175. throw;
  176. }
  177. }
  178. [TestMethod]
  179. public void TestSodiumEncryption()
  180. {
  181. // run it once before the multi-threading test to initialize global tables
  182. RunSingleSodiumEncryptionThread();
  183. List<Thread> threads = new List<Thread>();
  184. for (int i = 0; i < 10; i++)
  185. {
  186. Thread t = new Thread(new ThreadStart(RunSingleSodiumEncryptionThread));
  187. threads.Add(t);
  188. t.Start();
  189. }
  190. foreach (Thread t in threads)
  191. {
  192. t.Join();
  193. }
  194. RNG.Close();
  195. Assert.IsFalse(encryptionFailed);
  196. }
  197. private void RunSingleSodiumEncryptionThread()
  198. {
  199. try
  200. {
  201. for (int i = 0; i < 100; i++)
  202. {
  203. var random = new Random();
  204. IEncryptor encryptor;
  205. IEncryptor decryptor;
  206. encryptor = new StreamSodiumEncryptor("salsa20", "barfoo!");
  207. decryptor = new StreamSodiumEncryptor("salsa20", "barfoo!");
  208. RunEncryptionRound(encryptor, decryptor);
  209. }
  210. }
  211. catch
  212. {
  213. encryptionFailed = true;
  214. throw;
  215. }
  216. }
  217. [TestMethod]
  218. public void TestOpenSSLEncryption()
  219. {
  220. // run it once before the multi-threading test to initialize global tables
  221. RunSingleOpenSSLEncryptionThread();
  222. List<Thread> threads = new List<Thread>();
  223. for (int i = 0; i < 10; i++)
  224. {
  225. Thread t = new Thread(new ThreadStart(RunSingleOpenSSLEncryptionThread));
  226. threads.Add(t);
  227. t.Start();
  228. }
  229. foreach (Thread t in threads)
  230. {
  231. t.Join();
  232. }
  233. RNG.Close();
  234. Assert.IsFalse(encryptionFailed);
  235. }
  236. private void RunSingleOpenSSLEncryptionThread()
  237. {
  238. try
  239. {
  240. for (int i = 0; i < 100; i++)
  241. {
  242. var random = new Random();
  243. IEncryptor encryptor;
  244. IEncryptor decryptor;
  245. encryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
  246. decryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
  247. RunEncryptionRound(encryptor, decryptor);
  248. }
  249. }
  250. catch
  251. {
  252. encryptionFailed = true;
  253. throw;
  254. }
  255. }
  256. [TestMethod]
  257. public void ParseAndGenerateShadowsocksUrl()
  258. {
  259. var server = new Server
  260. {
  261. server = "192.168.100.1",
  262. server_port = 8888,
  263. password = "test",
  264. method = "bf-cfb"
  265. };
  266. var serverCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4";
  267. var server2 = new Server
  268. {
  269. server = "192.168.1.1",
  270. server_port = 8388,
  271. password = "test",
  272. method = "bf-cfb"
  273. };
  274. var server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==";
  275. var serverWithRemark = new Server
  276. {
  277. server = server.server,
  278. server_port = server.server_port,
  279. password = server.password,
  280. method = server.method,
  281. remarks = "example-server"
  282. };
  283. var serverWithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server";
  284. var server2WithRemark = new Server
  285. {
  286. server = server2.server,
  287. server_port = server2.server_port,
  288. password = server2.password,
  289. method = server2.method,
  290. remarks = "example-server"
  291. };
  292. var server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server";
  293. var serverWithPlugin = new Server
  294. {
  295. server = server.server,
  296. server_port = server.server_port,
  297. password = server.password,
  298. method = server.method,
  299. plugin = "obfs-local",
  300. plugin_opts = "obfs=http;obfs-host=google.com"
  301. };
  302. var serverWithPluginCanonUrl =
  303. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
  304. var server2WithPlugin = new Server
  305. {
  306. server = server2.server,
  307. server_port = server2.server_port,
  308. password = server2.password,
  309. method = server2.method,
  310. plugin = "obfs-local",
  311. plugin_opts = "obfs=http;obfs-host=google.com"
  312. };
  313. var server2WithPluginCanonUrl =
  314. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
  315. var serverWithPluginAndRemark = new Server
  316. {
  317. server = server.server,
  318. server_port = server.server_port,
  319. password = server.password,
  320. method = server.method,
  321. plugin = serverWithPlugin.plugin,
  322. plugin_opts = serverWithPlugin.plugin_opts,
  323. remarks = serverWithRemark.remarks
  324. };
  325. var serverWithPluginAndRemarkCanonUrl =
  326. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
  327. var server2WithPluginAndRemark = new Server
  328. {
  329. server = server2.server,
  330. server_port = server2.server_port,
  331. password = server2.password,
  332. method = server2.method,
  333. plugin = server2WithPlugin.plugin,
  334. plugin_opts = server2WithPlugin.plugin_opts,
  335. remarks = server2WithRemark.remarks
  336. };
  337. var server2WithPluginAndRemarkCanonUrl =
  338. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
  339. RunParseShadowsocksUrlTest(
  340. string.Join(
  341. "\r\n",
  342. serverCanonUrl,
  343. "\r\n",
  344. "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/",
  345. serverWithRemarkCanonUrl,
  346. "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server"),
  347. new[]
  348. {
  349. server,
  350. server,
  351. serverWithRemark,
  352. serverWithRemark
  353. });
  354. RunParseShadowsocksUrlTest(
  355. string.Join(
  356. "\r\n",
  357. server2CanonUrl,
  358. "\r\n",
  359. "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/",
  360. server2WithRemarkCanonUrl,
  361. "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server"),
  362. new[]
  363. {
  364. server2,
  365. server2,
  366. server2WithRemark,
  367. server2WithRemark
  368. });
  369. RunParseShadowsocksUrlTest(
  370. string.Join(
  371. "\r\n",
  372. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888",
  373. "\r\n",
  374. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/",
  375. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server",
  376. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server",
  377. serverWithPluginCanonUrl,
  378. serverWithPluginAndRemarkCanonUrl,
  379. "ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
  380. new[]
  381. {
  382. server,
  383. server,
  384. serverWithRemark,
  385. serverWithRemark,
  386. serverWithPlugin,
  387. serverWithPluginAndRemark,
  388. serverWithPluginAndRemark
  389. });
  390. RunParseShadowsocksUrlTest(
  391. string.Join(
  392. "\r\n",
  393. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388",
  394. "\r\n",
  395. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/",
  396. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server",
  397. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server",
  398. server2WithPluginCanonUrl,
  399. server2WithPluginAndRemarkCanonUrl,
  400. "ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
  401. new[]
  402. {
  403. server2,
  404. server2,
  405. server2WithRemark,
  406. server2WithRemark,
  407. server2WithPlugin,
  408. server2WithPluginAndRemark,
  409. server2WithPluginAndRemark
  410. });
  411. var generateUrlCases = new Dictionary<string, Server>
  412. {
  413. [serverCanonUrl] = server,
  414. [serverWithRemarkCanonUrl] = serverWithRemark,
  415. [serverWithPluginCanonUrl] = serverWithPlugin,
  416. [serverWithPluginAndRemarkCanonUrl] = serverWithPluginAndRemark
  417. };
  418. RunGenerateShadowsocksUrlTest(generateUrlCases);
  419. }
  420. private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList<Server> expected)
  421. {
  422. var actual = Server.GetServers(testCase);
  423. if (actual.Count != expected.Count)
  424. {
  425. Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count);
  426. }
  427. for (int i = 0; i < expected.Count; i++)
  428. {
  429. var expectedServer = expected[i];
  430. var actualServer = actual[i];
  431. Assert.AreEqual(expectedServer.server, actualServer.server);
  432. Assert.AreEqual(expectedServer.server_port, actualServer.server_port);
  433. Assert.AreEqual(expectedServer.password, actualServer.password);
  434. Assert.AreEqual(expectedServer.method, actualServer.method);
  435. Assert.AreEqual(expectedServer.plugin, actualServer.plugin);
  436. Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts);
  437. Assert.AreEqual(expectedServer.remarks, actualServer.remarks);
  438. Assert.AreEqual(expectedServer.timeout, actualServer.timeout);
  439. }
  440. }
  441. private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary<string, Server> testCases)
  442. {
  443. foreach (var testCase in testCases)
  444. {
  445. string expected = testCase.Key;
  446. Server config = testCase.Value;
  447. var actual = ShadowsocksController.GetServerURL(config);
  448. Assert.AreEqual(expected, actual);
  449. }
  450. }
  451. }
  452. }