ProtocGenCsUnittests.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using NUnit.Framework;
  35. using System;
  36. using System.Collections.Generic;
  37. using System.Diagnostics;
  38. using System.IO;
  39. using System.Reflection;
  40. using System.Text;
  41. namespace Google.ProtocolBuffers.ProtoGen
  42. {
  43. /// <summary>
  44. /// Tests protoc-gen-cs plugin.
  45. /// </summary>
  46. [TestFixture]
  47. [Category("Preprocessor")]
  48. public partial class ProtocGenCsUnittests
  49. {
  50. private static readonly string TempPath = Path.Combine(Path.GetTempPath(), "protoc-gen-cs.Test");
  51. private const string DefaultProto =
  52. @"
  53. package nunit.simple;
  54. // Test a very simple message.
  55. message MyMessage {
  56. optional string name = 1;
  57. }";
  58. #region TestFixture SetUp/TearDown
  59. private static readonly string OriginalWorkingDirectory = Environment.CurrentDirectory;
  60. private StringBuilder buffer = new StringBuilder();
  61. [TestFixtureSetUp]
  62. public virtual void Setup()
  63. {
  64. Teardown();
  65. Directory.CreateDirectory(TempPath);
  66. Environment.CurrentDirectory = TempPath;
  67. this.buffer.Length = 0;
  68. }
  69. [TestFixtureTearDown]
  70. public virtual void Teardown()
  71. {
  72. Environment.CurrentDirectory = OriginalWorkingDirectory;
  73. if (Directory.Exists(TempPath))
  74. {
  75. Directory.Delete(TempPath, true);
  76. }
  77. }
  78. #endregion
  79. #region Helper Methods RunProtoGen / RunCsc
  80. private void RunProtoc(int expect, string protoFile, params string[] args)
  81. {
  82. string protoPath = string.Format("-I. -I\"{0}\"", OriginalWorkingDirectory);
  83. string plugin = string.Format("--plugin=\"{0}\"", Path.Combine(OriginalWorkingDirectory, "protoc-gen-cs.exe"));
  84. string csOut = args.Length == 0 ? "--cs_out=." : string.Format("--cs_out=\"{0}:.\"", string.Join(" ", args));
  85. // Start the child process.
  86. Process p = new Process();
  87. // Redirect the output stream of the child process.
  88. p.StartInfo.CreateNoWindow = true;
  89. p.StartInfo.UseShellExecute = false;
  90. p.StartInfo.RedirectStandardError = true;
  91. p.StartInfo.RedirectStandardOutput = true;
  92. p.StartInfo.WorkingDirectory = TempPath;
  93. p.StartInfo.FileName = Path.Combine(OriginalWorkingDirectory, "protoc.exe");
  94. p.StartInfo.Arguments = string.Join(" ", new string[] { plugin, csOut, protoPath, protoFile });
  95. p.Start();
  96. // Read the output stream first and then wait.
  97. buffer.AppendLine(string.Format("{0}> \"{1}\" {2}", p.StartInfo.WorkingDirectory, p.StartInfo.FileName, p.StartInfo.Arguments));
  98. buffer.AppendLine(p.StandardError.ReadToEnd());
  99. buffer.AppendLine(p.StandardOutput.ReadToEnd());
  100. p.WaitForExit();
  101. Assert.AreEqual(expect, p.ExitCode, this.buffer.ToString());
  102. }
  103. private Assembly RunCsc(int expect, params string[] sources)
  104. {
  105. using (TempFile tempDll = new TempFile(String.Empty))
  106. {
  107. tempDll.ChangeExtension(".dll");
  108. List<string> args = new List<string>();
  109. args.Add("/nologo");
  110. args.Add("/target:library");
  111. args.Add("/debug-");
  112. args.Add(String.Format(@"""/out:{0}""", tempDll.TempPath));
  113. args.Add("/r:System.dll");
  114. args.Add(String.Format(@"""/r:{0}""",
  115. typeof(Google.ProtocolBuffers.DescriptorProtos.DescriptorProto).Assembly.
  116. Location));
  117. args.AddRange(sources);
  118. string exe = Path.Combine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(),
  119. "csc.exe");
  120. ProcessStartInfo psi = new ProcessStartInfo(exe);
  121. psi.WorkingDirectory = TempPath;
  122. psi.CreateNoWindow = true;
  123. psi.UseShellExecute = false;
  124. psi.RedirectStandardOutput = true;
  125. psi.RedirectStandardError = true;
  126. psi.Arguments = string.Join(" ", args.ToArray());
  127. Process p = Process.Start(psi);
  128. buffer.AppendLine(string.Format("{0}> \"{1}\" {2}", p.StartInfo.WorkingDirectory, p.StartInfo.FileName, p.StartInfo.Arguments));
  129. buffer.AppendLine(p.StandardError.ReadToEnd());
  130. buffer.AppendLine(p.StandardOutput.ReadToEnd());
  131. p.WaitForExit();
  132. Assert.AreEqual(expect, p.ExitCode, this.buffer.ToString());
  133. Assembly asm = null;
  134. if (p.ExitCode == 0)
  135. {
  136. byte[] allbytes = File.ReadAllBytes(tempDll.TempPath);
  137. asm = Assembly.Load(allbytes);
  138. foreach (Type t in asm.GetTypes())
  139. {
  140. Debug.WriteLine(t.FullName, asm.FullName);
  141. }
  142. }
  143. return asm;
  144. }
  145. }
  146. #endregion
  147. // *******************************************************************
  148. // The following tests excercise options for protogen.exe
  149. // *******************************************************************
  150. [Test]
  151. public void TestProtoFile()
  152. {
  153. string test = new StackFrame(false).GetMethod().Name;
  154. Setup();
  155. using (TempFile source = TempFile.Attach(test + ".cs"))
  156. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  157. {
  158. RunProtoc(0, proto.TempPath);
  159. Assembly a = RunCsc(0, source.TempPath);
  160. //assert that the message type is in the expected namespace
  161. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  162. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  163. //assert that we can find the static descriptor type
  164. a.GetType("nunit.simple." + test, true, true);
  165. }
  166. }
  167. [Test]
  168. public void TestProtoFileWithConflictingType()
  169. {
  170. string test = new StackFrame(false).GetMethod().Name;
  171. Setup();
  172. using (TempFile source = TempFile.Attach(test + ".cs"))
  173. using (
  174. ProtoFile proto = new ProtoFile(test + ".proto",
  175. @"
  176. package nunit.simple;
  177. // Test a very simple message.
  178. message " +
  179. test + @" {
  180. optional string name = 1;
  181. } "))
  182. {
  183. RunProtoc(0, proto.TempPath);
  184. Assembly a = RunCsc(0, source.TempPath);
  185. //assert that the message type is in the expected namespace
  186. Type t = a.GetType("nunit.simple." + test, true, true);
  187. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  188. //assert that we can find the static descriptor type
  189. a.GetType("nunit.simple.Proto." + test, true, true);
  190. }
  191. }
  192. [Test]
  193. public void TestProtoFileWithNamespace()
  194. {
  195. string test = new StackFrame(false).GetMethod().Name;
  196. Setup();
  197. using (TempFile source = TempFile.Attach(test + ".cs"))
  198. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  199. {
  200. RunProtoc(0, proto.TempPath, "-namespace=MyNewNamespace");
  201. Assembly a = RunCsc(0, source.TempPath);
  202. //assert that the message type is in the expected namespace
  203. Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
  204. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  205. //assert that we can find the static descriptor type
  206. a.GetType("MyNewNamespace." + test, true, true);
  207. }
  208. }
  209. [Test]
  210. public void TestProtoFileWithUmbrellaClassName()
  211. {
  212. string test = new StackFrame(false).GetMethod().Name;
  213. Setup();
  214. using (TempFile source = TempFile.Attach("MyUmbrellaClassname.cs"))
  215. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  216. {
  217. RunProtoc(0, proto.TempPath, "/umbrella_classname=MyUmbrellaClassname");
  218. Assembly a = RunCsc(0, source.TempPath);
  219. //assert that the message type is in the expected namespace
  220. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  221. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  222. //assert that we can find the static descriptor type
  223. a.GetType("nunit.simple.MyUmbrellaClassname", true, true);
  224. }
  225. }
  226. [Test]
  227. public void TestProtoFileWithNestedClass()
  228. {
  229. string test = new StackFrame(false).GetMethod().Name;
  230. Setup();
  231. using (TempFile source = TempFile.Attach(test + ".cs"))
  232. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  233. {
  234. RunProtoc(0, proto.TempPath, "-nest_classes=true");
  235. Assembly a = RunCsc(0, source.TempPath);
  236. //assert that the message type is in the expected namespace
  237. Type t = a.GetType("nunit.simple." + test + "+MyMessage", true, true);
  238. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  239. //assert that we can find the static descriptor type
  240. a.GetType("nunit.simple." + test, true, true);
  241. }
  242. }
  243. [Test]
  244. public void TestProtoFileWithExpandedNsDirectories()
  245. {
  246. string test = new StackFrame(false).GetMethod().Name;
  247. Setup();
  248. using (TempFile source = TempFile.Attach(@"nunit\simple\" + test + ".cs"))
  249. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  250. {
  251. RunProtoc(0, proto.TempPath, "-expand_namespace_directories=true");
  252. Assembly a = RunCsc(0, source.TempPath);
  253. //assert that the message type is in the expected namespace
  254. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  255. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  256. //assert that we can find the static descriptor type
  257. a.GetType("nunit.simple." + test, true, true);
  258. }
  259. }
  260. [Test]
  261. public void TestProtoFileWithNewExtension()
  262. {
  263. string test = new StackFrame(false).GetMethod().Name;
  264. Setup();
  265. using (TempFile source = TempFile.Attach(test + ".Generated.cs"))
  266. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  267. {
  268. RunProtoc(0, proto.TempPath, "-file_extension=.Generated.cs");
  269. Assembly a = RunCsc(0, source.TempPath);
  270. //assert that the message type is in the expected namespace
  271. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  272. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  273. //assert that we can find the static descriptor type
  274. a.GetType("nunit.simple." + test, true, true);
  275. }
  276. }
  277. [Test]
  278. public void TestProtoFileWithUmbrellaNamespace()
  279. {
  280. string test = new StackFrame(false).GetMethod().Name;
  281. Setup();
  282. using (TempFile source = TempFile.Attach(test + ".cs"))
  283. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  284. {
  285. RunProtoc(0, proto.TempPath, "-umbrella_namespace=MyUmbrella.Namespace");
  286. Assembly a = RunCsc(0, source.TempPath);
  287. //assert that the message type is in the expected namespace
  288. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  289. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  290. //assert that we can find the static descriptor type
  291. a.GetType("nunit.simple.MyUmbrella.Namespace." + test, true, true);
  292. }
  293. }
  294. [Test]
  295. public void TestProtoFileWithIgnoredUmbrellaNamespaceDueToNesting()
  296. {
  297. string test = new StackFrame(false).GetMethod().Name;
  298. Setup();
  299. using (TempFile source = TempFile.Attach(test + ".cs"))
  300. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  301. {
  302. RunProtoc(0, proto.TempPath, "-nest_classes=true", "-umbrella_namespace=MyUmbrella.Namespace");
  303. Assembly a = RunCsc(0, source.TempPath);
  304. //assert that the message type is in the expected namespace
  305. Type t = a.GetType("nunit.simple." + test + "+MyMessage", true, true);
  306. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  307. //assert that we can find the static descriptor type
  308. a.GetType("nunit.simple." + test, true, true);
  309. }
  310. }
  311. [Test]
  312. public void TestProtoFileWithExplicitEmptyUmbrellaNamespace()
  313. {
  314. string test = new StackFrame(false).GetMethod().Name;
  315. Setup();
  316. using (TempFile source = TempFile.Attach(test + ".cs"))
  317. using (
  318. ProtoFile proto = new ProtoFile(test + ".proto",
  319. @"
  320. package nunit.simple;
  321. // Test a very simple message.
  322. message " +
  323. test + @" {
  324. optional string name = 1;
  325. } "))
  326. {
  327. //Forces the umbrella class to not use a namespace even if a collision with a type is detected.
  328. RunProtoc(0, proto.TempPath, "-umbrella_namespace=");
  329. //error CS0441: 'nunit.simple.TestProtoFileWithExplicitEmptyUmbrellaNamespace': a class cannot be both static and sealed
  330. RunCsc(1, source.TempPath);
  331. }
  332. }
  333. [Test]
  334. public void TestProtoFileWithNewOutputFolder()
  335. {
  336. string test = new StackFrame(false).GetMethod().Name;
  337. Setup();
  338. using (TempFile source = TempFile.Attach(@"generated-code\" + test + ".cs"))
  339. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  340. {
  341. RunProtoc(1, proto.TempPath, "-output_directory=generated-code");
  342. Directory.CreateDirectory("generated-code");
  343. RunProtoc(0, proto.TempPath, "-output_directory=generated-code");
  344. Assembly a = RunCsc(0, source.TempPath);
  345. //assert that the message type is in the expected namespace
  346. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  347. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  348. //assert that we can find the static descriptor type
  349. a.GetType("nunit.simple." + test, true, true);
  350. }
  351. }
  352. [Test]
  353. public void TestProtoFileAndIgnoreGoogleProtobuf()
  354. {
  355. string test = new StackFrame(false).GetMethod().Name;
  356. Setup();
  357. using (TempFile source = TempFile.Attach(test + ".cs"))
  358. using (
  359. ProtoFile proto = new ProtoFile(test + ".proto",
  360. @"
  361. import ""google/protobuf/csharp_options.proto"";
  362. option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
  363. " +
  364. DefaultProto))
  365. {
  366. string google = Path.Combine(TempPath, "google\\protobuf");
  367. Directory.CreateDirectory(google);
  368. foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
  369. {
  370. File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
  371. }
  372. Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
  373. RunProtoc(0, proto.TempPath);
  374. Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
  375. Assembly a = RunCsc(0, source.TempPath);
  376. //assert that the message type is in the expected namespace
  377. Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
  378. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  379. //assert that we can find the static descriptor type
  380. a.GetType("MyNewNamespace." + test, true, true);
  381. }
  382. }
  383. [Test]
  384. public void TestProtoFileWithoutIgnoreGoogleProtobuf()
  385. {
  386. string test = new StackFrame(false).GetMethod().Name;
  387. Setup();
  388. using (TempFile source = TempFile.Attach(test + ".cs"))
  389. using (
  390. ProtoFile proto = new ProtoFile(test + ".proto",
  391. @"
  392. import ""google/protobuf/csharp_options.proto"";
  393. option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
  394. " +
  395. DefaultProto))
  396. {
  397. string google = Path.Combine(TempPath, "google\\protobuf");
  398. Directory.CreateDirectory(google);
  399. foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
  400. {
  401. File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
  402. }
  403. Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
  404. //Without the option this fails due to being unable to resolve google/protobuf descriptors
  405. RunProtoc(0, proto.TempPath);
  406. }
  407. }
  408. // *******************************************************************
  409. // The following tests excercise options for protoc.exe
  410. // *******************************************************************
  411. [Test]
  412. public void TestProtoFileWithIncludeImports()
  413. {
  414. string test = new StackFrame(false).GetMethod().Name;
  415. Setup();
  416. using (TempFile source = TempFile.Attach(test + ".cs"))
  417. using (
  418. ProtoFile proto = new ProtoFile(test + ".proto",
  419. @"
  420. import ""google/protobuf/csharp_options.proto"";
  421. option (google.protobuf.csharp_file_options).namespace = ""MyNewNamespace"";
  422. package nunit.simple;
  423. // Test a very simple message.
  424. message MyMessage {
  425. optional string name = 1;
  426. } ")
  427. )
  428. {
  429. string google = Path.Combine(TempPath, "google\\protobuf");
  430. Directory.CreateDirectory(google);
  431. foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
  432. {
  433. File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
  434. }
  435. Assert.AreEqual(0, Directory.GetFiles(TempPath, "*.cs").Length);
  436. //if you specify the protoc option --include_imports this should build three source files
  437. RunProtoc(0, proto.TempPath);
  438. Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
  439. //you can (and should) simply omit the inclusion of the extra source files in your project
  440. Assembly a = RunCsc(0, source.TempPath);
  441. //assert that the message type is in the expected namespace
  442. Type t = a.GetType("MyNewNamespace.MyMessage", true, true);
  443. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  444. //assert that we can find the static descriptor type
  445. a.GetType("MyNewNamespace." + test, true, true);
  446. }
  447. }
  448. //Seems the --proto_path or -I option is non-functional for me. Maybe others have luck?
  449. [Test]
  450. public void TestProtoFileInDifferentDirectory()
  451. {
  452. string test = new StackFrame(false).GetMethod().Name;
  453. Setup();
  454. using (TempFile source = TempFile.Attach(test + ".cs"))
  455. using (ProtoFile proto = new ProtoFile(test + ".proto", DefaultProto))
  456. {
  457. Environment.CurrentDirectory = OriginalWorkingDirectory;
  458. RunProtoc(0, proto.TempPath);
  459. Assembly a = RunCsc(0, source.TempPath);
  460. //assert that the message type is in the expected namespace
  461. Type t = a.GetType("nunit.simple.MyMessage", true, true);
  462. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t), "Expect an IMessage");
  463. //assert that we can find the static descriptor type
  464. a.GetType("nunit.simple." + test, true, true);
  465. }
  466. }
  467. // *******************************************************************
  468. // Handling of mutliple input files
  469. // *******************************************************************
  470. [Test]
  471. public void TestMultipleProtoFiles()
  472. {
  473. Setup();
  474. using (TempFile source1 = TempFile.Attach("MyMessage.cs"))
  475. using (
  476. ProtoFile proto1 = new ProtoFile("MyMessage.proto",
  477. @"
  478. package nunit.simple;
  479. // Test a very simple message.
  480. message MyMessage {
  481. optional string name = 1;
  482. }")
  483. )
  484. using (TempFile source2 = TempFile.Attach("MyMessageList.cs"))
  485. using (
  486. ProtoFile proto2 = new ProtoFile("MyMessageList.proto",
  487. @"
  488. package nunit.simple;
  489. import ""MyMessage.proto"";
  490. // Test a very simple message.
  491. message MyMessageList {
  492. repeated MyMessage messages = 1;
  493. }")
  494. )
  495. {
  496. RunProtoc(0, proto1.TempPath);
  497. RunProtoc(0, proto2.TempPath);
  498. Assembly a = RunCsc(0, source1.TempPath, source2.TempPath);
  499. //assert that the message type is in the expected namespace
  500. Type t1 = a.GetType("nunit.simple.MyMessage", true, true);
  501. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t1), "Expect an IMessage");
  502. //assert that the message type is in the expected namespace
  503. Type t2 = a.GetType("nunit.simple.MyMessageList", true, true);
  504. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t2), "Expect an IMessage");
  505. //assert that we can find the static descriptor type
  506. a.GetType("nunit.simple.Proto.MyMessage", true, true);
  507. a.GetType("nunit.simple.Proto.MyMessageList", true, true);
  508. }
  509. }
  510. [Test]
  511. public void TestOneProtoFileWithBufferFile()
  512. {
  513. Setup();
  514. using (TempFile source1 = TempFile.Attach("MyMessage.cs"))
  515. using (
  516. ProtoFile proto1 = new ProtoFile("MyMessage.proto",
  517. @"
  518. package nunit.simple;
  519. // Test a very simple message.
  520. message MyMessage {
  521. optional string name = 1;
  522. }")
  523. )
  524. using (TempFile source2 = TempFile.Attach("MyMessageList.cs"))
  525. using (
  526. ProtoFile proto2 = new ProtoFile("MyMessageList.proto",
  527. @"
  528. package nunit.simple;
  529. import ""MyMessage.proto"";
  530. // Test a very simple message.
  531. message MyMessageList {
  532. repeated MyMessage messages = 1;
  533. }")
  534. )
  535. {
  536. //build the proto buffer for MyMessage
  537. RunProtoc(0, proto1.TempPath);
  538. //build the MyMessageList proto-buffer and generate code by including MyMessage.pb
  539. RunProtoc(0, proto2.TempPath);
  540. Assembly a = RunCsc(0, source1.TempPath, source2.TempPath);
  541. //assert that the message type is in the expected namespace
  542. Type t1 = a.GetType("nunit.simple.MyMessage", true, true);
  543. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t1), "Expect an IMessage");
  544. //assert that the message type is in the expected namespace
  545. Type t2 = a.GetType("nunit.simple.MyMessageList", true, true);
  546. Assert.IsTrue(typeof(IMessage).IsAssignableFrom(t2), "Expect an IMessage");
  547. //assert that we can find the static descriptor type
  548. a.GetType("nunit.simple.Proto.MyMessage", true, true);
  549. a.GetType("nunit.simple.Proto.MyMessageList", true, true);
  550. }
  551. }
  552. [Test]
  553. public void TestProtoFileWithService()
  554. {
  555. string test = new StackFrame(false).GetMethod().Name;
  556. Setup();
  557. using (TempFile source = TempFile.Attach(test + ".cs"))
  558. using (ProtoFile proto = new ProtoFile(test + ".proto",
  559. @"
  560. import ""google/protobuf/csharp_options.proto"";
  561. option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;
  562. package nunit.simple;
  563. // Test a very simple message.
  564. message MyMessage {
  565. optional string name = 1;
  566. }
  567. // test a very simple service.
  568. service TestService {
  569. rpc Execute (MyMessage) returns (MyMessage);
  570. }"))
  571. {
  572. CopyInGoogleProtoFiles();
  573. RunProtoc(0, proto.TempPath, "-nest_classes=false");
  574. Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
  575. Assembly a = RunCsc(0, source.TempPath);
  576. //assert that the service type is in the expected namespace
  577. Type t1 = a.GetType("nunit.simple.TestService", true, true);
  578. Assert.IsTrue(typeof(IService).IsAssignableFrom(t1), "Expect an IService");
  579. Assert.IsTrue(t1.IsAbstract, "Expect abstract class");
  580. //assert that the Stub subclass type is in the expected namespace
  581. Type t2 = a.GetType("nunit.simple.TestService+Stub", true, true);
  582. Assert.IsTrue(t1.IsAssignableFrom(t2), "Expect a sub of TestService");
  583. Assert.IsFalse(t2.IsAbstract, "Expect concrete class");
  584. }
  585. }
  586. [Test]
  587. public void TestProtoFileWithServiceInternal()
  588. {
  589. string test = new StackFrame(false).GetMethod().Name;
  590. Setup();
  591. using (TempFile source = TempFile.Attach(test + ".cs"))
  592. using (ProtoFile proto = new ProtoFile(test + ".proto",
  593. @"
  594. import ""google/protobuf/csharp_options.proto"";
  595. option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;
  596. package nunit.simple;
  597. // Test a very simple message.
  598. message MyMessage {
  599. optional string name = 1;
  600. }
  601. // test a very simple service.
  602. service TestService {
  603. rpc Execute (MyMessage) returns (MyMessage);
  604. }"))
  605. {
  606. CopyInGoogleProtoFiles();
  607. RunProtoc(0, proto.TempPath, "-nest_classes=false", "-public_classes=false");
  608. Assert.AreEqual(1, Directory.GetFiles(TempPath, "*.cs").Length);
  609. Assembly a = RunCsc(0, source.TempPath);
  610. //assert that the service type is in the expected namespace
  611. Type t1 = a.GetType("nunit.simple.TestService", true, true);
  612. Assert.IsTrue(typeof(IService).IsAssignableFrom(t1), "Expect an IService");
  613. Assert.IsTrue(t1.IsAbstract, "Expect abstract class");
  614. //assert that the Stub subclass type is in the expected namespace
  615. Type t2 = a.GetType("nunit.simple.TestService+Stub", true, true);
  616. Assert.IsTrue(t1.IsAssignableFrom(t2), "Expect a sub of TestService");
  617. Assert.IsFalse(t2.IsAbstract, "Expect concrete class");
  618. }
  619. }
  620. private static void CopyInGoogleProtoFiles()
  621. {
  622. string google = Path.Combine(TempPath, "google\\protobuf");
  623. Directory.CreateDirectory(google);
  624. foreach (string file in Directory.GetFiles(Path.Combine(OriginalWorkingDirectory, "google\\protobuf")))
  625. {
  626. File.Copy(file, Path.Combine(google, Path.GetFileName(file)));
  627. }
  628. }
  629. }
  630. }