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!!