Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
1/*
2 * Copyright (C) 2023-2025 Yomitan Authors
3 * Copyright (C) 2020-2022 Yomichan Authors
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19import {describe, expect, test} from 'vitest';
20import {DynamicProperty} from '../ext/js/core/dynamic-property.js';
21import {deepEqual} from '../ext/js/core/utilities.js';
22
23describe('DynamicProperty', () => {
24 /** @type {import('test/core').DynamicPropertyTestData} */
25 const data = [
26 {
27 initialValue: 0,
28 operations: [
29 {
30 operation: null,
31 args: [0],
32 expectedDefaultValue: 0,
33 expectedValue: 0,
34 expectedOverrideCount: 0,
35 expectedEventOccurred: false,
36 },
37 {
38 operation: 'set.defaultValue',
39 args: [1],
40 expectedDefaultValue: 1,
41 expectedValue: 1,
42 expectedOverrideCount: 0,
43 expectedEventOccurred: true,
44 },
45 {
46 operation: 'set.defaultValue',
47 args: [1],
48 expectedDefaultValue: 1,
49 expectedValue: 1,
50 expectedOverrideCount: 0,
51 expectedEventOccurred: false,
52 },
53 {
54 operation: 'set.defaultValue',
55 args: [0],
56 expectedDefaultValue: 0,
57 expectedValue: 0,
58 expectedOverrideCount: 0,
59 expectedEventOccurred: true,
60 },
61 {
62 operation: 'setOverride',
63 args: [8],
64 expectedDefaultValue: 0,
65 expectedValue: 8,
66 expectedOverrideCount: 1,
67 expectedEventOccurred: true,
68 },
69 {
70 operation: 'setOverride',
71 args: [16],
72 expectedDefaultValue: 0,
73 expectedValue: 8,
74 expectedOverrideCount: 2,
75 expectedEventOccurred: false,
76 },
77 {
78 operation: 'setOverride',
79 args: [32, 1],
80 expectedDefaultValue: 0,
81 expectedValue: 32,
82 expectedOverrideCount: 3,
83 expectedEventOccurred: true,
84 },
85 {
86 operation: 'setOverride',
87 args: [64, -1],
88 expectedDefaultValue: 0,
89 expectedValue: 32,
90 expectedOverrideCount: 4,
91 expectedEventOccurred: false,
92 },
93 {
94 operation: 'clearOverride',
95 args: [-4],
96 expectedDefaultValue: 0,
97 expectedValue: 32,
98 expectedOverrideCount: 3,
99 expectedEventOccurred: false,
100 },
101 {
102 operation: 'clearOverride',
103 args: [-3],
104 expectedDefaultValue: 0,
105 expectedValue: 32,
106 expectedOverrideCount: 2,
107 expectedEventOccurred: false,
108 },
109 {
110 operation: 'clearOverride',
111 args: [-2],
112 expectedDefaultValue: 0,
113 expectedValue: 64,
114 expectedOverrideCount: 1,
115 expectedEventOccurred: true,
116 },
117 {
118 operation: 'clearOverride',
119 args: [-1],
120 expectedDefaultValue: 0,
121 expectedValue: 0,
122 expectedOverrideCount: 0,
123 expectedEventOccurred: true,
124 },
125 ],
126 },
127 ];
128
129 describe.each(data)('Test DynamicProperty($initialValue)', ({initialValue, operations}) => {
130 test('works as expected', () => {
131 const property = new DynamicProperty(initialValue);
132 const overrideTokens = [];
133 let eventOccurred = false;
134 const onChange = () => { eventOccurred = true; };
135 property.on('change', onChange);
136 for (const {operation, args, expectedDefaultValue, expectedValue, expectedOverrideCount, expectedEventOccurred} of operations) {
137 eventOccurred = false;
138 switch (operation) {
139 case 'set.defaultValue': property.defaultValue = args[0]; break;
140 case 'setOverride': overrideTokens.push(property.setOverride(...args)); break;
141 case 'clearOverride': property.clearOverride(overrideTokens[overrideTokens.length + args[0]]); break;
142 }
143 expect(eventOccurred).toStrictEqual(expectedEventOccurred);
144 expect(property.defaultValue).toStrictEqual(expectedDefaultValue);
145 expect(property.value).toStrictEqual(expectedValue);
146 expect(property.overrideCount).toStrictEqual(expectedOverrideCount);
147 }
148 property.off('change', onChange);
149 });
150 });
151});
152
153describe('deepEqual', () => {
154 /** @type {import('test/core').DeepEqualTestData} */
155 const simpleTestsData = [
156 {
157 value1: 0,
158 value2: 0,
159 expected: true,
160 },
161 {
162 value1: null,
163 value2: null,
164 expected: true,
165 },
166 {
167 value1: 'test',
168 value2: 'test',
169 expected: true,
170 },
171 {
172 value1: true,
173 value2: true,
174 expected: true,
175 },
176 {
177 value1: 0,
178 value2: 1,
179 expected: false,
180 },
181 {
182 value1: null,
183 value2: false,
184 expected: false,
185 },
186 {
187 value1: 'test1',
188 value2: 'test2',
189 expected: false,
190 },
191 {
192 value1: true,
193 value2: false,
194 expected: false,
195 },
196 ];
197 /** @type {import('test/core').DeepEqualTestData} */
198 const simpleObjectTestsData = [
199 {
200 value1: {},
201 value2: {},
202 expected: true,
203 },
204 {
205 value1: {},
206 value2: [],
207 expected: false,
208 },
209 {
210 value1: [],
211 value2: [],
212 expected: true,
213 },
214 {
215 value1: {},
216 value2: null,
217 expected: false,
218 },
219 ];
220 /** @type {import('test/core').DeepEqualTestData} */
221 const complexObjectTestsData = [
222 {
223 value1: [1],
224 value2: [],
225 expected: false,
226 },
227 {
228 value1: [1],
229 value2: [1],
230 expected: true,
231 },
232 {
233 value1: [1],
234 value2: [2],
235 expected: false,
236 },
237
238 {
239 value1: {},
240 value2: {test: 1},
241 expected: false,
242 },
243 {
244 value1: {test: 1},
245 value2: {test: 1},
246 expected: true,
247 },
248 {
249 value1: {test: 1},
250 value2: {test: {test2: false}},
251 expected: false,
252 },
253 {
254 value1: {test: {test2: true}},
255 value2: {test: {test2: false}},
256 expected: false,
257 },
258 {
259 value1: {test: {test2: [true]}},
260 value2: {test: {test2: [true]}},
261 expected: true,
262 },
263 ];
264 /** @type {import('test/core').DeepEqualTestData} */
265 const recursiveTestsData = [
266 {
267 value1: (() => {
268 const x = {};
269 x.x = x;
270 return x;
271 })(),
272 value2: (() => {
273 const x = {};
274 x.x = x;
275 return x;
276 })(),
277 expected: false,
278 },
279 ];
280 describe('simple tests', () => {
281 test.each(simpleTestsData)('deepEqual($value1, $value2) -> $expected', ({value1, value2, expected}) => {
282 const actual1 = deepEqual(value1, value2);
283 expect(actual1).toStrictEqual(expected);
284
285 const actual2 = deepEqual(value2, value1);
286 expect(actual2).toStrictEqual(expected);
287 });
288 });
289
290 describe('simple object tests', () => {
291 test.each(simpleObjectTestsData)('deepEqual($value1, $value2) -> $expected', ({value1, value2, expected}) => {
292 const actual1 = deepEqual(value1, value2);
293 expect(actual1).toStrictEqual(expected);
294
295 const actual2 = deepEqual(value2, value1);
296 expect(actual2).toStrictEqual(expected);
297 });
298 });
299
300 describe('complex object tests', () => {
301 test.each(complexObjectTestsData)('deepEqual($value1, $value2) -> $expected', ({value1, value2, expected}) => {
302 const actual1 = deepEqual(value1, value2);
303 expect(actual1).toStrictEqual(expected);
304
305 const actual2 = deepEqual(value2, value1);
306 expect(actual2).toStrictEqual(expected);
307 });
308 });
309
310 describe('recursive tests', () => {
311 test.each(recursiveTestsData)('deepEqual($value1, $value2) -> $expected', ({value1, value2, expected}) => {
312 const actual1 = deepEqual(value1, value2);
313 expect(actual1).toStrictEqual(expected);
314
315 const actual2 = deepEqual(value2, value1);
316 expect(actual2).toStrictEqual(expected);
317 });
318 });
319});