Sunteți pe pagina 1din 71

ATS Automated Test Software Style Guide

Brian Jackson Test Technologies


EDCS-303404 Version: 1.5 Approved February 3, 2004

Abstract
This document describes the Cisco Test Technologies style convention standards for development of ATS automated test scripts and procedure libraries.

ATS Automated Test Software Style Guide Copyright 2004 Cisco Systems, Inc. All rights reserved. Cisco Confidential For Internal Use Only

Table of Contents

Table of Contents
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 Quoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1 Quoting for Variable, Command, and Special-Character Substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Quoting for Variable, Command, and Special-Character Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Default to the Use of Double Quotes to Quote Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Quote Single-Element Strings Using Double Quotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Quote Expressions Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Quote Expressions Using Curly Braces to Maintain Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.2 Quote Expressions Using Curly Braces to Improve Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.3 Quote Looping Expressions Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 Quote Code Blocks Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7 Quote Procedure Bodies and Script Sections Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8 Quote Non-Space-Delimited Variable Names Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.9 Quote Procedure Argument Lists Using Curly Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Commands and Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1 Command Placement and Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Code One Command per Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Split Lengthy Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2.1 Split Command Lines That Exceed 80 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2.2 Use join to Split Strings That Exceed 80 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2.3 Split Commands at Logical Breaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Quote Code Blocks Using Curly Braces (Reminder) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.2 Align Opening and Closing Code Block Curly Brace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.3 Indent the Contents of Code Blocks Four Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.4 Avoid Excessively Long or Deeply Nested Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.5 Treat Script Sections and Device Configurations As Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.6 Treat Procedure Bodies As Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Command Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Use Spaces to Delimit Operators and Values in Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.2 Exclude the Equality Operator from Boolean Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.3 Explicitly Define Expression Operation Precedence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Special Command Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 Handling switch Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.2 Handling for Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.3 Do Not Include then in if Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.4 Using switch Versus elseif Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.5 Use "--" string to mark end of options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.6 Handling uplevel and upvar statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.7 Handling case statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 White Space and Indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 Code Logic White-Space Separation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Use One Line of White Space to Visually Segment Software Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Using Formfeeds for Print Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 4 4 4 5 5 6 7 8 8 11 11 11 11 12 12 13 13 13 13 14 14 15 15 15 15 16 17 17 17 18 18 19 19 19 20 21 21 21 22

ATS Automated Test Software Style Guide

Table of Contents

4.2 Indent Nested Code Blocks Four Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Format Comments Like Bullet Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Comment All Logical Blocks of Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Indent Comments to Align Them with the Code That Follows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Add Comments at End of Nested Code Blocks (Optional) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5 Variable Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1 Document Constants and Important Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.2 Document Internal Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.6 Script Header and Footer Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.6.1 Include the Standard Script Header Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.6.2 Include the Standard Script Footer Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7 Procedure Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.1 Include Script Procedure Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.2 Include the Standard Procedure Library Header Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.3 Include the Standard Procedure Library Footer Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.4 Include Standard Procedure Library Procedure Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.7.5 Include Procedure Library Internal Procedure Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.8 ITcl Class Library Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.8.1 Include the Standard Class Library Header Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.8.2 Include Standard Class Library Method Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.9 Comment Nonintuitive Script Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.10 Use Comments to Document Output Being Parsed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.11 Comment Router Configurations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.12 Generating Documentation from Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.13 Include Cisco copyright notice in all files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.14 Include RCS $Id$ tag in all files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.1 Assign Meaningful Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Use Standard Characters in Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3 Abbreviate Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4 Techniques for Constructing Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1 Underscore-Delimited Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.2 Camelback Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5 Name Prefixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.1 Name Space Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.2 Use Simple Name Prefixing in Test Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.3 Use Name Spaces in Procedure Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.4 Begin Names with Underscores to Hide Them . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.6 Name Constant Variables Using Uppercase Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.7 Name Files Using Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 23 23 24 24 25 25 25 26 26 29 30 30 30 32 32 34 35 35 36 37 37 38 39 39 39 41 41 41 42 42 42 42 43 43 43 44 44 44 44

7 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 7.1 Define and Use Constant Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 8 Software Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 8.1 Script Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 8.2 Procedure Library Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

ATS Automated Test Software Style Guide

ii

Table of Contents

9 Emacs TCL Mode and Fontification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 10 Where to Go from Here . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Appendix A: Style Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

ATS Automated Test Software Style Guide

iii

1 Introduction

1 Introduction
This document addresses automated software coding style. Style issues affect the look and feel of the code being developed. Although virtually any style can be used to implement Tool Control Language (TCL) code, the style conventions presented in this document are intended to reduce the potential for error by fostering sound style practices. Additionally, the use of the following standard style will help to improve the maintainability and understandability of your code both by other users and by yourself when you return to work on a script after a lengthy absence. Finally, the use of this style will promote code sharing by ensuring that your code looks the same as that developed by other adopters of this style. In applying a coding style, respecting the intent of each style rule is more important than adhering to the letter of the law. Either follow the rule as given or develop your own rule to address the need as you see fit. Any script that follows a well-thought-out and consistent style will achieve the goal of being understandable and maintainable, by yourself and others, and will avoid common coding errors. So don't be rigid about using this style guide. Do become familiar with its intent and how it can shape or supplement your own personal style. Also note that some of these style elements affect performance and enable the use of certain tools (for example, ATSDOC documentation generation). Style guidelines presented in this document apply equally to the development of test scripts and script development procedure libraries. This document is the Test Technologies approved style guide for all TCL software developed for use with the Automated Test System (ATS). The Style Summary provides a quick overview of the most important topics in this document. From there you can click the style item titles to see the details of any style rule. This document is appropriate reading for any developer of ATS TCL language based automated test software, either scripts or procedure libraries. Send comments and questions about this document to the test-consulting mailing list.

ATS Automated Test Software Style Guide

1 Quoting

ATS Automated Test Software Style Guide

1 Quoting

2 Quoting
Quoting is one of the most fundamental aspects of TCL. As such, it is also the most common source of TCL scripting errors. This section discusses standard style for the quoting of strings, expressions, and code blocks. For a detailed discussion of quoting, refer to the Tcl Scripting Language Primer.

2.1 Quoting for Variable, Command, and Special-Character Substitution


One common error in developing TCL software is incorrectly quoting strings in such a way that variable, command, and special-character substitution is suppressed when substitution is actually intended. In TCL, double quotes are used to quote strings in which substitution is to occur. The following code fragments allow for proper substitution: set data 1 puts "Data: $data"; # Outputs: Data: 1 puts "TCL Version: [info tcl]"; # Outputs: TCL Version: 8.0 puts "Tab\tcharacter"; # Outputs: Tab character If you find unwanted dollar signs, square brackets, or backslashes in your output, odds are that you've quoted a string in curly braces instead of double quotes.

2.2 Quoting for Variable, Command, and Special-Character Suppression


To suppress the substitution of variables, commands, and special characters, place your string in curly braces, as seen in the following example: puts {Referencing $variable}; # Outputs: Referencing $variable puts {Calling [info tcl]}; # Outputs: Calling [info tcl] puts {Tab is \t} # Outputs: Tab is \t To suppress the substitution of only some elements of a string, place the string within double quotes and use backslash (\) characters to escape the special meaning from specific characters. The following code fragment suppresses substitution of the first dollar sign: set var 1 puts "\$var == $var"; # Outputs: $var == 1

2.3 Default to the Use of Double Quotes to Quote Strings


It might seem that a standard rule for quoting should be to quote data in curly braces when it contains nothing to be expanded or when you wish to suppress substitution and to use double quoting in all other cases. However, this practice is not recommended. Instead you should default to the use of double quoting wherever possible. The reason for this rule is that curly braces are used extensively throughout a script to quote code blocks. Quoting data in double quotes makes it stand out as uniquely "data" amongst all the other quoting. So use double quotes by default to quote all data. Use curly braces to quote data only when you need to suppress substitution.
ATS Automated Test Software Style Guide 3

1 Quoting

Instead of quoting a string as in the following example: set variable {This is the contents of the variable} you should quote the string using double quotes, as in this example: set variable "This is the contents of the variable"

2.4 Quote Single-Element Strings Using Double Quotes


In order to visually highlight string data, always quote a string using double quoteseven if the string is composed of only a single word. The following code fragment shows proper quoting of a single-element string: pak_process parse $pak "output" The exception to this rule is that you need not quote single-variable strings or strings that are being passed to a procedure as a subcommand. In the example above, the argument variable $pak is not quoted, because it is a single-variable string, and the string 'parse' is not quoted because it is a pak_process subcommand argument. The argument string 'output' is quoted because it is a string data argument.

2.5 Quote Expressions Using Curly Braces


Always quote expressions using curly braces. The consistent use of curly brace quoting helps establish visual consistency within your code, improves performance, and can prevent errors in looping logic. This section presents explanations for a policy of quoting all expressions using curly braces.

2.5.1 Quote Expressions Using Curly Braces to Maintain Consistency


Always quote expressions using curly braces to establish visual consistency within your code. TCL requires you to quote expressions only if they contain spaces. Therefore, many expressions (for example, Boolean expressions) need not be quoted. The following code fragment shows an if statement containing an unquoted Boolean expression: set var 1 if $var { puts "var is true" } Although this code fragment will evaluate, it breaks the visual consistency of code in which all other expressions are quoted in curly braces. In the following example, notice that the first expression is not quoted while all others are: if $debug_flag { if {$debug_option == "verbose"} { puts "Verbose debugging is requested" } else { puts "Non-verbose debugging is requested" } } To improve the visual consistency of the example above, the first expression should be quoted
ATS Automated Test Software Style Guide 4

1 Quoting

using curly braces: if {$debug_flag} { if {$debug_option == "verbose"} { puts "Verbose debugging is requested" } else { puts "Non-verbose debugging is requested" } } Notice that in this reimplementation of the previous example, the if expression '$debug_flag' has been quoted.

2.5.2 Quote Expressions Using Curly Braces to Improve Performance


An even greater reason for quoting all expressions using curly braces concerns performance. If you fail to quote an expression, the TCL interpreter will perform variable, special-character, and command substitution on the expression twicefirst before the command is evaluated, and again when the command evaluates the expression. By quoting expressions in curly braces, you suppress the first substitution pass and as a result improve the performance of the command. Consider the following example in which the expression is quoted using square brackets to force command substitution: if [string match "-verbose" $args] { puts "The verbose argument was received" } Because the above expression is not quoted using curly braces, it will incur the overhead of having multiple substitutions performed on the expression. The following code fragment shows the above example rewriten to properly quote the if expression: if {[string match "-verbose" $args]} { puts "The verbose argument was received" } Although quoting with both curly braces and square brackets in the example above may seem redundant, it should be used anyway because it improves the performance of the code by suppressing the first substitution pass. Note: Because of the performance impact, failing to quote expressions in curly braces will produce a warning message when you scan your code using the Tcl validator, Tclchecker (formerly named Procheck). This utility is located in '/auto/ttsw/bin/tclchecker'. You must run '/auto/ttsw/bin/as-install-license' to install a product license before you can run tclchecker. In another application of this standard, you should always quote arithmetic expressions using curly braces. As is the case with other expressions, the reason for quoting arithmetic expression in curly braces is both a cosmetic and performance consideration. For example: set var [expr {$a * $b}] In this example, the expr command will perform substitution on the expression before it is evaluated. Because the expression is quoted, the interpreter will not perform substitution before the expression is passed to expr. This treatment will dramatically improve the performance of this command.

2.5.3 Quote Looping Expressions Using Curly Braces


You should use curly braces to quote expressions passed to looping commands such as the
ATS Automated Test Software Style Guide 5

1 Quoting

TCL while and for commands not only to maintain visual consistency and suppress multiple substitutions but also to prevent infinite loops. Consider the following example: set flag 1 set count 1 while $flag { incr count if {$count > 100} { set flag 0 } } At first glance, it would appear that the above code fragment is a clumsy attempt to stay in a spin loop for 100 iterations. However, since the variable reference $flag is replaced with the value of the variable before being passed to the while command, this in fact becomes an infinite loop, as in 'while 1' . Such errors can be avoided by enclosing the expression in curly braces and thus deferring the variable substitution of $flag to a point within the while loop. This can be seen in the following example: set flag 1 set count 1 while {$flag} { incr count if {$count > 100} { set flag 0 } } The same potential for error and associated style convention applies to use of the TCL for command and any other looping command expression. Warning: Never quote expressions in double quotes. This treatment is meaningless because all expressions can be evaluated and substituted just as easily by the command to which they're passed, and it ruins the visual consistency of your code. It also leads to substitution errors such as those just discussed. In summary, quote all expressions in curly braces to achieve visual consistency, improve command performance, and avoid infinite loops. The following example demonstrates curly brace quoting used to accomplish all these goals: if {[info exists flag]} { if {$flag} { for {set i 1} {$i < 10} {incr i} { puts "${i}: Flag is set" } } else { puts "Flag is not set" } }

2.6 Quote Code Blocks Using Curly Braces


Code blocks should always be quoted within curly braces, with the first command and closing brace starting on their own lines. Although double quotes can be used to quote a code block, this practice should be avoided because the TCL interpreter will immediately evaluate and expand the variable and command substitutions in the block before they are passed to the conditional or looping logic used to execute them. In all cases, opt for deferred evaluation of the code. This is achieved by quoting the code block within curly braces. The use of curly braces to quote code blocks also contributes to consistency within your software and makes the code
ATS Automated Test Software Style Guide 6

1 Quoting

block stand out as a code block. For example, rather than coding this: if {[string match "8*" [info tclversion]]} " puts "This is TCL version 8" " you should code the following: if {[string match "8*" [info tclversion]]} { puts "This is TCL version 8" } In this case, both quoting styles would produce the same result; however, notice that the second style makes the code block stand out as something different from the quoted string in the string match expression. The following example shows a case in which double-quoting of a code block will not produce the desired result: set counter 0 while {$counter < 10} " set counter [expr {$counter + 1}] " Here, because the code block is double-quoted, it will be evaluated by the TCL interpreter before it is passed to the while command, with the result that the body of the while statement becomes the static expression 'set counter 1' . This will produce an infinite loop. Note that you should always quote the body of a conditional or looping command, even if it is not required. This practice will help to establish a consistent visual look for all command bodies, as seen in the following example: if {$option == "debug"} { debug }

2.7 Quote Procedure Bodies and Script Sections Using Curly Braces
Treat procedure bodies and script sections as you would code blocks by always quoting them in curly braces. For example, you should never code these elements as follows: proc display {msg} " puts $msg " test_config " $router config " interface Ethernet1 no shutdown " " Not only does the use of double quotes confuse the visual presentation of your code but, in the case of the procedure definition example above, it causes errors. The above procedure definition will perform a variable substitution on $msg when the procedure is defined instead of when it is called. Quote all procedure bodies using curly braces so that evaluation and substitution will be deferred until invocation.
ATS Automated Test Software Style Guide 7

1 Quoting

The above example should be coded as follows: proc display {msg} { puts $msg } test_config { $router config " interface Ethernet1 no shutdown " }

2.8 Quote Non-Space-Delimited Variable Names Using Curly Braces


Place curly braces around variable names to delimit them in relation to surrounding text when white space or punctuation cannot be used for this purpose. You may encounter the need to display the contents of a variable with no space between those contents and surrounding fixed text. In the following code fragment, we're attempting to display the contents of the variable var concatenated with the string 'd': set var "value" puts "$vard"; # Produces an error This code fragment will produce an error because the TCL interpreter will search for a variable named vard. Instead, we should encapsulate the variable name in curly braces to delimit it, as in the following example: set var "value" puts "${var}d"; # Outputs "valued" This code fragment will be correctly interpreted to produce the output valued. In cases in which a variable name is not delimited by a space but is delimited by characters that are not valid within a variable name, the TCL interpreter will correctly interpret the code, as in the following examples: set var1 "my" set var2 "data" puts "$var1$var2"; # Outputs "mydata" puts "$var1.$var2"; # Outputs "my.data" The coder may excercise discretion as to whether to quote the variable names: set var1 "my" set var2 "data" puts "${var1}data"; # Outputs "mydata" puts "${var1}${var2}"; # Outputs "mydata" puts "${var1}.${var2}"; # Outputs "my.data"

2.9 Quote Procedure Argument Lists Using Curly Braces


TCL requires you to quote the list of arguments accepted by a procedure if that procedure accepts more than one argument. This practice is required so that the argument list can be passed as a single element to the TCL proc command. When a procedure accepts only one argument, TCL does not require that argument name to be quoted; for example:
ATS Automated Test Software Style Guide 8

1 Quoting

proc msg string { puts $string } Although TCL does not require you to quote single-argument lists, you should always quote all procedure arguments lists in curly braces to establish consistency in the look of all procedure definitions. Therefore, the above example should be coded as follows: proc msg {string} { puts $string } Note: When a procedure accepts no arguments, you should supply an empty list ({}) as the argument list in the procedure definition.

ATS Automated Test Software Style Guide

1 Commands and Code Blocks

ATS Automated Test Software Style Guide

10

1 Commands and Code Blocks

3 Commands and Code Blocks


This section discusses style issues related to coding of TCL commands and code blocks in your software. Code blocks contain multiple commands that are to be evaluated by a command or procedure, typically either conditionally or in a loop.

3.1 Command Placement and Length


An important aspect of script readability, and therefore its maintainability, is the placement and length of commands. Typically, commands should be written on separate lines in such a way that no individual command exceeds 80 characters in length. This section discusses these two aspects of command coding, providing examples and outlining the exceptions to these general rules.

3.1.1 Code One Command per Line


Although TCL supports the ability to code multiple commands on a single line by ending each command with a semicolon (;), you should not take advantage of this feature. Code TCL commands on separate lines. By encoding each command on its own line, you'll make your scripts easier to read, understand, and debug. The only appropriate times to use semicolons in an ATS script are when placing a comment at the end of a line and when separating variable set commands in for loop expressions. You can use this method to comment on variables and constant definitions, to document the ends of deeply nested code blocks, and to highlight commands of interest. The following example shows the use of the semicolon in these instances: set FAIL 0; # Use this constant to return failure from a script set PASS 1; # Use this constant to return success from a script for {set s 1; set p 0} {$s < $MAX_STRING} {incr s; incr p} { if {$s == 1} { ... }; # End of if {$s == 1} }; # End of for loop Most TCL examples will show the semicolon indented to immediately precede the pound sign (#) (for example, 'set FAIL 0 ;# Use ...' ). An alternative is to terminate the command with the semicolon and place spaces after the semicolon up to the comment character. You should feel free to use either convention, but stay consistently with one style or the other. Note: The need to use end-of-block comments can point to the fact that your nested blocks are too long. You may want to reduce the length of some blocks by turning them into well-documented procedures rather than leaving them as one long listing of code.

3.1.2 Split Lengthy Lines


To enhance readability, no single line of TCL code should exceed 80 characters in length. Because many developers set their editor window width to 80 characters, lines that exceed this limit can produce ugly line wrapping that will adversely effect the readability of your code. This section discusses methods for implementing this safe and sane coding practice. The use of 80-character line lengths is a convention inherited from the Cisco IOS style standard. This is a widely used standard within the computing industry.
ATS Automated Test Software Style Guide 11

1 Commands and Code Blocks

3.1.2.1 Split Command Lines That Exceed 80 Characters


No single line of your script should exceed 80 characters in length. Split comment lines appropriately to ensure that no single line of comment exceeds this limit. In the case of command lines that exceed 80 characters in length, you should split the command onto multiple lines by ending each line with backslash character (\) followed by a newline. The backslash character escapes the meaning of the newline (newline is interpreted by TCL as end of command) so that the command can be continued on subsequent lines. For example: if {[string index [lindex $arg 0] 0] == "-" && \ [lindex $arg 1] != "false"} { ... } Some command lines become very long because of nesting of command substitutions in the line. You should split such commands by using temporary variables to store intermediate results and then using the variables in the final command. For example, the following command: if {![regexp {input: +([0-9]+),.+output: +([0-9]+),} \ [$router exec "show interface ethernet 0"] - input output]} { log_diagnostic_msg "Unable to parse shoud interface output" update_test_status $FAIL return } could be recoded as: set pattern {input: +([0-9]+),.+output: +([0-9]+),} set output [$router exec "show interface ethernet 0"] if {![regexp $pattern $output - input output]} { log_diagnostic_msg "Unable to parse shoud interface output" update_test_status $FAIL return } Note: Upon release, this document suggested a maximum line length of 72 characters. Review comments indicated that this was too short. All agreed that lines should not exceed 80 characters. However, most agreed that lines of no more than 76 characters produce more readable code by not crowding the right hand window border and producing a right hand margin roughly the size of the 4 character left hand indent used on many lines. Additionally, code lines of fewer than 80 characters leave room for display of carriage returns by some editors and allow developers to position the cursor at the end of the line without having it wrap to the next line (e.g. 78 characters) It is therefore suggested that you try to leave some space to the right of each code line. To this end, 76 characters is a good target to shoot for.

3.1.2.2 Use join to Split Strings That Exceed 80 Characters


No string within your script should exceed 80 characters in length. In the case of very long string constants, you should split the string into multiple string values and merge them using the TCL join and list commands. For example: log_message [join [list "Interface $interface packet counters," \ "Input counter: $input, Output counter: $output"]] In the above example, a lengthy string is split into two smaller strings. These strings are passed to the list command to be turned into a single two-element list, which is in turn passed to the join command to be merged into a single string. By default, the join command places a space between joined list items. You can pass an optional second argument to join to specify the join
ATS Automated Test Software Style Guide 12

1 Commands and Code Blocks

character; for example, {} would place no characters between the joined list elements. When this method is used to split long strings across multiple lines, tabs and spaces used to align code lines will not be included as part of the new string. Additionally, newline characters will be excluded. When a very long string of text is defined , it is sometimes preferable to allow the newlines to be included in the string so that you can control where long strings break on output. For example: set message { When this method is used to split long strings across multiple lines, newline characters will be escaped so they do not appear in the string. When a very long string of text is defined, it is sometimes preferable to allow the newlines to be included in the string so that you can control where long string break when output. }

3.1.2.3 Split Commands at Logical Breaks


When splitting a long command onto multiple lines, you should not arbitrarily split the command. Instead, split the command at the natural separation points in the meaning of the command. For example, rather than coding this: for {set iptr 0; set optr 0} {iptr < $END_OF STRING} {incr \ iptr} { ... } you should code this: for {set iptr 0; set optr 0} {iptr < $END_OF STRING} \ {incr iptr} { ... } Notice the improved readability of the above command caused by breaking the lengthy command line between expressions rather than in the middle of an expression.

3.2 Code Blocks


Code blocks represent groups of commands that should all be executed in sequence, usually as a result of a conditional expression or within a loop. This section discusses style issues related to coding of TCL code blocks.

3.2.1 Quote Code Blocks Using Curly Braces (Reminder)


Code blocks should always be quoted within curly braces. For a detailed discussion of code block quoting, refer to .

3.2.2 Align Opening and Closing Code Block Curly Brace


Code blocks should always be opened by placing the opening curly brace at the end of the command to which the code block is associated and ended by placing the ending curly brace on a line of its own. The indentation of the opening command line and the closing curly brace should be the same. For example:
ATS Automated Test Software Style Guide 13

1 Commands and Code Blocks

if {[string match "8*" [info tclversion]]} { if {[string match "*2" [info tclversion]]} { puts "This is TCL version 8.2" } } Notice that in the above example, each code block's opening curly brace appears at the end of the line containing the if statement, and the closing curly brace is aligned at the same indentation as the associated if statement. When including an else or elseif extension in an if statement, you should place them on the same line as the closing curly brace, as seen in the following example: if {[string match "8*" [info tclversion]]} { if {[string match "*2" [info tclversion]]} { puts "This is TCL version 8.2" } elseif {[string match "*3" [info tclversion]]} { puts "This is TCL version 8.3" } else { puts "This is TCL version 8" } }

3.2.3 Indent the Contents of Code Blocks Four Spaces


Blocks of code can be nested, and quite often are. For example, TCL if command bodies can contain additional if statements. In the case of nested code blocks, each code block should be indented four spaces. See for a detailed discussion of this topic.

3.2.4 Avoid Excessively Long or Deeply Nested Code Blocks


As much as possible, avoid excessively long or deeply nested code blocks. When code blocks are extremely long, it is difficult for anyone browsing the code to fully understand the actions performed by the code block and then return to the original command flow of the script. Deeply nested code blocks make it difficult for a reviewer of your code to keep track of the many conditions that must be satisfied to enter a block of code. As a general rule, try to write code blocks that are no longer than 24 lines (one screen) and are nested no more than three code blocks deep. When logic requires long code blocks or deep nesting, the logic should be broken up into multiple procedures called from the script or procedure containing the nesting. For example: if {$access_list_flag} { access_list_apply $interface_list foreach interface $interface_list { set result [access_list_evaluate $interface] if {$result} { puts "Access list looks good" } else { puts "Access list looks bad" } } } The example provides an overview of the operations being performed by the script while hiding the particulars of how the operations are performed in procedure definitions. This provides an appropriate level of detail for someone wishing to review a script's functionality; for example, someone trying to determine whether to incorporate a script into their test plan. Logic details can be obtained by reviewing each called procedure. The use of procedures to shorten long code
ATS Automated Test Software Style Guide 14

1 Commands and Code Blocks

blocks and reduce deep nesting also promotes code reusability.

3.2.5 Treat Script Sections and Device Configurations As Code Blocks


In many cases, blocks of code or device configuration commands are passed to a procedure for evaluation. For example, the test_config procedure is used in Autotest scripts to bracket code that initializes a testbed before a test is executed and analyzed. Additionally, the CSCCON router control library config subcommand is used to specify a block of router configuration commands to be applied to a router. In both these cases, the instructions being passed to these procedures should be treated like code blocks, following all the style rules that apply to such blocks. For example: package require Csccon package require Test set router "my_router" test_config { $router config { interface ethernet1 no shutdown } } test_analyze { set result [$router exec "show interface ethernet1"] if {[regexp "line protocol up" $result]} { puts "Everything looks good on ethernet1" } } Notice that standard indentation rules are followed for the if command body being passed to the test_analyze procedure for evaluation. Note: Device configuration blocks are often double quoted to allow for variable expansion. However, you should still indent them as you would any other code block.

3.2.6 Treat Procedure Bodies As Code Blocks


Indent procedure bodies four spaces (just like any other code block). The closing curly brace for the procedure body should align with the beginning of the proc command that initiated the definition (nearly always column 1). For example: proc display {msg} { puts $msg }

3.3 Command Expressions


Arithmetic and Boolean expressions are often passed to TCL commands to perform calculations or to influence conditional command evaluation. This section discusses the style standards for coding such expressions.

3.3.1 Use Spaces to Delimit Operators and Values in Expressions


TCL doesn't require you to use white space separation between numbers, variables, and
ATS Automated Test Software Style Guide 15

1 Commands and Code Blocks

operators in expressions because the operator characters are interpreted as number and variable name terminators. When coding lengthy expressions, you may be tempted to remove white space from the expression in order to fit the entire expression on a single line. For example: if {($pak_siz>=64&&$pak_siz<=1500)||!$pak_err_flg} { puts "Packet contains an error" } However, the simple lack of white space in the above example makes the expression difficult to read. When coding expressions, you should always include white space around operators, numbers, and variable names. If the inclusion of white space forces the expression to exceed a single line, split the expression onto multiple lines using command continuation (\). Using this convention, the previous example would be coded as follows: if {($pak_siz >= 64 && $pak_siz <= 1500) || !$pak_err_flg} { puts "Packet contains an error" } Notice the improvement in readability produced simply by adding white space. Some users find that adding a single space after and before the opening an closing curly braces enhances the readability of an expression.

3.3.2 Exclude the Equality Operator from Boolean Expressions


When using an if statement to test a variable's contents for either true or false (1 or 0), you do not have to code the comparison with true or false. Just code the variable to be evaluated as the sole contents of the expression. For example, rather than coding: set flag 1 if {$flag == 1} { puts "Flag is true" } you should code: set flag 1 if {$flag} { puts "Flag is true" } Both expressions produce the same result; however, the second is terser and easier to read. In the first example, '$flag == 1' is replaced by TCL with the result of the comparison, which is true (1), so the statement is evaluated as 'if {1}' . The same is true of the second example, in which the variable $flag is replaced with its contents ('1'). In addition to performing Boolean comparisons on variable contents, such comparisons can be performed on the result of command substitution, as in the following example: If {[info exists myflag]} { puts "myflag: $myflag" } Note: To negate a Boolean expression (for example, to test the expression for "falseness"), precede the expression with a not sign (!), as in the following examples: if {!$flag} { puts "Flag is false" } if {![regexp {foobar} $output]} {
ATS Automated Test Software Style Guide 16

1 Commands and Code Blocks

puts "Unable to parse output: $output" }

3.3.3 Explicitly Define Expression Operation Precedence


Both arithmetic and Boolean operations in an expression are performed in the standard order of precedence as dictated by the rules of math and logic. The order of evaluation, from top to bottom and left to right, is as follows: Unary operators Binary arithmetic operators Bitwise shift operators Comparison operators Inequality operators Bitwise union operators Logical operators If-then-else operator -+~! */%+-

<< >> < > <= >= == != < > <= >= &^ && || x?y:z

Even though the number of commonly used operators is small, it can be difficult to remember the order in which operations are performed. Even if you do know the order, there's no guarantee that the next person who works on your code will. Therefore, you should always explicitly define the order of the operations to be performed in a multi-operation expression by grouping the operations using parentheses, as in the following example: if {($var > 10) && ($var < 100)} { puts "Value is within range" } set var [expr "(($foo * 100) - ($bar / 7)) + 3"]

3.4 Special Command Considerations


This section discusses style rules as they apply to specific TCL commands. In some cases, coding of TCL commands stretches or breaks the general style rules to enhance the readability of a specific command. In other cases, the coding of a command allows options that should be standardized to develop a consistent style.

3.4.1 Handling switch Statements


Switch statements may break the rule for writing code blocks on separate lines. When the action to be performed by a switch case is a single statement, that statement can be coded on the same line as the switch command expression being evaluated. For example: set option [lindex $args 0]
ATS Automated Test Software Style Guide 17

1 Commands and Code Blocks

set value [lindex $args 1] switch -- $option { "-logging" {set logging 1] "-nologging" {set logging 0} "-timeout" {set timeout $value} } Note: The -- option is passed in the switch statement above not only to utilize the default matching mechanism ( '-exact' ) but to ensure that the contents of the option variable are not misinterpreted as an option should its contents begin with a hyphen. Since a single TCL switch statement can encapsulate a great deal of logic, lengthy code blocks can be associated with each expression. It is sometimes desirable to have each expression evaluate a single procedure invocation instead of a block of code to keep the switch statement short. Coding lengthy logic within a switch statement can be extremely confusing because it is difficult to implement an indentation rule that will make sense of the result. A default case is recommended for each switch statement in order to ensure that appropriate actions are taken for all possible values. In some cases, this could be just to indicate that an unexpected value was found and needs a case to be added for it.

3.4.2 Handling for Statements


The TCL for statement accepts four blocks of code for evaluation. The first block of code is executed when the statement is entered and is used to initialize the environment. The second block of code is an expression used to determine whether the statement should continue to be evaluated. The third block is evaluated between iterations of the for loop. The fourth block, the body, contains the statements to be evaluated during each iteration. The first three code blocks that are passed to a for statement are usually very small. Therefore, when coding a for statement, you can code the first three code blocks on a single line, but the fourth block should be coded on multiple lines as in the case of an if statement body. For example: puts "Countdown: " for {set i 1} {i <= 100} {incr i} { puts "\t$i..." } puts "" When one or more of the first three code blocks of a for statement are so long as to exceed 80 characters when taken together, the blocks should be separated onto multiple lines, as in the following example: for {set i 0; set j [length $string]} \ {$i < $j} {incr $i; incr $j -1} { ... } Notice in this example that semicolons have been used to separate statements within two code blocks. Since for command code blocks are typically very short, it is acceptable, and often desirable, to use semicolons in these code blocks to allow placing the entire code block on a single line.

3.4.3 Do Not Include then in if Statements


Although TCL supports the optional inclusion of the then clause, you should not include it in your if statements. For example: if {1} then {
ATS Automated Test Software Style Guide 18

1 Commands and Code Blocks

puts "True" } should be coded as: if {1} { puts "False" } The two if statements shown above produce identical results. The first statement includes the optional then clause, which adds nothing to the understanding of the statement and makes if differ from other standard languages such as C and Perl that don't support the then clause. You should always use the second form when encoding an if statement.

3.4.4 Using switch Versus elseif Statements


In most cases, you should be perfectly content to code conditional branching logic using if statements containing elseif and else clauses. For example: if {[string match "8*" [info tclversion]]} { if {[string match "*2" [info tclversion]]} { puts "This is TCL version 8.2" } elseif {[string match "*3" [info tclversion]]} { puts "This is TCL version 8.3" } else { puts "This is TCL version 8" } } However, should the number of conditions to be evaluated become exceedingly long, you should instead use a switch statement to reduce the amount of code needed to perform the evaluation. For example: switch -glob [info tclversion] "8*2" {puts "This is TCL "8*3" {puts "This is TCL "8*" {puts "This is TCL } { version 8.2"} version 8.3"} version 8"}

A single switch statement is often easier to read and understand than a lengthy chain of elseif expressions. Consider using switch instead of if when the number of expressions to evaluate exceeds three.

3.4.5 Use "--" string to mark end of options


Some Tcl commands support an arbitrary number of dashed options followed by an arbitrary number of arguments: in particular, regexp, regsub, and switch. Where an argument has the possibility of starting with a dash, Tcl can be confused into thinking an argument is an option where it isn't. Even if the argument is constant and doesn't start with a dash, there is the possibility of code being modified in the future and making it non-constant with dash as a possible first character. To avoid bugs, you should always use the "--" string to mark the division between options and arguments, even if it does not currently seem necessary. regexp -all -nocase -- $pattern -> result

3.4.6 Handling uplevel and upvar statements


ATS Automated Test Software Style Guide 19

1 Commands and Code Blocks

The uplevel and upvar statements both take an optional first argument that indicates where in the call stack the command should apply. For uplevel, the given command is executed in the appropriate scope. For upvar the named variable in the appropriate scope is linked to a local variable. By default, the scope is that of the immediate parent in the call stack. There can, however, be a performance impact and Tcl may do the wrong thing if the first argument looks like it could be a level because these commands take a variable number of arguments. To prevent this, always specify a level as the first argument. Use level 1 to get the same scope as you would if the level were not specified: uplevel 1 $cmd $args

3.4.7 Handling case statements


The case command is an obsolete form of switch. It should not be used in new code, and preferrably should be replaced by switch. The command uses and style rules are very similar.

ATS Automated Test Software Style Guide

20

1 White Space and Indentation

4 White Space and Indentation


It may only be empty space, but it's still important to the readability and maintainability of your software. This section discusses standards for the use of white space to separate your software visually into sections and to highlight the nesting of code blocks.

4.1 Code Logic White-Space Separation


Blank lines of separation can be used to separate your software visually into blocks of logic. This section discusses two methods for visually delimiting the logical blocks of your software using white space.

4.1.1 Use One Line of White Space to Visually Segment Software Logic
Use of blank lines in your software is an effective way to separate and group your program logic. Your choice of the groupings that you highlight is somewhat subjective, but in general you should attempt to group your code into blocks of from 2 to 20 lines by placing blank lines between related blocks of code. For example: set output [$router exec "show interface $int1"] foreach s [split $output "\n"] { regexp {([0-9]+) packets input} $output - $ipaks } if {![info exists ipaks]} { log_diagnostic_msg "Unable to parse router show interface output:\n$output" update_test_status $FAIL return } if {$output > $threshold} { log_diagnostic_msg "Input packet threshold ($theshold) exceed" update_test_status $PASS } else { log_diagnostic_msg "Input packet threshold ($theshold) not exceed" update_test_status $FAIL } Note: The use of white-space separation is particularly effective in combination with code block comments, as seen in the following enhanced version of the example above: # Extract the input counter value from the router # "show interface" output for the target interface set output [$router exec "show interface $int1"] foreach s {[split $output "\n"]} { regexp {([0-9]+) packets input} $output - $ipaks } if {![info exists ipaks]} { log_diagnostic_msg "Unable to parse router interface output:\n$output" update_test_status $FAIL return } # Register the result of this test based on the number # of incoming packets received if {$output > $threshold} { log_diagnostic_msg "Input packet threshold ($theshold) exceed"
ATS Automated Test Software Style Guide 21

1 White Space and Indentation

update_test_status $PASS } else { log_diagnostic_msg "Input packet threshold ($theshold) not exceed" update_test_status $FAIL } Just a word of caution: don't overuse white space when separating code logic. A single line of white space will suffice for separation; never use more. If you're adding white space to enhance the printed output of your code, use the technique outlined in the next section instead.

4.1.2 Using Formfeeds for Print Formatting


You may optionally choose to insert formfeed characters (^L) into your software to enhance its readability when printed. These characters will be ignored by the TCL interpreter but will force a printer to eject the current page before printing continues. You can use formfeeds to force blocks of code to remain together on a single page. For example, you may wish to place formfeeds between all procedure definitions in a library. The method used to insert formfeeds into your software is dependent upon your editor. In Emacs, enter the key sequence C-qC-l

4.2 Indent Nested Code Blocks Four Spaces


Blocks of code can be nested, and quite often are. For example, TCL if command bodies can contain additional if statements. If code blocks are nested, each code block should be indented four spaces. By indenting each nested code block four spaces, you'll clearly identify separations in the logic of your software. For example: foreach s {"one" "two" "three"} { set len [string length $s] if {$s == "one"} { puts "The first string is length of $len" } else { puts "This isn't the first string" puts "Its length is $len" } } This indentation standard is adopted from the Cisco IOS router software style guide. Note: Any combination of tab and space characters can be used to produce the required indentation. The standard is to insert the required number tabs, bound to 8 character tab stops, followed by 4 spaces if required.

ATS Automated Test Software Style Guide

22

1 Comments

5 Comments
Anything that aids in the readability of software, such as white space, also enhances its maintainability. Comments are another such element. It is important to comment your code so that you and others can better understand it later. This section contains a description of the various styles of commenting that should be incorporated into a well-formed script.

5.1 Format Comments Like Bullet Items


All comments should begin with a pound sign (#) followed by a single space and a sentence whose first letter is capitalized. You may indent portions of a comment to highlight sample text and other items that are not part of the comment being made. Comment sentences are typically not terminated by periods. If several sentences are required to create a comment, you can either end each sentence with a period or simply begin each sentence on a new comment line. Always use an initial capital letter. Comments must appear on a line by themselves unless they follow a semicolon. Separation of commands and comments by means of a semicolon should be used only to document variables and the end of nested blocks. Each comment line must not exceed 80 characters in length. For example: # Update the program counter . . . # Extract the input packet counter from the router show # interface output . . . # Recalibrate the traffic rate # Traffic rate recalibration must be performed periodically # to ensure valid test results . . . This standard applies to embedded code comments. Header comments should be written as you would a document, using periods to terminate sentences and blank lines to represent paragraph breaks.

5.2 Comment All Logical Blocks of Code


Natural breaks in software logic should be delineated with a single line of white space. In addition, each block of software logic should be preceded by a brief comment explaining the operation being performed. For example: # Display a sorted list of the TCL commands # Insert blank lines between commands beginning with # different characters # Iterate across a sorted list of all TCL commands set command_list [lsort [info commands]]
ATS Automated Test Software Style Guide 23

1 Comments

foreach command {$command_list} { # Print a blank line between commands starting with # different characters set first_letter [string index $command 0] if {[info exists prev_letter]} { if {![string match $first_letter $prev_letter]} { puts "" set prev_letter $first_letter } } # Display the current command puts $command } In the above example, we've preceded the entire code fragment with a comment explaining its function, and then we've inserted brief comments to explain each logical portion of the code. Notice that there is no blank line placed between the comment and the code in the individual logic blocks. This practice binds the comment to the code being described.

5.3 Indent Comments to Align Them with the Code That Follows
Comments that describe a following block of code should be indented to align with the code. The alignment make it obvious that the comment belongs with the following code. For example: # Iterate across a sorted list of all TCL commands set command_list [lsort [info commands]] foreach command {$command_list} { # Print a blank line between commands starting with # different characters set first_letter [string index $command 0] if {[info exists prev_letter]} { if {![string match $first_letter $prev_letter]} { puts "" set prev_letter $first_letter } } # Display the current command puts $command }

5.4 Add Comments at End of Nested Code Blocks (Optional)


When code blocks are long or excessively nested, it is sometimes difficult to determine which code block is being closed by a curly brace. In these cases, follow the curly brace with a brief comment identifying the code block being closed. For example: if {$route_flag} { ... foreach route {$route_list} { ... if {$security_flag} { ... }; # End of if {$security_flag} }; # End of foreach route loop }; # End of if {$route_flag}
ATS Automated Test Software Style Guide 24

1 Comments

When a comment is placed on the same line as a closing curly brace, or any other TCL syntax element, the comment must be separated from the brace by a semicolon (;). The semicolon indicates that the current command is completed and a new command followsthat new command being a comment in this case. Warning: You shouldn't need to make frequent use of this style element because no code block should be so long or so deeply nested as to cause the reader to lose track of the closing curly brace. It is preferable to break such code blocks into multiple procedure calls. However, if you absolutely must keep the logic all in one place, use this method to document your code blocks.

5.5 Variable Comments


Variables and data structures may warrant special documentation. Some software maintains a great deal of data stored in several variables. Both TCL arrays and keyed lists can be used to create complex data structures containing multiple fields, each for a specific purpose. In such cases, add comments to your code explaining the use of important variables and data structures.

5.5.1 Document Constants and Important Variables


Variable constants (explained later in this document) should be defined at the beginning of your script. In addition to initializing each constant, you should include a comment explaining the purpose and use of the constant. For example: set MAX_RETRY_COUNT 10; operation set MIN_PAK_SIZE 64; set MAX_PAK_SIZE 1500; # Maximum number of times to try an # Minimum size of a valid IP packet # Maximum size of a valid IP packet

The convention of using a semicolon followed by a comment describing the constant conserves space so that all constant definitions can be viewed on a single screen. Use simple comments to document important variables, as shown in the following example: # # # # # Important Variables: command_max command_current command_prev Maximum number of commands to be processed Current command being processed Last command processed

5.5.2 Document Internal Data Structures


Complex data structures do not need to be initialized. So there is no initialization statement to provide an obvious place for descriptive comments. However, you should still include comments at the top of your script explaining the use of such variables and the purpose for each field. For example: # # # # # # # # Important Data Structures: Global Array: tcl_command_list Used to store information about TCL commands Indexes: command,[1-n] Contains the command name type,[1-n] Contains 'p' for proc, 'c' for command used,[1-n] Exists if the command has been executed

The above example shows the documentation for a complex data structure that could be used to
ATS Automated Test Software Style Guide 25

1 Comments

store information about TCL commands. The data structure is stored as an array and contains elements for the command name itself, whether the command is a proc or a TCL built-in command, and a flag to indicate whether the command has been executed. The array is initialized later in the script, so a block comment is used to document it.

5.6 Script Header and Footer Comments


All ATS test scripts should contain standard script header and footer comments to assist users in the execution and maintenance of the script. This section discusses the format of these comments.

5.6.1 Include the Standard Script Header Comment


All scripts should begin with a standard header comment containing a common set of descriptive elements in a specified order. This comment, known as the standard script header comment, specifies the minimum information that the header should contain and can be extended to include additional information as needed. The script header should be placed immediately after the interpreter invocation line at the top of your script. The following fields constitute the script header comment: ##Script Header $Id: $ A visual flag that indicates to automated documentation generators that the following comment is a script header comment. The first line of the header comment should be included unmodified. This line will be replaced by Concurrent Versioning System (CVS) upon script checkout to indicate the version of the script being used. The second line of the header comment should be included unmodified. The standard Cisco copyright should be included in all software developed at Cisco. The name of the script. This must match the filename containing the script. A single sentence explaining the testing performed by the script. The person, identified by name and group, who developed the script and is responsible for its maintenance. (Optional) Include pointers to any external documents related to this test script, such as a test plan or a functional specification. Supply EDCS numbers where available. A detailed description of the testing performed by the script. A character mode diagram of the testbed topology required to run the script. If topology is unimportant, or the script runs on a single device, it is sufficient to simply state the topology requirements using a few words. An overview of the usage syntax for the script. Identify variable arguments by enclosing a symbolic name for the argument in angle brackets. Identify optional arguments by enclosing them within square brackets and separating the values by the or sign (|) surrounded by spaces. Identify required arguments by enclosing them in curly braces and using the or sign to delimit possible values. Use an ellipsis (...) to indicate that the preceding argument can be repeated any number of times.

Copyright (c) 2003 Cisco Systems, Inc. Name: Purpose: Author: References:

Description: Topology:

Synopsis:

ATS Automated Test Software Style Guide

26

1 Comments

Arguments:

List the arguments accepted by the script, one argument per line, and explain the purpose and use of the argument. Include valid values and numeric ranges in the description. Provide samples of one or more suite or job file entries used to invoke the script, along with comments explaining their significance. Include a pointer to a committed suite file in this section if one exists. Interpretation of test results should be outlined. This includes the pass/fail criteria of the script. Note that if a script implements multiple test cases, it may be more appropriate to specify the pass/fail criteria for each test case in the "Test Steps" section of this header. (Optional) Include a sample of the diagnostic output generated by the script. Include explanations of any values that are not self-explanatory in the sample. (Optional) It is often useful to enumerate the steps performed by a script in the header comment. It may be sufficient to simply explain a script's functionality in the "Description" section, but if a script performs many actions or is very complex, it may be best to outline these actions as numbered steps in this section. (Optional) The username or mailing list used to contact the individual or group providing support for this script. (Optional) Any usage notes of interest that you wish to highlight for this script. (Optional) List any known bugs in this script along with any workarounds. (Optional) List any enhancements that you have planned for the script but haven't yet implemented. You or someone else may do further work on the script. (Optional) List any other related scripts that anyone running this script should also consider running. Since script header comments can be lengthy, this comment provides a visual flag that can be searched for in order to skip over the header comment while in the editor.

Sample Usage:

Pass/Fail Criteria:

Sample Output: Test Steps:

Support Alias: Notes: Known Bugs: Todo:

See Also: # End of Header

The following example shows a script header comment for a typical script: ##Script Header # $Id: $ # Copyright (c) 2003 Cisco Systems, Inc. # # Name: # ip_static # # Purpose: # Execute a three router IP Static routed ping packet # switching test using a variety media, encapsulations, # and switching modes. # # Author: # Brian Jackson, Test Technologies # # References: # IP Static Switching Test Plan (EDCS-12345) # # Description: # This script implements a suite of tests exercising the
ATS Automated Test Software Style Guide 27

1 Comments

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

IP protocol running on a Cisco router to determine the success or failure of sending ping packets between two routers through the router under test. Static routes are applied on the source and destination routers to direct the packet stream. The router issuing the ping packets is refered to as the Generator (Gen). The router responding to the ping packets is the Reflector (Ref). The router switching packets between the Generator and Reflector is the Unit Under Test (UUT). This test is described as a "connectivity" or "switching" test because its purpose is to test the UUT's ability to switch packets between various media interfaces and encapsulations using a variety of switching modes on a variety of hardware platforms that are running a variety of IOS software releases. This script is configured for Autotest execution. Topology: +-----------+ +-----------------+ +-------------+ | Generator |---| Unit Under Test |---| Reflector | +-----------+ +-----------------+ +-------------+ A three-router topology connected via multiple media. Synopsis: switching/ip_static Id GenDescr GenUnit GenEncap GenMode \ RefDescr RefUnit RefEncap RefMode GenInt UutGenInt \ UutRefInt RefInt Gen Uut Ref Arguments: Id GenDescr GenUnit GenEncap Standard Autotest suite file line ID Brief description of the Generator side media (e.g., mci_e) Generator side UUT card number (1 or 2) Generator side media encapsulation: default, arpa, frame-relay, fr-ietf, hdh, hdlc, iso1, noencap, ppp, ppp-stac, smds, snap, x25 Unit Under Test Generator side switching mode (slow or fast) Brief description of the Reflector side media (e.g. mci_e) Reflector side UUT card number (1 or 2) Reflector side media encapsulation: default, arpa, frame-relay, fr-ietf, hdh, hdlc, iso1, noencap, ppp, ppp-stac, smds, snap, x25 Unit Under Test Reflector side switching mode (slow or fast) Generator interface used in the test Generator side Unit Under Test interface used in the test Reflector side Unit Under Test interface used in the test Refelctor interface used in the test Name of the Generator router Name of the Unit Under Test router Name of the Reflector Router

GenMode RefDescr RefUnit RefEncap

RefMode GenInt UutGenInt UutRefInt RefInt Gen Uut Ref

Sample Usage: switching/ipstatic ipstatic.1 mci_e 1 noencap slow \ mci_s 1 x25 slow $router1 $router2 $router3 Pass/Fail Criteria: Pass - If interfaces come up, configs apply, routes appear, and ping packet switches Fail - Otherwise
28

ATS Automated Test Software Style Guide

1 Comments

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Sample Output: IP STATIC route switching from mci_e # 1 \ (slow, noencap) to mci_s # 1 (slow, x25) No fr_ietf encaps. in $Version; skipped Test Steps: 1) Bring up the interfaces involved in the test and apply the encapsulations and switching modes. 2) Verify that all test interfaces are up. 3) Configure the static routes on the Gen and Ref routers. 4) Verify that the routes appear in the IP routing table. 5) Send 5 ping packets from the Gen to Ref router. 6) Verify that at least 80% of the ping packets are received. 7) Remove all configuration. 8) Verify that the configuration is gone, the interfaces are down, and the static routes are gone. Notes: 1) This script depends upon external encapsulation and switching mode configuration information and valid combinations as defined in the following switching matrix files: /autons/matrix/interns/ip/switching_matrix.91 /autons/matrix/interns/ip/switching_matrix.90 /autons/matrix/interns/ip/switching_matrix.83 2) The $router[1-n] arguments specified in the suite file entry will be replaced with the names of the [1-n] routers as defined in the testbed configuration section of the CONFIG file. 3) To some degree, this script has become superseded by the Core switching script located in the tests/functionality/core directory. Known Bugs: None Todo: 1) Ensure 100% packet switching instead of 80% by priming the ARP cache with an initial ping. See Also: tests/switching/* - Switching scripts for other protocols. End of Header

Note that the standard script header comment is included in the ATS scripting templates. When you copy a template, you'll have access to the comment fields that you should fill in.

5.6.2 Include the Standard Script Footer Comment


The standard script footer comment is a fixed comment as follows: # # # # # $Log: $ ;;; Local Variables: *** ;;; mode: tcl *** ;;; End: ***

The footer comment is composed of two elements. The first line ( '$Log: $' ) instructs CVS to append a copy of the commit comments to the end of the script. These commit comments can be used by an individual browsing a script to understand the modification history of the script. There is therefore no reason to include a manually maintained modification history in the script header comment (a common practice). Note that the log is maintained at the end of the script so
ATS Automated Test Software Style Guide 29

1 Comments

that scripters need not scroll through lengthy logs to reach the body of the script. The second element of the footer comment, the lines beginning with three semicolons, is instructions to the Emacs editor that tell the editor to enter tcl-mode when the script is opened. Include the footer comment in your script as is. The standard footer comment is also included in the ATS scripting templates.

5.7 Procedure Comments


The comments used to document a procedure depend upon the location and purpose of the procedure. If the procedure is defined in a script, the documentation requirements are fairly minimal. If, however, the procedure is placed in a library, the documentation requirements are more strict. If the library is intended for wide usethat is, by those outside your groupthen the documentation requirements become very stringent. Although the commenting of a locally used procedure library can be quite minimal, you may still want to fully comment the library as outlined in this section in anticipation of its wider use. The following sections outline the commenting standards for procedures.

5.7.1 Include Script Procedure Comments


Procedures to be used within a single script should be defined at the top of the script. A procedure should be preceded by short comments describing the function performed by the procedure. Typically, procedures located within a script are fairly short and do not call other procedures, so the description of these procedures can be very brief. For example: # Repeatedly poll the router route table until the desired route # appears, returning True if the route appears and False otherwise proc route_up {router prot addr} { for {set i 0} {$i < $MAX_ROUTE_RETRIES} {incr $i} { if {[string match $route [$router exec "show $prot route"]]} { return $TRUE } sleep $ROUTE_SLEEP } return $FALSE } The above example is prefaced by a very brief comment explaining what the route_up procedure does and the value returned.

5.7.2 Include the Standard Procedure Library Header Comment


If one or more procedures are to be used by more than one script, they should be stored in a procedure library that can be shared by those scripts. All procedure library files should begin with a standard procedure library header comment that includes the following fields of information: ##Library Header $Id: $ A visual flag that indicates to automated documentation generators that the following comment is a library header comment. The first line of the header comment should be included unmodified. This line will be replaced by CVS upon file checkout to indicate the version of the library being used.

ATS Automated Test Software Style Guide

30

1 Comments

# Copyright (c) 2003 Cisco Systems, Inc. Name: Purpose: Author: Usage:

The second line of the header comment should be included unmodified. The standard Cisco copyright should be included in all software developed at Cisco. The name of the library. This must match the filename containing the library. A single sentence explaining the functionality provided by the library. The person, identified by name and group, who developed the library and is responsible for its maintenance. Include the command (either source or package require) used to load the library (e.g., 'source $expect_library/sparse.exp' ). A detailed description of the functionality provided by the library. Identify any additional libraries required by this library and indicate whether they need to be sourced prior to sourcing this one. Even if autosourcing is handled through the package require command, it is still a good idea to list the required libraries in the header comment. State "None" if there are no external library requirements. (Optional) Provide a list of the variables within the library's name space that are used to maintain state, along with a brief description. Also document the fields defined within complex data structures. See the previous section on commenting important variables and complex data structures in a script for additional details and examples. (Optional) Any usage notes of interest that you wish to highlight for this script. (Optional) List any known bugs in this library along with any workarounds. (Optional) List any enhancements that you have planned for the library but haven't yet implemented. You or someone else may do further work on the library. (Optional) List any other related libraries that anyone running this library should also consider running. (Optional) The username or mailing list used to contact the individual or group providing support for this library. This is required for libraries submitted for inclusion in the cisco-share module. Provide a list of keywords associated with this library that can be used to search for it in the future. The keywords associated with a library should be a list of single words that summarizes its functionality. Provide a storage hierarchy for the library used in the automatic generation of the script development library command reference manual. Since library header comments can be lengthy, this comment provides a visual flag that can be searched for in order to skip over the header comment while in the editor.

Description: Requirements:

Variables:

Notes: Known Bugs: Todo:

See Also: Support Alias:

Keywords:

Category:

# End of Header

The following example shows a procedure library header comment for a typical procedure library:
ATS Automated Test Software Style Guide 31

1 Comments

##Library Header # $Id: $ # Copyright (c) 2003 Cisco Systems, Inc. # # Name: # dbg_util.exp # # Purpose: # A script development library containing general purpose # script debugging utilities. # # Author: # Brian Jackson, Test Technologies # # Usage: # source $expect/library/dgb_util.exp # # Description: # This library contains general purpose procedures that can # be used during the TCL software development process to # debug common scripting problems. The procedures contained # within this library include utilities to conditionally # display debugging messages, to test procedure and script # assertions, to simulate remote device interactions, to # inject faults into a script, and to implement a procedure # library self-test. # # Use this library during the development of a script or # procedure library to verify the software in a simulation # environment and to perform an internal unit test on the # software components. # # Requirements: # msg_lib.exp - A general purpose message display library. # # Variables: # dbg_enable - A Boolean flag used to enable debug message # display. # # Support Alias: # test-consulting # # Keywords: # script, software, development, debug, test, simulate # # Category: # internal/development/test The standard procedure library header comment is included in the standard ATS procedure library template.

5.7.3 Include the Standard Procedure Library Footer Comment


The procedure library footer comment is the same as that used in a script and should be included without modification. The following is the fixed format of this comment: # # # # # $Log: $ ;;; Local Variables: *** ;;; mode: tcl *** ;;; End: ***

5.7.4 Include Standard Procedure Library Procedure Comments


ATS Automated Test Software Style Guide 32

1 Comments

Each procedure in a procedure library should be preceded by a standard procedure library procedure comment. This comment explains the use of the procedure, lists its return values, and provides examples that can be used to incorporate the procedure into a script. The fields of information that should be included in a procedure library procedure comment are as follows: ##Procedure Header A visual flag that indicates to automated documentation generators that the following comment is a procedure comment. Note that you should only place this visual flag in front of user-callable procedures for which you want to produce documentation. Exclude this line from procedures that are used internally within the library. The name of the procedure (including a name space prefix if used). A single sentence summarizing the functionality provided by the procedure. An overview of the usage syntax for the procedure. Identify variable arguments by enclosing a symbolic name for the argument in angle brackets. Identify optional arguments by enclosing them within question marks. List alternate argument syntaxes on separate lines, repeating the procedure name followed by the argument list alternative. Use an ellipsis (...) to indicate that the preceding argument can be repeated any number of times. List the arguments to the procedure, one per line, followed by an explanation of each argument's purpose. If applicable, list valid argument values or number ranges (e.g., [64 - 1500]) in the comment. If arguments are valid only in conjunction with a preceding argument, indent the subordinate arguments. List the values returned by the procedure and indicate the purpose of each possible value. Provide a detailed description of the procedure, explaining fully the function that it performs and discussing potential applications. Provide example uses of the procedure. Include comments in the examples if they are not self-explanatory. (Optional) Provide a sample of the input to the procedure provided by its argument values. This is particularly important in the case of parsing procedures, where an understanding of the procedure is aided by a sample of the input being parsed. (Optional) For procedures that log output to files, provide a sample of the format of the output produced. (Optional) Add any special notes related to the use of the procedure, numbered for ease of reference. (Optional) List any procedures or commands that are closely associated with the use of this procedure. For example, a 'read' procedure should reference corresponding 'open', 'write', and 'close' procedures.

Name: Purpose: Synopsis:

Arguments:

Return Values: Description: Examples: Sample Input:

Sample Output: Notes: See Also:

The following example shows a procedure library procedure comment for a typical library procedure: ##Procedure Header # Name: # ats::debug # # Purpose: # Conditionally output debug messages # # Synopsis: # ats::debug enable
ATS Automated Test Software Style Guide 33

1 Comments

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

ats::debug disable ats::debug msg <format> ?<string> ...? Arguments: enable disable msg <format> <string> Enable display of debug messages Disable display of debug messages Conditionally display the following message Message to be displayed or a 'printf' style message format Optional elements to be formatted into a message format Returns the current debug status when called

Return Values: "enable" | "disable"

Description: The "debug" command can be used to conditionally display debug messages embedded in script or procedure libraries. When debugging is enabled, messages are displayed to standard output if running in an interactive interpreter or the log file if running under Autotest or EASY control. When debugging is disabled, debug messages are suppressed. Use the "debug enable" command to enable display of debug messages. Use the "debug disable" command to disable message display. To display a message, use the "debug msg" command followed by the message to be displayed. Note that the message can be a 'printf' style format string followed by one or more string elements to be formatted into the message. Use this form of the command to include the current value of variables in the message being displayed. Use of this library typically involves loading the library into an interactive interpreter, issuing the 'debug enable' command, then sourcing the script or library to be debugged. Optionally, you may place the 'debug enable' command in the head of a script and execute that script in the Autotest or EASY environment. Examples: ats::debug enable ats::debug msg "This is a sample message" set myvar 9 ats::debug msg "The value of my is %s" $myvar ats::debug disable ats::debug msg "You'll never see this message" Sample Output: DEBUG: This is a sample message DEBUG: The value of myvar is 9 Notes: 1) Debug message will not be displayed until the "debug enable" command has been issued. 2) Calls to "debug" cause a minor performance impact to the code in which they're used. In the case of performance critical software or software that is executed repeatedly, you should limit your use of this procedure or possibly remove calls to "debug" from such software before productional release.

The standard procedure library procedure comment is included in the ATS procedure library template.

5.7.5 Include Procedure Library Internal Procedure Comments


ATS Automated Test Software Style Guide 34

1 Comments

Documentation for procedures used internally within a procedure library (procedures for procedures) can sometimes be useful to people who are trying to understand the use of a library. Include the following simple internal procedure header comment for all such procedures, not only to document these procedures for individuals browsing the code but also to provide for inclusion in generated documentation: ##Internal Procedure Header # Return the first element of a list while setting the # list to contain the remaining elements proc shift {listName} { upvar $listName list set rc [lindex $list 0] set list [lrange $list 1 end] return $rc } In the example, internal procedure header comments contain a brief description of the operation performed by the procedure preceded by the '##Internal Procedure Header' visual flag.

5.8 ITcl Class Library Comments


ITcl classes and methods are defined in a file known as a class library. Although this document provides no information specific to ITcl coding style, this section outlines the standard header comments that should be included in an ITcl class library. Note: This standard was developed after the development of the ITcl based Metal product. Those extending and documenting the Metal libraries should feel free to continue to conform to the Metal header commenting standard while adopting the remainder of the standards presented in this document.

5.8.1 Include the Standard Class Library Header Comment


All class libraries should begin with a standard class library header comment that includes the following fields of information: ##Class Header $Id: $ A visual flag that indicates to automated documentation generators that the following comment is a class library header comment. The first line of the header comment should be included unmodified. This line will be replaced by CVS upon script checkout to indicate the version of the library being used. The second line of the header comment should be included unmodified. The standard Cisco copyright should be included in all software developed at Cisco. The name of the class library. This must match the filename containing the library. A single sentence explaining the functionality provided by the class library. The person, identified by name and group, who developed the class library and is responsible for its maintenance. The base classes from which the class inherits. Include the command (either source or package require) used to load the class library (e.g., 'source $expect_library/sparse.itcl' ).

# Copyright (c) 2003 Cisco Systems, Inc. Name: Purpose: Author: Inherits: Usage:

ATS Automated Test Software Style Guide

35

1 Comments

Instantiation Example: Description: Requirements:

Examples of how to instantiate an object of this class. Include examples of available configuration options. A detailed description of the functionality provided by the class library. Identify any additional class libraries required by this library and indicate whether they need to be sourced prior to sourcing this one. Even if autosourcing is handled through the package require command, it is still a good idea to list the required libraries in the header comment. State "None" if there are no external library requirements. (Optional) Provide a list of the public variables within the class library's name space that are used to maintain state, along with a brief description. Also document the fields defined within complex data structures. See the previous section on commenting important variables and complex data structures in a script for additional details and examples. (Optional) Any usage notes of interest that you wish to highlight for this class library. (Optional) List any known bugs in this class library along with any workarounds. (Optional) List any enhancements that you have planned for the class library but haven't yet implemented. You or someone else may do further work on the library. (Optional) List any other related libraries to which anyone using this library may want to refer. (Optional) The username or mailing list used to contact the individual or group providing support for this class library. This is required for libraries submitted for inclusion in the cisco-share module. Provide a list of keywords associated with this class library that can be used to search for it in the future. The keywords associated with a library should be a list of single words that summarizes its functionality. Provide a storage hierarchy for the class library used in the automatic generation of the script development library command reference manual. Since class library header comments can be lengthy, this comment provides a visual flag that can be searched for in order to skip over the header comment while in the editor.

Public Variables:

Notes: Known Bugs: Todo:

See Also: Support Alias:

Keywords:

Category:

# End of Header

5.8.2 Include Standard Class Library Method Comments


All methods defined in a class library should be preceded with a detailed comment defining the purpose and use of the method. The following fields of information should be included: ##Method Header Name: Class Name: A visual flag that indicates to automated documentation generators that the following comment is a class library header comment. The name of class followed by two colons (::) and the name of the method. The name of the class to which this method belongs.

ATS Automated Test Software Style Guide

36

1 Comments

Purpose: Synopsis: Arguments:

A single sentence explaining the functionality provided by the method. An overview of the usage syntax for the method. List the arguments to the method, one per line, followed by an explanation of each argument's purpose. If applicable, list valid argument values or number ranges (e.g., [64 - 1500]) in the comment. If arguments are valid only in conjunction with a preceding argument, indent the subordinate arguments. List the values returned by the method and indicate the purpose of each possible value. Provide a detailed description of the method, explaining fully the function that it performs and discussing potential applications. Provide example uses of the method. Include comments in the examples if they are not self-explanatory. (Optional) Provide a sample of the input to the method provided by its argument values. (Optional) For methods that log output to files, provide a sample of the format of the output produced. (Optional) Add any special notes related to the use of the method, numbered for ease of reference. (Optional) List any procedures, methods, or commands that are closely associated with the use of this method. For example, a 'read' procedure should reference corresponding 'open', 'write', and 'close' procedures.

Return Values: Description: Examples: Sample Input: Sample Output: Notes: See Also:

5.9 Comment Nonintuitive Script Logic


Particular emphasis should be placed on commenting nonintuitive script logic. This documentation includes a detailed explanation of the meaning of input being evaluated or actions being taken, and an account of the implementation of complex algorithms. In these cases, you should provide more than a single line of comment to explain the operations performed by the software. For example: # Set the number of days in the current year # Leap year adds 1 day to February (the 29th) in years that are # divisible by 4 and either divisible by 400 or not by 100 (i.e. # throw out the years divisible by 100 except those that are also # divisible by 400) in order to synchronize the calendar with the # seasons if {!($year % 4) && (($year % 400) || !($year % 100))} { set days 366; # Leap year } else { set days 365 }

5.10 Use Comments to Document Output Being Parsed


Most scripts include invocations of the TCL regexp command, or a utility procedure that ultimately calls regexp, in order to parse output from a device. When the output being parsed is complex or lengthy, include a sample of the output being parsed in a comment preceding the parsing logic. By doing so, you'll make it easier for individuals reading the code to understand
ATS Automated Test Software Style Guide 37

1 Comments

the goal of potentially complex regular expression patterns. For example: # Parse the packet counters from the IOS "show interface" command # output to extract input and output packet, byte, and error # counters # Sample "show interface" output: # # Ethernet 0 is up, line protocol is up # Hardware is MCI Ethernet, address is 0000.0c00.750c (bia 0000 # Internet address is 131.108.28.8, subnet mask is 255.255.255.0 # MTU 1500 bytes, BW 10000 Kbit, DLY 100000 usec, rely 255/255, # Encapsulation ARPA, loopback not set, keepalive set (10 sec) # ARP type: ARPA, ARP Timeout 4:00:00 # Last input 0:00:00, output 0:00:00, output hang never # Last clearing of "show interface" counters 0:00:00 # Output queue 0/40, 0 drops; input queue 0/75, 0 drops # Five minute input rate 0 bits/sec, 0 packets/sec # Five minute output rate 2000 bits/sec, 4 packets/sec # 1127576 packets input, 447251251 bytes, 0 no buffer # Received 354125 broadcasts, 0 runts, 0 giants, 57186* thr # 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 ab # 5332142 packets output, 496316039 bytes, 0 underruns # 0 output errors, 432 collisions, 0 interface resets, 0 re # set output [$router exec "show interface $int1"] foreach s [split $output "\n"] { regexp {([0-9]+) packets input, ([0-9]+) bytes,} $s - ipaks ibytes regexp {([0-9]+) input errors,} $s - ierrors regexp {([0-9]+) packets output, ([0-9]+) bytes,} $s - opaks obytes regexp {([0-9]+) output errors,} $s - ierrors } if {![info exists ipaks] || ![info exists ierrors] || ![info exists opaks] || ![info exists oerrors]} { log_diagnostic_msg \ "Unable to parse $router 'show interface $int1' output\n$output" update_test_status $FAIL }

5.11 Comment Router Configurations


Cisco router test scripts usually include a great deal of router configuration data that needs to be applied to the routers in a testbed to set up the test environment. These configuration statements are typically standard router commands (e.g., "no shutdown") that are simply part of the administrative task of configuring a router. But some configurations being applied are complex or are integral to the test being performed. In these cases, you should use the router configuration comment character (!) to include comments and white space in your router configuration to improve its readability and understandability. For example: $uut_router config " ! Apply the requested encapsulation and switching mode to the ! generator side interface interface $uut_gen_int [get_modes off ip_static $Version $gen_mode] [get_encaps off ip_static $Version $gen_encap "UutGen"] no ip address shutdown ! ! Apply the requested encapsulation and switching mode to the ! reflector side interface interface $uut_ref_int
ATS Automated Test Software Style Guide 38

1 Comments

[get_encaps off ip_static $Version $RefEncap "UutRef"] no ip address shutdown ! no ip routing "

5.12 Generating Documentation from Comments


The Test Technologies organization is currently working on a set of tools that can be used to generate procedure library and script documentation in HTML, Unix man page, and text format from comments contained in source code. The details of these tools are not available as of the writing of this document, but if you follow the header-commenting conventions outlined in this document, you can be assured that documentation for your software can and will be included in the generated output.

5.13 Include Cisco copyright notice in all files


All Cisco code should carry the Cisco copyright notice. This notice is normally included in the standard header comments for the file, although currently there is no standard header comment format for command-line tools. These should, however, still carry the copyright notice: # Copyright (c) 2006 Cisco Systems, Inc.

5.14 Include RCS $Id$ tag in all files


As with the Cisco copyright notice, the RCS $Id$ tag is normally present in the standard header comment for the file. This tag is substituted by CVS (through RCS) with information about the file that is useful for distinguishing it from other versions of the same file: including numeric version, date and user name associated with the commit. In lieu of other versioning information, this is important for keeping track of updates and patches to deployed files.

ATS Automated Test Software Style Guide

39

1 Naming

ATS Automated Test Software Style Guide

40

1 Naming

6 Naming
Every element incorporates one piece of documentation that will follow it everywherethat is, its name. Just as comments can aid in understanding software, applying meaningful names to variables and procedures can enhance software by quickly identifying the purpose and use of an element. This section discusses standards for naming variables and procedures used in ATS test scripts and procedure libraries.

6.1 Assign Meaningful Names


The first and most important rule regarding the naming of variables and procedures is to apply a meaningful name to each of these elements. For example, instead of giving a counter variable a name such as i, name the variable something like input_count. The following are examples of variables and procedures that have meaningful names: pak_count_out pak_count_in A variable used to count outgoing packets. A similar variable used to count incoming packets. Notice that the "in" versus "out" distinction is placed at the end of the name so that both variables can be clearly identified as packet counters and the slight difference is subordinated to the end of the name. A procedure used to obtain the packet counter values.

pak_count_get()

Variables should always have meaningful names except in cases where short-lived variables are being used within a very limited scope of your software. The most frequent example of this exception is the naming of loop variables. For example: set string "This is a string" foreach s $string { puts $s } In this example, the variable s need not be given a significant name because its purpose and scope of use are limited and obvious. Here the use of a very brief name is preferable because it saves typing time and space.

6.2 Use Standard Characters in Names


TCL allows you to use a wide range of characters in variable and procedure names. These characters include uppercase and lowercase alphabetic characters, numerals, and virtually any punctuation character that won't be misinterpreted as a language element. Noentheless, you should restrict the characters used in naming elements to lowercase alphabetics and underscores (_). Use of punctuation characters other than underscore in a name, can create visual confusion in your program by making names look like regular expression patterns or other software elements. A name should always begin with a lowercase alphabetic character unless you are trying to hide the name, in which case it should begin with an underscore (see ). Uppercase alphabetic characters should be used only in naming constants (see ) and camelback naming (see below). Underscore or upper case characters should be used to delimit multiple words used to compose a variable name. Variable names should always end with a lowercase alphabetic character. The following are some naming examples: router router_type
ATS Automated Test Software Style Guide

A variable used to store a router name. A variable used to store the router type.
41

1 Naming

trim_flag trimFlag

A Boolean variable used to enable trimming. Embedded underscore naming. The same definition using camelback naming.

_csccon_connect_timeout A hidden global variable used by the CSCCON router control library to store a timeout value for router connections. TRUE var9__a__mEss? A constant variable storing the value of true (1). A total mess.

6.3 Abbreviate Names


In order to avoid lengthy command lines, reduce overall program size, and save your fingers from cramping up, you should abbreviate the words used to compose variable and procedure names. Words are commonly abbreviated by removing vowels (e.g., 'count' becomes 'cnt' and 'flag' becomes 'flg'), unless the vowels are useful in distinguishing the abbreviated word from other words. Abbreviations can also be produced by using the significant portion of the word (e.g., 'number' becomes 'num') or the phonetic value (e.g., 'packet' becomes 'pak'). Combine these abbreviations with underscore separation and you've created a terse, but meaningful, name. The following are examples of well-formed abbreviated names: pak_cnt_in trim_flg usr_num Input packet counter. A Boolean variable used to enable trimming. A user's relative number.

Note: The first two examples above should be used in preference to the unabbreviated examples shown in previous sections.

6.4 Techniques for Constructing Names


This document stresses the value of following a single standard naming convention. That standard should be one of two accepted conventions. This section discusses the relative merits of those conventions, leaving it to you to select the one the better suits your style. Whichever method you adopt, use it consistently across all the software that you develop.

6.4.1 Underscore-Delimited Naming


Underscore-delimited naming uses underscores to separate the individual words or abbreviations that make up a name. The convention is visually pleasing and helps to highlight name components, but the inclusion of underscores does add to the name length. The primary benefit of this convention is that it is already extensively used throughout the ATS, so if you adopt it you're more likely to achieve visual consistency between your software and the software surrounding it.

6.4.2 Camelback Naming


An alternate naming convention, used extensively in object oriented programming, is camelback naming. This method involves using uppercase letters to separate the individual words and abbreviations that compose a name. Instead of using an underscore to separate two name elements, simply change the case of the first letter of the second element to uppercase and join them. For example:
ATS Automated Test Software Style Guide 42

1 Naming

pakCntIn trimFlg usrNum router pakCountGet()

Input packet counter. A Boolean variable used to enable trimming. A user's relative number. The name of a router. A procedure used to obtain the packet counter values.

An obvious benefit to this naming convention is that it can significantly reduce the length of a name while retaining the visual separation of its components. Additionally, those who are experienced object oriented programmers will find this naming convention more familiar and visually more appealing. The downside to this naming convention is that it is not consistent with the naming convention in primary use throughout the ATS; namely, underscore-delimited naming. Note: Despite a personal preference for camelback naming, I use underscore-delimited naming when writing ATS software for the sake of visual consistency with the entire system of software. This naming convention may be more useful in software development performed outside the ATS.

6.5 Name Prefixes


In order to differentiate a variable or procedure name from names used by software other than your own, you may have to apply a word prefix to the name to associate it with your software. This section discusses when name prefixing should be used and how to do it.

6.5.1 Name Space Collision


When naming variables for local use within your software, you can be confident that the names you assign are unique. However, a common practice in defining procedures is to store persistent data in global variables. All global variables are stored in a single name space. Variable name collision can occur with other software using the global name space. Furthermore, all procedures are defined in the global name space, even if they're to be used only locally within your script. Let's say you're using the CSCCON router control library. If you define a procedure within your script named 'console', you will have just destroyed the CSCCON console procedure. The general problem of inadvertently replacing variables and procedures in the global name space is known as name space collision. This section addresses methods for avoiding this phenomenon.

6.5.2 Use Simple Name Prefixing in Test Scripts


The simplest way to avoid name space collision is to apply a name prefix to all global variables and procedures that are defined within your software. A name prefix is simply a short string prepended to a name using an underscore. The prefix, though short, should also attempt to uniquely identify the owner of the element. The following are examples of some simple name prefixes. ipmtst_ atutl_ Used by the IP Multicast test script. Used for AppleTalk utility procedures.

Using of simple name prefixing is acceptable, but a preferred method for making procedure names unique is presented in the next section.

ATS Automated Test Software Style Guide

43

1 Naming

6.5.3 Use Name Spaces in Procedure Libraries


Name spaces provide a simple mechanism for avoiding name space collision and the cumbersome and needlessly long names that can be produced by simple name prefixing. When developing a procedure library for reuse, you should always use name spaces to define your procedures and global data in a name space other than the global name space. To define a name space, use the namespace eval command as seen in the following simple example: namespace eval dbg { variable debug_enable; output } # Flag used to enable/disable debug

proc dbg::debug {cmd {msg {}}} { ... } In this example, the 'dbg' name space is created. Within that name space, the variable command is used to define a variable that is global to that name space. A procedure called debug is then defined within that name space by prefacing the name of the procedure with the name of the name space, bracketed in double colons. This procedure can be called by other procedures within the name space using the command debug or by users outside the name space by specifying its fully qualified name dbg::debug. For more information on name spaces, refer to ATS Procedure Library Development Guide.

6.5.4 Begin Names with Underscores to Hide Them


One danger of defining persistent variables in the global name space is the potential for users to redefine the contents of those variables. One way of hiding your global variables from tampering is to place a visual flag in the the variable name. A common standard in global variable naming is to begin the name of global variables with an underscore (_). This provides a visual flag to the user to indicate that the contents of the variable should neither be read nor modified.

6.6 Name Constant Variables Using Uppercase Characters


An exception to the rule regarding the use of uppercase characters in variable names involves constant variables. Constant variables are variables that store a constant value; in other words, they are variables that should not be modified by the user. Constant variables should be used to store looping values and addresses rather than hard-coding such constant data in your script. Constant variable names should be composed entirely of uppercase characters and, optionally, underscores. The use of uppercase characters signals to the user that the contents of the variable are constant and the variable therefore should not be modified. The following are examples of constant variable names: FALSE MAX_RETRIES IP_ADDR Stores the value 0 (false). Stores the value 10 (a maximum loop counter). Stores the value 10.227.20.1.

6.7 Name Files Using Extensions


ATS Automated Test Software Style Guide 44

1 Naming

All of the naming conventions outlined in this section for variables and procedures also apply to the naming of files that are added to the ATS system, including procedure libraries, suites, and job and queue files. An additional convention that applies to the naming of files involves the use of filename suffixes. When naming a file, you should append a suffix that identifies the use and contents of the file. This convention does not apply to the naming of scripts, which by precedence do not possess filename suffixes. The following are some of the standard filename suffixes used in the ATS system: .exp .suite .queue .job .dat .config | .conf .txt | .doc Use this filename suffix on procedure libraries. Use this filename suffix on Autotest suite files. Use this filename suffix on Autotest queue files. Use this filename suffix on EASY job files. Use this filename suffix on data files. Use this filename suffix on software configuration files. Use this filename suffix on documentation files.

Note: It is better to distinguish similarly named files by significant differences in name rather than by simply appending a number to identical names. Whatever is the cause for separating the file contents can be used to differentiate the filenames.

ATS Automated Test Software Style Guide

45

1 Constants

ATS Automated Test Software Style Guide

46

1 Constants

7 Constants 7.1 Define and Use Constant Variables


Scripts typically include a large amount of constant data. Constant data includes maximum loop counters, comparison values, device configuration strings, and procedure call data. When you are using a constant data value that is likely to be changed, you should define a constant variable to store and refer to the constant data value rather than hard-coding the value in your script. The reason for using constant variables is twofold: economy and meaningfulness. First, a change to a single constant variable definition affects all of its use cases throughout your script. Second, a well-named constant variable can provide more information about the meaning of the value than does the value itself. For a list of potential constant variable names, refer to the section . The following example shows the definition and use of a constant variable: # Define constants set MAX_RETRIES 10 ... # Attempt to create a test device connection for {set i 0} {$i < $MAX_RETRIES} {incr i} { ... } Note: There's a fine line between proper use of constants and overuse of constants. Every constant value in your script need not be defined in a constant variable. Typically the signs that point to the need for a constant variable definition are reuse of the value, the need to document the purpose of the value, and the need to change the value in order to fix bugs in the script.

ATS Automated Test Software Style Guide

47

1 Software Structure

ATS Automated Test Software Style Guide

48

1 Software Structure

8 Software Structure
Each line of a piece of software should be formatted to achieve visual consistency. In addition, the overall structure of the software and the order in which sections appear should be made consistent to enhance its readability and maintainability. This section discusses the standard structure that should be used to implement test scripts and reusable procedure libraries.

8.1 Script Structure


To ensure visual consistency with other test scripts and to make portions of a script easy to find, each test script should be developed in sections that adhere to a prescribed order, as follows: Interpreter Invocation The first line of a test script should invoke the Expect interpreter. Although test scripts aren't run from the command line and therefore don't need to invoke the interpreter, the inclusion of this line will cause the Unix file type to identify the script as an Expect executable shell script. Include the standard ATS script header comment as explained in the section . Source any procedure libraries (e.g., csccon.exp) required by the test script to perform the test. Define and set constant variables used in the script. Parse the script argument string, storing its contents in individual variables. Verify any argument dependencies of the script. Set any passwords required to connect to equipment in the testbed. Define any procedures that will be used locally within the test script. Configure the testbed equipment and the environment to prepare for test execution and analysis. Actually perform the test by injecting the stimulus into the testbed and verifying the response. Report the test result in this section. Remove all configuration that was applied to the testbed in order to perform the test. Scripts should leave the testbed in the same state that it was in before the script began execution. Include the ATS standard test script footer comment, as explained in the section .

Header Comment Library Sourcing Constant Definition Argument Parsing Argument Validation Password Setting Local Procedure Definition Test Configuration Test Execution and Analysis Test Unconfiguration Footer Comment

For additional information on the development of test scripts, refer to ATS Test Script Development Guide.

8.2 Procedure Library Structure


To ensure visual consistency with other procedure libraries and to make portions of a library
ATS Automated Test Software Style Guide 49

1 Software Structure

easy to find, each library should be developed in sections that adhere to a prescribed order, as follows: Interpreter Invocation Header Comment Package Definition A procedure library should begin with a line that identifies the file as an Expect executable shell script. Include the standard ATS procedure library header comment as explained in . Use the package provide command to define the library as a package. Not all libraries are used as packages, but the inclusion of this line will ensure that the library is ready to be used as one if the need arises. Include package require statements for any other procedure libraries upon which this library depends. As section explains, you should use the namespace command to define a name space to contain your library procedures. Within the name space definition, use variable to define global variables to be used locally within the procedure library. The initialization logic can also make calls to the namespace export command to export procedure and variables for namespace import into the global name space. Define the procedures that are accessible to the user of the library.

Require Libraries Define and Initialize the Namespace

Define User Callable Procedures Define Internal, Support Procedures Footer Comment

Define the procedures that are accessible only to the procedures within the library.

Include the ATS standard procedure library footer comment, as explained in .

For additional information on the development of procedure library, refer to ATS Procedure Library Development Guide.

ATS Automated Test Software Style Guide

50

1 Emacs TCL Mode and Fontification

9 Emacs TCL Mode and Fontification


If you're using the Emacs editor to develop TCL software (a practice that I highly recommend), you can use the context sensitive features of the editor to help implement this coding standard. For example, when you enable tcl-mode during the edit session, the tab character will automatically indent nested code blocks. The cursor will jump back and forth between opening and closing braces for strings and blocks. You can enable font-lock to highlight various sections of your program using different colors: comments will be displayed in red, commands in turquoise, and strings in orange. This editing mode can help you to quickly identify unterminated strings and other program elements. To enable these features, add the following command blocks to your "~/.emacs" configuration file: ;;; Automatically enter an editing mode based on the file suffix (setq auto-mode-alist (cons '("\\.tcl$" . tcl-mode) auto-mode-alist)) (setq auto-mode-alist (cons '("\\.exp$" . tcl-mode) auto-mode-alist)) ... ;;; Enable font locking for various modes (cond (window-system (add-hook 'tcl-mode-hook 'turn-on-font-lock) (setq font-lock-maximum-decoration t) (global-font-lock-mode t) ))

ATS Automated Test Software Style Guide

51

1 Where to Go from Here

ATS Automated Test Software Style Guide

52

1 Where to Go from Here

10 Where to Go from Here


If you've just finished reading through the Test Technologies style standards for development of ATS software, you should plan to review this document after completion of your next ATS software development project in order to verify that the software complies with this standard. But then what? Before reading this guide, you probably browsed the TCL Scripting Language Primer. If you haven't already done so, take a look at that document to obtain a solid understanding of TCL so that you can fully comprehend and appreciate the conventions and examples presented in this document. If you will be developing automated test scripts for use with the ATS, you should now review the ATS Test Script Development Guide for detailed instructions on use of the ATS script development libraries. If you will be developing reusable procedure libraries for use with the ATS, you should review the ATS Procedure Library Development Guide for information on how to make software findable and reusable. As you continue to develop ATS scripts, refer back to this guide to increase your familiarity with the style conventions.

ATS Automated Test Software Style Guide

53

Appendix A: Style Summary

ATS Automated Test Software Style Guide

54

Appendix A: Style Summary

Appendix A: Style Summary


2 Quoting
2.3 Default to the Use of Double Quotes to Quote Strings Unless you're suppressing substitution, use double quotes in preference to curly braces when quoting strings to differentiate string data from other quoted data (e.g., code blocks and expressions). 2.4 Quote Single-Element Strings Using Double Quotes Quote single-element strings using double quotes, except strings composed of a single variable or subcommand strings passed to a procedure. 2.5.1 Quote Expressions Using Curly Braces to Maintain Consistency Always quote expressions using curly braces, even if not required by TCL, to promote coding style consistency. 2.5.2 Quote Expressions Using Curly Braces to Improve Performance Quote expressions using curly braces to improve performance by preventing multiple substitution. 2.5.3 Quote Looping Expressions Using Curly Braces
set flag 1 set count 1 if {$debug_flag} { if {$debug_option == "verbose"} { puts "Verbose debugging is requested" } else { puts "Non-verbose debugging is requested" } } pak_process parse $pak "output" set variable "This is the contents of the variable"

if {[string match "-verbose" $args]} { puts "The verbose argument was received" }

while {$flag} { incr count if {$count > 100} { set flag 0 Quote looping expressions } ATS Automated Test Software Style Guide

55

Appendix A: Style Summary }

using curly braces to prevent infinite loops. 2.6 Quote Code Blocks Using Curly Braces Always quote code blocks using curly braces instead of double quotes to defer evaluation and visually delineate your code blocks, even if the code block body of a conditional or looping command doesn't require quoting. 2.7 Quote Procedure Bodies and Script Sections Using Curly Braces Always quote procedure bodies and script sections using curly braces instead of double quotes to defer evaluation and visually delineate these elements. 2.8 Quote Non-Space-Delimited Variable Names Using Curly Braces Always place curly braces around variable names that are not delimited by space or punctuation from surrounding characters in a string. 2.9 Quote Procedure Argument Lists Using Curly Braces Always place curly braces around procedure argument lists even if the procedure accepts only one argument.

if {[string match "8*" [info tclversion]]} { puts "This is TCL version 8" }

proc display {msg} { puts $msg } test_config { $router config " interface Ethernet1 no shutdown " }

set var1 "my" set var2 "data" puts "${var1}data"; # Outputs "mydata" puts "${var1}${var2}"; # Outputs "mydata" puts "${var1}.${var2}"; # Outputs "my.data"

proc msg {string} { puts $string }

3 Commands and Code Blocks


3.1.1 Code One Command per Line
set FAIL 0; # Use this constant to return failure from a script set PASS 1; # Use this constant to return success from a script for {set s 1; set p 0} {$s < $MAX_STRING} {incr s; incr p} { ATS Automated Test Software Style Guide 56

Appendix A: Style Summary if {$s == 1} { ... }; # End of if {$s == 1} }; # End of for loop

Always write a single command per line, reserving semicolons for placing comments after variable definitions and lines of interest and for separating commands in for expressions. 3.1.2.1 Split Command Lines That Exceed 80 Characters Use the backslash character to escape newlines in order to continue a lengthy command (a line that exceeds 80 characters) on one or more new lines. 3.1.2.2 Use join to Split Strings That Exceed 80 Characters Use the TCL join and list commands to rejoin lengthy strings that have been split onto multiple lines. 3.1.2.3 Split Commands at Logical Breaks Instead of splitting lengthy commands onto multiple lines arbitrarily, split the commands at natural separation points in the command syntax. 3.2.2 Align Opening and Closing Code Block Curly Brace Open code blocks using a curly brace at the end of the line containing the command to which they are passed, and close them with a curly brace aligned with the start of the command line on which they're opened.

if {[string index [lindex $arg 0] 0] == "-" && \ [lindex $arg 1] != "false"} { ... }

log_message [join [list "Interface $interface packet counters," \ "Input counter: $input, Output counter: $output"]]

for {set iptr 0; set optr 0} {iptr < $END_OF STRING} \ {incr iptr} { ... }

if {[string match "8*" [info tclversion]]} { if {[string match "*2" [info tclversion]]} { puts "This is TCL version 8.2" } }

if {$access_list_flag} { access_list_apply $interface_list foreach interface $interface_list { set result [access_list_evaluate $interface] if {$result} { puts "Access list looks good" ATS Automated Test Software Style Guide

3.2.4 Avoid Excessively Long or Deeply Nested Code Blocks

57

Appendix A: Style Summary } else { puts "Access list looks bad" } } }

Avoid the use of excessively long or deeply nested code blocks by breaking your code up into multiple procedures.

3.2.5 Treat Script Sections package require Csccon package require Test and Device Configurations set router "my_router" As Code Blocks Indent the contents of script sections 4 spaces just as you would a code block.
test_config { $router config { interface ethernet1 no shutdown } } test_analyze { set result [$router exec "show interface ethernet1"] if {[regexp "line protocol up" $result]} { puts "Everything looks good on ethernet1" } }

3.2.6 Treat Procedure Bodies As Code Blocks Indent the body of procedure definitions four spaces just as you would a code block. 3.3.1 Use Spaces to Delimit Operators and Values in Expressions Use spaces to delimit operators, variables, and numbers to enhance the readability of an expression. 3.3.2 Exclude the Equality Operator from Boolean Expressions Do not include the equality operator (==) in Boolean expressions. 3.3.3 Explicitly Define Expression Operation Precedence Use parentheses () to explicitly define the order in which arithmetic and Boolean operations will be performed in a complex expressions. 3.4.3 Do Not Include then

proc display {msg} { puts $msg }

if {($pak_siz >= 64 && $pak_siz <= 1500) || !$pak_err_flg} { puts "Packet contains an error" }

set flag 1 if {$flag} { puts "Flag is true" }

if {($var > 10) && ($var < 100)} { puts "Value is within range" } set var [expr "(($foo * 100) - ($bar / 7)) + 3"]

if {1} { 58

ATS Automated Test Software Style Guide

Appendix A: Style Summary

in if Statements Exclude the then from if statements. 3.4.5 Use "--" string to mark end of options Include the "--" argument after options to prevent bugs.

puts "False" }

regexp -all -nocase -- $pattern -> result

3.4.6 Handling uplevel and uplevel 1 $cmd $args upvar statements Include levels in uplevel and upvar calls to prevent bugs.

4 White Space and Indentation


4.1.1 Use One Line of White Space to Visually Segment Software Logic Visually separate your software into groups of program logic using single blank lines to enhance software readability and maintainability.
set output [$router exec "show interface $int1"] foreach s [split $output "\n"] { regexp {([0-9]+) packets input} $output - $ipaks } if {![info exists ipaks]} { log_diagnostic_msg "Unable to parse router show interface output:\n$output" update_test_status $FAIL return } if {$output > $threshold} { log_diagnostic_msg "Input packet threshold ($theshold) exceed" update_test_status $PASS } else { log_diagnostic_msg "Input packet threshold ($theshold) not exceed" update_test_status $FAIL } foreach s {"one" "two" "three"} { set len [string length $s] if {$s == "one"} { puts "The first string is length of $len" } else { puts "This isn't the first string" puts "Its length is $len" } }

4.2 Indent Nested Code Blocks Four Spaces Indent nested code blocks four spaces per code block to visually identify the nesting level of each line of code in the block.

5 Comments
5.1 Format Comments Like Bullet Items Begin comments with a pound sign, followed by one space, then the comment with the first letter
# Update the program counter . . . # Extract the input packet counter from the router show # interface output . . . 59

ATS Automated Test Software Style Guide

Appendix A: Style Summary

capitalized, and omit the terminating period.

# Recalibrate the traffic rate # Traffic rate recalibration must be performed periodically # to ensure valid test results . . . # Display a sorted list of the TCL commands # Insert blank lines between commands beginning with # different characters # Iterate across a sorted list of all TCL commands set command_list [lsort [info commands]] foreach command {$command_list} { # Print a blank line between commands starting with # different characters set first_letter [string index $command 0] if {[info exists prev_letter]} { if {![string match $first_letter $prev_letter]} { puts "" set prev_letter $first_letter } } # Display the current command puts $command }

5.2 Comment All Logical Blocks of Code Comment all blocks of code that have been separated using white space.

5.3 Indent Comments to Align Them with the Code That Follows Align comments to the same nest level as the code they describe.

# Iterate across a sorted list of all TCL commands set command_list [lsort [info commands]] foreach command {$command_list} { # Print a blank line between commands starting with # different characters set first_letter [string index $command 0] if {[info exists prev_letter]} { if {![string match $first_letter $prev_letter]} { puts "" set prev_letter $first_letter } } # Display the current command puts $command }

5.4 Add Comments at End of Nested Code Blocks (Optional) Place comments after the ending curly braces of deeply nested or lengthy code blocks to identify the block they terminate; or better yet, don't write deeply nested or lengthy code blocks.

if {$route_flag} { ... foreach route {$route_list} { ... if {$security_flag} { ... }; # End of if {$security_flag} }; # End of foreach route loop }; # End of if {$route_flag}

5.5.1 Document Constants set MAX_RETRY_COUNT 10; operation and Important Variables set MIN_PAK_SIZE 64;
set MAX_PAK_SIZE 1500;

# Maximum number of times to try an # Minimum size of a valid IP packet # Maximum size of a valid IP packet

Add comments to document the purpose and use of all constants and important variables used in your software. 5.5.2 Document Internal Data Structures
# Important Data Structures: # # Global Array: tcl_command_list # Used to store information about TCL commands 60

ATS Automated Test Software Style Guide

Appendix A: Style Summary # Indexes: # command,[1-n] # type,[1-n] # used,[1-n]

Add comments to document the contents of complex internal data structures. 5.6.1 Include the Standard Script Header Comment Begin test scripts with the standard ATS script header comment.

Contains the command name Contains 'p' for proc, 'c' for command Exists if the command has been executed

##Script Header $Id: $ # Copyright (C) 2003 by Cisco Systems, Inc. Name: Purpose: Author: References: Description: Topology: Synopsis: Arguments: Sample Usage: Pass/Fail Criteria: Sample Output: Test Steps: Support Alias: Notes: Known Bugs: Todo: See Also: # End of Header
# # # # # $Log: $ ;;; Local Variables: *** ;;; mode: tcl *** ;;; End: ***

5.6.2 Include the Standard Script Footer Comment End test scripts with the ATS standard script footer comment. 5.7.1 Include Script Procedure Comments All procedures defined within a script should be preceded by a simple comment explaining the purpose and use of the procedure. 5.7.2 Include the Standard Procedure Library Header Comment All procedure libraries should begin with the ATS standard procedure library header comment.

# Repeatedly poll the router route table until the desired route # appears, returning True if the route appears and False otherwise proc route_up {router prot addr} { for {set i 0} {$i < $MAX_ROUTE_RETRIES} {incr $i} { if {[string match $route [$router exec "show $prot route"]]} { return $TRUE } sleep $ROUTE_SLEEP } return $FALSE }

##Library Header $Id: $ # Copyright (C) 2003 by Cisco Systems, Inc. Name: Purpose: Author: Usage: Description: Requirements: Variables: Notes: Known Bugs:
61

ATS Automated Test Software Style Guide

Appendix A: Style Summary

Todo: See Also: Support Alias: Keywords: Category: # End of Header 5.7.3 Include the Standard Procedure Library Footer Comment All procedure libraries should end with the ATS standard procedure library footer comment. 5.7.4 Include Standard Procedure Library Procedure Comments All procedures defined in a procedure library should be preceded with a detailed procedure comment defining the purpose and use of the procedure. ##Procedure Header Name: Purpose: Synopsis: Arguments: Return Values: Description: Examples: Sample Input: Sample Output: Notes: See Also:
##Internal Procedure Header # Return the first element of a list while setting the # list to contain the remaining elements proc shift {listName} { upvar $listName list set rc [lindex $list 0] set list [lrange $list 1 end] return $rc } # # # # # $Log: $ ;;; Local Variables: *** ;;; mode: tcl *** ;;; End: ***

5.7.5 Include Procedure Library Internal Procedure Comments Provide documentation for internal procedures as an aid to someone trying to understand the use of a library. 5.8.1 Include the Standard Class Library Header Comment All class libraries should begin with the ATS standard class library header comment.

##Class Header $Id: $ # Copyright (C) 2003 by Cisco Systems, Inc. Name: Purpose: Author: Inherits: Usage: Instantiation Example: Description: Requirements: Public Variables: Notes: Known Bugs: Todo: See Also: Support Alias:
62

ATS Automated Test Software Style Guide

Appendix A: Style Summary

5.8.2 Include Standard Class Library Method Comments All methods defined in a class library should be preceded with a detailed comment defining the purpose and use of the method.

Keywords: Category: # End of Header ##Method Header Name: Class Name: Purpose: Synopsis: Arguments: Return Values: Description: Examples: Sample Input: Sample Output: Notes: See Also:
# Set the number of days in the current year # Leap year adds 1 day to February (the 29th) in years that are # divisible by 4 and either divisible by 400 or not by 100 (i.e. # throw out the years divisible by 100 except those that are also # divisible by 400) in order to synchronize the calendar with the # seasons if {!($year % 4) && (($year % 400) || !($year % 100))} { set days 366; # Leap year } else { set days 365 } # Parse the packet counters from the IOS "show interface" command # output to extract input and output packet, byte, and error # counters # Sample "show interface" output: # # Ethernet 0 is up, line protocol is up # Hardware is MCI Ethernet, address is 0000.0c00.750c (bia 0000 # Internet address is 131.108.28.8, subnet mask is 255.255.255.0 # MTU 1500 bytes, BW 10000 Kbit, DLY 100000 usec, rely 255/255, # Encapsulation ARPA, loopback not set, keepalive set (10 sec) # ARP type: ARPA, ARP Timeout 4:00:00 # Last input 0:00:00, output 0:00:00, output hang never # Last clearing of "show interface" counters 0:00:00 # Output queue 0/40, 0 drops; input queue 0/75, 0 drops # Five minute input rate 0 bits/sec, 0 packets/sec # Five minute output rate 2000 bits/sec, 4 packets/sec # 1127576 packets input, 447251251 bytes, 0 no buffer # Received 354125 broadcasts, 0 runts, 0 giants, 57186* thr # 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 ab # 5332142 packets output, 496316039 bytes, 0 underruns # 0 output errors, 432 collisions, 0 interface resets, 0 re # set output [$router exec "show interface $int1"] foreach s [split $output "\n"] { regexp {([0-9]+) packets input, ([0-9]+) bytes,} $s ipaks ibytes regexp {([0-9]+) input errors,} $s ierrors regexp {([0-9]+) packets output, ([0-9]+) bytes,} $s opaks obytes regexp {([0-9]+) output errors,} $s ierrors } if {![info exists ipaks] || ![info exists ierrors] || ![info exists opaks] || ![info exists oerrors]} { 63

5.9 Comment Nonintuitive Script Logic Use detailed comments to document nonintuitive logic in your software.

5.10 Use Comments to Document Output Being Parsed Before a regexp command, include a comment that contains output being parsed so that readers can understand the data that the pattern must match.

ATS Automated Test Software Style Guide

Appendix A: Style Summary log_diagnostic_msg \ "Unable to parse $router 'show interface $int1' output\n$output" update_test_status $FAIL }

5.11 Comment Router Configurations Use the router configuration comment character (!) to comment complex and important router configuration strings.

$uut_router config " ! Apply the requested encapsulation and switching mode to the ! generator side interface interface $uut_gen_int [get_modes off ip_static $Version $gen_mode] [get_encaps off ip_static $Version $gen_encap "UutGen"] no ip address shutdown ! ! Apply the requested encapsulation and switching mode to the ! reflector side interface interface $uut_ref_int [get_encaps off ip_static $Version $RefEncap "UutRef"] no ip address shutdown ! no ip routing " # Copyright (c) 2006 Cisco Systems, Inc.

5.13 Include Cisco copyright notice in all files Include Cisco copyright notice in all files

6 Naming
6.1 Assign Meaningful Names Use meaningful names for variables and procedures. Instead of 'i' use 'input_count'. 6.2 Use Standard Characters in Names Use only lowercase alphabetic characters and underscores in variable names. Use uppercase characters only for naming constants and in camelback naming. 6.3 Abbreviate Names Abbreviate the words used to compose a name by removing vowels or using a portion of the word where appropriate. 6.5.2 Use Simple Name router router_type trim_flag _csccon_connect_timeout TRUE trimFlag var9__a__mess? pak_count_out pak_count_in pak_count_get()

pak_cnt_in trim_flg usr_num

ipmtst_ atutl_
64

ATS Automated Test Software Style Guide

Appendix A: Style Summary

Prefixing in Test Scripts Use simple name prefixing to ensure that script procedure and global data variable names are unique within the global name space. 6.5.3 Use Name Spaces in Procedure Libraries Use name spaces in procedure libraries to avoid name space collision. 6.6 Name Constant Variables Using Uppercase Characters Use uppercase alphabetic characters and underscores to make constant variables stand out visually. 6.7 Name Files Using Extensions Use filename extensions as suffixes to filenames to signify the type of file contents. .exp - Procedure Library .suite - Autotest Suite File .queue - Autotest Queue File .job - Autotest Job File .dat - Data File .config | .conf - Test Configuration File .txt | .doc - Documentation
namespace eval dbg { variable debug_enable; debug output }

# Flag used to enable/disable

proc dbg::debug {cmd {msg {}}} { ... }

FALSE MAX_RETRIES IP_ADDR

7 Constants
7.1 Define and Use Constant Variables Define constant variables for constant values that will be reused, need to be documented, or are likely to need quick changing to implement a script bug fix.
# Define constants set MAX_RETRIES 10 ... # Attempt to create a test device connection for {set i 0} {$i < $MAX_RETRIES} {incr i} { ... }

8 Software Structure
8.1 Script Structure Ensure that your script follows the standard structure and includes all Interpreter Invocation Header Comment Library Sourcing Password Setting Argument Parsing Argument Validation and Parsing
65

ATS Automated Test Software Style Guide

Appendix A: Style Summary

necessary sections.

Constant Definition Local Procedure Definition Test Configuration Test Execution and Analysis Test Unconfiguration Footer Comment Interpreter Invocation Header Comment Package Definition Require Libraries Define and Initialize the Namespace Define User Callable Procedures Define Internal, Support Procedures Footer Comment

8.2 Procedure Library Structure Ensure that your procedure library follows the standard structure and includes all necessary sections.

ATS Automated Test Software Style Guide

66

S-ar putea să vă placă și