From c635034dabb3412582af7f4af754c8881ba94f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Thu, 26 Apr 2018 16:44:34 -0700 Subject: [PATCH] Add richer types to graphDemoData (#146) In preparation for using type info in the Graph apis, it is helpful to have richer type info in the graph demo data. Test plan: Check that the snapshot changes only consist of type changes, and that CI passes. --- src/core/__snapshots__/graph.test.js.snap | 56 +++++++------- src/core/graph.test.js | 90 ++++++++++++++--------- src/core/graphDemoData.js | 37 ++++++---- 3 files changed, 107 insertions(+), 76 deletions(-) diff --git a/src/core/__snapshots__/graph.test.js.snap b/src/core/__snapshots__/graph.test.js.snap index 981eb0c..3c4d381 100644 --- a/src/core/__snapshots__/graph.test.js.snap +++ b/src/core/__snapshots__/graph.test.js.snap @@ -3,12 +3,12 @@ exports[`graph #Graph JSON functions should serialize a simple graph 1`] = ` Object { "edges": Object { - "{\\"id\\":\\"crab-self-assessment\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"crab-self-assessment\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"SILLY\\"}": Object { "dst": Object { "id": "razorclaw_crab#2", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, "payload": Object { "evaluation": "not effective at avoiding hero", @@ -17,15 +17,15 @@ Object { "id": "razorclaw_crab#2", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"hero_of_time#0@again_cooks@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0@again_cooks@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"ACTION\\"}": Object { "dst": Object { "id": "hero_of_time#0", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "PC", }, "payload": Object { "crit": true, @@ -35,15 +35,15 @@ Object { "id": "seafood_fruit_mix#3", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"hero_of_time#0@cooks@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0@cooks@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"ACTION\\"}": Object { "dst": Object { "id": "hero_of_time#0", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "PC", }, "payload": Object { "crit": false, @@ -52,96 +52,96 @@ Object { "id": "seafood_fruit_mix#3", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"hero_of_time#0@eats@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0@eats@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"ACTION\\"}": Object { "dst": Object { "id": "seafood_fruit_mix#3", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, "payload": Object {}, "src": Object { "id": "hero_of_time#0", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "PC", }, }, - "{\\"id\\":\\"hero_of_time#0@grabs@razorclaw_crab#2\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0@grabs@razorclaw_crab#2\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"ACTION\\"}": Object { "dst": Object { "id": "hero_of_time#0", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "PC", }, "payload": Object {}, "src": Object { "id": "razorclaw_crab#2", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"hero_of_time#0@picks@mighty_bananas#1\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0@picks@mighty_bananas#1\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"ACTION\\"}": Object { "dst": Object { "id": "hero_of_time#0", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "PC", }, "payload": Object {}, "src": Object { "id": "mighty_bananas#1", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"mighty_bananas#1@included_in@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"mighty_bananas#1@included_in@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"INGREDIENT\\"}": Object { "dst": Object { "id": "mighty_bananas#1", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, "payload": Object {}, "src": Object { "id": "seafood_fruit_mix#3", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, - "{\\"id\\":\\"razorclaw_crab#2@included_in@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"razorclaw_crab#2@included_in@seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"INGREDIENT\\"}": Object { "dst": Object { "id": "razorclaw_crab#2", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, "payload": Object {}, "src": Object { "id": "seafood_fruit_mix#3", "pluginName": "hill_cooking_pot", "repositoryName": "sourcecred/eventide", - "type": "demoType", + "type": "FOOD", }, }, }, "nodes": Object { - "{\\"id\\":\\"hero_of_time#0\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"hero_of_time#0\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"PC\\"}": Object { "payload": Object {}, }, - "{\\"id\\":\\"mighty_bananas#1\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"mighty_bananas#1\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"FOOD\\"}": Object { "payload": Object {}, }, - "{\\"id\\":\\"razorclaw_crab#2\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"razorclaw_crab#2\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"FOOD\\"}": Object { "payload": Object {}, }, - "{\\"id\\":\\"seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"demoType\\"}": Object { + "{\\"id\\":\\"seafood_fruit_mix#3\\",\\"pluginName\\":\\"hill_cooking_pot\\",\\"repositoryName\\":\\"sourcecred/eventide\\",\\"type\\":\\"FOOD\\"}": Object { "payload": Object { "effect": Array [ "attack_power", diff --git a/src/core/graph.test.js b/src/core/graph.test.js index 60b182a..6089a2b 100644 --- a/src/core/graph.test.js +++ b/src/core/graph.test.js @@ -133,7 +133,7 @@ describe("graph", () => { expect( demoData .simpleMealGraph() - .getNode(demoData.makeAddress("treasure_octorok#5")) + .getNode(demoData.makeAddress("treasure_octorok#5", "NPC")) ).toBeUndefined(); }); @@ -143,7 +143,8 @@ describe("graph", () => { .simpleMealGraph() .getNode( demoData.makeAddress( - "treasure_octorok#5@helps_cook@seafood_fruit_mix#3" + "treasure_octorok#5@helps_cook@seafood_fruit_mix#3", + "ACTION" ) ) ).toBeUndefined(); @@ -180,10 +181,11 @@ describe("graph", () => { it("allows adding an edge with dangling `dst`", () => { const edge = () => ({ address: demoData.makeAddress( - "treasure_octorok#5@helps_cook@seafood_fruit_mix#3" + "treasure_octorok#5@helps_cook@seafood_fruit_mix#3", + "ACTION" ), src: demoData.mealNode().address, - dst: demoData.makeAddress("treasure_octorok#5"), + dst: demoData.makeAddress("treasure_octorok#5", "NPC"), payload: {}, }); const g = demoData.simpleMealGraph().addEdge(edge()); @@ -193,9 +195,10 @@ describe("graph", () => { it("allows adding an edge with dangling `src`", () => { const edge = () => ({ address: demoData.makeAddress( - "health_bar#6@healed_by@seafood_fruit_mix#3" + "health_bar#6@healed_by@seafood_fruit_mix#3", + "PLAYER_EFFECT" ), - src: demoData.makeAddress("health_bar#6"), + src: demoData.makeAddress("health_bar#6", "PLAYER_STATE"), dst: demoData.mealNode().address, payload: {}, }); @@ -365,24 +368,24 @@ describe("graph", () => { it("gets empty out-edges for a nonexistent node", () => { const result = demoData .simpleMealGraph() - .getOutEdges(demoData.makeAddress("hinox")); + .getOutEdges(demoData.makeAddress("hinox", "NPC")); expect(result).toEqual([]); }); it("gets empty in-edges for a nonexistent node", () => { const result = demoData .simpleMealGraph() - .getInEdges(demoData.makeAddress("hinox")); + .getInEdges(demoData.makeAddress("hinox", "NPC")); expect(result).toEqual([]); }); { const danglingSrc = () => ({ - address: demoData.makeAddress("meaty_rice_balls#8"), + address: demoData.makeAddress("meaty_rice_balls#8", "FOOD"), payload: {meaty: true}, }); const danglingDst = () => ({ - address: demoData.makeAddress("treasure_octorok#5"), + address: demoData.makeAddress("treasure_octorok#5", "NPC"), payload: {meaty: false}, }); @@ -390,7 +393,8 @@ describe("graph", () => { // demo meal graph. const fullyDanglingEdge = () => ({ address: demoData.makeAddress( - "treasure_octorok#5@helps_cook@meaty_rice_balls#8" + "treasure_octorok#5@helps_cook@meaty_rice_balls#8", + "ACTION" ), src: danglingSrc().address, dst: danglingDst().address, @@ -526,11 +530,11 @@ describe("graph", () => { ).toBe(false); }); const extraNode1 = () => ({ - address: demoData.makeAddress("octorok"), + address: demoData.makeAddress("octorok", "NPC"), payload: {}, }); const extraNode2 = () => ({ - address: demoData.makeAddress("hinox"), + address: demoData.makeAddress("hinox", "NPC"), payload: {status: "sleeping"}, }); it("returns false when the LHS has edges missing in the RHS", () => { @@ -626,20 +630,32 @@ describe("graph", () => { it("conservatively merges graphs of different payload types", () => { const data = { - a: () => ({address: demoData.makeAddress("a"), payload: "alpha"}), - b: () => ({address: demoData.makeAddress("b"), payload: "bravo"}), + a: () => ({ + address: demoData.makeAddress("a", "EXPERIMENT"), + payload: "alpha", + }), + b: () => ({ + address: demoData.makeAddress("b", "EXPERIMENT"), + payload: "bravo", + }), u: () => ({ - address: demoData.makeAddress("u"), - src: demoData.makeAddress("a"), - dst: demoData.makeAddress("b"), + address: demoData.makeAddress("u", "EXPERIMENT"), + src: demoData.makeAddress("a", "EXPERIMENT"), + dst: demoData.makeAddress("b", "EXPERIMENT"), payload: 21, }), - c: () => ({address: demoData.makeAddress("c"), payload: true}), - d: () => ({address: demoData.makeAddress("d"), payload: false}), + c: () => ({ + address: demoData.makeAddress("c", "EXPERIMENT"), + payload: true, + }), + d: () => ({ + address: demoData.makeAddress("d", "EXPERIMENT"), + payload: false, + }), v: () => ({ - address: demoData.makeAddress("v"), - src: demoData.makeAddress("c"), - dst: demoData.makeAddress("d"), + address: demoData.makeAddress("v", "EXPERIMENT"), + src: demoData.makeAddress("c", "EXPERIMENT"), + dst: demoData.makeAddress("d", "EXPERIMENT"), payload: null, }), }; @@ -666,7 +682,7 @@ describe("graph", () => { it("conservatively rejects a graph with conflicting nodes", () => { const makeGraph: (nodePayload: string) => Graph<*, *> = (nodePayload) => new Graph().addNode({ - address: demoData.makeAddress("conflicting-node"), + address: demoData.makeAddress("conflicting-node", "EXPERIMENT"), payload: nodePayload, }); const g1 = makeGraph("one"); @@ -677,14 +693,14 @@ describe("graph", () => { }); it("conservatively rejects a graph with conflicting edges", () => { - const srcAddress = demoData.makeAddress("src"); - const dstAddress = demoData.makeAddress("dst"); + const srcAddress = demoData.makeAddress("src", "EXPERIMENT"); + const dstAddress = demoData.makeAddress("dst", "EXPERIMENT"); const makeGraph: (edgePayload: string) => Graph<*, *> = (edgePayload) => new Graph() .addNode({address: srcAddress, payload: {}}) .addNode({address: dstAddress, payload: {}}) .addEdge({ - address: demoData.makeAddress("conflicting-edge"), + address: demoData.makeAddress("conflicting-edge", "EXPERIMENT"), src: srcAddress, dst: dstAddress, payload: edgePayload, @@ -775,11 +791,11 @@ describe("graph", () => { it("allows adding explicitly typed nodes", () => { expect(() => { const stringNode: Node = { - address: demoData.makeAddress("hello"), + address: demoData.makeAddress("hello", "EXPERIMENT"), payload: "hello", }; const numberNode: Node = { - address: demoData.makeAddress("hello"), + address: demoData.makeAddress("hello", "EXPERIMENT"), payload: 17, }; // This will be a Graph. @@ -789,16 +805,22 @@ describe("graph", () => { it("allows adding explicitly typed edges", () => { expect(() => { - const src = {address: demoData.makeAddress("src"), payload: {}}; - const dst = {address: demoData.makeAddress("dst"), payload: {}}; + const src = { + address: demoData.makeAddress("src", "EXPERIMENT"), + payload: {}, + }; + const dst = { + address: demoData.makeAddress("dst", "EXPERIMENT"), + payload: {}, + }; const stringEdge: Edge = { - address: demoData.makeAddress("hello"), + address: demoData.makeAddress("hello", "EXPERIMENT"), src: src.address, dst: dst.address, payload: "hello", }; const numberEdge: Edge = { - address: demoData.makeAddress("hello"), + address: demoData.makeAddress("hello", "EXPERIMENT"), src: src.address, dst: dst.address, payload: 18, @@ -818,7 +840,7 @@ describe("graph", () => { const g1 = demoData.advancedMealGraph(); const g2 = g1.copy(); const newNode = () => ({ - address: demoData.makeAddress("brand-new"), + address: demoData.makeAddress("brand-new", "EXPERIMENT"), payload: 777, }); g2.addNode(newNode()); diff --git a/src/core/graphDemoData.js b/src/core/graphDemoData.js index 3ec7a09..8eeabb4 100644 --- a/src/core/graphDemoData.js +++ b/src/core/graphDemoData.js @@ -7,46 +7,46 @@ import type {Address} from "./address"; import {Graph} from "./graph"; -export function makeAddress(id: string): Address { +export function makeAddress(id: string, type: string): Address { return { repositoryName: "sourcecred/eventide", pluginName: "hill_cooking_pot", - type: "demoType", id, + type, }; } export const heroNode = () => ({ - address: makeAddress("hero_of_time#0"), + address: makeAddress("hero_of_time#0", "PC"), payload: {}, }); export const bananasNode = () => ({ - address: makeAddress("mighty_bananas#1"), + address: makeAddress("mighty_bananas#1", "FOOD"), payload: {}, }); export const crabNode = () => ({ - address: makeAddress("razorclaw_crab#2"), + address: makeAddress("razorclaw_crab#2", "FOOD"), payload: {}, }); export const mealNode = () => ({ - address: makeAddress("seafood_fruit_mix#3"), + address: makeAddress("seafood_fruit_mix#3", "FOOD"), payload: { effect: ["attack_power", 1], }, }); export const pickEdge = () => ({ - address: makeAddress("hero_of_time#0@picks@mighty_bananas#1"), + address: makeAddress("hero_of_time#0@picks@mighty_bananas#1", "ACTION"), src: bananasNode().address, dst: heroNode().address, payload: {}, }); export const grabEdge = () => ({ - address: makeAddress("hero_of_time#0@grabs@razorclaw_crab#2"), + address: makeAddress("hero_of_time#0@grabs@razorclaw_crab#2", "ACTION"), src: crabNode().address, dst: heroNode().address, payload: {}, }); export const cookEdge = () => ({ - address: makeAddress("hero_of_time#0@cooks@seafood_fruit_mix#3"), + address: makeAddress("hero_of_time#0@cooks@seafood_fruit_mix#3", "ACTION"), src: mealNode().address, dst: heroNode().address, payload: { @@ -54,19 +54,25 @@ export const cookEdge = () => ({ }, }); export const bananasIngredientEdge = () => ({ - address: makeAddress("mighty_bananas#1@included_in@seafood_fruit_mix#3"), + address: makeAddress( + "mighty_bananas#1@included_in@seafood_fruit_mix#3", + "INGREDIENT" + ), src: mealNode().address, dst: bananasNode().address, payload: {}, }); export const crabIngredientEdge = () => ({ - address: makeAddress("razorclaw_crab#2@included_in@seafood_fruit_mix#3"), + address: makeAddress( + "razorclaw_crab#2@included_in@seafood_fruit_mix#3", + "INGREDIENT" + ), src: mealNode().address, dst: crabNode().address, payload: {}, }); export const eatEdge = () => ({ - address: makeAddress("hero_of_time#0@eats@seafood_fruit_mix#3"), + address: makeAddress("hero_of_time#0@eats@seafood_fruit_mix#3", "ACTION"), src: heroNode().address, dst: mealNode().address, payload: {}, @@ -85,14 +91,17 @@ export const simpleMealGraph = () => .addEdge(eatEdge()); export const crabLoopEdge = () => ({ - address: makeAddress("crab-self-assessment"), + address: makeAddress("crab-self-assessment", "SILLY"), src: crabNode().address, dst: crabNode().address, payload: {evaluation: "not effective at avoiding hero"}, }); export const duplicateCookEdge = () => ({ - address: makeAddress("hero_of_time#0@again_cooks@seafood_fruit_mix#3"), + address: makeAddress( + "hero_of_time#0@again_cooks@seafood_fruit_mix#3", + "ACTION" + ), src: mealNode().address, dst: heroNode().address, payload: {