Swaks Release 20111230.0 Available

Updated 2012-03-20: The links below still work for the 20111230.0 release, but this release is no longer current. If you are not specifically looking for the 20111230.0 release, please see the project home page at http://jetmore.org/john/code/swaks/ for the latest release.

A new version of swaks is currently available for download.

Downloads:

New Features:

  • Added –output-file family of options to capture some or all output without requiring shell redirection
  • Added –protect-prompt option to protect “sensitive” user input (currently only auth passwords)
  • Added –auth-hide-password to replace recoverable passwords in SMTP session output with a dummy string
  • Added –auth-extra to have a single interface to pass non-standard authentication options into swaks. Currently used by NTLM and DIGEST-MD5.
  • Added –show-raw-text option to provide more details of exact data being sent on the wire

Notable Changes:

  • SMTP Data token parsing has been changed from single-character (%F) to multi-character (%FROM_ADDRESS%) to reduce chance of collisions with message text, especially non-ascii language encoding. See –use-old-data-tokens to recover old tokens while transitioning. (issue reported by Peter Baranyi)
  • Specifying the NTLM/MSN/SPA DOMAIN by appending “%DOMAIN” to the username is no longer supported. See the new –auth-extra command.
  • The DIGEST-MD5 authentication no longer uses the (buggy) Authen::DigestMD5 module. The Authen::SASL module is now used.

Notable Bugs Fixed:

  • Previous release broke ability to use –header to set custom headers (first reported by David Favor)
  • Previous release would not allow a file to be used to provide the message data if the file name contained the character “n”. (first reported by dietrich.rebmann@******)
  • swaks has never properly handled creating date strings for timezones that are not on an even hour boundary. (report from, and patch provided by, Peter Samuelson)
  • The documented behavior of the “no-” prefix on swaks’ options did not work when –OPTION and –no-OPTION were given in the same context.
  • The DIGEST-MD5 auth type was not completely implemented. Worked extensively with Erwan Legrand to get as complete and useful an implementation as possible.
  • Previous release contained a regression in which TLS responses sent in multiple packets were not processed correctly. (reported by Peter J. Holzer)

Swaks Release Preview 20111202.0-dev Available

I’m almost ready to release a new version of swaks which includes a few new features and some bug fixes.  The last change I made involved a change in the code which reads text from the server.  All of my testing indicates that the code is right, but my available testing platforms aren’t as varied as they used to be.   If you are able, please download and test.  Feel free to share the link as much as you want, but please don’t package it yet.  If no one reports anything serious I’ll release the “real” version in a week or so.

Here are links to the script and the Changelog for this version:

LINK REMOVED – this was a development release and the changes have been incorporated in official releases. Please see the project home page at http://jetmore.org/john/code/swaks/ for the latest release.

I don’t have a pretty version of new features or bug fixes yet but the Changelog can be trawled for a decent overview.

Any testing notes or last minute requests can be dropped as a comment here if you want, but they are most useful as an email to proj-swaks@jetmore.net.

More places to hear about swaks

I’ve never been especially proactive in evangelizing swaks, but its usage number have grown to the point in the last 10 years that I think I probably am probably hurting users by not having more communication channels to receive and provide updates.  So, here’s a quick breakdown of what channels exist right now, and where I want to go in the future

Current

  • Website – http://jetmore.org/john/code/swaks
  • Update list – There’s no UI for this, but emailing updates-swaks@jetmore.net and asking to be notified of new releases will get you on the notify list.

New

Future

  • I don’t really have any desire to run a mailing list myself but there have been some requests for one (which I assume would be very, very low traffic).
  • swaks.net – I own this domain, at some point in the future I think it makes sense for the swaks distribution to move to it.
  • Trac – swaks’ “todo” list is not huge, and not especially hard to hold in my head, but I like the idea of Trac or something similar because of its ticket/commit cross reference and the timeline to help remember the history of the development.  Not sold on this being worth the effort of maintaining yet.
If there’s some specific thing you’d like to see from swaks, whether it’s a communication channel or a feature/bug, please let me know in the comments or via email (proj-swaks@jetmore.net).

UI Improvements for TestLink’s Vertical Step Layout

I have previous posts on several improvements which drastically improved my team’s ability to use TestLink:

As we began really testing in earnest, we found that the “horizontal” test case layout we had been using was limiting in several ways.  First, when the expected results was a collection of logs rather than a text description of behavior, it became a labor to find the relevant bits in the long log lines.  Second, some types of expected results would cause the results cell to take up as much horizontal space as possible, which squashed the “actions” cell.  On more than one occasion I had to copy the actions to a text file so that I could read them in a meaningful manner.

Update 2012-05-08: There is a usable-with-the-patch-command patch available that incorporates all of these changes and more. See the README at the base of the github repo for more details on what’s in that patch.

Fortunately there is also a “vertical” test case layout.  We recently switched to using this and so far it solves our problem.  Unfortunately I had to reimplement all of the items from the links above.  The diffs below are the changes I made to our files to get the desired changes.  Possible items of interest:

  • The diffs below assume that the changes from the previous blog posts have been made.  This affects the line numbers in the diffs, as well as things like the existence of the CSS file and its contents.
  • I never really liked the alternating BG color behind the steps, but it was the best solution in the horizontal view.  In the vertical view I alternated the colors in the empty gutter cells to the left of the action/result rows.  Since there’s no text in those cells, it allowed me to use darker, more contrasting colors.
Index: gui/themes/default/css/custom.css
===================================================================
--- gui/themes/default/css/custom.css   (revision 241)
+++ gui/themes/default/css/custom.css   (revision 242)
@@ -6,6 +6,14 @@
        background-color:       #CCCCCC;
 }

+.row_color_3 {
+       background-color:       #555555;
+}
+
+.row_color_4 {
+       background-color:       #AAAAAA;
+}
+
 div.c_actions, div.c_expected_results {
        font-family: 'Courier New', Courier, monospace;
 }
Index: gui/templates/testcases/inc_steps.tpl
===================================================================
--- gui/templates/testcases/inc_steps.tpl       (revision 241)
+++ gui/templates/testcases/inc_steps.tpl       (revision 242)
@@ -91,14 +91,16 @@
        {/if}
        {foreach from=$steps item=step_info}
        <tr>
-               <th width="25px"><nobr>{$inc_steps_labels.step_number}
+               <th width="25px"><nobr>
                <span class="order_info" style='display:none'>
                <input type="text" name="step_set[{$step_info.id}]" id="step_set_{$step_info.id}"
                       value="{$step_info.step_number}"
                       size="{#STEP_NUMBER_SIZE#}"
                       maxlength="{#STEP_NUMBER_MAXLEN#}">
                {include file="error_icon.tpl" field="step_number"}
-               </span>{$step_info.step_number}</nobr></th>
+               </span><span {if $edit_enabled} style="cursor:pointer;"
+        onclick="launchEditStep({$step_info.id})"{/if}
+               >{$inc_steps_labels.step_number} {$step_info.step_number}</span></nobr></th>
                <th>{$inc_steps_labels.step_actions}</th>
                {if $session['testprojectOptions']->automationEnabled}
                <th>{$inc_steps_labels.execution_type_short_descr}:
@@ -111,10 +113,8 @@
                {/if}
        </tr>
        <tr>
-               <td>&nbsp;</td>
-               <td colspan="2" {if $edit_enabled} style="cursor:pointer;"
-                   onclick="launchEditStep({$step_info.id})"{/if}
-                   style="padding: 0.5em">{$step_info.actions}</td>
+               <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}">&nbsp;</td>
+               <td colspan="2" style="padding: 0.5em"><div>{$step_info.actions}</div></td>
                {if $edit_enabled}
                <td class="clickable_icon">
                        <img style="border:none;cursor: pointer;"
@@ -133,13 +133,13 @@
                {/if}
        </tr>
        <tr>
-               <th style="background: transparent; border: none"></th>
+               <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}"></td>
                <th colspan="2">{$inc_steps_labels.expected_results}</th>
        </tr>
-       <tr {if $edit_enabled} style="cursor:pointer;"
-           onclick="launchEditStep({$step_info.id})"{/if}>
-           <td>&nbsp;</td>
-               <td colspan="2" style="padding: 0.5em 0.5em 2em 0.5em">{$step_info.expected_results}</td>
+       <tr>
+           <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}">&nbsp;</td>
+               <td colspan="2" style="padding: 0.5em 0.5em 2em 0.5em">
+                       <div>{$step_info.expected_results}</div></td>
        </tr>
        {/foreach}
 {/if}
Index: gui/templates/testcases/tcStepEdit.tpl
===================================================================
--- gui/templates/testcases/tcStepEdit.tpl      (revision 241)
+++ gui/templates/testcases/tcStepEdit.tpl      (revision 242)
@@ -223,7 +223,7 @@
   {else} {* Vertical layout *}
                {foreach from=$gui->tcaseSteps item=step_info}
                        <tr id="step_row_{$step_info.step_number}">
-                               <th width="20">{$args_labels.step_number} {$step_info.step_number}</th>
+                               <th width="20"><a href="{$hrefEditStep}{$step_info.id}">{$args_labels.step_number} {$step_info.step_number}</a></th>
                                <th>{$labels.step_actions}</th>
                                {if $session['testprojectOptions']->automationEnabled}
                                        {if $step_info.step_number == $gui->step_number}
@@ -244,24 +244,24 @@
                                {/if}
                        </tr>
                        <tr>
-                               <td>&nbsp;</td>
+                               <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}">&nbsp;</td>
                                {if $step_info.step_number == $gui->step_number}
                                        <td colspan="2">{$steps}</td>
                                {else}
-                                       <td colspan="2"><a href="{$hrefEditStep}{$step_info.id}">{$step_info.actions}</a></td>
+                                       <td colspan="2"><div>{$step_info.actions}</div></td>
                                {/if}
                        </tr>
                        <tr>
-                               <th style="background: transparent; border: none"></th>
+                               <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}"></td>
                                <th colspan="2">{$labels.expected_results}</th>
                        </tr>
                        <tr>
-                               <td>&nbsp;</td>
+                               <td class="{cycle values="row_color_3,row_color_3,row_color_3,row_color_4,row_color_4,row_color_4"}">&nbsp;</td>
                                {if $step_info.step_number == $gui->step_number}
                                        <td colspan="2">{$expected_results}</td>
                                {else}
                                        <td colspan="2" style="padding: 0.5em 0.5em 2em 0.5em">
-                                       <a href="{$hrefEditStep}{$step_info.id}">{$step_info.expected_results}</a></td>
+                                       <div>{$step_info.expected_results}</div></td>
                                {/if}
                        </tr>
                {/foreach}

Setting Default Font in TestLink

When I first set up TestLink, one of my first actions was to figure out how to force FCKEditor to use a monospace font. Much of our testing takes place in terminals using a monospace font, and I thought it would be easier to engage with the expected results if they were also in a monospace font. This was a fairly easy thing to do using the TestLink and FCKEditor docs, but since I haven’t written it down before, here are the steps using a monospace font by default in TestLink using FCKEditor.

Update 2012-05-08: There is a usable-with-the-patch-command patch available that incorporates all of these changes and more. See the README at the base of the github repo for more details on what’s in that patch.

First, create a file called custom_textarea.css. I placed this in the root of my install, which probably wasn’t the best place for it. The contents are a lightly edited copy of body class from gui/themes/default/css/testlink.css:

body {
    background:     #FFF;
    font-family:    'Courier New', 'Trebuchet MS', Arial, Verdana, sans-serif;
    font-size:      small;
    margin:         0px;
    padding:        0px;
}

The “light editing” I did was to push ‘Courier New’ onto the front of the font-family.  I also changed it so that the edit window background would be white instead of grey by changing the background color.

Then I told FCKEditor to use this CSS as the style for the edit boxes by adding the following line to cfg/tl_fckeditor_config.js:

// Set our own custom css (sets white background and mono-space font)
FCKConfig.EditorAreaCSS = FCKConfig.BasePath + '../../../custom_textarea.css';

This did accomplish the task that I had set for myself, which was changing the default font displayed by FCKEditor when editing text.  However, I also assumed that it would, when the text in the editor was saved, cause that saved text to be displayed in a monospace font.  It turns out that this didn’t work though.  I can’t decide if this is a bug in TestLink or not, but these defaults don’t get applied when the text is displayed.

I spent quite a bit of time looking for the correct knob to fix this in the TestLink docs and the FCKEditor docs, and I couldn’t find one.  Font editing works, but you have to explicitly change the font option while editing to make it work.

What I ended up doing was to edit the two Smarty templates used for displaying steps so that each action and step were wrapped in a div I could control, and then changed the style for that div so that the default font was monospaced.  In a way this was actually a better solution than a general FCKEditor knob because it allowed me to just change the default font in action/expected results, and not other text, like Summary, that might look better as a variable-width font.

To achieve this I first added two new classes to gui/themes/default/css/custom.css.  This could have been done with just one class, but I liked the idea of being able to change the style of actions and results independently in the future.

div.c_actions, div.c_expected_results {
    font-family: 'Courier New', Courier, monospace;
}

Then I added the class to inc_steps.tpl and tcStepEdit.tpl.

--- inc_steps.tpl.dist  2011-08-22 21:08:21.000000000 -0500
+++ inc_steps.tpl       2011-09-26 09:42:25.000000000 -0500
@@ -53,10 +53,10 @@
                                size="{#STEP_NUMBER_SIZE#}"
                                maxlength="{#STEP_NUMBER_MAXLEN#}">
                        {include file="error_icon.tpl" field="step_number"}
                        </span>{$step_info.step_number}
                </td>
-               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$step_info.actions}</td>
-               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$step_info.expected_results}</td>
+               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}><div class="c_actions">{$step_info.actions}</div></td>
+               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}><div class="c_expected_results">{$step_info.expected_results}</div></td>
                {if $session['testprojectOptions']->automationEnabled}
                <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$gui->execution_types[$step_info.execution_type]}</td>
                {/if}
--- tcStepEdit.tpl.dist 2011-09-22 10:27:23.000000000 -0500
+++ tcStepEdit.tpl      2011-09-26 09:43:47.000000000 -0500
@@ -211,8 +211,8 @@
        {/if}
       {else}
         <td style="text-align:left;"><a href="{$hrefEditStep}{$step_info.id}">{$step_info.step_number}</a></td>
-               <td ><a href="{$hrefEditStep}{$step_info.id}">{$step_info.actions}</a></td>
-               <td ><a href="{$hrefEditStep}{$step_info.id}">{$step_info.expected_results}</a></td>
+               <td ><a href="{$hrefEditStep}{$step_info.id}"><div class="c_actions">{$step_info.actions}</div></a></td>
+               <td ><a href="{$hrefEditStep}{$step_info.id}"><div class="c_expected_results">{$step_info.expected_results}</div></a></td>
         {if $session['testprojectOptions']->automationEnabled}
                  <td><a href="{$hrefEditStep}{$step_info.id}">{$gui->execution_types[$step_info.execution_type]}</a></td>
                {/if}

These aren’t exactly what my diffs look like since I removed the links from the display text last week, but I believe it will work.

Better Copy/Paste When Editing Test Steps in TestLink

My current biggest peeve with TestLink is how hard TestLink makes it to copy text out of test steps when editing a test case. Both when viewing a case and when editing test case steps via the Test Specification interface, clicking on the text of a test step causes you to start editing the text in that step.

I find this behavior very off-putting. I constantly find myself trying to copy in these views, either to copy repetitive actions from a previous step, or to do a dry-run executing a test case. I finally got mad enough today to spend the time figuring out how to change this behavior.

Update 2012-05-08: There is a usable-with-the-patch-command patch available that incorporates all of these changes and more. See the README at the base of the github repo for more details on what’s in that patch.

There are two Smarty templates that control the layout of these views, both of which live in gui/templates/testcases/. inc_steps.tpl controls the layout when viewing a test case (but not editing steps), and tcStepEdit.tpl controls the layout when editing steps.

After applying these patches, you can copy text out of the Step Action and Expected Results columns. To edit the row as before the patch, click on the row counter (the first cell in the row).

These patches are against TestLink 1.9.3

--- inc_steps.tpl.dist  2011-08-22 21:08:21.000000000 -0500
+++ inc_steps.tpl       2011-09-22 10:08:55.000000000 -0500
@@ -53,10 +53,10 @@
                                size="{#STEP_NUMBER_SIZE#}"
                                maxlength="{#STEP_NUMBER_MAXLEN#}">
                        {include file="error_icon.tpl" field="step_number"}
-                       </span>{$step_info.step_number}
+                       </span><div {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$step_info.step_number}</div>
                </td>
-               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$step_info.actions}</td>
-               <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$step_info.expected_results}</td>
+               <td>{$step_info.actions}</td>
+               <td>{$step_info.expected_results}</td>
                {if $session['testprojectOptions']->automationEnabled}
                <td {if $edit_enabled} style="cursor:pointer;" onclick="launchEditStep({$step_info.id})" {/if}>{$gui->execution_types[$step_info.execution_type]}</td>
                {/if}
--- tcStepEdit.tpl.dist 2011-09-22 10:27:23.000000000 -0500
+++ tcStepEdit.tpl      2011-09-22 10:39:55.000000000 -0500
@@ -211,8 +211,8 @@
        {/if}
       {else}
         <td style="text-align:left;"><a href="{$hrefEditStep}{$step_info.id}">{$step_info.step_number}</a></td>
-               <td ><a href="{$hrefEditStep}{$step_info.id}">{$step_info.actions}</a></td>
-               <td ><a href="{$hrefEditStep}{$step_info.id}">{$step_info.expected_results}</a></td>
+               <td >{$step_info.actions}</td>
+               <td >{$step_info.expected_results}</td>
         {if $session['testprojectOptions']->automationEnabled}
                  <td><a href="{$hrefEditStep}{$step_info.id}">{$gui->execution_types[$step_info.execution_type]}</a></td>
                {/if}

I’ve been writing test cases with this change in place all morning and it is much, much nicer than the default behavior

Using Wiki Markup in Trac Custom Ticket Fields

Yesterday I worked on streamlining our ticket workflow in Trac. While I was in the test project anyway, I decided to address an issue that had bugged me since I first set up Trac. I originally set up two custom ticket fields related to case IDs in our CRM system:

crmnum = text
crmnum.label = Case #
crmnum.format = plain
crmnum.order = 1
crmlink = text
crmlink.label = Case Link
crmlink.format = wiki
crmlink.order = 3

The idea was that we could have the “crmnum” field to just hold the ID, which we could act on programmatically. The “crmlink” field would be a copy/paste link of the ticket’s URL, which would allow someone looking at the ticket to click through to the CRM case easily.

The problem with this is that the link is long and ugly and completely throws off the tidiness of the ticket summary.

So, having recently figured out how to write a custom wiki macro, I decided to create one for links to our CRM system also. The idea would be that the “crmlink” field would go away and the “crmnum” field could be updated to use the wiki Macro to generate the link automatically.

I nuked the “crmlink” field and changed “crmnum” from “type = plain” to “type = wiki“. I wrote my custom CRM macro, testing it in the wiki itself until I had it behaving. I then created a new ticket, entered [[CRM(123)]] in the crmnum field, and clicked “Preview”. Instead of seeing the link it should have returned, instead I got [[CRM(...)]]. I did some testing and proved to myself that some wiki processing was taking place (ticket:1 expanded correctly) and that no macro expanded in that field, including built-in macros.

Then on a hunch, I changed crmnum to “type = textarea” instead of “type = text“. Sure enough, macros work properly in textarea fields but not text fields. In a way this makes sense since almost all built-in macros return multiple lines of text. The documentation for custom ticket fields doesn’t mention that wiki processing behavior differs between these field types. Unfortunately the textarea fields can’t easily be tricked into looking like a simple text field. They come with an editing bar, and they are assigned the same class as the description field, so you can’t easily use CSS tricks on it.

I was unsure if this was a bug or intentional, but I managed to find the original Trac ticket for adding wiki processing to custom fields, and it’s clear that it was intentional to make the wiki-processing behavior of the two field types differ. Specifically, text fields are processed with format_to_oneliner() and textareas are processed with format_to_html() (this can be seen in the change to web_ui.py associated with new feature.

After figuring out that the text/textarea parsing differences were done intentionally, I lost interest in patching the code itself. Instead I looked into using InterWiki links instead of macros, which are processed in text fields.

I created trac ticket 10352 about this issue, hopefully it gets addressed one way or another.

Linking to TestLink testcases from Trac addendum

Last week I posted about a custom [[TestLink()]] macro I had written for Trac. Yesterday I wrote another macro to do something similar, but in doing so I found out that I was probably doing a lot more work than I needed to.

The macro I wrote allowed me to write [[TestLink(m3-123)]] to link directly to test case 123 in the m3 project. It was about seven lines of python and not the most complex thing in the world, but nowhere near as simple as using an InterWiki prefix. I did this by adding the following line to my Trac install’s InterMapTxt wiki page:

TestCase https://devtest.example.com/linkto.php?tprojectPrefix=$1&item=testcase&id=$1-$2

This allows me to replace [[TestLink(m3-123)]] with testcase:m3:123.

There are tradeoffs of course. The macro allows full control using python. That allowed me to write a single macro that could produce links to different places in our CRM system based on the format of the single argument to the macro. Since I don’t get that flexibility with InterWiki links, I had to use two InterWiki links instead of a single macro.

On the other hand, the InterWiki links are simpler to write, look better, and are much closer to the standard Trac wiki link style that my users are already used to. Also, they have the advantage that they are expanded in ticket custom text fields and macros aren’t.

In the end I’ll keep both the macros and the InterWiki links for these cases since they aren’t mutually exclusive, but I’ll definitely turn to InterWiki links before I turn to writing a custom macro in the future.

Arduino’s map() Function and Numeric Distribution

The Arduino map() function is an interesting beast. Very technically it works exactly as its documented to work, but not the way almost every example uses it.

Here’s an example you can find in hundreds of sketches online, including the actual documentation for map():

val = map(val, 0, 1023, 0, 255);

This is a simple map, and one would expect that every four ticks on the input would map to one tick on the output (that is, {0,1,2,3} -> 0, {4,5,6,7} -> 1, etc). But that’s not what the function above actually does.

To show the issue, let’s make the output range smaller (but still an even divisor):

val = map(val, 0, 1023, 0, 15);

This should result in an even distribution, 64 input ticks per one output tick. To test this, I wrote a quick script implementing the Arduino map logic (which they were nice enough to document):

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

The script prints a table of output values and the number of times that value was returned. Here’s the output for map(?, 0, 1023, 0, 15) for each value in 0..1023:

map(0..1023, 0, 1023, 0, 15);
  0   69
  1   68
  2   68
  3   68
  4   68
  5   69
  6   68
  7   68
  8   68
  9   68
 10   69
 11   68
 12   68
 13   68
 14   68
 15    1

That’s definitely not an even distribution. Now here’s a really stark example:

map(0..1023, 0, 1023, 0, 1);
  0 1023
  1    1

That’s a pretty egregious imbalance.

I mentioned earlier that the function’s actually working how it’s documented to work, just not how it’s usually used in examples. The map() docs state that “[t]he map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged.”

This completely makes sense – if you imagine a range of 1024 values between 0 and one, all of them will be less than 1 except the last value, and since it’s integer arithmetic, all the less-than-1 values are 0.

The solution is fairly simple – increase the in_max and out_max args by one more than the actual maximum value (and then wrap the output in constrain(), which you ought to have done anyway). It’s fairly easy to work through why this works in your head, but here are the same examples I gave above with the increased maximums:

map(0..1023, 0, 1024, 0, 2);
  0   512
  1   512
map(0..1023, 0, 1024, 0, 16);
  0   64
  1   64
  2   64
  3   64
  4   64
  5   64
  6   64
  7   64
  8   64
  9   64
 10   64
 11   64
 12   64
 13   64
 14   64
 15   64

I have worked through this and I now understand how to get the values I want out of constrain. What I don’t know, however, is why the docs and the examples don’t address this issue. I know I’m not the first person to find this issue because I’ve found sketches on the internet where people are doing this (and they’re doing it in a way that leads me to believe they’re doing it on purpose), but I couldn’t get Google to show me any pages where someone actually addresses this point. I wonder why?

As for why I was looking into this, I was playing around with a couple of pots and an LCD, making a fakey etch-a-sketch using the 2-row LCD I have for such things. I could not figure out why my vertical control would only drop me down a line when I had the pot turned 100%. Now I know…

Edit 2011-09-13:

I posted this in the arduino.cc forum last night. As I expected, this is an issue known in the arduino community. Among other things, I was referenced to this post discussing the issue. My problem with all of this isn’t so much that it’s odd behavior, but that it’s been odd for at least 2 years and there’s no mention of the oddness in the map() documentation. The docs are a wiki, so I proposed an addition in the forum thread, maybe I’ll get to add it and help someone out in the future.

Custom TestLink Macro for Trac

I’ve been spending a lot of time lately trying to get the workflow between Trac and TestLink to make sense. I’m far from having the perfect solution, but a great first step was creating a Trac wiki macro that will link to specific test cases in TestLink. There’s lots of areas in which this could be improved in the future…

Create this as conf/TestLinkMacro.py in your project (replacing test.example.com with your TestLink host):

import re

from trac.wiki.macros import WikiMacroBase

class TestLinkMacro(WikiMacroBase):
    """Macro to generate automatic links to test cases in TestLink.
    """

    def expand_macro(self, formatter, name, args):
        """Expand a TestLink test case ID into a link
        """
        TestLinkServer = 'test.example.com'
        matches = re.match(r'(.*)-(d+)$', args)
        
        return '<a href="https://' + TestLinkServer + '/linkto.php?tprojectPrefix=' + matches.group(1) + '&item=testcase&id=' + matches.group(0) + '">[[TestLink(' + matches.group(0) + ')]]</a>'

After putting this in place, and possibly restarting Trac, you can create a direct link to test case m3-123 in a wiki by typing [[TestLink(m3-123)]]. Note that I could have changed the actual string displayed in the wiki to anything I wanted, but I chose to leave it looking identical to the actual macro (but linked) so that it would reinforce to people the correct format for the test case links.

This macro is useful in several ways, but the most obvious is allowing us to enter regression test case IDs into commit messages (which then get associated with a ticket in Trac and are displayed with the wiki engine, making the test case link clickable).
With commit messages being associated with tickets automatically and being displayed by the wiki engine, this gives us a nice syntax to enter regression case links into commit messages and be very followable later

Edit 2011-09-13:

See also this update to my use of macros for linking to test cases and this comment on custom ticket field wiki parsing, both of which have a direct relation to this post