mummy  1.0.2
MummyCsharpUnitTestGenerator.cxx
Go to the documentation of this file.
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 }