| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  | describe("basic usage", () => { | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("using in normal for loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let isDisposed = false; | 
					
						
							|  |  |  |         let lastI = -1; | 
					
						
							|  |  |  |         for ( | 
					
						
							|  |  |  |             using x = { | 
					
						
							|  |  |  |                 i: 0, | 
					
						
							|  |  |  |                 tick() { | 
					
						
							|  |  |  |                     this.i++; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 done() { | 
					
						
							|  |  |  |                     return this.i === 3; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 [Symbol.dispose]() { | 
					
						
							|  |  |  |                     isDisposed = true; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             !x.done(); | 
					
						
							|  |  |  |             x.tick() | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |             expect(isDisposed).toBeFalse(); | 
					
						
							|  |  |  |             expect(x.i).toBeGreaterThan(lastI); | 
					
						
							|  |  |  |             lastI = x.i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(isDisposed).toBeTrue(); | 
					
						
							|  |  |  |         expect(lastI).toBe(2); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("using in normal for loop with expression body", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let isDisposed = false; | 
					
						
							|  |  |  |         let outerI = 0; | 
					
						
							|  |  |  |         for ( | 
					
						
							|  |  |  |             using x = { | 
					
						
							|  |  |  |                 i: 0, | 
					
						
							|  |  |  |                 tick() { | 
					
						
							|  |  |  |                     this.i++; | 
					
						
							|  |  |  |                     outerI++; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 done() { | 
					
						
							|  |  |  |                     return this.i === 3; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 [Symbol.dispose]() { | 
					
						
							|  |  |  |                     isDisposed = true; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             !x.done(); | 
					
						
							|  |  |  |             x.tick() | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |             expect(isDisposed).toBeFalse(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(isDisposed).toBeTrue(); | 
					
						
							|  |  |  |         expect(outerI).toBe(3); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("using in for of loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         const disposable = []; | 
					
						
							|  |  |  |         const values = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function createDisposable(value) { | 
					
						
							|  |  |  |             return { | 
					
						
							|  |  |  |                 value: value, | 
					
						
							|  |  |  |                 [Symbol.dispose]() { | 
					
						
							|  |  |  |                     expect(this.value).toBe(value); | 
					
						
							|  |  |  |                     disposable.push(value); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (using a of [createDisposable('a'), createDisposable('b'), createDisposable('c')]) { | 
					
						
							|  |  |  |             expect(disposable).toEqual(values); | 
					
						
							|  |  |  |             values.push(a.value); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(disposable).toEqual(['a', 'b', 'c']); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("using in for of loop with expression body", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let disposableCalls = 0; | 
					
						
							|  |  |  |         let i = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const obj = { | 
					
						
							|  |  |  |             [Symbol.dispose]() { | 
					
						
							|  |  |  |                 disposableCalls++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (using a of [obj, obj, obj]) | 
					
						
							|  |  |  |             expect(disposableCalls).toBe(i++); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(disposableCalls).toBe(3); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("can have multiple declaration in normal for loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let disposed = 0; | 
					
						
							|  |  |  |         const a = { | 
					
						
							|  |  |  |             [Symbol.dispose]() { | 
					
						
							|  |  |  |                 disposed++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(disposed).toBe(0); | 
					
						
							|  |  |  |         for (using b = a, c = a; false;) | 
					
						
							|  |  |  |             expect().fail(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(disposed).toBe(2); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("can have using in block in for loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         const disposed = []; | 
					
						
							|  |  |  |         const values = []; | 
					
						
							|  |  |  |         for (let i = 0; i < 3; i++) { | 
					
						
							|  |  |  |             using a = { | 
					
						
							|  |  |  |                 val: i, | 
					
						
							|  |  |  |                 [Symbol.dispose]() { | 
					
						
							|  |  |  |                     expect(i).toBe(this.val); | 
					
						
							|  |  |  |                     disposed.push(i); | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             expect(disposed).toEqual(values); | 
					
						
							|  |  |  |             values.push(i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(disposed).toEqual([0, 1, 2]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("can have using in block in for-in loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         const disposed = []; | 
					
						
							|  |  |  |         const values = []; | 
					
						
							|  |  |  |         for (const i in ['a', 'b', 'c']) { | 
					
						
							|  |  |  |             using a = { | 
					
						
							|  |  |  |                 val: i, | 
					
						
							|  |  |  |                 [Symbol.dispose]() { | 
					
						
							|  |  |  |                     expect(i).toBe(this.val); | 
					
						
							|  |  |  |                     disposed.push(i); | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             expect(disposed).toEqual(values); | 
					
						
							|  |  |  |             values.push(i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(disposed).toEqual(["0", "1", "2"]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("dispose is called even if throw in for of loop", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let disposableCalls = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const obj = { | 
					
						
							|  |  |  |             [Symbol.dispose]() { | 
					
						
							|  |  |  |                 expect() | 
					
						
							|  |  |  |                 disposableCalls++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             for (using a of [obj]) | 
					
						
							|  |  |  |                 throw new ExpectationError("Expected in for-of"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             expect().fail("Should have thrown"); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |             expect(e).toBeInstanceOf(ExpectationError); | 
					
						
							|  |  |  |             expect(e.message).toBe("Expected in for-of"); | 
					
						
							|  |  |  |             expect(disposableCalls).toBe(1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(disposableCalls).toBe(1); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe("using is still a valid variable in loops", () => { | 
					
						
							|  |  |  |     test("for loops var", () => { | 
					
						
							|  |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (var using = 1; using < 2; using++) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("for loops const", () => { | 
					
						
							|  |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (const using = 1; using < 2; ) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("for loops let", () => { | 
					
						
							|  |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (let using = 1; using < 2; using++) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("using in", () => { | 
					
						
							|  |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (using in [1]) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |             expect(using).toBe("0"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("using of", () => { | 
					
						
							|  |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (using of [1]) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |             expect(using).toBe(1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 15:14:05 -04:00
										 |  |  |     test.xfail("using using of", () => { | 
					
						
							| 
									
										
										
										
											2022-12-23 01:45:29 +01:00
										 |  |  |         let enteredLoop = false; | 
					
						
							|  |  |  |         for (using using of [null]) { | 
					
						
							|  |  |  |             enteredLoop = true; | 
					
						
							|  |  |  |             expect(using).toBeNull(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         expect(enteredLoop).toBeTrue(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe("syntax errors", () => { | 
					
						
							|  |  |  |     test("cannot have using as for loop body", () => { | 
					
						
							|  |  |  |         expect("for (;;) using a = {};").not.toEval(); | 
					
						
							|  |  |  |         expect("for (x in []) using a = {};").not.toEval(); | 
					
						
							|  |  |  |         expect("for (x of []) using a = {};").not.toEval(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("must have one declaration without initializer in for loop", () => { | 
					
						
							|  |  |  |         expect("for (using x = {} of []) {}").not.toEval(); | 
					
						
							|  |  |  |         expect("for (using x, y of []) {}").not.toEval(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test("cannot have using in for-in loop", () => { | 
					
						
							|  |  |  |         expect("for (using x in []) {}").not.toEval(); | 
					
						
							|  |  |  |         expect("for (using of in []) {}").not.toEval(); | 
					
						
							|  |  |  |         expect("for (using in of []) {}").not.toEval(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | }); |