2010-03-25 8 views
4

J'ai un test nunit en C#, qui appelle un wrapper C# d'une fonction dans une DLL C++. Le code C++ utilise std :: cerr pour générer divers messages.NUnit ne capture pas la sortie de std :: cerr

Ces messages ne peuvent pas être redirigés à l'aide du commutateur nunit-console/out/err ou/xml. En nunit (la version GUI), la sortie n'apparaît nulle part.

Je voudrais être en mesure de voir cette sortie dans nunit (version GUI). Idéalement, j'aimerais pouvoir accéder à cette sortie dans le test.

Merci pour toute aide.

+0

J'ai aussi un problème similaire. Pire encore, c'est que j'utilise std :: wcerr et std :: wcout pour sortir en console ou dans un fichier journal en fonction d'un drapeau .. mais aucun d'entre eux ne fonctionne depuis NUnit, mais ils fonctionnent depuis mon programme C# .. –

Répondre

1

Rediriger std :: cerr consiste à remplacer le tampon de flux par le vôtre. Il est important de restaurer dans le tampon d'origine avant de quitter. Je ne sais pas à quoi ressemble votre wrapper, mais vous pouvez probablement comprendre comment le faire lire output.str().

#include <iostream> 
#include <sstream> 
#include <cassert> 

using namespace std; 

int main() 
{ 
    streambuf* buf(cerr.rdbuf()); 
    stringstream output; 

    cerr.rdbuf(output.rdbuf()); 
    cerr << "Hello, world!" << endl; 

    assert(output.str() == "Hello, world!\n"); 
    cerr.rdbuf(buf); 

    return 0; 
} 
+0

Voir mon autre 'réponse' pour ce que j'ai fait avec ceci. – Richard

1

Merci pour l'indice. C'est ce que je fini par faire:

fichier .CPP ------------------------

#include <iostream> 
#include <sstream> 

static std::stringstream buffer; 
static std::streambuf * savedBuffer = NULL; 


extern "C" __declspec(dllexport) bool Redirect() 
{ 
    if (savedBuffer) 
    { 
     return false; 
    } 
    std::streambuf * buf(std::cerr.rdbuf()); 
    std::cerr.rdbuf(buffer.rdbuf()); 

    // This two lines are for illustration purposes only! 
    std::cerr << "Hello world" << std::endl; 

    return true; 
} 


extern "C" __declspec(dllexport) void Revert() 
{ 
    if (savedBuffer) 
    { 
     std::cerr.rdbuf(savedBuffer); 
    } 
    savedBuffer = NULL; 
} 


extern "C" __declspec(dllexport) const char * getCerr() 
{ 
    return _strdup(buffer.str().c_str()); 
} 

extern "C" __declspec(dllexport) void freeCharPtr(char *ptr) 
{ 
    free(ptr); 
} 

fichier .CS ------------------------------------------

public static class Redirector 
{ 
    // PRIVATE ------------------------------------------------------------ 
    private const String LibraryName = "MyCpp.dll"; 

    [DllImport(LibraryName, CharSet = CharSet.Ansi)] 
    private static extern IntPtr getCerr(); 

    // PUBLIC ------------------------------------------------------------- 
    [DllImport(LibraryName, CharSet = CharSet.Ansi)] 
    public static extern bool Redirect(); 

    [DllImport(LibraryName, CharSet = CharSet.Ansi)] 
    public static extern void Revert(); 

    [DllImport(LibraryName, CharSet = CharSet.Ansi)] 
    internal static extern void freeCharPtr(IntPtr ptr); 

    public static string GetCerr() 
    { 
     IntPtr temp = getCerr(); 
     string result = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(temp); 
     freeCharPtr(temp); 
     return result; 
    } 
} 

NUnit test -----------------------

[Test] 
    // [Ignore] 
    public void TestRedirect() 
    { 
     Redirector.Redirect(); 
     // Call more functions that output to std::cerr here. 
     Redirector.Revert(); 
     System.Console.WriteLine(Redirector.GetCerr()); 
    } 

Le truc freeCharPtr() est nécessaire pour libérer la mémoire allouée de _strdup(), puisque je n'ai pas pu mettre au point (si c'est possible) comment marier une chaîne std ::.

Remarque: Ceci n'est pas sûr pour les threads!

Questions connexes