UNPKG

execution-engine

Version:

A TypeScript library for tracing and visualizing code execution workflows.

143 lines (142 loc) 6.96 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); const memoize_decorator_1 = require("./memoize.decorator"); describe('memoize decorator', () => { it('should memoize Fibonacci results and prevent redundant function calls', async () => { let memoizationCheckCount = 0; let memoizedCalls = 0; let totalFunctionCalls = 0; class Calculator { fibonacci(n) { totalFunctionCalls++; if (n <= 1) { return n; } return this.fibonacci(n - 1) + this.fibonacci(n - 2); } } __decorate([ (0, memoize_decorator_1.memoize)((memoContext) => { memoizationCheckCount++; if (memoContext.isMemoized) { memoizedCalls++; } }) ], Calculator.prototype, "fibonacci", null); const calculator = new Calculator(); memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; const fib3 = calculator.fibonacci(3); expect(memoizedCalls).toBe(0); expect(totalFunctionCalls).toBe(5); // fib(3) = (fib(2) = fib(1) + fib(0)) + fib(1) expect(memoizationCheckCount).toEqual(totalFunctionCalls + memoizedCalls); expect(fib3).toBe(2); memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; // first call: const fib50_1 = calculator.fibonacci(50); expect(memoizedCalls).toBeGreaterThan(0); expect(totalFunctionCalls).toBeLessThan(1274); // 1274 calls for fibonacci(50) if all exist expect(memoizationCheckCount).toEqual(totalFunctionCalls + memoizedCalls); expect(fib50_1).toBe(12586269025); const memoizedCallsAfterFirstCall = memoizedCalls; const totalFunctionCallsAfterFirstCall = totalFunctionCalls; // second call: const fib50_2 = calculator.fibonacci(50); expect(memoizedCalls).toBe(memoizedCallsAfterFirstCall + 1); // a new get of memoized fib50 expect(totalFunctionCalls).toBe(totalFunctionCallsAfterFirstCall); // no new call, fib50 is memoized expect(memoizationCheckCount).toEqual(totalFunctionCalls + memoizedCalls); expect(fib50_2).toBe(12586269025); memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; const fib51 = calculator.fibonacci(51); expect(totalFunctionCalls).toBe(1); // we need 1 extra call to get fibonacci of 51 as we did fibonacci(50) expect(memoizedCalls).toBe(2); // yes fib(51-1) and fib(51-2) are memoized expect(memoizationCheckCount).toBe(3); // 2memoized and 1 call expect(fib51).toBe(20365011074); memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; const fib5 = calculator.fibonacci(6); expect(totalFunctionCalls).toBe(0); // no need for extra call to get fibonacci of 5 as we did fibonacci(50) expect(memoizedCalls).toBe(1); // yes fib(5) is memoized implicitly expect(memoizationCheckCount).toBe(1); // 1memoized expect(fib5).toBe(8); }); it('should memoize async function results and prevent redundant calls', async () => { let memoizationCheckCount = 0; let memoizedCalls = 0; let totalFunctionCalls = 0; class DataService { async fetchData(id) { totalFunctionCalls++; return new Promise((resolve) => setTimeout(() => resolve(`Data for ID: ${id}`), 100)); } async throwData(name) { totalFunctionCalls++; throw new Error(`hello ${name} but I throw!`); } } __decorate([ (0, memoize_decorator_1.memoize)(async (memoContext) => { memoizationCheckCount++; if (memoContext.isMemoized) { memoizedCalls++; } }) ], DataService.prototype, "fetchData", null); __decorate([ (0, memoize_decorator_1.memoize)(async (memoContext) => { memoizationCheckCount++; if (memoContext.isMemoized) { memoizedCalls++; } }) ], DataService.prototype, "throwData", null); const service = new DataService(); memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; const result1 = await service.fetchData(1); expect(result1).toBe('Data for ID: 1'); expect(memoizedCalls).toBe(0); expect(totalFunctionCalls).toBe(1); expect(memoizationCheckCount).toBe(1); // Called once const result2 = await service.fetchData(1); expect(result2).toBe('Data for ID: 1'); expect(memoizedCalls).toBe(1); // Now it should be memoized expect(totalFunctionCalls).toBe(1); // No new calls expect(memoizationCheckCount).toBe(2); // Checked twice const result3 = await service.fetchData(2); expect(result3).toBe('Data for ID: 2'); expect(memoizedCalls).toBe(1); // No extra memoized calls yet expect(totalFunctionCalls).toBe(2); // New call for different ID expect(memoizationCheckCount).toBe(3); // Three checks (1st, 2nd for ID 1, and 3rd for ID 2) const result4 = await service.fetchData(2); expect(result4).toBe('Data for ID: 2'); expect(memoizedCalls).toBe(2); // ID 2 result is now memoized expect(totalFunctionCalls).toBe(2); // No extra new calls expect(memoizationCheckCount).toBe(4); // 4 checks in total // test memoize a throwing async method memoizationCheckCount = 0; memoizedCalls = 0; totalFunctionCalls = 0; await Promise.all([ expect(service.throwData('akram')).rejects.toThrow('hello akram but I throw!'), expect(service.throwData('akram')).rejects.toThrow('hello akram but I throw!'), expect(service.throwData('akram')).rejects.toThrow('hello akram but I throw!') ]); expect(memoizationCheckCount).toEqual(totalFunctionCalls + memoizedCalls); expect(memoizedCalls).toEqual(2); expect(totalFunctionCalls).toBe(1); // No extra new calls }); });