====== [hemmerling] Tcl / Tk ( tickle ) 2/2 - Debugging & Testing ====== Related page: *[[tickle.html|Tcl / Tk ( tickle ) 1/2]]. ===== Static Code Analysis with Tcl / Tk ===== ==== Style Guides ==== *[[http://wiki.tcl.tk/708|Tcler's Wiki "Tcl Style GRay Johnsonuide"]] by Ray Johnson ##. *[[http://mike.dewolfe.bc.ca/exhumed/jva/TCL.style.html|Shawn DeWolfe "Tk/TCL style guide"]] - Brief instructions. ==== Ray Johnson's Style Guide Rules ==== === 5.2 Basic Syntax Rules === Below are some specific rules governing the syntax of names. Please follow the rules exactly, since they make it possible to determine certain properties of a variable just from its name. -Exported names for both procedures and variables always start with a lower-case letter. Procedures and variables that are meant only for use with in the current package or namespace should start with an upper-case letter. We chose lower-case for the exported symbols because it is possible they may be commonly used from the command line and they should be easy to write. For example: # CountNum is a private variable set CountNum 0 # The function addWindow is public proc addWindow {} {... # newWindow is a public interface in the spectcl namespace proc spectcl::newWindow {} {... -In multi-word names, the first letter of each trailing word is capitalized. Do not use underscores or dashes as separators between the words of a name. set numWindows 0 -Any variable whose value refers to another variable has a name that ends in Name. Furthermore, the name should also indicate what type of variable the name is referring to. These names are often used in arguments to procedures that are taking a name of a variable. proc foo::Bar {arrayName} { upvar 1 $arrayName array ... } -Variables that hold Tcl code that will be evaled should have names ending in Script. proc log::eval {logScript} { if {$Log::logOn} { set result [catch {eval $logScript} msg] ... -Variables that hold a partial Tcl command that must have additional arguments appended before being a valid script should have names ending in Cmd. foreach scrollCmd $listScrollCmds { eval $scrollCmd $args } === 6. Low-level coding Conventions === This section describes several low-level syntactic rules for writing Tcl code. These rules help to ensure that all of the Tcl code looks the same, and they prohibit a few confusing coding constructs. == 6.1 Indents are 4 Spaces == Each level of indentation should be four spaces. There are ways to set 4-space indents in all of the most common editors. Be sure that your editor really uses four spaces for the indent, rather than just displaying tabs as four spaces wide; if you use the latter approach then the indents will appear eight spaces wide in other editors. == 6.2 Code Comments occupy full Lines == Comments that document code should occupy full lines, rather than being tacked onto the ends of lines containing code. The reason for this is that side-by-side comments are hard to see, particularly if neighboring statements are long enough to overlap the side-by-side comments. Also it is easy to place comments in a place that could cause errors. Comments must have exactly the structure shown in Figure 3, with a blank line above and below the comment. The leading blank line can be omitted if the comment is at the beginning of a block, as is the case in the second comment in Figure 3. Each comment should be indented to the same level as the surrounding code. Use proper English in comments: write complete sentences, capitalize the first word of each sentence, and so on. # If we are running on the Macintosh platform then we can # assume that the sources are located in the resource fork # of our application, and we do not need to search for them. if {$tcl_platform(platform) == “macintosh”} { return } foreach dir $dirList { # If the source succeds then we are done. if {![catch {source [file join $dir file.tcl]}]} { break } } Figure 3. Comments in code have the form shown above, using full lines, with lined-up hash marks, the comment takes at least a full line, and blank separator lines around each comment (except that the leading blank line can be omitted if the comment is at the beginning of a code block). == 6.3 Continuation Lines are indented 8 Spaces == You should use continuation lines to make sure that no single line exceeds 80 characters in length. Continuation lines should be indented 8 spaces so that they won’t be confused with an immediately-following nested block. Pick clean places to break your lines for continuation, so that the continuation doesn’t obscure the structure of the statement. For example, if a procedure call requires continuation lines, try to avoid situations where a single argument spans multiple lines. If the test for an if or while command spans lines, try to make each line have the same nesting level of parentheses and/or brackets if possible. I try to start each continuation line with an operator such as *, &&, or ||; this makes it clear that the line is a continuation, since a new statement would never start with such an operator. == 6.4 Only one Command per Line == You should only have one Tcl command per line on the page. Do not use the semi-colon character to place multiple commands on the same line. This makes the code easier to read and helps with debugging. == 6.5 Curly Braces: { goes at the end of a Line == Open curly braces can not appear on lines by themselves in Tcl. Instead, they should be placed at the end of the preceding line. Close curly braces are indented to the same level as the outer code, i.e., four spaces less than the statements they enclose. However, you should always use curly braces rather than some other list generating mechanism that will work in the Tcl language. This will help make code more readable, will avoid unwanted side effects, and in many cases will generate faster code with the Tcl compiler. Control structures should always use curly braces, even if there is only one statement in the block. Thus you shouldn’t write code like if {$tcl_platform(platform) == "unix"} return but rather if {$tcl_platform(platform) == "unix"} { return } This approach makes code less dense, but it avoids potential mistakes like unwanted Tcl substitutions. It also makes it easier to set breakpoints in a debugger, since it guarantees that each statement is on a separate line and can be named individually. == 6.6 Parenthesize Expressions == Use parentheses around each subexpression in an expression to make it absolutely clear what is the evaluation order of the expression (a reader of your code should not need to remember Tcl’s precedence rules). For example, don’t type if {$x > 22 && $y <= 47} ... Instead, type this: if {($x > 22) && ($y <= 47)} ... == 6.7 Always use the return statement == You should always explicitly use the return statement to return values from a Tcl procedure. By default Tcl will return the value of the last Tcl statement executed in a Tcl procedure as the return value of the procedure which often leads to confusion as to where the result is coming from. In addition, you should use a return statement with no argument for procedures whose results are ignored. Supplying this return will actually speed up your application with the new Tcl compiler. For example, don’t write code like this: proc foo {x y} { if {$x < 0} { incr x } else { expr $x + $y } } But rather, type this: proc foo {x y} { if {$x < 0} { return [incr x] } else { return [expr $x + $y] } } For Tcl procedures that have no return value a single return statement with no arguments is placed at the end of the procedure. == 6.8 Switch statements == The switch statement should be formatted as below. Always use the -- option to avoid having the string be confused with an option. This can happen when the string is user generated. Comments can be added on the same line as the pattern to comment the pattern case. The comments for each case should line up on the same tab stop and must be within the braces. Note that this is an exception to the standard commenting conventions. switch -regexp -- $string { plus - add { # Do add task ... } subtract { # Do subtract case ... } default { ... } } == 6.9 If statements == Never use the then word of an if statement. It is syntactic sugar that really isn’t that useful. However, the else word should always be used as it does impart some semantic information and it is more like the C language. Here is an example: if {$x < 0} { ... } elseif {$x == 0} { ... } else { ... } ==== Tools ==== *TclPro. *The commercial [[http://www.activestate.com/tcl-dev-kit|ActiveState "Tcl Dev Kit (TDK). Productivity and Deployment Tools for Tcl"]]. *[[http://docs.activestate.com/tdk/4.1/Checker.html|ActiveState Docs "Tcl Dev Kit User Guide / TclChecker]]. *"By default, the Tcl Dev Kit TclChecker verifies scripts written for Tcl version 8.4". *So even this commercial edition 4.1 doesn´t support the features of TCL 8.5 and 8.6. *So does it support TCL 8.6 object oriented programming at all!? *[[http://docs.activestate.com/tdk/4.1/Debugger.html|ActiveState Docs "Tcl Dev Kit User Guide / Debugger"]]. *The free [[http://www.sourceforge.net/projects/tclpro/|SourceForge "TclPro"]], [[http://tclpro.sourceforge.net/|SourceForge "TclPro"]]. *[[http://www.tcl.tk/software/tclpro/|Tcl Developer Xchange "TclPro"]] - Product history. *The free edition "TclPro 1.4.1" requires license keys in order to use the development tools (e.g, TclPro Debugger, TclPro Checker, TclPro Compiler, and TclPro Wrapper). *TclPro 1.4.1, for Tcl/Tk 8.3.2: Key: "1094-320C-1G38-2U24-P8YY". *If you run the TclPro network license server, the keys are different: *TclPro 1.4.1, Key for 10 seats: "2M1C-1H28-34U3-4P8Z-DRG2". *[[http://www.tcl.tk/software/tclpro/eval/1.4.html|Tcl Developer Xchange "Download TclPro 1.4"]]. *The free "TclPro Checker" of the free edition "TclPro 1.4.1" is a command line tool "C:\Program Files\TclPro1.4\win32-ix86\bin\procheck.exe". You have to add the path to that directory manually to your Windows system path. *The free [[http://nagelfar.sourceforge.net/|SourceForge "Nagelfar"]], [[http://www.sourceforge.net/projects/nagelfar|SourceForge "Nagelfar"]]. *[[http://wiki.tcl.tk/9064|Tcler's Wiki "Nagelfar"]]. *"With version 1.1.11 support for 8.6 is getting better. OO support is still not very friendly but possible". ==== Resources ==== *I was told by experts, that Tcl/Tk can´t be verified formally, as the language is too much dynamic by the option of redefinition at runtime. So the benefit of static code analysis is very limited, by definition. *[[http://wiki.tcl.tk/3162|Tcler's Wiki "Static syntax analysis"]]. *[[http://www.msen.com/~clif/TclLint.html|Clif Flynt "Comparison of Static Tcl Code Validity Testers"]]. ===== Interactive Development & Debugging ===== ==== By built-in Commands ( "All Batteries included" ) & no or little extra Code ==== *[[http://www.tcl.tk/man/tcl8.6/TkCmd/trace.htm|Tcl/Tk Documentation / Tk Commands "trace"]]. *[[http://www.tcl.tk/man/tcl8.6/TkCmd/info.htm|Tcl/Tk Documentation / Tk Commands "info"]]. *[[http://www.tcl.tk/man/tcl8.6/TkCmd/winfo.htm|Tcl/Tk Documentation / Tk Commands "winfo"]]. *[[http://wiki.tcl.tk/1151|Tcler's Wiki, Richard Suchenwirth "A minimal debugger"]]. *[[http://wiki.tcl.tk/473|Tcler's Wiki "What debugging tools are available to a Tcl programmer"]]. *Experts told me about a special simple method for stack analysis, not yet tested: *A log function is called in the code to be debugged. *The log function explores the state of the stack by "info" function ( i.e. "info args" and "info errorstack" ). *[[https://www.tcl.tk/man/tcl/TclCmd/info.htm#M13|Tcl/Tk Documentation / Tcl Commands "info"]] - "info errorstack". ==== By Tools ==== *The OpenSource [[http://expect.sourceforge.net/|Sourceforge "Expect"]], [[http://www.sourceforge.net/projects/expect/|Sourceforge "Expect"]], [[http://www.nist.gov/el/msid/expect.cfm|National Institute of Standards and Technology (NIST) "Expect"]] is shipped with a command-line debugger. *[[http://www.amazon.de/exec/obidos/ASIN/0123847176/hemmerling-21|Clif Flynt: "Tcl/Tk. A Developer's Guide"]] - Chapter 18.3.1, page 714 - 717 explains how to use the "Expect" debugger for Tcl debugging. *The commercial IDE [[http://www.komodoide.com/|KomodoIDE]] by [[http://www.activestate.com/|ActiveState]] is shipped with a Tcl debugger. * TkOAT / OAT ( Object Attribute Traces ), just for Tcl 7.6 with Tk4.1/4.2 due to the need for patching the Tcl/Tk system. *[[http://www-users.cs.umn.edu/~konstan/BRS97-MM.html|University of Minnesota, Joseph A. Konstan "Building on the GUI Toolkit Paradigm: Creating Multimedia System Toolkits]]. *[[http://web.archive.org/web/*/http://www.cs.umn.edu/Research/GIMME|Archive.org "University of Minnesota: GIMME -- Graphical Interfaces for MultiMedia Environments"]] ( - 2003-12-06 ). *[[http://web.archive.org/web/*/http://www.cs.umn.edu/research/GIMME/tclprop.html|Archive.org "University of Minnesota: TclProp - A Formula Manager for Tcl and Tk"]] ( - 2003-12-11 ). *[[ftp://ftp.arnes.si/packages/tcl/sorted/packages-7.6/devel/TclProp-2.0.README|ftp://ftp.arnes.si/packages/tcl/sorted/packages-7.6/devel/ "TclProp-2.0.README"]] - "TkOAT, an extension to Tk that enables traces on Tk widget and canvas item attributes. A patch for Tk 4.1/4.2 required by TkOAT is included". *[[http://www-users.cs.umn.edu/~safonov/tcl97/oat-tcl97.html|University of Minnesota - Alex Safonov, Joseph A. Konstan, John V. Carlis and Brian Bailey "Extending Traces with OAT: an Object Attribute Trace package for Tcl/Tk"]]. *The OpenSource IDE [[http://www.netbeans.org/|NetBeans]]. *[[http://plugins.netbeans.org/plugin/39119/tcl-plugin|NetBeans Plugins "Tcl Plugin"]] for Netbeans 7.2 - "Syntax Highlight, Create/Open Tcl Projects And Files, Run Tcl Files, Debugger". *[[http://wiki.tcl.tk/28292|Tcler's Wiki "netbeanstcl debugger"]]. *[[http://wiki.tcl.tk/28657|Tcler's Wiki "netbeanstcl debugger" - "Tcl Plugin for Netbeans - Debugger Overview"]]. *The OpenSource [[http://www.compassis.com/ramdebugger|RamDebugger]] - "A debugger and IDE for TCL-TK". *[[http://wiki.tcl.tk/3912|Tcler's Wiki "RamDebugger"]]. *TclPro. *[[http://docs.activestate.com/tdk/4.1/Debugger.html|ActiveState Docs "Tcl Dev Kit User Guide / Debugger"]]. ==== By Overwriting / Overloading ==== *By creating your own procedures with name of standard procedures, for debugging. The self-defined procedures, e.g "putc" provide additinal debugging communications. A Tcl expert named that like this: "I wrap procs". *[[http://wiki.tcl.tk/17765|Tcler's Wiki "Overridden commands"]]. *[[http://www.stackoverflow.com/questions/9775429/function-overloading-in-tcl|StackOverflow "Function Overloading in TCL"]]. ==== With TclCon ==== ==== With Wish ==== === demo.tcl === bind all {console show} set LabelText "Hello" set Message "Hello World!" pack [button .b -text $LabelText -command onButtonClick] proc onButtonClick {} { puts "Start of Reaction to Buttonclick" tk_messageBox -parent . -message $::Message puts "End of Reaction to Buttonclick" } === console_logging.txt === % info vars tcl_rcFileName tcl_version argv0 argv tcl_interactive tk_library tk_version LabelText auto_path errorCode tk_strictMotif errorInfo auto_index env tcl_patchLevel Message argc tk_patchLevel tcl_library tcl_platform% % winfo ch . .b # Replacement of the message of a modal window % set Message Hallo World! % set Message "Hello Tcl User!" Hello Tcl User! # Now press the Button "Hello" # and see that the new message # is displayed on the button of # the modal window # Replacement on the callback function # for a buttonclick: % proc onButtonClick {} { puts "New Start of Reaction to Buttonclick" tk_messageBox -parent . -message $::Message puts "New End of Reaction to Buttonclick" } # Now press the Button "Hello" # and see that by the buttonclick # now new messages are displayed # in the console window % proc e {} {uplevel #0 [clipboard get]} # Now mark the Tcl command "winfo ch .", # copy it with CTRL-C to the keyboard # and execute the command "e" # By this, the contents of the clipboard # is executed as Tcl command % e .b % proc i {} {puts $::errorInfo} # Now cause an error by an invalid command % abc invalid command name "abc" # So you can replay the last error, # by calling the "i" procedure % i invalid command name "abc" while executing "abc" === Instructions === -Execute the "Wish" GUI application. -Load and execute the "demo.tcl" application by "File / Source "demo.tcl". This starts -The GUI application "wish", a window sith a "Hello" button. -The console window "Console". -Switch the window context of the "wish" application, and press "SHIFT-F1". This (re-)opens the console window "Console". If you close the console window, you can reopen it by this again at every time. -Load "console_logging.txt" in an editor, e.g. in the Eclipse IDE. On Windows, you may mark and copy code instructions from the editor window by "CTRL-C" and paste it by "CTRL-V" in the "wish" window so that it is accepted as input as if typed in by keyboard. -Check how you can explore the Tcl environment by -"info vars". -"winfo .b". -Press the button "Hello", and press the button "Hello World!" of the upcoming modal window. Take notice of the messages in the console window. -In the console window, set a new message by executing the ' set Message "Hello Tcl User!"' command. -Press the button "Hello", and you see that the upcoming modal window now has a button "Hello Tcl User!". Press this button. -In the console window, execute a command to redefine the "onButtonClick {}" procedure. -Press the button "Hello", and you see that the messages in the console window are different. -By "e {} {uplevel #0 [clipboard get]}", you may execute the contents of the clipboard as Tcl command. Example: -Mark the Tcl command "winfo ch .". -Copy it with CTRL-C to the keyboard. -Execute the command "e" at Tclsh. By this, the contents of the clipboard is executed as Tcl command. -By "proc i {} {puts $::errorInfo}" you may recall the Tcl variable "errorInfo" which contains the last error message. Example: -Execute the unknown Tcl command "abc" at Tclsh. -Display the last Tcl error message, by executing "i". ==== Resources ==== *[[http://wiki.tcl.tk/473|Tcler's Wiki "What debugging tools are available to a Tcl programmer"]]. ===== Unit Testing ===== ==== tcltest ==== *[[http://docs.activestate.com/activetcl/8.5/tcl/TclCmd/tcltest.htm|ActiveState Docs - ActiveTcl User Guide "Tcl/Tk Documentation > TclCmd > tcltest"]]. *[[http://www.tcl.tk/man/tcl8.5/TclCmd/tcltest.htm|tcl.tk "Tcl8.5.12/Tk8.5.12 Documentation > TclCmd > tcltest"]]. *[[http://wuhrr.wordpress.com/2011/03/28/getting-started-with-tcltest/|Hai’s Blog. Useful stuff, life, photography, kids, technical, programming, and what-else? "Getting Started with tcltest"]], 2011. *[[http://wiki.tcl.tk/14465|Tcl.tk Wiki "Your first tcltests"]]. *[[http://www.wellho.net/|Well House Consultants LTD]]. *[[http://www.wellho.net/mouth/4457_Test-framework-for-TCL-Tcltest-some-examples.html|Well House Consultants LTD. "Test framework for TCL - Tcltest - some examples"]]. *[[http://www.wellho.net/resources/ex.php4?item=t249/ttrun|Well House Consultants LTD. "tcltest - an example running all the tests in a directory"]]. *[[http://paste.tclers.tk/425|paste.tclers.tk "small tcltest example"]]. *Mirrors: *[[http://www.mkssoftware.com/docs/man1/tcltest.1t.asp|MKS Software "Tcltest - Test harness support code and utilities"]]. *[[http://web.ics.purdue.edu/~aai/tcl8.4a4/html/TclCmd/tcltest.htm|Phil Cheeseman "Tcl Built-In Commands - tcltest manual page"]]. ==== The Simple Development Library ==== *The OpenSource [[http://simpledevlib.sourceforge.net/|SourceForge "The Simple Development Library. A collection of packages and utilities for Tcl development"]], [[http://www.sourceforge.net/projects/simpledevlib|SourceForge "The Simple Development Library"]] -> "SimpleTest: regression testing framework". ==== t-unit ==== *The OpenSource [[http://code.google.com/p/t-unit/|Google Code "t-unit. a unit test framework for the tcl programming language"]]. ==== tclunit ==== *The OpenSource [[http://www.sourceforge.net/projects/tcllib/files/|SourceForge "tcllib"]] - "tclunit". *[[http://wiki.tcl.tk/5647|Wiki.Tcl.Tk "ANNOUNCE: tclunit 0.1"]] ==== TclUnit ==== *The OpenSource [[http://tclunit.sourceforge.net/|SourceForge "TclUnit"]], [[http://www.sourceforge.net/projects/tclunit/|SourceForge "TclUnit"]]. *The free [[http://wayback.archive.org/web/*/http://park.ruru.ne.jp/ando/work/tclTkUnit/|Archive.org "TclTkUnit"]] ( -2012-10-09 ). ===== Application Testing with Expect, DejaGnu, tcl-automated-test-framework ==== ==== Expert ==== *The OpenSource [[http://expect.sourceforge.net/|Sourceforge "Expect"]], [[http://www.sourceforge.net/projects/expect/|Sourceforge "Expect"]], [[http://www.nist.gov/el/msid/expect.cfm|National Institute of Standards and Technology (NIST) "Expect"]] - "a tool for automating interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, etc. Also useful for testing these same applications". *Book [[http://www.amazon.de/exec/obidos/ASIN/1565920902/hemmerling-21|Don Libes: "Exploring EXPECT: A TCL Based Toolkit for Automating Interactive Programs (Nutshell Handbooks)"]] ( 1994 ). ==== Tools based on Expert ==== *The OpenSource [[http://www.gnu.org/software/dejagnu/|DejaGnu]] - "A framework for testing other programs", "DejaGnu is written in [[http://expect.sourceforge.net/|Expect]], which in turn uses Tcl -- Tool command language". *The OpenSource [[http://code.google.com/p/tcl-automated-test-framework/|Google Code "tcl-automated-test-framework. Test Automation Framework written in Tcl Expect for testing product with CLI"]]. ===== Appropriate OpenDirectory Directory Pages ===== *[[http://www.dmoz.org/Computers/Programming/Languages/Tcl-Tk/|OpenDirectory "Top: Computers: Programming: Languages: Tcl-Tk]]. *[[http://www.dmoz.org/World/Deutsch/Computer/Programmieren/Sprachen/Tcl-Tk/|OpenDirectory "Top: World: Deutsch: Computer: Programmieren: Sprachen: Tcl-Tk"]]. {{tag>"Unix script languages" "script languages" "script language" "Tcl / Tk" Tcl Tk tickle}}