Is there an automatic test case generated available for Tcl? Similar to quickcheck or scala check? An internet search did not reveal any library.
tl;dr: Nothing that I'm aware of, but you can code it on top of tcltest easily enough.
I looked into some QuickCheck and ScalaCheck tutorials. Interesting, but they have the problem of not guaranteeing to find problems. The examples all nicely show how things can work, when problems are found with short inputs, but with the stochastic input models (poisson distributions I suspect?) used I really don't think there's much chance of finding upper-bound or specific-value failures unless you feed through a very large amount of data indeed.
There's also the problem that Tcl code is in general stateful; testing when you've got state about requires a more complex approach. Basically, you in general need an extra piece of code to put the system into the state you want to test and another to take the system out of that state and return it to quiescent. Good test frameworks have this sort of thing down pat, so it's not actually a real problem. Just a complication you need to be aware of.
But we can use the fact that Tcl is pretty much all a domain-specific language to make our own little fuzz tester. (The upvar and uplevel commands are awesomely useful for this sort of thing.)
package require tcltest 2
proc fuzzInteger {var from to count test} {
upvar 1 $var v
for {set i 0} {$i < $count} {incr i} {
set v [expr {$from+int(rand()*($to-$from))}]
uplevel 1 $test
}
}
proc fuzzList {var P language count test} {
upvar 1 $var v
for {set i 0} {$i < $count} {incr i} {
set v {}
while {rand() <= $P} {
lappend v [lindex $language [expr {int(rand() * [llength $language])}]]
}
uplevel 1 $test
}
}
# Demonstrate by throwing random crap into 'lindex'; it should never produce an error
fuzzList abcList 0.5 {a b c} 500 {
fuzzInteger foobar 0 20 500 {
tcltest::test lindex-fuzztest-[incr count] "fuzzed: lindex {$abcList} $foobar" -body {
lindex $abcList $foobar
} -match glob -result *
}
}
# Print the final report
tcltest::cleanupTests
In this case, there was no need for state setup/cleanup; those would be handled by the -setup and -cleanup clauses to the tcltest::test. Also note that it's an extremely good idea to record what fuzzed values are used in the title of the test or by doing substitutions in the body (the second is harder, BTW; my example above shows the first).
Related
I tried to write an automatic script for modelsim, where I would go through each possible malfunction in the circuit one by one, and then analyze it. For one malfunction, I did everything, and it works, however when I tried to make a loop where I did the same with everyone one by one, I had several problems at once.
Can do files be called from tcl scripts? Since the actions for one malfunction are performed using the do file, and the loop for iterating over them is already a Tcl script.
When trying to run the whole thing, modelsim gave an execution result of 0 and that's all, despite the fact that it did not swear at syntax errors.
Here is the do file for one fault (fault.do):
vmap work work
vcom -reportprogress 300 -work work {sheme.vhd}
vcom -reportprogress 300 -work work {testbench.vhd}
vsim -wav simwave.wlf work.device_tb
env sim:/device_tb/uut
view signals
.signals.tree write signalfile.txt
add wave sim:/device_tb/uut/*
add list sim:/device_tb/uut/*
run 5000 ns
quit -sim
quietly WaveActivateNextPane {} 0
dataset open ./simwave.wlf simwave
add wave simwave:/device_tb/uut/*
add list simwave:/device_tb/uut/*
vsim work.device_tb
env sim:/device_tb/uut
view signals
quietly WaveActivateNextPane
add wave sim:/device_tb/uut/*
add list sim:/device_tb/uut/*
source forc.tcl
tosignal 1
quietly WaveActivateNextPane
compare start simwave sim
compare options -track
compare add -wave -recursive -tolL {0 ns} -tolT {0 ns} simwave:/device_tb/uut sim:/device_tb/uut
compare add -list -recursive -tolL {0 ns} -tolT {0 ns} simwave:/device_tb/uut sim:/device_tb/uut
compare run
view wave
view list
compare info -write C:/Modeltech_5.7f/examples/dip/compare.txt
source analys.tcl
comp 2
And here are my attempts to make a loop for all such faults:
set fp [open "signalfile.txt" r]
set cnts 0
set cntoth 0
while { [gets $fp data] >= 0 } {
if {[string match $data s?] == 1} {
incr cnts } else {
incr cntoth }
}
for {set i 0} {$i < $cnts} {incr i} {
set var $env($i)
source fault.do
exec $var }
set fn [open "errors.txt" r]
set er 0
while { [gets $fn data] >= 0 } {
incr er }
set per [expr $er/[expr $cntoth + $cnts]]
puts $per
Can anyone suggest how best to implement this? I'll be very thankful)
In Python, Ruby 2.0, Perl 6, and some hardware description languages, one can use named arguments. See this example. This makes the code more readable, easy to maintain, etc. Is there a way of getting it done/extension, in TCL 8.6, other than using a dictionary as a workaround?
In 8.6, use a dictionary parsed from args. The dict merge command can help:
proc example args {
if {[llength $args] % 2} {
return -code error "wrong # args: should be \"example ?-abc abc? ?-def def?\""
}
set defaults {
-abc 123
-def 456
}
set args [dict merge $defaults $args]
set abc [dict get $args -abc]
set def [dict get $args -def]
puts "abc=$abc, def=$def"
}
example; # abc=123, def=456
example -abc 789; # abc=789, def=456
example -def 789; # abc=123, def=789
example -def 246 -abc 135; # abc=135, def=246
You can go further than that with verifying (the tcl::prefix command can help) but it's a lot more work and doesn't buy you a lot more in production code. Not that that has stopped people from trying.
There are two proposals to add full named argument handling
(TIP #457, TIP #479) to 8.7 at the moment, but I'm not sure that either have really gained traction. (The problem from my perspective is the extra runtime cost that has to be borne by code that doesn't volunteer to support named arguments. There might be other issues too, such as disagreement over preferred syntax; I've not paid so much attention to that as I'm still fretting over the performance implications in a pretty hot piece of code.)
There is an entire page on the tcler's wiki that discusses named arguments: http://wiki.tcl.tk/10702
You can do it yourself with a little creativity. There are several mechanisms that allow you to do this:
procs can define other procs
proc behave just like a proc (the function definition system is not a syntax, it is a function call)
procs can use the args argument instead of positional parameter and manually process the list of arguments
you can execute code in any parent stack frame using uplevel
you can pull variables from any parent stack frame using upvar
everything is a string!
etc.
I'm not sure I've listed all the possible mechanisms.
My personal implementation of this idea is optproc: http://wiki.tcl.tk/20066
The implementation itself is quite simple:
proc optproc {name args script} {
proc $name args [
string map [list ARGS $args SCRIPT $script] {
foreach var {ARGS} {
set [lindex $var 0] [lindex $var 1]
}
foreach {var val} $args {
set [string trim $var -] $val
}
SCRIPT
}
]
}
I basically used string manipulation (string map) to directly insert the function body ($script) into the defined function without any substitutions etc. This is to avoid any $ or [] from being processed. There are many ways to do this but my go-to tool is string map.
This is similar to Donald's answer except for two things:
I don't transform args into a dict instead I manually process args and declare each local variable in a loop.
This is a meta solution. Instead of processing args I created another function (syntax) to create a function that processes args.
Usage (stolen from Donald's answer) would be:
optproc example {abc def} {
puts "abc=$abc, def=$def"
}
But note that my solution is not the only solution. There are many ways to do this limited only by creativity.
I want to write a tcl script to align my tcl script with proper indentation. For Example if i have a code like :
proc calc { } {
set a 5
set b 10
if {a < b} {
puts "b Greater"
}
}
I need to change like:
proc calc { } {
set a 5
set b 10
if {a < b} {
puts "b Greater"
}
}
Could u guys help on this.
Writing an indenter that handles your example is trivial. A full indenter that can handle most Tcl scripts is going to be very big and quite complicated. An indenter that can handle any Tcl script will have to incorporate a full Tcl interpreter.
This is because Tcl source code is very dynamic: for one thing you can't always just look at the code and know which parts are executing code and which parts are data. Another thing is user-defined control structures, which might change how the code is to be viewed. The example below works by counting braces, but it makes no attempt to distinguish between quoting braces that should increase indentation and quoted braces that should not.
This example is a very simple indenter. It is severely limited and should not be used for serious implementations.
proc indent code {
set res {}
set ind 0
foreach line [split [string trim $code] \n] {
set line [string trim $line]
# find out if the line starts with a closing brace
set clb [string match \}* $line]
# indent the line, with one less level if it starts with a closing brace
append res [string repeat { } [expr {$ind - $clb}]]$line\n
# look through the line to find out the indentation level of the next line
foreach c [split $line {}] {
if {$c eq "\{"} {incr ind}
if {$c eq "\}"} {incr ind -1}
}
}
return $res
}
This will convert your first code example to your second one. Add even a single brace as data somewhere in the code to be indented, though, and the indentation will be off.
Documentation: append, expr, foreach, if, incr, proc, return, set, split, string
Brain Teaser: I self originated this question, but stuck completely.
I want to create all possible combination of all characters, but of all possible lengths. Suppose, [a-z] combination of 1 length, then [a-z] combination of 2 length, and so on till the maximum length achieved.
this could be very easily done by iterative looping.
Example for 3 length:
proc triples list {
foreach i $list {
foreach j $list {
foreach k $list {
puts [list $i $j $k]
}
}
}
}
But, it should solve using less loops (looping needs to be dynamic)
set chars "abcdefghijklmnopqrstuvwxyz"
set chars [split $chars ""]
set complete_length [llength $chars]
set start 0
set maximum_length 15
while {1} {
if {$start > $maximum_length} {
break
}
for {set i [expr $maximum_length-$start]} {$i >= 0} {incr i -1} {
# dump combinations
}
incr start
}
In this chunk, what algorithm or method i should apply? Any kind of suggestions/help/code will be appreciated.
Sry, this is not an answer, but hopefully some interesting discussion anyway:
The word "combinations" is often used way too generally, so it can be interpreted in many different ways. Let's say that you have a source list of 26 different elements, the english letters, and you want to pick 3 of them and combine in a 3 element destination list:
Can you always pick any letter from the source list, or do the elements disappear from it as you pick them? Either define "pick" (are the elements copied or moved during a pick), or define the set of source values (is there 1 of each of A-Z or an infinite amount of A-Z).
Does the order in the destination list matter? Is AHM considered to be the same combination as HAM? Define "combine".
If you have a list where not all elements are different, e.g. {2 10 10 64 100}, you have even more possibilities. Define your set of values.
Your first example prints permutations, not combinations. If that's what you want, the easiset way is a recursive procedure. Combinations are more complicated to generate.
EDIT:
I wrote this procedure for a Project Euler program. It picks all the elements, but maybe you can modify it to pick n. It takes a command prefix as argument, so you don't have to store all permutations.
package require Tcl 8.5.0
proc forEachPerm {list cmdPrefix} {
_forEachPerm {} $list $cmdPrefix
}
proc _forEachPerm {head list cmdPrefix} {
if {![llength $list]} {
{*}$cmdPrefix $head
} else {
for {set i 0} {$i < [llength $list]} {incr i} {
_forEachPerm [concat $head [lrange $list $i $i]] [lreplace $list $i $i] $cmdPrefix
}
}
}
# example use:
forEachPerm {a b c} {apply {{list} {puts [join $list]}}}
How do I write and apply a simple lambda function using the tcl 8.6 features "apply" and "lmap"?
map (lambda x -> x*x) [list 1 2 3]
how can I write the above in Tcl 8.6? The man pages are not that self explanatory for me.
Perhaps also a more advance version, but I guess I can figure that out myself:
lambda y -> map (lambda x -> x*x) y
Basically I would like to improve this version:
proc \x {f val} {
set res [apply $f $val]
set res
}
set res [\x {x {expr $x*$x}} 5]
puts "res: $res"
So that I can just write:
set res [\x {expr $x*$x} 5]
puts "res: $res"
Here's what lambda looks like:
proc lambda {arguments expression} {
list ::apply [list $arguments [list expr $expression]]
}
Then we do this, noting that {*} is required because the inner lambda term can't be a command directly without causing other trouble that we didn't want to have in 8.5 (or 8.6):
set res [lmap x [list 1 2 3] {
{*}[lambda x {$x * $x}] $x
}]
The 8.6 lmap is syntactically like foreach, so an extra layer of application is needed. It is, however, more easily understood by average Tcl programmers for being like that.
Note that the lambdas are fully first-class values that can be passed around however you want (put in variables, returned, stored in a list, whatever):
set square [lambda x {$x * $x}]
puts "the square of 42 is [{*}$square 42]"
(You could use λ for a command name if you wanted, but I find it awkward to type on this keyboard. I don't recommend using \x though; Tcl uses backslashes for various escaping duties.)