123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- import t from 'tap';
- import CacheableObject from '#cacheable-object';
- function newCacheableObject(PD) {
- return new (class extends CacheableObject {
- static [CacheableObject.propertyDescriptors] = PD;
- });
- }
- t.test(`CacheableObject simple separate update & expose`, t => {
- const obj = newCacheableObject({
- number: {
- flags: {
- update: true
- }
- },
- timesTwo: {
- flags: {
- expose: true
- },
- expose: {
- dependencies: ['number'],
- compute: ({ number }) => number * 2
- }
- }
- });
- t.plan(1);
- obj.number = 5;
- t.equal(obj.timesTwo, 10);
- });
- t.test(`CacheableObject basic cache behavior`, t => {
- let computeCount = 0;
- const obj = newCacheableObject({
- string: {
- flags: {
- update: true
- }
- },
- karkat: {
- flags: {
- expose: true
- },
- expose: {
- dependencies: ['string'],
- compute: ({ string }) => {
- computeCount++;
- return string.toUpperCase();
- }
- }
- }
- });
- t.plan(8);
- t.equal(computeCount, 0);
- obj.string = 'hello world';
- t.equal(computeCount, 0);
- obj.karkat;
- t.equal(computeCount, 1);
- obj.karkat;
- t.equal(computeCount, 1);
- obj.string = 'testing once again';
- t.equal(computeCount, 1);
- obj.karkat;
- t.equal(computeCount, 2);
- obj.string = 'testing once again';
- t.equal(computeCount, 2);
- obj.karkat;
- t.equal(computeCount, 2);
- });
- t.test(`CacheableObject combined update & expose (no transform)`, t => {
- const obj = newCacheableObject({
- directory: {
- flags: {
- update: true,
- expose: true
- }
- }
- });
- t.plan(2);
- obj.directory = 'the-world-revolving';
- t.equal(obj.directory, 'the-world-revolving');
- obj.directory = 'chaos-king';
- t.equal(obj.directory, 'chaos-king');
- });
- t.test(`CacheableObject combined update & expose (basic transform)`, t => {
- const obj = newCacheableObject({
- getsRepeated: {
- flags: {
- update: true,
- expose: true
- },
- expose: {
- transform: value => value.repeat(2)
- }
- }
- });
- t.plan(1);
- obj.getsRepeated = 'dog';
- t.equal(obj.getsRepeated, 'dogdog');
- });
- t.test(`CacheableObject combined update & expose (transform with dependency)`, t => {
- const obj = newCacheableObject({
- customRepeat: {
- flags: {
- update: true,
- expose: true
- },
- expose: {
- dependencies: ['times'],
- transform: (value, { times }) => value.repeat(times)
- }
- },
- times: {
- flags: {
- update: true
- }
- }
- });
- t.plan(3);
- obj.customRepeat = 'dog';
- obj.times = 1;
- t.equal(obj.customRepeat, 'dog');
- obj.times = 5;
- t.equal(obj.customRepeat, 'dogdogdogdogdog');
- obj.customRepeat = 'cat';
- t.equal(obj.customRepeat, 'catcatcatcatcat');
- });
- t.test(`CacheableObject validate on update`, t => {
- const mockError = new TypeError(`Expected a string, not ${typeof value}`);
- const obj = newCacheableObject({
- directory: {
- flags: {
- update: true,
- expose: true
- },
- update: {
- validate: value => {
- if (typeof value !== 'string') {
- throw mockError;
- }
- return true;
- }
- }
- },
- date: {
- flags: {
- update: true,
- expose: true
- },
- update: {
- validate: value => (value instanceof Date)
- }
- }
- });
- let thrownError;
- t.plan(6);
- obj.directory = 'megalovania';
- t.equal(obj.directory, 'megalovania');
- t.throws(
- () => { obj.directory = 25; },
- {cause: mockError});
- t.equal(obj.directory, 'megalovania');
- const date = new Date(`25 December 2009`);
- obj.date = date;
- t.equal(obj.date, date);
- t.throws(
- () => { obj.date = `TWELFTH PERIGEE'S EVE`; },
- {cause: TypeError});
- t.equal(obj.date, date);
- });
- t.test(`CacheableObject transform on null value`, t => {
- let computed = false;
- const obj = newCacheableObject({
- spookyFactor: {
- flags: {
- update: true,
- expose: true,
- },
- expose: {
- transform: value => {
- computed = true;
- return (value ? 2 * value : -1);
- },
- },
- },
- });
- t.plan(4);
- t.equal(obj.spookyFactor, -1);
- t.ok(computed);
- computed = false;
- obj.spookyFactor = 1;
- t.equal(obj.spookyFactor, 2);
- t.ok(computed);
- });
- t.test(`CacheableObject don't transform on successful update`, t => {
- let computed = false;
- const obj = newCacheableObject({
- original: {
- flags: {
- update: true,
- expose: true,
- },
- update: {
- validate: value => value.startsWith('track:'),
- },
- expose: {
- transform: value => {
- computed = true;
- return (value ? value.split(':')[1] : null);
- },
- },
- },
- });
- t.plan(4);
- t.doesNotThrow(() => obj.original = 'track:foo');
- t.notOk(computed);
- t.equal(obj.original, 'foo');
- t.ok(computed);
- });
- t.test(`CacheableObject don't transform on failed update`, t => {
- let computed = false;
- const obj = newCacheableObject({
- original: {
- flags: {
- update: true,
- expose: true,
- },
- update: {
- validate: value => value.startsWith('track:'),
- },
- expose: {
- transform: value => {
- computed = true;
- return (value ? value.split(':')[1] : null);
- },
- },
- },
- });
- t.plan(4);
- t.throws(() => obj.original = 'album:foo');
- t.notOk(computed);
- t.equal(obj.original, null);
- t.ok(computed);
- });
- t.test(`CacheableObject default update property value`, t => {
- const obj = newCacheableObject({
- fruit: {
- flags: {
- update: true,
- expose: true
- },
- update: {
- default: 'potassium'
- }
- }
- });
- t.plan(1);
- t.equal(obj.fruit, 'potassium');
- });
- t.test(`CacheableObject default property throws if invalid`, t => {
- const mockError = new TypeError(`Expected a string, not ${typeof value}`);
- t.plan(1);
- let thrownError;
- t.throws(
- () => newCacheableObject({
- string: {
- flags: {
- update: true
- },
- update: {
- default: 123,
- validate: value => {
- if (typeof value !== 'string') {
- throw mockError;
- }
- return true;
- }
- }
- }
- }),
- {cause: mockError});
- });
|