Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
强哥很慌张
Echarts
提交
3ad08d4e
E
Echarts
项目概览
强哥很慌张
/
Echarts
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
Echarts
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3ad08d4e
编写于
10月 17, 2020
作者:
1
100pah
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: tweak list id name generation rule (avoid some potential flaw) and add test cases.
上级
1f71fadc
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
491 addition
and
125 deletion
+491
-125
src/data/List.ts
src/data/List.ts
+112
-111
src/data/helper/dataProvider.ts
src/data/helper/dataProvider.ts
+13
-6
src/util/model.ts
src/util/model.ts
+3
-0
test/ut/spec/data/List.test.ts
test/ut/spec/data/List.test.ts
+363
-8
未找到文件。
src/data/List.ts
浏览文件 @
3ad08d4e
...
...
@@ -34,7 +34,7 @@ import Element from 'zrender/src/Element';
import
{
DimensionIndex
,
DimensionName
,
DimensionLoose
,
OptionDataItem
,
ParsedValue
,
ParsedValueNumeric
,
OrdinalNumber
,
DimensionUserOuput
,
ModelOption
,
SeriesDataType
,
O
rdinalRawValue
ModelOption
,
SeriesDataType
,
O
ptionSourceData
,
SOURCE_FORMAT_TYPED_ARRAY
,
SOURCE_FORMAT_ORIGINAL
}
from
'
../util/types
'
;
import
{
isDataItemOption
,
convertOptionIdName
}
from
'
../util/model
'
;
import
{
getECData
}
from
'
../util/innerStore
'
;
...
...
@@ -43,7 +43,8 @@ import type Graph from './Graph';
import
type
Tree
from
'
./Tree
'
;
import
type
{
VisualMeta
}
from
'
../component/visualMap/VisualMapModel
'
;
import
{
parseDataValue
}
from
'
./helper/dataValueHelper
'
;
import
{
isSourceInstance
}
from
'
./Source
'
;
import
{
isSourceInstance
,
Source
}
from
'
./Source
'
;
import
OrdinalMeta
from
'
./OrdinalMeta
'
;
const
mathFloor
=
Math
.
floor
;
const
isObject
=
zrUtil
.
isObject
;
...
...
@@ -160,15 +161,15 @@ export interface DataCalculationInfo<SERIES_MODEL> {
// -----------------------------
let
defaultDimValueGetters
:
{[
sourceFormat
:
string
]:
DimValueGetter
};
let
prepareInvertedIndex
:
(
list
:
List
)
=>
void
;
let
getRawValueFromStore
:
(
list
:
List
,
dimIndex
:
number
,
rawIndex
:
number
)
=>
ParsedValue
|
OrdinalRawValue
;
let
getIndicesCtor
:
(
list
:
List
)
=>
DataArrayLikeConstructor
;
let
prepareStorage
:
(
storage
:
DataStorage
,
dimInfo
:
DataDimensionInfo
,
end
:
number
,
append
?:
boolean
)
=>
void
;
let
getRawIndexWithoutIndices
:
(
this
:
List
,
idx
:
number
)
=>
number
;
let
getRawIndexWithIndices
:
(
this
:
List
,
idx
:
number
)
=>
number
;
let
getIdFromName
:
(
list
:
List
,
name
:
string
)
=>
string
;
let
getId
:
(
list
:
List
,
rawIndex
:
number
)
=>
string
;
let
getIdNameFromStore
:
(
list
:
List
,
dimIdx
:
number
,
ordinalMeta
:
OrdinalMeta
,
rawIndex
:
number
)
=>
string
;
let
makeIdFromName
:
(
list
:
List
,
idx
:
number
)
=>
void
;
let
normalizeDimensions
:
(
dimensions
:
ItrParamDims
)
=>
Array
<
DimensionLoose
>
;
let
validateDimensions
:
(
list
:
List
,
dims
:
DimensionName
[])
=>
void
;
let
cloneListForMapAndSample
:
(
original
:
List
,
excludeDimensions
:
DimensionName
[])
=>
List
;
...
...
@@ -176,6 +177,7 @@ let getInitialExtent: () => [number, number];
let
setItemDataAndSeriesIndex
:
(
this
:
Element
,
child
:
Element
)
=>
void
;
let
transferProperties
:
(
target
:
List
,
source
:
List
)
=>
void
;
class
List
<
HostModel
extends
Model
=
Model
,
Visual
extends
DefaultDataVisual
=
DefaultDataVisual
...
...
@@ -267,7 +269,10 @@ class List<
// avoid clone them too many times.
readonly
userOutput
:
DimensionUserOuput
;
// If each data item has it's own option
// Having detected that there is data item is non primitive type
// (in type `OptionDataItemObject`).
// Like `data: [ { value: xx, itemStyle: {...} }, ...]`
// At present it only happen in `SOURCE_FORMAT_ORIGINAL`.
hasItemOption
:
boolean
=
true
;
// @readonly
...
...
@@ -275,9 +280,14 @@ class List<
private
_dimValueGetter
:
DimValueGetter
;
private
_dimValueGetterArrayRows
:
DimValueGetter
;
// id or name is used on dynamic data, mapping old and new items.
// When generating id from name, avoid repeat.
private
_nameRepeatCount
:
NameRepeatCount
;
private
_nameDimIdx
:
number
;
private
_nameOrdinalMeta
:
OrdinalMeta
;
private
_idDimIdx
:
number
;
private
_idOrdinalMeta
:
OrdinalMeta
;
private
_dontMakeIdFromName
:
boolean
;
private
__wrappedMethods
:
string
[];
...
...
@@ -318,7 +328,7 @@ class List<
dimensionInfo
.
coordDimIndex
=
0
;
}
dimensionInfo
.
otherDims
=
dimensionInfo
.
otherDims
||
{};
const
otherDims
=
dimensionInfo
.
otherDims
=
dimensionInfo
.
otherDims
||
{};
dimensionNames
.
push
(
dimensionName
);
dimensionInfos
[
dimensionName
]
=
dimensionInfo
;
...
...
@@ -327,6 +337,14 @@ class List<
if
(
dimensionInfo
.
createInvertedIndices
)
{
invertedIndicesMap
[
dimensionName
]
=
[];
}
if
(
otherDims
.
itemName
===
0
)
{
this
.
_nameDimIdx
=
i
;
this
.
_nameOrdinalMeta
=
dimensionInfo
.
ordinalMeta
;
}
if
(
otherDims
.
itemId
===
0
)
{
this
.
_idDimIdx
=
i
;
this
.
_idOrdinalMeta
=
dimensionInfo
.
ordinalMeta
;
}
}
this
.
dimensions
=
dimensionNames
;
...
...
@@ -417,39 +435,45 @@ class List<
/**
* Initialize from data
* @param data source or data or data provider.
* @param nameL
I
st The name of a datum is used on data diff and
* @param nameL
i
st The name of a datum is used on data diff and
* default label/tooltip.
* A name can be specified in encode.itemName,
* or dataItem.name (only for series option data),
* or provided in nameList from outside.
*/
initData
(
data
:
any
,
data
:
Source
|
OptionSourceData
|
DataProvider
,
nameList
?:
string
[],
dimValueGetter
?:
DimValueGetter
):
void
{
const
notProvider
=
isSourceInstance
(
data
)
||
zrUtil
.
isArrayLike
(
data
);
if
(
notProvider
)
{
data
=
new
DefaultDataProvider
(
data
,
this
.
dimensions
.
length
);
}
const
provider
:
DataProvider
=
notProvider
?
new
DefaultDataProvider
(
data
as
Source
|
OptionSourceData
,
this
.
dimensions
.
length
)
:
data
as
DataProvider
;
if
(
__DEV__
)
{
if
(
!
notProvider
&&
(
typeof
data
.
getItem
!==
'
function
'
||
typeof
data
.
count
!==
'
function
'
)
)
{
throw
new
Error
(
'
Inavlid data provider.
'
);
}
zrUtil
.
assert
(
notProvider
||
(
zrUtil
.
isFunction
(
provider
.
getItem
)
&&
zrUtil
.
isFunction
(
provider
.
count
)
),
'
Inavlid data provider.
'
);
}
this
.
_rawData
=
data
;
this
.
_rawData
=
provider
;
const
sourceFormat
=
provider
.
getSource
().
sourceFormat
;
// Clear
this
.
_storage
=
{};
this
.
_indices
=
null
;
this
.
_dontMakeIdFromName
=
this
.
_idDimIdx
!=
null
||
sourceFormat
===
SOURCE_FORMAT_TYPED_ARRAY
// Cosndier performance.
||
!!
provider
.
fillStorage
;
this
.
_nameList
=
nameList
||
[];
this
.
_nameList
=
(
nameList
||
[]).
slice
();
this
.
_idList
=
[];
this
.
_nameRepeatCount
=
{};
...
...
@@ -458,9 +482,7 @@ class List<
this
.
hasItemOption
=
false
;
}
this
.
defaultDimValueGetter
=
defaultDimValueGetters
[
this
.
_rawData
.
getSource
().
sourceFormat
];
this
.
defaultDimValueGetter
=
defaultDimValueGetters
[
sourceFormat
];
// Default dim value getter
this
.
_dimValueGetter
=
dimValueGetter
=
dimValueGetter
||
this
.
defaultDimValueGetter
;
...
...
@@ -469,10 +491,10 @@ class List<
// Reset raw extent.
this
.
_rawExtent
=
{};
this
.
_initDataFromProvider
(
0
,
data
.
count
());
this
.
_initDataFromProvider
(
0
,
provider
.
count
());
// If data has no item option.
if
(
data
.
pure
)
{
if
(
provider
.
pure
)
{
this
.
hasItemOption
=
false
;
}
}
...
...
@@ -557,6 +579,9 @@ class List<
if
(
names
)
{
this
.
_nameList
[
idx
]
=
names
[
sourceIdx
];
if
(
!
this
.
_dontMakeIdFromName
)
{
makeIdFromName
(
this
,
idx
);
}
}
}
...
...
@@ -581,24 +606,15 @@ class List<
const
nameList
=
this
.
_nameList
;
const
idList
=
this
.
_idList
;
const
rawExtent
=
this
.
_rawExtent
;
this
.
_nameRepeatCount
=
{}
;
let
nameDimIdx
;
const
sourceFormat
=
rawData
.
getSource
().
sourceFormat
;
const
isFormatOriginal
=
sourceFormat
===
SOURCE_FORMAT_ORIGINAL
;
for
(
let
i
=
0
;
i
<
dimLen
;
i
++
)
{
const
dim
=
dimensions
[
i
];
if
(
!
rawExtent
[
dim
])
{
rawExtent
[
dim
]
=
getInitialExtent
();
}
const
dimInfo
=
dimensionInfoMap
[
dim
];
if
(
dimInfo
.
otherDims
.
itemName
===
0
)
{
nameDimIdx
=
this
.
_nameDimIdx
=
i
;
}
if
(
dimInfo
.
otherDims
.
itemId
===
0
)
{
this
.
_idDimIdx
=
i
;
}
prepareStorage
(
storage
,
dimInfo
,
end
,
append
);
prepareStorage
(
storage
,
dimensionInfoMap
[
dim
],
end
,
append
);
}
const
storageArr
=
this
.
_storageArr
=
map
(
dimensions
,
(
dim
)
=>
{
...
...
@@ -637,46 +653,25 @@ class List<
val
>
dimRawExtent
[
1
]
&&
(
dimRawExtent
[
1
]
=
val
);
}
// ??? FIXME not check by pure but sourceFormat?
// TODO refactor these logic.
if
(
!
rawData
.
pure
)
{
let
name
:
string
=
nameList
[
idx
];
if
(
dataItem
&&
name
==
null
)
{
// If dataItem is {name: ...}, it has highest priority.
// That is appropriate for many common cases.
if
((
dataItem
as
any
).
name
!=
null
)
{
// There is no other place to persistent dataItem.name,
// so save it to nameList.
nameList
[
idx
]
=
name
=
convertOptionIdName
((
dataItem
as
any
).
name
,
null
);
}
else
if
(
nameDimIdx
!=
null
)
{
const
nameDim
=
dimensions
[
nameDimIdx
];
const
nameDimChunk
=
storage
[
nameDim
];
if
(
nameDimChunk
)
{
const
ordinalMeta
=
dimensionInfoMap
[
nameDim
].
ordinalMeta
;
name
=
convertOptionIdName
(
(
ordinalMeta
&&
ordinalMeta
.
categories
.
length
)
?
ordinalMeta
.
categories
[
nameDimChunk
[
idx
]
as
number
]
:
nameDimChunk
[
idx
],
null
);
}
}
// If dataItem is {name: ...} or {id: ...}, it has highest priority.
// This kind of ids and names are always stored `_nameList` and `_idList`.
if
(
isFormatOriginal
&&
!
rawData
.
pure
&&
dataItem
)
{
const
itemName
=
(
dataItem
as
any
).
name
;
if
(
nameList
[
idx
]
==
null
&&
itemName
!=
null
)
{
nameList
[
idx
]
=
convertOptionIdName
(
itemName
,
null
);
}
// Try using the id in option
// id or name is used on dynamical data, mapping old and new items.
let
id
:
string
=
dataItem
==
null
?
null
:
convertOptionIdName
((
dataItem
as
any
).
id
,
null
);
if
(
id
==
null
&&
name
!=
null
)
{
// Use name as id and add counter to avoid same name
id
=
getIdFromName
(
this
,
name
);
const
itemId
=
(
dataItem
as
any
).
id
;
if
(
idList
[
idx
]
==
null
&&
itemId
!=
null
)
{
idList
[
idx
]
=
convertOptionIdName
(
itemId
,
null
);
}
id
!=
null
&&
(
idList
[
idx
]
=
id
);
}
if
(
!
this
.
_dontMakeIdFromName
)
{
makeIdFromName
(
this
,
idx
);
}
}
}
if
(
!
rawData
.
persistent
&&
rawData
.
clean
)
{
// Clean unused data if data source is typed array.
rawData
.
clean
();
...
...
@@ -1132,9 +1127,14 @@ class List<
*/
getName
(
idx
:
number
):
string
{
const
rawIndex
=
this
.
getRawIndex
(
idx
);
return
this
.
_nameList
[
rawIndex
]
||
convertOptionIdName
(
getRawValueFromStore
(
this
,
this
.
_nameDimIdx
,
rawIndex
),
''
)
||
''
;
let
name
=
this
.
_nameList
[
rawIndex
];
if
(
name
==
null
&&
this
.
_nameDimIdx
!=
null
)
{
name
=
getIdNameFromStore
(
this
,
this
.
_nameDimIdx
,
this
.
_nameOrdinalMeta
,
rawIndex
);
}
if
(
name
==
null
)
{
name
=
''
;
}
return
name
;
}
/**
...
...
@@ -2062,22 +2062,18 @@ class List<
});
};
get
RawValu
eFromStore
=
function
(
list
:
List
,
dimI
ndex
:
number
,
rawIndex
:
number
):
ParsedValue
|
OrdinalRawValue
{
get
IdNam
eFromStore
=
function
(
list
:
List
,
dimI
dx
:
number
,
ordinalMeta
:
OrdinalMeta
,
rawIndex
:
number
):
string
{
let
val
;
if
(
dimIndex
!=
null
)
{
const
dim
=
list
.
dimensions
[
dimIndex
];
const
chunk
=
list
.
_storage
[
dim
];
if
(
chunk
)
{
val
=
chunk
[
rawIndex
];
const
ordinalMeta
=
list
.
_dimensionInfos
[
dim
].
ordinalMeta
;
if
(
ordinalMeta
&&
ordinalMeta
.
categories
.
length
)
{
val
=
ordinalMeta
.
categories
[
val
as
OrdinalNumber
];
}
const
chunk
=
list
.
_storageArr
[
dimIdx
];
if
(
chunk
)
{
val
=
chunk
[
rawIndex
];
if
(
ordinalMeta
&&
ordinalMeta
.
categories
.
length
)
{
val
=
ordinalMeta
.
categories
[
val
as
OrdinalNumber
];
}
}
return
val
;
return
convertOptionIdName
(
val
,
null
)
;
};
getIndicesCtor
=
function
(
list
:
List
):
DataArrayLikeConstructor
{
...
...
@@ -2123,37 +2119,16 @@ class List<
return
-
1
;
};
getIdFromName
=
function
(
list
:
List
,
name
:
string
)
{
const
nameRepeatCount
=
list
.
_nameRepeatCount
;
nameRepeatCount
[
name
]
=
nameRepeatCount
[
name
]
||
0
;
let
id
=
name
;
if
(
nameRepeatCount
[
name
]
>
0
)
{
id
+=
'
__ec__
'
+
nameRepeatCount
[
name
];
}
nameRepeatCount
[
name
]
++
;
return
id
;
};
/**
* @see the comment of `List['getId']`.
*/
getId
=
function
(
list
:
List
,
rawIndex
:
number
):
string
{
let
id
=
list
.
_idList
[
rawIndex
];
if
(
id
==
null
)
{
id
=
convertOptionIdName
(
getRawValueFromStore
(
list
,
list
.
_idDimIdx
,
rawIndex
),
null
);
if
(
id
==
null
&&
list
.
_idDimIdx
!=
null
)
{
id
=
getIdNameFromStore
(
list
,
list
.
_idDimIdx
,
list
.
_idOrdinalMeta
,
rawIndex
);
}
if
(
id
==
null
)
{
// Use name
id
=
convertOptionIdName
(
getRawValueFromStore
(
list
,
list
.
_nameDimIdx
,
rawIndex
),
null
);
if
(
id
!=
null
)
{
id
=
getIdFromName
(
list
,
id
);
// Cache the id. Avoid getting twice.
list
.
_idList
[
rawIndex
]
=
id
;
}
else
{
// FIXME Check the usage in graph, should not use prefix.
id
=
ID_PREFIX
+
rawIndex
;
}
id
=
ID_PREFIX
+
rawIndex
;
}
return
id
;
};
...
...
@@ -2253,6 +2228,32 @@ class List<
target
.
_calculationInfo
=
zrUtil
.
extend
({},
source
.
_calculationInfo
);
};
makeIdFromName
=
function
(
list
:
List
,
idx
:
number
):
void
{
const
nameList
=
list
.
_nameList
;
const
idList
=
list
.
_idList
;
const
nameDimIdx
=
list
.
_nameDimIdx
;
const
idDimIdx
=
list
.
_idDimIdx
;
let
name
=
nameList
[
idx
];
let
id
=
idList
[
idx
];
if
(
name
==
null
&&
nameDimIdx
!=
null
)
{
nameList
[
idx
]
=
name
=
getIdNameFromStore
(
list
,
nameDimIdx
,
list
.
_nameOrdinalMeta
,
idx
);
}
if
(
id
==
null
&&
idDimIdx
!=
null
)
{
idList
[
idx
]
=
id
=
getIdNameFromStore
(
list
,
idDimIdx
,
list
.
_idOrdinalMeta
,
idx
);
}
if
(
id
==
null
&&
name
!=
null
)
{
const
nameRepeatCount
=
list
.
_nameRepeatCount
;
const
nmCnt
=
nameRepeatCount
[
name
]
=
(
nameRepeatCount
[
name
]
||
0
)
+
1
;
id
=
name
;
if
(
nmCnt
>
1
)
{
id
+=
'
__ec__
'
+
nmCnt
;
}
idList
[
idx
]
=
id
;
}
};
})();
}
...
...
src/data/helper/dataProvider.ts
浏览文件 @
3ad08d4e
...
...
@@ -39,10 +39,17 @@ import {
import
List
from
'
../List
'
;
export
interface
DataProvider
{
// If data is pure without style configuration
pure
:
boolean
;
// If data is persistent and will not be released after use.
persistent
:
boolean
;
/**
* true: all of the value are in primitive type (in type `OptionDataValue`).
* false: Not sure whether any of them is non primitive type (in type `OptionDataItemObject`).
* Like `data: [ { value: xx, itemStyle: {...} }, ...]`
* At present it only happen in `SOURCE_FORMAT_ORIGINAL`.
*/
pure
?:
boolean
;
/**
* If data is persistent and will not be released after use.
*/
persistent
?:
boolean
;
getSource
():
Source
;
count
():
number
;
...
...
@@ -53,8 +60,8 @@ export interface DataProvider {
out
:
ArrayLike
<
ParsedValue
>
[],
extent
:
number
[][]
):
void
appendData
(
newData
:
ArrayLike
<
OptionDataItem
>
):
void
;
clean
():
void
;
appendData
?
(
newData
:
ArrayLike
<
OptionDataItem
>
):
void
;
clean
?
():
void
;
}
...
...
src/util/model.ts
浏览文件 @
3ad08d4e
...
...
@@ -539,6 +539,9 @@ function makeComparableKey(val: unknown): string {
}
export
function
convertOptionIdName
(
idOrName
:
unknown
,
defaultValue
:
string
):
string
{
if
(
idOrName
==
null
)
{
return
defaultValue
;
}
const
type
=
typeof
idOrName
;
return
type
===
'
string
'
?
idOrName
as
string
...
...
test/ut/spec/data/List.test.ts
浏览文件 @
3ad08d4e
...
...
@@ -18,10 +18,18 @@
* under the License.
*/
/* global Float32Array */
import
List
from
'
../../../../src/data/List
'
;
import
Model
from
'
../../../../src/model/Model
'
;
import
{
createSourceFromSeriesDataOption
}
from
'
../../../../src/data/Source
'
;
import
{
createSourceFromSeriesDataOption
,
Source
,
createSource
}
from
'
../../../../src/data/Source
'
;
import
{
OptionDataItemObject
,
OptionDataValue
,
SOURCE_FORMAT_ARRAY_ROWS
}
from
'
../../../../src/util/types
'
;
import
DataDimensionInfo
from
'
../../../../src/data/DataDimensionInfo
'
;
import
OrdinalMeta
from
'
../../../../src/data/OrdinalMeta
'
;
const
ID_PREFIX
=
'
e
\
0
\
0
'
;
const
NAME_REPEAT_PREFIX
=
'
__ec__
'
;
describe
(
'
List
'
,
function
()
{
...
...
@@ -53,10 +61,13 @@ describe('List', function () {
it
(
'
Data with option 1d
'
,
function
()
{
const
list
=
new
List
([
'
x
'
,
'
y
'
],
new
Model
());
list
.
initData
([
1
,
{
value
:
2
,
somProp
:
'
foo
'
}]);
list
.
initData
([
1
,
{
value
:
2
,
somProp
:
'
foo
'
}
as
OptionDataItemObject
<
OptionDataValue
>
]);
expect
(
list
.
getItemModel
(
1
).
get
(
'
somProp
'
as
any
)).
toEqual
(
'
foo
'
);
expect
(
list
.
getItemModel
(
0
).
get
(
'
somProp
'
as
any
)).
toBeNull
();
});
...
...
@@ -162,13 +173,13 @@ describe('List', function () {
const
typedArray
=
new
Float32Array
([
10
,
10
,
20
,
20
]);
const
source
=
createSourceFromSeriesDataOption
(
typedArray
);
list
.
initData
({
count
:
function
()
{
count
:
function
()
:
number
{
return
typedArray
.
length
/
2
;
},
getItem
:
function
(
idx
:
number
)
{
getItem
:
function
(
idx
:
number
)
:
number
[]
{
return
[
typedArray
[
idx
*
2
],
typedArray
[
idx
*
2
+
1
]];
},
getSource
:
function
()
{
getSource
:
function
()
:
Source
{
return
source
;
}
});
...
...
@@ -199,4 +210,348 @@ describe('List', function () {
expect
(
list
.
indicesOfNearest
(
'
value
'
,
50.5
,
0.5
)).
toEqual
([
7
]);
});
});
describe
(
'
id_and_name
'
,
function
()
{
function
makeOneByOneChecker
(
list
:
List
)
{
let
getIdDataIndex
=
0
;
let
getNameDataIndex
=
0
;
return
{
idEqualsTo
:
function
(
expectedId
:
string
):
void
{
expect
(
list
.
getId
(
getIdDataIndex
)).
toEqual
(
expectedId
);
getIdDataIndex
++
;
},
nameEqualsTo
:
function
(
expectedName
:
string
):
void
{
expect
(
list
.
getName
(
getNameDataIndex
)).
toEqual
(
expectedName
);
getNameDataIndex
++
;
},
currGetIdDataIndex
:
function
():
number
{
return
getIdDataIndex
;
},
currGetNameDataIndex
:
function
():
number
{
return
getNameDataIndex
;
}
};
}
describe
(
'
only_name_declared
'
,
function
()
{
function
doChecks
(
list
:
List
)
{
const
oneByOne
=
makeOneByOneChecker
(
list
);
oneByOne
.
idEqualsTo
(
'
a
'
);
oneByOne
.
idEqualsTo
(
'
b
'
);
oneByOne
.
idEqualsTo
(
`b
${
NAME_REPEAT_PREFIX
}
2`
);
oneByOne
.
idEqualsTo
(
'
c
'
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}
4`
);
oneByOne
.
idEqualsTo
(
`c
${
NAME_REPEAT_PREFIX
}
2`
);
oneByOne
.
idEqualsTo
(
'
d
'
);
oneByOne
.
idEqualsTo
(
`c
${
NAME_REPEAT_PREFIX
}
3`
);
oneByOne
.
nameEqualsTo
(
'
a
'
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
c
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
c
'
);
oneByOne
.
nameEqualsTo
(
'
d
'
);
oneByOne
.
nameEqualsTo
(
'
c
'
);
}
it
(
'
sourceFormatOriginal
'
,
function
()
{
const
list
=
new
List
([
'
x
'
,
'
y
'
],
new
Model
());
list
.
initData
([
{
value
:
10
,
name
:
'
a
'
},
{
value
:
20
,
name
:
'
b
'
},
{
value
:
30
,
name
:
'
b
'
},
{
value
:
40
,
name
:
'
c
'
},
{
value
:
50
},
// name not declared
{
value
:
60
,
name
:
'
c
'
},
{
value
:
70
,
name
:
'
d
'
},
{
value
:
80
,
name
:
'
c
'
}
]);
doChecks
(
list
);
});
it
(
'
sourceFormatArrayRows
'
,
function
()
{
const
list
=
new
List
(
[
'
x
'
,
{
name
:
'
q
'
,
type
:
'
ordinal
'
,
otherDims
:
{
itemName
:
0
}
}
],
new
Model
()
);
const
source
=
createSource
(
[
[
10
,
'
a
'
],
[
20
,
'
b
'
],
[
30
,
'
b
'
],
[
40
,
'
c
'
],
[
50
,
null
],
[
60
,
'
c
'
],
[
70
,
'
d
'
],
[
80
,
'
c
'
]
],
{
seriesLayoutBy
:
'
column
'
,
sourceHeader
:
0
,
dimensions
:
null
},
SOURCE_FORMAT_ARRAY_ROWS
,
{
itemName
:
1
}
);
list
.
initData
(
source
);
doChecks
(
list
);
});
});
describe
(
'
id_name_declared_sourceFormat_original
'
,
function
()
{
it
(
'
sourceFormatOriginal
'
,
function
()
{
const
list
=
new
List
([
'
x
'
],
new
Model
());
const
oneByOne
=
makeOneByOneChecker
(
list
);
list
.
initData
([
{
value
:
0
,
id
:
'
myId_10
'
},
{
value
:
10
,
id
:
555
},
// numeric id.
{
value
:
20
,
id
:
'
666%
'
},
{
value
:
30
,
id
:
'
myId_good
'
,
name
:
'
b
'
},
{
value
:
40
,
name
:
'
b
'
},
{
value
:
50
,
id
:
null
},
{
value
:
60
,
id
:
undefined
},
{
value
:
70
,
id
:
NaN
},
{
value
:
80
,
id
:
''
},
{
value
:
90
,
name
:
'
b
'
},
{
value
:
100
},
{
value
:
110
,
id
:
'
myId_better
'
},
{
value
:
120
,
id
:
'
myId_better
'
}
// duplicated id.
]);
oneByOne
.
idEqualsTo
(
'
myId_10
'
);
oneByOne
.
idEqualsTo
(
'
555
'
);
oneByOne
.
idEqualsTo
(
'
666%
'
);
oneByOne
.
idEqualsTo
(
'
myId_good
'
);
oneByOne
.
idEqualsTo
(
'
b
'
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
'
NaN
'
);
oneByOne
.
idEqualsTo
(
''
);
oneByOne
.
idEqualsTo
(
`b
${
NAME_REPEAT_PREFIX
}
2`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
'
myId_better
'
);
oneByOne
.
idEqualsTo
(
'
myId_better
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
list
.
appendData
([
{
value
:
200
,
id
:
'
myId_best
'
},
{
value
:
210
,
id
:
999
},
// numeric id.
{
value
:
220
,
id
:
'
777px
'
},
{
value
:
230
,
name
:
'
b
'
},
{
value
:
240
}
]);
oneByOne
.
idEqualsTo
(
'
myId_best
'
);
oneByOne
.
idEqualsTo
(
'
999
'
);
oneByOne
.
idEqualsTo
(
'
777px
'
);
oneByOne
.
idEqualsTo
(
`b
${
NAME_REPEAT_PREFIX
}
3`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
list
.
appendValues
(
[
[
300
],
[
310
],
[
320
]
],
[
'
b
'
,
'
c
'
,
null
]
);
oneByOne
.
idEqualsTo
(
`b
${
NAME_REPEAT_PREFIX
}
4`
);
oneByOne
.
idEqualsTo
(
'
c
'
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
c
'
);
oneByOne
.
nameEqualsTo
(
''
);
});
});
describe
(
'
id_name_declared_sourceFormat_arrayRows
'
,
function
()
{
function
makeChecker
(
list
:
List
)
{
const
oneByOne
=
makeOneByOneChecker
(
list
);
return
{
checkAfterInitData
()
{
oneByOne
.
idEqualsTo
(
'
myId_10
'
);
oneByOne
.
idEqualsTo
(
'
555
'
);
oneByOne
.
idEqualsTo
(
'
666%
'
);
oneByOne
.
idEqualsTo
(
'
myId_good
'
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
'
NaN
'
);
oneByOne
.
idEqualsTo
(
''
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
'
myId_better
'
);
oneByOne
.
idEqualsTo
(
'
myId_better
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
},
checkAfterAppendData
()
{
oneByOne
.
idEqualsTo
(
'
myId_best
'
);
oneByOne
.
idEqualsTo
(
'
999
'
);
oneByOne
.
idEqualsTo
(
'
777px
'
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
''
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
''
);
},
checkAfterAppendValues
()
{
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
idEqualsTo
(
`
${
ID_PREFIX
}${
oneByOne
.
currGetIdDataIndex
()}
`
);
oneByOne
.
nameEqualsTo
(
'
b
'
);
oneByOne
.
nameEqualsTo
(
'
c
'
);
oneByOne
.
nameEqualsTo
(
''
);
}
};
}
it
(
'
no_ordinalMeta
'
,
function
()
{
testArrayRowsInSource
([
{
name
:
'
x
'
,
type
:
'
number
'
},
{
name
:
'
p
'
,
type
:
'
ordinal
'
,
otherDims
:
{
itemId
:
0
}
},
{
name
:
'
q
'
,
type
:
'
ordinal
'
,
otherDims
:
{
itemName
:
0
}
}
]);
});
it
(
'
has_ordinalMeta
'
,
function
()
{
const
ordinalMetaP
=
new
OrdinalMeta
({
categories
:
[],
needCollect
:
true
,
deduplication
:
true
});
const
ordinalMetaQ
=
new
OrdinalMeta
({
categories
:
[],
needCollect
:
true
,
deduplication
:
true
});
testArrayRowsInSource
([
{
name
:
'
x
'
,
type
:
'
number
'
},
{
name
:
'
p
'
,
type
:
'
ordinal
'
,
otherDims
:
{
itemId
:
0
},
ordinalMeta
:
ordinalMetaP
},
{
name
:
'
q
'
,
type
:
'
ordinal
'
,
otherDims
:
{
itemName
:
0
},
ordinalMeta
:
ordinalMetaQ
}
]);
});
function
testArrayRowsInSource
(
dimensionsInfo
:
DataDimensionInfo
[]):
void
{
const
list
=
new
List
(
dimensionsInfo
,
new
Model
());
const
checker
=
makeChecker
(
list
);
const
source
=
createSource
(
[
[
0
,
'
myId_10
'
,
null
],
[
10
,
555
,
null
],
// numeric id.
[
20
,
'
666%
'
,
null
],
[
30
,
'
myId_good
'
,
'
b
'
],
[
40
,
null
,
'
b
'
],
[
50
,
null
,
null
],
[
60
,
undefined
,
null
],
[
70
,
NaN
,
null
],
[
80
,
''
,
null
],
[
90
,
null
,
'
b
'
],
[
100
,
null
,
null
],
[
110
,
'
myId_better
'
,
null
],
[
120
,
'
myId_better
'
,
null
]
// duplicated id.
],
{
seriesLayoutBy
:
'
column
'
,
sourceHeader
:
0
,
dimensions
:
null
},
SOURCE_FORMAT_ARRAY_ROWS
,
{
itemId
:
1
,
itemName
:
2
}
);
list
.
initData
(
source
);
checker
.
checkAfterInitData
();
list
.
appendData
([
[
200
,
'
myId_best
'
,
null
],
[
210
,
999
,
null
],
// numeric id.
[
220
,
'
777px
'
,
null
],
[
230
,
null
,
'
b
'
],
[
240
,
null
,
null
]
]);
checker
.
checkAfterAppendData
();
list
.
appendValues
(
[
[
300
],
[
310
],
[
320
]
],
[
'
b
'
,
'
c
'
,
null
]
);
checker
.
checkAfterAppendValues
();
}
});
});
});
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录