mummy
1.0.2
|
00001 //---------------------------------------------------------------------------- 00002 // 00003 // $Id: MummyCsharpUnitTestGenerator.cxx 2 2007-12-17 18:15:56Z david.cole $ 00004 // 00005 // $Author: david.cole $ 00006 // $Date: 2007-12-17 13:15:56 -0500 (Mon, 17 Dec 2007) $ 00007 // $Revision: 2 $ 00008 // 00009 // Copyright (C) 2006-2007 Kitware, Inc. 00010 // 00011 //---------------------------------------------------------------------------- 00012 00013 #include "MummyCsharpUnitTestGenerator.h" 00014 #include "MummyCsharpGenerator.h" 00015 #include "MummyLog.h" 00016 #include "MummySettings.h" 00017 00018 #include "cableClass.h" 00019 #include "cableClassType.h" 00020 #include "cableFunctionType.h" 00021 #include "cableMethod.h" 00022 #include "cablePointerType.h" 00023 #include "cableReferenceType.h" 00024 #include "cxxCvQualifiedType.h" 00025 #include "cxxFunctionType.h" 00026 #include "cxxPointerType.h" 00027 00028 #include "gxsys/stl/algorithm" 00029 #include "gxsys/SystemTools.hxx" 00030 00031 00032 //---------------------------------------------------------------------------- 00033 MummyCsharpUnitTestGenerator::MummyCsharpUnitTestGenerator() 00034 { 00035 this->CsharpGenerator = 0; 00036 } 00037 00038 00039 //---------------------------------------------------------------------------- 00040 MummyCsharpUnitTestGenerator::~MummyCsharpUnitTestGenerator() 00041 { 00042 } 00043 00044 00045 //---------------------------------------------------------------------------- 00046 bool MummyCsharpUnitTestGenerator::GenerateWrappers() 00047 { 00048 this->EmitClass(*GetStream(), GetTargetClass()); 00049 return false; 00050 } 00051 00052 00053 //---------------------------------------------------------------------------- 00054 MummyCsharpGenerator* MummyCsharpUnitTestGenerator::GetCsharpGenerator() 00055 { 00056 return this->CsharpGenerator; 00057 } 00058 00059 00060 //---------------------------------------------------------------------------- 00061 void MummyCsharpUnitTestGenerator::SetCsharpGenerator(MummyCsharpGenerator* generator) 00062 { 00063 this->CsharpGenerator = generator; 00064 } 00065 00066 00067 //---------------------------------------------------------------------------- 00068 //bool MummyCsharpUnitTestGenerator::FundamentalTypeIsWrappable(const cable::Type* t) 00069 //{ 00070 // return this->GetCsharpGenerator()->FundamentalTypeIsWrappable(t); 00071 //} 00072 00073 00074 //---------------------------------------------------------------------------- 00075 //bool MummyCsharpUnitTestGenerator::TypeIsWrappable(const cable::Type* t) 00076 //{ 00077 // return this->GetCsharpGenerator()->TypeIsWrappable(t); 00078 //} 00079 00080 00081 //---------------------------------------------------------------------------- 00082 //bool MummyCsharpUnitTestGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft) 00083 //{ 00084 // return this->GetCsharpGenerator()->FunctionTypeIsWrappable(ft); 00085 //} 00086 00087 00088 //---------------------------------------------------------------------------- 00089 //bool MummyCsharpUnitTestGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access) 00090 //{ 00091 // return this->GetCsharpGenerator()->MethodIsWrappable(m, access); 00092 //} 00093 00094 00095 //---------------------------------------------------------------------------- 00096 //bool MummyCsharpUnitTestGenerator::ClassIsWrappable(const cable::Class* c) 00097 //{ 00098 // return this->GetCsharpGenerator()->ClassIsWrappable(c); 00099 //} 00100 00101 00102 //---------------------------------------------------------------------------- 00103 const char *MummyCsharpUnitTestGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i) 00104 { 00105 return this->GetCsharpGenerator()->GetArgName(ftype, i); 00106 } 00107 00108 00109 //---------------------------------------------------------------------------- 00110 void MummyCsharpUnitTestGenerator::EmitCSharpFactoryMethodUnitTest(gxsys_ios::ostream &os, const cable::Class *) 00111 { 00112 Emit(os, "// EmitCSharpFactoryMethodUnitTest\n"); 00113 } 00114 00115 00116 //---------------------------------------------------------------------------- 00117 void MummyCsharpUnitTestGenerator::EmitCSharpMethodUnitTest(gxsys_ios::ostream &os, const cable::Class *, const cable::Method*) 00118 { 00119 Emit(os, "// EmitCSharpMethodUnitTest\n"); 00120 } 00121 00122 00123 //---------------------------------------------------------------------------- 00124 void MummyCsharpUnitTestGenerator::EmitCSharpPropertyUnitTest(gxsys_ios::ostream &os, const cable::Class *, const cable::Method*, const cable::Method*) 00125 { 00126 Emit(os, "// EmitCSharpPropertyUnitTest\n"); 00127 } 00128 00129 00130 //---------------------------------------------------------------------------- 00131 void MummyCsharpUnitTestGenerator::EmitCSharpStructMemberAccessUnitTest(gxsys_ios::ostream &os, const cable::Class *) 00132 { 00133 Emit(os, "// EmitCSharpStructMemberAccessUnitTest\n"); 00134 } 00135 00136 00137 //---------------------------------------------------------------------------- 00138 void MummyCsharpUnitTestGenerator::EmitClass(gxsys_ios::ostream &os, const cable::Class *c) 00139 { 00140 // Gather wrapped elements: 00141 // 00142 gxsys_stl::vector<cable::Method*> wrapped_methods; 00143 gxsys_stl::vector<cable::Method*>::iterator mit; 00144 cable::Method *factoryM = 0; 00145 cable::Method *disposalM = 0; 00146 cable::Method *registerM = 0; 00147 cable::Method *unRegisterM = 0; 00148 bool verbose = this->GetSettings()->GetVerbose(); 00149 gxsys_stl::string atts(c->GetAttributes()); 00150 00151 00152 // The "package" directive from the gccxml input is used as a base 00153 // namespace. If it's not empty, prepend it to the class's namespace. 00154 // 00155 gxsys_stl::string target_namespace; 00156 gxsys_stl::string base_namespace(this->GetSettings()->GetPackage()); 00157 gxsys_stl::string class_namespace(GetFullyQualifiedNameForCSharp(c->GetContext())); 00158 00159 // C++ global scope means "no namespace please" 00160 // 00161 if (class_namespace == "::") 00162 { 00163 class_namespace = ""; 00164 } 00165 00166 if (base_namespace == "") 00167 { 00168 target_namespace = class_namespace; 00169 } 00170 else if (class_namespace == "") 00171 { 00172 target_namespace = base_namespace; 00173 } 00174 else 00175 { 00176 target_namespace = base_namespace + "." + class_namespace; 00177 } 00178 00179 if (target_namespace != "") 00180 { 00181 target_namespace = target_namespace + ".UnitTests"; 00182 } 00183 00184 00185 // Emit code: 00186 // 00187 EmitMummyVersionComments(os, "//"); 00188 00189 00190 // If the class maps directly to a builtin type, then DO NOT emit any code. 00191 // 00192 gxsys_stl::string mapToType = ExtractMapToType(c); 00193 if (mapToType != "") 00194 { 00195 Emit(os, "\n"); 00196 Emit(os, "//----------------------------------------------------------------------------\n"); 00197 Emit(os, "// Unmanaged class '"); 00198 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00199 Emit(os, "' maps directly to type '"); 00200 Emit(os, mapToType.c_str()); 00201 Emit(os, "'.\n"); 00202 Emit(os, "// No code generated for '"); 00203 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 00204 Emit(os, "'...\n"); 00205 00206 if (verbose) 00207 { 00208 LogInfo(mi_VerboseInfo, << "Skipping code generation because class maps directly to native type."); 00209 } 00210 00211 return; 00212 } 00213 00214 00215 Emit(os, "\n"); 00216 Emit(os, "//----------------------------------------------------------------------------\n"); 00217 Emit(os, "using System;\n"); 00218 Emit(os, "using System.Runtime.InteropServices; // DllImport and HandleRef both live here\n"); 00219 Emit(os, "\n"); 00220 00221 00222 // If this project depends on "using" any other C# namespaces, they will be listed 00223 // as "Reference" elements in MummySettings.xml... 00224 // 00225 gxsys_stl::vector<gxsys_stl::string> refs; 00226 this->GetSettings()->GetReferences(refs); 00227 if (refs.size()) 00228 { 00229 Emit(os, "// References\n"); 00230 gxsys_stl::vector<gxsys_stl::string>::iterator rit; 00231 for (rit = refs.begin(); rit != refs.end(); ++rit) 00232 { 00233 Emit(os, "using "); 00234 Emit(os, rit->c_str()); 00235 Emit(os, ";\n"); 00236 } 00237 Emit(os, "\n"); 00238 } 00239 00240 00241 // Open the (optional) namespace: 00242 // 00243 if (target_namespace != "") 00244 { 00245 Emit(os, "namespace "); 00246 Emit(os, target_namespace.c_str()); 00247 Emit(os, "\n"); 00248 Emit(os, "{\n"); 00249 Emit(os, "\n"); 00250 } 00251 00252 00253 // Documentation: 00254 // 00255 Emit(os, "/// <summary>\n"); 00256 Emit(os, "/// Automatically generated unit test\n"); 00257 Emit(os, "/// </summary>\n"); 00258 00259 00260 if (IsUtilityClass(c)) 00261 { 00262 // Utility classes get wrapped as structs: 00263 // 00264 EmitCSharpStructMemberAccessUnitTest(os, c); 00265 } 00266 else 00267 { 00268 if (verbose) 00269 { 00270 LogInfo(mi_VerboseInfo, << "Calling GatherWrappedMethods..."); 00271 } 00272 00273 this->GetCsharpGenerator()->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false); 00274 00275 00276 // Filter out prop gets and sets, putting them in their very own data structure. 00277 // Key in the map is the name of the property. 1st method in pair is propget, 00278 // 2nd method is propset. 00279 // 00280 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> > wrapped_properties; 00281 this->GetCsharpGenerator()->BuildPropGetsAndSetsMap(wrapped_methods, wrapped_properties); 00282 00283 // Now remove any entries found in the props *map* from the methods *vector*. 00284 // Otherwise, we'd end up with all of the properties "repeated" as methods, too. 00285 // 00286 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit; 00287 for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit) 00288 { 00289 if (gsit->second.first) 00290 { 00291 mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(), 00292 gsit->second.first); 00293 if (mit != wrapped_methods.end()) 00294 { 00295 wrapped_methods.erase(mit); 00296 } 00297 else 00298 { 00299 LogWarning(mw_InternalWarning, << "Unexpected unfound propget method..."); 00300 } 00301 } 00302 00303 if (gsit->second.second) 00304 { 00305 mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(), 00306 gsit->second.second); 00307 if (mit != wrapped_methods.end()) 00308 { 00309 wrapped_methods.erase(mit); 00310 } 00311 else 00312 { 00313 LogWarning(mw_InternalWarning, << "Unexpected unfound propset method..."); 00314 } 00315 } 00316 } 00317 00318 00319 // Class declaration: 00320 // 00321 Emit(os, "public "); 00322 // if (c->GetAbstract()) 00323 // { 00324 // Emit(os, "abstract "); 00325 // } 00326 Emit(os, "class "); 00327 Emit(os, GetWrappedClassName(c).c_str()); 00328 Emit(os, "UnitTest"); 00329 00330 Emit(os, "\n"); 00331 00332 00333 // Open class: 00334 // 00335 Emit(os, "{\n"); 00336 00337 00338 // Factory method test: 00339 // 00340 if (factoryM || this->GetSettings()->GetUseShadow(c)) 00341 { 00342 Emit(os, "\n"); 00343 Emit(os, "\n"); 00344 EmitCSharpFactoryMethodUnitTest(os, c); 00345 } 00346 00347 00348 // Properties: 00349 // 00350 for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit) 00351 { 00352 Emit(os, "\n"); 00353 Emit(os, "\n"); 00354 EmitCSharpPropertyUnitTest(os, c, gsit->second.first, gsit->second.second); 00355 } 00356 00357 00358 // Plain old methods: 00359 // 00360 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 00361 { 00362 Emit(os, "\n"); 00363 Emit(os, "\n"); 00364 EmitCSharpMethodUnitTest(os, c, *mit); 00365 } 00366 } 00367 00368 00369 // Hand written shtuff: 00370 // 00371 // If there is extraCSharpCode, emit it *within* the class definition. 00372 // If it's there, it's the name of a file that we are to include in 00373 // its entirety... 00374 // 00375 gxsys_stl::string extraCode = this->GetSettings()->GetExtraCsharpUnitTestCode(c); 00376 if (extraCode != "") 00377 { 00378 Emit(os, "\n"); 00379 Emit(os, "\n"); 00380 Emit(os, "// Begin extraCSharpCode\n"); 00381 Emit(os, "\n"); 00382 EmitFile(os, extraCode.c_str()); 00383 Emit(os, "\n"); 00384 Emit(os, "// End extraCSharpCode\n"); 00385 Emit(os, "\n"); 00386 } 00387 00388 00389 // Close the struct/class: 00390 // 00391 Emit(os, "}\n"); 00392 00393 00394 // Close the namespace: 00395 // 00396 if (target_namespace != "") 00397 { 00398 Emit(os, "\n"); 00399 Emit(os, "}\n"); 00400 } 00401 }