# -*- tcl -*- # Tests for the 'disjointset' module in the 'struct' library. -*- tcl -*- # # This file contains a collection of tests for one or more of the Tcllib # procedures. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2008 by Alejandro Eduardo Cruz Paz # Copyright (c) 2008 by Andreas Kupries (extended for API changes and # error conditions) # Copyright (c) 2018 by Kevin B. Kenny - reworked to a proper disjoint-sets # data structure, added 'add-element', 'exemplars' and 'find-exemplar'. # # RCS: @(#) $Id: disjointset.testsuite,v 1.1 2008/09/10 16:23:14 andreas_kupries Exp $ #---------------------------------------------------------------------- test disjointset-1.0 {disjointset creation} { ::struct::disjointset DS set result [djstate DS] DS destroy set result } {{} 0} test disjointset-1.1 {disjointset creation error} { catch {::struct::disjointset DS other} msg set result $msg } {wrong # args: should be "::struct::disjointset ?name?"} #---------------------------------------------------------------------- test disjointset-2.0 {disjointset add-partition error, wrong#args, missing} { ::struct::disjointset DS catch {DS add-partition} msg DS destroy set msg } [tcltest::wrongNumArgs "DS add-partition" {items} 1] test disjointset-2.1 {disjointset add-partition error, wrong#args, too many} { ::struct::disjointset DS catch {DS add-partition x y} msg DS destroy set msg } [tcltest::tooManyArgs "DS add-partition" {items}] test disjointset-2.2 {disjointset add-partition error, elements already known} { testset catch {DS add-partition {1}} msg DS destroy set msg } {The element "1" is already known to the disjoint set ::DS} test disjointset-2.3 {disjointset add-partition, ok} { testset set result [list [DS add-partition {11 14}] [djstate DS]] DS destroy set result } {{} {{0 {1 2 3 4} {5 6} {7 10} {8 9} {11 14}} 6}} #---------------------------------------------------------------------- test disjointset-3.0 {disjointset partitions error, wrong#args, too many} { ::struct::disjointset DS catch {DS partitions x} msg DS destroy set msg } [tcltest::tooManyArgs "DS partitions" {}] test disjointset-3.1 {disjointset partitions, ok} { testset set result [djstate DS] DS destroy set result } {{0 {1 2 3 4} {5 6} {7 10} {8 9}} 5} test disjointset-3.2 {disjointset partitions, empty} { ::struct::disjointset DS set result [DS partitions] DS destroy set result } {} #---------------------------------------------------------------------- test disjointset-4.0 {disjointset equal error, wrong#args, missing} { ::struct::disjointset DS catch {DS equal} msg DS destroy set msg } [tcltest::wrongNumArgs "DS equal" {a b} 1] test disjointset-4.1 {disjointset equal error, wrong#args, missing} { ::struct::disjointset DS catch {DS equal x} msg DS destroy set msg } [tcltest::wrongNumArgs "DS equal" {a b} 2] test disjointset-4.2 {disjointset equal error, wrong#args, too many} { ::struct::disjointset DS catch {DS equal x y z} msg DS destroy set msg } [tcltest::tooManyArgs "DS equal" {a b}] test disjointset-4.3 {disjointset equal error, unknown elements} { testset catch {DS equal x 1} msg DS destroy set msg } {The element "x" is not known to the disjoint set ::DS} test disjointset-4.4 {disjointset equal error, unknown elements} { testset catch {DS equal 1 x} msg DS destroy set msg } {The element "x" is not known to the disjoint set ::DS} test disjointset-4.5 {disjointset equal ok, unequal elements} { testset set res [DS equal 1 5] DS destroy set res } 0 test disjointset-4.6 {disjointset equal ok, equal elements} { testset set res [DS equal 4 1] DS destroy set res } 1 #---------------------------------------------------------------------- test disjointset-5.0 {disjointset merge error, wrong#args, missing} { ::struct::disjointset DS catch {DS merge} msg DS destroy set msg } [tcltest::wrongNumArgs "DS merge" {a b} 1] test disjointset-5.1 {disjointset merge error, wrong#args, missing} { ::struct::disjointset DS catch {DS merge x} msg DS destroy set msg } [tcltest::wrongNumArgs "DS merge" {a b} 2] test disjointset-5.2 {disjointset merge error, wrong#args, too many} { ::struct::disjointset DS catch {DS merge x y z} msg DS destroy set msg } [tcltest::tooManyArgs "DS merge" {a b}] test disjointset-5.3 {disjointset merge error, unknown elements} { testset catch {DS merge x 1} msg DS destroy set msg } {The element "x" is not known to the disjoint set ::DS} test disjointset-5.4 {disjointset merge error, unknown elements} { testset catch {DS merge 1 x} msg DS destroy set msg } {The element "x" is not known to the disjoint set ::DS} test disjointset-5.5 {disjointset merge ok, different partitions} { testset DS merge 1 5 set result [djstate DS] DS destroy set result } {{0 {1 2 3 4 5 6} {7 10} {8 9}} 4} test disjointset-5.6 {disjointset merge ok, same partition, no change} { testset DS merge 4 3 set result [djstate DS] DS destroy set result } {{0 {1 2 3 4} {5 6} {7 10} {8 9}} 5} #---------------------------------------------------------------------- test disjointset-6.0 {disjointset find error, wrong#args, missing} { ::struct::disjointset DS catch {DS find} msg DS destroy set msg } [tcltest::wrongNumArgs "DS find" {item} 1] test disjointset-6.1 {disjointset find error, wrong#args, too many} { ::struct::disjointset DS catch {DS find x y} msg DS destroy set msg } [tcltest::tooManyArgs "DS find" {item}] test disjointset-6.2 {disjointset find, unknown element} { testset set result [DS find 11] DS destroy set result } {} test disjointset-6.3 {disjointset find, known element} { testset set result [lsort -dict [DS find 3]] DS destroy set result } {1 2 3 4} #---------------------------------------------------------------------- test disjointset-7.0 {disjointset num-partitions error, wrong#args, too many} { ::struct::disjointset DS catch {DS num-partitions x} msg DS destroy set msg } [tcltest::tooManyArgs "DS num-partitions" {}] test disjointset-7.1 {disjointset num-partitions, ok} { testset set result [DS num-partitions] DS destroy set result } 5 #---------------------------------------------------------------------- test disjointset-8.0 {disjointset add-element error, wrongArgs, none} { ::struct::disjointset DS catch {DS add-element} msg DS destroy set msg } [tcltest::wrongNumArgs "DS add-element" {item} 1] test disjointset-8.1 {disjointset add-element error, wrongArgs, too many} { ::struct::disjointset DS catch {DS add-element p q} msg DS destroy set msg } [tcltest::tooManyArgs "DS add-element" {item}] test disjointset-8.2 {disjointset add-element error, duplicate element} { testset catch {DS add-element 0} message DS destroy set message } {The element "0" is already known to the disjoint set ::DS} test disjointset-8.3 {disjointset add-element ok} { testset DS add-element 11 set result [djstate DS] DS destroy set result } {{0 {1 2 3 4} {5 6} {7 10} {8 9} 11} 6} #---------------------------------------------------------------------- test disjointset-9.0 {disjointset find-exemplar error, wrongArgs, none} { ::struct::disjointset DS catch {DS find-exemplar} msg DS destroy set msg } [tcltest::wrongNumArgs "DS find-exemplar" {item} 1] test disjointset-9.1 {disjointset find-exemplar error, wrongArgs, too many} { ::struct::disjointset DS catch {DS find-exemplar p q} msg DS destroy set msg } [tcltest::tooManyArgs "DS find-exemplar" {item}] test disjointset-9.2 {disjointset find-exemplar error, not found} { testset catch {DS find-exemplar x} message DS destroy set message } {The element "x" is not known to the disjoint set ::DS} test disjointset-9.3 {disjointset find-exemplar ok} { testset set result [DS find-exemplar 3] DS destroy expr {$result in {1 2 3 4}} } {1} #---------------------------------------------------------------------- test disjointset-10.0 {disjointset exemplars error, wrong#args, too many} { ::struct::disjointset DS catch {DS exemplars x} msg DS destroy set msg } [tcltest::tooManyArgs "DS exemplars" {}] test disjointset-10.1 {disjointset exemplars, ok} { ::struct::disjointset DS DS add-element 0 set result [DS exemplars] DS destroy set result } 0 test disjointset-10.2 {disjointset exemplars, empty} { ::struct::disjointset DS set result [DS exemplars] DS destroy set result } {} #---------------------------------------------------------------------- test disjointset-11.0 {disjointset merge - larger randomized set of merges} { struct::disjointset DS foreach item {a b c d e f g h i j k l m n o p q r s t u v w x y z} { DS add-partition [list $item] } DS merge g a DS merge o n DS merge v o DS merge c w DS merge r h DS merge s y DS merge g i DS merge d f DS merge m q DS merge a z DS merge k e DS merge x k DS merge r s DS merge h m DS merge d l DS merge e a DS merge o t DS merge q p DS merge u c DS merge o a DS merge p j DS merge b l DS merge p c DS merge f e set result [lsort [lmap x [DS partitions] {lsort $x}]] DS destroy set result } {{a b d e f g i k l n o t v x z} {c h j m p q r s u w y}} test disjointset-11.1 {disjointset merge - larger randomized set of merges} { struct::disjointset DS foreach item {a b c d e f g h i j k l m n o p q r s t u v w x y z} { DS add-partition [list $item] } DS merge g a DS merge o n DS merge v o DS merge c w DS merge r h DS merge s y DS merge g i DS merge d f DS merge m q DS merge a z DS merge k e DS merge x k DS merge r s DS merge h m DS merge d l DS merge e a DS merge o t DS merge q p DS merge u c DS merge o a DS merge p j DS merge b l DS merge p c DS merge f e set result [DS exemplars] DS destroy set trouble {} if {[llength $result] ne 2} { append trouble "\nShould be two exemplars, found $result" } lassign $result e1 e2 set l1 {a b d e f g i k l n o t v x z} set l2 {c h j m p q r s u w y} if {!(($e1 in $l1) ^ ($e2 in $l1))} { append trouble "\nExactly one of $e1 and $e2\ should be in the first set" } if {!(($e1 in $l2) ^ ($e2 in $l2))} { append trouble "\nExactly one of $e1 and $e2\ should be in the second set" } set trouble } {}