builtin.attl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #!/usr/bin/env attl
  2. #
  3. # Tests for the builtins except the following:
  4. # if: if runs $1 if $0 is true, otherwise runs $2
  5. # fail: fail execution of a procedure
  6. # set: sets a variable
  7. # get: get the contents of a variable
  8. # ret: return from a procedure
  9. # return: return from a procedure
  10. # to: define a procedure
  11. # see basic.attl for tests for these builtins
  12. ## Test function
  13. # Performs a test case case and then passes the test if cond returns nonzero
  14. # Can also rescue failures.
  15. to test case cond {
  16. rescue {
  17. let res $1
  18. if [cond $res "fail"] {
  19. print "PASS rescue test $1: $2\n" $case $res
  20. return 0
  21. } else {
  22. print "FAIL rescue test $1: $2\n" $case $res
  23. return 0
  24. }
  25. return "$res"
  26. }
  27. let res [case]
  28. if [cond $res "return"] {
  29. print "PASS test $1: $2\n" $case $res
  30. } else {
  31. print "FAIL test $1: $2\n" $case $res
  32. }
  33. }
  34. ## Output
  35. # print: print to the environnment's current output writer
  36. print "PASS print"
  37. ## Help
  38. # explain: set the help for a procedure
  39. explain "PASS" "PASS help"
  40. # help: get help for a procedure
  41. help "PASS"
  42. ## Strings
  43. # sadd: returns a string with $2 appended to string $1
  44. test {sadd "PA" "SS"} {seq $1 "PASS"}
  45. # sget: gets a rune from a string by index
  46. test {sget "abµc" 2} {seq $1 181}
  47. # slen: returns the length of a string in runes
  48. test {slen "abµc"} {seq $1 4}
  49. # expand: interpolate strings from environment
  50. let e "PASS expand"
  51. print "$1\n" [expand "$e"]
  52. # Equality
  53. # seq: checks if [str $1] == [str $2]
  54. if [seq "7" 7] {
  55. print "PASS seq\n"
  56. }
  57. # ieq: checks if $1 == $2, where $1 and $2 must be Int
  58. if [ieq 7 7] {
  59. print "PASS ieq\n"
  60. }
  61. ## Integers
  62. # iadd: adds an Int to an Int
  63. test {iadd 3 4} {ieq $1 7}
  64. # isub: subtracts an Int from an Int
  65. test {isub 3 4} {ieq $1 -1}
  66. # imul: multiplies an Int by an Int
  67. test {imul 3 4} {ieq $1 12}
  68. # idiv: divides an Int by an Int
  69. test {idiv 12 4} {ieq $1 3}
  70. # idiv: divide an Int by 0 should give an error
  71. test {idiv 12 0} {seq $1 "division by 0"}
  72. # ilt: checks if $1 < $2, where $1 and $2 must be Int
  73. test {ilt 12 4} {ieq $1 0}
  74. # ilt: checks if $1 < $2, where $1 and $2 must be Int
  75. test {ilt 4 12} {ieq $1 -1}
  76. # igt: checks if $1 > $2, where $1 and $2 must be Int
  77. test {igt 12 4} {ieq $1 -1}
  78. # igt: checks if $1 > $2, where $1 and $2 must be Int
  79. test {igt 4 12} {ieq $1 0}
  80. # ile: checks if $1 <= $2, where $1 and $2 must be Int
  81. test {ile 12 4} {ieq $1 0}
  82. # ile: checks if $1 <= $2, where $1 and $2 must be Int
  83. test {ile 4 12} {ieq $1 -1}
  84. # ige: checks if $1 >= $2, where $1 and $2 must be Int
  85. test {ige 12 4} {ieq $1 -1}
  86. # ige: checks if $1 >= $2, where $1 and $2 must be Int
  87. test {ige 4 12} {ieq $1 0}
  88. let i 123
  89. # inc: increments the named integer $1 and returns it
  90. test {inc i} {ieq $i 124}
  91. set i 123
  92. # dec: decrements the named integer $1 and returns it
  93. test {dec i} {ieq $i 122}
  94. ## Booleans
  95. # bor: returns true if one of its arguments are true
  96. test {bor 0 0} {ieq $1 0}
  97. # bor: returns true if one of its arguments are true
  98. test {bor 0 -1} {ieq $1 -1}
  99. # bor: returns true if one of its arguments are true
  100. test {bor -1 0} {ieq $1 -1}
  101. # bor: returns true if one of its arguments are true
  102. test {bor -1 -1} {ieq $1 -1}
  103. # band: returns true if all of its arguments are true
  104. test {band 0 0} {ieq $1 0}
  105. # band: returns true if all of its arguments are true
  106. test {band 0 -1} {ieq $1 0}
  107. # band: returns true if all of its arguments are true
  108. test {band -1 0} {ieq $1 0}
  109. # band: returns true if all of its arguments are true
  110. test {band -1 -1} {ieq $1 -1}
  111. # bxor: returns true if its arguments are different
  112. test {bxor 0 0} {ieq $1 0}
  113. # bxor: returns true if its arguments are different
  114. test {bxor 0 -1} {ieq $1 -1}
  115. # bxor: returns true if its arguments are different
  116. test {bxor -1 0} {ieq $1 -1}
  117. # bxor: returns true if its arguments are different
  118. test {bxor -1 -1} {ieq $1 0}
  119. # bnot
  120. test {bnot -1 } {ieq $1 0}
  121. # bnot
  122. test {bnot 0 } {ieq $1 -1}
  123. ## Lists
  124. # list: creates a new array list
  125. let l [list 1 2 3]
  126. test {expand "$l"} {seq $1 "[list 1 2 3]"}
  127. # llen: returns the length of a list
  128. test {llen $l} {ieq $1 3}
  129. # lget: gets a value from a list by index
  130. test {lget $l 0} {ieq $1 1}
  131. # lget: gets a value from a list by index
  132. test {lget $l 1} {ieq $1 2}
  133. # lget: out of bounds
  134. test {lget $l 77} {seq $1 "index out of range"}
  135. # lget: out of bounds
  136. test {lget $l -1} {seq $1 "index out of range"}
  137. # lset: sets a value to a list by index and value
  138. lset $l 1 7
  139. test {lget $l 1} {ieq $1 7}
  140. # ladd: returns a list with $2 appended to List $1
  141. set l [ladd $l 99]
  142. test {lget $l 3} {seq $1 99}
  143. # leach: calls the block $4 for each entry in the list
  144. to leach_test l {
  145. let ksum 0
  146. let vsum 0
  147. let reps 0
  148. let l2 $l
  149. leach $l k v {
  150. inc reps
  151. set ksum [iadd $ksum $k] 2
  152. set vsum [iadd $vsum $v] 2
  153. # try to cause overflow, should not cause leach to change
  154. ladd $l2 77
  155. }
  156. return [list $ksum $vsum $reps]
  157. }
  158. test {leach_test $l} {set l $1; seq [str $l] "[list 6 110 4]"}
  159. ## Maps
  160. # map: creates a new hash map
  161. let m [map "key3" "value3"]
  162. test {expand "$m"} {seq $1 "[map key3 value3]"}
  163. # mget: gets a value from a map by key
  164. test {mget $m "key3"} {seq $1 "value3"}
  165. # mset: sets a value to a map by key and value
  166. mset $m "key1" "value1"
  167. mset $m "key2" "2"
  168. test {mget $m key2} {seq $1 "2"}
  169. test {mget $m key1} {seq $1 "value1"}
  170. # mkeys: returns all keys of a map as an unsorted list
  171. test {mkeys $m} {set k $1; ieq [llen $k] 3}
  172. # meach: calls the block $4 for each entry in the list
  173. to meach_test m {
  174. let ksum ""
  175. let vsum ""
  176. let reps 0
  177. meach $m k v {
  178. inc reps
  179. set ksum [sadd $ksum $k]
  180. set vsum [sadd $vsum [str $v]]
  181. # try to cause overflow, should not cause meach to change iterations
  182. mset $m $ksum $vsum
  183. }
  184. return $reps
  185. }
  186. test {meach_test $m} {set m $1; ieq $m 3}
  187. ## Conversions
  188. # str: converts $1 to String
  189. test {str 123} {seq $1 "123"}
  190. # int: converts $1 to Int
  191. test {int "-123"} {ieq $1 -123}
  192. test {int "banana"} {seq $1 "Value cannot be converted"}
  193. test {int "-123banana"} {ieq $1 -123}
  194. # val: gets the value of a value
  195. let vi 23
  196. # FIXME: val has a bug
  197. # test {val $vi} {ieq $1 23}
  198. ## Types
  199. # type: returns $1 converted to a type
  200. test {type Foo} {seq $1 "Foo"}
  201. # typeof: returns the type of $1 or Unknown if not known
  202. test {typeof 1} {seq $1 [type Int]}
  203. # typeof: String
  204. test {typeof "foo"} {seq $1 [type String]}
  205. # typeof: Word
  206. test {typeof FooWord} {seq $1 [type Word]}
  207. # teq: checks if $1 and $2 are exactly the same type"
  208. test {teq [type Foo] [type Foo]} {ieq $1 -1}
  209. ## Control statemnts
  210. let i 10
  211. # while: executes $2 while $1 returns true
  212. to while_test {
  213. while { igt $i 0 } {
  214. dec i
  215. }
  216. }
  217. test {while_test} {ieq $i 0}
  218. # switch: selects one of many cases
  219. to switch_test v {
  220. switch $v 0 {
  221. return 10
  222. } 1 {
  223. return 20
  224. } 2 {
  225. return 30
  226. } "3" {
  227. return 40
  228. } default {
  229. return 50
  230. }
  231. }
  232. test {switch_test 0} {ieq $1 10}
  233. test {switch_test 1} {ieq $1 20}
  234. test {switch_test 2} {ieq $1 30}
  235. test {switch_test "3"} {ieq $1 40}
  236. test {switch_test "not in case"} {ieq $1 50}