Best JavaScript code snippet using fast-check-monorepo
Arbitrary.utest.spec.ts
Source:Arbitrary.utest.spec.ts  
1import { Arbitrary } from '../../../../../src/check/arbitrary/definition/Arbitrary';2import { Value } from '../../../../../src/check/arbitrary/definition/Value';3import { Stream } from '../../../../../src/stream/Stream';4import * as stubRng from '../../../stubs/generators';5import { cloneMethod, hasCloneMethod } from '../../../../../src/check/symbols';6import { Random } from '../../../../../src/random/generator/Random';7const mrngNoCall = stubRng.mutable.nocall();8describe('NextArbitrary', () => {9  describe('filter', () => {10    it('should filter the values produced by the original arbitrary on generate', () => {11      // Arrange12      const expectedBiasFactor = 48;13      const generate = jest.fn();14      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;15      const shrink = jest.fn();16      const choice1 = new Value(1, Symbol());17      const choice2 = new Value(2, Symbol());18      const choice3 = new Value(3, Symbol());19      const choice4 = new Value(4, Symbol());20      generate21        .mockReturnValueOnce(choice1)22        .mockReturnValueOnce(choice2)23        .mockReturnValueOnce(choice3)24        .mockReturnValueOnce(choice4);25      class MyNextArbitrary extends Arbitrary<any> {26        generate = generate;27        canShrinkWithoutContext = canShrinkWithoutContext;28        shrink = shrink;29      }30      // Act31      const arb = new MyNextArbitrary().filter((v) => v % 3 === 0);32      const g = arb.generate(mrngNoCall, expectedBiasFactor);33      // Assert34      expect(g).toBe(choice3); // just returning the first Value that fits35      expect(generate).toHaveBeenNthCalledWith(3, mrngNoCall, expectedBiasFactor); // same Random not cloned36    });37    it('should filter the values produced by the original arbitrary on shrink', () => {38      // Arrange39      const generate = jest.fn();40      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;41      const shrink = jest.fn();42      const valueToShrink = 5;43      const contextToShrink = Symbol();44      const choice1 = new Value(1, Symbol());45      const choice2 = new Value(2, Symbol());46      const choice3 = new Value(3, Symbol());47      const choice4 = new Value(4, Symbol());48      const choice5 = new Value(6, Symbol());49      shrink.mockReturnValueOnce(Stream.of(choice1, choice2, choice3, choice4, choice5));50      class MyNextArbitrary extends Arbitrary<any> {51        generate = generate;52        canShrinkWithoutContext = canShrinkWithoutContext;53        shrink = shrink;54      }55      // Act56      const arb = new MyNextArbitrary().filter((v) => v % 3 === 0);57      const shrinks = arb.shrink(valueToShrink, contextToShrink);58      // Assert59      expect([...shrinks]).toEqual([choice3, choice5]); // just keeping values fitting the predicate60      expect(shrink).toHaveBeenCalledWith(valueToShrink, contextToShrink);61    });62    it.each`63      canShrinkWithoutContextOutput | predicateOutput | expected64      ${false}                      | ${false}        | ${false}65      ${false}                      | ${true}         | ${false}66      ${false}                      | ${false}        | ${false}67      ${true}                       | ${true}         | ${true}68    `(69      'should check underlying arbitrary then predicate to know if the value could have been generated',70      ({ canShrinkWithoutContextOutput, predicateOutput, expected }) => {71        // Arrange72        const requestedValue = Symbol();73        const generate = jest.fn();74        const canShrinkWithoutContext = jest.fn();75        const shrink = jest.fn();76        const predicate = jest.fn();77        class MyNextArbitrary extends Arbitrary<any> {78          generate = generate;79          canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;80          shrink = shrink;81        }82        canShrinkWithoutContext.mockReturnValueOnce(canShrinkWithoutContextOutput);83        predicate.mockReturnValueOnce(predicateOutput);84        // Act85        const arb = new MyNextArbitrary().filter(predicate);86        const out = arb.canShrinkWithoutContext(requestedValue);87        // Assert88        expect(out).toBe(expected);89        expect(canShrinkWithoutContext).toHaveBeenCalledWith(requestedValue);90        if (canShrinkWithoutContextOutput) {91          expect(predicate).toHaveBeenCalledWith(requestedValue);92        } else {93          expect(predicate).not.toHaveBeenCalledWith(requestedValue);94          expect(predicate).not.toHaveBeenCalled();95        }96      }97    );98  });99  describe('map', () => {100    it('should map the values produced by the original arbitrary on generate', () => {101      // Arrange102      const expectedBiasFactor = 48;103      const generate = jest.fn();104      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;105      const shrink = jest.fn();106      const choice = new Value(1, Symbol());107      generate.mockReturnValueOnce(choice);108      class MyNextArbitrary extends Arbitrary<any> {109        generate = generate;110        canShrinkWithoutContext = canShrinkWithoutContext;111        shrink = shrink;112      }113      // Act114      const arb = new MyNextArbitrary().map((v) => String(v));115      const g = arb.generate(mrngNoCall, expectedBiasFactor);116      // Assert117      expect(g.value).toBe(String(choice.value)); // value has been mapped118      expect(generate).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor);119    });120    it('should preserve cloneable capabilities for mapped values on generate', () => {121      // Arrange122      const expectedBiasFactor = 48;123      const generate = jest.fn();124      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;125      const shrink = jest.fn();126      const choice = new Value({ source: 1, [cloneMethod]: () => choice.value_ }, Symbol());127      generate.mockReturnValueOnce(choice);128      class MyNextArbitrary extends Arbitrary<any> {129        generate = generate;130        canShrinkWithoutContext = canShrinkWithoutContext;131        shrink = shrink;132      }133      // Act134      const arb = new MyNextArbitrary().map((v) => ({ stringValue: String(v.source) }));135      const g = arb.generate(mrngNoCall, expectedBiasFactor);136      // Assert137      expect(g.value.stringValue).toBe(String(choice.value.source)); // value has been mapped138      expect(g.hasToBeCloned).toBe(true); // clone has been preserved on Value139      expect(hasCloneMethod(g.value)).toBe(true); // clone has been preserved on the instance140      expect(generate).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor);141    });142    it('should not alter the mapped value if already cloneable on generate', () => {143      // Arrange144      const expectedBiasFactor = 48;145      const generate = jest.fn();146      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;147      const shrink = jest.fn();148      const choice = new Value({ source: 1, [cloneMethod]: () => choice.value_ }, Symbol());149      const mappedClone = jest.fn();150      const mapped = { source: 42, [cloneMethod]: mappedClone };151      generate.mockReturnValueOnce(choice);152      class MyNextArbitrary extends Arbitrary<any> {153        generate = generate;154        canShrinkWithoutContext = canShrinkWithoutContext;155        shrink = shrink;156      }157      // Act158      const arb = new MyNextArbitrary().map((_v) => mapped); // mapped already comes with clone capacities159      const g = arb.generate(mrngNoCall, expectedBiasFactor);160      // Assert161      expect(g.value_).toBe(mapped); // value has been mapped162      expect(g.value_.source).toBe(mapped.source); // value has been mapped and value not altered163      expect(g.value_[cloneMethod]).toBe(mapped[cloneMethod]); // value has been mapped and clone method has been preserved164      expect(g.hasToBeCloned).toBe(true); // clone has been preserved on Value165      expect(hasCloneMethod(g.value_)).toBe(true); // clone has been preserved on the instance166      expect(generate).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor);167    });168    it('should properly shrink output of generate by calling back shrink with the right context', () => {169      // Arrange170      const expectedBiasFactor = 42;171      const generate = jest.fn();172      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;173      const shrink = jest.fn();174      const source = new Value(69, Symbol());175      generate.mockReturnValueOnce(source);176      const choice1 = new Value(1, Symbol());177      const choice2 = new Value(2, Symbol());178      const choice3 = new Value(3, Symbol());179      shrink.mockReturnValueOnce(Stream.of(choice1, choice2, choice3));180      class MyNextArbitrary extends Arbitrary<any> {181        generate = generate;182        canShrinkWithoutContext = canShrinkWithoutContext;183        shrink = shrink;184      }185      // Act186      const arb = new MyNextArbitrary().map((v) => String(v));187      const g = arb.generate(mrngNoCall, expectedBiasFactor);188      const shrinks = arb.shrink(g.value, g.context);189      // Assert190      expect([...shrinks].map((s) => s.value)).toEqual(['1', '2', '3']); // just mapping values191      expect(shrink).toHaveBeenCalledWith(source.value, source.context);192    });193    it('should properly shrink output of shrink by calling back shrink with the right context', () => {194      // Arrange195      const expectedBiasFactor = 42;196      const generate = jest.fn();197      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;198      const shrink = jest.fn();199      const source = new Value(69, Symbol());200      generate.mockReturnValueOnce(source);201      const choice1 = new Value(1, Symbol());202      const choice2 = new Value(2, Symbol());203      const choice3 = new Value(3, Symbol());204      shrink.mockReturnValueOnce(Stream.of(choice1, choice2, choice3));205      const choice21 = new Value(21, Symbol());206      const choice22 = new Value(22, Symbol());207      shrink.mockReturnValueOnce(Stream.of(choice21, choice22));208      class MyNextArbitrary extends Arbitrary<any> {209        generate = generate;210        canShrinkWithoutContext = canShrinkWithoutContext;211        shrink = shrink;212      }213      // Act214      const arb = new MyNextArbitrary().map((v) => String(v));215      const g = arb.generate(mrngNoCall, expectedBiasFactor);216      const shrinksGen1 = arb.shrink(g.value, g.context);217      const mappedChoice2 = shrinksGen1.getNthOrLast(1)!;218      const shrinksGen2 = arb.shrink(mappedChoice2.value, mappedChoice2.context);219      // Assert220      expect([...shrinksGen2].map((s) => s.value)).toEqual(['21', '22']); // just mapping values221      expect(shrink).toHaveBeenCalledWith(source.value, source.context);222      expect(shrink).toHaveBeenCalledWith(choice2.value, choice2.context);223    });224    it('should preserve cloneable capabilities for mapped values on shrink', () => {225      // Arrange226      const expectedBiasFactor = 48;227      const generate = jest.fn();228      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;229      const shrink = jest.fn();230      const source = new Value({ source: 1, [cloneMethod]: () => source.value_ }, Symbol());231      generate.mockReturnValueOnce(source);232      const choice1 = new Value({ source: 2, [cloneMethod]: () => choice1.value_ }, Symbol());233      const choice2 = new Value({ source: 2, [cloneMethod]: () => choice2.value_ }, Symbol());234      shrink.mockReturnValueOnce(Stream.of(choice1, choice2));235      class MyNextArbitrary extends Arbitrary<any> {236        generate = generate;237        canShrinkWithoutContext = canShrinkWithoutContext;238        shrink = shrink;239      }240      // Act241      const arb = new MyNextArbitrary().map((v) => ({ stringValue: String(v.source) }));242      const g = arb.generate(mrngNoCall, expectedBiasFactor);243      const shrinks = arb.shrink(g.value, g.context);244      const shrinksValues = [...shrinks];245      // Assert246      expect(shrinksValues).toHaveLength(2);247      expect(shrinksValues[0].hasToBeCloned).toBe(true); // clone has been preserved on Value248      expect(shrinksValues[1].hasToBeCloned).toBe(true);249      expect(hasCloneMethod(shrinksValues[0].value)).toBe(true); // clone has been preserved on the instance250      expect(hasCloneMethod(shrinksValues[1].value)).toBe(true);251    });252    it('should always return false for canShrinkWithoutContext when not provided any unmapper function', () => {253      // Arrange254      const generate = jest.fn();255      const canShrinkWithoutContext = jest.fn();256      const shrink = jest.fn();257      class MyNextArbitrary extends Arbitrary<any> {258        generate = generate;259        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;260        shrink = shrink;261      }262      // Act263      const arb = new MyNextArbitrary().map(() => '');264      const out = arb.canShrinkWithoutContext('');265      // Assert266      expect(out).toBe(false);267      expect(canShrinkWithoutContext).not.toHaveBeenCalled();268    });269    it('should return empty stream when shrinking without any context and not provided any unmapper function', () => {270      // Arrange271      const generate = jest.fn();272      const canShrinkWithoutContext = jest.fn();273      const shrink = jest.fn();274      class MyNextArbitrary extends Arbitrary<any> {275        generate = generate;276        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;277        shrink = shrink;278      }279      // Act280      const arb = new MyNextArbitrary().map(() => '');281      const shrinks = arb.shrink('', undefined);282      // Assert283      expect([...shrinks]).toHaveLength(0);284      expect(shrink).not.toHaveBeenCalled();285      expect(canShrinkWithoutContext).not.toHaveBeenCalled();286    });287    it.each`288      outputCanGenerate289      ${false}290      ${true}291    `(292      'should try to unmap the value then call source arbitrary on canShrinkWithoutContext when provided a successful unmapper function',293      ({ outputCanGenerate }) => {294        // Arrange295        const generate = jest.fn();296        const canShrinkWithoutContext = jest.fn().mockReturnValue(outputCanGenerate);297        const shrink = jest.fn();298        const originalValue = Symbol();299        const unmapperOutput = Symbol();300        const unmapper = jest.fn().mockReturnValue(unmapperOutput);301        class MyNextArbitrary extends Arbitrary<any> {302          generate = generate;303          canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;304          shrink = shrink;305        }306        // Act307        const arb = new MyNextArbitrary().map(() => Symbol(), unmapper);308        const out = arb.canShrinkWithoutContext(originalValue);309        // Assert310        expect(out).toBe(outputCanGenerate);311        expect(unmapper).toHaveBeenCalledTimes(1);312        expect(unmapper).toHaveBeenCalledWith(originalValue);313        expect(canShrinkWithoutContext).toHaveBeenCalledTimes(1);314        expect(canShrinkWithoutContext).toHaveBeenCalledWith(unmapperOutput);315      }316    );317    it('should try to unmap the value and stop on error in case of failing unmapper function', () => {318      // Arrange319      const generate = jest.fn();320      const canShrinkWithoutContext = jest.fn();321      const shrink = jest.fn();322      const originalValue = Symbol();323      const unmapper = jest.fn().mockImplementation(() => {324        throw new Error('Unable to unmap such value');325      });326      class MyNextArbitrary extends Arbitrary<any> {327        generate = generate;328        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;329        shrink = shrink;330      }331      // Act332      const arb = new MyNextArbitrary().map(() => Symbol(), unmapper);333      const out = arb.canShrinkWithoutContext(originalValue);334      // Assert335      expect(out).toBe(false);336      expect(unmapper).toHaveBeenCalledTimes(1);337      expect(unmapper).toHaveBeenCalledWith(originalValue);338      expect(canShrinkWithoutContext).not.toHaveBeenCalled();339    });340    it('should return a mapped version of the stream produced by the source arbitrary for the unmapped value when provided an unmapper function', () => {341      // Arrange342      const expectedStreamValuesFromSource = Stream.of(343        new Value('titi', undefined),344        new Value('toto', undefined),345        new Value('tutu', undefined)346      );347      const generate = jest.fn();348      const canShrinkWithoutContext = jest.fn();349      const shrink = jest.fn().mockReturnValueOnce(expectedStreamValuesFromSource);350      const originalValue = Symbol();351      const unmapperOutput = 'tata';352      const unmapper = jest.fn().mockReturnValue('tata');353      class MyNextArbitrary extends Arbitrary<any> {354        generate = generate;355        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;356        shrink = shrink;357      }358      // Act359      const arb = new MyNextArbitrary().map((tag) => Symbol.for(tag), unmapper);360      const shrinks = [...arb.shrink(originalValue, undefined)];361      // Assert362      expect(shrinks.map((s) => s.value)).toEqual([Symbol.for('titi'), Symbol.for('toto'), Symbol.for('tutu')]);363      expect(unmapper).toHaveBeenCalledTimes(1);364      expect(unmapper).toHaveBeenCalledWith(originalValue);365      expect(shrink).toHaveBeenCalledTimes(1);366      expect(shrink).toHaveBeenCalledWith(unmapperOutput, undefined);367    });368  });369  describe('chain', () => {370    it('should chain the values produced by the original arbitrary on generate', () => {371      // Arrange372      const expectedBiasFactor = 48;373      const generate = jest.fn();374      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;375      const shrink = jest.fn();376      const choiceRoot = new Value(1, Symbol());377      generate.mockReturnValueOnce(choiceRoot);378      const generateChained = jest.fn();379      const canShrinkWithoutContextChained = jest.fn() as any as (value: unknown) => value is any;380      const shrinkChained = jest.fn();381      const choiceChained = new Value(50, Symbol());382      generateChained.mockReturnValueOnce(choiceChained);383      class MyNextArbitrary extends Arbitrary<any> {384        generate = generate;385        canShrinkWithoutContext = canShrinkWithoutContext;386        shrink = shrink;387      }388      class MyNextChainedArbitrary extends Arbitrary<any> {389        generate = generateChained;390        canShrinkWithoutContext = canShrinkWithoutContextChained;391        shrink = shrinkChained;392      }393      const chainer = jest.fn();394      chainer.mockReturnValueOnce(new MyNextChainedArbitrary());395      // Act396      const arb = new MyNextArbitrary().chain(chainer);397      const g = arb.generate(mrngNoCall, expectedBiasFactor);398      // Assert399      expect(g.value).toBe(choiceChained.value); // value has been chained400      expect(generate).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor); // the two calls to generate401      expect(generateChained).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor); // they share the same Random402      expect(chainer).toHaveBeenCalledWith(choiceRoot.value); // chainer was called with output of generate403    });404    it('should properly shrink output of generate by calling back shrink with the right context', () => {405      // Arrange406      const expectedBiasFactor = 48;407      const generate = jest.fn();408      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;409      const shrink = jest.fn();410      const choiceRoot = new Value(1, Symbol());411      generate.mockReturnValueOnce(choiceRoot);412      const shrinkRoot1 = new Value(10, Symbol());413      const shrinkRoot2 = new Value(11, Symbol());414      const shrinkRoot3 = new Value(15, Symbol());415      shrink.mockReturnValueOnce(Stream.of(shrinkRoot1, shrinkRoot2, shrinkRoot3));416      const generateChained = jest.fn();417      const canShrinkWithoutContextChained = jest.fn() as any as (value: unknown) => value is any;418      const shrinkChained = jest.fn();419      const choiceChained = new Value(50, Symbol());420      const choiceShrink1Chained = new Value(58, Symbol()); // chain will be called for each sub-shrink of root421      const choiceShrink2Chained = new Value(57, Symbol());422      const choiceShrink3Chained = new Value(16, Symbol());423      generateChained424        .mockReturnValueOnce(choiceChained)425        .mockReturnValueOnce(choiceShrink1Chained)426        .mockReturnValueOnce(choiceShrink2Chained)427        .mockReturnValueOnce(choiceShrink3Chained);428      const shrinkChained1 = new Value(25, Symbol());429      const shrinkChained2 = new Value(51, Symbol());430      shrinkChained.mockReturnValueOnce(Stream.of(shrinkChained1, shrinkChained2));431      class MyNextArbitrary extends Arbitrary<any> {432        generate = generate;433        canShrinkWithoutContext = canShrinkWithoutContext;434        shrink = shrink;435      }436      class MyNextChainedArbitrary extends Arbitrary<any> {437        generate = generateChained;438        canShrinkWithoutContext = canShrinkWithoutContextChained;439        shrink = shrinkChained;440      }441      const chainer = jest.fn();442      chainer.mockReturnValue(new MyNextChainedArbitrary());443      // Act444      const arb = new MyNextArbitrary().chain(chainer);445      const g = arb.generate(mrngNoCall, expectedBiasFactor);446      const shrinks = arb.shrink(g.value, g.context);447      // Assert448      expect([...shrinks].map((v) => v.value)).toEqual([449        choiceShrink1Chained.value,450        choiceShrink2Chained.value,451        choiceShrink3Chained.value,452        shrinkChained1.value,453        shrinkChained2.value,454      ]); // shrink of source chained, then the one of original chained455      expect(generateChained).toHaveBeenNthCalledWith(4, expect.any(Random), expectedBiasFactor); // sub-sequent calls re-use the original bias456      expect(chainer).toHaveBeenCalledWith(choiceRoot.value); // original call457      expect(chainer).toHaveBeenCalledWith(shrinkRoot1.value); // chained during shrink458      expect(chainer).toHaveBeenCalledWith(shrinkRoot2.value); // chained during shrink459      expect(chainer).toHaveBeenCalledWith(shrinkRoot3.value); // chained during shrink460    });461    it('should properly shrink output of shrink by calling back shrink with the right context', () => {462      // Arrange463      const expectedBiasFactor = 48;464      const generate = jest.fn();465      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;466      const shrink = jest.fn();467      const choiceRoot = new Value(1, Symbol());468      generate.mockReturnValueOnce(choiceRoot);469      const shrinkRoot1 = new Value(10, Symbol());470      const shrinkRoot2 = new Value(11, Symbol()); // will not be iterated (getNthOrLast(0))471      const shrinkRoot3 = new Value(15, Symbol()); // will not be iterated (getNthOrLast(0))472      shrink.mockReturnValueOnce(Stream.of(shrinkRoot1, shrinkRoot2, shrinkRoot3));473      const shrinkRoot11 = new Value(310, Symbol());474      shrink.mockReturnValueOnce(Stream.of(shrinkRoot11));475      const generateChained = jest.fn();476      const canShrinkWithoutContextChained = jest.fn() as any as (value: unknown) => value is any;477      const shrinkChained = jest.fn();478      const choiceChained = new Value(50, Symbol());479      const choiceShrink1Chained = new Value(58, Symbol()); // chain will be called for each iterated sub-shrink of root (->10)480      const choiceShrink2Chained = new Value(57, Symbol()); // ->310 - 11 and 15 will not be retrieved (getNthOrLast(0))481      generateChained482        .mockReturnValueOnce(choiceChained)483        .mockReturnValueOnce(choiceShrink1Chained)484        .mockReturnValueOnce(choiceShrink2Chained);485      const shrinkChained1 = new Value(25, Symbol());486      const shrinkChained2 = new Value(51, Symbol());487      shrinkChained.mockReturnValueOnce(Stream.of(shrinkChained1, shrinkChained2));488      const shrinkChained11 = new Value(125, Symbol());489      const shrinkChained12 = new Value(151, Symbol());490      shrinkChained.mockReturnValueOnce(Stream.of(shrinkChained11, shrinkChained12));491      class MyNextArbitrary extends Arbitrary<any> {492        generate = generate;493        canShrinkWithoutContext = canShrinkWithoutContext;494        shrink = shrink;495      }496      class MyNextChainedArbitrary extends Arbitrary<any> {497        generate = generateChained;498        canShrinkWithoutContext = canShrinkWithoutContextChained;499        shrink = shrinkChained;500      }501      const chainer = jest.fn();502      chainer.mockReturnValue(new MyNextChainedArbitrary());503      // Act504      const arb = new MyNextArbitrary().chain(chainer);505      const g = arb.generate(mrngNoCall, expectedBiasFactor);506      const firstShrunkValue = arb.shrink(g.value, g.context).getNthOrLast(0)!;507      const shrinks = arb.shrink(firstShrunkValue.value, firstShrunkValue.context);508      // Assert509      expect([...shrinks].map((v) => v.value)).toEqual([510        choiceShrink2Chained.value,511        shrinkChained11.value,512        shrinkChained12.value,513      ]);514      expect(generateChained).toHaveBeenNthCalledWith(2, expect.any(Random), expectedBiasFactor); // sub-sequent calls re-use the original bias515      expect(chainer).toHaveBeenCalledWith(choiceRoot.value); // original call516      expect(chainer).toHaveBeenCalledWith(shrinkRoot1.value); // chained during shrink517      expect(chainer).not.toHaveBeenCalledWith(shrinkRoot2.value); // chained during shrink (skipped due to getNthOrLast(0)518      expect(chainer).not.toHaveBeenCalledWith(shrinkRoot3.value); // chained during shrink (skipped due to getNthOrLast(0)519      expect(chainer).toHaveBeenCalledWith(shrinkRoot11.value); // chained during second shrink (returned choiceShrink2Chained)520    });521    it('should stop shrink on source if it exhausted it once', () => {522      // Arrange523      const expectedBiasFactor = 48;524      const generate = jest.fn();525      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;526      const shrink = jest.fn();527      const choiceRoot = new Value(1, Symbol());528      generate.mockReturnValueOnce(choiceRoot);529      const shrinkRoot1 = new Value(10, Symbol());530      const shrinkRoot2 = new Value(11, Symbol());531      shrink.mockReturnValueOnce(Stream.of(shrinkRoot1, shrinkRoot2));532      const generateChained = jest.fn();533      const canShrinkWithoutContextChained = jest.fn() as any as (value: unknown) => value is any;534      const shrinkChained = jest.fn();535      const choiceChained = new Value(50, Symbol());536      const choiceShrink1Chained = new Value(58, Symbol());537      const choiceShrink2Chained = new Value(57, Symbol());538      generateChained539        .mockReturnValueOnce(choiceChained)540        .mockReturnValueOnce(choiceShrink1Chained)541        .mockReturnValueOnce(choiceShrink2Chained);542      const shrinkChained1 = new Value(25, Symbol());543      const shrinkChained2 = new Value(51, Symbol());544      shrinkChained.mockReturnValueOnce(Stream.of(shrinkChained1, shrinkChained2));545      const shrinkChained11 = new Value(125, Symbol());546      const shrinkChained12 = new Value(151, Symbol());547      shrinkChained.mockReturnValueOnce(Stream.of(shrinkChained11, shrinkChained12));548      class MyNextArbitrary extends Arbitrary<any> {549        generate = generate;550        canShrinkWithoutContext = canShrinkWithoutContext;551        shrink = shrink;552      }553      class MyNextChainedArbitrary extends Arbitrary<any> {554        generate = generateChained;555        canShrinkWithoutContext = canShrinkWithoutContextChained;556        shrink = shrinkChained;557      }558      const chainer = jest.fn();559      chainer.mockReturnValue(new MyNextChainedArbitrary());560      // Act561      const arb = new MyNextArbitrary().chain(chainer);562      const g = arb.generate(mrngNoCall, expectedBiasFactor);563      const shrunkValue = arb.shrink(g.value, g.context).getNthOrLast(2)!; // source will be exhausted it only declares two shrunk values564      const shrinks = arb.shrink(shrunkValue.value, shrunkValue.context);565      // Assert566      expect([...shrinks].map((v) => v.value)).toEqual([shrinkChained11.value, shrinkChained12.value]);567      expect(shrink).toHaveBeenCalledTimes(1); // not called back on second call to shrink568    });569    it('should always return false for canShrinkWithoutContext when not provided any unchain function', () => {570      // Arrange571      const generate = jest.fn();572      const canShrinkWithoutContext = jest.fn();573      const shrink = jest.fn();574      class MyNextArbitrary extends Arbitrary<any> {575        generate = generate;576        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;577        shrink = shrink;578      }579      // Act580      const arb = new MyNextArbitrary().chain(() => new MyNextArbitrary());581      const out = arb.canShrinkWithoutContext('');582      // Assert583      expect(out).toBe(false);584      expect(canShrinkWithoutContext).not.toHaveBeenCalled();585    });586    it('should return empty stream when shrinking without any context and not provided any unchainer function', () => {587      // Arrange588      const generate = jest.fn();589      const canShrinkWithoutContext = jest.fn();590      const shrink = jest.fn();591      class MyNextArbitrary extends Arbitrary<any> {592        generate = generate;593        canShrinkWithoutContext = canShrinkWithoutContext as any as (value: unknown) => value is any;594        shrink = shrink;595      }596      // Act597      const arb = new MyNextArbitrary().chain(() => new MyNextArbitrary());598      const shrinks = arb.shrink('', undefined);599      // Assert600      expect([...shrinks]).toHaveLength(0);601      expect(shrink).not.toHaveBeenCalled();602    });603  });604  describe('noShrink', () => {605    it('should simply return the original instance of Value on generate', () => {606      // Arrange607      const expectedBiasFactor = 48;608      const generate = jest.fn();609      const canShrinkWithoutContext = jest.fn() as any as (value: unknown) => value is any;610      const shrink = jest.fn();611      const choice = new Value(1, Symbol());612      generate.mockReturnValueOnce(choice);613      class MyNextArbitrary extends Arbitrary<any> {614        generate = generate;615        canShrinkWithoutContext = canShrinkWithoutContext;616        shrink = shrink;617      }618      // Act619      const arb = new MyNextArbitrary().noShrink();620      const g = arb.generate(mrngNoCall, expectedBiasFactor);621      // Assert622      expect(g).toBe(choice); // just returning the instance of the source arbitrary (including its context)623      expect(generate).toHaveBeenCalledWith(mrngNoCall, expectedBiasFactor);624    });625    it('should override default shrink with function returning an empty Stream', () => {626      // Arrange627      const shrink = jest.fn();628      class MyNextArbitrary extends Arbitrary<any> {629        generate(): Value<any> {630          throw new Error('Not implemented.');631        }632        canShrinkWithoutContext(value: unknown): value is any {633          throw new Error('Not implemented.');634        }635        shrink = shrink;636      }637      const fakeArbitrary: Arbitrary<any> = new MyNextArbitrary();638      const noShrinkArbitrary = fakeArbitrary.noShrink();639      // Act640      const out = noShrinkArbitrary.shrink(5, Symbol());641      // Assert642      expect([...out]).toHaveLength(0);643      expect(shrink).not.toHaveBeenCalled();644    });645    it('should return itself when called twice', () => {646      // Arrange647      class MyNextArbitrary extends Arbitrary<any> {648        generate(): Value<any> {649          throw new Error('Not implemented.');650        }651        canShrinkWithoutContext(value: unknown): value is any {652          throw new Error('Not implemented.');653        }654        shrink(): Stream<Value<any>> {655          throw new Error('Not implemented.');656        }657      }658      const fakeArbitrary: Arbitrary<any> = new MyNextArbitrary();659      // Act660      const firstNoShrink = fakeArbitrary.noShrink();661      const secondNoShrink = firstNoShrink.noShrink();662      // Assert663      expect(secondNoShrink).toBe(firstNoShrink);664    });665  });666  describe('noBias', () => {667    it('should override passed bias with undefined', () => {668      // Arrange669      const generate = jest.fn();670      class MyNextArbitrary extends Arbitrary<any> {671        generate = generate;672        canShrinkWithoutContext(value: unknown): value is any {673          throw new Error('Not implemented.');674        }675        shrink(): Stream<Value<any>> {676          throw new Error('Not implemented.');677        }678      }679      const fakeArbitrary: Arbitrary<any> = new MyNextArbitrary();680      const noBiasArbitrary = fakeArbitrary.noBias();681      // Act682      noBiasArbitrary.generate(mrngNoCall, 42);683      // Assert684      expect(generate).toHaveBeenCalledTimes(1);685      expect(generate).toHaveBeenCalledWith(mrngNoCall, undefined);686    });687    it('should return itself when called twice', () => {688      // Arrange689      class MyNextArbitrary extends Arbitrary<any> {690        generate(): Value<any> {691          throw new Error('Not implemented.');692        }693        canShrinkWithoutContext(value: unknown): value is any {694          throw new Error('Not implemented.');695        }696        shrink(): Stream<Value<any>> {697          throw new Error('Not implemented.');698        }699      }700      const fakeArbitrary: Arbitrary<any> = new MyNextArbitrary();701      // Act702      const firstNoBias = fakeArbitrary.noBias();703      const secondNoBias = firstNoBias.noBias();704      // Assert705      expect(secondNoBias).toBe(firstNoBias);706    });707  });...Triptych-1.1.4.js
Source:Triptych-1.1.4.js  
1/*2   Copyright 2012 Dexter Pratt3   Licensed under the Apache License, Version 2.0 (the "License");4   you may not use this file except in compliance with the License.5   You may obtain a copy of the License at6       http://www.apache.org/licenses/LICENSE-2.07   Unless required by applicable law or agreed to in writing, software8   distributed under the License is distributed on an "AS IS" BASIS,9   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.10   See the License for the specific language governing permissions and11   limitations under the License.12*/13/*14Triptych.js15	In this version of Triptych.js, visualization has been built around THREE.js, and so there16	are dependencies on that library. But the underlying design of Triptych is to encourage17	separation of the visualization and layout layers from the abstract graph, so in the18	future Triptych is intended to evolve to work with other graphics layers.19	20	One of the key points of that separation is that the nodes and edges of the21	abstract graph layer are not the objects displayed by the visualizer.  When 22	the abstract graph is modified, it is the responsibility of visualizer to manage23	any graphic objects that it uses to render that abstract graph.24	25*/26var TRIPTYCH = {};27/*28------------------------------------29	Graph30------------------------------------31*/32TRIPTYCH.Graph = function(){33	this.nodes = [];34	this.edges = [];35	this.nodeIdMap = {};36	this.nodeIdentifierMap = {};37	this.relationships = {};38	this.maxId = 0;39	this.startingPosition = new THREE.Vector3(0,0,0);40	this.changed = false;41};42TRIPTYCH.Graph.prototype = {43	constructor : TRIPTYCH.Graph,44	45	addNode : function (node){46		this.nodes.push(node);47		this.nodeIdMap[node.id] = node;48		if (node.identifier) this.nodeIdentifierMap[node.identifier] = node;49		node.graph = this;50		this.maxId = Math.max(this.maxId, node.id);51		this.changed = true;52	},53	54	copyExternalNode : function (externalNode){55		var internalNode = this.nodeByIdentifier(externalNode.identifier);56		if (internalNode) return internalNode;57		internalNode = new TRIPTYCH.Node(graph.maxId + 1);58		internalNode.identifier = externalNode.identifier;59		internalNode.type = externalNode.type;60		internalNode.label = externalNode.label;61		$.each(externalNode.literals, function(predicate, value){62			internalNode.setLiteral(predicate, value);63		});64		this.addNode(internalNode);65		return internalNode;66	67	},68	69	addEdge : function (edge){70		this.edges.push(edge);71		edge.graph = this;72		this.changed = true;73		return edge;74	},75	76	relationshipByType : function (type){77		return this.relationships[type];78	},79	80	findOrCreateRelationship : function (type){81		var rel = this.relationshipByType(type);82		if (rel) return rel;83		console.log("creating relationship from " + type);84		rel = new TRIPTYCH.Relationship(type);85		this.relationships[type] = rel;86		return rel;87	},88	89	// id within the graph90	nodeById : function (id){91		return this.nodeIdMap[id];92	},93	94	// id across graphs 95	// (a given application is responsible for assigning unique identifiers96	// for nodes in the graphs that it loads)97	nodeByIdentifier : function(identifier){98		if (identifier) return this.nodeIdentifierMap[identifier];99		return false;100	},101	102	nodesByLiteral : function(predicate, value){103		var foundNodes = [];104		$.each(graph.nodes, function(index, node){105			if (node.getLiteral(predicate) == value){106				foundNodes.push(node);107			}	108		});109		return foundNodes;110	},111	112	findOrCreateNodeByIdentifier : function(identifier){113		var node = this.nodeByIdentifier(identifier);114		if (node) return node;115		node = new TRIPTYCH.Node(this.maxId++);116		node.identifier = identifier;117		this.addNode(node)118		return node;119	},120	121	122	findEdge : function (fromNode, relationship, toNode){123		for (var i = 0; i < this.edges.length; i++){124			var edge = this.edges[i];125			if (fromNode == edge.from && toNode == edge.to && relationship == edge.relationship){126				127				return edge;128			}129		}130		return false;131	},132	133	findOrCreateEdge : function(fromNode, rel, toNode){134		var edge = this.findEdge(fromNode, rel, toNode);135		if (edge) return edge;136		edge = new TRIPTYCH.Edge(fromNode, rel, toNode);137		this.addEdge(edge);138		return edge;139	},140	141	copyExternalEdge : function(edge){142		var rel = this.findOrCreateRelationship(edge.relationship.type);143		var from = this.copyExternalNode(edge.from);144		var to = this.copyExternalNode(edge.to);145		var internalEdge = this.findEdge(from, rel, to);146		if (internalEdge) return internalEdge;147		internalEdge = new TRIPTYCH.Edge(from, rel, to);148		this.addEdge(internalEdge);149		return internalEdge;150	},151	152	addGraph : function (graph){153		var internalGraph = this;154		$.each(graph.nodes, function(index, node){155			internalGraph.copyExternalNode(node);	156		});157		158		$.each(graph.edges, function(index, edge){159			var internalEdge = internalGraph.copyExternalEdge(edge);160			internalEdge.initNodePositions(graph.startingPosition);161		});162		163		return internalGraph;164	165	},166	167	markSubgraphs : function(){168		var subgraph_num = 0;169		var subgraphMap = {};170		$.each(graph.edges, function(index, edge){171			if (!edge.from.subgraph){172				if (!edge.to.subgraph){173					// neither node has been marked yet, assign both the next subgraph number174					subgraph_num++;175					edge.to.subgraph = subgraph_num;176					edge.from.subgraph = subgraph_num;177				} else {178					// to_node is marked, but from is not, so assign from_node the to_node subgraph number179					edge.from.subgraph = edge.to.subgraph;180				}181			} else {182				// from_node is marked183				if (!edge.to.subgraph){184					// but to_node is not, so assign to_node the from_node subgraph number185					edge.to.subgraph = edge.from.subgraph;186				} else {187					// both nodes already marked188					// note that their subgraph numbers are equivalent189				}190			}191		});192		193		$.each(graph.nodes, function(index, node){194			lowestSubgraph = subgraphMap[node.subgraph];195			if (lowestSubgraph) node.subgraph = lowestSubgraph;196		});197	198	},199	200	mappedClone : function(){201		var originalGraph = this;202		var mappedGraph = new TRIPTYCH.Graph();203		$.each(originalGraph.nodes, function(index, node){204			var mappedNode = mappedGraph.copyExternalNode(node);	205			mappedNode.mapsTo = node;206		});207		208		$.each(originalGraph.edges, function(index, edge){209			var mappedEdge = mappedGraph.copyExternalEdge(edge);210			mappedEdge.mapsTo = edge;211		});212		213		return mappedGraph;214	215	},216	217	getOutgoing : function(node){218		var outgoing = [];219		$.each(this.edges, function(index, edge){220			if(edge.from == node && outgoing.indexOf(edge) == -1){221				outgoing.push(edge);222			}223		});224		return outgoing;225	},226	227	getIncoming : function(node){228		var incoming = [];229		$.each(this.edges, function(index, edge){230			if(edge.to == node && incoming.indexOf(edge) == -1){231				incoming.push(edge);232			}233		});234		return incoming;235	},236	237	getEdges : function(node){238		var allEdges = [];239		$.each(this.edges, function(index, edge){240			if((edge.from == node || edge.to == node) && allEdges.indexOf(edge) == -1){241				allEdges.push(edge);242			}243		});244		return allEdges;245	},246	247	getSinks : function(){248		var sinks = [];249		$.each(this.nodes, function(index, node){250			if (node.isSink()){251				sinks.push(node);252			}253		});254		return sinks;255	},256	getSources : function(){257		var sources = [];258		$.each(this.nodes, function(index, node){259			if (node.isSource(node)){260				sources.push(node);261			}262		});263		return sources;264	},265	266	isSink : function(node){267		var isSink = true;268		$.each(this.edges, function(index, edge){269			if (node == edge.from){270				isSink = false;271				return;272			}273		});274		return isSink;275	},276	277	isSource : function(node){278		var isSource = true;279		$.each(this.edges, function(index, edge){280			if (node == edge.to){281				isSource = false;282				return;283			}284		});285		return isSource;286	}287};288/*289------------------------------------290	Node291------------------------------------292*/293TRIPTYCH.Node = function(id){294	this.literals = {};295	this.position = new THREE.Vector3(0, 0, 0);296	this.force = new THREE.Vector3(0, 0, 0);297	this.modified = true;298	this.id = id; 					// id within the graph299	this.identifier = null; 		// external identifier300	this.ns = null;					// namespace for external identifier301	this.label = "node";  			// label to display302	this.type = "node";				// primary type of node303	this.displayList = {};304	this.selected = false;305	this.graph = null;306	this.planes = [];307	this.subGraphs = {};				// marked subsets - typically disjoint graphs308	309};310TRIPTYCH.Node.prototype = {311	constructor : TRIPTYCH.Node,312	313	getVector : function (node){314		var v = node.position.clone();315		v.subSelf(this.position);316		return v;317	},318	319	onClick : function (event, role){320		if (this.selected){321			this.setSelected(false);322		} else {323			this.setSelected(true);324		}325	},326	327	onIntersectedStart : function (event, role){328		this.setHighlighted(true);329	},330	331	onIntersectedEnd : function (event, role){332		this.setHighlighted(false);333	},334	335	setHighlighted : function(boolean){336		this.highlighted = boolean;337		this.graph.changed = true;338	},339	340	setSelected : function(boolean){341		this.selected = boolean;342		this.graph.changed = true;343	},344	345	atOrigin : function(){346		return this.position.x == 0 && this.position.y == 0 && this.position.z == 0;347	},348	349	getOutgoing : function(){350		return this.graph.getOutgoing(this);351	},352	353	getIncoming : function(){354		return this.graph.getIncoming(this);355	},356	357	getEdges : function(){358		return this.graph.getEdges(this);359	},360	361	getChildren : function(){362		var children = [];363		$.each(this.getOutgoing(), function(index, edge){364			if (children.indexOf(edge.to) == -1){365				children.push(edge.to);366			}367		});368		return children;369	},370	371	getParents : function(){372		var parents = [];373		$.each(this.getIncoming(), function(index, edge){374			var parent = edge.from;375			if (parents.indexOf(parent) == -1){376				parents.push(parent);377			}378		});379		return parents;380	381	},382	383	isSource : function(){384		return this.graph.isSource(this); 385	},386	387	isSink : function(){388		return this.graph.isSink(this); 389	},390	391	setLiteral : function(predicate, string){392		this.literals[predicate] = string;393	},394	395	getLiteral : function(predicate){396		return this.literals[predicate];397	},398	399	addSubGraph : function(id, text){400		if (!text) text = "subgraph " + id;401		if (!this.subGraphs.id){402			this.subGraphs.id = text;403		}404	},405	406	addPlane : function(id){407		if (this.planes.lastIndexOf(id) == -1) this.planes.push(id);408		this.graph.changed = true;409	}410		411};412/*413------------------------------------414	Edge415------------------------------------416*/417TRIPTYCH.Edge = function(fromNode, relationship, toNode){418	this.from = fromNode;419	this.to = toNode;420	this.relationship = relationship;421	this.displayList = {};422	this.subGraphs = {};423	this.planes = [];424};425TRIPTYCH.Edge.prototype = {426	constructor : TRIPTYCH.Edge,427	getVector : function(){428		var v = this.to.position.clone();429		v.subSelf(this.from.position);430		return v;431	},432	onClick : function (event, role){433		if (this.selected){434			this.setSelected(false);435		} else {436			this.setSelected(true);437		}438	},439	440	onIntersectedStart : function (event, role){441		this.setHighlighted(true);442	},443	444	onIntersectedEnd : function (event, role){445		this.setHighlighted(false);446	},447	448	setHighlighted : function(boolean){449		this.highlighted = boolean;450		this.graph.changed = true;451	},452	453	setSelected : function(boolean){454		this.selected = boolean;455		this.graph.changed = true;456	},457		458	initNodePositions : function(startingPosition){459		// if one of the two nodes position isn't initialized,460		// copy its position from the other.461		// this will start nodes in the layout next to a neighbor462		if (this.to.atOrigin() && !this.from.atOrigin()){463			this.to.position.set(Math.random() + this.from.position.x, 464								Math.random() + this.from.position.y,465								Math.random() + this.from.position.z);466			//this.to.position.copy(this.from.position);467		} else if (this.from.atOrigin() && !this.to.atOrigin()){468			this.from.position.set(Math.random() + this.to.position.x, 469								Math.random() + this.to.position.y,470								Math.random() + this.to.position.z);471			//this.from.position.copy(this.to.position);472		} else if (startingPosition) {473			this.from.position.set(startingPosition.x, startingPosition.y, startingPosition.z);474			this.to.position.set(startingPosition.x, startingPosition.y, startingPosition.z)475		}476		this.graph.changed = true;477	},478	479	reverse : function(){480		var temp = this.from;481		this.from = this.to;482		this.to = temp;483	},484	485	addSubGraph : function(id, text){486		if (!text) text = "subgraph " + id;487		if (!this.subGraphs.id){488			this.subGraphs.id = text;489		}490	},491	492	addPlane : function(id){493		this.planes.push(id);494		this.graph.changed = true;495	}496	497};498/*499------------------------------------500	Relationship501------------------------------------502*/503TRIPTYCH.Relationship = function(type, causal, inverting){504	this.type = type;505	if (causal){506		this.causal = causal;507	} else {508		this.causal = false;509	}510	if (inverting){511		this.inverting = inverting;512	} else {513		this.inverting = false;514	}515};516TRIPTYCH.Relationship.prototype = {517	constructor : TRIPTYCH.Relationship518};519/*520------------------------------------521	Graph Loader522------------------------------------523*/524TRIPTYCH.GraphLoader = function(){525};526TRIPTYCH.Relationship.prototype = {527	constructor : TRIPTYCH.Relationship,528	529	// returns a graph or false if a serious problem is encountered530	// TODO: deal with appropriate exception handling and 531	// reporting of errors532	load : function(type, data){533	}534};535/*536------------------------------------537	Visualizer538------------------------------------539*/540TRIPTYCH.Visualizer = function(){541	this.scene = new THREE.Scene();542	this.displayObjectToElementMap = {};543	this.intersectedElement = null;544	this.intersectionRole = null;545	this.lastIntersectedElement = null;546	this.lastIntersectionRole = null;547	this.edgeReferenceLength = 100;548	this.resources = {};549};550TRIPTYCH.Visualizer.prototype = {551	constructor : TRIPTYCH.Visualizer,552	553	init : function(){554		555	},556	557	render : function(){558		this.renderer.clear();559		this.renderer.render( this.scene, this.camera );560	},561	562	update : function(graph){563	564		visualizer.needsRender = false;565	566		this.updateTimeLoops();567		568		this.updateLights();569		570		for (var i = 0; i<graph.nodes.length; i++){571			var node = graph.nodes[i];572			this.updateNode(node);573		}574		575		for (var i = 0; i<graph.edges.length; i++){576			var edge = graph.edges[i];577			this.updateEdge(edge);578		}579	580	},581	582	// These methods could be regarded as redundant,583	// but they are used to make the code especially clear584	// in an area where confusion is easy585	//586	mapDisplayObjectToElement : function (displayObject, element, role){587		this.displayObjectToElementMap[displayObject.id] = [element, role];588	},589	590	unmapDisplayObject : function(displayObject){591		delete this.displayObjectToElementMap[displayObject.id];592	},593	594	getElementAndRoleByDisplayObject : function(displayObject){595		if (!displayObject) return null;596		if (!displayObject.id) return null;597		return this.displayObjectToElementMap[displayObject.id];598	},599	600	addElement : function (object, element, role){601		this.scene.add( object );602		this.mapDisplayObjectToElement( object, element, role);603	},604	605	updateLights : function(){606	607	},608	609	updateTimeLoops : function(){610	611	},612	613	addTexture : function(resourceName, url){614		this.resources[resourceName] = THREE.ImageUtils.loadTexture(url);615	}616};617/*618------------------------------------619	NodeDisplayer620------------------------------------621*/622TRIPTYCH.NodeDisplayer = function(node){623	this.node = node;624};625TRIPTYCH.NodeDisplayer.prototype.constructor = TRIPTYCH.NodeDisplayer;626/*627------------------------------------628	EdgeDisplayer629------------------------------------630*/631TRIPTYCH.EdgeDisplayer = function(edge){632	this.edge = edge;633};634TRIPTYCH.EdgeDisplayer.prototype.constructor = TRIPTYCH.EdgeDisplayer;635/*636------------------------------------637	LayoutEngine638------------------------------------639*/640TRIPTYCH.LayoutEngine = function(){641};642TRIPTYCH.LayoutEngine.prototype = {643	constructor : TRIPTYCH.LayoutEngine,644	645	setGraph : function(graph){646		this.graph = graph;647		this.graph.changed = true;648	},649	650	update : function(){651	652	}653};654TRIPTYCH.DynamicLayoutEngine = function(graph){655	this.needsUpdate = true;656	this.updateCount = 200;657	658};659TRIPTYCH.DynamicLayoutEngine.prototype = new TRIPTYCH.LayoutEngine();660TRIPTYCH.DynamicLayoutEngine.prototype.constructor = TRIPTYCH.DynamicLayoutEngine;661TRIPTYCH.DynamicLayoutEngine.prototype.update = function(){662	if (this.updateCount <= 0){663		this.needsUpdate = false;664	}665	if (this.needsUpdate){666		// doing 2 layout steps is a workaround for 667		// a "jitter" problem in the dynamic layout engines668		this.layoutStep();669		this.layoutStep();670		this.graph.changed = true;671		this.updateCount--;672	}673	return this.needsUpdate;674	675};676TRIPTYCH.DynamicLayoutEngine.prototype.startUpdating = function(max){677	this.needsUpdate = true;678	this.updateCount = max || 200;679	680};681TRIPTYCH.DynamicLayoutEngine.prototype.stopUpdating = function(){682	this.needsUpdate = false;683	this.updateCount = 0;684	685};686/*687------------------------------------688	Space689------------------------------------690*/691TRIPTYCH.Space = function(graph, visualizer, layoutEngine, controls, container){692	693	this.graph = graph;694	this.visualizer = visualizer;695	this.visualizer.space = this;696	this.layoutEngine = layoutEngine;697	this.layoutEngine.space = this;698	this.container = container;699	this.controls = controls;700	this.controls.space = this;701	this.cameraInitialZ = 300;702	this.alwaysUpdate = false;703	704};705TRIPTYCH.Space.prototype = {706	constructor : TRIPTYCH.Space,	707	708	init : function(){709	710		// if no container is provided, then create one711		if (!this.container) this.container = document.createElement('div');712		713		document.body.appendChild(this.container);714		715		this.layoutEngine.setGraph(this.graph);716		717		this.initCamera();718		719		this.visualizer.init(window.innerWidth, window.innerHeight, this.camera);720		721		this.controls.init(this.visualizer);722		723		this.container.appendChild( this.visualizer.renderer.domElement );724		725	},726	727	initCamera : function(){728		this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );729		this.camera.position.z = this.cameraInitialZ;730	},731	732	update : function(){733		734		this.layoutEngine.update();735		736		var controlsChanged = this.controls.update();		737		738		// 739		// Update the visualization and render if the graph has changed740		// or if the controls change741		//742		if (controlsChanged || this.graph.changed || this.alwaysUpdate){ 743			this.visualizer.update(this.graph);		744			this.visualizer.render();745		}746		747		//748		// Clear the state of the graph 749		//750		this.graph.changed = false;751	}752};753//754//  Adapted from the THREE.js Detector755//756TRIPTYCH.EnvironmentDetector = {757	canvas : !! window.CanvasRenderingContext2D,758	webgl : ( function () 759				{ try 760					{ 761						return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); 762					} 763				catch( e ) 764					{ return false; } 765				} )(),766	workers : !! window.Worker,767	fileapi : window.File && window.FileReader && window.FileList && window.Blob,768	getWebGLErrorMessage : function () {769		var domElement = document.createElement( 'div' );770		domElement.style.fontFamily = 'helvetica neue, helvetica, arial, sans-serif';771		domElement.style.fontSize = '200%';772		domElement.style.textAlign = 'center';773		domElement.style.background = '#000000';774		domElement.style.color = '#FFFFFF';775		domElement.style.padding = '1em';776		domElement.style.width = '50%';777		//domElement.style.margin = '5em auto 0';778		domElement.style.left = '50%';779		domElement.style.marginLeft = '-25%';780		domElement.style.top = '100px';781		domElement.style.zIndex = 2000;782		domElement.style.position = 'absolute';783		if ( ! this.webgl ) {784			domElement.innerHTML = window.WebGLRenderingContext ? [785				'This Triptych.js application requires a graphics system that supports WebGL - a WebGL-compatible graphics card or built-in GPU, plus a browser such as a recent version of Chrome or Firefox. Safari will work if WebGL is enabled.'786			].join( '\n' ) : [787				'This Triptych.js-based application requires a browser that supports WebGL, such as recent versions of Chrome or Firefox. Safari will work if WebGL is enabled.'788			].join( '\n' );789		}790		return domElement;791	},792	addGetWebGLMessage : function ( parameters ) {793		var parent, id, domElement;794		parameters = parameters || {};795		parent = parameters.parent !== undefined ? parameters.parent : document.body;796		id = parameters.id !== undefined ? parameters.id : 'oldie';797		domElement = this.getWebGLErrorMessage();798		domElement.id = id;799		parent.appendChild( domElement );800	}...Using AI Code Generation
1const { mappedClone } = require('fast-check-monorepo');2const obj = {3  d: { e: 5 },4  f: () => 6,5};6const clone = mappedClone(obj, (value) => {7  if (typeof value === 'number') {8    return value * 2;9  }10  return value;11});12console.log(clone);13const { mappedClone } = require('fast-check');14const obj = {15  d: { e: 5 },16  f: () => 6,17};18const clone = mappedClone(obj, (value) => {19  if (typeof value === 'number') {20    return value * 2;21  }22  return value;23});24console.log(clone);25const { mappedClone } = require('fast-check-monorepo');26const obj = {27  d: { e: 5 },28  f: () => 6,29};30const clone = mappedClone(obj, (value) => {31  if (typeof value === 'number') {32    return value * 2;33  }34  return value;35});36console.log(clone);Using AI Code Generation
1const {mappedClone} = require('fast-check-monorepo');2const fc = require('fast-check');3const clone = require('clone');4const data = {a: 1, b: 2, c: 3};5const clone1 = mappedClone(data, clone);6const clone2 = mappedClone(data, clone);Using AI Code Generation
1const fc = require('fast-check');2const { mappedClone } = require('fast-check-monorepo');3const arbitrary = fc.array(fc.integer(), 1, 10);4const mapper = (x) => x * 2;5const clone = mappedClone(arbitrary, mapper);6fc.assert(fc.property(clone, (x) => x.every((y) => y % 2 === 0)));7✓ OK: 1000 shrinks (0ms)8const clone = fc.cloneArbitrary(arbitrary, mapper);Using AI Code Generation
1const { clone } = require('fast-check-monorepo')2const obj = {3  c: { d: 3 }4}5const clonedObj = clone(obj)6console.log(obj)7console.log(clonedObj)8const { clone } = require('fast-check')9const obj = {10  c: { d: 3 }11}12const clonedObj = clone(obj)13console.log(obj)14console.log(clonedObj)Using AI Code Generation
1const { mappedClone } = require('fast-check');2const clone = mappedClone({3  foo: fc.integer(),4  bar: fc.string(),5});6fc.assert(7  fc.property(clone, (obj) => {8  })9);Using AI Code Generation
1const { mappedClone } = require('fast-check');2const fc = require('fast-check');3const { clone } = require('fast-check/lib/src/check/arbitrary/definition/MapperArbitrary');4describe('test', () => {5    it('should work', () => {6        const arb = fc.integer();7        const cloneArb = clone(arb);8        expect(mappedClone(arb)).toEqual(cloneArb);9    });10});Using AI Code Generation
1const fc = require('fast-check');2const { mappedClone } = require('fast-check-monorepo');3const myClone = mappedClone({ a: 42, b: 'hello' }, { a: 'b', b: 'a' });4const fc = require('fast-check');5const { mappedClone } = require('fast-check-monorepo');6const myClone = mappedClone({ a: 42, b: 'hello' }, { a: 'b', b: 'a' });7const myClone = mappedClone({ a: 42, b: 'hello' }, { a: 'b', b: 'a' });8const myClone = mappedClone({ a: 42, b: 'hello', c: true }, { a: 'b', b: 'a', c: 'c' });9const myClone = mappedClone({ a: 42, b: 'hello', c: true }, { a: 'b', b: 'a', c: 'c' });Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
