LCOV - code coverage report
Current view: top level - sal/cppunittester - cppunittester.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 97 126 77.0 %
Date: 2015-06-13 12:38:46 Functions: 16 23 69.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #ifdef WNT
      21             : #include <windows.h>
      22             : #endif
      23             : 
      24             : #include <cstdlib>
      25             : #include <iostream>
      26             : #include <string>
      27             : #include <sal/types.h>
      28             : #include "cppunittester/protectorfactory.hxx"
      29             : #include "osl/module.h"
      30             : #include "osl/module.hxx"
      31             : #include "osl/thread.h"
      32             : #include "rtl/process.h"
      33             : #include "rtl/string.h"
      34             : #include "rtl/string.hxx"
      35             : #include "rtl/textcvt.h"
      36             : #include "rtl/ustring.hxx"
      37             : #include "sal/main.h"
      38             : 
      39             : #include "cppunit/CompilerOutputter.h"
      40             : #include "cppunit/Exception.h"
      41             : #include "cppunit/TestFailure.h"
      42             : #include "cppunit/TestResult.h"
      43             : #include "cppunit/TestResultCollector.h"
      44             : #include "cppunit/TestRunner.h"
      45             : #include "cppunit/extensions/TestFactoryRegistry.h"
      46             : #include "cppunit/plugin/PlugInManager.h"
      47             : #include "cppunit/plugin/DynamicLibraryManagerException.h"
      48             : #include "cppunit/portability/Stream.h"
      49             : 
      50             : #include "boost/noncopyable.hpp"
      51             : #include <boost/scoped_array.hpp>
      52             : #include <boost/algorithm/string.hpp>
      53             : 
      54             : #include <algorithm>
      55             : 
      56             : namespace {
      57             : 
      58           0 : void usageFailure() {
      59             :     std::cerr
      60             :         << ("Usage: cppunittester (--protector <shared-library-path>"
      61           0 :             " <function-symbol>)* <shared-library-path>")
      62           0 :         << std::endl;
      63           0 :     std::exit(EXIT_FAILURE);
      64             : }
      65             : 
      66        1514 : rtl::OUString getArgument(sal_Int32 index) {
      67        1514 :     rtl::OUString arg;
      68        1514 :     rtl_getAppCommandArg(index, &arg.pData);
      69        1514 :     return arg;
      70             : }
      71             : 
      72           0 : std::string convertLazy(rtl::OUString const & s16) {
      73           0 :     rtl::OString s8(rtl::OUStringToOString(s16, osl_getThreadTextEncoding()));
      74             :     static_assert(sizeof (sal_Int32) <= sizeof (std::string::size_type), "must be at least the same size");
      75             :         // ensure following cast is legitimate
      76             :     return std::string(
      77           0 :         s8.getStr(), static_cast< std::string::size_type >(s8.getLength()));
      78             : }
      79             : 
      80             : #if defined TIMETESTS
      81             : //Output how long each test took
      82             : class TimingListener
      83             :     : public CppUnit::TestListener
      84             :     , private boost::noncopyable
      85             : {
      86             : public:
      87             :     void startTest( CppUnit::Test *) SAL_OVERRIDE
      88             :     {
      89             :         m_nStartTime = osl_getGlobalTimer();
      90             :     }
      91             : 
      92             :     void endTest( CppUnit::Test *test ) SAL_OVERRIDE
      93             :     {
      94             :         sal_uInt32 nEndTime = osl_getGlobalTimer();
      95             :         std::cout << test->getName() << ": " << nEndTime-m_nStartTime
      96             :             << "ms" << std::endl;
      97             :     }
      98             : 
      99             : private:
     100             :     sal_uInt32 m_nStartTime;
     101             : };
     102             : #endif
     103             : 
     104             : #ifdef UNX
     105             : #include <stdlib.h>
     106             : // Setup an env variable so that temp file (or other) can
     107             : // have a useful value to identify the source
     108         195 : class EyecatcherListener
     109             :     : public CppUnit::TestListener
     110             :     , private boost::noncopyable
     111             : {
     112             : public:
     113        4326 :     void startTest( CppUnit::Test* test) SAL_OVERRIDE
     114             :     {
     115        4326 :         boost::scoped_array<char> tn(new char [ test->getName().length() + 2 ]);
     116        4326 :         strcpy(tn.get(), test->getName().c_str());
     117        4326 :         int len = strlen(tn.get());
     118      174194 :         for(int i = 0; i < len; i++)
     119             :         {
     120      169868 :             if(!isalnum(tn[i]))
     121             :             {
     122       19568 :                 tn[i] = '_';
     123             :             }
     124             :         }
     125        4326 :         tn[len] = '_';
     126        4326 :         tn[len + 1] = 0;
     127        4326 :         setenv("LO_TESTNAME", tn.get(), true);
     128        4326 :     }
     129             : 
     130        4326 :     void endTest( CppUnit::Test* /* test */ ) SAL_OVERRIDE
     131             :     {
     132        4326 :     }
     133             : };
     134             : #endif
     135             : 
     136         195 : class LogFailuresAsTheyHappen : public CppUnit::TestListener
     137             : {
     138             : public:
     139           2 :     virtual void addFailure( const CppUnit::TestFailure &failure ) SAL_OVERRIDE
     140             :     {
     141           2 :         printFailureLocation( failure.sourceLine() );
     142           2 :         printFailedTestName( failure );
     143           2 :         printFailureMessage( failure );
     144           2 :     }
     145             : 
     146             : private:
     147           2 :     static void printFailureLocation( const CppUnit::SourceLine &sourceLine )
     148             :     {
     149           2 :         if ( !sourceLine.isValid() )
     150           1 :             std::cerr << "unknown:0:";
     151             :         else
     152           1 :             std::cerr << sourceLine.fileName() << ":" << sourceLine.lineNumber() << ":";
     153           2 :     }
     154             : 
     155           2 :     static void printFailedTestName( const CppUnit::TestFailure &failure )
     156             :     {
     157           2 :         std::cerr << failure.failedTestName() << std::endl;
     158           2 :     }
     159             : 
     160           2 :     static void printFailureMessage( const CppUnit::TestFailure &failure )
     161             :     {
     162           2 :         std::cerr << failure.thrownException()->message().shortDescription() << std::endl;
     163           2 :         std::cerr << failure.thrownException()->message().details() << std::endl;
     164           2 :     }
     165             : };
     166             : 
     167             : namespace {
     168             : 
     169           0 : void addRecursiveTests(const std::vector<std::string>& test_names, CppUnit::Test* pTest, CppUnit::TestRunner& rRunner)
     170             : {
     171           0 :     for (int i = 0; i < pTest->getChildTestCount(); ++i)
     172             :     {
     173           0 :         CppUnit::Test* pNewTest = pTest->getChildTestAt(i);
     174           0 :         addRecursiveTests(test_names, pNewTest, rRunner);
     175           0 :         if (std::find(test_names.begin(), test_names.end(), pNewTest->getName()) != test_names.end())
     176           0 :             rRunner.addTest(pNewTest);
     177             :     }
     178           0 : }
     179             : 
     180             : }
     181             : 
     182             : //Allow the whole uniting testing framework to be run inside a "Protector"
     183             : //which knows about uno exceptions, so it can print the content of the
     184             : //exception before falling over and dying
     185         195 : class CPPUNIT_API ProtectedFixtureFunctor
     186             :     : public CppUnit::Functor
     187             :     , private boost::noncopyable
     188             : {
     189             : private:
     190             :     const std::string &testlib;
     191             :     const std::string &args;
     192             :     std::vector<CppUnit::Protector *> &protectors;
     193             :     CppUnit::TestResult &result;
     194             : public:
     195         195 :     ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, std::vector<CppUnit::Protector*> &protectors_, CppUnit::TestResult &result_)
     196             :         : testlib(testlib_)
     197             :         , args(args_)
     198             :         , protectors(protectors_)
     199         195 :         , result(result_)
     200             :     {
     201         195 :     }
     202         195 :     bool run() const
     203             :     {
     204             : #ifdef DISABLE_DYNLOADING
     205             : 
     206             :         // NOTE: Running cppunit unit tests on iOS was something I did
     207             :         // only very early (several years ago) when starting porting
     208             :         // this stuff to iOS. The complicated mechanisms to do build
     209             :         // such unit test single executables have surely largely
     210             :         // bit-rotted or been semi-intentionally broken since. This
     211             :         // stuff here left for information only. --tml 2014.
     212             : 
     213             :         // For iOS cppunit plugins aren't really "plugins" (shared
     214             :         // libraries), but just static archives. In the real main
     215             :         // program of a cppunit app, which calls the lo_main() that
     216             :         // the SAL_IMPLEMENT_MAIN() below expands to, we specifically
     217             :         // call the initialize methods of the CppUnitTestPlugIns that
     218             :         // we statically link to the app executable.
     219             : #else
     220         195 :         CppUnit::PlugInManager manager;
     221             :         try {
     222         195 :             manager.load(testlib, args);
     223           0 :         } catch (const CppUnit::DynamicLibraryManagerException &e) {
     224           0 :             std::cerr << "DynamicLibraryManagerException: \"" << e.what() << "\"\n";
     225             : #ifdef WIN32
     226             :             const char *pPath = getenv ("PATH");
     227             :             if (pPath && strlen (pPath) > 256)
     228             :             {
     229             :                 std::cerr << "Windows has significant build problems with long PATH variables ";
     230             :                 std::cerr << "please check your PATH variable and re-autogen.\n";
     231             :             }
     232             : #endif
     233           0 :             std::cerr << "Path is '" << getenv("PATH") << "'\n";
     234           0 :             return false;
     235             :         }
     236             : #endif
     237             : 
     238         570 :         for (size_t i = 0; i < protectors.size(); ++i)
     239         375 :             result.pushProtector(protectors[i]);
     240             : 
     241             :         bool success;
     242             :         {
     243         195 :             CppUnit::TestResultCollector collector;
     244         195 :             result.addListener(&collector);
     245             : 
     246         390 :             LogFailuresAsTheyHappen logger;
     247         195 :             result.addListener(&logger);
     248             : 
     249             : #ifdef TIMETESTS
     250             :             TimingListener timer;
     251             :             result.addListener(&timer);
     252             : #endif
     253             : 
     254             : #ifdef UNX
     255         390 :             EyecatcherListener eye;
     256         195 :             result.addListener(&eye);
     257             :             // set this to track down files created before first test method
     258         390 :             std::string lib(testlib.substr(testlib.rfind('/')+1));
     259         195 :             setenv("LO_TESTNAME", lib.c_str(), true);
     260             : #endif
     261             : 
     262         195 :             const char* pVal = getenv("CPPUNIT_TEST_NAME");
     263             : 
     264         390 :             CppUnit::TestRunner runner;
     265         195 :             if (pVal)
     266             :             {
     267           0 :                 std::vector<std::string> test_names;
     268           0 :                 boost::split(test_names, pVal, boost::is_any_of("\t "));
     269           0 :                 CppUnit::Test* pTest = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
     270           0 :                 addRecursiveTests(test_names, pTest, runner);
     271             :             }
     272             :             else
     273             :             {
     274         195 :                 runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
     275             :             }
     276         195 :             runner.run(result);
     277             : 
     278         390 :             CppUnit::CompilerOutputter outputter(&collector, CppUnit::stdCErr());
     279         195 :             outputter.setNoWrap();
     280         195 :             outputter.write();
     281         390 :             success = collector.wasSuccessful();
     282             :         }
     283             : 
     284         570 :         for (size_t i = 0; i < protectors.size(); ++i)
     285         375 :             result.popProtector();
     286             : 
     287         195 :         return success;
     288             :     }
     289           0 :     virtual bool operator()() const SAL_OVERRIDE
     290             :     {
     291           0 :         return run();
     292             :     }
     293             : };
     294             : 
     295             : }
     296             : 
     297         390 : SAL_IMPLEMENT_MAIN()
     298             : {
     299         195 :     bool ok = false;
     300             :     try
     301             :     {
     302             : #ifdef WNT
     303             :         //Disable Dr-Watson in order to crash simply without popup dialogs under
     304             :         //windows
     305             :         DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
     306             :         SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
     307             : #ifdef _DEBUG // These functions are present only in the debgging runtime
     308             :         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
     309             :         _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
     310             :         _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
     311             :         _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
     312             :         _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
     313             :         _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
     314             : #endif
     315             : #endif
     316             : 
     317         195 :         std::vector<CppUnit::Protector *> protectors;
     318         390 :         CppUnit::TestResult result;
     319         390 :         std::string args;
     320         390 :         std::string testlib;
     321         195 :         sal_uInt32 index = 0;
     322        1154 :         while (index < rtl_getAppCommandArgCount())
     323             :         {
     324         764 :             rtl::OUString arg = getArgument(index);
     325         764 :             if ( arg != "--protector" )
     326             :             {
     327         389 :                 if (testlib.empty())
     328             :                 {
     329         195 :                     testlib = rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
     330         195 :                     args += testlib;
     331             :                 }
     332             :                 else
     333             :                 {
     334         194 :                     args += ' ';
     335         194 :                     args += rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
     336             :                 }
     337         389 :                 ++index;
     338         389 :                 continue;
     339             :             }
     340         375 :             if (rtl_getAppCommandArgCount() - index < 3) {
     341           0 :                 usageFailure();
     342             :             }
     343         750 :             rtl::OUString lib(getArgument(index + 1));
     344         750 :             rtl::OUString sym(getArgument(index + 2));
     345             : #ifndef DISABLE_DYNLOADING
     346         750 :             osl::Module mod(lib, SAL_LOADMODULE_GLOBAL);
     347         375 :             oslGenericFunction fn = mod.getFunctionSymbol(sym);
     348         375 :             mod.release();
     349             : #else
     350             :             oslGenericFunction fn = 0;
     351             :             if (sym == "unoexceptionprotector")
     352             :                 fn = (oslGenericFunction) unoexceptionprotector;
     353             :             else if (sym == "unobootstrapprotector")
     354             :                 fn = (oslGenericFunction) unobootstrapprotector;
     355             :             else if (sym == "vclbootstrapprotector")
     356             :                 fn = (oslGenericFunction) vclbootstrapprotector;
     357             :             else
     358             :             {
     359             :                 std::cerr
     360             :                     << "Only unoexceptionprotector or unobootstrapprotector protectors allowed"
     361             :                     << std::endl;
     362             :                 std::exit(EXIT_FAILURE);
     363             :             }
     364             : #endif
     365             :             CppUnit::Protector *protector = fn == 0
     366             :                 ? 0
     367         375 :                 : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
     368         375 :             if (protector == 0) {
     369             :                 std::cerr
     370           0 :                     << "Failure instantiating protector \"" << convertLazy(lib)
     371           0 :                     << "\", \"" << convertLazy(sym) << '"' << std::endl;
     372           0 :                 std::exit(EXIT_FAILURE);
     373             :             }
     374         375 :             protectors.push_back(protector);
     375         375 :             index+=3;
     376         375 :         }
     377             : 
     378         390 :         ProtectedFixtureFunctor tests(testlib, args, protectors, result);
     379         390 :         ok = tests.run();
     380             :     }
     381           0 :     catch (const std::exception& e)
     382             :     {
     383             :         SAL_WARN("vcl.app", "Fatal exception: " << e.what());
     384             :     }
     385             : 
     386         195 :     return ok ? EXIT_SUCCESS : EXIT_FAILURE;
     387         585 : }
     388             : 
     389             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11