using-for-loops.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. describe("basic usage", () => {
  2. test.xfailIf(isBytecodeInterpreterEnabled(), "using in normal for loop", () => {
  3. let isDisposed = false;
  4. let lastI = -1;
  5. for (
  6. using x = {
  7. i: 0,
  8. tick() {
  9. this.i++;
  10. },
  11. done() {
  12. return this.i === 3;
  13. },
  14. [Symbol.dispose]() {
  15. isDisposed = true;
  16. },
  17. };
  18. !x.done();
  19. x.tick()
  20. ) {
  21. expect(isDisposed).toBeFalse();
  22. expect(x.i).toBeGreaterThan(lastI);
  23. lastI = x.i;
  24. }
  25. expect(isDisposed).toBeTrue();
  26. expect(lastI).toBe(2);
  27. });
  28. test.xfailIf(isBytecodeInterpreterEnabled(), "using in normal for loop with expression body", () => {
  29. let isDisposed = false;
  30. let outerI = 0;
  31. for (
  32. using x = {
  33. i: 0,
  34. tick() {
  35. this.i++;
  36. outerI++;
  37. },
  38. done() {
  39. return this.i === 3;
  40. },
  41. [Symbol.dispose]() {
  42. isDisposed = true;
  43. },
  44. };
  45. !x.done();
  46. x.tick()
  47. )
  48. expect(isDisposed).toBeFalse();
  49. expect(isDisposed).toBeTrue();
  50. expect(outerI).toBe(3);
  51. });
  52. test.xfailIf(isBytecodeInterpreterEnabled(), "using in for of loop", () => {
  53. const disposable = [];
  54. const values = [];
  55. function createDisposable(value) {
  56. return {
  57. value: value,
  58. [Symbol.dispose]() {
  59. expect(this.value).toBe(value);
  60. disposable.push(value);
  61. }
  62. };
  63. }
  64. for (using a of [createDisposable('a'), createDisposable('b'), createDisposable('c')]) {
  65. expect(disposable).toEqual(values);
  66. values.push(a.value);
  67. }
  68. expect(disposable).toEqual(['a', 'b', 'c']);
  69. });
  70. test.xfailIf(isBytecodeInterpreterEnabled(), "using in for of loop with expression body", () => {
  71. let disposableCalls = 0;
  72. let i = 0;
  73. const obj = {
  74. [Symbol.dispose]() {
  75. disposableCalls++;
  76. }
  77. };
  78. for (using a of [obj, obj, obj])
  79. expect(disposableCalls).toBe(i++);
  80. expect(disposableCalls).toBe(3);
  81. });
  82. test.xfailIf(isBytecodeInterpreterEnabled(), "can have multiple declaration in normal for loop", () => {
  83. let disposed = 0;
  84. const a = {
  85. [Symbol.dispose]() {
  86. disposed++;
  87. }
  88. }
  89. expect(disposed).toBe(0);
  90. for (using b = a, c = a; false;)
  91. expect().fail();
  92. expect(disposed).toBe(2);
  93. });
  94. test.xfailIf(isBytecodeInterpreterEnabled(), "can have using in block in for loop", () => {
  95. const disposed = [];
  96. const values = [];
  97. for (let i = 0; i < 3; i++) {
  98. using a = {
  99. val: i,
  100. [Symbol.dispose]() {
  101. expect(i).toBe(this.val);
  102. disposed.push(i);
  103. },
  104. };
  105. expect(disposed).toEqual(values);
  106. values.push(i);
  107. }
  108. expect(disposed).toEqual([0, 1, 2]);
  109. });
  110. test.xfailIf(isBytecodeInterpreterEnabled(), "can have using in block in for-in loop", () => {
  111. const disposed = [];
  112. const values = [];
  113. for (const i in ['a', 'b', 'c']) {
  114. using a = {
  115. val: i,
  116. [Symbol.dispose]() {
  117. expect(i).toBe(this.val);
  118. disposed.push(i);
  119. },
  120. };
  121. expect(disposed).toEqual(values);
  122. values.push(i);
  123. }
  124. expect(disposed).toEqual(["0", "1", "2"]);
  125. });
  126. test.xfailIf(isBytecodeInterpreterEnabled(), "dispose is called even if throw in for of loop", () => {
  127. let disposableCalls = 0;
  128. const obj = {
  129. [Symbol.dispose]() {
  130. expect()
  131. disposableCalls++;
  132. }
  133. };
  134. try {
  135. for (using a of [obj])
  136. throw new ExpectationError("Expected in for-of");
  137. expect().fail("Should have thrown");
  138. } catch (e) {
  139. expect(e).toBeInstanceOf(ExpectationError);
  140. expect(e.message).toBe("Expected in for-of");
  141. expect(disposableCalls).toBe(1);
  142. }
  143. expect(disposableCalls).toBe(1);
  144. });
  145. });
  146. describe("using is still a valid variable in loops", () => {
  147. test("for loops var", () => {
  148. let enteredLoop = false;
  149. for (var using = 1; using < 2; using++) {
  150. enteredLoop = true;
  151. }
  152. expect(enteredLoop).toBeTrue();
  153. });
  154. test("for loops const", () => {
  155. let enteredLoop = false;
  156. for (const using = 1; using < 2; ) {
  157. enteredLoop = true;
  158. break;
  159. }
  160. expect(enteredLoop).toBeTrue();
  161. });
  162. test("for loops let", () => {
  163. let enteredLoop = false;
  164. for (let using = 1; using < 2; using++) {
  165. enteredLoop = true;
  166. }
  167. expect(enteredLoop).toBeTrue();
  168. });
  169. test("using in", () => {
  170. let enteredLoop = false;
  171. for (using in [1]) {
  172. enteredLoop = true;
  173. expect(using).toBe("0");
  174. }
  175. expect(enteredLoop).toBeTrue();
  176. });
  177. test("using of", () => {
  178. let enteredLoop = false;
  179. for (using of [1]) {
  180. enteredLoop = true;
  181. expect(using).toBe(1);
  182. }
  183. expect(enteredLoop).toBeTrue();
  184. });
  185. test.xfailIf(isBytecodeInterpreterEnabled(), "using using of", () => {
  186. let enteredLoop = false;
  187. for (using using of [null]) {
  188. enteredLoop = true;
  189. expect(using).toBeNull();
  190. }
  191. expect(enteredLoop).toBeTrue();
  192. });
  193. });
  194. describe("syntax errors", () => {
  195. test("cannot have using as for loop body", () => {
  196. expect("for (;;) using a = {};").not.toEval();
  197. expect("for (x in []) using a = {};").not.toEval();
  198. expect("for (x of []) using a = {};").not.toEval();
  199. });
  200. test("must have one declaration without initializer in for loop", () => {
  201. expect("for (using x = {} of []) {}").not.toEval();
  202. expect("for (using x, y of []) {}").not.toEval();
  203. });
  204. test("cannot have using in for-in loop", () => {
  205. expect("for (using x in []) {}").not.toEval();
  206. expect("for (using of in []) {}").not.toEval();
  207. expect("for (using in of []) {}").not.toEval();
  208. });
  209. });