• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import DeepTypeUtils from './DeepTypeUtils'
17function assertDeepEquals(actualValue, expected) {
18    console.log('actualValue:' + actualValue + ',expected:' + expected[0]);
19    let result = eq(actualValue, expected[0],[], [])
20    let msg = logMsg(actualValue, expected[0]);
21    return {
22        pass: result,
23        message: msg
24    };
25}
26
27/**
28 * 获取失败显示日志
29 * @param actualValue 实际对象
30 * @param expected 期待比较对象
31 */
32function logMsg(actualValue, expected) {
33    // 获取a的对象名称
34    const aClassName = Object.prototype.toString.call(actualValue);
35    const bClassName = Object.prototype.toString.call(expected);
36    let actualMsg;
37    let expectMsg;
38    if(aClassName == "[object Function]") {
39        actualMsg = "actualValue Function"
40    }else if(aClassName == "[object Promise]") {
41        actualMsg = "actualValue Promise"
42    }else if(aClassName == "[object Set]" || aClassName == "[object Map]") {
43        actualMsg = JSON.stringify(Array.from(actualValue));;
44    }else if(aClassName == "[object RegExp]") {
45        actualMsg = JSON.stringify(actualValue.source.replace("\\",""));;
46    }else if(aClassName == "[object BigInt]") {
47        actualMsg = actualValue;
48    }
49    else{
50        actualMsg = JSON.stringify(actualValue);
51    }
52    if(bClassName == "[object Function]") {
53        expectMsg = "expected Function"
54    }else if(bClassName == "[object Promise]") {
55        expectMsg = "expected Promise"
56    }else if(bClassName == "[object Set]" || bClassName == "[object Map]") {
57        expectMsg = JSON.stringify(Array.from(expected));
58    }else if(bClassName == "[object RegExp]") {
59        expectMsg = JSON.stringify(expected.source.replace("\\",""));;
60    }else if(bClassName == "[object BigInt]") {
61        expectMsg = expected;
62    }
63    else{
64        expectMsg = JSON.stringify(expected);
65    }
66    return actualMsg + " is not deep equal " + expectMsg;
67}
68
69function eq(a, b, aStack, bStack) {
70    let result = true;
71    console.log('a is:' + a + ',b is:' + b);
72    const asymmetricResult = asymmetricMatch_(a,b);
73    if (!DeepTypeUtils.isUndefined(asymmetricResult)) {
74        return asymmetricResult;
75    }
76
77    if (a instanceof Error && b instanceof Error) {
78        result = a.message == b.message;
79        return result;
80    }
81
82    if (a === b) {
83        result = a !== 0 || 1 / a == 1 / b;
84        return result;
85    }
86
87    if (a === null || b === null) {
88        result = a === b;
89        return result;
90    }
91    // 获取a的对象名称
92    const aClassName = Object.prototype.toString.call(a);
93    const bClassName = Object.prototype.toString.call(b);
94    console.log('aClassName is:' + aClassName);
95    console.log('bClassName is:' + bClassName);
96    // 不同类型不同对象
97    if (aClassName != bClassName) {
98        return false;
99    }
100    // 俩个string对象
101    if(aClassName === '[object String]') {
102        result = a == String(b);
103        return result;
104    }
105    // 俩个Number对象
106    if(aClassName === '[object Number]') {
107        result = a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b;
108        return result;
109    }
110
111    if(aClassName === '[object Date]' || aClassName === '[object Boolean]') {
112        result = +a == +b;
113        return result;
114    }
115
116    // 数组
117    if(aClassName === '[object ArrayBuffer]') {
118        return eq(new Uint8Array(a), new Uint8Array(b), aStack, bStack);
119    }
120
121    // 正则表达式
122    if(aClassName === '[object RegExp]') {
123        return (
124            a.source == b.source &&
125            a.global == b.global &&
126            a.multiline == b.multiline &&
127            a.ignoreCase == b.ignoreCase
128        );
129    }
130
131    if (typeof a != 'object' || typeof b != 'object') {
132        return false;
133    }
134
135    const aIsDomNode = DeepTypeUtils.isDomNode(a);
136    const bIsDomNode = DeepTypeUtils.isDomNode(b);
137    if (aIsDomNode && bIsDomNode) {
138        // At first try to use DOM3 method isEqualNode
139        result = a.isEqualNode(b);
140        return result;
141    }
142    if (aIsDomNode || bIsDomNode) {
143        return false;
144    }
145    const aIsPromise = DeepTypeUtils.isPromise(a);
146    const bIsPromise = DeepTypeUtils.isPromise(b);
147    if (aIsPromise && bIsPromise) {
148        return a === b;
149    }
150    let length = aStack.length;
151    while (length--) {
152        if (aStack[length] == a) {
153            return bStack[length] == b;
154        }
155    }
156    aStack.push(a);
157    bStack.push(b);
158    let size = 0;
159
160    // 都是数组
161    if(aClassName == '[object Array]') {
162        const aLength = a.length;
163        const bLength = b.length;
164        if (aLength !== bLength) {
165            // 数组长度不同,不是同一个对象
166            return false;
167            }
168        for (let i = 0; i < aLength || i < bLength; i++) {
169            // 递归每一个元素是否相同
170            result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack) && result;
171        }
172        if (!result) {
173            return false;
174        }
175    } else if(DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
176        if (a.size != b.size) {
177            return false;
178        }
179        const keysA = [];
180        const keysB = [];
181        a.forEach(function(valueA, keyA) {
182            keysA.push(keyA);
183        });
184        b.forEach(function(valueB, keyB) {
185            keysB.push(keyB);
186        });
187        const mapKeys = [keysA, keysB];
188        const cmpKeys = [keysB, keysA];
189        for (let i = 0; result && i < mapKeys.length; i++) {
190            const mapIter = mapKeys[i];
191            const cmpIter = cmpKeys[i];
192
193            for (let j = 0; result && j < mapIter.length; j++) {
194                const mapKey = mapIter[j];
195                const cmpKey = cmpIter[j];
196                const mapValueA = a.get(mapKey);
197                let mapValueB;
198                if (
199                DeepTypeUtils.isAsymmetricEqualityTester_(mapKey) ||
200                (DeepTypeUtils.isAsymmetricEqualityTester_(cmpKey) &&
201                eq(mapKey, cmpKey))
202                ) {
203                    mapValueB = b.get(cmpKey);
204                } else {
205                    mapValueB = b.get(mapKey);
206                }
207                result = eq(mapValueA, mapValueB, aStack, bStack);
208            }
209        }
210        if (!result) {
211            return false;
212        }
213    } else if(DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
214        if (a.size != b.size) {
215            return false;
216        }
217        const valuesA = [];
218        a.forEach(function(valueA) {
219            valuesA.push(valueA);
220        });
221        const valuesB = [];
222        b.forEach(function(valueB) {
223            valuesB.push(valueB);
224        });
225        const setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
226       const stackPairs = [[aStack, bStack], [bStack, aStack]];
227        for (let i = 0; result && i < setPairs.length; i++) {
228            const baseValues = setPairs[i][0];
229            const otherValues = setPairs[i][1];
230            const baseStack = stackPairs[i][0];
231            const otherStack = stackPairs[i][1];
232            for (const baseValue of baseValues) {
233                let found = false;
234                for (let j = 0; !found && j < otherValues.length; j++) {
235                    const otherValue = otherValues[j];
236                    const prevStackSize = baseStack.length;
237                    // 深度比较对象
238                    found = eq(baseValue, otherValue, baseStack, otherStack);
239                    if (!found && prevStackSize !== baseStack.length) {
240                        baseStack.splice(prevStackSize);
241                        otherStack.splice(prevStackSize);
242                    }
243                }
244                result = result && found;
245            }
246        }
247        if (!result) {
248            return false;
249        }
250    } else {
251        const aCtor = a.constructor,
252            bCtor = b.constructor;
253        if (
254        aCtor !== bCtor &&
255        DeepTypeUtils.isFunction_(aCtor) &&
256        DeepTypeUtils.isFunction_(bCtor) &&
257        a instanceof aCtor &&
258        b instanceof bCtor &&
259        !(aCtor instanceof aCtor && bCtor instanceof bCtor)
260        ) {
261            return false;
262        }
263    }
264
265    // 获取对象所有的属性集合
266    const aKeys = DeepTypeUtils.keys(a, aClassName == '[object Array]');
267    size = aKeys.length;
268
269    // 俩个对象属性长度不一致, 俩对象不相同
270    if (DeepTypeUtils.keys(b, bClassName == '[object Array]').length !== size) {
271        return false;
272    }
273
274    // 俩对象属性数量相同, 递归比较每个属性值得值
275    for (const key of aKeys) {
276        console.log('key is:' + key);
277        // b 没有 key 属性
278        if(!DeepTypeUtils.has(b, key)) {
279            result = false;
280            continue;
281        }
282        if (!eq(a[key], b[key], aStack, bStack)) {
283            result = false;
284        }
285    }
286    if (!result) {
287        return false;
288    }
289    aStack.pop();
290    bStack.pop();
291    return result;
292}
293
294function asymmetricMatch_(a, b) {
295    const asymmetricA = DeepTypeUtils.isAsymmetricEqualityTester_(a);
296    const asymmetricB = DeepTypeUtils.isAsymmetricEqualityTester_(b);
297
298    if (asymmetricA === asymmetricB) {
299        return undefined;
300    }
301
302}
303
304/**
305 * 获取对象的自有属性
306 *
307 * @param obj 对象
308 * @param isArray 是否是一个数组
309 */
310function keys(obj, isArray) {
311    const keys = [];
312
313}
314
315export default assertDeepEquals;
316