« get me outta code hell

data, test: WIP tests for compositeFrom - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-09-23 20:24:08 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-09-23 20:24:32 -0300
commit8bcae16b391762f6b533654ec06c3bf0c8770d35 (patch)
treea165a898f6cd4213c786e3c52e25901e5b16b224
parent7f7c50e7976bebc937c302638cade5e1fd543ff4 (diff)
data, test: WIP tests for compositeFrom
-rw-r--r--src/data/things/composite.js6
-rw-r--r--test/unit/data/composite/compositeFrom.js237
2 files changed, 240 insertions, 3 deletions
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index da2848f..c0f0ab0 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -752,6 +752,9 @@ export function templateCompositeFrom(description) {
 
 templateCompositeFrom.symbol = Symbol();
 
+export const continuationSymbol = Symbol.for('compositeFrom: continuation symbol');
+export const noTransformSymbol = Symbol.for('compositeFrom: no-transform symbol');
+
 export function compositeFrom(description) {
   const {annotation} = description;
 
@@ -1070,9 +1073,6 @@ export function compositeFrom(description) {
     return {continuation, continuationStorage};
   }
 
-  const continuationSymbol = Symbol.for('compositeFrom: continuation symbol');
-  const noTransformSymbol = Symbol.for('compositeFrom: no-transform symbol');
-
   function _computeOrTransform(initialValue, continuationIfApplicable, initialDependencies) {
     const expectingTransform = initialValue !== noTransformSymbol;
 
diff --git a/test/unit/data/composite/compositeFrom.js b/test/unit/data/composite/compositeFrom.js
new file mode 100644
index 0000000..faeef59
--- /dev/null
+++ b/test/unit/data/composite/compositeFrom.js
@@ -0,0 +1,237 @@
+import t from 'tap';
+
+import {isString} from '#validators';
+
+import {
+  compositeFrom,
+  continuationSymbol,
+  debugComposite,
+  input,
+} from '#composite';
+
+t.test(`compositeFrom: basic behavior`, t => {
+  t.plan(2);
+
+  const composite = compositeFrom({
+    annotation: `myComposite`,
+    compose: false,
+
+    steps: [
+      {
+        dependencies: ['foo'],
+        compute: (continuation, {foo}) =>
+          continuation({'#bar': foo * 2}),
+      },
+
+      {
+        dependencies: ['#bar', 'baz', 'suffix'],
+        compute: ({'#bar': bar, baz, suffix}) =>
+          baz.repeat(bar) + suffix,
+      },
+    ],
+  });
+
+  t.match(composite, {
+    annotation: `myComposite`,
+
+    flags: {expose: true, compose: false, update: false},
+
+    expose: {
+      dependencies: ['foo', 'baz', 'suffix'],
+      compute: Function,
+      transform: null,
+    },
+
+    update: null,
+  });
+
+  t.equal(
+    composite.expose.compute({
+      foo: 3,
+      baz: 'ba',
+      suffix: 'BOOM',
+    }),
+    'babababababaBOOM');
+});
+
+t.test(`compositeFrom: input-shaped step dependencies`, t => {
+  t.plan(2);
+
+  const composite = compositeFrom({
+    compose: false,
+    steps: [
+      {
+        dependencies: [
+          input.myself(),
+          input.updateValue(),
+        ],
+
+        transform: (updateValue1, {
+          [input.myself()]: me,
+          [input.updateValue()]: updateValue2,
+        }) => ({me, updateValue1, updateValue2}),
+      },
+    ],
+  });
+
+  t.match(composite, {
+    expose: {
+      dependencies: ['this'],
+      transform: Function,
+      compute: null,
+    },
+  });
+
+  const myself = {foo: 'bar'};
+
+  t.same(
+    composite.expose.transform('banana', {
+      this: myself,
+      pomelo: 'delicious',
+    }),
+    {
+      me: myself,
+      updateValue1: 'banana',
+      updateValue2: 'banana',
+    });
+});
+
+t.test(`compositeFrom: dependencies from inputs`, t => {
+  t.plan(3);
+
+  const composite = compositeFrom({
+    annotation: `myComposite`,
+
+    compose: true,
+
+    inputs: {
+      foo: input('bar'),
+      pomelo: input.value('delicious'),
+      humorous: input.dependency('#mammal'),
+      data: input.dependency('albumData'),
+      ref: input.updateValue(),
+    },
+
+    steps: [
+      {
+        dependencies: [
+          input('foo'),
+          input('pomelo'),
+          input('humorous'),
+          input('data'),
+          input('ref'),
+        ],
+
+        compute: (continuation, {
+          [input('foo')]: foo,
+          [input('pomelo')]: pomelo,
+          [input('humorous')]: humorous,
+          [input('data')]: data,
+          [input('ref')]: ref,
+        }) => continuation.exit({foo, pomelo, humorous, data, ref}),
+      },
+    ],
+  });
+
+  t.match(composite, {
+    expose: {
+      dependencies: [
+        input('bar'),
+        '#mammal',
+        'albumData',
+      ],
+
+      transform: Function,
+      compute: null,
+    },
+  });
+
+  const exitData = {};
+  const continuation = {
+    exit(value) {
+      Object.assign(exitData, value);
+      return continuationSymbol;
+    },
+  };
+
+  t.equal(
+    composite.expose.transform('album:bepis', continuation, {
+      [input('bar')]: 'squid time',
+      '#mammal': 'fox',
+      'albumData': ['album1', 'album2'],
+    }),
+    continuationSymbol);
+
+  t.same(exitData, {
+    foo: 'squid time',
+    pomelo: 'delicious',
+    humorous: 'fox',
+    data: ['album1', 'album2'],
+    ref: 'album:bepis',
+  });
+});
+
+t.test(`compositeFrom: update from various sources`, t => {
+  t.plan(2);
+
+  const match = {
+    flags: {update: true, expose: true, compose: false},
+
+    update: {
+      validate: isString,
+      default: 'foo',
+    },
+
+    expose: {
+      transform: Function,
+      compute: null,
+    },
+  };
+
+  t.test(`compositeFrom: update from composition description`, t => {
+    t.plan(2);
+
+    const composite = compositeFrom({
+      compose: false,
+
+      update: {
+        validate: isString,
+        default: 'foo',
+      },
+
+      steps: [
+        {transform: (value, continuation) => continuation(value.repeat(2))},
+        {transform: (value) => `Xx_${value}_xX`},
+      ],
+    });
+
+    t.match(composite, match);
+    t.equal(composite.expose.transform('foo'), `Xx_foofoo_xX`);
+  });
+
+  t.test(`compositeFrom: update from step dependencies`, t => {
+    t.plan(2);
+
+    const composite = compositeFrom({
+      compose: false,
+
+      steps: [
+        {
+          dependencies: [
+            input.updateValue({
+              validate: isString,
+              default: 'foo',
+            }),
+          ],
+
+          compute: ({
+            [input.updateValue()]: value,
+          }) => `Xx_${value.repeat(2)}_xX`,
+        },
+      ],
+    });
+
+    t.match(composite, match);
+    t.equal(debugComposite(() => composite.expose.transform('foo')), 'Xx_foofoo_xX');
+  });
+});