mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-26 09:22:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			352 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			352 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const noHoistLexTopLevel = false;
 | |
| let canCallNonHoisted = 0;
 | |
| 
 | |
| expect(basicHoistTopLevel()).toEqual("basicHoistTopLevel");
 | |
| 
 | |
| function basicHoistTopLevel() {
 | |
|     return "basicHoistTopLevel";
 | |
| }
 | |
| 
 | |
| expect(typeof noHoistLexTopLevel).toBe("boolean");
 | |
| expect(typeof hoistInBlockTopLevel).toBe("undefined");
 | |
| 
 | |
| {
 | |
|     expect(noHoistLexTopLevel()).toEqual("noHoistLexTopLevel");
 | |
|     ++canCallNonHoisted;
 | |
| 
 | |
|     expect(basicHoistTopLevel()).toEqual("basicHoistTopLevelInBlock");
 | |
|     ++canCallNonHoisted;
 | |
| 
 | |
|     expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
 | |
| 
 | |
|     function hoistInBlockTopLevel() {
 | |
|         return "hoistInBlockTopLevel";
 | |
|     }
 | |
| 
 | |
|     function noHoistLexTopLevel() {
 | |
|         return "noHoistLexTopLevel";
 | |
|     }
 | |
| 
 | |
|     function basicHoistTopLevel() {
 | |
|         return "basicHoistTopLevelInBlock";
 | |
|     }
 | |
| }
 | |
| 
 | |
| expect(canCallNonHoisted).toBe(2);
 | |
| 
 | |
| expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
 | |
| 
 | |
| {
 | |
|     {
 | |
|         expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
 | |
| 
 | |
|         function nestedBlocksTopLevel() {
 | |
|             return "nestedBlocksTopLevel";
 | |
|         }
 | |
|     }
 | |
|     expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
 | |
| }
 | |
| expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
 | |
| expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
 | |
| 
 | |
| expect(typeof hoistSecondOneTopLevel).toBe("undefined");
 | |
| {
 | |
|     expect(typeof hoistSecondOneTopLevel).toBe("undefined");
 | |
| 
 | |
|     {
 | |
|         expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
| 
 | |
|         function hoistSecondOneTopLevel() {
 | |
|             return "hoistFirstOneTopLevel";
 | |
|         }
 | |
| 
 | |
|         expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
| 
 | |
|         function hoistSecondOneTopLevel() {
 | |
|             return "hoistSecondOneTopLevel";
 | |
|         }
 | |
| 
 | |
|         expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
| 
 | |
|         {
 | |
|             expect(hoistSecondOneTopLevel()).toEqual("hoistThirdOneTopLevel");
 | |
| 
 | |
|             function hoistSecondOneTopLevel() {
 | |
|                 return "hoistThirdOneTopLevel";
 | |
|             }
 | |
| 
 | |
|             expect(hoistSecondOneTopLevel()).toEqual("hoistThirdOneTopLevel");
 | |
|         }
 | |
| 
 | |
|         expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
|     }
 | |
| 
 | |
|     expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
| }
 | |
| 
 | |
| expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
 | |
| 
 | |
| test("Non-strict function does hoist", () => {
 | |
|     const noHoistLexFunction = false;
 | |
|     let canCallNonHoisted = 0;
 | |
| 
 | |
|     expect(basicHoistFunction()).toEqual("basicHoistFunction");
 | |
| 
 | |
|     function basicHoistFunction() {
 | |
|         return "basicHoistFunction";
 | |
|     }
 | |
| 
 | |
|     expect(typeof noHoistLexFunction).toBe("boolean");
 | |
|     expect(typeof hoistInBlockFunction).toBe("undefined");
 | |
| 
 | |
|     {
 | |
|         expect(noHoistLexFunction()).toEqual("noHoistLexFunction");
 | |
|         ++canCallNonHoisted;
 | |
| 
 | |
|         expect(basicHoistFunction()).toEqual("basicHoistFunctionInBlock");
 | |
|         ++canCallNonHoisted;
 | |
| 
 | |
|         expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
 | |
| 
 | |
|         function hoistInBlockFunction() {
 | |
|             return "hoistInBlockFunction";
 | |
|         }
 | |
| 
 | |
|         function noHoistLexFunction() {
 | |
|             return "noHoistLexFunction";
 | |
|         }
 | |
| 
 | |
|         function basicHoistFunction() {
 | |
|             return "basicHoistFunctionInBlock";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     expect(canCallNonHoisted).toBe(2);
 | |
| 
 | |
|     expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
 | |
| 
 | |
|     {
 | |
|         {
 | |
|             expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
 | |
| 
 | |
|             function nestedBlocksFunction() {
 | |
|                 return "nestedBlocksFunction";
 | |
|             }
 | |
|         }
 | |
|         expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
 | |
|     }
 | |
|     expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
 | |
|     expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
 | |
| 
 | |
|     expect(typeof hoistSecondOneFunction).toBe("undefined");
 | |
|     {
 | |
|         expect(typeof hoistSecondOneFunction).toBe("undefined");
 | |
| 
 | |
|         {
 | |
|             expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
| 
 | |
|             function hoistSecondOneFunction() {
 | |
|                 return "hoistFirstOneFunction";
 | |
|             }
 | |
| 
 | |
|             expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
| 
 | |
|             function hoistSecondOneFunction() {
 | |
|                 return "hoistSecondOneFunction";
 | |
|             }
 | |
| 
 | |
|             expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
| 
 | |
|             {
 | |
|                 expect(hoistSecondOneFunction()).toEqual("hoistThirdOneFunction");
 | |
| 
 | |
|                 function hoistSecondOneFunction() {
 | |
|                     return "hoistThirdOneFunction";
 | |
|                 }
 | |
| 
 | |
|                 expect(hoistSecondOneFunction()).toEqual("hoistThirdOneFunction");
 | |
|             }
 | |
| 
 | |
|             expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
|         }
 | |
| 
 | |
|         expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
|     }
 | |
| 
 | |
|     expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
 | |
| 
 | |
|     expect(notBlockFunctionTopLevel()).toBe("second");
 | |
| 
 | |
|     function notBlockFunctionTopLevel() {
 | |
|         return "first";
 | |
|     }
 | |
| 
 | |
|     expect(notBlockFunctionTopLevel()).toBe("second");
 | |
| 
 | |
|     function notBlockFunctionTopLevel() {
 | |
|         return "second";
 | |
|     }
 | |
| 
 | |
|     expect(notBlockFunctionTopLevel()).toBe("second");
 | |
| });
 | |
| 
 | |
| test("Strict function does not hoist", () => {
 | |
|     "use strict";
 | |
| 
 | |
|     const noHoistLexStrictFunction = false;
 | |
|     let canCallNonHoisted = 0;
 | |
| 
 | |
|     expect(basicHoistStrictFunction()).toEqual("basicHoistStrictFunction");
 | |
| 
 | |
|     function basicHoistStrictFunction() {
 | |
|         return "basicHoistStrictFunction";
 | |
|     }
 | |
| 
 | |
|     expect(typeof noHoistLexStrictFunction).toBe("boolean");
 | |
|     // We cannot use expect(() => ).toThrow because that introduces extra scoping
 | |
|     try {
 | |
|         hoistInBlockStrictFunction;
 | |
|         expect().fail();
 | |
|     } catch (e) {
 | |
|         expect(e).toBeInstanceOf(ReferenceError);
 | |
|         expect(e.message).toEqual("'hoistInBlockStrictFunction' is not defined");
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         expect(noHoistLexStrictFunction()).toEqual("noHoistLexStrictFunction");
 | |
|         ++canCallNonHoisted;
 | |
| 
 | |
|         expect(basicHoistStrictFunction()).toEqual("basicHoistStrictFunctionInBlock");
 | |
|         ++canCallNonHoisted;
 | |
| 
 | |
|         expect(hoistInBlockStrictFunction()).toEqual("hoistInBlockStrictFunction");
 | |
| 
 | |
|         function hoistInBlockStrictFunction() {
 | |
|             return "hoistInBlockStrictFunction";
 | |
|         }
 | |
| 
 | |
|         function noHoistLexStrictFunction() {
 | |
|             return "noHoistLexStrictFunction";
 | |
|         }
 | |
| 
 | |
|         function basicHoistStrictFunction() {
 | |
|             return "basicHoistStrictFunctionInBlock";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     expect(canCallNonHoisted).toBe(2);
 | |
| 
 | |
|     try {
 | |
|         hoistInBlockStrictFunction;
 | |
|         expect().fail();
 | |
|     } catch (e) {
 | |
|         expect(e).toBeInstanceOf(ReferenceError);
 | |
|         expect(e.message).toEqual("'hoistInBlockStrictFunction' is not defined");
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         try {
 | |
|             nestedBlocksStrictFunction;
 | |
|             expect().fail();
 | |
|         } catch (e) {
 | |
|             expect(e).toBeInstanceOf(ReferenceError);
 | |
|             expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
 | |
|         }
 | |
| 
 | |
|         {
 | |
|             expect(nestedBlocksStrictFunction()).toEqual("nestedBlocksStrictFunction");
 | |
| 
 | |
|             function nestedBlocksStrictFunction() {
 | |
|                 return "nestedBlocksStrictFunction";
 | |
|             }
 | |
|         }
 | |
|         try {
 | |
|             nestedBlocksStrictFunction;
 | |
|             expect().fail();
 | |
|         } catch (e) {
 | |
|             expect(e).toBeInstanceOf(ReferenceError);
 | |
|             expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     try {
 | |
|         nestedBlocksStrictFunction;
 | |
|         expect().fail();
 | |
|     } catch (e) {
 | |
|         expect(e).toBeInstanceOf(ReferenceError);
 | |
|         expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
 | |
|     }
 | |
| 
 | |
|     expect(notBlockStrictFunctionTopLevel()).toBe("second");
 | |
| 
 | |
|     function notBlockStrictFunctionTopLevel() {
 | |
|         return "first";
 | |
|     }
 | |
| 
 | |
|     expect(notBlockStrictFunctionTopLevel()).toBe("second");
 | |
| 
 | |
|     function notBlockStrictFunctionTopLevel() {
 | |
|         return "second";
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         expect(notBlockStrictFunctionTopLevel()).toBe("third");
 | |
| 
 | |
|         function notBlockStrictFunctionTopLevel() {
 | |
|             return "third";
 | |
|         }
 | |
| 
 | |
|         expect(notBlockStrictFunctionTopLevel()).toBe("third");
 | |
|     }
 | |
| 
 | |
|     expect(notBlockStrictFunctionTopLevel()).toBe("second");
 | |
| 
 | |
|     // Inside a block inside a strict function gives a syntax error
 | |
|     let didNotRunEval = true;
 | |
|     expect(`
 | |
|         didNotRunEval = false;
 | |
|         () => {
 | |
|             "use strict";
 | |
| 
 | |
|             {
 | |
|                 function f() {
 | |
|                     return "first";
 | |
|                 }
 | |
| 
 | |
|                 function f() {
 | |
|                     return "second";
 | |
|                 }
 | |
|             }
 | |
|         };
 | |
|     `).not.toEval();
 | |
| 
 | |
|     expect(didNotRunEval).toBeTrue();
 | |
| 
 | |
|     // However, in eval it's fine but the function does not escape the eval
 | |
|     {
 | |
|         let ranEval = false;
 | |
|         eval(`
 | |
|             expect(hoistSecondOneStrictFunction()).toBe("hoistSecondOneStrictFunction");
 | |
| 
 | |
|             function hoistSecondOneStrictFunction() {
 | |
|                 return "hoistFirstOneStrictFunction";
 | |
|             }
 | |
| 
 | |
|             function hoistSecondOneStrictFunction() {
 | |
|                 return "hoistSecondOneStrictFunction";
 | |
|             }
 | |
| 
 | |
|             ranEval = true;
 | |
|             `);
 | |
| 
 | |
|         expect(ranEval).toBeTrue();
 | |
| 
 | |
|         try {
 | |
|             hoistSecondOneStrictFunction;
 | |
|             expect().fail();
 | |
|         } catch (e) {
 | |
|             expect(e).toBeInstanceOf(ReferenceError);
 | |
|             expect(e.message).toEqual("'hoistSecondOneStrictFunction' is not defined");
 | |
|         }
 | |
|     }
 | |
| });
 | 
