#!/usr/bin/perl -w # -*- perl -*- # # $Id: $ # Translated by: Slaven Rezic # # Original copyright from tk/tests/canvas.test, version 1.23 from # tktoolkit CVS on sourceforge: # This file is a Tcl script to test out the procedures in tkCanvas.c, # which implements generic code for canvases. It is organized in the # standard fashion for Tcl tests. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # All rights reserved. # # RCS: @(#) $Id: canvas.test,v 1.23 2004/12/07 21:22:19 dgp Exp $ use strict; use FindBin; use lib $FindBin::RealBin; use Getopt::Long; use Tk; BEGIN { if (!eval q{ use Test::More; 1; }) { print "1..0 # skip: no Test::More module\n"; exit; } } use TkTest qw(is_float_pair); plan tests => 166; use_ok("Tk::Canvas"); my $verbose = 0; GetOptions("v" => \$verbose) or die "usage: $0 [-v]"; # XXX - This test file is woefully incomplete. At present, only a # few of the features are tested. my $mw = MainWindow->new; $mw->geometry("+10+10"); if ($^O eq 'darwin') { # Under some newer MacOSX versions it seems that there are # problems by creating and destroying widgets with different # widths. The canvas widget with requested -width 100 created # after the one with -width 60 will only be 60px wide. This is # probably some wm-related bug, but as we test here for canvas # features, we need to workaround this bug. This is just done with # a dummy frame, which just makes sure that the mainwindow width # is at least 100 pixels. $mw->Frame(-width => 100, -height => 1)->pack; } my $c = $mw->Canvas; isa_ok($c, "Tk::Canvas"); isa_ok($c, "Tk::Widget"); $c->pack; $c->update; sub deleteWindows () { eval { $_->destroy } for $mw->children; } use constant SKIP_CGET => 5; use constant SKIP_CONF => 6; use constant SKIP_ERROR => 7; use constant SKIP_RESTORE => 8; my @tests = ( ['-background', '#ff0000', '#ff0000', 'non-existent', 'unknown color name "non-existent"'], ['-bg', '#ff0000', '#ff0000', 'non-existent', 'unknown color name "non-existent"'], [qw(-bd 4 4 badValue), 'bad screen distance "badValue"'], [qw(-borderwidth 1.3 1 badValue), 'bad screen distance "badValue"'], [qw(-closeenough 24 24 bogus), q{'bogus' isn't numeric}], [qw(-confine true 1 silly), 'expected boolean value but got "silly"', 0,0,1,0], # probably auto-converted to some boolean value? [qw(-cursor arrow arrow badValue), 'bad cursor spec "badValue"'], [qw(-height 2.1 2 x42), 'bad screen distance "x42"'], [qw(-highlightbackground), '#112233', '#112233', 'ugly', 'unknown color name "ugly"'], [qw(-highlightcolor), '#110022', '#110022', 'bogus', 'unknown color name "bogus"'], [qw(-highlightthickness 18 18 badValue), 'bad screen distance "badValue"'], [qw(-insertbackground), '#110022', '#110022', 'bogus', 'unknown color name "bogus"'], [qw(-insertborderwidth 1.3 1 2.6x), 'bad screen distance "2.6x"'], [qw(-insertofftime 100 100 3.2), q{expected integer but got "3.2"}, 0,0,1,0], # probably auto-converted to integer? [qw(-insertontime 100 100 3.2), q{expected integer but got "3.2"}, 0,0,1,0], # probably auto-converted to integer? [qw(-insertwidth 1.3 1 6x), q{bad screen distance "6x"}], [qw(-relief groove groove 1.5), q{bad relief type "1.5": must be flat, groove, raised, ridge, solid, or sunken}], [qw(-selectbackground), '#110022', '#110022', 'bogus', q{unknown color name "bogus"}], [qw(-selectborderwidth 1.3 1 badValue), q{bad screen distance "badValue"}], [qw(-selectforeground), '#654321', '#654321', 'bogus', q{unknown color name "bogus"}], [qw(-takefocus), "any string", "any string", undef, undef], [qw(-width 402 402 xyz), q{bad screen distance "xyz"}], [qw(-xscrollcommand), q{Some command}, q{Some command}, undef, undef, 1], [qw(-yscrollcommand), q{Another command}, q{Another command}, undef, undef, 1], ); foreach my $test (@tests) { my $name = $test->[0]; $c->configure($name, $test->[1]); if (!$test->[SKIP_CGET]) { is($c->cget($name), $test->[2], "cget $name"); } if (!$test->[SKIP_CONF]) { is(($c->configure($name))[4], $c->cget($name), "Comparing configure and cget values for $name"); } if (defined $test->[4]) { if (!$test->[SKIP_ERROR]) { eval { $c->configure($name, $test->[3]) }; like($@, qr/$test->[4]/, "Expected error message for $name"); } } if (!$test->[SKIP_RESTORE]) { $c->configure($name, ($c->configure($name))[3]); } } eval { $c->configure(-gorp => "foo") }; like($@, qr{Bad option `-gorp'}, "configure throws error on bad option"); $c->create("rect",10,10,100,100); eval { $c->configure(-gorp => "foo") }; like($@, qr{Bad option `-gorp'}, "configure throws error on bad option"); eval { $c->destroy }; $c = $mw->Canvas(qw(-width 60 -height 40), -scrollregion => [qw(0 0 200 150)], -bd => 0, -highlightthickness => 0, )->pack; $c->update; { my $i = $c->createRectangle(10,10,100,100); eval { $c->bind($i, "") }; is($@, "", "bind method"); } { my $i = $c->create('rect',10,10,100,100); eval { $c->bind($i, "<") }; like($@, qr{no event type or button # or keysym}, "bind method with failure"); } { $c->configure(-xscrollincrement => 40, -yscrollincrement => 5); $c->xview('moveto', 0); $c->update; is_float_pair([$c->xview], [0, 0.3], "xview method"); $c->xview('scroll', 2, 'units'); $c->update; is_float_pair([$c->xview], [0.4, 0.7], "xview method after scroll"); } { # Tcl/Tk comment: # This test gives slightly different results on platforms such # as NetBSD. I don't know why... # Perl/Tk comment: # Everything's ok on a FreeBSD machine. $c->configure(-xscrollincrement => 0, -yscrollincrement => 5); $c->xviewMoveto(0.6); $c->update; is_float_pair([$c->xview], [0.6, 0.9], "xview method (2)"); $c->xviewScroll(2, 'units'); $c->update; is_float_pair([$c->xview], [0.66, 0.96], "xview method after scroll (2)"); } eval { $c->destroy }; $c = $mw->Canvas(qw(-width 60 -height 40), -scrollregion => [qw(0 0 200 80)], -borderwidth => 0, -highlightthickness => 0, )->pack; $c->update; { $c->configure(qw(-xscrollincrement 40 -yscrollincrement 5)); $c->yview('moveto', 0); $c->update; is_float_pair([$c->yview], [0, 0.5], "yview method"); $c->yview('scroll', 3, 'units'); $c->update; is_float_pair([$c->yview], [0.1875, 0.6875], "yview method after scroll"); } { $c->configure(qw(-xscrollincrement 40 -yscrollincrement 0)); $c->yviewMoveto(0); $c->update; is_float_pair([$c->yview], [0, 0.5], "yview method (2)"); $c->yviewScroll(2, 'units'); $c->update; is_float_pair([$c->yview], [0.1, 0.6], "yview method after scroll (2)"); } { eval { $c->destroy }; $c = $mw->Canvas(qw(-width 100 -height 50), -scrollregion => [qw(-200 -100 305 102)], -borderwidth => 2, -highlightthickness => 3, )->pack; $c->update; $c->configure(qw(-xscrollincrement 0 -yscrollincrement 0)); $c->xview('moveto', 0); $c->yview('moveto', 0); $c->update; is($c->canvasx(0), -205, "canvasx after scrolling to origin"); is($c->canvasy(0), -105, "canvasy after scrolling to origin"); } { $c->configure(qw(-xscrollincrement 20 -yscrollincrement 10)); my @x; for my $i (qw(.08 .10 .48 .50)) { $c->xviewMoveto($i); $c->update; push @x, $c->canvasx(0); } is_deeply(\@x, [-165, -145, 35, 55], "canvasx after multiple scroll"); } { $c->configure(qw(-xscrollincrement 20 -yscrollincrement 10)); my @x; for my $i (qw(.06 .08 .70 .72)) { $c->yviewMoveto($i); $c->update; push @x, $c->canvasy(0); } is_deeply(\@x, [-95, -85, 35, 45], "canvasy after multiple scroll"); } { $c->configure(qw(-xscrollincrement 20 -yscrollincrement 10)); $c->xview('moveto', 1.0); is($c->canvasx(0), 215); } { $c->configure(qw(-xscrollincrement 20 -yscrollincrement 10)); $c->yview(moveto => 1.0); is($c->canvasy(0), 55); } deleteWindows; { eval { $c->destroy } if Tk::Exists($c); # without existence test dumps SV contents ... $c = $mw->Canvas; $c->create(qw(arc -100 10 100 210 -start 10 -extent 50 -style arc -tags arc1)); is_deeply([$c->bbox("arc1")], [qw(48 21 100 94)], "BBox of arc"); $c->createArc(qw(100 10 300 210 -start 10 -extent 50 -style chord -tags arc2)); is_deeply([$c->bbox("arc2")], [qw(248 21 300 94)], "BBox of chord"); $c->create(qw(arc 300 10 500 210 -start 10 -extent 50 -style pieslice -tags arc3)); is_deeply([$c->bbox("arc3")], [qw(398 21 500 112)], "BBox of pieslice"); } { eval { $c->destroy } if Tk::Exists($c); # without existence test dumps SV contents ... $c = $mw->Canvas; # With Tk 8.0.4 the ids are now stored in a hash table. You # can use this test as a performance test with older versions # by changing the value of size. my $size = 15; for my $i (0 .. $size-1) { my $x = -10 + 3*$i; for(my $j = 0, my $y = -10; $j < 10; $j++, $y+=3) { $c->create('rect', "${x}c", "${y}c", ($x+2)."c", ($y+2)."c", qw(-outline black -fill blue -tags rect)); $c->create('text', ($x+1)."c", ($y+1)."c", -text => "$i,$j", qw(-anchor center -tags text)); } } # The actual bench mark - this code also exercises all the hash # table changes. my $time = Tk::timeofday(); foreach my $id ($c->find(withtag => "all")) { $c->lower($id); $c->raise($id); $c->find(withtag => $id); $c->bind('', $id, ''); $c->delete($id); } my $delta = Tk::timeofday() - $time; diag "Canvas creation and deletion test needed $delta s" if $verbose; } { eval { $c->destroy } if Tk::Exists($c); # without existence test dumps SV contents ... $c = $mw->Canvas; $c->create(qw(oval 20 20 40 40 -fill red -tag) , [qw(a b c d)]); $c->create(qw(oval 20 60 40 80 -fill yellow -tag), [qw(b a)]); $c->create(qw(oval 20 100 40 120 -fill green -tag), [qw(c b)]); $c->create(qw(oval 20 140 40 160 -fill blue -tag), [qw(b)]); $c->create(qw(oval 20 180 40 200 -fill bisque -tag), [qw(a d e)]); $c->create(qw(oval 20 220 40 240 -fill bisque -tag b)); $c->create(qw(oval 20 260 40 280 -fill bisque -tag), ['d', "tag with spaces"]); is_deeply([$c->find(withtag => q{!a})],[qw(3 4 6 7)], "Tag expressions"); is_deeply([$c->find(withtag => q{b&&c})],[qw(1 3)]); is_deeply([$c->find(withtag => q{b||c})],[qw(1 2 3 4 6)]); is_deeply([$c->find(withtag => q{a&&!b})],[qw(5)]); is_deeply([$c->find(withtag => q{!b&&!c})],[qw(5 7)]); is_deeply([$c->find(withtag => q{d&&a&&c&&b})],[qw(1)]); is_deeply([$c->find(withtag => q{b^a})],[qw(3 4 5 6)]); is_deeply([$c->find(withtag => q{(a&&!b)||(!a&&b)})],[qw(3 4 5 6)]); is_deeply([$c->find(withtag => q{ ( a && ! b ) || ( ! a && b ) })],[qw(3 4 5 6)]); is_deeply([$c->find(withtag => q{a&&!(c||d)})],[qw(2)]); is_deeply([$c->find(withtag => q{d&&"tag with spaces"})],[qw(7)], "Tag with spaces"); is_deeply([$c->find(withtag => q"tag with spaces")],[qw(7)]); } for my $testdef ( [q{&&c}, qr{Unexpected operator in tag search expression}], [q{!!c}, qr{Too many '!' in tag search expression}], [q{b||}, qr{Missing tag in tag search expression}], [q{b&&(c||)}, qr{Unexpected operator in tag search expression}], [q{d&&""}, qr{Null quoted tag string in tag search expression}], [q"d&&\"tag with spaces", qr{Missing endquote in tag search expression}], [q{a&&"tag with spaces"z}, qr{Invalid boolean operator in tag search expression}], [q{a&&b&c}, qr{Singleton '&' in tag search expression}], [q{a||b|c}, qr{Singleton '|' in tag search expression}], ) { my($tag_expr, $error_rx) = @$testdef; eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas; $c->create(qw(oval 20 20 40 40 -fill red -tag), [qw(a b c d)]); $c->create(qw(oval 20 260 40 280 -fill bisque -tag), ['d', "tag with spaces"]); eval { $c->find(withtag => $tag_expr) }; like($@, $error_rx, "Tag expression error ($tag_expr)"); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas; $c->create(qw(oval 20 20 40 40 -fill red -tag), [q{ strange tag(xxx&yyy|zzz) " && \" || ! ^ " }]); ok($c->find(withtag => q{ strange tag(xxx&yyy|zzz) " && \" || ! ^ " }), q{backward compatility - strange tags that are not expressions}); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas; $c->bind(q{a && b}, '' => sub {warn "Enter"}); $c->bind(q{a && b}, '' => sub {warn "Leave"}); pass(q{multple events bound to same tag expr}); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; # This would crash in 8.3.0 and 8.3.1 $c->create(qw(polygon 0 0 100 100 200 50), -fill => undef, qw(-stipple gray50 -outline black)); pass(q{canvas poly fill check, bug 5783}); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; $c->create(qw(poly 30 30 90 90 30 90 90 30)); ok($c->find(qw(over 40 40 45 45)), "rect region inc. edge; canvas poly overlap fill check, bug 226357"); ok($c->find(qw(over 60 40 60 40)), "top-center point"); ok(!$c->find(qw(over 0 0 0 0)), "not on poly"); { # The failure only occurs with the real X server, but not # with Xnest and Xvfb, and it seems to occur only on some # X server versions (maybe driver dependent?). An equivalent # wish8.4 program had the same problem. local $TODO; $TODO = "Failure observed under some conditions on Debian" if $^O eq 'linux'; ok($c->find(qw(over 60 60 60 60)), "center-point"); } ok(!$c->find(qw(over 45 50 45 50)), "outside poly"); $c->itemconfigure(1, -fill => "", -outline => "black"); ok($c->find(qw(over 40 40 45 45)), "rect region inc. edge"); ok($c->find(qw(over 60 40 60 40)), "top-center point"); ok(!$c->find(qw(over 0 0 0 0)), "not on poly"); ok($c->find(qw(over 60 60 60 60)), "center-point"); ok(!$c->find(qw(over 45 50 45 50)), "outside poly"); $c->itemconfigure(1, -width => 8); ok($c->find(qw(over 45 50 45 50)), "outside poly?"); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; my $qx = 1.+1.; # qx has type double and no string representation (in Tcl?) $c->scale('all', $qx, 0, 1., 1.); # qx has now type MMRep and no string representation (in Tcl?); is($qx, 2, q{canvas mm obj, patch SF-403327, 102471}); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; my $val = 10; $val++; # qx has type double and no string representation (in Tcl?) $c->scale('all', $val, 0, 1, 1); # qx has now type MMRep and no string representation (in Tcl?) $val++; is($val, 12, q{canvas mm obj, patch SF-403327, 102471}); } { my $x = ""; my $kill_canvas = sub { my $w = shift; $w->destroy; $w = $mw->Canvas(qw(-height 200 -width 200))->pack(qw(-fill both -expand yes)); $mw->idletasks; $w->create('rectangle', qw(80 80 120 120 -fill blue -tags blue)); # bind a button press to re-build the canvas $w->bind('blue', '' => sub { $x .= "ok" }); $w; }; $c = $kill_canvas->($c); # do this many times to improve chances of triggering the crash for my $i (0 .. 29) { $c->eventGenerate('<1>', qw(-x 100 -y 100)); $c->eventGenerate('', qw(-x 100 -y 100)); } is($x, "okokokokokokokokokokokokokokokokokokokokokokokokokokokokokok", q{canvas delete during event, SF bug-228024}); } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; eval { $c->scan }; like($@, qr{\Qwrong # args: should be ".canvas scan mark|dragto x y ?dragGain?"\E}, q{canvas scan SF bug 581560}); eval { $c->scan("bogus") }; like($@, qr{\Qwrong # args: should be ".canvas scan mark|dragto x y ?dragGain?"\E}, "canvas scan"); eval { $c->scan("mark") }; like($@, qr{\Qwrong # args: should be ".canvas scan mark|dragto x y ?dragGain?"\E}); $c->scan(qw(mark 10 10)); pass("correct canvas scan mark"); eval { $c->scan(qw(mark 10 10 5)) }; like($@, qr{wrong # args: should be ".canvas scan mark x y"}); $c->scan(qw(dragto 10 10 5)); pass("correct canvas scan dragto"); } { foreach my $type (qw{arc bitmap image line oval polygon rect text window}) { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; eval { $c->create($type) }; like($@, qr{wrong # args: should be ".canvas create $type coords \Q?arg arg ...?"\E}, "basic types check: $type requires coords"); eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; eval { $c->create($type, 0) }; like($@, qr{wrong # coordinates: expected}, "basic coords check: $type coords are paired"); } } { eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; my $id = $c->createArc(qw(0 10 20 30 -start 33)); is($c->itemcget($id, "-start"), 33, "arc coords check"); } { local $TODO = "Decide whether test failures are expected or not..."; eval { $c->destroy } if Tk::Exists($c); # without existence test may dump SV contents ... $c = $mw->Canvas->pack; my $id = $c->createLine(qw{0 0 1 1 2 2 3 3 4 4 5 5 6 6}); is($c->itemcget($id, '-smooth'), 0); foreach my $smoothtest ( ['yes', 'true'], [1, 'true'], ['bezier', 'true'], ['raw', 'raw'], ['r', 'raw'], ['b', 'b'] ) { my($smoother, $expected) = @$smoothtest; $c->itemconfigure($id, -smooth => $smoother); is($c->itemcget($id, '-smooth'), $expected, "smooth test"); } } __END__