From: abv Date: Sat, 17 Nov 2018 09:51:26 +0000 (+0300) Subject: 0027620: Test perf bop boxholes crashes DRAW X-Git-Tag: V7_4_0_beta~304 X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff_plain;h=e05c25c1235d8740cde1a49bf43f6a4bad916c88 0027620: Test perf bop boxholes crashes DRAW Implementation of capturing of output to standard streams in DRAW (see command dlog) is revised to avoid problems with command "test" executing long test scripts: 1. Method OSD_File::Capture() is removed: on Windows it was allocating a C file descriptor for a file opened using WinAPI, and never released that descriptor (once allocated, it cannot be released separately from WinAPI file handle). Direct calls to dup/dup2 are used instead. 2. In Draw_Window.cxx the standard Tcl channels are initialized manually using corrected version of Tcl internal function. This works around a problem with Tcl channels on Windows being bound to OS device handle owned by the system which can get invalidated as result of calls to dup2() (used to capture output to standard streams). 3. Temporary file for capturing is opened once and used to store whole log, thus the need to collect log in the string stream in memory is avoided 4. Possible errors of dup() and dup2() are checked and reported Test demo draw dlog is added Off-topic changes: - Test demo draw getsource is corrected for VS2017 which generates file name in lowercase - Field myFaceBounds is initialized in constructor of the class BRepAlgo_NormalProjection to avoid undefined behavior - Test bugs modalg_5 bug24012 is corrected to use command nproject instead of custom one, and to check propertes of the resulting shape --- diff --git a/src/BRepAlgo/BRepAlgo_NormalProjection.cxx b/src/BRepAlgo/BRepAlgo_NormalProjection.cxx index 5910205061..434ebf441c 100644 --- a/src/BRepAlgo/BRepAlgo_NormalProjection.cxx +++ b/src/BRepAlgo/BRepAlgo_NormalProjection.cxx @@ -83,14 +83,12 @@ void ResultChron( OSD_Chronometer & ch, Standard_Real & time) //======================================================================= BRepAlgo_NormalProjection::BRepAlgo_NormalProjection() - : myWith3d(Standard_True) - + : myIsDone(Standard_False), myMaxDist(-1.), + myWith3d(Standard_True), myFaceBounds(Standard_True) { BRep_Builder BB; BB.MakeCompound(TopoDS::Compound(myToProj)); - myFaceBounds=Standard_True; SetDefaultParams(); - myMaxDist = -1; } //======================================================================= @@ -99,12 +97,12 @@ void ResultChron( OSD_Chronometer & ch, Standard_Real & time) //======================================================================= BRepAlgo_NormalProjection::BRepAlgo_NormalProjection(const TopoDS_Shape& S) - : myWith3d(Standard_True) + : myIsDone(Standard_False), myMaxDist(-1.), + myWith3d(Standard_True), myFaceBounds(Standard_True) { BRep_Builder BB; BB.MakeCompound(TopoDS::Compound(myToProj)); SetDefaultParams(); - myMaxDist = -1; Init(S); } diff --git a/src/Draw/Draw_BasicCommands.cxx b/src/Draw/Draw_BasicCommands.cxx index bf67e02f1a..a30799e755 100644 --- a/src/Draw/Draw_BasicCommands.cxx +++ b/src/Draw/Draw_BasicCommands.cxx @@ -273,15 +273,20 @@ static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const cha } else if (! strcmp (a[1], "reset") && n == 2) { - di.Log().str(""); + di.ResetLog(); } else if (! strcmp (a[1], "get") && n == 2) { - di << di.Log().str().c_str(); + di << di.GetLog(); } else if (! strcmp (a[1], "add") && n == 3) { - di.Log() << a[2] << "\n"; + di.AddLog (a[2]); + di.AddLog ("\n"); + } + else if (! strcmp (a[1], "status") && n == 2) + { + di << (di.GetDoLog() ? "on" : "off"); } else { cout << "Unrecognized option(s): " << a[1] << endl; diff --git a/src/Draw/Draw_Interpretor.cxx b/src/Draw/Draw_Interpretor.cxx index 025df3183f..411fbf45ed 100644 --- a/src/Draw/Draw_Interpretor.cxx +++ b/src/Draw/Draw_Interpretor.cxx @@ -30,6 +30,7 @@ #include #include +#include #ifndef _WIN32 #include #endif @@ -37,6 +38,7 @@ // for capturing of cout and cerr (dup(), dup2()) #ifdef _WIN32 #include +#include #endif #if ! defined(STDOUT_FILENO) @@ -67,50 +69,45 @@ namespace { cout << flush; } - int capture_start (OSD_File& theTmpFile, int std_fd) + int capture_start (int theFDStd, int theFDLog) { - theTmpFile.BuildTemporary(); - if (theTmpFile.Failed()) + Standard_ASSERT_RETURN (theFDLog >= 0, "Invalid descriptor of log file", -1); + + // Duplicate a file descriptor of the standard stream to be able to restore output to it later + int aFDSave = dup (theFDStd); + if (aFDSave < 0) + { + perror ("Error capturing standard stream to log: dup() returned"); + return -1; + } + + // Redirect the stream to the log file + if (dup2 (theFDLog, theFDStd) < 0) { - cerr << "Error: cannot create temporary file for capturing console output" << endl; + close (aFDSave); + perror ("Error capturing standard stream to log: dup2() returned"); return -1; } - // remember current file descriptors of standard stream, and replace it by temporary - return theTmpFile.Capture(std_fd); + // remember saved file descriptor of standard stream + return aFDSave; } - void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho) + void capture_end (int theFDStd, int& theFDSave) { - if (!tmp_file) + if (theFDSave < 0) return; // restore normal descriptors of console stream - #ifdef _WIN32 - _dup2(save_fd, std_fd); - _close(save_fd); - #else - dup2(save_fd, std_fd); - close(save_fd); - #endif - - // extract all output and copy it to log and optionally to cout - const int BUFSIZE = 2048; - TCollection_AsciiString buf; - tmp_file->Rewind(); - while (tmp_file->ReadLine (buf, BUFSIZE) > 0) + if (dup2(theFDSave, theFDStd) < 0) { - log << buf; - if (doEcho) - cout << buf; + perror ("Error returning capturing standard stream to log: dup2() returned"); + return; } - // close temporary file - tmp_file->Close(); - - // remove temporary file if this is not done by the system - if (tmp_file->Exists()) - tmp_file->Remove(); + // close saved file descriptor + close(theFDSave); + theFDSave = -1; } } // anonymous namespace @@ -136,24 +133,24 @@ static Standard_Integer CommandCmd strcmp (argv[0], "decho") == 0); Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation); Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation); - if (doLog) - dumpArgs (di.Log(), argc, argv); - if (doEcho) - dumpArgs (cout, argc, argv); // flush cerr and cout flush_standard_streams(); // capture cout and cerr to log - OSD_File aFile_out, aFile_err; - int fd_err_save = -1; - int fd_out_save = -1; + int aFDstdout = STDOUT_FILENO; + int aFDstderr = STDERR_FILENO; + int aFDerr_save = -1; + int aFDout_save = -1; if (doLog) { - fd_out_save = capture_start (aFile_out, STDOUT_FILENO); - fd_err_save = capture_start (aFile_err, STDERR_FILENO); + aFDout_save = capture_start (aFDstdout, di.GetLogFileDescriptor()); + aFDerr_save = capture_start (aFDstderr, di.GetLogFileDescriptor()); } + if (doEcho || doLog) + dumpArgs (cout, argc, argv); + // run command try { OCC_CATCH_SIGNALS @@ -195,30 +192,24 @@ static Standard_Integer CommandCmd code = TCL_ERROR; } + // log command result + if (doLog || doEcho) + { + const char* aResultStr = Tcl_GetStringResult (interp); + if (aResultStr != 0 && aResultStr[0] != '\0' ) + { + std::cout << aResultStr << std::endl; + } + } + // flush streams flush_standard_streams(); // end capturing cout and cerr if (doLog) { - capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho); - capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho); - } - - // log command result - const char* aResultStr = NULL; - if (doLog) - { - aResultStr = Tcl_GetStringResult (interp); - if (aResultStr != 0 && aResultStr[0] != '\0' ) - di.Log() << Tcl_GetStringResult (interp) << endl; - } - if (doEcho) - { - if (aResultStr == NULL) - aResultStr = Tcl_GetStringResult (interp); - if (aResultStr != 0 && aResultStr[0] != '\0' ) - cout << Tcl_GetStringResult (interp) << endl; + capture_end (aFDstderr, aFDerr_save); + capture_end (aFDstdout, aFDout_save); } return code; @@ -236,7 +227,7 @@ static void CommandDelete (ClientData theClientData) //======================================================================= Draw_Interpretor::Draw_Interpretor() : - isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False) + isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False), myFDLog(-1) { // The tcl interpreter is not created immediately as it is kept // by a global variable and created and deleted before the main(). @@ -529,6 +520,13 @@ Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line) Draw_Interpretor::~Draw_Interpretor() { + SetDoLog (Standard_False); + if (myFDLog >=0) + { + close (myFDLog); + myFDLog = 0; + } + // MKV 01.02.05 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) try { @@ -573,6 +571,35 @@ void Draw_Interpretor::Set(const Draw_PInterp& PIntrp) void Draw_Interpretor::SetDoLog (Standard_Boolean doLog) { + if (myDoLog == doLog) + return; + + // create log file if not opened yet + if (doLog && myFDLog < 0) + { +#ifdef _WIN32 + char tmpfile[L_tmpnam + 1]; + tmpnam(tmpfile); + myFDLog = open (tmpfile, O_RDWR | O_CREAT | O_EXCL | O_TEMPORARY, S_IREAD | S_IWRITE); +#else + // according to Linux Filesystem Hierarchy Standard, 3.17, + // /tmp/ is the right directory for temporary files + char tmpfile[256] = "/tmp/occt_draw_XXXXXX"; + myFDLog = mkstemp (tmpfile); + if (myFDLog >= 0) + { +// printf ("Tmp file: %s\n", tmpfile); + unlink (tmpfile); // make sure the file will be deleted on close + } +#endif + if (myFDLog < 0) + { + perror ("Error creating temporary file for capturing console output"); + printf ("path: %s\n", tmpfile); + return; + } + } + myDoLog = doLog; } @@ -591,7 +618,67 @@ Standard_Boolean Draw_Interpretor::GetDoEcho () const return myDoEcho; } -Standard_SStream& Draw_Interpretor::Log () +void Draw_Interpretor::ResetLog () { - return myLog; + if (myFDLog < 0) + return; + + // flush cerr and cout, for the case if they are bound to the log + flush_standard_streams(); + + lseek (myFDLog, 0, SEEK_SET); + +#ifdef _WIN32 + if (_chsize_s (myFDLog, 0) != 0) +#else + if (ftruncate (myFDLog, 0) != 0) +#endif + { + perror ("Error truncating the console log"); + } +} + +void Draw_Interpretor::AddLog (const Standard_CString theStr) +{ + if (myFDLog < 0 || ! theStr || ! theStr[0]) + return; + + // flush cerr and cout, for the case if they are bound to the log + flush_standard_streams(); + + // write as plain bytes + if (write (myFDLog, theStr, (unsigned int)strlen(theStr)) <0) + { + perror ("Error writing to console log"); + } +} + +TCollection_AsciiString Draw_Interpretor::GetLog () +{ + TCollection_AsciiString aLog; + if (myFDLog < 0) + return aLog; + + // flush cerr and cout + flush_standard_streams(); + + // rewind the file to its start + lseek (myFDLog, 0, SEEK_SET); + + // read the whole log to string; this implementation + // is not optimized but should be sufficient + const int BUFSIZE = 4096; + char buffer[BUFSIZE + 1]; + for (;;) + { + int nbRead = read (myFDLog, buffer, BUFSIZE); + if (nbRead <= 0) + { + break; + } + buffer[nbRead] = '\0'; + aLog.AssignCat (buffer); + } + + return aLog; } diff --git a/src/Draw/Draw_Interpretor.hxx b/src/Draw/Draw_Interpretor.hxx index 9e113bc696..579f6f94f8 100644 --- a/src/Draw/Draw_Interpretor.hxx +++ b/src/Draw/Draw_Interpretor.hxx @@ -238,8 +238,18 @@ public: //! Returns true if echoing of commands is enabled Standard_EXPORT Standard_Boolean GetDoEcho() const; - //! Returns log stream - Standard_EXPORT Standard_SStream& Log(); + //! Resets log (if opened) to zero size + Standard_EXPORT void ResetLog(); + + //! Writes a text string to the log (if opened); + //! end of line is not appended + Standard_EXPORT void AddLog (const Standard_CString theStr); + + //! Returns current content of the log file as a text string + Standard_EXPORT TCollection_AsciiString GetLog(); + + //! Returns current value of the log file descriptor + Standard_Integer GetLogFileDescriptor() { return myFDLog; } protected: @@ -255,7 +265,7 @@ private: Draw_PInterp myInterp; Standard_Boolean myDoLog; Standard_Boolean myDoEcho; - Standard_SStream myLog; + Standard_Integer myFDLog; //!< file descriptor of log file public: diff --git a/src/Draw/Draw_Window.cxx b/src/Draw/Draw_Window.cxx index 93a4606b99..7aab0be547 100644 --- a/src/Draw/Draw_Window.cxx +++ b/src/Draw/Draw_Window.cxx @@ -2166,16 +2166,120 @@ void exitProc(ClientData /*dc*/) TerminateProcess(proc, 0); } +// This is fixed version of TclpGetDefaultStdChannel() defined in tclWinChan.c +// See https://core.tcl.tk/tcl/tktview/91c9bc1c457fda269ae18595944fc3c2b54d961d +static Tcl_Channel +TclpGetDefaultStdChannel( + int type) /* One of TCL_STDIN, TCL_STDOUT, or + * TCL_STDERR. */ +{ + Tcl_Channel channel; + HANDLE handle; + int mode = -1; + const char *bufMode = NULL; + DWORD handleId = (DWORD) -1; + /* Standard handle to retrieve. */ + + switch (type) { + case TCL_STDIN: + handleId = STD_INPUT_HANDLE; + mode = TCL_READABLE; + bufMode = "line"; + break; + case TCL_STDOUT: + handleId = STD_OUTPUT_HANDLE; + mode = TCL_WRITABLE; + bufMode = "line"; + break; + case TCL_STDERR: + handleId = STD_ERROR_HANDLE; + mode = TCL_WRITABLE; + bufMode = "none"; + break; + default: + Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type"); + break; + } + + handle = GetStdHandle(handleId); + + /* + * Note that we need to check for 0 because Windows may return 0 if this + * is not a console mode application, even though this is not a valid + * handle. + */ + + if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) { + return (Tcl_Channel) NULL; + } + + /* + * Make duplicate of the standard handle as it may be altered + * (closed, reopened with another type of the object etc.) by + * the system or a user code at any time, e.g. by call to _dup2() + */ + if (! DuplicateHandle (GetCurrentProcess(), handle, + GetCurrentProcess(), &handle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + return (Tcl_Channel) NULL; + } + + channel = Tcl_MakeFileChannel(handle, mode); + + if (channel == NULL) { + return (Tcl_Channel) NULL; + } + + /* + * Set up the normal channel options for stdio handles. + */ + + if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK || + Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK || + Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) { + Tcl_Close(NULL, channel); + return (Tcl_Channel) NULL; + } + return channel; +} + +// helper functuion +static void ResetStdChannel (int type) +{ + Tcl_Channel aChannel = TclpGetDefaultStdChannel (type); + Tcl_SetStdChannel (aChannel, type); + if (aChannel) + { + Tcl_RegisterChannel (NULL, aChannel); + } +} + /*--------------------------------------------------------*\ | tkLoop: implements Tk_Main()-like behaviour in a separate thread \*--------------------------------------------------------*/ static DWORD WINAPI tkLoop(VOID) { - Draw_Interpretor& aCommands = Draw::GetInterpretor(); - Tcl_CreateExitHandler(exitProc, 0); + + // Work-around against issue with Tcl standard channels on Windows. + // These channels by default use OS handles owned by the system which + // may get invalidated e.g. by dup2() (see dlog command). + // If this happens, output to stdout from Tcl (e.g. puts) gets broken + // (sympthom is error message: "error writing "stdout": bad file number"). + // To prevent this, we set standard channels using duplicate of system handles. + // The effect is that Tcl channel becomes independent on C file descriptor + // and even if stdout/stderr are redirected using dup2(), Tcl keeps using + // original device. + ResetStdChannel (TCL_STDOUT); + ResetStdChannel (TCL_STDERR); + #if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)) + // Plain Tcl (8.6.4+) initializes interpretor channels automatically, but + // ActiveState Tcl (at least 8.6.4) does not seem to do that, so channels + // need to be set into interpretor explicitly { + Draw_Interpretor& aCommands = Draw::GetInterpretor(); + Tcl_Channel aChannelIn = Tcl_GetStdChannel (TCL_STDIN); Tcl_Channel aChannelOut = Tcl_GetStdChannel (TCL_STDOUT); Tcl_Channel aChannelErr = Tcl_GetStdChannel (TCL_STDERR); diff --git a/src/OSD/OSD_File.cxx b/src/OSD/OSD_File.cxx index 4b759ed147..cb4850f6da 100644 --- a/src/OSD/OSD_File.cxx +++ b/src/OSD/OSD_File.cxx @@ -372,8 +372,8 @@ OSD_File::OSD_File() : myFileHandle (INVALID_HANDLE_VALUE), #else myFileChannel (-1), -#endif myFILE (NULL), +#endif myIO (0), myLock (OSD_NoLock), myMode (OSD_ReadWrite), @@ -392,8 +392,8 @@ OSD_File::OSD_File (const OSD_Path& theName) myFileHandle (INVALID_HANDLE_VALUE), #else myFileChannel (-1), -#endif myFILE (NULL), +#endif myIO (0), myLock (OSD_NoLock), myMode (OSD_ReadWrite), @@ -1616,39 +1616,6 @@ Standard_Boolean OSD_File::IsExecutable() #endif } -// ======================================================================= -// function : Capture -// purpose : -// ======================================================================= -int OSD_File::Capture (int theDescr) -{ -#ifdef _WIN32 - // Get POSIX file descriptor from this file handle - int dFile = _open_osfhandle (reinterpret_cast(myFileHandle), myMode); - if (0 > dFile) - { - _osd_wnt_set_error (myError, OSD_WFile, myFileHandle); - return -1; - } - - // Duplicate an old file descriptor of the given one to be able to restore output to it later. - int oldDescr = _dup (theDescr); - // Redirect the output to this file - _dup2 (dFile, theDescr); - - // Return the old descriptor - return oldDescr; -#else - // Duplicate an old file descriptor of the given one to be able to restore output to it later. - int oldDescr = dup (theDescr); - // Redirect the output to this file - dup2 (myFileChannel, theDescr); - - // Return the old descriptor - return oldDescr; -#endif -} - // ======================================================================= // function : Rewind // purpose : diff --git a/src/OSD/OSD_File.hxx b/src/OSD/OSD_File.hxx index a1c0b3b1ed..10f6a71ef2 100644 --- a/src/OSD/OSD_File.hxx +++ b/src/OSD/OSD_File.hxx @@ -182,31 +182,14 @@ public: //! Set file pointer position to the beginning of the file Standard_EXPORT void Rewind(); - //! Redirect a standard handle (fileno(stdout), fileno(stdin) or - //! fileno(stderr) to this OSD_File and return the copy of the original - //! standard handle. - //! Example: - //! OSD_File aTmp; - //! aTmp.BuildTemporary(); - //! int stdfd = _fileno(stdout); - //! - //! int oldout = aTmp.Capture(stdfd); - //! cout << "Some output to the file" << endl; - //! cout << flush; - //! fflush(stdout); - //! - //! _dup2(oldout, stdfd); // Restore standard output - //! aTmp.Close(); - Standard_EXPORT int Capture(int theDescr); - protected: #ifdef _WIN32 Standard_Address myFileHandle; #else Standard_Integer myFileChannel; -#endif Standard_Address myFILE; +#endif Standard_Integer myIO; private: diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 7a90f39572..f2ab1ee5f2 100644 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -1264,43 +1264,6 @@ static Standard_Integer OCC24005 (Draw_Interpretor& theDI, Standard_Integer theN return 0; } -#include -static Standard_Integer OCC24012 (Draw_Interpretor& di, Standard_Integer argc, const char ** argv) -{ - if (argc != 3) { - di << "Usage : " << argv[0] << " should be 2 arguments (face and edge)"; - return 1; - } - - Handle(AIS_InteractiveContext) myAISContext = ViewerTest::GetAISContext(); - if(myAISContext.IsNull()) { - di << "use 'vinit' command before " << argv[0] << "\n"; - return 1; - } - - TopoDS_Face m_Face1 = TopoDS::Face(DBRep::Get(argv[1])); - TopoDS_Edge m_Edge = TopoDS::Edge(DBRep::Get(argv[2])); - - BRepAlgo_NormalProjection anormpro(m_Face1); - anormpro.Add(m_Edge); - anormpro.SetDefaultParams(); - - //anormpro.Compute3d(); - //anormpro.SetLimit(); - - anormpro.Build(); - - if (anormpro.IsDone()) - { - TopoDS_Shape rshape = anormpro.Projection(); - Handle(AIS_InteractiveObject) myShape = new AIS_Shape (rshape); - myAISContext->SetColor (myShape, Quantity_Color(Quantity_NOC_YELLOW), Standard_False); - myAISContext->Display (myShape, Standard_True); - } - - return 0; -} - #include #include #include @@ -5305,7 +5268,6 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) { theCommands.Add ("OCC23972", "OCC23972", __FILE__, OCC23972, group); theCommands.Add ("OCC24370", "OCC24370 edge pcurve surface prec", __FILE__, OCC24370, group); theCommands.Add ("OCC24533", "OCC24533", __FILE__, OCC24533, group); - theCommands.Add ("OCC24012", "OCC24012 face edge", __FILE__, OCC24012, group); theCommands.Add ("OCC24086", "OCC24086 face wire", __FILE__, OCC24086, group); theCommands.Add ("OCC24667", "OCC24667 result Wire_spine Profile [Mode [Approx]], no args to get help", __FILE__, OCC24667, group); theCommands.Add ("OCC24755", "OCC24755", __FILE__, OCC24755, group); diff --git a/tests/bugs/modalg_5/bug24012 b/tests/bugs/modalg_5/bug24012 index 31a660f64b..a27a3cb205 100644 --- a/tests/bugs/modalg_5/bug24012 +++ b/tests/bugs/modalg_5/bug24012 @@ -12,14 +12,18 @@ pload QAcommands igesread [locate_data_file bug24012_face.igs] face * igesread [locate_data_file bug24012_line.igs] edge * +nproject r edge face +checknbshapes r -edge 1 +checkprops r -l 5.96 + vinit -OCC24012 face edge vsetdispmode 0 vdisplay face vdisplay edge +vdisplay r +vsetcolor r yellow vfit - set scale 71.101493567712652 set proj_X -0.14605970947882216 set proj_Y -0.18639384905183365 diff --git a/tests/demo/draw/dlog b/tests/demo/draw/dlog new file mode 100644 index 0000000000..0743b52761 --- /dev/null +++ b/tests/demo/draw/dlog @@ -0,0 +1,39 @@ +# Check functionality of dlog command (capturing of stdout) + +pload MODELING + +# activate logging +set status [dlog status] +dlog on + +# check that log does not fail at many executions +# note that this makes sense only if we do not run by test command with +# dlog already active, in which case puts is redefined +if { $status == off } { + for {set i 0} {$i < 10000} {incr i} { box b 1 1 1 } + dlog off + puts "Try puts to check that channel is not broken" + dlog on +} + +# check that logging works as expected +dlog reset +box b 1 1 1 +explode b f +if { $status == off } { + # this will get to log if executed using "test" command instead of testgrid, as it redefines puts + puts "output of puts -- should not be in the log" +} +dlog add "output of dlog add" +set log [dlog get] +set expected "box b 1 1 1 \nexplode b f \nb_1 b_2 b_3 b_4 b_5 b_6\noutput of dlog add\n" +if { $log != $expected } { + puts "Error: Logged text does not match expected" + puts "Value: \"$log\"" + puts "Expected: \"$expected\"" +} + +# return original state of logging +dlog $status + +puts "TEST COMPLETED" diff --git a/tests/demo/draw/getsource b/tests/demo/draw/getsource index acfe3bbac1..f0604d260f 100755 --- a/tests/demo/draw/getsource +++ b/tests/demo/draw/getsource @@ -3,7 +3,7 @@ # check that path returned for command pload is as expected set expected src/Draw/Draw_PloadCommands.cxx set path [lindex [getsourcefile pload] 1] -if { [string compare $path $expected] } { +if { [string compare -nocase $path $expected] } { puts "Error: command 'getsourcefile pload' returned '$path' while expected '$expected'" }