From fcec29f32cce6f674571f36004cd586a65a5be10 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 20:08:25 +0800 Subject: [PATCH] [graph test] edge cases enriched --- src/data-structures/graph/abstract-graph.ts | 12 +-- src/data-structures/graph/directed-graph.ts | 6 +- src/data-structures/graph/undirected-graph.ts | 6 +- src/interfaces/graph.ts | 2 +- .../graph/abstract-graph.test.ts | 101 +++++++++++++++++- .../graph/directed-graph.test.ts | 10 ++ .../graph/undirected-graph.test.ts | 8 ++ 7 files changed, 130 insertions(+), 15 deletions(-) diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 5b0aa79..6005bcc 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -45,7 +45,7 @@ export abstract class AbstractVertex { } } -export abstract class AbstractEdge { +export abstract class AbstractEdge { /** * The above function is a protected constructor that initializes the weight, value, and hash code properties of an * object. @@ -55,19 +55,19 @@ export abstract class AbstractEdge { * @param {VO} [val] - The `val` parameter is of type `VO`, which means it can be any type. It is an optional parameter, * meaning it can be omitted when creating an instance of the class. */ - protected constructor(weight?: number, val?: VO) { + protected constructor(weight?: number, val?: E) { this._weight = weight !== undefined ? weight : 1; this._val = val; this._hashCode = uuidV4(); } - private _val: VO | undefined; + private _val: E | undefined; - get val(): VO | undefined { + get val(): E | undefined { return this._val; } - set val(value: VO | undefined) { + set val(value: E | undefined) { this._val = value; } @@ -131,7 +131,7 @@ export abstract class AbstractGraph< * @param weight * @param val */ - abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; + abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; abstract deleteEdge(edge: EO): EO | null; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 32e522d..b3072a7 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -129,13 +129,13 @@ export class DirectedGraph< /** * The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs. - * @param {VO | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. - * @param {VO | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the + * @param {VO | VertexKey | null} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. + * @param {VO | VertexKey | null} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the * destination vertex of the edge. It can be either a vertex object (`VO`), a vertex ID (`VertexKey`), or `null` if the * destination is not specified. * @returns the first edge found between the source and destination vertices, or null if no such edge is found. */ - getEdge(srcOrKey: VO | null | VertexKey, destOrKey: VO | null | VertexKey): EO | null { + getEdge(srcOrKey: VO | VertexKey | null, destOrKey: VO | VertexKey | null): EO | null { let edges: EO[] = []; if (srcOrKey !== null && destOrKey !== null) { diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 7adeb28..85a7e0b 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -102,13 +102,13 @@ export class UndirectedGraph< /** * The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists. - * @param {VO | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex + * @param {VO | VertexKey | null} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (a string or number representing the ID of a vertex). - * @param {VO | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex + * @param {VO | VertexKey | null} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (vertex ID). * @returns an edge (EO) or null. */ - getEdge(v1: VO | null | VertexKey, v2: VO | null | VertexKey): EO | null { + getEdge(v1: VO | VertexKey | null, v2: VO | VertexKey | null): EO | null { let edges: EO[] | undefined = []; if (v1 !== null && v2 !== null) { diff --git a/src/interfaces/graph.ts b/src/interfaces/graph.ts index eae6ae9..7b968ae 100644 --- a/src/interfaces/graph.ts +++ b/src/interfaces/graph.ts @@ -3,5 +3,5 @@ import {VertexKey} from '../types'; export interface IGraph { createVertex(key: VertexKey, val?: V): VO; - createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; } diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index 8b2fb42..efd2250 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -1,5 +1,102 @@ +import {AbstractEdge, AbstractGraph, AbstractVertex, VertexKey} from '../../../../src'; + +class MyVertex extends AbstractVertex { + data?: V; + + constructor(key: VertexKey, val?: V) { + super(key, val); + this.data = val; + } +} + +class MyEdge extends AbstractEdge { + data?: E; + src: VertexKey; + dest: VertexKey; + + constructor(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E) { + super(weight, val); + this.src = srcOrV1; + this.dest = destOrV2; + this.data = val; + this._setHashCode(''); + } +} + +class MyGraph< + V = any, + E = any, + VO extends MyVertex = MyVertex, + EO extends MyEdge = MyEdge +> extends AbstractGraph { + createVertex(key: VertexKey, val?: V): VO { + return new MyVertex(key, val) as VO; + } + + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO { + return new MyEdge(srcOrV1, destOrV2, weight, val) as EO; + } + + deleteEdge(edge: EO): EO | null { + return edge; + } + + getEdge(srcOrKey: VertexKey, destOrKey: VertexKey): EO | null { + return new MyEdge(srcOrKey, destOrKey) as EO; + } + + degreeOf(vertexOrKey: VO | VertexKey): number { + return 1 ?? Number(vertexOrKey); + } + + edgeSet(): EO[] { + return [new MyEdge('a', 'b') as EO]; + } + + edgesOf(vertexOrKey: VO | VertexKey): EO[] { + const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + return [new MyEdge(a, 'b') as EO]; + } + + getNeighbors(vertexOrKey: VO | VertexKey): VO[] { + const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + return [new MyVertex(a, 'b') as VO]; + } + + getEndsOfEdge(edge: EO): [VO, VO] | null { + return edge ? null : null; + } + + protected _addEdgeOnly(edge: EO): boolean { + return edge ? true : true; + } +} + describe('AbstractGraph Operation Test', () => { - it('should xxx', function () { - expect(true).toBe(true); + const myGraph: MyGraph = new MyGraph(); + + beforeEach(() => { + }); + it('should edge cases', function () { + myGraph.addVertex('A', 1); + myGraph.addVertex('B', 2); + myGraph.addVertex('C', 3); + myGraph.addVertex('D', 4); + + const vA = myGraph.getVertex('A'); + // const vB = myGraph.getVertex('B'); + // const vC = myGraph.getVertex('C'); + // const vD = myGraph.getVertex('D'); + + const eAB = new MyEdge('A', 'B'); + // const eBC = new MyEdge('B', 'C'); + // const eCD = new MyEdge('C', 'D'); + vA!.key = vA?.key || 1; + vA!.val = vA?.val ?? 2; + + eAB!.val = eAB.val; + const hs = eAB.hashCode; + + expect(hs).toBe(''); }); }); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index fdb90f2..9b2c2a4 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -139,6 +139,14 @@ class MyDirectedGraph< createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { return new MyEdge(src, dest, weight ?? 1, val) as EO; } + + setInEdgeMap(value: Map) { + super._setInEdgeMap(value); + } + + setOutEdgeMap(value: Map) { + super._setOutEdgeMap(value); + } } describe('Inherit from DirectedGraph and perform operations', () => { @@ -164,6 +172,8 @@ describe('Inherit from DirectedGraph and perform operations', () => { myGraph.addVertex(2, 'data2'); myGraph.addEdge(1, 2, 10, 'edge-data1-2'); myGraph.addEdge(new MyEdge(2, 1, 20, 'edge-data2-1')); + myGraph.setInEdgeMap(myGraph.inEdgeMap); + myGraph.setOutEdgeMap(myGraph.outEdgeMap); expect(myGraph.edgeSet().length).toBe(2); // TODO diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 622f29f..e8129cb 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -7,6 +7,14 @@ describe('UndirectedGraph Operation Test', () => { graph = new UndirectedGraph(); }); + it('should edge cases', () => { + expect(graph.deleteEdge(new UndirectedEdge('c', 'd'))).toBe(null); + expect(graph.deleteEdgeBetween('c', 'd')).toBe(null); + expect(graph.degreeOf('c')).toBe(0); + expect(graph.edgesOf('c').length).toBe(0); + expect(graph.getEndsOfEdge(new UndirectedEdge('c', 'd'))).toBe(null); + }); + it('should add vertices', () => { const vertex1 = new UndirectedVertex('A'); const vertex2 = new UndirectedVertex('B');