mummy  1.0.3
MummyCsharpUnitTestGenerator.cxx
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // $Id: MummyCsharpUnitTestGenerator.cxx 2 2007-12-17 18:15:56Z david.cole $
4 //
5 // $Author: david.cole $
6 // $Date: 2007-12-17 13:15:56 -0500 (Mon, 17 Dec 2007) $
7 // $Revision: 2 $
8 //
9 // Copyright (C) 2006-2007 Kitware, Inc.
10 //
11 //----------------------------------------------------------------------------
12 
14 #include "MummyCsharpGenerator.h"
15 #include "MummyLog.h"
16 #include "MummySettings.h"
17 
18 #include "cableClass.h"
19 #include "cableClassType.h"
20 #include "cableFunctionType.h"
21 #include "cableMethod.h"
22 #include "cablePointerType.h"
23 #include "cableReferenceType.h"
24 #include "cxxCvQualifiedType.h"
25 #include "cxxFunctionType.h"
26 #include "cxxPointerType.h"
27 
28 #include "gxsys/stl/algorithm"
29 #include "gxsys/SystemTools.hxx"
30 
31 
32 //----------------------------------------------------------------------------
34 {
35  this->CsharpGenerator = 0;
36 }
37 
38 
39 //----------------------------------------------------------------------------
41 {
42 }
43 
44 
45 //----------------------------------------------------------------------------
47 {
48  this->EmitClass(*GetStream(), GetTargetClass());
49  return false;
50 }
51 
52 
53 //----------------------------------------------------------------------------
55 {
56  return this->CsharpGenerator;
57 }
58 
59 
60 //----------------------------------------------------------------------------
62 {
63  this->CsharpGenerator = generator;
64 }
65 
66 
67 //----------------------------------------------------------------------------
68 //bool MummyCsharpUnitTestGenerator::FundamentalTypeIsWrappable(const cable::Type* t)
69 //{
70 // return this->GetCsharpGenerator()->FundamentalTypeIsWrappable(t);
71 //}
72 
73 
74 //----------------------------------------------------------------------------
75 //bool MummyCsharpUnitTestGenerator::TypeIsWrappable(const cable::Type* t)
76 //{
77 // return this->GetCsharpGenerator()->TypeIsWrappable(t);
78 //}
79 
80 
81 //----------------------------------------------------------------------------
82 //bool MummyCsharpUnitTestGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft)
83 //{
84 // return this->GetCsharpGenerator()->FunctionTypeIsWrappable(ft);
85 //}
86 
87 
88 //----------------------------------------------------------------------------
89 //bool MummyCsharpUnitTestGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access)
90 //{
91 // return this->GetCsharpGenerator()->MethodIsWrappable(m, access);
92 //}
93 
94 
95 //----------------------------------------------------------------------------
96 //bool MummyCsharpUnitTestGenerator::ClassIsWrappable(const cable::Class* c)
97 //{
98 // return this->GetCsharpGenerator()->ClassIsWrappable(c);
99 //}
100 
101 
102 //----------------------------------------------------------------------------
103 const char *MummyCsharpUnitTestGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i)
104 {
105  return this->GetCsharpGenerator()->GetArgName(ftype, i);
106 }
107 
108 
109 //----------------------------------------------------------------------------
110 void MummyCsharpUnitTestGenerator::EmitCSharpFactoryMethodUnitTest(gxsys_ios::ostream &os, const cable::Class *)
111 {
112  Emit(os, "// EmitCSharpFactoryMethodUnitTest\n");
113 }
114 
115 
116 //----------------------------------------------------------------------------
117 void MummyCsharpUnitTestGenerator::EmitCSharpMethodUnitTest(gxsys_ios::ostream &os, const cable::Class *, const cable::Method*)
118 {
119  Emit(os, "// EmitCSharpMethodUnitTest\n");
120 }
121 
122 
123 //----------------------------------------------------------------------------
124 void MummyCsharpUnitTestGenerator::EmitCSharpPropertyUnitTest(gxsys_ios::ostream &os, const cable::Class *, const cable::Method*, const cable::Method*)
125 {
126  Emit(os, "// EmitCSharpPropertyUnitTest\n");
127 }
128 
129 
130 //----------------------------------------------------------------------------
131 void MummyCsharpUnitTestGenerator::EmitCSharpStructMemberAccessUnitTest(gxsys_ios::ostream &os, const cable::Class *)
132 {
133  Emit(os, "// EmitCSharpStructMemberAccessUnitTest\n");
134 }
135 
136 
137 //----------------------------------------------------------------------------
138 void MummyCsharpUnitTestGenerator::EmitClass(gxsys_ios::ostream &os, const cable::Class *c)
139 {
140  // Gather wrapped elements:
141  //
142  gxsys_stl::vector<cable::Method*> wrapped_methods;
143  gxsys_stl::vector<cable::Method*>::iterator mit;
144  cable::Method *factoryM = 0;
145  cable::Method *disposalM = 0;
146  cable::Method *registerM = 0;
147  cable::Method *unRegisterM = 0;
148  bool verbose = this->GetSettings()->GetVerbose();
149  gxsys_stl::string atts(c->GetAttributes());
150 
151 
152  // The "package" directive from the gccxml input is used as a base
153  // namespace. If it's not empty, prepend it to the class's namespace.
154  //
155  gxsys_stl::string target_namespace;
156  gxsys_stl::string base_namespace(this->GetSettings()->GetPackage());
157  gxsys_stl::string class_namespace(GetFullyQualifiedNameForCSharp(c->GetContext()));
158 
159  // C++ global scope means "no namespace please"
160  //
161  if (class_namespace == "::")
162  {
163  class_namespace = "";
164  }
165 
166  if (base_namespace == "")
167  {
168  target_namespace = class_namespace;
169  }
170  else if (class_namespace == "")
171  {
172  target_namespace = base_namespace;
173  }
174  else
175  {
176  target_namespace = base_namespace + "." + class_namespace;
177  }
178 
179  if (target_namespace != "")
180  {
181  target_namespace = target_namespace + ".UnitTests";
182  }
183 
184 
185  // Emit code:
186  //
187  EmitMummyVersionComments(os, "//");
188 
189 
190  // If the class maps directly to a builtin type, then DO NOT emit any code.
191  //
192  gxsys_stl::string mapToType = ExtractMapToType(c);
193  if (mapToType != "")
194  {
195  Emit(os, "\n");
196  Emit(os, "//----------------------------------------------------------------------------\n");
197  Emit(os, "// Unmanaged class '");
198  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
199  Emit(os, "' maps directly to type '");
200  Emit(os, mapToType.c_str());
201  Emit(os, "'.\n");
202  Emit(os, "// No code generated for '");
203  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
204  Emit(os, "'...\n");
205 
206  if (verbose)
207  {
208  LogInfo(mi_VerboseInfo, << "Skipping code generation because class maps directly to native type.");
209  }
210 
211  return;
212  }
213 
214 
215  Emit(os, "\n");
216  Emit(os, "//----------------------------------------------------------------------------\n");
217  Emit(os, "using System;\n");
218  Emit(os, "using System.Runtime.InteropServices; // DllImport and HandleRef both live here\n");
219  Emit(os, "\n");
220 
221 
222  // If this project depends on "using" any other C# namespaces, they will be listed
223  // as "Reference" elements in MummySettings.xml...
224  //
225  gxsys_stl::vector<gxsys_stl::string> refs;
226  this->GetSettings()->GetReferences(refs);
227  if (refs.size())
228  {
229  Emit(os, "// References\n");
230  gxsys_stl::vector<gxsys_stl::string>::iterator rit;
231  for (rit = refs.begin(); rit != refs.end(); ++rit)
232  {
233  Emit(os, "using ");
234  Emit(os, rit->c_str());
235  Emit(os, ";\n");
236  }
237  Emit(os, "\n");
238  }
239 
240 
241  // Open the (optional) namespace:
242  //
243  if (target_namespace != "")
244  {
245  Emit(os, "namespace ");
246  Emit(os, target_namespace.c_str());
247  Emit(os, "\n");
248  Emit(os, "{\n");
249  Emit(os, "\n");
250  }
251 
252 
253  // Documentation:
254  //
255  Emit(os, "/// <summary>\n");
256  Emit(os, "/// Automatically generated unit test\n");
257  Emit(os, "/// </summary>\n");
258 
259 
260  if (IsUtilityClass(c))
261  {
262  // Utility classes get wrapped as structs:
263  //
265  }
266  else
267  {
268  if (verbose)
269  {
270  LogInfo(mi_VerboseInfo, << "Calling GatherWrappedMethods...");
271  }
272 
273  this->GetCsharpGenerator()->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false);
274 
275 
276  // Filter out prop gets and sets, putting them in their very own data structure.
277  // Key in the map is the name of the property. 1st method in pair is propget,
278  // 2nd method is propset.
279  //
280  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> > wrapped_properties;
281  this->GetCsharpGenerator()->BuildPropGetsAndSetsMap(wrapped_methods, wrapped_properties);
282 
283  // Now remove any entries found in the props *map* from the methods *vector*.
284  // Otherwise, we'd end up with all of the properties "repeated" as methods, too.
285  //
286  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit;
287  for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit)
288  {
289  if (gsit->second.first)
290  {
291  mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(),
292  gsit->second.first);
293  if (mit != wrapped_methods.end())
294  {
295  wrapped_methods.erase(mit);
296  }
297  else
298  {
299  LogWarning(mw_InternalWarning, << "Unexpected unfound propget method...");
300  }
301  }
302 
303  if (gsit->second.second)
304  {
305  mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(),
306  gsit->second.second);
307  if (mit != wrapped_methods.end())
308  {
309  wrapped_methods.erase(mit);
310  }
311  else
312  {
313  LogWarning(mw_InternalWarning, << "Unexpected unfound propset method...");
314  }
315  }
316  }
317 
318 
319  // Class declaration:
320  //
321  Emit(os, "public ");
322 // if (c->GetAbstract())
323 // {
324 // Emit(os, "abstract ");
325 // }
326  Emit(os, "class ");
327  Emit(os, GetWrappedClassName(c).c_str());
328  Emit(os, "UnitTest");
329 
330  Emit(os, "\n");
331 
332 
333  // Open class:
334  //
335  Emit(os, "{\n");
336 
337 
338  // Factory method test:
339  //
340  if (factoryM || this->GetSettings()->GetUseShadow(c))
341  {
342  Emit(os, "\n");
343  Emit(os, "\n");
345  }
346 
347 
348  // Properties:
349  //
350  for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit)
351  {
352  Emit(os, "\n");
353  Emit(os, "\n");
354  EmitCSharpPropertyUnitTest(os, c, gsit->second.first, gsit->second.second);
355  }
356 
357 
358  // Plain old methods:
359  //
360  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
361  {
362  Emit(os, "\n");
363  Emit(os, "\n");
364  EmitCSharpMethodUnitTest(os, c, *mit);
365  }
366  }
367 
368 
369  // Hand written shtuff:
370  //
371  // If there is extraCSharpCode, emit it *within* the class definition.
372  // If it's there, it's the name of a file that we are to include in
373  // its entirety...
374  //
375  gxsys_stl::string extraCode = this->GetSettings()->GetExtraCsharpUnitTestCode(c);
376  if (extraCode != "")
377  {
378  Emit(os, "\n");
379  Emit(os, "\n");
380  Emit(os, "// Begin extraCSharpCode\n");
381  Emit(os, "\n");
382  EmitFile(os, extraCode.c_str());
383  Emit(os, "\n");
384  Emit(os, "// End extraCSharpCode\n");
385  Emit(os, "\n");
386  }
387 
388 
389  // Close the struct/class:
390  //
391  Emit(os, "}\n");
392 
393 
394  // Close the namespace:
395  //
396  if (target_namespace != "")
397  {
398  Emit(os, "\n");
399  Emit(os, "}\n");
400  }
401 }