|  |  | 
|  | /* | 
|  | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | * or more contributor license agreements.  See the NOTICE file | 
|  | * distributed with this work for additional information | 
|  | * regarding copyright ownership.  The ASF licenses this file | 
|  | * to you under the Apache License, Version 2.0 (the | 
|  | * "License"); you may not use this file except in compliance | 
|  | * with the License.  You may obtain a copy of the License at | 
|  | * | 
|  | *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied.  See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | */ | 
|  |  | 
|  | import ComponentModel, { ComponentModelConstructor } from '@/src/model/Component'; | 
|  | import { ComponentMainType } from '@/src/util/types'; | 
|  |  | 
|  | const componentModelConstructor = ComponentModel as ComponentModelConstructor; | 
|  |  | 
|  | function extendModel(type: string, dependencies?: string[]) { | 
|  | class SubModel extends ComponentModel { | 
|  | static type: string = type; | 
|  | type: string = type; | 
|  | static dependencies = dependencies || []; | 
|  | }; | 
|  | ComponentModel.registerClass(SubModel); | 
|  | return SubModel; | 
|  | } | 
|  |  | 
|  | describe('componentDependency', function () { | 
|  |  | 
|  | let idx = 0; | 
|  |  | 
|  | function makeTypes(count: number): string[] { | 
|  | const arr = []; | 
|  | for (let i = 0; i < count; i++) { | 
|  | arr.push('type_' + idx++); | 
|  | } | 
|  | return arr; | 
|  | } | 
|  |  | 
|  | type TopoResultItem = [ComponentMainType, ComponentMainType[]]; | 
|  |  | 
|  | it('topologicalTravel_base', function () { | 
|  | const [m1, a1, a2] = makeTypes(3); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a1); | 
|  | extendModel(a2); | 
|  | const result: TopoResultItem[] = []; | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a1, a2], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a2, ['dataset']], [a1, ['dataset']], [m1, ['dataset', a1, a2]]]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_a1IsAbsent', function () { | 
|  | const [m1, a1, a2] = makeTypes(3); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a2); | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | const result: TopoResultItem[] = []; | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a2], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a2, ['dataset']], [m1, ['dataset', a1, a2]]]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_empty', function () { | 
|  | const [m1, a1, a2] = makeTypes(3); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a1); | 
|  | extendModel(a2); | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | const result: TopoResultItem[] = []; | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_isolate', function () { | 
|  | const [m1, a1, a2] = makeTypes(3); | 
|  | extendModel(a2); | 
|  | extendModel(a1); | 
|  | extendModel(m1, [a2]); | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | const result: TopoResultItem[] = []; | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [a1, a2, m1], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a1, ['dataset']], [a2, ['dataset']], [m1, ['dataset', a2]]]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_diamond', function () { | 
|  | const [m1, a1, a2, a3] = makeTypes(4); | 
|  | extendModel(a1, []); | 
|  | extendModel(a2, [a1]); | 
|  | extendModel(a3, [a1]); | 
|  | extendModel(m1, [a2, a3]); | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | const result: TopoResultItem[] = []; | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a1, a2, a3], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual( | 
|  | [[a1, ['dataset']], | 
|  | [a3, ['dataset', a1]], | 
|  | [a2, ['dataset', a1]], | 
|  | [m1, ['dataset', a2, a3]] | 
|  | ]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_loop', function () { | 
|  | const [m1, m2, a1, a2, a3] = makeTypes(5); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(m2, [m1, a2]); | 
|  | extendModel(a1, [m2, a2, a3]); | 
|  | extendModel(a2); | 
|  | extendModel(a3); | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | expect(function () { | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, m2, a1], | 
|  | allList, | 
|  | () => {} | 
|  | ); | 
|  | }).toThrowError(/Circular/); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_multipleEchartsInstance', function () { | 
|  | const [m1, m2, a1, a2] = makeTypes(4); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a1); | 
|  | extendModel(a2); | 
|  | let allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | let result: TopoResultItem[] = []; | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a1, a2], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a2, ['dataset']], [a1, ['dataset']], [m1, ['dataset', a1, a2]]]); | 
|  |  | 
|  | result = []; | 
|  | extendModel(m2, [a1, m1]); | 
|  | allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m2, m1, a1, a2], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual( | 
|  | [[a2, ['dataset']], [a1, ['dataset']], [m1, ['dataset', a1, a2]], [m2, ['dataset', a1, m1]]] | 
|  | ); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_missingSomeNodeButHasDependencies', function () { | 
|  | const [m1, a1, a2, a3, a4] = makeTypes(5); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a2, [a3]); | 
|  | extendModel(a3); | 
|  | extendModel(a4); | 
|  | let result: TopoResultItem[] = []; | 
|  | let allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [a3, m1], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a3, ['dataset']], [a2, ['dataset', a3]], [m1, ['dataset', a1, a2]]]); | 
|  | result = []; | 
|  | allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a3], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual([[a3, ['dataset']], [a2, ['dataset', a3]], [m1, ['dataset', a1, a2]]]); | 
|  | }); | 
|  |  | 
|  | it('topologicalTravel_subType', function () { | 
|  | const [m1, a1, a2, a3, a4] = makeTypes(5); | 
|  | extendModel(m1, [a1, a2]); | 
|  | extendModel(a1 + '.aaa', [a2]); | 
|  | extendModel(a1 + '.bbb', [a3, a4]); | 
|  | extendModel(a2); | 
|  | extendModel(a3); | 
|  | extendModel(a4); | 
|  | const result: TopoResultItem[] = []; | 
|  | const allList = componentModelConstructor.getAllClassMainTypes(); | 
|  | componentModelConstructor.topologicalTravel( | 
|  | [m1, a1, a2, a4], | 
|  | allList, | 
|  | function (componentType, dependencies) { | 
|  | result.push([componentType, dependencies]); | 
|  | } | 
|  | ); | 
|  | expect(result).toEqual( | 
|  | [[a4, ['dataset']], | 
|  | [a2, ['dataset']], | 
|  | [a1, ['dataset', a2, a3, a4]], | 
|  | [m1, ['dataset', a1, a2]] | 
|  | ]); | 
|  | }); | 
|  | }); |