UNPKG

7.55 kBtext/coffeescriptView Raw
1suite 'Operators', ->
2
3 # * Operators
4 # * Existential Operator (Binary)
5 # * Existential Operator (Unary)
6 # * Aliased Operators
7 # * [not] in/of
8 # * Chained Comparison
9
10 # TODO: sort these
11 # TODO: basic functionality of all binary and unary operators
12
13 test 'binary maths operators do not require spaces', ->
14 a = 1
15 b = -1
16 eq 1, a*-b
17 eq -1, a*b
18 eq 1, a/-b
19 eq -1, a/b
20
21 test 'operators should respect new lines as spaced', ->
22 a = 123 +
23 456
24 eq 579, a
25
26 b = "1#{2}3" +
27 '456'
28 eq '123456', b
29
30 test 'multiple operators should space themselves', ->
31 eq (+ +1), (- -1)
32
33 test 'bitwise operators', ->
34 eq 2, (10 & 3)
35 eq 11, (10 | 3)
36 eq 9, (10 ^ 3)
37 eq 80, (10 << 3)
38 eq 1, (10 >> 3)
39 eq 1, (10 >>> 3)
40 num = 10; eq 2, (num &= 3)
41 num = 10; eq 11, (num |= 3)
42 num = 10; eq 9, (num ^= 3)
43 num = 10; eq 80, (num <<= 3)
44 num = 10; eq 1, (num >>= 3)
45 num = 10; eq 1, (num >>>= 3)
46
47 test 'instanceof', ->
48 ok new String instanceof String
49 ok new Boolean instanceof Boolean
50
51 test 'not instanceof', ->
52 ok new Number not instanceof String
53 ok new Array not instanceof Boolean
54
55 test "use `::` operator on keywords `this` and `@`", ->
56 obj = prototype: prop: nonce = {}
57 eq nonce, (-> @::prop).call obj
58 eq nonce, (-> this::prop).call obj
59
60
61 suite 'Existential Operator (Binary)', ->
62
63 test "binary existential operator", ->
64 nonce = {}
65
66 b = a ? nonce
67 eq nonce, b
68
69 a = null
70 b = undefined
71 b = a ? nonce
72 eq nonce, b
73
74 a = false
75 b = a ? nonce
76 eq false, b
77
78 a = 0
79 b = a ? nonce
80 eq 0, b
81
82 test "binary existential operator conditionally evaluates second operand", ->
83 i = 1
84 func = -> i -= 1
85 result = func() ? func()
86 eq result, 0
87
88 test "binary existential operator with negative number", ->
89 a = null ? - 1
90 eq -1, a
91
92 test 'jashkenas/coffee-script#2026: exponentiation operator via `**`', ->
93 eq 27, 3 ** 3
94 # precedence
95 eq 55, 1 + 3 ** 3 * 2
96 # right associativity
97 eq 2, 2 ** 1 ** 3
98 eq 2 ** 8, 2 ** 2 ** 3
99 # compound assignment with exponentiation
100 a = 2
101 a **= 2
102 eq 4, a
103
104
105 suite 'Existential Operator (Unary)', ->
106
107 test "postfix existential operator", ->
108 ok (if nonexistent? then false else true)
109 defined = true
110 ok defined?
111 defined = false
112 ok defined?
113
114 test "postfix existential operator only evaluates its operand once", ->
115 semaphore = 0
116 fn = ->
117 ok false if semaphore
118 ++semaphore
119 ok(if fn()? then true else false)
120
121 test "negated postfix existential operator", ->
122 ok !nothing?.value
123
124 test "postfix existential operator on expressions", ->
125 eq true, (1 or 0)?, true
126
127
128 suite '`is`,`isnt`,`==`,`!=`', ->
129
130 test "`==` and `is` should be interchangeable", ->
131 a = b = 1
132 ok a is 1 and b == 1
133 ok a == b
134 ok a is b
135
136 test "`!=` and `isnt` should be interchangeable", ->
137 a = 0
138 b = 1
139 ok a isnt 1 and b != 0
140 ok a != b
141 ok a isnt b
142
143
144 suite '[not] in/of', ->
145 # - `in` should check if an array contains a value using `indexOf`
146 # - `of` should check if a property is defined on an object using `in`
147
148 test "in, of", ->
149 arr = [1]
150 ok 0 of arr
151 ok 1 in arr
152
153 test 'not in, not of', ->
154 arr = [1]
155 ok 1 not of arr
156 ok 0 not in arr
157
158 test "`in` should be able to operate on an array literal", ->
159 ok 2 in [0, 1, 2, 3]
160 ok 4 not in [0, 1, 2, 3]
161 arr = [0, 1, 2, 3]
162 ok 2 in arr
163 ok 4 not in arr
164 # should cache the value used to test the array
165 arr = [0]
166 val = 0
167 ok val++ in arr
168 ok val++ not in arr
169 val = 0
170 ok val++ of arr
171 ok val++ not of arr
172
173 test "`in` with cache and `__indexOf` should work in argument lists", ->
174 eq 1, [Object() in Array()].length
175
176 test "jashkenas/coffee-script#737: `in` should have higher precedence than logical operators", ->
177 eq 1, 1 in [1] and 1
178
179 test "jashkenas/coffee-script#768: `in` should preserve evaluation order", ->
180 share = 0
181 a = -> share++ if share is 0
182 b = -> share++ if share is 1
183 c = -> share++ if share is 2
184 ok a() not in [b(),c()]
185 eq 3, share
186
187 test "jashkenas/coffee-script#1099: empty array after `in` should compile to `false`", ->
188 eq 1, [5 in []].length
189 eq false, do -> return 0 in []
190
191 test "jashkenas/coffee-script#1354: optimized `in` checks should not happen when splats are present", ->
192 a = [6, 9]
193 eq 9 in [3, a...], true
194
195 test "jashkenas/coffee-script#1100: precedence in or-test compilation of `in`", ->
196 ok 0 in [1 and 0]
197 ok 0 in [1, 1 and 0]
198 ok not (0 in [1, 0 or 1])
199
200 test "jashkenas/coffee-script#1630: `in` should check `hasOwnProperty`", ->
201 ok undefined not in {length: 1}
202
203 #test "jashkenas/coffee-script#1714: lexer bug with raw range `for` followed by `in`", ->
204 # 0 for [1..2]
205 # ok not ('a' in ['b'])
206 #
207 # 0 for [1..2]; ok not ('a' in ['b'])
208 #
209 # 0 for [1..10] # comment ending
210 # ok not ('a' in ['b'])
211
212 test "jashkenas/coffee-script#1099: statically determined `not in []` reporting incorrect result", ->
213 ok 0 not in []
214
215
216 # Chained Comparison
217
218 test "chainable operators", ->
219 ok 100 > 10 > 1 > 0 > -1
220 ok -1 < 0 < 1 < 10 < 100
221
222 test "`is` and `isnt` may be chained", ->
223 ok true is not false is true is not false
224 ok 0 is 0 isnt 1 is 1
225
226 test "different comparison operators (`>`,`<`,`is`,etc.) may be combined", ->
227 ok 1 < 2 > 1
228 ok 10 < 20 > 2+3 is 5
229
230 test "some chainable operators can be negated by `unless`", ->
231 ok (true unless 0==10!=100)
232
233 test "operator precedence: `|` lower than `<`", ->
234 eq 1, 1 | 2 < 3 < 4
235
236 test "preserve references", ->
237 a = b = c = 1
238 # `a == b <= c` should become `a === b && b <= c`
239 # (this test does not seem to test for this)
240 ok a == b <= c
241
242 test "chained operations should evaluate each value only once", ->
243 a = 0
244 ok 1 > a++ < 1
245
246 #test "jashkenas/coffee-script#891: incorrect inversion of chained comparisons", ->
247 # ok (true unless 0 > 1 > 2)
248 # ok (true unless (NaN = 0/0) < 0/0 < NaN)
249
250 test "jashkenas/coffee-script#1234: Applying a splat to :: applies the splat to the wrong object", ->
251 nonce = {}
252 class C
253 method: -> @nonce
254 nonce: nonce
255
256 arr = []
257 eq nonce, C::method arr... # should be applied to `C::`
258
259 test "jashkenas/coffee-script#1102: String literal prevents line continuation", ->
260 eq "': '", '' +
261 "': '"
262
263 test "jashkenas/coffee-script#1703, ---x is invalid JS", ->
264 x = 2
265 eq (- --x), -1
266
267 #test "Regression with implicit calls against an indented assignment", ->
268 # eq 1, a =
269 # 1
270 # eq a, 1
271
272 test "jashkenas/coffee-script#2155: conditional assignment to a closure", ->
273 x = null
274 func = -> x ?= (-> if true then 'hi')
275 func()
276 eq x(), 'hi'
277
278 test "jashkenas/coffee-script#2197: Existential existential double trouble", ->
279 counter = 0
280 func = -> counter++
281 func()? ? 100
282 eq counter, 1
283
284 test "#85: operands of ExistsOp must be coerced to expressions", ->
285 f = ->
286 f (a ? a?.b())
287 f (a ? while 0 then)
288
289 test "#89: extends operator has side effects and should not be optimised away", ->
290 class A
291 class B
292 B extends A
293 ok new B instanceof A