Compare commits
2185 Commits
v24.02.0
...
release/25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b009b9aac0 | ||
|
|
a133180925 | ||
|
|
78d2b12fa7 | ||
|
|
8e80e643f4 | ||
|
|
09e81a51b6 | ||
|
|
4c64ff5925 | ||
|
|
00a497f0d2 | ||
|
|
6f91a45c8e | ||
|
|
6cfdf9dab9 | ||
|
|
3fefdf57ac | ||
|
|
94df22832e | ||
|
|
86cecf49c1 | ||
|
|
71e6acef76 | ||
|
|
9966e02eaf | ||
|
|
cd776b8bd7 | ||
|
|
55f1de221c | ||
|
|
090ef3ac7a | ||
|
|
27c49714de | ||
|
|
18fdba2f7a | ||
|
|
a1615118d0 | ||
|
|
9d816158f5 | ||
|
|
d8619356d3 | ||
|
|
6b6ccdaff0 | ||
|
|
18a29bc46b | ||
|
|
76180ace07 | ||
|
|
c439fa7e45 | ||
|
|
9cadce88bb | ||
|
|
d8984dc812 | ||
|
|
3f096da49b | ||
|
|
bb51b1d677 | ||
|
|
e45ccc00c3 | ||
|
|
c6f041d0bb | ||
|
|
566f9de72a | ||
|
|
6abc398033 | ||
|
|
bef4f370b6 | ||
|
|
b18c12f149 | ||
|
|
e267f9f667 | ||
|
|
32d264a3aa | ||
|
|
77f9e43c82 | ||
|
|
bc0d1aff35 | ||
|
|
bc594ec8a2 | ||
|
|
2a7f0b406c | ||
|
|
c9f685a733 | ||
|
|
5be43575fc | ||
|
|
558519f355 | ||
|
|
f83e2e2677 | ||
|
|
4c4f406c41 | ||
|
|
2f8a873202 | ||
|
|
78b3cfe916 | ||
|
|
0bc529da2d | ||
|
|
6ad6121dfa | ||
|
|
7b5b7a67ae | ||
|
|
59c8b82bc2 | ||
|
|
c6aec89b61 | ||
|
|
2ef3fd9d6c | ||
|
|
e64b6033f3 | ||
|
|
82989e7ef2 | ||
|
|
ddf272ab2b | ||
|
|
4d4b44e011 | ||
|
|
a17d7e18fd | ||
|
|
1e78f119f1 | ||
|
|
b6a4b67c22 | ||
|
|
e965e1680f | ||
|
|
7d4cc7a5cf | ||
|
|
112b4b54e5 | ||
|
|
782f096f21 | ||
|
|
57e0f04086 | ||
|
|
a639011db6 | ||
|
|
26e7f3780c | ||
|
|
8c96d05799 | ||
|
|
bc6e22bc6d | ||
|
|
4371c3f7e5 | ||
|
|
b88ee65a4c | ||
|
|
033e865a27 | ||
|
|
75ba46e292 | ||
|
|
d492ed038a | ||
|
|
b29108a2f7 | ||
|
|
2790d430ae | ||
|
|
23f61fff36 | ||
|
|
254d105e35 | ||
|
|
6dde57a786 | ||
|
|
d803fcb874 | ||
|
|
90e70a9295 | ||
|
|
2090e4dc0e | ||
|
|
5ced491d54 | ||
|
|
e156d4da90 | ||
|
|
b3aa2abd89 | ||
|
|
7627d6d0e2 | ||
|
|
77da7e6c7d | ||
|
|
1e3ce9d6cd | ||
|
|
321561fd89 | ||
|
|
856bc7b713 | ||
|
|
10e9b8d8f8 | ||
|
|
9f1803c551 | ||
|
|
9260c92026 | ||
|
|
9c7030a5db | ||
|
|
909e20889e | ||
|
|
74f4c291a0 | ||
|
|
242a248bf3 | ||
|
|
dfb0bb75f4 | ||
|
|
3cefd4b1ef | ||
|
|
3f3ce6b421 | ||
|
|
73d910421a | ||
|
|
1da44f3ae3 | ||
|
|
08836010c6 | ||
|
|
13042d9ba6 | ||
|
|
0e4b52ee62 | ||
|
|
4c32280343 | ||
|
|
a2e540d6ef | ||
|
|
573c8925d2 | ||
|
|
6c0bd850b0 | ||
|
|
1da9719314 | ||
|
|
3cd5f3a1c6 | ||
|
|
b4108f2eef | ||
|
|
bb7de18341 | ||
|
|
7b8328fce6 | ||
|
|
aeee6570c0 | ||
|
|
780b9a6f9b | ||
|
|
0ba06882d1 | ||
|
|
ce131a53e5 | ||
|
|
e9421e28dd | ||
|
|
1c64a6b5f0 | ||
|
|
9b5200c344 | ||
|
|
5baf4ab823 | ||
|
|
58a72a08f2 | ||
|
|
c9b97d4d0d | ||
|
|
2a7d61c73b | ||
|
|
f55bd28e10 | ||
|
|
2a67861099 | ||
|
|
273d962707 | ||
|
|
5e8b44fea6 | ||
|
|
be9e2ec7d0 | ||
|
|
ee042cc1a2 | ||
|
|
25c0bc131a | ||
|
|
7def8c066c | ||
|
|
1ddaf37e52 | ||
|
|
40694f502a | ||
|
|
d9f4a0a032 | ||
|
|
5e392f3101 | ||
|
|
ce1ac6128e | ||
|
|
a9d08a6ee2 | ||
|
|
24d4829ba9 | ||
|
|
a121c39b6e | ||
|
|
f009420c20 | ||
|
|
069e0d8f16 | ||
|
|
1f1db11197 | ||
|
|
be92e56c3a | ||
|
|
d1fc426513 | ||
|
|
c778ba8b24 | ||
|
|
07fb3160eb | ||
|
|
7444d68280 | ||
|
|
1d5536401d | ||
|
|
099e996f2f | ||
|
|
6d9974b2b1 | ||
|
|
f65e9f7599 | ||
|
|
4a39810923 | ||
|
|
6720e2dfaa | ||
|
|
eb1bf2ed2b | ||
|
|
cc26b1b62f | ||
|
|
59c2c88eb6 | ||
|
|
99e8fd16eb | ||
|
|
eaa4bdb0b7 | ||
|
|
892b61e6bb | ||
|
|
6d56b673c4 | ||
|
|
f59e5a4b3c | ||
|
|
16e3fd4476 | ||
|
|
82d0fdefd2 | ||
|
|
cbde14d58b | ||
|
|
f3c37e4304 | ||
|
|
369008cec3 | ||
|
|
1a2af57901 | ||
|
|
dbb41d061c | ||
|
|
d1d3c43c6f | ||
|
|
ba2b1529ea | ||
|
|
b5150f82f0 | ||
|
|
00c81de035 | ||
|
|
52d4451932 | ||
|
|
3efc11b9aa | ||
|
|
5fd9f07664 | ||
|
|
bec9f36bce | ||
|
|
a631acc0ac | ||
|
|
b729aaf6ee | ||
|
|
94b7fc5cdf | ||
|
|
ec5355d86e | ||
|
|
1a43d15c6d | ||
|
|
7356a68f4c | ||
|
|
1070427a0d | ||
|
|
196ef535ca | ||
|
|
88fd173829 | ||
|
|
8b0698c670 | ||
|
|
5b07a0ff45 | ||
|
|
ba1d175d67 | ||
|
|
36ce55e892 | ||
|
|
ba4a83d38c | ||
|
|
5c49c35b82 | ||
|
|
2b0251c593 | ||
|
|
3b08d0f382 | ||
|
|
f64e8a3192 | ||
|
|
eab45e761a | ||
|
|
0f03290c57 | ||
|
|
59f87bb2c2 | ||
|
|
9afc10160d | ||
|
|
cfc7f50a1f | ||
|
|
a2fc00365e | ||
|
|
466cfd971d | ||
|
|
8e83febb24 | ||
|
|
12072b0a73 | ||
|
|
83b1daac07 | ||
|
|
981ea053a6 | ||
|
|
e41fd7d986 | ||
|
|
a88a82ca08 | ||
|
|
23dc88df60 | ||
|
|
520b1daeec | ||
|
|
cbe7ace32d | ||
|
|
2b4471ea91 | ||
|
|
88e1e1dd2a | ||
|
|
94ea1305b2 | ||
|
|
960377838d | ||
|
|
a48e8662d6 | ||
|
|
9c90a38efc | ||
|
|
8696a24127 | ||
|
|
f2d1b4c1e1 | ||
|
|
4cdc2b5e58 | ||
|
|
e26f02d9e2 | ||
|
|
5d83fe9a1d | ||
|
|
6a506f237a | ||
|
|
3a5a0153d8 | ||
|
|
27519b8788 | ||
|
|
dd45fe16a5 | ||
|
|
161815acff | ||
|
|
438edf2155 | ||
|
|
6607a4b72c | ||
|
|
8f0c4ab133 | ||
|
|
78e5cd51cd | ||
|
|
f5da44655e | ||
|
|
a91863c60d | ||
|
|
29e3a09aba | ||
|
|
a59952f189 | ||
|
|
b169da25ab | ||
|
|
833e357d70 | ||
|
|
f9bf2b8f7a | ||
|
|
7b27579f2d | ||
|
|
edb9d9f54e | ||
|
|
abf9a486d0 | ||
|
|
b0bc19c055 | ||
|
|
71776ef275 | ||
|
|
8dc7d1d39d | ||
|
|
adb9e59503 | ||
|
|
518044e34a | ||
|
|
d6d747bb99 | ||
|
|
f390702a7a | ||
|
|
e056360ddd | ||
|
|
85163791ce | ||
|
|
b5a853bc96 | ||
|
|
e4cd6ce5a6 | ||
|
|
84fa68e3ae | ||
|
|
649dc7a815 | ||
|
|
b87e43660c | ||
|
|
511138e3bb | ||
|
|
5a3c23d000 | ||
|
|
1036384023 | ||
|
|
e3f618489b | ||
|
|
cfedd4fdb5 | ||
|
|
812e5beee6 | ||
|
|
17b632eb78 | ||
|
|
877d5f34f7 | ||
|
|
c93ce52ba1 | ||
|
|
2504ca3f5c | ||
|
|
5be05032be | ||
|
|
81e5061831 | ||
|
|
3b419e18a3 | ||
|
|
1a1190d7bd | ||
|
|
5b4d3df6ee | ||
|
|
f53d47fa28 | ||
|
|
67d5711cc4 | ||
|
|
9f51b1e7ab | ||
|
|
5ac296ee71 | ||
|
|
1b8adcc91a | ||
|
|
1e78209cd7 | ||
|
|
0fd924be7b | ||
|
|
d67cb89505 | ||
|
|
0d0f88e251 | ||
|
|
4cbd4a034c | ||
|
|
e7ed07e386 | ||
|
|
390654fa4a | ||
|
|
e8830b56d8 | ||
|
|
bbf2587908 | ||
|
|
409b6da160 | ||
|
|
9d8c9853ce | ||
|
|
b3781e0db4 | ||
|
|
fbcb2379fb | ||
|
|
e8ad4a5dee | ||
|
|
6c57c41993 | ||
|
|
ce0014f846 | ||
|
|
e5df412258 | ||
|
|
0c482aa463 | ||
|
|
2df3a21fb5 | ||
|
|
9dd438e8a2 | ||
|
|
cea5006e15 | ||
|
|
8ff3b31497 | ||
|
|
c7a9f9f07e | ||
|
|
1de10a4b87 | ||
|
|
d7f19efbd6 | ||
|
|
a3a28b2472 | ||
|
|
919fc8b821 | ||
|
|
b80a2f94f4 | ||
|
|
6d18d1a237 | ||
|
|
a2d64d2955 | ||
|
|
95617e3210 | ||
|
|
1522f7086e | ||
|
|
14167d197f | ||
|
|
c377cf05b8 | ||
|
|
4a52bc04fb | ||
|
|
53cd230d16 | ||
|
|
e7b204b9fd | ||
|
|
4d91ae96e3 | ||
|
|
b422d641de | ||
|
|
adc23e22cd | ||
|
|
a673d97144 | ||
|
|
5a71dfcd7a | ||
|
|
5f6c248181 | ||
|
|
8e04a5ed2f | ||
|
|
f45582dc03 | ||
|
|
19cfe118ac | ||
|
|
79b8987d85 | ||
|
|
1d9708ffa4 | ||
|
|
c55f30be5b | ||
|
|
669a00a7e3 | ||
|
|
51fe090043 | ||
|
|
cf85d0fc0d | ||
|
|
c257ac504b | ||
|
|
9412f7e189 | ||
|
|
385fafa51c | ||
|
|
c7e409abe9 | ||
|
|
98816aedd4 | ||
|
|
38c66d1b7d | ||
|
|
0e01a43aab | ||
|
|
ddf67aef94 | ||
|
|
fa8294d4b9 | ||
|
|
8ad822fd0b | ||
|
|
69568c628f | ||
|
|
62a770b3e2 | ||
|
|
9b65ae1e66 | ||
|
|
5d5295d06d | ||
|
|
8f7be9993c | ||
|
|
821d7621e3 | ||
|
|
91b00a34b7 | ||
|
|
19e74b60a9 | ||
|
|
5ee5991c39 | ||
|
|
abffeec938 | ||
|
|
77ac811498 | ||
|
|
1ba6b840db | ||
|
|
bfb640487f | ||
|
|
4b3cc750a1 | ||
|
|
8bef9713fd | ||
|
|
889bf9cbc6 | ||
|
|
003ab4f278 | ||
|
|
a6b9759a31 | ||
|
|
5c5dcd555b | ||
|
|
8098fce461 | ||
|
|
227ea231d5 | ||
|
|
35ac1b7a55 | ||
|
|
86be1d82bc | ||
|
|
c6dd82d2ff | ||
|
|
2624ed1817 | ||
|
|
8706ee950e | ||
|
|
bde27dc826 | ||
|
|
25b4ee2efb | ||
|
|
e7f6adaa01 | ||
|
|
bb3e28bc43 | ||
|
|
026db80391 | ||
|
|
2c09a48c8d | ||
|
|
6e0931e31b | ||
|
|
1424b8ce42 | ||
|
|
f5f151681d | ||
|
|
306d75a9b0 | ||
|
|
ee33a70bb2 | ||
|
|
bd80390daa | ||
|
|
0fa490f532 | ||
|
|
1c7cc45d8e | ||
|
|
f3288c2e34 | ||
|
|
7eff1eec56 | ||
|
|
85c7b1a3fc | ||
|
|
5c82c07f06 | ||
|
|
fcf125f9ca | ||
|
|
8ae13adbcd | ||
|
|
1e1ad389e3 | ||
|
|
f58212e8de | ||
|
|
8622087e51 | ||
|
|
5fc59b0d66 | ||
|
|
5aeefea5c0 | ||
|
|
52e9c9e8e2 | ||
|
|
ae69401d57 | ||
|
|
2339cad49f | ||
|
|
8f6683fd1d | ||
|
|
74deb684e1 | ||
|
|
54a918b0cf | ||
|
|
55c9b09b24 | ||
|
|
0d63fce59a | ||
|
|
4498d4457b | ||
|
|
83415d202a | ||
|
|
ed65855cdd | ||
|
|
1477159376 | ||
|
|
53a88708d6 | ||
|
|
8eb8803afd | ||
|
|
20e30982cf | ||
|
|
e13b82f66a | ||
|
|
8e50388031 | ||
|
|
fb21686894 | ||
|
|
62faf0f784 | ||
|
|
be377d9ad8 | ||
|
|
ab8e2f7573 | ||
|
|
7991429ef4 | ||
|
|
e3b70a14be | ||
|
|
39abf6b5f3 | ||
|
|
096842bd3a | ||
|
|
c69db9d375 | ||
|
|
ec36d519b1 | ||
|
|
45b02ae34e | ||
|
|
9b763daf52 | ||
|
|
6e8ed5b341 | ||
|
|
63a3c3e58a | ||
|
|
aadd9b0189 | ||
|
|
39f595e45d | ||
|
|
823b2d3747 | ||
|
|
eb268576da | ||
|
|
8e51f3ec8e | ||
|
|
de03e1ce2b | ||
|
|
21b1258b8d | ||
|
|
becad8c127 | ||
|
|
4044048352 | ||
|
|
7d6bd7ab4c | ||
|
|
209ae00f8f | ||
|
|
f64c860453 | ||
|
|
36fccaffe6 | ||
|
|
13deb2d928 | ||
|
|
14fe71b556 | ||
|
|
ecb900994b | ||
|
|
55b97b469e | ||
|
|
1d594b492d | ||
|
|
3902293de7 | ||
|
|
a8bc51667c | ||
|
|
0bcf6e74c0 | ||
|
|
78b218fef3 | ||
|
|
964bcfd5f5 | ||
|
|
fc733f9ba1 | ||
|
|
e7e83fa789 | ||
|
|
ef4f11546f | ||
|
|
648796b9e0 | ||
|
|
3b5da2473d | ||
|
|
9a04ae3e02 | ||
|
|
9ed5224470 | ||
|
|
bc82ceeb5f | ||
|
|
5f7ff209d3 | ||
|
|
35b363fdce | ||
|
|
a74931e794 | ||
|
|
6698bbcf79 | ||
|
|
8c78992b1a | ||
|
|
04e3b88e8c | ||
|
|
9b8b13e98e | ||
|
|
e6dd6aec7f | ||
|
|
c6f0879c9c | ||
|
|
9e7ae37add | ||
|
|
0c727237ee | ||
|
|
bf66118355 | ||
|
|
aacb097650 | ||
|
|
ce5d60fc5d | ||
|
|
96a0b86c33 | ||
|
|
279b611754 | ||
|
|
f7c74a60cd | ||
|
|
3465fc7d39 | ||
|
|
6381f06acb | ||
|
|
a7c7a5c72d | ||
|
|
c8ded65e46 | ||
|
|
729b46fc71 | ||
|
|
e63e04aa57 | ||
|
|
ae88879651 | ||
|
|
dfd106258b | ||
|
|
4d29b9fd57 | ||
|
|
3de7ad237a | ||
|
|
7d4e589894 | ||
|
|
4bbd127fe8 | ||
|
|
f2a0a66b01 | ||
|
|
143c685045 | ||
|
|
b8fa6f0690 | ||
|
|
93b6c53c82 | ||
|
|
6822a1ef08 | ||
|
|
12b7c25395 | ||
|
|
42c0060122 | ||
|
|
b30ee55a81 | ||
|
|
9d2ef838bb | ||
|
|
b5351e48dd | ||
|
|
7b437d91e1 | ||
|
|
a9d39353ab | ||
|
|
5f778dbd81 | ||
|
|
b01286eae3 | ||
|
|
4688802628 | ||
|
|
0282f2c7aa | ||
|
|
53d0fd1663 | ||
|
|
24bdb7d651 | ||
|
|
dc32f2f947 | ||
|
|
401cf29ca8 | ||
|
|
f16dea85ed | ||
|
|
b4e1740cad | ||
|
|
501f14fead | ||
|
|
d14466451d | ||
|
|
f7cd4bd2fb | ||
|
|
7742c6d4b0 | ||
|
|
4f6dd50320 | ||
|
|
92f77860dd | ||
|
|
03035b735d | ||
|
|
4e0b295f66 | ||
|
|
8cbd3f5e0f | ||
|
|
a0b3e484f5 | ||
|
|
8ff83ca6df | ||
|
|
5fe28cb183 | ||
|
|
17af4dfddb | ||
|
|
43c6349359 | ||
|
|
265494ee44 | ||
|
|
a9e4996191 | ||
|
|
6e3276826d | ||
|
|
bfe976c438 | ||
|
|
f288367653 | ||
|
|
6082bc89b0 | ||
|
|
4d3791250b | ||
|
|
04472dae4f | ||
|
|
aa40fc84ea | ||
|
|
24e43d063a | ||
|
|
c5caffcdf9 | ||
|
|
95d334ad86 | ||
|
|
602ac5c55f | ||
|
|
247423bf83 | ||
|
|
24d35b3eae | ||
|
|
8bcd9f7469 | ||
|
|
edf5d55da4 | ||
|
|
976af783e2 | ||
|
|
d87954838e | ||
|
|
e757331dce | ||
|
|
bf4f6f5728 | ||
|
|
c73bc8fc29 | ||
|
|
211a08db68 | ||
|
|
38987e6d4c | ||
|
|
9d76e7e30b | ||
|
|
4c1a8d3657 | ||
|
|
7a5de25885 | ||
|
|
a17aa2c6fa | ||
|
|
207a7876b6 | ||
|
|
4c638a740e | ||
|
|
0ee89e1b2b | ||
|
|
4af42a57f4 | ||
|
|
34f2c2dabc | ||
|
|
9ff942915a | ||
|
|
10123abc5b | ||
|
|
ad993d4340 | ||
|
|
ddc0a66d5b | ||
|
|
e8981bdc0f | ||
|
|
c42486a061 | ||
|
|
64d82b8d2a | ||
|
|
677abee890 | ||
|
|
3a25a62350 | ||
|
|
bc7b480c41 | ||
|
|
d9b495356d | ||
|
|
ce82606e6e | ||
|
|
07837c2e64 | ||
|
|
1738253e6f | ||
|
|
17fa2246da | ||
|
|
4f5e096e7e | ||
|
|
b125c284bd | ||
|
|
87213903b1 | ||
|
|
3d9d211d25 | ||
|
|
d5d291396d | ||
|
|
d7cd38b5e5 | ||
|
|
1a25cfc0e3 | ||
|
|
8d9669e033 | ||
|
|
690d2e2b12 | ||
|
|
2208b1b2b3 | ||
|
|
67da272ccd | ||
|
|
171930fb1d | ||
|
|
2bd59fa16f | ||
|
|
d0d0384bdb | ||
|
|
680573de61 | ||
|
|
ba7f866cf5 | ||
|
|
57a95ae972 | ||
|
|
de97275a38 | ||
|
|
d08181f56d | ||
|
|
f6e8491bf1 | ||
|
|
a1447ebd6f | ||
|
|
3b67e4deaf | ||
|
|
e55afd0402 | ||
|
|
7c0710d445 | ||
|
|
61f9cd41f7 | ||
|
|
6c7a7a7be5 | ||
|
|
63125d97c3 | ||
|
|
cb4e7d4943 | ||
|
|
b9d5ed699e | ||
|
|
75fe5c8970 | ||
|
|
91da2d01b7 | ||
|
|
4bade72ce4 | ||
|
|
9c05e2feed | ||
|
|
ba94098411 | ||
|
|
43c691160e | ||
|
|
e2daa091e8 | ||
|
|
f026414b1a | ||
|
|
fd640a4bd0 | ||
|
|
dd433d7f99 | ||
|
|
3183e00acc | ||
|
|
1860de12ea | ||
|
|
277f1ab252 | ||
|
|
324b332fa6 | ||
|
|
33d29f6b02 | ||
|
|
419aed6375 | ||
|
|
7bb26ac3be | ||
|
|
7654333ec1 | ||
|
|
d3a2da391d | ||
|
|
f19f59c37f | ||
|
|
94e53e14a3 | ||
|
|
d2b3788872 | ||
|
|
8095062db2 | ||
|
|
89beaa9316 | ||
|
|
dfaffd043e | ||
|
|
a8c200222f | ||
|
|
598a1c28ac | ||
|
|
b972703f34 | ||
|
|
d30fdc67c6 | ||
|
|
6a5a2e6144 | ||
|
|
235143528c | ||
|
|
33ca2b8d09 | ||
|
|
50176cfafb | ||
|
|
a67fb36a84 | ||
|
|
aea9984187 | ||
|
|
7a6c234b40 | ||
|
|
4cdaa513d3 | ||
|
|
aaf655ea5b | ||
|
|
207c824ec7 | ||
|
|
29abe0bacb | ||
|
|
d14eda2ca0 | ||
|
|
0425cf41d0 | ||
|
|
4ff014f288 | ||
|
|
2e24500866 | ||
|
|
f13a256150 | ||
|
|
c958e8cba9 | ||
|
|
7668da68d3 | ||
|
|
c478a0c0fc | ||
|
|
fe60a08817 | ||
|
|
dec5369a8f | ||
|
|
5ec0b9393e | ||
|
|
3d8f724bb1 | ||
|
|
bc7a663f92 | ||
|
|
90369e927f | ||
|
|
034cad79c7 | ||
|
|
5c8ba7e29e | ||
|
|
bf1dc00338 | ||
|
|
54f7fd08cb | ||
|
|
e7afa07c84 | ||
|
|
e196ef03d6 | ||
|
|
0fa452ca04 | ||
|
|
15b625a3f8 | ||
|
|
e2427c0683 | ||
|
|
a0e8039d92 | ||
|
|
2f87b1f398 | ||
|
|
86fd2e8e1e | ||
|
|
4167f55ad8 | ||
|
|
76919a13b8 | ||
|
|
fe0f159490 | ||
|
|
4527a6399e | ||
|
|
b8ff75c5ce | ||
|
|
049e8af8b2 | ||
|
|
8ce2386cc9 | ||
|
|
5239040d9c | ||
|
|
c5eb7578b7 | ||
|
|
76ce44230d | ||
|
|
4a20371b87 | ||
|
|
9a76c30aaf | ||
|
|
9cba57368e | ||
|
|
d895f8d771 | ||
|
|
de8c9f4878 | ||
|
|
f029cf842a | ||
|
|
6ce9b77b3c | ||
|
|
5a60c6ec67 | ||
|
|
a1ca768711 | ||
|
|
f0d2c19393 | ||
|
|
67db05a0c3 | ||
|
|
05e932b884 | ||
|
|
763713cd32 | ||
|
|
2687448212 | ||
|
|
d059195e92 | ||
|
|
6ef7acc8e5 | ||
|
|
2cb89807ef | ||
|
|
b5fcad3db0 | ||
|
|
d3fd441c88 | ||
|
|
e9568b50fc | ||
|
|
e7040a518a | ||
|
|
495f7194ac | ||
|
|
d31cc486bb | ||
|
|
3ea844496a | ||
|
|
7b953d0cc0 | ||
|
|
becc127dc4 | ||
|
|
e2742cbf8b | ||
|
|
a1513b30cd | ||
|
|
e2c0316e7d | ||
|
|
fda84a6aac | ||
|
|
142312d87d | ||
|
|
906fb97259 | ||
|
|
80923a2025 | ||
|
|
12882586d3 | ||
|
|
d51e68e9e2 | ||
|
|
7f6e489f20 | ||
|
|
161111bf5c | ||
|
|
5452c51c6a | ||
|
|
09917d45e3 | ||
|
|
101a8b9ec3 | ||
|
|
a04769baad | ||
|
|
07441df3f6 | ||
|
|
b5465cd8d0 | ||
|
|
0a2af02c5f | ||
|
|
3183be460e | ||
|
|
beb72dfa48 | ||
|
|
60d493e34b | ||
|
|
36a5e8bdb5 | ||
|
|
489e60996a | ||
|
|
3d15e4f061 | ||
|
|
28c39292f7 | ||
|
|
d7c9bea783 | ||
|
|
e232501715 | ||
|
|
4757ac11dc | ||
|
|
14cbbd394f | ||
|
|
5d4529ccf9 | ||
|
|
baa214df0e | ||
|
|
6b5996a1bd | ||
|
|
86a43c4f7e | ||
|
|
107f3b6616 | ||
|
|
bcab617b9d | ||
|
|
f6c12dc27a | ||
|
|
3e954a24a1 | ||
|
|
08dc05c707 | ||
|
|
8817ca7f2b | ||
|
|
5262ec4b56 | ||
|
|
f4799a4287 | ||
|
|
97d5be9d81 | ||
|
|
6913a4b447 | ||
|
|
41e96fca70 | ||
|
|
f6b3f3ac80 | ||
|
|
db0c423763 | ||
|
|
df9a7292b9 | ||
|
|
7abca73339 | ||
|
|
30ee914baf | ||
|
|
5b835933e6 | ||
|
|
85f3d3b633 | ||
|
|
41d6233f78 | ||
|
|
ccb162cfed | ||
|
|
56472f6cfd | ||
|
|
14c26b1663 | ||
|
|
14043f861f | ||
|
|
7761e4e0f7 | ||
|
|
4214b7691f | ||
|
|
62da98af94 | ||
|
|
0cc14f710d | ||
|
|
a148c6e326 | ||
|
|
bb864cac5b | ||
|
|
e465ef6d41 | ||
|
|
1303dcce8f | ||
|
|
b6791485c4 | ||
|
|
0708f022bc | ||
|
|
d81478ac97 | ||
|
|
f57004601d | ||
|
|
c104c0b7d0 | ||
|
|
50ceddaa7e | ||
|
|
23803223bf | ||
|
|
438d4ca3fd | ||
|
|
d668d2f2de | ||
|
|
0f704417c6 | ||
|
|
9b8cfafa04 | ||
|
|
195e175186 | ||
|
|
2d5d2c6c06 | ||
|
|
e787eaabcd | ||
|
|
4aec891b1f | ||
|
|
86f04f8b98 | ||
|
|
cee9c90f55 | ||
|
|
2ca744c960 | ||
|
|
854aa34e52 | ||
|
|
b8d4ffcedc | ||
|
|
0380de698c | ||
|
|
380a52d981 | ||
|
|
ddc3c11e12 | ||
|
|
05e1c2e6f8 | ||
|
|
bffd7fb13d | ||
|
|
4fe9c76d90 | ||
|
|
866fee2ea3 | ||
|
|
b9ffe12154 | ||
|
|
09cb2bd261 | ||
|
|
3a4bc18d45 | ||
|
|
32ee590cef | ||
|
|
5ef4ab0756 | ||
|
|
1e26e740fb | ||
|
|
704505958e | ||
|
|
b230641600 | ||
|
|
3f457774dc | ||
|
|
6ff32d0935 | ||
|
|
928b48fd14 | ||
|
|
c040031771 | ||
|
|
324a8ee2e1 | ||
|
|
a866c9b924 | ||
|
|
9877962dd0 | ||
|
|
aef4f75c33 | ||
|
|
8327b4369e | ||
|
|
0403ecbd70 | ||
|
|
16daca09e8 | ||
|
|
9f60a8957b | ||
|
|
9a169bbf3d | ||
|
|
8af0ae6263 | ||
|
|
420baaaf4a | ||
|
|
c56054a05a | ||
|
|
d9b8b1c8ef | ||
|
|
73623ec41a | ||
|
|
02e11e8008 | ||
|
|
22b3641a07 | ||
|
|
913b4ea923 | ||
|
|
88eb2223c5 | ||
|
|
123d11945e | ||
|
|
7a078b2d34 | ||
|
|
054f87cae2 | ||
|
|
f026e4e5ed | ||
|
|
b9bd12e451 | ||
|
|
0f75369658 | ||
|
|
075f2c96b2 | ||
|
|
d3b9aa9808 | ||
|
|
16d42aa6e3 | ||
|
|
e90f038f6a | ||
|
|
bd0c76559b | ||
|
|
42fab806c6 | ||
|
|
fadb5725e0 | ||
|
|
8180f111d0 | ||
|
|
5c30785d8d | ||
|
|
581a1e7153 | ||
|
|
0b9a8be45d | ||
|
|
40883d9461 | ||
|
|
91010c52db | ||
|
|
2546d79f26 | ||
|
|
c3404936fd | ||
|
|
ec635d7de3 | ||
|
|
d416270cad | ||
|
|
3fa6dadb43 | ||
|
|
cee391746f | ||
|
|
8432fa82a8 | ||
|
|
72edfe1112 | ||
|
|
3b2a6800a0 | ||
|
|
6b7ad6b1af | ||
|
|
37d77f579a | ||
|
|
55d68af499 | ||
|
|
1ca4120fd9 | ||
|
|
9164660d19 | ||
|
|
ba78cf050d | ||
|
|
e8d1142a94 | ||
|
|
f40eaf55a3 | ||
|
|
0b85f62858 | ||
|
|
24235174fd | ||
|
|
4a800f99e1 | ||
|
|
96e61c8357 | ||
|
|
f153e57fdb | ||
|
|
bac93e778e | ||
|
|
2aeed10429 | ||
|
|
ea6ad902a7 | ||
|
|
f9c53ee3b0 | ||
|
|
3f0843647c | ||
|
|
a50df870e7 | ||
|
|
716ae11941 | ||
|
|
4ff16ff402 | ||
|
|
bd598b9c44 | ||
|
|
f1253e4ede | ||
|
|
79a3da3358 | ||
|
|
5a6bdfbbba | ||
|
|
3d663be506 | ||
|
|
0ada4cdebe | ||
|
|
d103de96aa | ||
|
|
f248b04834 | ||
|
|
9572f20682 | ||
|
|
409cec08fc | ||
|
|
51f330eae9 | ||
|
|
51750267e5 | ||
|
|
99948d5151 | ||
|
|
030726e6fb | ||
|
|
1fad54272f | ||
|
|
4af4bfd55f | ||
|
|
77cedef5bb | ||
|
|
db36f187dc | ||
|
|
2861eb9c60 | ||
|
|
9811c0d97a | ||
|
|
e9c21373ed | ||
|
|
bda23ec54a | ||
|
|
e23641375b | ||
|
|
024d54345a | ||
|
|
59fd4d3916 | ||
|
|
88d684b6c1 | ||
|
|
94fdf777cb | ||
|
|
dea70152e4 | ||
|
|
614caf5ca0 | ||
|
|
25dbae37fb | ||
|
|
e060032e6a | ||
|
|
4725410c0f | ||
|
|
20488ee400 | ||
|
|
b1c0619af5 | ||
|
|
ade730179a | ||
|
|
9264ad26d6 | ||
|
|
9020e2c7cb | ||
|
|
0f51c34b24 | ||
|
|
f6a427e865 | ||
|
|
9b95930463 | ||
|
|
cb96b4991e | ||
|
|
cde7a51cde | ||
|
|
046d611f56 | ||
|
|
d7b3748159 | ||
|
|
188c9fc726 | ||
|
|
dbc735e63b | ||
|
|
8750486f7b | ||
|
|
6dc4baeeb5 | ||
|
|
ff28828a2e | ||
|
|
e28452dfd1 | ||
|
|
5d7cb5c28f | ||
|
|
08b29f7081 | ||
|
|
c9e034b5b3 | ||
|
|
d9f0ff466f | ||
|
|
6b4b895102 | ||
|
|
0c7e02e7c9 | ||
|
|
4d1c82a623 | ||
|
|
8d33fe6221 | ||
|
|
9d27651411 | ||
|
|
268975bc3b | ||
|
|
66343ba11e | ||
|
|
684cd85a7a | ||
|
|
ef9a80e76f | ||
|
|
fbb5f02379 | ||
|
|
5f4bde96e9 | ||
|
|
f8c8a68840 | ||
|
|
bf6f4a951e | ||
|
|
58c9366548 | ||
|
|
f410ecac2b | ||
|
|
1d1a43ade2 | ||
|
|
37adb56233 | ||
|
|
aca0669bf6 | ||
|
|
b33ab76ff8 | ||
|
|
38a391b7fa | ||
|
|
82434fe87c | ||
|
|
8bf7c36249 | ||
|
|
cff3557a24 | ||
|
|
2c476c4351 | ||
|
|
82c8ab511d | ||
|
|
486ed6edd2 | ||
|
|
a4b0a9ed36 | ||
|
|
bba9c37ba5 | ||
|
|
febc7d1630 | ||
|
|
1ed071949b | ||
|
|
3878c264ef | ||
|
|
21daf0b664 | ||
|
|
5efaa72cea | ||
|
|
191cd7cbba | ||
|
|
c583e31b16 | ||
|
|
590fba7deb | ||
|
|
a8f22003cb | ||
|
|
54596e3fe6 | ||
|
|
2ee4d110a0 | ||
|
|
7a949dccbb | ||
|
|
111a45ab38 | ||
|
|
2bcf59c225 | ||
|
|
d542033125 | ||
|
|
44c72828e1 | ||
|
|
99d3ee32fa | ||
|
|
7df0ff309e | ||
|
|
856a751fcb | ||
|
|
da99bcae5d | ||
|
|
1b0c6c2847 | ||
|
|
c315e817b2 | ||
|
|
6fde07a20d | ||
|
|
8a86159fd7 | ||
|
|
1d532a1fc1 | ||
|
|
a67ce75924 | ||
|
|
b3d845ea32 | ||
|
|
008e12cb42 | ||
|
|
ceaed8be51 | ||
|
|
f0e0979366 | ||
|
|
c43563a804 | ||
|
|
8ec3b2d05d | ||
|
|
39a95c727f | ||
|
|
a2f5a585e3 | ||
|
|
aa95bc62bd | ||
|
|
ae7bfa5bcb | ||
|
|
37de1ec583 | ||
|
|
bb8f0eae1b | ||
|
|
571d3c14c8 | ||
|
|
d7202ae0a7 | ||
|
|
2a9c75e24f | ||
|
|
7231662f94 | ||
|
|
df83927ed7 | ||
|
|
f14dfc5de8 | ||
|
|
188d0c9d5c | ||
|
|
8d68c64fdf | ||
|
|
d796ab350e | ||
|
|
334a1b5bef | ||
|
|
3304ee0985 | ||
|
|
d7b3523544 | ||
|
|
1a8d346064 | ||
|
|
42f9b36667 | ||
|
|
c21e9f2114 | ||
|
|
3dbe605de8 | ||
|
|
41a6dd6175 | ||
|
|
09af6fe0a7 | ||
|
|
3b8c3afa3e | ||
|
|
7b7f4d264c | ||
|
|
c454a4942e | ||
|
|
44cd52af6c | ||
|
|
0d01339b02 | ||
|
|
e5b4ca53f8 | ||
|
|
703b03b33c | ||
|
|
73cdad66ac | ||
|
|
4b1afdbe2d | ||
|
|
64bfc0f29a | ||
|
|
28c4c0b48c | ||
|
|
40ccde9f06 | ||
|
|
baa7d02ba5 | ||
|
|
a391df1e67 | ||
|
|
1f26485208 | ||
|
|
733b72bcbd | ||
|
|
f0816260c5 | ||
|
|
32e9e66e49 | ||
|
|
6e4973cef7 | ||
|
|
4f02472421 | ||
|
|
00ce6be66e | ||
|
|
3eaef148fe | ||
|
|
c92284ab02 | ||
|
|
40718d1180 | ||
|
|
ca325cb7bf | ||
|
|
06e4fc0962 | ||
|
|
8f82ce6ffb | ||
|
|
138f224109 | ||
|
|
ef8c89b999 | ||
|
|
b595a2966c | ||
|
|
3480c5f067 | ||
|
|
a456b10420 | ||
|
|
b7dee707a3 | ||
|
|
9f2f0f1375 | ||
|
|
fe7cf0a595 | ||
|
|
0f79c04d93 | ||
|
|
2d3373efbb | ||
|
|
f3a96b3562 | ||
|
|
7f79fd95b5 | ||
|
|
2eab366a1b | ||
|
|
038a3bb5c8 | ||
|
|
7bef8c99ec | ||
|
|
5cbae6e8e6 | ||
|
|
862c022ec6 | ||
|
|
71349b575b | ||
|
|
2acc08402f | ||
|
|
adf79e1926 | ||
|
|
d2e5c1d33b | ||
|
|
3fce30f709 | ||
|
|
6bdb67f504 | ||
|
|
314f86007e | ||
|
|
476edc6ad3 | ||
|
|
a56cafb97e | ||
|
|
6663b0c257 | ||
|
|
c50d4289c4 | ||
|
|
595080b5c1 | ||
|
|
a9cbd766c8 | ||
|
|
fdfd49105f | ||
|
|
c7afddcfab | ||
|
|
9fe3d4faf0 | ||
|
|
41a827555c | ||
|
|
c9317e4ec5 | ||
|
|
0ae16ccf76 | ||
|
|
73d3b638df | ||
|
|
e2b0a105a7 | ||
|
|
195864d3ac | ||
|
|
c4aa843038 | ||
|
|
843da2664f | ||
|
|
23eaa6a4c7 | ||
|
|
f29bb971e0 | ||
|
|
266123a5e0 | ||
|
|
9b0d01619c | ||
|
|
291162f5f0 | ||
|
|
29820e2ab2 | ||
|
|
a92a72cebd | ||
|
|
fe09dc23a6 | ||
|
|
9cd4a7416e | ||
|
|
f6e3210b0d | ||
|
|
16d33eb02c | ||
|
|
326512697c | ||
|
|
f25de891bf | ||
|
|
e785533858 | ||
|
|
0699bc4147 | ||
|
|
d07a8258e9 | ||
|
|
d490e65315 | ||
|
|
7a632c9561 | ||
|
|
ec4b35fa5f | ||
|
|
b263755629 | ||
|
|
828585a260 | ||
|
|
3b33121dbc | ||
|
|
21484c8184 | ||
|
|
020385c850 | ||
|
|
c585f3d8ae | ||
|
|
3356e6c6cf | ||
|
|
2fa6ad22a3 | ||
|
|
b887519f26 | ||
|
|
b1e54a834c | ||
|
|
171e62a272 | ||
|
|
053770c117 | ||
|
|
911f3e1f54 | ||
|
|
1494ba95b3 | ||
|
|
c0b00ce146 | ||
|
|
47a08b829e | ||
|
|
953bb60aac | ||
|
|
fc4cb31277 | ||
|
|
9876636dbc | ||
|
|
8314ab03bd | ||
|
|
9d887ba3e7 | ||
|
|
1612a8a960 | ||
|
|
99af210e62 | ||
|
|
8fd108cde1 | ||
|
|
ca81d35936 | ||
|
|
d65aacac6f | ||
|
|
43f052a363 | ||
|
|
0e0a38ffa2 | ||
|
|
819586fc4e | ||
|
|
6b8a331428 | ||
|
|
57e7004e05 | ||
|
|
25c95cafe3 | ||
|
|
54be1a8918 | ||
|
|
d4a0573051 | ||
|
|
4a96eac67b | ||
|
|
2f4134a6d2 | ||
|
|
4f87dcc0c0 | ||
|
|
47eba6b720 | ||
|
|
cba537d561 | ||
|
|
c9d03cb042 | ||
|
|
e42c002fbd | ||
|
|
7c7b073a47 | ||
|
|
20090d21eb | ||
|
|
b0e69ff4b8 | ||
|
|
552bb0a98b | ||
|
|
19510858af | ||
|
|
44b2f6ee63 | ||
|
|
c5d3002f31 | ||
|
|
2e3659d4ee | ||
|
|
f8a5509a91 | ||
|
|
421f436871 | ||
|
|
a37c9d6cea | ||
|
|
d14d576d99 | ||
|
|
9391e44e4b | ||
|
|
a7aebe3a61 | ||
|
|
1fca9021a4 | ||
|
|
a39194b2ad | ||
|
|
bff93d9352 | ||
|
|
d76c9cd16d | ||
|
|
14774fe235 | ||
|
|
39046632aa | ||
|
|
fbb2afdb49 | ||
|
|
aff0402f71 | ||
|
|
cee9058c77 | ||
|
|
3f922b4c90 | ||
|
|
02d2d31cf3 | ||
|
|
240cf6a0ed | ||
|
|
dcd9ee93de | ||
|
|
2a8cd74ab1 | ||
|
|
63bc7055c2 | ||
|
|
1cca9733d6 | ||
|
|
1104da5e2c | ||
|
|
3a9718c09d | ||
|
|
55362c5573 | ||
|
|
0bba2299b3 | ||
|
|
45685af9e9 | ||
|
|
6c416a9338 | ||
|
|
1b0027e1d2 | ||
|
|
2409adf516 | ||
|
|
554801dfe4 | ||
|
|
20c23917e9 | ||
|
|
ef953b7574 | ||
|
|
6b79795229 | ||
|
|
9cb7ec2348 | ||
|
|
437c981d30 | ||
|
|
0334cae4c8 | ||
|
|
24c405d747 | ||
|
|
a3f5962809 | ||
|
|
0deb7495f0 | ||
|
|
d34f89fc4b | ||
|
|
a909ed498f | ||
|
|
16f4e17e8f | ||
|
|
0e9592a96c | ||
|
|
704ee6a53a | ||
|
|
5b9afbce9a | ||
|
|
396cc8e8ef | ||
|
|
bf776b5c06 | ||
|
|
be319f88d3 | ||
|
|
af40d555d4 | ||
|
|
f802dbe686 | ||
|
|
2379e3d83b | ||
|
|
9e90ac0412 | ||
|
|
c27948ca3c | ||
|
|
c3b9d664df | ||
|
|
31ef0a5223 | ||
|
|
14c58acea1 | ||
|
|
5dae20603e | ||
|
|
3f6fa94289 | ||
|
|
117615a8b0 | ||
|
|
4a52773c7d | ||
|
|
edfee495c6 | ||
|
|
7d112df7c6 | ||
|
|
9acaaade45 | ||
|
|
aaca28dbf6 | ||
|
|
d4ef5f9d4d | ||
|
|
2095dea801 | ||
|
|
a36f7ef10d | ||
|
|
9874962ee3 | ||
|
|
4b08022075 | ||
|
|
dc3db3aec4 | ||
|
|
0568c2a93d | ||
|
|
7ab0a6fc9e | ||
|
|
d6b780762e | ||
|
|
5ef66b5cf6 | ||
|
|
19e8cd5e48 | ||
|
|
df5117892f | ||
|
|
aaa4216f55 | ||
|
|
85ee5084b6 | ||
|
|
bb9ce117de | ||
|
|
00c5aa26bb | ||
|
|
bae4de227c | ||
|
|
253f891c5a | ||
|
|
6966159062 | ||
|
|
07d3b80c3e | ||
|
|
a41d0f3214 | ||
|
|
1ee15de78b | ||
|
|
b044358970 | ||
|
|
d2e11bb3bb | ||
|
|
a55bac899c | ||
|
|
c2380fb8df | ||
|
|
f31c644b13 | ||
|
|
26cd621d0e | ||
|
|
4c58512c54 | ||
|
|
04c1b47660 | ||
|
|
7b249e9fa6 | ||
|
|
46593ef68f | ||
|
|
b70f73c7d6 | ||
|
|
ece5e34fa2 | ||
|
|
74b400288d | ||
|
|
83f19b0631 | ||
|
|
c905d2d6fb | ||
|
|
d0c1eb2f04 | ||
|
|
d7d9d29c1d | ||
|
|
2a3f019ec6 | ||
|
|
d384d50b0d | ||
|
|
be8cb12bba | ||
|
|
a1aa2918be | ||
|
|
d7536bccb3 | ||
|
|
6b677355e1 | ||
|
|
85d625f6ac | ||
|
|
f5d6f87afe | ||
|
|
31d755f407 | ||
|
|
ebfc20d4b4 | ||
|
|
b83d42103f | ||
|
|
c9856347fe | ||
|
|
7224c92caf | ||
|
|
a84f98c96f | ||
|
|
a40bccc29d | ||
|
|
171897161c | ||
|
|
013ad49e2b | ||
|
|
b357586164 | ||
|
|
5642f3416a | ||
|
|
9bbb1710df | ||
|
|
e2b7679252 | ||
|
|
5c353cd4b5 | ||
|
|
cba6dc994f | ||
|
|
b0c4b7fc2a | ||
|
|
ed7aff1f24 | ||
|
|
33f4be0d88 | ||
|
|
1178cafef0 | ||
|
|
1be97e65b4 | ||
|
|
634cefc694 | ||
|
|
36469c6097 | ||
|
|
0cd9c6a434 | ||
|
|
e285a94273 | ||
|
|
a2ec6d97b1 | ||
|
|
b42fd3fc51 | ||
|
|
12971bb08b | ||
|
|
79deda4f2d | ||
|
|
365af2cd6c | ||
|
|
cc50e76c0d | ||
|
|
16df22af68 | ||
|
|
53a957fa15 | ||
|
|
69571489fa | ||
|
|
3a66b4d67e | ||
|
|
ba8d2b1281 | ||
|
|
11185c127d | ||
|
|
0ab3bfd4f3 | ||
|
|
b5fdb3d0db | ||
|
|
9ef342e448 | ||
|
|
0bda65b5ac | ||
|
|
005b7a760c | ||
|
|
ab3c40a709 | ||
|
|
a809b7f11e | ||
|
|
702c7d49a8 | ||
|
|
a2afaf40cd | ||
|
|
eb900a5c2c | ||
|
|
14eadb3b92 | ||
|
|
a5d84bb266 | ||
|
|
5a03ce4e95 | ||
|
|
607db82db0 | ||
|
|
56b302d4c8 | ||
|
|
1237e9d4bd | ||
|
|
71468e453c | ||
|
|
d0a915e81c | ||
|
|
e7751f40fa | ||
|
|
498240c6ec | ||
|
|
d448cf4c7e | ||
|
|
d7d9f254ff | ||
|
|
aedba5c650 | ||
|
|
a4e9794b13 | ||
|
|
4bd4bd6f22 | ||
|
|
ac9bfbff78 | ||
|
|
e26392ce94 | ||
|
|
a314e56425 | ||
|
|
4af27f7609 | ||
|
|
773017c881 | ||
|
|
153cbeae8a | ||
|
|
777ea9fbe0 | ||
|
|
d22cc7f40a | ||
|
|
c28ca9087c | ||
|
|
857412d9cc | ||
|
|
4b132460f6 | ||
|
|
644f5c0ce1 | ||
|
|
45439e17c9 | ||
|
|
485e0f0510 | ||
|
|
2969d20a92 | ||
|
|
7cf97a5c9b | ||
|
|
f2894ed774 | ||
|
|
3e1044b8fd | ||
|
|
0c6480c5e0 | ||
|
|
232c45979a | ||
|
|
848031c315 | ||
|
|
bf2389c31c | ||
|
|
d87bba7993 | ||
|
|
9b837a8656 | ||
|
|
90061caec3 | ||
|
|
6e81701d4b | ||
|
|
2164c4c3f8 | ||
|
|
a0665187c6 | ||
|
|
77e933f620 | ||
|
|
deed9cf6d7 | ||
|
|
fad4e506bc | ||
|
|
9d6b940b78 | ||
|
|
cfb663d399 | ||
|
|
4620c176b6 | ||
|
|
8c927a59d9 | ||
|
|
2fe9bc9846 | ||
|
|
b9615eadb3 | ||
|
|
e4e5d14d6e | ||
|
|
75eddd2a6f | ||
|
|
634407a22d | ||
|
|
42dd2e5413 | ||
|
|
2a6e3c0add | ||
|
|
abb81e0d8e | ||
|
|
e9a4b43331 | ||
|
|
08b2c39a61 | ||
|
|
f89cec9c55 | ||
|
|
4c49ca2a51 | ||
|
|
52ab6f484b | ||
|
|
2a5359e73b | ||
|
|
977ea73237 | ||
|
|
a769b904dc | ||
|
|
5def5124ef | ||
|
|
40c3cc7f9e | ||
|
|
17c0906044 | ||
|
|
38cfc915f1 | ||
|
|
1821d9fc04 | ||
|
|
ec6a8dd028 | ||
|
|
e0c3b7f808 | ||
|
|
155dc4919e | ||
|
|
a38c53b2be | ||
|
|
67dfc7b32e | ||
|
|
f156551d4f | ||
|
|
5c04eb85af | ||
|
|
1efa27177a | ||
|
|
17da652152 | ||
|
|
4ff866ea29 | ||
|
|
3c9c7abe35 | ||
|
|
157017126a | ||
|
|
928e4ae5ed | ||
|
|
2bc790f4cb | ||
|
|
a3148b264c | ||
|
|
16b27700f5 | ||
|
|
9ee10b6968 | ||
|
|
4d0db0b5c2 | ||
|
|
6e49aaf17b | ||
|
|
1092d75f2e | ||
|
|
8059c3797d | ||
|
|
1302d62ad9 | ||
|
|
8eaae4034d | ||
|
|
354e3414a1 | ||
|
|
fc24beae6d | ||
|
|
923cc67b55 | ||
|
|
30e24069bc | ||
|
|
f7533a454c | ||
|
|
ab4e1a86dc | ||
|
|
d28c2ed113 | ||
|
|
3a467328f5 | ||
|
|
979d83cb01 | ||
|
|
d165cd955d | ||
|
|
6eb770343e | ||
|
|
54be52b855 | ||
|
|
d201333409 | ||
|
|
3db8b4cd17 | ||
|
|
0e246a00bc | ||
|
|
e638fa8929 | ||
|
|
cdc982ad91 | ||
|
|
bff69e21ad | ||
|
|
e117cc0cfb | ||
|
|
3af1a88e05 | ||
|
|
aa116a35f5 | ||
|
|
ac232d7f55 | ||
|
|
928911e33c | ||
|
|
e3c30f5bb3 | ||
|
|
4b51855528 | ||
|
|
79c27db0a9 | ||
|
|
78e42ab352 | ||
|
|
93909c45ee | ||
|
|
eda0bf4b23 | ||
|
|
4f4b10e0b6 | ||
|
|
2b374a8bec | ||
|
|
7821de4a8d | ||
|
|
86b88c851f | ||
|
|
1157882f1b | ||
|
|
594d1373c9 | ||
|
|
1e6948bbc7 | ||
|
|
41845b97d5 | ||
|
|
bb56f74622 | ||
|
|
a98f6ac331 | ||
|
|
15d6287995 | ||
|
|
0242ab72e8 | ||
|
|
4b7cbf37d5 | ||
|
|
0ccfe7d991 | ||
|
|
ab5585cd06 | ||
|
|
b25a0a7a4e | ||
|
|
f574c12adc | ||
|
|
05a2f03c18 | ||
|
|
cbc2e65856 | ||
|
|
1df80a7d2a | ||
|
|
050a014df7 | ||
|
|
4775ae09b0 | ||
|
|
8d4c3bb4fc | ||
|
|
439260ff03 | ||
|
|
5b04ad6805 | ||
|
|
6d77ed1e0e | ||
|
|
cc7f783b50 | ||
|
|
1d7ed1983b | ||
|
|
c0151353c5 | ||
|
|
72994248fa | ||
|
|
af0d3d5ee1 | ||
|
|
07dd1d2e91 | ||
|
|
185a88a16e | ||
|
|
e3059e636a | ||
|
|
aeb566746a | ||
|
|
8da567d9fa | ||
|
|
d99f69cc24 | ||
|
|
8240962400 | ||
|
|
bd1d4289c0 | ||
|
|
5d2139471a | ||
|
|
d49a64ac1e | ||
|
|
cd867ea581 | ||
|
|
32fd62c484 | ||
|
|
f2c561bd15 | ||
|
|
80734944d3 | ||
|
|
b3afa9f595 | ||
|
|
656558850c | ||
|
|
e41cca9be0 | ||
|
|
46916b34d4 | ||
|
|
4f9ca3e74d | ||
|
|
2bcdd0f52b | ||
|
|
56d790dda9 | ||
|
|
149013d2ff | ||
|
|
776807580a | ||
|
|
75e9eee3a9 | ||
|
|
183615fa7b | ||
|
|
7405fbaa16 | ||
|
|
22743b6d8b | ||
|
|
b5864f02cb | ||
|
|
373431fb1a | ||
|
|
29167fbdf2 | ||
|
|
699ac3a8e6 | ||
|
|
d7b572faaf | ||
|
|
a09b4e7f2c | ||
|
|
a794420d3e | ||
|
|
8b606266c5 | ||
|
|
11e4329d5e | ||
|
|
68dfc6ca81 | ||
|
|
e0c8945431 | ||
|
|
fe60ee00fb | ||
|
|
5990e00577 | ||
|
|
358a699290 | ||
|
|
da6e4378d9 | ||
|
|
5edb0629b3 | ||
|
|
5170854a2c | ||
|
|
37d6033df4 | ||
|
|
ea2f891533 | ||
|
|
42cec7d5ba | ||
|
|
2df2e39d43 | ||
|
|
b34525a4d8 | ||
|
|
0a7bd64b0d | ||
|
|
11fd4f88ec | ||
|
|
4d9452b862 | ||
|
|
060e30e612 | ||
|
|
ade7270add | ||
|
|
338428b0c0 | ||
|
|
54574e4450 | ||
|
|
ae564451b8 | ||
|
|
9a4504ce61 | ||
|
|
80785a2ff3 | ||
|
|
cb8ed02e82 | ||
|
|
a64c1b8eab | ||
|
|
d43aa169c3 | ||
|
|
8ae7141851 | ||
|
|
d3908db2c9 | ||
|
|
55de838a55 | ||
|
|
4cdfc38b87 | ||
|
|
51197d7c1a | ||
|
|
2a2a2e0c05 | ||
|
|
07fee30cc0 | ||
|
|
83c6ce0ace | ||
|
|
fb7303efa0 | ||
|
|
ef5585d312 | ||
|
|
11475259a1 | ||
|
|
9df4cd6f13 | ||
|
|
c9583964c8 | ||
|
|
5022ed1a63 | ||
|
|
799ffa18c4 | ||
|
|
6323e27040 | ||
|
|
03acb26109 | ||
|
|
34fc1f6a6b | ||
|
|
042032ec46 | ||
|
|
73de99f661 | ||
|
|
cc068f9ebb | ||
|
|
2bfc2b1944 | ||
|
|
029936112f | ||
|
|
d5e400e8a4 | ||
|
|
9dbb9c3f3b | ||
|
|
a101e6b0a7 | ||
|
|
c525ea55ce | ||
|
|
8ca45f298f | ||
|
|
cb4c6cb677 | ||
|
|
d574a97a35 | ||
|
|
20f9a86ad9 | ||
|
|
a4a411cf1f | ||
|
|
029bda5734 | ||
|
|
0fd578e6aa | ||
|
|
95e1bee5e6 | ||
|
|
c8dc10f311 | ||
|
|
a00f4e393b | ||
|
|
5a7dea8857 | ||
|
|
27e8970fff | ||
|
|
7848274ba1 | ||
|
|
145bf0298b | ||
|
|
0392a33b54 | ||
|
|
b211f46e3e | ||
|
|
709711c3ca | ||
|
|
841607406f | ||
|
|
70b726b04d | ||
|
|
2799248106 | ||
|
|
2321299084 | ||
|
|
aa00773a3b | ||
|
|
733de1d0e1 | ||
|
|
c16e4ad412 | ||
|
|
d1cf7a07f1 | ||
|
|
8751f6fea7 | ||
|
|
ea1b577ec7 | ||
|
|
a41afa70eb | ||
|
|
e11c97cdc0 | ||
|
|
d76e44512e | ||
|
|
fd1931377d | ||
|
|
68ce6c4ed7 | ||
|
|
a2ee330307 | ||
|
|
c3a17f951e | ||
|
|
443c0f34d7 | ||
|
|
8725600368 | ||
|
|
3b83b7f190 | ||
|
|
e0c3a1c143 | ||
|
|
bec1ad7bee | ||
|
|
9e6c00f78c | ||
|
|
abbbd9d705 | ||
|
|
4a5c012f05 | ||
|
|
319862b3d4 | ||
|
|
1fcf58024d | ||
|
|
9db162d0fc | ||
|
|
13b15390c3 | ||
|
|
799b62e9d2 | ||
|
|
d91ed535ad | ||
|
|
c48b9874bf | ||
|
|
6a788f6c32 | ||
|
|
53519a604e | ||
|
|
2818b87f02 | ||
|
|
50e10133b9 | ||
|
|
068161719e | ||
|
|
c8d5d095e0 | ||
|
|
52d07320ef | ||
|
|
158b9ea2ca | ||
|
|
6a100bfbab | ||
|
|
b3bd6ee176 | ||
|
|
04696b27eb | ||
|
|
332937dbc1 | ||
|
|
92d932ce5c | ||
|
|
af3c4f536a | ||
|
|
b98ca5af52 | ||
|
|
a15a11f44b | ||
|
|
1460132772 | ||
|
|
76d68bb3e4 | ||
|
|
08df0ebbea | ||
|
|
e918db2cc1 | ||
|
|
2e0dc8db94 | ||
|
|
b78a9f2a9c | ||
|
|
832e6b9de0 | ||
|
|
feec7ca408 | ||
|
|
408f0a12e2 | ||
|
|
35ab4e6e09 | ||
|
|
430bafafe7 | ||
|
|
58d727350d | ||
|
|
c6a4057659 | ||
|
|
60ac806690 | ||
|
|
e9263fc596 | ||
|
|
3dd28a0382 | ||
|
|
066cb8184e | ||
|
|
373e22b999 | ||
|
|
fd8725f649 | ||
|
|
3d433762b1 | ||
|
|
ea4cb5bf62 | ||
|
|
a6ca3b8203 | ||
|
|
bc4ceb6d52 | ||
|
|
24480229cd | ||
|
|
8b10573197 | ||
|
|
cbc81e8285 | ||
|
|
0b9a978061 | ||
|
|
e974e5d13b | ||
|
|
5a42e86bf6 | ||
|
|
889946e186 | ||
|
|
5c47e8044e | ||
|
|
1a974ac305 | ||
|
|
db1bf61805 | ||
|
|
5456b4a7ff | ||
|
|
a08ffaae77 | ||
|
|
18445f55f0 | ||
|
|
2daf3b5c4b | ||
|
|
923b844212 | ||
|
|
0aec9f8472 | ||
|
|
23b0c8a143 | ||
|
|
3c2c2e2bd8 | ||
|
|
c1465a7368 | ||
|
|
be1dadab74 | ||
|
|
1cba39eae9 | ||
|
|
a0c8bdf021 | ||
|
|
6fdb22a5b5 | ||
|
|
19c370a273 | ||
|
|
861336ea97 | ||
|
|
24219bcb03 | ||
|
|
77ed762e2c | ||
|
|
d45b6cb03d | ||
|
|
9a921b2e0d | ||
|
|
c17e213e11 | ||
|
|
6275d7afaa | ||
|
|
364eda6400 | ||
|
|
ccf34cfe20 | ||
|
|
7daae6a2d9 | ||
|
|
277a4ad124 | ||
|
|
b11d46e34a | ||
|
|
e8ad0a055d | ||
|
|
8a8c745d77 | ||
|
|
a523fe7674 | ||
|
|
dc9a150929 | ||
|
|
be66ffef0f | ||
|
|
f278cc0c86 | ||
|
|
7f72808a9a | ||
|
|
1d5297c0f0 | ||
|
|
e40528ba45 | ||
|
|
29972b5867 | ||
|
|
91109ca845 | ||
|
|
8e5ccb5461 | ||
|
|
8a75967953 | ||
|
|
3f4965b182 | ||
|
|
2ac266029c | ||
|
|
3261231d07 | ||
|
|
95ce6385b0 | ||
|
|
64c5894602 | ||
|
|
8c4839c300 | ||
|
|
80c2bc1a52 | ||
|
|
bcd417e039 | ||
|
|
ac216f697f | ||
|
|
9893fae27c | ||
|
|
cb183efa66 | ||
|
|
87d707bc21 | ||
|
|
227ebd610a | ||
|
|
ab4af48e52 | ||
|
|
78a8227219 | ||
|
|
ec73a53101 | ||
|
|
3fb1d086b7 | ||
|
|
5d4a12c127 | ||
|
|
d2a79214b5 | ||
|
|
db57111188 | ||
|
|
b22276bcd5 | ||
|
|
6e2d85f2d2 | ||
|
|
efb72652ce | ||
|
|
3615c3e8e5 | ||
|
|
8186ee0e3f | ||
|
|
74aa14c011 | ||
|
|
aa68369f95 | ||
|
|
7837364b86 | ||
|
|
31f0e39617 | ||
|
|
a48151920d | ||
|
|
8199653ddd | ||
|
|
9d650519c7 | ||
|
|
a545eaca97 | ||
|
|
9da9de2d2d | ||
|
|
c9ddd9d513 | ||
|
|
415cfd57e7 | ||
|
|
b1ede93cdb | ||
|
|
32df465c8a | ||
|
|
2f1c5df11d | ||
|
|
f85f6a7fdc | ||
|
|
93cc80a4b3 | ||
|
|
0f3e401d42 | ||
|
|
a9f2c33053 | ||
|
|
c5ef8c3fec | ||
|
|
ad696bd60b | ||
|
|
9da7462f3e | ||
|
|
0ecdf354c6 | ||
|
|
67f10632fb | ||
|
|
044b910357 | ||
|
|
3de943e50f | ||
|
|
1a2272249d | ||
|
|
0dfeec6cae | ||
|
|
8d193021ab | ||
|
|
f45226a680 | ||
|
|
40d55805ff | ||
|
|
7d6d0b012b | ||
|
|
d7d2c6bf01 | ||
|
|
ce1c6096d3 | ||
|
|
8c4ea6180a | ||
|
|
95649ba758 | ||
|
|
2b61f2a9e8 | ||
|
|
47242aa66c | ||
|
|
31a8abe615 | ||
|
|
4dae3c34b4 | ||
|
|
65aa8919b9 | ||
|
|
acf8eac0d4 | ||
|
|
e8aa29d3c2 | ||
|
|
a36194afe2 | ||
|
|
8554898e45 | ||
|
|
55b29f645b | ||
|
|
52cc91ba3e | ||
|
|
c9e3a9f8fe | ||
|
|
c3de788956 | ||
|
|
53e3c36f7e | ||
|
|
20908107a0 | ||
|
|
cbe1a0d6f8 | ||
|
|
7d8c79ec57 | ||
|
|
9bb89c728f | ||
|
|
be2e28cc53 | ||
|
|
57be57971d | ||
|
|
64eed47f04 | ||
|
|
7659105fda | ||
|
|
18c9376992 | ||
|
|
3a4aca7fbd | ||
|
|
85ff8cdd4a | ||
|
|
b1048cb84a | ||
|
|
ff9cf9abf6 | ||
|
|
157c84663d | ||
|
|
908e4fb5a4 | ||
|
|
fdca7d58e5 | ||
|
|
2eb26d512b | ||
|
|
b7fdf7d60f | ||
|
|
2a1e66468d | ||
|
|
cd7faf751e | ||
|
|
d79d806cda | ||
|
|
cae389c04c | ||
|
|
4e6850a60c | ||
|
|
a71f8cf358 | ||
|
|
fe6ff9b2b6 | ||
|
|
5a0f3e474d | ||
|
|
cd9c4239b1 | ||
|
|
0cf1d87b12 | ||
|
|
99d91c1e07 | ||
|
|
457f80bc9b | ||
|
|
968e3fc23b | ||
|
|
b1e338579d | ||
|
|
7e4361bb5e | ||
|
|
dd35fa3d91 | ||
|
|
affb911d97 | ||
|
|
785f9cd1b6 | ||
|
|
419056f098 | ||
|
|
396db18de2 | ||
|
|
f124721cd9 | ||
|
|
52e49b49fb | ||
|
|
10e03777e9 | ||
|
|
27538b72e9 | ||
|
|
19ace37a75 | ||
|
|
90c5377ef0 | ||
|
|
f0e3d3e474 | ||
|
|
26064ebf8c | ||
|
|
1d92b74131 | ||
|
|
5f83c137d2 | ||
|
|
fa57db8e83 | ||
|
|
9d3c2e19f5 | ||
|
|
46a9600d55 | ||
|
|
de40701cf6 | ||
|
|
307536c6b6 | ||
|
|
203be8bd35 | ||
|
|
1e644587b3 | ||
|
|
66a60f09e3 | ||
|
|
69b6f16ec1 | ||
|
|
10b4274a3d | ||
|
|
28c9d94457 | ||
|
|
d74fd1a560 | ||
|
|
624b1b06c5 | ||
|
|
95376c2ccc | ||
|
|
1eb622165b | ||
|
|
9d6ba324fb | ||
|
|
d462852ab9 | ||
|
|
eeec81898b | ||
|
|
ab0c8b8170 | ||
|
|
91d295e0bb | ||
|
|
125974dd7a | ||
|
|
92895a7d00 | ||
|
|
d9308440e6 | ||
|
|
5340142c06 | ||
|
|
012d30ee9f | ||
|
|
031d69d996 | ||
|
|
8b63c18f65 | ||
|
|
dc2f11eb2b | ||
|
|
13e64a9487 | ||
|
|
6a3c88ae5b | ||
|
|
08a7e324aa | ||
|
|
9202a4525f | ||
|
|
bfc756fb35 | ||
|
|
2a735ff1cc | ||
|
|
551092a1b4 | ||
|
|
ddd12688aa | ||
|
|
71767c4172 | ||
|
|
ee405fbff6 | ||
|
|
c87c6fbabb | ||
|
|
096b36b89b | ||
|
|
c3db90d2e3 | ||
|
|
b7df10aa45 | ||
|
|
fea5e02e7d | ||
|
|
cb94261727 | ||
|
|
efac7e4860 | ||
|
|
0f6fd3adee | ||
|
|
e5e0405401 | ||
|
|
bb35e9ce15 | ||
|
|
5881db4e55 | ||
|
|
89f7167b08 | ||
|
|
3b39fcff84 | ||
|
|
0daf45a465 | ||
|
|
c0d7b96e79 | ||
|
|
a247e40865 | ||
|
|
c3e7a99bca | ||
|
|
9080d8be6a | ||
|
|
b7ee83f6b6 | ||
|
|
1e24bde9a9 | ||
|
|
ba82df1152 | ||
|
|
8980fe7838 | ||
|
|
ef34ed7c20 | ||
|
|
17d60b79ca | ||
|
|
ab0a32c339 | ||
|
|
697778df8d | ||
|
|
55caf84b94 | ||
|
|
335c012f1b | ||
|
|
3c4c538de8 | ||
|
|
c344a3ee55 | ||
|
|
d2695947ed | ||
|
|
21beeef920 | ||
|
|
a4630a53fa | ||
|
|
f5aef8d0c3 | ||
|
|
e044e66030 | ||
|
|
88bfacd386 | ||
|
|
c61c73088f | ||
|
|
2887263f26 | ||
|
|
72b90bdf5c | ||
|
|
163b02f023 | ||
|
|
1a96899336 | ||
|
|
554c086aba | ||
|
|
1fad9bf7db | ||
|
|
22d922e451 | ||
|
|
70bff21632 | ||
|
|
f58c390a47 | ||
|
|
089a9abcb4 | ||
|
|
bf1c76d0a6 | ||
|
|
879da627b1 | ||
|
|
9b93eb44d5 | ||
|
|
b30220eca9 | ||
|
|
d270d4e5e1 | ||
|
|
21da6cb0f4 | ||
|
|
6ac75df935 | ||
|
|
f29781349c | ||
|
|
bb776d5c2b | ||
|
|
6cfab9e3ea | ||
|
|
6373186c15 | ||
|
|
e342de3bc1 | ||
|
|
4cd7b69ea5 | ||
|
|
988e8529da | ||
|
|
6a32d1e961 | ||
|
|
0552c798fb | ||
|
|
a53ad41879 | ||
|
|
92351edcd0 | ||
|
|
878eb48cb0 | ||
|
|
053ca6bed8 | ||
|
|
78ae14ab2f | ||
|
|
5fdc2ad765 | ||
|
|
b75dbe8d5c | ||
|
|
eaf4663c84 | ||
|
|
64b8cd5bcc | ||
|
|
482d61ee47 | ||
|
|
276dcce95e | ||
|
|
217f9e2e02 | ||
|
|
f40a0a6f5f | ||
|
|
9bd67acc2f | ||
|
|
e87da0feb0 | ||
|
|
2608d879fa | ||
|
|
6ab61fd41f | ||
|
|
30dd6297ee | ||
|
|
ce02183f82 | ||
|
|
7c74a6cbe1 | ||
|
|
e6a11b2ad8 | ||
|
|
158942d1b5 | ||
|
|
aaa97ec029 | ||
|
|
882ead5715 | ||
|
|
ab4519dedd | ||
|
|
c3fd2428a2 | ||
|
|
fbb4b962fa | ||
|
|
9bf65de649 | ||
|
|
75f069cb7d | ||
|
|
87d50125ab | ||
|
|
dc2cf21cb8 | ||
|
|
bae14ecd35 | ||
|
|
b48c1c3b80 | ||
|
|
0f9eb4beeb | ||
|
|
0ab8624d79 | ||
|
|
e872c934c3 | ||
|
|
c3d5d18aae | ||
|
|
ff5853a850 | ||
|
|
f772906324 | ||
|
|
07eabb2dc1 | ||
|
|
b3c88763a4 | ||
|
|
f7081f8829 | ||
|
|
ceef2167fd | ||
|
|
1dcfd94328 | ||
|
|
a1aa0804e2 | ||
|
|
77176478eb | ||
|
|
bf4ebfa7a8 | ||
|
|
6e7d622b41 | ||
|
|
8398b7d24d | ||
|
|
aef9b7375a | ||
|
|
ba45318b56 | ||
|
|
7d4f8780ad | ||
|
|
b504c990f8 | ||
|
|
e07b876677 | ||
|
|
a0bfd34951 | ||
|
|
b173714bbe | ||
|
|
db4021b601 | ||
|
|
2f46fd1d2c | ||
|
|
1f85f848e2 | ||
|
|
d7e0954e86 | ||
|
|
1671e05d12 | ||
|
|
33c55d1563 | ||
|
|
4984181613 | ||
|
|
af75136269 | ||
|
|
c8eb75a148 | ||
|
|
5109b4fcd1 | ||
|
|
1b7f482d0b | ||
|
|
6f9a273d39 | ||
|
|
51d354a9c8 | ||
|
|
40b2b9554b | ||
|
|
ba1aca84ff | ||
|
|
17688a49d5 | ||
|
|
5ff199cc3e | ||
|
|
81a79105d7 | ||
|
|
e39760ccfb | ||
|
|
1c43da2532 | ||
|
|
2846def00f | ||
|
|
e2eb6ab33c | ||
|
|
35b08d085c | ||
|
|
064b0581a7 | ||
|
|
0cc38aa69a | ||
|
|
8312483659 | ||
|
|
0ceb0b4421 | ||
|
|
cc373365fb | ||
|
|
75d9b6e2a1 | ||
|
|
78fa38ba68 | ||
|
|
0b28712a34 | ||
|
|
48937c8d9a | ||
|
|
8c966a5e1a | ||
|
|
f49dd371b7 | ||
|
|
6947fbc12a | ||
|
|
550dc43dc0 | ||
|
|
23c9a4fea7 | ||
|
|
7d26f3351f | ||
|
|
b546554fef | ||
|
|
cc058a7cd3 | ||
|
|
7654b83339 | ||
|
|
93426546ad | ||
|
|
23bc38ca6c | ||
|
|
5ccce364d3 | ||
|
|
b488b55a71 | ||
|
|
0bace17074 | ||
|
|
ad6c7dbd1f | ||
|
|
2a6e63595e | ||
|
|
4d62ad1938 | ||
|
|
e7c3a24011 | ||
|
|
37468607fe | ||
|
|
5b007129e3 | ||
|
|
93ceb4d49c | ||
|
|
85b806fcba | ||
|
|
20596aabb8 | ||
|
|
825108c59e | ||
|
|
09c31b20e6 | ||
|
|
78271a3738 | ||
|
|
e029aaadfc | ||
|
|
f6efa35ed2 | ||
|
|
728bad00b4 | ||
|
|
97f3013f7a | ||
|
|
269a832ac9 | ||
|
|
3b5b7af531 | ||
|
|
76e7eb7009 | ||
|
|
fa99b8829d | ||
|
|
98b749ee9f | ||
|
|
cb9fd02dc7 | ||
|
|
1f4a271dd6 | ||
|
|
bdf192df58 | ||
|
|
1249304907 | ||
|
|
10e3ab1f78 | ||
|
|
59ea270b2f | ||
|
|
3b748e2e21 | ||
|
|
432fae5ce2 | ||
|
|
f557ceda19 | ||
|
|
943f6c762c | ||
|
|
5a9293e293 | ||
|
|
a1bc52c1a5 | ||
|
|
dcd752be8f | ||
|
|
deb2c61b28 | ||
|
|
5e346283a9 | ||
|
|
dc1e4219a0 | ||
|
|
a916f70698 | ||
|
|
77da4d2d53 | ||
|
|
1ae3fc86da | ||
|
|
0c24996b44 | ||
|
|
1cbb4a93eb | ||
|
|
1fac6ca34a | ||
|
|
ca439b0f86 | ||
|
|
f70febc8d3 | ||
|
|
628de56087 | ||
|
|
bc67033c00 | ||
|
|
e0ba2a179c | ||
|
|
e0ce5d9544 | ||
|
|
38acfe04b9 | ||
|
|
5b0068d9e4 | ||
|
|
38edad2ac5 | ||
|
|
e95f191dc6 | ||
|
|
8ae92ff4d4 | ||
|
|
40e15d456a | ||
|
|
a1b3308cd7 | ||
|
|
48ef19e4be | ||
|
|
d3f00b9246 | ||
|
|
89de676982 | ||
|
|
6dec624d22 | ||
|
|
d4eb9ea320 | ||
|
|
1cfaa88989 | ||
|
|
82ae0891a8 | ||
|
|
58c43b0cd4 | ||
|
|
1c373031bd | ||
|
|
e93842a95f | ||
|
|
9cdb34cb1d | ||
|
|
864f9b8f74 | ||
|
|
d99fae333a | ||
|
|
b27bec3e16 | ||
|
|
5fb4838734 | ||
|
|
1296255a86 | ||
|
|
e3ed2fcaa9 | ||
|
|
69d6b90a12 | ||
|
|
6937a4b2fe | ||
|
|
621c36f821 | ||
|
|
940929d044 | ||
|
|
bac5fa8c14 | ||
|
|
a10da64378 | ||
|
|
f2c12c582e | ||
|
|
a686c44555 | ||
|
|
8e96217ae6 | ||
|
|
ec906813fc | ||
|
|
36543d0872 | ||
|
|
fc6ea0b779 | ||
|
|
dae23ccd4b | ||
|
|
666cd3c81f | ||
|
|
dc5366e924 | ||
|
|
f21b3bb0e4 | ||
|
|
4ebcc36fb3 | ||
|
|
292cfb0d3d | ||
|
|
1b59917f16 | ||
|
|
fcf64a7e1b | ||
|
|
b598584aea | ||
|
|
0ebcacce69 | ||
|
|
33c38288a3 | ||
|
|
f00e3ded45 | ||
|
|
250483fbe7 | ||
|
|
755a060e12 | ||
|
|
6d3839dd42 | ||
|
|
15084459bb | ||
|
|
7150445f8e | ||
|
|
b02bdd22dd | ||
|
|
8755cd9d61 | ||
|
|
2c4c07dc81 | ||
|
|
645771c03d | ||
|
|
b2af69fd92 | ||
|
|
ca57732871 | ||
|
|
cd9e98f24b | ||
|
|
136da65381 | ||
|
|
b909cb2db8 | ||
|
|
3a4b531edf | ||
|
|
413453dd85 | ||
|
|
fe52d26f05 | ||
|
|
6029c0d0b3 | ||
|
|
12bfe9d6ca | ||
|
|
dd910f2856 | ||
|
|
b4e0d9e996 | ||
|
|
d3f691548c | ||
|
|
367131d64c | ||
|
|
2895b7bc21 | ||
|
|
f9cdd55a4d | ||
|
|
1854373dd6 | ||
|
|
00a621a5f7 | ||
|
|
f047bd797e | ||
|
|
777f8b4276 | ||
|
|
0992b7fc93 | ||
|
|
b7d6208869 | ||
|
|
da4ce27168 | ||
|
|
4746401bec | ||
|
|
79cf399bf5 | ||
|
|
563323f241 | ||
|
|
e2048dfa1c | ||
|
|
c986c63b84 | ||
|
|
0b3426a9b2 | ||
|
|
173e507ebf | ||
|
|
fb3b1490a9 | ||
|
|
48502480df | ||
|
|
efb3b8f38c | ||
|
|
f185b1773c | ||
|
|
95fff4c9f7 | ||
|
|
27662f9a4a | ||
|
|
f9f678a801 | ||
|
|
8e07e7553a | ||
|
|
bb566e3c7b | ||
|
|
35c68a6de1 | ||
|
|
7fd8394253 | ||
|
|
c54a447caf | ||
|
|
61b009422d | ||
|
|
5a8b0184ea | ||
|
|
f48c2a21d9 | ||
|
|
538cfbee8d | ||
|
|
7666f1c362 | ||
|
|
4b5d828bf8 | ||
|
|
4bd160cceb | ||
|
|
5f56fc1156 | ||
|
|
72a2a74395 | ||
|
|
f6a5cc7c25 | ||
|
|
80f3bd64b6 | ||
|
|
1f69a96766 | ||
|
|
f963e06983 | ||
|
|
e6980e2370 | ||
|
|
8e8105d04d | ||
|
|
21d9e69712 | ||
|
|
e0783a3c6e | ||
|
|
3b9337d2a8 | ||
|
|
85cda8ffa7 | ||
|
|
f1efc1f17d | ||
|
|
0486fa61cd | ||
|
|
2247a2a7af | ||
|
|
08a0fbfd6b | ||
|
|
898b993b94 | ||
|
|
77e366b179 | ||
|
|
981edc9cf7 | ||
|
|
d45aa14348 | ||
|
|
4926488d49 | ||
|
|
dcc1935150 | ||
|
|
55364a8eb8 | ||
|
|
70bb06715f | ||
|
|
ec4aa73e37 | ||
|
|
c1d122a717 |
2
.contextProperties.ini
Normal file
2
.contextProperties.ini
Normal file
@@ -0,0 +1,2 @@
|
||||
[General]
|
||||
disableUnqualifiedAccess = "i18nc,xi18nc,i18ncp,i18n"
|
||||
@@ -2,6 +2,5 @@
|
||||
; SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
[BlueprintSettings]
|
||||
kde/frameworks/extra-cmake-modules.version=master
|
||||
kde/unreleased/kirigami-addons.version=master
|
||||
kde/applications/neochat.packageAppx=True
|
||||
libs/qt.qtMajorVersion=6
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"id": "org.kde.neochat",
|
||||
"branch": "master",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "6.6-kf6preview",
|
||||
"runtime-version": "6.9",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "neochat",
|
||||
"tags": [
|
||||
@@ -20,18 +20,52 @@
|
||||
"--talk-name=org.kde.kwalletd5",
|
||||
"--talk-name=org.kde.StatusNotifierWatcher",
|
||||
"--talk-name=org.freedesktop.secrets",
|
||||
"--talk-name=org.kde.kuiserver",
|
||||
"--own-name=org.kde.StatusNotifierItem-2-2"
|
||||
],
|
||||
"cleanup": [
|
||||
"/include",
|
||||
"/lib/*.a",
|
||||
"/lib/cmake",
|
||||
"/lib/pkgconfig",
|
||||
"/share/ndk-modules"
|
||||
],
|
||||
"modules": [
|
||||
{
|
||||
"name": "kirigamiaddons",
|
||||
"config-opts": [ "-DBUILD_TESTING=OFF" ],
|
||||
"config-opts": [
|
||||
"-DBUILD_TESTING=OFF"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [ { "type": "git", "url": "https://invent.kde.org/libraries/kirigami-addons.git" } ]
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://invent.kde.org/libraries/kirigami-addons.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opencv",
|
||||
"config-opts": [
|
||||
"-DBUILD_TESTS=OFF",
|
||||
"-DWITH_GTK=OFF",
|
||||
"-DBUILD_LIST=core,imgproc"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/opencv/opencv"
|
||||
}
|
||||
],
|
||||
"builddir": true
|
||||
},
|
||||
{
|
||||
"name": "kquickimageeditor",
|
||||
"config-opts": [ "-DBUILD_WITH_QT6=ON" ],
|
||||
"config-opts": [
|
||||
"-DBUILD_WITH_QT6=ON",
|
||||
"-DBUILD_TESTING=OFF"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
@@ -43,17 +77,19 @@
|
||||
{
|
||||
"name": "olm",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [ "-DOLM_TESTS=OFF" ],
|
||||
"config-opts": [
|
||||
"-DOLM_TESTS=OFF"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.matrix.org/matrix-org/olm.git",
|
||||
"tag": "3.2.10",
|
||||
"tag": "3.2.16",
|
||||
"x-checker-data": {
|
||||
"type": "git",
|
||||
"tag-pattern": "^([\\d.]+)$"
|
||||
},
|
||||
"commit": "9908862979147a71dc6abaecd521be526ae77be1"
|
||||
"commit": "7e0c8277032e40308987257b711b38af8d77cc69"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -65,13 +101,13 @@
|
||||
"-Dvapi=false",
|
||||
"-Dgtk_doc=false",
|
||||
"-Dintrospection=false",
|
||||
"-Dgcrypt=false"
|
||||
"-Dcrypto=disabled"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.gnome.org/sources/libsecret/0.20/libsecret-0.20.5.tar.xz",
|
||||
"sha256": "3fb3ce340fcd7db54d87c893e69bfc2b1f6e4d4b279065ffe66dac9f0fd12b4d",
|
||||
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz",
|
||||
"sha256": "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e",
|
||||
"x-checker-data": {
|
||||
"type": "gnome",
|
||||
"name": "libsecret",
|
||||
@@ -86,13 +122,13 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/frankosterfeld/qtkeychain/archive/0.14.2.tar.gz",
|
||||
"sha256": "cf2e972b783ba66334a79a30f6b3a1ea794a1dc574d6c3bebae5ffd2f0399571",
|
||||
"url": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/0.15.0.tar.gz",
|
||||
"sha256": "f4254dc8f0933b06d90672d683eab08ef770acd8336e44dfa030ce041dc2ca22",
|
||||
"x-checker-data": {
|
||||
"type": "anitya",
|
||||
"project-id": 4138,
|
||||
"stable-only": true,
|
||||
"url-template": "https://github.com/frankosterfeld/qtkeychain/archive/v$version.tar.gz"
|
||||
"url-template": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/$version.tar.gz"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -100,7 +136,8 @@
|
||||
"-DBUILD_WITH_QT6=ON",
|
||||
"-DCMAKE_INSTALL_LIBDIR=/app/lib",
|
||||
"-DLIB_INSTALL_DIR=/app/lib",
|
||||
"-DBUILD_TRANSLATIONS=NO"
|
||||
"-DBUILD_TRANSLATIONS=NO",
|
||||
"-DBUILD_TESTING=OFF"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,7 +147,7 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||
"branch": "dev",
|
||||
"branch": "0.9.6.1",
|
||||
"disable-submodules": true
|
||||
}
|
||||
],
|
||||
@@ -123,34 +160,37 @@
|
||||
{
|
||||
"name": "cmark",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [ "-DCMARK_TESTS=OFF" ],
|
||||
"config-opts": [
|
||||
"-DCMARK_TESTS=OFF",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_INSTALL_PREFIX=/app"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/commonmark/cmark.git"
|
||||
}
|
||||
],
|
||||
"config-opts": [
|
||||
"-DCMARK_TESTS=OFF",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_INSTALL_PREFIX=/app"
|
||||
],
|
||||
"builddir": true
|
||||
},
|
||||
{
|
||||
"name": "qcoro",
|
||||
"name": "kunifiedpush",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [ "-DQCORO_BUILD_EXAMPLES=OFF", "-DBUILD_TESTING=OFF" ],
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"-DENABLE_TESTING=OFF",
|
||||
"-DKUNIFIEDPUSH_CLIENT_ONLY=ON"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.7.0.tar.gz",
|
||||
"sha256": "23ef0217926e67c8d2eb861cf91617da2f7d8d5a9ae6c62321b21448b1669210",
|
||||
"url": "https://download.kde.org/stable/release-service/25.08.0/src/kunifiedpush-25.08.0.tar.xz",
|
||||
"sha256": "846db6ffc7d93f6afea7ce0d5a9f10b52792157ceb593856542279f4197f3518",
|
||||
"x-checker-data": {
|
||||
"type": "anitya",
|
||||
"project-id": 236236,
|
||||
"project-id": 8763,
|
||||
"stable-only": true,
|
||||
"url-template": "https://github.com/danvratil/qcoro/archive/refs/tags/v$version.tar.gz"
|
||||
"url-template": "https://download.kde.org/stable/release-service/$version/src/kunifiedpush-$version.tar.xz"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -158,14 +198,15 @@
|
||||
{
|
||||
"name": "neochat",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [
|
||||
"-DBUILD_TESTING=OFF",
|
||||
"-DNEOCHAT_FLATPAK=ON"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"config-opts": [
|
||||
"-DNEOCHAT_FLATPAK=ON"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ kate.project.ctags.*
|
||||
.idea/
|
||||
cmake-build-*
|
||||
src/res.generated.qrc
|
||||
.qmlls.ini
|
||||
|
||||
@@ -5,11 +5,17 @@ include:
|
||||
- project: sysadmin/ci-utilities
|
||||
file:
|
||||
- /gitlab-templates/reuse-lint.yml
|
||||
- /gitlab-templates/json-validation.yml
|
||||
- /gitlab-templates/xml-lint.yml
|
||||
- /gitlab-templates/yaml-lint.yml
|
||||
- /gitlab-templates/android-qt6.yml
|
||||
- /gitlab-templates/linux-qt6.yml
|
||||
- /gitlab-templates/linux-qt6-next.yml
|
||||
- /gitlab-templates/windows-qt6.yml
|
||||
- /gitlab-templates/freebsd-qt6.yml
|
||||
- /gitlab-templates/flatpak.yml
|
||||
- /gitlab-templates/snap-snapcraft-lxd.yml
|
||||
- /gitlab-templates/craft-android-qt6-apks.yml
|
||||
- /gitlab-templates/craft-appimage-qt6.yml
|
||||
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||
- /gitlab-templates/craft-windows-appx-qt6.yml
|
||||
|
||||
70
.kde-ci.yml
70
.kde-ci.yml
@@ -2,40 +2,44 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
Dependencies:
|
||||
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
|
||||
'require':
|
||||
'frameworks/extra-cmake-modules': '@latest-kf6'
|
||||
'frameworks/kcoreaddons': '@latest-kf6'
|
||||
'frameworks/kirigami': '@latest-kf6'
|
||||
'frameworks/ki18n': '@latest-kf6'
|
||||
'frameworks/kconfig': '@latest-kf6'
|
||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'frameworks/kcolorscheme': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'frameworks/prison': '@latest-kf6'
|
||||
'libraries/kirigami-addons': '@latest-kf6'
|
||||
'third-party/libquotient': '@latest'
|
||||
'third-party/qtkeychain': '@latest'
|
||||
'third-party/cmark': '@latest'
|
||||
'third-party/qcoro': '@latest'
|
||||
- 'on': ['Windows', 'Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
|
||||
'require':
|
||||
'frameworks/extra-cmake-modules': '@latest-kf6'
|
||||
'frameworks/kcoreaddons': '@latest-kf6'
|
||||
'frameworks/kirigami': '@latest-kf6'
|
||||
'frameworks/ki18n': '@latest-kf6'
|
||||
'frameworks/kconfig': '@latest-kf6'
|
||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||
'frameworks/kiconthemes': '@latest-kf6'
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'frameworks/kcolorscheme': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'frameworks/prison': '@latest-kf6'
|
||||
'libraries/kirigami-addons': '@latest-kf6'
|
||||
'third-party/libquotient': '@latest'
|
||||
'third-party/qtkeychain': '@latest'
|
||||
'third-party/cmark': '@latest'
|
||||
'third-party/qcoro': '@latest'
|
||||
- 'on': ['Windows', 'Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
'frameworks/purpose': '@latest-kf6'
|
||||
'libraries/kunifiedpush': '@latest-kf6'
|
||||
|
||||
- 'on': ['Linux']
|
||||
'require':
|
||||
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
|
||||
- 'on': ['Linux']
|
||||
'require':
|
||||
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
|
||||
|
||||
Options:
|
||||
per-test-timeout: 90
|
||||
require-passing-tests-on: [ '@all' ]
|
||||
require-passing-tests-on: ['Linux', 'Android', 'FreeBSD', 'Windows']
|
||||
run-qmllint: True
|
||||
|
||||
51
.reuse/dep5
51
.reuse/dep5
@@ -1,51 +0,0 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: NeoChat
|
||||
Upstream-Contact: Carl Schwan <carlschwan@kde.org>
|
||||
|
||||
Files: 128-logo.png icons/* logo.png org.kde.neochat.svg org.kde.neochat.tray.svg android/res/drawable/neochat.png
|
||||
Copyright: 2020 Carson Black <uhhadd@gmail.com>
|
||||
License: LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
|
||||
Files: android/res/drawable/splash.xml
|
||||
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: .gitignore
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
Files: .gitlab/issue_templates/bug.md
|
||||
Copyright: 2021 Carl Schwan <carlschwan@kde.org>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: src/res.qrc src/res_android.qrc src/res_desktop.qrc
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
Files: cmake/Flatpak/99-noto-mono-color-emoji.conf
|
||||
Copyright: 2021 Carl Schwan <carlschwan@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/neochatconfig.kcfg
|
||||
Copyright: 2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/neochat.notifyrc
|
||||
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/qml/confetti.png src/qml/glowdot.png
|
||||
Copyright: 2021 Alexey Andreyev <aa13q@ya.ru>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: .flatpak-manifest.json
|
||||
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: autotests/data/*
|
||||
Copyright: none
|
||||
License: CC0-1.0
|
||||
|
||||
Files: appiumtests/data/*
|
||||
Copyright: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
License: CC0-1.0
|
||||
@@ -7,15 +7,15 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "02")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "0")
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "12")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "3")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
set(KF_MIN_VERSION "5.240.0")
|
||||
set(QT_MIN_VERSION "6.5")
|
||||
set(KF_MIN_VERSION "6.17")
|
||||
set(QT_MIN_VERSION "6.9")
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
@@ -24,7 +24,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(KDE_COMPILERSETTINGS_LEVEL 5.105)
|
||||
set(KDE_COMPILERSETTINGS_LEVEL 6.17)
|
||||
|
||||
include(FeatureSummary)
|
||||
include(ECMSetupVersion)
|
||||
@@ -38,6 +38,10 @@ include(KDEGitCommitHooks)
|
||||
include(ECMCheckOutboundLicense)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
include(ECMAddAndroidApk)
|
||||
include(ECMQmlModule)
|
||||
include(ECMDeprecationSettings)
|
||||
include(GenerateExportHeader)
|
||||
include(ECMGenerateHeaders)
|
||||
if (NOT ANDROID)
|
||||
include(KDEClangFormat)
|
||||
endif()
|
||||
@@ -48,17 +52,24 @@ endif()
|
||||
|
||||
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
||||
|
||||
ecm_set_disabled_deprecation_versions(Qt 6.9.0 KF 6.17.0)
|
||||
|
||||
ecm_setup_version(${PROJECT_VERSION}
|
||||
VARIABLE_PREFIX NEOCHAT
|
||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
||||
)
|
||||
|
||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg WebView)
|
||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg TextToSpeech WebView)
|
||||
set_package_properties(Qt6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||
|
||||
if (QT_KNOWN_POLICY_QTP0004)
|
||||
qt_policy(SET QTP0004 NEW)
|
||||
endif ()
|
||||
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme IconThemes)
|
||||
set_package_properties(KF6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
@@ -67,7 +78,11 @@ set_package_properties(KF6Kirigami PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Kirigami application UI framework"
|
||||
)
|
||||
find_package(KF6KirigamiAddons 0.7.2 REQUIRED)
|
||||
find_package(KF6KirigamiAddons 1.10.0 REQUIRED)
|
||||
|
||||
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
|
||||
endif ()
|
||||
|
||||
if(ANDROID)
|
||||
find_package(OpenSSL)
|
||||
@@ -78,6 +93,7 @@ if(ANDROID)
|
||||
else()
|
||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
||||
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
|
||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||
TYPE RUNTIME
|
||||
)
|
||||
@@ -90,11 +106,11 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
||||
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(QuotientQt6 0.7)
|
||||
find_package(QuotientQt6 0.9.3)
|
||||
set_package_properties(QuotientQt6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
DESCRIPTION "Qt wrapper around Matrix API"
|
||||
@@ -102,11 +118,6 @@ set_package_properties(QuotientQt6 PROPERTIES
|
||||
PURPOSE "Talk with matrix server"
|
||||
)
|
||||
|
||||
if (NOT TARGET Olm::Olm)
|
||||
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(cmark)
|
||||
set_package_properties(cmark PROPERTIES
|
||||
TYPE REQUIRED
|
||||
@@ -139,16 +150,24 @@ set_package_properties(KF6DocTools PROPERTIES DESCRIPTION
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
|
||||
find_package(KUnifiedPush QUIET)
|
||||
set_package_properties(KUnifiedPush PROPERTIES
|
||||
TYPE OPTIONAL
|
||||
PURPOSE "Push notification support"
|
||||
URL "https://invent.kde.org/libraries/kunifiedpush"
|
||||
)
|
||||
option(WITH_UNIFIEDPUSH "Build with KUnifiedPush support" ON)
|
||||
|
||||
if (ANDROID OR APPLE OR WIN32 OR HAIKU)
|
||||
set(WITH_UNIFIEDPUSH OFF)
|
||||
endif()
|
||||
|
||||
if (WITH_UNIFIEDPUSH)
|
||||
find_package(KUnifiedPush)
|
||||
set_package_properties(KUnifiedPush PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Push notification support"
|
||||
URL "https://invent.kde.org/libraries/kunifiedpush"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
find_package(Sqlite3)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle)
|
||||
set(BUILD_TESTING FALSE)
|
||||
endif()
|
||||
|
||||
ki18n_install(po)
|
||||
@@ -163,9 +182,12 @@ add_definitions(-DQT_NO_FOREACH)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
|
||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test HttpServer)
|
||||
add_subdirectory(autotests)
|
||||
add_subdirectory(appiumtests)
|
||||
# add_subdirectory(appiumtests)
|
||||
if (NOT ANDROID)
|
||||
add_subdirectory(memorytests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(KF6DocTools_FOUND)
|
||||
@@ -173,7 +195,7 @@ if(KF6DocTools_FOUND)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
|
||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
if (NOT ANDROID)
|
||||
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES src/*.cpp src/*.h)
|
||||
|
||||
50
README.md
50
README.md
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
|
||||
SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-FileCopyrightText: 2020-2024 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
@@ -11,24 +11,23 @@ A Qt/QML based Matrix client.
|
||||
|
||||
<a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
|
||||
<a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
|
||||
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://snapcraft.io/static/images/badges/en/snap-store-black.svg'/></a>
|
||||
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://apps.kde.org/store_badges/snapstore/en.svg'/></a>
|
||||
|
||||
## Introduction
|
||||
|
||||
NeoChat is a client for [Matrix](https://matrix.org), the decentralized communication protocol for instant
|
||||
messaging. It is a fork of Spectral, using KDE frameworks, most notably [Kirigami](https://invent.kde.org/frameworks/kirigami)
|
||||
to provide a convergent experience across multiple platforms.
|
||||
messaging.
|
||||
|
||||
NeoChat also make use of other KDE Frameworks as well as [libQuotient](https://github.com/quotient-im/libQuotient), a
|
||||
NeoChat is based on KDE frameworks and as [libQuotient](https://github.com/quotient-im/libQuotient), a
|
||||
Qt-based SDK for the [Matrix Protocol](https://spec.matrix.org/).
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions
|
||||
of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
|
||||
evolving but the aim remains to provide eventual support for the entire spec.
|
||||
NeoChat aims to be a fully featured application for the Matrix specification. As such most parts of the current specification are supported, with the notable exceptions
|
||||
of VoIP, threads, and some aspects of End-to-End Encryption. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
|
||||
evolving, but the aim remains to provide eventual support for the entire spec.
|
||||
|
||||
Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:
|
||||
- Polls - MSC3381
|
||||
@@ -39,26 +38,9 @@ Due to the nature of the Matrix specification development NeoChat also supports
|
||||
|
||||
Details where to find stable releases for NeoChat can be found on its [homepage](https://apps.kde.org/neochat).
|
||||
|
||||
In addition to the stable builds, unstable nightly builds are available for all platforms. These can be downloaded
|
||||
from the [binary factory](https://binary-factory.kde.org/). There are unstable versions for the following platforms
|
||||
in addition to stable ones:
|
||||
- Android
|
||||
- MacOS
|
||||
- Windows
|
||||
|
||||
Additionally the nightly Flatpak version can be obtained from the nightly Flatpak repo using the following commands in your terminal:
|
||||
|
||||
```
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak remote-add --if-not-exists kdeapps --from https://distribute.kde.org/kdeapps.flatpakrepo
|
||||
flatpak install kdeapps org.kde.neochat
|
||||
```
|
||||
|
||||
The unstable Android version can also be obtained from the [KDE nightly F-Droid repo](https://community.kde.org/Android/FDroid).
|
||||
|
||||
## Running
|
||||
|
||||
Just start the executable in your preferred way - either from the build directory or from the installed location.
|
||||
Nightly builds for Linux and Windows can be downloaded from [cdn.kde.org](https://cdn.kde.org/ci-builds/network/neochat/).
|
||||
Nightly builds for Android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid).
|
||||
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak).
|
||||
|
||||
## Building NeoChat
|
||||
|
||||
@@ -69,14 +51,18 @@ is primarily aimed at Linux development.
|
||||
For Windows and Android [Craft](https://invent.kde.org/packaging/craft) is the primary choice. There are guides for setting up
|
||||
development environments for [Windows](https://community.kde.org/Get_Involved/development/Windows) and [Android](https://develop.kde.org/docs/packaging/android/building_applications/).
|
||||
|
||||
## Running
|
||||
|
||||
Just start the executable in your preferred way - either from the build directory or from the installed location.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests are in the repository under [autotests](autotests) and should all pass for any contribution.
|
||||
Tests are in the repository under [autotests](autotests) and [appiumtests](appiumtests).
|
||||
|
||||
The project has CI setup to test new commits to the repository. All tests are expected to pass for a merge request to
|
||||
be complete.
|
||||
|
||||
Current build status
|
||||
## Current build status
|
||||
|
||||

|
||||
|
||||
@@ -100,9 +86,9 @@ The best place to reach the maintainers is on the KDE Matrix instance in the Neo
|
||||
|
||||
## Acknowledgement
|
||||
|
||||
This program utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
|
||||
NeoChat utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
|
||||
|
||||
This program is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
|
||||
NeoChat is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
96
REUSE.toml
Normal file
96
REUSE.toml
Normal file
@@ -0,0 +1,96 @@
|
||||
# SPDX-FileCopyrightText: none
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
version = 1
|
||||
SPDX-PackageName = "NeoChat"
|
||||
SPDX-PackageSupplier = "Carl Schwan <carlschwan@kde.org>"
|
||||
|
||||
[[annotations]]
|
||||
path = ["128-logo.png", "icons/**", "logo.png", "org.kde.neochat.svg", "org.kde.neochat.tray.svg", "android/res/drawable/neochat.png", "android/neochat-playstore.png"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020 Carson Black <uhhadd@gmail.com>"
|
||||
SPDX-License-Identifier = "LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL"
|
||||
|
||||
[[annotations]]
|
||||
path = "android/res/drawable/splash.xml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ".gitignore"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "None"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".gitlab/issue_templates/bug.md"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Carl Schwan <carlschwan@kde.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ["src/res.qrc", "src/res_android.qrc", "src/res_desktop.qrc"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "None"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "cmake/Flatpak/99-noto-mono-color-emoji.conf"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Carl Schwan <carlschwan@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/app/neochatconfig.kcfg"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/app/neochat.notifyrc"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["src/qml/confetti.png", "src/qml/glowdot.png"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Alexey Andreyev <aa13q@ya.ru>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".flatpak-manifest.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020-2022 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = "autotests/data/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "none"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "appiumtests/data/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/purpose/purposeplugin.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = "memorytests/memtest-sync.json"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ".contextProperties.ini"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2025 Tobias Fella <tobias.fella@kde.org>"
|
||||
SPDX-License-Identifier = "BSD-2-Clause"
|
||||
@@ -55,5 +55,6 @@
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- for Android >= 33 -->
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.android.tools.build:gradle:8.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ repositories {
|
||||
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply from: '../version.gradle'
|
||||
def timestamp = (int)(new Date().getTime()/1000)
|
||||
apply from: '../ecm-version.gradle'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
@@ -79,9 +78,9 @@ android {
|
||||
targetSdkVersion qtTargetSdkVersion
|
||||
applicationId "org.kde.neochat"
|
||||
namespace "org.kde.neochat"
|
||||
versionCode timestamp
|
||||
versionName projectVersionFull
|
||||
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
||||
versionCode ecmVersionCode
|
||||
versionName ecmVersionName
|
||||
manifestPlaceholders = [versionName: ecmVersionName, versionCode: ecmVersionCode]
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
|
||||
BIN
android/neochat-playstore.png
Normal file
BIN
android/neochat-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -1,6 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
ext {
|
||||
projectVersionFull = "@NEOCHAT_VERSION@"
|
||||
}
|
||||
56
appiumtests/createroomtest.py
Executable file
56
appiumtests/createroomtest.py
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
import time
|
||||
|
||||
from appium import webdriver
|
||||
from appium.options.common.base import AppiumOptions
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
|
||||
|
||||
class CreateRoomTest(unittest.TestCase):
|
||||
|
||||
mockServerProcess: subprocess.Popen
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
|
||||
options = AppiumOptions()
|
||||
options.set_capability("app", "neochat --ignore-ssl-errors --test")
|
||||
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
if not self._outcome.result.wasSuccessful():
|
||||
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
self.mockServerProcess.terminate()
|
||||
self.driver.quit()
|
||||
|
||||
def test_create_room(self):
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Show Menu").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Create a Room").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Name:").send_keys("Super awesome room name")#
|
||||
time.sleep(0.1) # without this, the second half of the text is sent to the topic field?!
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Topic:").send_keys("There are not enough raccoons here")
|
||||
time.sleep(0.1)
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Create Room").click()
|
||||
time.sleep(0.1)
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Super awesome room name").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Show Room Information").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="There are not enough raccoons here")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
78
appiumtests/data/sync_response_new_room.json
Normal file
78
appiumtests/data/sync_response_new_room.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"next_batch": "batch1234",
|
||||
"rooms": {
|
||||
"join": {
|
||||
"!newroom123321:localhost:1234": {
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"type": "m.room.member",
|
||||
"state_key": "@user:localhost:1234",
|
||||
"sender": "@user:localhost:1234",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"event_id": "$event_id_1234_0:localhost:1234",
|
||||
"room_id": "!newroom123321:localhost:1234",
|
||||
"content": {
|
||||
"avatar_url": "",
|
||||
"displayname": "A Display Name",
|
||||
"membership": "join",
|
||||
"reason": "Nothing"
|
||||
},
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "m.room.name",
|
||||
"state_key": "",
|
||||
"sender": "@user:localhost:1234",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"event_id": "$event_id_1234_1:localhost:1234",
|
||||
"room_id": "!newroom123321:localhost:1234",
|
||||
"content": {
|
||||
"name": "Super awesome room name"
|
||||
},
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "m.room.topic",
|
||||
"state_key": "",
|
||||
"sender": "@user:localhost:1234",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"event_id": "$event_id_1234_2:localhost:1234",
|
||||
"room_id": "!newroom123321:localhost:1234",
|
||||
"content": {
|
||||
"topic": "There are not enough raccoons here"
|
||||
},
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"sender": "@user:localhost:1234",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"event_id": "$event_id_1234_1:localhost:1234",
|
||||
"room_id": "!newroom123321:localhost:1234",
|
||||
"content": {
|
||||
"body": "This is a message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<a href=\"https://matrix.to/#/@user:localhost:1234\">User</a>:",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,26 @@
|
||||
"!room_id_1234:localhost:1234": {
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"m.federate": true,
|
||||
"predecessor": {
|
||||
"event_id": "$something:example.org",
|
||||
"room_id": "!oldroom:example.org"
|
||||
},
|
||||
"room_version": "11"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "",
|
||||
"type": "m.room.create",
|
||||
"unsigned": {
|
||||
"age": 1234,
|
||||
"membership": "join"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "m.room.member",
|
||||
"state_key": "@user:localhost:1234",
|
||||
@@ -26,6 +46,26 @@
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"m.federate": true,
|
||||
"predecessor": {
|
||||
"event_id": "$something:example.org",
|
||||
"room_id": "!oldroom:example.org"
|
||||
},
|
||||
"room_version": "11"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "",
|
||||
"type": "m.room.create",
|
||||
"unsigned": {
|
||||
"age": 1234,
|
||||
"membership": "join"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "m.room.message",
|
||||
"sender": "@user:localhost:1234",
|
||||
|
||||
@@ -6,6 +6,8 @@ from flask import Flask, request, abort
|
||||
import os
|
||||
app = Flask(__name__)
|
||||
|
||||
next_sync_payload = ""
|
||||
|
||||
|
||||
@app.route("/_matrix/client/v3/login", methods=["GET"])
|
||||
def login_get():
|
||||
@@ -42,8 +44,13 @@ def load_json(name):
|
||||
|
||||
@app.route("/_matrix/client/r0/sync")
|
||||
def sync():
|
||||
|
||||
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
||||
global next_sync_payload
|
||||
result = dict()
|
||||
if len(next_sync_payload) > 0:
|
||||
result = load_json(next_sync_payload)
|
||||
next_sync_payload = ""
|
||||
else:
|
||||
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
||||
return result
|
||||
|
||||
@app.route("/.well-known/matrix/client")
|
||||
@@ -65,6 +72,27 @@ def upload_keys():
|
||||
reply = dict()
|
||||
return reply
|
||||
|
||||
@app.route("/_matrix/client/v3/createRoom", methods=["POST"])
|
||||
def create_room():
|
||||
global next_sync_payload
|
||||
data = request.get_json()
|
||||
if data["name"] != "Super awesome room name" or data["topic"] != "There are not enough raccoons here":
|
||||
return dict(), 400
|
||||
response = dict()
|
||||
response["room_id"] = "!newroom123321:localhost:1234"
|
||||
next_sync_payload = "sync_response_new_room"
|
||||
return response
|
||||
|
||||
@app.route("/_matrix/client/v3/publicRooms", methods=["POST"])
|
||||
def public_rooms():
|
||||
if request.get_json()["filter"]["generic_search_term"] == "forbidden":
|
||||
data = dict()
|
||||
data["errcode"] = "M_FORBIDDEN"
|
||||
data["error"] = "You are not allowed to search for this. Go to https://wikipedia.org for more information"
|
||||
return data, 403
|
||||
return dict()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(ssl_context='adhoc', port=1234)
|
||||
|
||||
@@ -39,6 +39,10 @@ class OpenUserDetailsTest(unittest.TestCase):
|
||||
|
||||
def test_open_sheet(self):
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
|
||||
try:
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Expand Normal").click()
|
||||
except:
|
||||
pass
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Account Details")
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_library(neochat_server STATIC server.cpp)
|
||||
|
||||
target_link_libraries(neochat_server PUBLIC Qt::HttpServer QuotientQt6)
|
||||
|
||||
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
|
||||
|
||||
ecm_add_test(
|
||||
@@ -48,15 +52,9 @@ ecm_add_test(
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
messageeventmodeltest.cpp
|
||||
timelinemessagemodeltest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME messageeventmodeltest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
actionshandlertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME actionshandlertest
|
||||
TEST_NAME timelinemessagemodeltest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
@@ -82,3 +80,27 @@ ecm_add_test(
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME linkpreviewertest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
messagecontentmodeltest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME messagecontentmodeltest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
actionstest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
||||
TEST_NAME actionstest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
servernoticestest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
||||
TEST_NAME servernoticestest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
roommanagertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
||||
TEST_NAME roommanagertest
|
||||
)
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "actionshandler.h"
|
||||
#include "chatbarcache.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
class ActionsHandlerTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Quotient::Connection *connection = Quotient::Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
ActionsHandler *actionsHandler = new ActionsHandler(this);
|
||||
|
||||
private Q_SLOTS:
|
||||
void nullObject();
|
||||
};
|
||||
|
||||
void ActionsHandlerTest::nullObject()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||
actionsHandler->handleMessageEvent(nullptr);
|
||||
|
||||
auto chatBarCache = new ChatBarCache(this);
|
||||
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||
actionsHandler->handleMessageEvent(chatBarCache);
|
||||
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
|
||||
actionsHandler->setRoom(room);
|
||||
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||
actionsHandler->handleMessageEvent(nullptr);
|
||||
|
||||
// The final one should throw no warning so we make sure.
|
||||
QTest::failOnWarning("ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||
actionsHandler->handleMessageEvent(chatBarCache);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(ActionsHandlerTest)
|
||||
#include "actionshandlertest.moc"
|
||||
151
autotests/actionstest.cpp
Normal file
151
autotests/actionstest.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
#include <QSignalSpy>
|
||||
#include <QVariantList>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "chatbarcache.h"
|
||||
#include "models/actionsmodel.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
//TODO: rainbow, rainbowme, plain, spoiler, me, join, knock, j, part, leave, nick, roomnick, myroomnick, ignore, unignore, react, ban, unban, kick
|
||||
|
||||
class ActionsTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
NeoChatRoom *room = nullptr;
|
||||
|
||||
void expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message);
|
||||
|
||||
Server server;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void testActions();
|
||||
void testActions_data();
|
||||
void testInvite();
|
||||
};
|
||||
|
||||
void ActionsTest::initTestCase()
|
||||
{
|
||||
Connection::setRoomType<NeoChatRoom>();
|
||||
server.start();
|
||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||
auto accountManager = new AccountManager(true);
|
||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
||||
connection = accountManager->accounts()->front();
|
||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
||||
server.inviteUser(roomId, u"@invited:example.com"_s);
|
||||
server.banUser(roomId, u"@banned:example.com"_s);
|
||||
server.joinUser(roomId, u"@example:example.com"_s);
|
||||
|
||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
||||
// We need to wait for two syncs, as the next one won't have the changes yet
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
||||
QVERIFY(room);
|
||||
}
|
||||
|
||||
void ActionsTest::testActions_data()
|
||||
{
|
||||
QTest::addColumn<QString>("command");
|
||||
QTest::addColumn<std::optional<QString>>("resultText");
|
||||
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
|
||||
|
||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\\\_(ツ)\\_/¯ Hello"_s)
|
||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
|
||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("unflip") << u"/unflip Hello"_s << std::make_optional(u"┬──┬ ノ( ゜-゜ノ) Hello"_s)
|
||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("rainbow") << u"/rainbow Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
|
||||
QTest::newRow("rainbowme") << u"/rainbowme Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
|
||||
QTest::newRow("plain") << u"/plain <b>Hello</b>"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
|
||||
QTest::newRow("spoiler") << u"/spoiler Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
|
||||
QTest::newRow("me") << u"/me Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Emote);
|
||||
QTest::newRow("notice") << u"/notice Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Notice);
|
||||
QTest::newRow("message") << u"Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("invite") << u"/invite @foo:example.com"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
|
||||
|
||||
//TODO: join, knock, j, part, leave, nick, roomnick, myroomnick, ignore, unignore, react, ban, unban, kick
|
||||
}
|
||||
|
||||
void ActionsTest::testActions()
|
||||
{
|
||||
QFETCH(QString, command);
|
||||
QFETCH(std::optional<QString>, resultText);
|
||||
QFETCH(std::optional<Quotient::RoomMessageEvent::MsgType>, type);
|
||||
|
||||
auto cache = new ChatBarCache();
|
||||
cache->setText(command);
|
||||
auto result = ActionsModel::handleAction(room, cache);
|
||||
QCOMPARE(resultText, std::get<std::optional<QString>>(result));
|
||||
QCOMPARE(type, std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result));
|
||||
}
|
||||
|
||||
static ActionsModel::Action findAction(const QString &name)
|
||||
{
|
||||
for (const auto &action : ActionsModel::allActions()) {
|
||||
if (action.prefix == name) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ActionsTest::expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message)
|
||||
{
|
||||
auto action = findAction(actionName);
|
||||
QSignalSpy spy(room, &NeoChatRoom::showMessage);
|
||||
auto result = action.handle(args, room, nullptr);
|
||||
auto expected = QVariantList {type, message};
|
||||
auto signal = spy.takeFirst();
|
||||
QCOMPARE(signal, expected);
|
||||
}
|
||||
|
||||
void ActionsTest::testInvite()
|
||||
{
|
||||
expectMessage(u"invite"_s, u"foo"_s, MessageType::Error, u"'foo' does not look like a matrix id."_s);
|
||||
expectMessage(u"invite"_s, u"@invited:example.com"_s, MessageType::Information, u"@invited:example.com is already invited to this room."_s);
|
||||
QCOMPARE(room->memberState(u"@invited:example.com"_s), Membership::Invite);
|
||||
expectMessage(u"invite"_s, u"@banned:example.com"_s, MessageType::Information, u"@banned:example.com is banned from this room."_s);
|
||||
QCOMPARE(room->memberState(u"@banned:example.com"_s), Membership::Ban);
|
||||
expectMessage(u"invite"_s, connection->userId(), MessageType::Positive, u"You are already in this room."_s);
|
||||
QCOMPARE(room->memberState(connection->userId()), Membership::Join);
|
||||
expectMessage(u"invite"_s, u"@example:example.com"_s, MessageType::Information, u"@example:example.com is already in this room."_s);
|
||||
QCOMPARE(room->memberState(u"@example:example.com"_s), Membership::Join);
|
||||
|
||||
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Leave);
|
||||
expectMessage(u"invite"_s, u"@user:example.com"_s, MessageType::Positive, u"@user:example.com was invited into this room."_s);
|
||||
|
||||
QSignalSpy spy(room, &NeoChatRoom::changed);
|
||||
QVERIFY(spy.wait());
|
||||
|
||||
auto tries = 0;
|
||||
|
||||
while (room->memberState(u"@user:example.com"_s) != Membership::Invite) {
|
||||
QVERIFY(spy.wait());
|
||||
tries += 1;
|
||||
if (tries > 3) {
|
||||
QVERIFY(false);
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Invite);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ActionsTest)
|
||||
#include "actionstest.moc"
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include <QSignalSpy>
|
||||
#include <Quotient/roommember.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qtestcase.h>
|
||||
|
||||
@@ -31,14 +33,15 @@ private Q_SLOTS:
|
||||
void noRoom();
|
||||
void badParent();
|
||||
void reply();
|
||||
void replyMissingUser();
|
||||
void edit();
|
||||
void attachment();
|
||||
};
|
||||
|
||||
void ChatBarCacheTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, "test-min-sync.json"_L1);
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::empty()
|
||||
@@ -50,7 +53,7 @@ void ChatBarCacheTest::empty()
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(QString()));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
@@ -58,13 +61,13 @@ void ChatBarCacheTest::empty()
|
||||
void ChatBarCacheTest::noRoom()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache());
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
||||
|
||||
// These should return empty even though a reply ID has been set because the
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||
QCOMPARE(chatBarCache->relationAuthor(), Quotient::RoomMember());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
@@ -74,13 +77,13 @@ void ChatBarCacheTest::badParent()
|
||||
{
|
||||
QScopedPointer<QObject> badParent(new QObject());
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(badParent.get()));
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
||||
|
||||
// These should return empty even though a reply ID has been set because the
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||
QCOMPARE(chatBarCache->relationAuthor(), Quotient::RoomMember());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
@@ -89,52 +92,84 @@ void ChatBarCacheTest::badParent()
|
||||
void ChatBarCacheTest::reply()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), true);
|
||||
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
||||
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::replyMissingUser()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), true);
|
||||
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
||||
|
||||
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
|
||||
|
||||
// sync again, which will simulate the reply user leaving the room
|
||||
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
|
||||
|
||||
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
|
||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::edit()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
connect(chatBarCache.get(), &ChatBarCache::relationIdChanged, this, [](const QString &oldEventId, const QString &newEventId) {
|
||||
QCOMPARE(oldEventId, QString());
|
||||
QCOMPARE(newEventId, QString(u"$153456789:example.org"_s));
|
||||
});
|
||||
chatBarCache->setEditId(u"$153456789:example.org"_s);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), true);
|
||||
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||
QCOMPARE(chatBarCache->editId(), u"$153456789:example.org"_s);
|
||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::attachment()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->setEditId(u"$153456789:example.org"_s);
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(QString()));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
||||
QCOMPARE(chatBarCache->attachmentPath(), u"some/path"_s);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ChatBarCacheTest)
|
||||
|
||||
20
autotests/data/localhost.crt
Normal file
20
autotests/data/localhost.crt
Normal file
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDNTCCAh2gAwIBAgIUXbyWfTfcvVLrVB1qx36pW/7IkwMwDQYJKoZIhvcNAQEL
|
||||
BQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
|
||||
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDAgFw0yNDEyMjQxNTAxMDNaGA8yNTcyMDcy
|
||||
NDE1MDEwM1owQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEc
|
||||
MBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAKlxZ540TQ1uUDAR7ZJ9ue0PzcD2dPmblIIddyekvZS59V7X
|
||||
drhamclXpHE2EelR87Sexst0BaHH/jmrHwxCtwbeXHZ8ueJHkGHJ5DLZCCiwfG+Q
|
||||
gml7wlSXxXz37vie2tdlZh2yJSM8yvLAYceHb2zOskaGvul7ZITIS0JrPc3o6VZk
|
||||
+MYGkYtA2JfUsv3jH4oQbxOf7RXqhWNAXbB+3hlwRBwMIdyoBNK6YS9QSrTeS9jj
|
||||
UqgO5QmaQZOVvpaPf1Y/rHHLd2Qa6+a/cCJ1sr2biagb75AihpQFsK/oy6D1PP70
|
||||
zTe7hPWn/efEpmtCV7CQ8ti4cRu0Kjy0T8grtCsCAwEAAaMhMB8wHQYDVR0OBBYE
|
||||
FIFlylzwADNLfgTDNkhFeFelaEDxMA0GCSqGSIb3DQEBCwUAA4IBAQBQ2rw4GLIU
|
||||
v+GY7Qru9LttkrQPd2bZXKxDMd/jT+wjmMVtqS4MAsCuDYwaYLjU1aWyqy0mN+lY
|
||||
A17kD0VjBNBy45sYqkZveY0ks8mCScBemtrIDmjz2tiueecBIEASwEPBOZgv5/MV
|
||||
cz864FiChF+2r8Zl8bhycGy9DEpRjzYKvIQWSDHQ3zpuh3iBnjfoieLHWX2kKCpk
|
||||
ouS3V6485rHNCWsZT5IcCwfBFQkOuWRJpIazpz4AfwZh1TK9+bgiKA5EyZjSNrKw
|
||||
xGQSpMSTRQMB0/FOCL/AixhN9unVFUViqUcdtSfoHE1VyBHv9kDT/cYms/Xl4B0t
|
||||
/ZSQJ/D/Km1+
|
||||
-----END CERTIFICATE-----
|
||||
28
autotests/data/localhost.key
Normal file
28
autotests/data/localhost.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpcWeeNE0NblAw
|
||||
Ee2SfbntD83A9nT5m5SCHXcnpL2UufVe13a4WpnJV6RxNhHpUfO0nsbLdAWhx/45
|
||||
qx8MQrcG3lx2fLniR5BhyeQy2QgosHxvkIJpe8JUl8V89+74ntrXZWYdsiUjPMry
|
||||
wGHHh29szrJGhr7pe2SEyEtCaz3N6OlWZPjGBpGLQNiX1LL94x+KEG8Tn+0V6oVj
|
||||
QF2wft4ZcEQcDCHcqATSumEvUEq03kvY41KoDuUJmkGTlb6Wj39WP6xxy3dkGuvm
|
||||
v3AidbK9m4moG++QIoaUBbCv6Mug9Tz+9M03u4T1p/3nxKZrQlewkPLYuHEbtCo8
|
||||
tE/IK7QrAgMBAAECggEAH9qmeKrra2F4KLlOGNKS//qPGz4Z+ozhi95/NpA1Zb7Z
|
||||
3pUSCBFcROo5i2D3WA4kiymoRLpQjrv60puVcCggoWVvK4VCKsR6Y6/hOx/q9T9M
|
||||
fWrE4ZC3FVEc+uPfZJT0nja9TkrdyXSV0LITD8Ap1eI7yJ9vR5R/bqj64QcpLMrU
|
||||
QeoQIy1oTMR+qdjj33duyRwBZU3Yf8FRB2iW6OILZ8hzFo1jngec7dph9a1RK4e0
|
||||
mEPdc9ywsKlDM7P0Y7zdmjar5XtQn87GiwNhz23f1fzCC2axLtOW0Xm4e4Qumehb
|
||||
WrIi6Vfq8IWMglU7QrBJ7iR0Ls+XoKA5GxomV2IJZQKBgQDoIkOl5YGPQ3iGR+WK
|
||||
e5/2Ml4G/uURzYiOlzSsyfoPXyO4EI2BJd5HkH+EvfgRx4xKkxUZRJdzR7llYPl8
|
||||
BFYcFitvhO8SbD0mNAB5YW7f+3v1pgEN2umzoKd389Zx5WqTZ7YB1VG5RN/Q1JJL
|
||||
2JM0Xgamq2vNtx3roRPxDBeW7QKBgQC63R/bmACJbgIzfaVBX4Zie3NQG0/Hf+gF
|
||||
LnBwUmQDZOR7MY+kSiIUVMn3NuZRiCSCFBVwApruyK8r535JCibTVm5PWjvhFddY
|
||||
LgaPOCKGlm9TLScjoH1pErYgG3uJ4nXeRfXhg4mco6EkrC7RzQywrd0VDoqpuc1Y
|
||||
EKfEsYk8dwKBgE+mSh3nNOBKX1V73+f3aTiZqaeu2DyWkG+UtE9BclrJ40Cp9VPG
|
||||
AZH+o7KRWEgJdzqzYv7riSfWCWgesRv7hOxYMwktzLY+i3DLUQpVAy05ZhwwnJX7
|
||||
ckrfKfc/pGoqNLplUI8qecMfPciy14vMwR2r0Y5orTHFzi9mcqg35PQ1AoGAW2LX
|
||||
OLq+0HdHhk0Va8I+450CSRQCUUvhed87SANTPEG0Z/dWC3/h6NWKrGdh/k+5oxAV
|
||||
Z+EuSkdFPBCLt0bKtCKZ8h7sF+lplotz08kdQXsC2MfFU2wiySdIgK1QHp/tCxZl
|
||||
6LM+sqdnoJrAjwRcB3AQJkMlV1ox7ba/hbdZqYMCgYBS6+JUXSSASpm5ZHd32a8m
|
||||
xwryEZ7H6Hek6lvMHdxmwoKat5dCavxw64nrtyeeGZpg1W3zLLyamF9x/8kMyr6y
|
||||
KKvtBfJ5sCvAbt80o9Pbs6R3yDB3AKiD3s3PQK7lol1nhE/8IbsF2r8JEQVcYd/k
|
||||
oBzkl7MrMyLhhaCqSxwqQQ==
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -25,7 +25,7 @@
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
"@bob:kde.org"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
@@ -35,7 +35,7 @@
|
||||
"content": {
|
||||
"$153456789:example.org": {
|
||||
"m.read": {
|
||||
"@alice:matrix.org": {
|
||||
"@alice:example.org": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@bob:example.com": {
|
||||
"@bob:kde.org": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,18 @@
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@tim2:example.com": {
|
||||
"ts": 1436451550454
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
@@ -136,6 +148,22 @@
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Bob",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "bob:kde.org",
|
||||
"state_key": "@bob:kde.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"displayname": "Look\nat\nme\nI\nput\nnewlines\nin\nmy\ndisplay name",
|
||||
@@ -156,7 +184,7 @@
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
"@bob:kde.org"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "https://matrix.to/#/@alice:example.org",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "testhttps://kde.org",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
20
autotests/data/test-min-sync-extra-sync.json
Normal file
20
autotests/data/test-min-sync-extra-sync.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"membership": "leave"
|
||||
},
|
||||
"event_id": "$1432735824666PhrSA:example.org",
|
||||
"origin_server_ts": 1432735824666,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"replaces_state": "$143273582443PhrSn:example.org"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -37,16 +37,59 @@
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
"displayname": "Example",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"displayname": "Bob",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273blorb3PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@bob:kde.org",
|
||||
"state_key": "@bob:kde.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"displayname": "Invited",
|
||||
"membership": "invite"
|
||||
},
|
||||
"event_id": "$asdfpj443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@invited:example.com",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"displayname": "Banned",
|
||||
"membership": "ban"
|
||||
},
|
||||
"event_id": "$asdfpj443PhrSnasfd:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@banned:example.com",
|
||||
"state_key": "@banned:example.com",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
@@ -59,7 +102,7 @@
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.invited_member_count": 1,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
"answers": [
|
||||
{
|
||||
"id": "option1",
|
||||
"org.matrix.msc1767.text": "option1"
|
||||
"org.matrix.msc1767.text": "option1text"
|
||||
},
|
||||
{
|
||||
"id": "option2",
|
||||
"org.matrix.msc1767.text": "option2"
|
||||
"org.matrix.msc1767.text": "option2text"
|
||||
}
|
||||
],
|
||||
"kind": "org.matrix.msc3381.poll.disclosed",
|
||||
"kind": "org.matrix.msc3381.poll.undisclosed",
|
||||
"max_selections": 1,
|
||||
"question": {
|
||||
"body": "test",
|
||||
|
||||
@@ -130,7 +130,23 @@
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"state_key": "@alice:matrix.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Bob",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "bob:example.org",
|
||||
"state_key": "@bob:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
|
||||
@@ -51,6 +51,21 @@
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"displayname": "Example",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "https://kde.org",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "www.example.org",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"body": "[Rich Link](https://kde.org)",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<a href=\"https://kde.org\">Rich Link</a>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$validlink1:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!test:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickItem>
|
||||
#include <QTest>
|
||||
|
||||
#include "delegatesizehelper.h"
|
||||
@@ -30,7 +31,7 @@ void DelegateSizeHelperTest::risingPercentage_data()
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("zero") << qreal(0) << int(0) << qreal(0);
|
||||
QTest::newRow("zero") << qreal(0) << int(100) << qreal(0);
|
||||
QTest::newRow("one hundred") << qreal(100) << int(0) << qreal(0);
|
||||
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
||||
QTest::newRow("two hundred") << qreal(200) << int(100) << qreal(200);
|
||||
@@ -43,16 +44,18 @@ void DelegateSizeHelperTest::risingPercentage()
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
auto item = QQuickItem();
|
||||
item.setWidth(parentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setParentItem(&item);
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(0);
|
||||
delegateSizeHelper.setEndPercentWidth(100);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::fallingPercentage_data()
|
||||
@@ -74,16 +77,18 @@ void DelegateSizeHelperTest::fallingPercentage()
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
auto item = QQuickItem();
|
||||
item.setWidth(parentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setParentItem(&item);
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(100);
|
||||
delegateSizeHelper.setEndPercentWidth(0);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::equalPercentage_data()
|
||||
@@ -105,16 +110,18 @@ void DelegateSizeHelperTest::equalPercentage()
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
auto item = QQuickItem();
|
||||
item.setWidth(parentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setParentItem(&item);
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(50);
|
||||
delegateSizeHelper.setEndPercentWidth(50);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::equalBreakpoint_data()
|
||||
@@ -124,13 +131,13 @@ void DelegateSizeHelperTest::equalBreakpoint_data()
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("start higher") << int(100) << int(0) << int(-1) << qreal(0);
|
||||
QTest::newRow("start higher") << int(100) << int(0) << int(100) << qreal(1000);
|
||||
QTest::newRow("equal") << int(50) << int(50) << int(50) << qreal(500);
|
||||
QTest::newRow("end higher") << int(0) << int(100) << int(-1) << qreal(0);
|
||||
QTest::newRow("end higher") << int(0) << int(100) << int(100) << qreal(1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* We expect a default return except in the case where the the two percentages are
|
||||
* We expect a default return except in the case where the two percentages are
|
||||
* equal as that case can be calculated without dividing by zero.
|
||||
*/
|
||||
void DelegateSizeHelperTest::equalBreakpoint()
|
||||
@@ -140,16 +147,18 @@ void DelegateSizeHelperTest::equalBreakpoint()
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
auto item = QQuickItem();
|
||||
item.setWidth(1000);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setParentItem(&item);
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(100);
|
||||
delegateSizeHelper.setStartPercentWidth(startPercentageWidth);
|
||||
delegateSizeHelper.setEndPercentWidth(endPercentageWidth);
|
||||
|
||||
delegateSizeHelper.setParentWidth(1000);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(DelegateSizeHelperTest)
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qcbormap.h>
|
||||
#include <qtestcase.h>
|
||||
|
||||
#include "enums/delegatetype.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "models/reactionmodel.h"
|
||||
#include "neochatroom.h"
|
||||
@@ -29,21 +30,10 @@ class EventHandlerTest : public QObject
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
TestUtils::TestRoom *room = nullptr;
|
||||
EventHandler eventHandler;
|
||||
EventHandler emptyHandler;
|
||||
EventHandler noEventHandler;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void nullSetEvent();
|
||||
void eventId();
|
||||
void nullEventId();
|
||||
void delegateType_data();
|
||||
void delegateType();
|
||||
void nullDelegateType();
|
||||
void author();
|
||||
void nullAuthor();
|
||||
void authorDisplayName();
|
||||
void nullAuthorDisplayName();
|
||||
void singleLineSidplayName();
|
||||
@@ -51,7 +41,6 @@ private Q_SLOTS:
|
||||
void time();
|
||||
void nullTime();
|
||||
void timeString();
|
||||
void nullTimeString();
|
||||
void highlighted();
|
||||
void nullHighlighted();
|
||||
void hidden();
|
||||
@@ -61,261 +50,159 @@ private Q_SLOTS:
|
||||
void genericBody_data();
|
||||
void genericBody();
|
||||
void nullGenericBody();
|
||||
void markdownBody();
|
||||
void markdownBodyReply();
|
||||
void subtitle();
|
||||
void nullSubtitle();
|
||||
void mediaInfo();
|
||||
void nullMediaInfo();
|
||||
void hasReply();
|
||||
void nullHasReply();
|
||||
void replyId();
|
||||
void nullReplyId();
|
||||
void replyDelegateType();
|
||||
void nullReplyDelegateType();
|
||||
void replyAuthor();
|
||||
void nullReplyAuthor();
|
||||
void replyBody();
|
||||
void nullReplyBody();
|
||||
void replyMediaInfo();
|
||||
void nullReplyMediaInfo();
|
||||
void thread();
|
||||
void nullThread();
|
||||
void location();
|
||||
void nullLocation();
|
||||
void readMarkers();
|
||||
void nullReadMarkers();
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
void EventHandlerTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-eventhandler-sync.json"));
|
||||
|
||||
eventHandler.setRoom(room);
|
||||
noEventHandler.setRoom(room);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullSetEvent()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "cannot setEvent when m_room is set to nullptr.");
|
||||
emptyHandler.setEvent(room->messageEvents().at(0).get());
|
||||
}
|
||||
|
||||
void EventHandlerTest::eventId()
|
||||
{
|
||||
eventHandler.setEvent(room->messageEvents().at(0).get());
|
||||
|
||||
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullEventId()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getId called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getId(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::delegateType_data()
|
||||
{
|
||||
QTest::addColumn<int>("eventNum");
|
||||
QTest::addColumn<DelegateType::Type>("delegateType");
|
||||
|
||||
QTest::newRow("message") << 0 << DelegateType::Message;
|
||||
QTest::newRow("state") << 1 << DelegateType::State;
|
||||
QTest::newRow("message 2") << 2 << DelegateType::Message;
|
||||
QTest::newRow("reaction") << 3 << DelegateType::Other;
|
||||
QTest::newRow("video") << 4 << DelegateType::Video;
|
||||
QTest::newRow("location") << 7 << DelegateType::Location;
|
||||
}
|
||||
|
||||
void EventHandlerTest::delegateType()
|
||||
{
|
||||
QFETCH(int, eventNum);
|
||||
QFETCH(DelegateType::Type, delegateType);
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(eventNum).get());
|
||||
|
||||
QCOMPARE(eventHandler.getDelegateType(), delegateType);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullDelegateType()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getDelegateType called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getDelegateType(), DelegateType::Other);
|
||||
}
|
||||
|
||||
void EventHandlerTest::author()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
auto author = room->user(event->senderId());
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
auto eventHandlerAuthor = eventHandler.getAuthor();
|
||||
|
||||
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
|
||||
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
|
||||
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
|
||||
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
|
||||
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
|
||||
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
|
||||
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
||||
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-eventhandler-sync.json"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::authorDisplayName()
|
||||
{
|
||||
auto event = room->messageEvents().at(1).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
|
||||
QCOMPARE(EventHandler::authorDisplayName(room, room->messageEvents().at(1).get()), u"before"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullAuthorDisplayName()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getAuthorDisplayName(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "authorDisplayName called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::authorDisplayName(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getAuthorDisplayName(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "authorDisplayName called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::authorDisplayName(room, nullptr), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::singleLineSidplayName()
|
||||
{
|
||||
auto event = room->messageEvents().at(11).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.singleLineAuthorDisplayname(), QStringLiteral("Look at me I put newlines in my display name"));
|
||||
QCOMPARE(EventHandler::singleLineAuthorDisplayname(room, room->messageEvents().at(11).get()), "Look at me I put newlines in my display name"_L1);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullSingleLineDisplayName()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.singleLineAuthorDisplayname(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "singleLineAuthorDisplayname called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::singleLineAuthorDisplayname(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.singleLineAuthorDisplayname(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "singleLineAuthorDisplayname called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::singleLineAuthorDisplayname(room, nullptr), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::time()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
const auto event = room->messageEvents().at(0).get();
|
||||
|
||||
QCOMPARE(eventHandler.getTime(), QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC));
|
||||
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
|
||||
QCOMPARE(EventHandler::time(room, event), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)));
|
||||
|
||||
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
|
||||
QCOMPARE(room->pendingEvents().size(), 1);
|
||||
const auto pendingIt = room->findPendingEvent(txID);
|
||||
QCOMPARE(EventHandler::time(room, pendingIt->event(), true), pendingIt->lastUpdated());
|
||||
|
||||
room->discardMessage(txID);
|
||||
QCOMPARE(room->pendingEvents().size(), 0);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullTime()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getTime called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getTime(), QDateTime());
|
||||
QTest::ignoreMessage(QtWarningMsg, "time called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::time(nullptr, nullptr), QDateTime());
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(0).get());
|
||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
||||
QCOMPARE(eventHandler.getTime(true), QDateTime());
|
||||
QTest::ignoreMessage(QtWarningMsg, "time called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::time(room, nullptr), QDateTime());
|
||||
}
|
||||
|
||||
void EventHandlerTest::timeString()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
const auto event = room->messageEvents().at(0).get();
|
||||
|
||||
KFormat format;
|
||||
|
||||
QCOMPARE(eventHandler.getTimeString(false),
|
||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
||||
QCOMPARE(eventHandler.getTimeString(true),
|
||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
||||
QCOMPARE(eventHandler.getTimeString(true, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat));
|
||||
QCOMPARE(eventHandler.getTimeString(true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
|
||||
}
|
||||
QCOMPARE(EventHandler::timeString(room, event, false),
|
||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat));
|
||||
QCOMPARE(EventHandler::timeString(room, event, true),
|
||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat));
|
||||
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s),
|
||||
QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::LocalTime)).toString(u"hh:mm"_s));
|
||||
|
||||
void EventHandlerTest::nullTimeString()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getTimeString called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getTimeString(false), QString());
|
||||
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
|
||||
QCOMPARE(room->pendingEvents().size(), 1);
|
||||
const auto pendingIt = room->findPendingEvent(txID);
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(0).get());
|
||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true), QString());
|
||||
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::ShortFormat, true),
|
||||
QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::ShortFormat));
|
||||
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::ShortFormat, true),
|
||||
format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::ShortFormat));
|
||||
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::LongFormat, true),
|
||||
QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::LongFormat));
|
||||
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::LongFormat, true),
|
||||
format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::LongFormat));
|
||||
|
||||
room->discardMessage(txID);
|
||||
QCOMPARE(room->pendingEvents().size(), 0);
|
||||
}
|
||||
|
||||
void EventHandlerTest::highlighted()
|
||||
{
|
||||
auto event = room->messageEvents().at(2).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isHighlighted(), true);
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isHighlighted(), false);
|
||||
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(2).get()), true);
|
||||
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(0).get()), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHighlighted()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isHighlighted(), false);
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::isHighlighted(nullptr, nullptr), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.isHighlighted(), false);
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::isHighlighted(room, nullptr), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::hidden()
|
||||
{
|
||||
auto event = room->messageEvents().at(3).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isHidden(), true);
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isHidden(), false);
|
||||
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(3).get()), true);
|
||||
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(0).get()), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHidden()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isHidden(), false);
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::isHidden(nullptr, nullptr), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.isHidden(), false);
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::isHidden(room, nullptr), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::body()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
const auto event = room->messageEvents().at(0).get();
|
||||
|
||||
QCOMPARE(eventHandler.getRichBody(), QStringLiteral("<b>This is an example<br>text message</b>"));
|
||||
QCOMPARE(eventHandler.getRichBody(true), QStringLiteral("<b>This is an example text message</b>"));
|
||||
QCOMPARE(eventHandler.getPlainBody(), QStringLiteral("This is an example\ntext message"));
|
||||
QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
|
||||
QCOMPARE(EventHandler::richBody(room, event), u"<b>This is an example<br>text message</b>"_s);
|
||||
QCOMPARE(EventHandler::richBody(room, event, true), u"<b>This is an example text message</b>"_s);
|
||||
QCOMPARE(EventHandler::plainBody(room, event), u"This is an example\ntext message"_s);
|
||||
QCOMPARE(EventHandler::plainBody(room, event, true), u"This is an example text message"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getRichBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getRichBody(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "richBody called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::richBody(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getPlainBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getPlainBody(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "richBody called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::richBody(room, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "plainBody called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::plainBody(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "plainBody called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::plainBody(room, nullptr), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::genericBody_data()
|
||||
@@ -323,11 +210,11 @@ void EventHandlerTest::genericBody_data()
|
||||
QTest::addColumn<int>("eventNum");
|
||||
QTest::addColumn<QString>("output");
|
||||
|
||||
QTest::newRow("message") << 0 << QStringLiteral("sent a message");
|
||||
QTest::newRow("member") << 1 << QStringLiteral("changed their display name and updated their avatar");
|
||||
QTest::newRow("message 2") << 2 << QStringLiteral("sent a message");
|
||||
QTest::newRow("reaction") << 3 << QStringLiteral("Unknown event");
|
||||
QTest::newRow("video") << 4 << QStringLiteral("sent a message");
|
||||
QTest::newRow("message") << 0 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s;
|
||||
QTest::newRow("member") << 1 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> changed their display name and updated their avatar"_s;
|
||||
QTest::newRow("message 2") << 2 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s;
|
||||
QTest::newRow("reaction") << 3 << u"Unknown event"_s;
|
||||
QTest::newRow("video") << 4 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s;
|
||||
}
|
||||
|
||||
void EventHandlerTest::genericBody()
|
||||
@@ -335,326 +222,116 @@ void EventHandlerTest::genericBody()
|
||||
QFETCH(int, eventNum);
|
||||
QFETCH(QString, output);
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(eventNum).get());
|
||||
|
||||
QCOMPARE(eventHandler.getGenericBody(), output);
|
||||
QCOMPARE(EventHandler::genericBody(room, room->messageEvents().at(eventNum).get()), output);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullGenericBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getGenericBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getGenericBody(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "genericBody called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::genericBody(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "genericBody called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::genericBody(room, nullptr), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::markdownBody()
|
||||
{
|
||||
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(0).get()), u"This is an example\ntext message"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::markdownBodyReply()
|
||||
{
|
||||
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(5).get()), u"reply"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::subtitle()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.subtitleText(), QStringLiteral("after: This is an example text message"));
|
||||
|
||||
event = room->messageEvents().at(2).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.subtitleText(), QStringLiteral("after: This is a highlight @bob:kde.org and this is a link https://kde.org"));
|
||||
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(0).get()), u"after: This is an example text message"_s);
|
||||
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(2).get()),
|
||||
u"after: This is a highlight @bob:kde.org and this is a link https://kde.org"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullSubtitle()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "subtitleText called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.subtitleText(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "subtitleText called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::subtitleText(nullptr, nullptr), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "subtitleText called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::subtitleText(room, nullptr), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::mediaInfo()
|
||||
{
|
||||
auto event = room->messageEvents().at(4).get();
|
||||
eventHandler.setEvent(event);
|
||||
auto mediaInfo = EventHandler::mediaInfo(room, event);
|
||||
auto thumbnailInfo = mediaInfo["tempInfo"_L1].toMap();
|
||||
|
||||
auto mediaInfo = eventHandler.getMediaInfo();
|
||||
auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
|
||||
|
||||
QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_ls)));
|
||||
QCOMPARE(mediaInfo["mimeType"_ls], QStringLiteral("video/mp4"));
|
||||
QCOMPARE(mediaInfo["mimeIcon"_ls], QStringLiteral("video-mp4"));
|
||||
QCOMPARE(mediaInfo["size"_ls], 62650636);
|
||||
QCOMPARE(mediaInfo["duration"_ls], 10);
|
||||
QCOMPARE(mediaInfo["width"_ls], 1920);
|
||||
QCOMPARE(mediaInfo["height"_ls], 1080);
|
||||
QCOMPARE(thumbnailInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/2234567"_ls)));
|
||||
QCOMPARE(thumbnailInfo["mimeType"_ls], QStringLiteral("image/jpeg"));
|
||||
QCOMPARE(thumbnailInfo["mimeIcon"_ls], QStringLiteral("image-jpeg"));
|
||||
QCOMPARE(thumbnailInfo["size"_ls], 382249);
|
||||
QCOMPARE(thumbnailInfo["width"_ls], 800);
|
||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
||||
QCOMPARE(mediaInfo["source"_L1], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_L1)));
|
||||
QCOMPARE(mediaInfo["mimeType"_L1], u"video/mp4"_s);
|
||||
QCOMPARE(mediaInfo["mimeIcon"_L1], u"video-mp4"_s);
|
||||
QCOMPARE(mediaInfo["size"_L1], 62650636);
|
||||
QCOMPARE(mediaInfo["duration"_L1], 10);
|
||||
QCOMPARE(mediaInfo["width"_L1], 1920);
|
||||
QCOMPARE(mediaInfo["height"_L1], 1080);
|
||||
QCOMPARE(thumbnailInfo["source"_L1], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/2234567"_L1)));
|
||||
QCOMPARE(thumbnailInfo["mimeType"_L1], u"image/jpeg"_s);
|
||||
QCOMPARE(thumbnailInfo["mimeIcon"_L1], u"image-jpeg"_s);
|
||||
QCOMPARE(thumbnailInfo["size"_L1], 382249);
|
||||
QCOMPARE(thumbnailInfo["width"_L1], 800);
|
||||
QCOMPARE(thumbnailInfo["height"_L1], 450);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullMediaInfo()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getMediaInfo(), QVariantMap());
|
||||
QTest::ignoreMessage(QtWarningMsg, "mediaInfo called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::mediaInfo(nullptr, nullptr), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getMediaInfo(), QVariantMap());
|
||||
}
|
||||
|
||||
void EventHandlerTest::hasReply()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.hasReply(), true);
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.hasReply(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHasReply()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReply called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.hasReply(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyId()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$153456789:example.org"));
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral(""));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyId()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyId called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyId(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyDelegateType()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Message);
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyDelegateType()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
QTest::ignoreMessage(QtWarningMsg, "mediaInfo called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::mediaInfo(room, nullptr), QVariantMap());
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyAuthor()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
auto replyEvent = room->messageEvents().at(0).get();
|
||||
auto replyAuthor = room->user(replyEvent->senderId());
|
||||
eventHandler.setEvent(event);
|
||||
auto replyAuthor = room->member(replyEvent->senderId());
|
||||
auto eventHandlerReplyAuthor = EventHandler::replyAuthor(room, room->messageEvents().at(5).get());
|
||||
|
||||
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
||||
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
|
||||
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
|
||||
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
|
||||
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
|
||||
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
|
||||
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
|
||||
|
||||
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
|
||||
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
|
||||
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
|
||||
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
|
||||
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
|
||||
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
|
||||
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
|
||||
|
||||
event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr));
|
||||
QCOMPARE(EventHandler::replyAuthor(room, room->messageEvents().at(0).get()), RoomMember());
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
||||
QTest::ignoreMessage(QtWarningMsg, "replyAuthor called with room set to nullptr.");
|
||||
QCOMPARE(EventHandler::replyAuthor(nullptr, nullptr), RoomMember());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
||||
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyBody()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getReplyRichBody(), QStringLiteral("<b>This is an example<br>text message</b>"));
|
||||
QCOMPARE(eventHandler.getReplyRichBody(true), QStringLiteral("<b>This is an example text message</b>"));
|
||||
QCOMPARE(eventHandler.getReplyPlainBody(), QStringLiteral("This is an example\ntext message"));
|
||||
QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyRichBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyRichBody(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyPlainBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyPlainBody(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyMediaInfo()
|
||||
{
|
||||
auto event = room->messageEvents().at(6).get();
|
||||
auto replyEvent = room->messageEvents().at(4).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
auto mediaInfo = eventHandler.getReplyMediaInfo();
|
||||
auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
|
||||
|
||||
QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(replyEvent->id(), QUrl("mxc://kde.org/1234567"_ls)));
|
||||
QCOMPARE(mediaInfo["mimeType"_ls], QStringLiteral("video/mp4"));
|
||||
QCOMPARE(mediaInfo["mimeIcon"_ls], QStringLiteral("video-mp4"));
|
||||
QCOMPARE(mediaInfo["size"_ls], 62650636);
|
||||
QCOMPARE(mediaInfo["duration"_ls], 10);
|
||||
QCOMPARE(mediaInfo["width"_ls], 1920);
|
||||
QCOMPARE(mediaInfo["height"_ls], 1080);
|
||||
QCOMPARE(thumbnailInfo["source"_ls], room->makeMediaUrl(replyEvent->id(), QUrl("mxc://kde.org/2234567"_ls)));
|
||||
QCOMPARE(thumbnailInfo["mimeType"_ls], QStringLiteral("image/jpeg"));
|
||||
QCOMPARE(thumbnailInfo["mimeIcon"_ls], QStringLiteral("image-jpeg"));
|
||||
QCOMPARE(thumbnailInfo["size"_ls], 382249);
|
||||
QCOMPARE(thumbnailInfo["width"_ls], 800);
|
||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyMediaInfo()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyMediaInfo(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyMediaInfo(), QVariantMap());
|
||||
}
|
||||
|
||||
void EventHandlerTest::thread()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), false);
|
||||
QCOMPARE(eventHandler.threadRoot(), QString());
|
||||
|
||||
event = room->messageEvents().at(9).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), true);
|
||||
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadroot:example.org"));
|
||||
|
||||
event = room->messageEvents().at(10).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), true);
|
||||
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadmessage1:example.org"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullThread()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isThreaded(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.threadRoot(), QString());
|
||||
QTest::ignoreMessage(QtWarningMsg, "replyAuthor called with event set to nullptr. Returning empty user.");
|
||||
QCOMPARE(EventHandler::replyAuthor(room, nullptr), RoomMember());
|
||||
}
|
||||
|
||||
void EventHandlerTest::location()
|
||||
{
|
||||
auto event = room->messageEvents().at(7).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.getLatitude(), QStringLiteral("51.7035").toFloat());
|
||||
QCOMPARE(eventHandler.getLongitude(), QStringLiteral("-1.14394").toFloat());
|
||||
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
|
||||
QCOMPARE(EventHandler::latitude(room->messageEvents().at(7).get()), u"51.7035"_s.toFloat());
|
||||
QCOMPARE(EventHandler::longitude(room->messageEvents().at(7).get()), u"-1.14394"_s.toFloat());
|
||||
QCOMPARE(EventHandler::locationAssetType(room->messageEvents().at(7).get()), u"m.pin"_s);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullLocation()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLatitude called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLatitude(), -100.0);
|
||||
QTest::ignoreMessage(QtWarningMsg, "latitude called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::latitude(nullptr), -100.0);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLongitude called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLongitude(), -200.0);
|
||||
QTest::ignoreMessage(QtWarningMsg, "longitude called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::longitude(nullptr), -200.0);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLocationAssetType called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLocationAssetType(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::readMarkers()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.hasReadMarkers(), true);
|
||||
|
||||
auto readMarkers = eventHandler.getReadMarkers();
|
||||
|
||||
QCOMPARE(readMarkers.size(), 1);
|
||||
QCOMPARE(readMarkers[0].toMap()["id"_ls], QStringLiteral("@alice:matrix.org"));
|
||||
|
||||
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
|
||||
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: @alice:matrix.org"));
|
||||
|
||||
event = room->messageEvents().at(2).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.hasReadMarkers(), true);
|
||||
|
||||
readMarkers = eventHandler.getReadMarkers();
|
||||
|
||||
QCOMPARE(readMarkers.size(), 5);
|
||||
|
||||
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QStringLiteral("+ 1"));
|
||||
// There are no guarantees on the order of the users it will be different every time so don't match the whole string.
|
||||
QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReadMarkers()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReadMarkersString(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReadMarkersString(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::cleanup()
|
||||
{
|
||||
eventHandler.setEvent(nullptr);
|
||||
QTest::ignoreMessage(QtWarningMsg, "locationAssetType called with event set to nullptr.");
|
||||
QCOMPARE(EventHandler::locationAssetType(nullptr), QString());
|
||||
}
|
||||
|
||||
QTEST_MAIN(EventHandlerTest)
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
|
||||
#include "linkpreviewer.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -30,74 +29,74 @@ private Q_SLOTS:
|
||||
void linkPreviewsMatch_data();
|
||||
void linkPreviewsMatch();
|
||||
|
||||
void multipleLinkPreviewsMatch_data();
|
||||
void multipleLinkPreviewsMatch();
|
||||
|
||||
void linkPreviewsReject_data();
|
||||
void linkPreviewsReject();
|
||||
|
||||
void editedLink();
|
||||
};
|
||||
|
||||
void LinkPreviewerTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:example.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("!test:example.org"));
|
||||
connection = Connection::makeMockConnection(u"@bob:example.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"!test:example.org"_s);
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsMatch_data()
|
||||
{
|
||||
QTest::addColumn<QString>("eventSource");
|
||||
QTest::addColumn<QString>("inputString");
|
||||
QTest::addColumn<QUrl>("testOutputLink");
|
||||
|
||||
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
|
||||
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
|
||||
QTest::newRow("plainHttps") << u"https://kde.org"_s << QUrl(u"https://kde.org"_s);
|
||||
QTest::newRow("richHttps") << u"<a href=\"https://kde.org\">Rich Link</a>"_s << QUrl(u"https://kde.org"_s);
|
||||
QTest::newRow("richHttpsLinkDescription") << u"<a href=\"https://kde.org\">https://kde.org</a>"_s << QUrl(u"https://kde.org"_s);
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsMatch()
|
||||
{
|
||||
QFETCH(QString, eventSource);
|
||||
QFETCH(QString, inputString);
|
||||
QFETCH(QUrl, testOutputLink);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(room, event.get());
|
||||
auto link = LinkPreviewer::linkPreviews(inputString)[0];
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), false);
|
||||
QCOMPARE(linkPreviewer.url(), testOutputLink);
|
||||
QCOMPARE(link, testOutputLink);
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::multipleLinkPreviewsMatch_data()
|
||||
{
|
||||
QTest::addColumn<QString>("inputString");
|
||||
QTest::addColumn<QList<QUrl>>("testOutputLinks");
|
||||
|
||||
QTest::newRow("multipleHttps") << u"www.example.org https://kde.org"_s << QList{QUrl(u"www.example.org"_s), QUrl(u"https://kde.org"_s)};
|
||||
QTest::newRow("multipleHttps1Invalid") << u"www.example.org mxc://example.org/SEsfnsuifSDFSSEF"_s << QList{QUrl(u"www.example.org"_s)};
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::multipleLinkPreviewsMatch()
|
||||
{
|
||||
QFETCH(QString, inputString);
|
||||
QFETCH(QList<QUrl>, testOutputLinks);
|
||||
|
||||
auto links = LinkPreviewer::linkPreviews(inputString);
|
||||
|
||||
QCOMPARE(links, testOutputLinks);
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsReject_data()
|
||||
{
|
||||
QTest::addColumn<QString>("eventSource");
|
||||
QTest::addColumn<QString>("inputString");
|
||||
|
||||
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
|
||||
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
|
||||
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
|
||||
QTest::newRow("mxc") << u"mxc://example.org/SEsfnsuifSDFSSEF"_s;
|
||||
QTest::newRow("matrixTo") << u"https://matrix.to/#/@alice:example.org"_s;
|
||||
QTest::newRow("noSpace") << u"testhttps://kde.org"_s;
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsReject()
|
||||
{
|
||||
QFETCH(QString, eventSource);
|
||||
QFETCH(QString, inputString);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(room, event.get());
|
||||
auto links = LinkPreviewer::linkPreviews(inputString);
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), true);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::editedLink()
|
||||
{
|
||||
room->syncNewEvents(QStringLiteral("test-linkpreviewerintial-sync.json"));
|
||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||
auto linkPreviewer = LinkPreviewer(room, event);
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), false);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl("https://kde.org"_ls));
|
||||
|
||||
room->syncNewEvents(QStringLiteral("test-linkpreviewerreplace-sync.json"));
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), true);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||
QCOMPARE(links.empty(), true);
|
||||
}
|
||||
|
||||
QTEST_MAIN(LinkPreviewerTest)
|
||||
|
||||
@@ -25,6 +25,7 @@ private Q_SLOTS:
|
||||
void MediaSizeHelperTest::uninitialized()
|
||||
{
|
||||
MediaSizeHelper mediasizehelper;
|
||||
mediasizehelper.setMaxSize(540, 540);
|
||||
QCOMPARE(mediasizehelper.currentSize(), QSize(540, qRound(qreal(NeoChatConfig::self()->mediaMaxWidth()) / qreal(16.0) * qreal(9.0))));
|
||||
}
|
||||
|
||||
@@ -60,6 +61,7 @@ void MediaSizeHelperTest::limits()
|
||||
QFETCH(QSize, currentSize);
|
||||
|
||||
MediaSizeHelper mediasizehelper;
|
||||
mediasizehelper.setMaxSize(540, 540);
|
||||
mediasizehelper.setMediaWidth(mediaWidth);
|
||||
mediasizehelper.setMediaHeight(mediaHeight);
|
||||
mediasizehelper.setContentMaxWidth(contentMaxWidth);
|
||||
|
||||
62
autotests/messagecontentmodeltest.cpp
Normal file
62
autotests/messagecontentmodeltest.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/roommember.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "models/eventmessagecontentmodel.h"
|
||||
|
||||
#include "neochatconnection.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
class MessageContentModelTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void missingEvent();
|
||||
};
|
||||
|
||||
void MessageContentModelTest::initTestCase()
|
||||
{
|
||||
connection = new NeoChatConnection;
|
||||
}
|
||||
|
||||
void MessageContentModelTest::missingEvent()
|
||||
{
|
||||
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||
auto model1 = EventMessageContentModel(room, u"$153456789:example.org"_s);
|
||||
|
||||
QCOMPARE(model1.rowCount(), 1);
|
||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading…"_s);
|
||||
|
||||
auto model2 = EventMessageContentModel(room, u"$153456789:example.org"_s, true);
|
||||
|
||||
QCOMPARE(model2.rowCount(), 1);
|
||||
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply…"_s);
|
||||
|
||||
room->syncNewEvents(u"test-min-sync.json"_s);
|
||||
QCOMPARE(model1.rowCount(), 2);
|
||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Author);
|
||||
QCOMPARE(model1.data(model1.index(1), MessageContentModel::ComponentTypeRole), MessageComponentType::Text);
|
||||
QCOMPARE(model1.data(model1.index(1), MessageContentModel::DisplayRole), u"<b>This is an example<br>text message</b>"_s);
|
||||
}
|
||||
|
||||
QTEST_MAIN(MessageContentModelTest)
|
||||
#include "messagecontentmodeltest.moc"
|
||||
@@ -27,8 +27,8 @@ private Q_SLOTS:
|
||||
|
||||
void NeoChatRoomTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), "test-min-sync.json"_ls);
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
||||
}
|
||||
|
||||
void NeoChatRoomTest::eventTest()
|
||||
|
||||
@@ -31,8 +31,8 @@ private Q_SLOTS:
|
||||
|
||||
void PollHandlerTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), "test-pollhandlerstart-sync.json"_ls);
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-pollhandlerstart-sync.json"_s);
|
||||
}
|
||||
|
||||
// Basically don't crash.
|
||||
@@ -41,29 +41,32 @@ void PollHandlerTest::nullObject()
|
||||
auto pollHandler = PollHandler();
|
||||
|
||||
QCOMPARE(pollHandler.hasEnded(), false);
|
||||
QCOMPARE(pollHandler.answerCount(), 0);
|
||||
QCOMPARE(pollHandler.numAnswers(), 0);
|
||||
QCOMPARE(pollHandler.question(), QString());
|
||||
QCOMPARE(pollHandler.options(), QJsonArray());
|
||||
QCOMPARE(pollHandler.answers(), QJsonObject());
|
||||
QCOMPARE(pollHandler.counts(), QJsonObject());
|
||||
QCOMPARE(pollHandler.kind(), QString());
|
||||
QCOMPARE(pollHandler.kind(), PollKind::Disclosed);
|
||||
}
|
||||
|
||||
void PollHandlerTest::poll()
|
||||
{
|
||||
auto startEvent = eventCast<const PollStartEvent>(room->messageEvents().at(0).get());
|
||||
auto pollHandler = PollHandler(room, startEvent);
|
||||
auto pollHandler = PollHandler(room, startEvent->id());
|
||||
|
||||
auto options = QJsonArray{QJsonObject{{"id"_ls, "option1"_ls}, {"org.matrix.msc1767.text"_ls, "option1"_ls}},
|
||||
QJsonObject{{"id"_ls, "option2"_ls}, {"org.matrix.msc1767.text"_ls, "option2"_ls}}};
|
||||
QList<Quotient::EventContent::Answer> options = {EventContent::Answer{"option1"_L1, "option1"_L1}, EventContent::Answer{"option2"_L1, "option2"_L1}};
|
||||
|
||||
const auto answer0 = pollHandler.answerAtRow(0);
|
||||
const auto answer1 = pollHandler.answerAtRow(1);
|
||||
QCOMPARE(pollHandler.hasEnded(), false);
|
||||
QCOMPARE(pollHandler.answerCount(), 0);
|
||||
QCOMPARE(pollHandler.question(), QStringLiteral("test"));
|
||||
QCOMPARE(pollHandler.options(), options);
|
||||
QCOMPARE(pollHandler.answers(), QJsonObject());
|
||||
QCOMPARE(pollHandler.counts(), QJsonObject());
|
||||
QCOMPARE(pollHandler.kind(), QStringLiteral("org.matrix.msc3381.poll.disclosed"));
|
||||
QCOMPARE(pollHandler.numAnswers(), 2);
|
||||
QCOMPARE(pollHandler.question(), u"test"_s);
|
||||
QCOMPARE(answer0.id, "option1"_L1);
|
||||
QCOMPARE(answer1.id, "option2"_L1);
|
||||
QCOMPARE(answer0.text, "option1text"_L1);
|
||||
QCOMPARE(answer1.text, "option2text"_L1);
|
||||
QCOMPARE(pollHandler.answerCountAtId(answer0.id), 0);
|
||||
QCOMPARE(pollHandler.answerCountAtId(answer1.id), 0);
|
||||
QCOMPARE(pollHandler.checkMemberSelectedId(connection->userId(), answer0.id), false);
|
||||
QCOMPARE(pollHandler.checkMemberSelectedId(connection->userId(), answer1.id), false);
|
||||
QCOMPARE(pollHandler.kind(), PollKind::Undisclosed);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(PollHandlerTest)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
#include "models/eventmessagecontentmodel.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -20,61 +21,50 @@ class ReactionModelTest : public QObject
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
TestUtils::TestRoom *room = nullptr;
|
||||
EventMessageContentModel *parentModel;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void nullModel();
|
||||
void basicReaction();
|
||||
void newReaction();
|
||||
};
|
||||
|
||||
void ReactionModelTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-reactionmodel-sync.json"));
|
||||
}
|
||||
|
||||
void ReactionModelTest::nullModel()
|
||||
{
|
||||
auto model = ReactionModel(nullptr, nullptr);
|
||||
|
||||
QCOMPARE(model.rowCount(), 0);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QVariant());
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
|
||||
parentModel = new EventMessageContentModel(room, "123456"_L1);
|
||||
}
|
||||
|
||||
void ReactionModelTest::basicReaction()
|
||||
{
|
||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||
auto model = ReactionModel(event, room);
|
||||
auto model = ReactionModel(parentModel, event->id(), room);
|
||||
|
||||
QCOMPARE(model.rowCount(), 1);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QStringLiteral("<span style=\"font-family: 'emoji';\">👍</span>"));
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||
auto authorList = QVariantList{room->getUser(room->user(QStringLiteral("@alice:matrix.org")))};
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), u"<span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), u"👍"_s);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalMember), false);
|
||||
}
|
||||
|
||||
void ReactionModelTest::newReaction()
|
||||
{
|
||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||
auto model = new ReactionModel(event, room);
|
||||
auto model = new ReactionModel(parentModel, event->id(), room);
|
||||
|
||||
QCOMPARE(model->rowCount(), 1);
|
||||
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
|
||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||
|
||||
QSignalSpy spy(model, SIGNAL(modelReset()));
|
||||
|
||||
room->syncNewEvents(QLatin1String("test-reactionmodel-extra-sync.json"));
|
||||
room->syncNewEvents(u"test-reactionmodel-extra-sync.json"_s);
|
||||
QCOMPARE(model->rowCount(), 2);
|
||||
QCOMPARE(spy.count(), 2); // Once for each of the 2 new reactions.
|
||||
QCOMPARE(model->data(model->index(1), ReactionModel::ReactionRole), QStringLiteral("😆"));
|
||||
QCOMPARE(model->data(model->index(1), ReactionModel::ReactionRole), u"😆"_s);
|
||||
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
|
||||
QStringLiteral("@alice:matrix.org and @bob:example.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||
u"Alice Margatroid and Bob reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||
|
||||
delete model;
|
||||
}
|
||||
|
||||
141
autotests/roommanagertest.cpp
Normal file
141
autotests/roommanagertest.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
#include <QVariantList>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "roommanager.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class RoomManagerTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
NeoChatConnection *connection = nullptr;
|
||||
NeoChatRoom *room = nullptr;
|
||||
|
||||
Server server;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void testMaximizeMedia();
|
||||
void testResolveMatrixLinks();
|
||||
};
|
||||
|
||||
void RoomManagerTest::initTestCase()
|
||||
{
|
||||
Connection::setRoomType<NeoChatRoom>();
|
||||
server.start();
|
||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||
auto accountManager = new AccountManager(true);
|
||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
||||
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
|
||||
QVERIFY(connection);
|
||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
||||
|
||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
||||
// We need to wait for two syncs, as the next one won't have the changes yet
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
||||
QVERIFY(room);
|
||||
RoomManager::instance().setConnection(connection);
|
||||
QSignalSpy roomSpy(&RoomManager::instance(), &RoomManager::currentRoomChanged);
|
||||
RoomManager::instance().resolveResource(room->id());
|
||||
QVERIFY(roomSpy.size() > 0);
|
||||
}
|
||||
|
||||
void RoomManagerTest::testMaximizeMedia()
|
||||
{
|
||||
QSignalSpy spy(&RoomManager::instance(), &RoomManager::showMaximizedMedia);
|
||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
||||
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for empty event id");
|
||||
RoomManager::instance().maximizeMedia(QString());
|
||||
QVERIFY(!spy.wait(10));
|
||||
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for unknown event id \"Doesn't exist\"");
|
||||
RoomManager::instance().maximizeMedia(u"Doesn't exist"_s);
|
||||
QVERIFY(!spy.wait(10));
|
||||
|
||||
const auto eventWithoutMedia = server.sendEvent(room->id(),
|
||||
u"m.room.message"_s,
|
||||
QJsonObject({
|
||||
{u"body"_s, u"Foo"_s},
|
||||
{u"format"_s, u"org.matrix.custom.html"_s},
|
||||
{u"formatted_body"_s, u"Foo"_s},
|
||||
{u"msgtype"_s, u"m.text"_s},
|
||||
}));
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(eventWithoutMedia).toLatin1().data());
|
||||
RoomManager::instance().maximizeMedia(eventWithoutMedia);
|
||||
QVERIFY(!spy.wait(10));
|
||||
|
||||
// NOTE: This is supposed to test that maximizing pending media works correctly. This probably doesn't work in the UI yet, but at least the backend supports
|
||||
// it. If the server ever learns how to process events, this becomes pointless and we need to find a way of preventing *these* events from arriving
|
||||
auto pendingEventWithoutMedia = room->postText(u"Hello"_s);
|
||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(pendingEventWithoutMedia).toLatin1().data());
|
||||
RoomManager::instance().maximizeMedia(pendingEventWithoutMedia);
|
||||
QVERIFY(!spy.wait(10));
|
||||
|
||||
const auto eventWithMedia = server.sendEvent(room->id(),
|
||||
u"m.room.message"_s,
|
||||
QJsonObject({
|
||||
{u"body"_s, u"Foo"_s},
|
||||
{u"filename"_s, u"foo.jpg"_s},
|
||||
{u"info"_s,
|
||||
QJsonObject{
|
||||
{u"h"_s, 1000},
|
||||
{u"w"_s, 2000},
|
||||
{u"size"_s, 10000},
|
||||
{u"mimetype"_s, u"image/png"_s},
|
||||
}},
|
||||
{u"msgtype"_s, u"m.image"_s},
|
||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
||||
}));
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
RoomManager::instance().maximizeMedia(eventWithMedia);
|
||||
QVERIFY(spy.size() == 1);
|
||||
QVERIFY(spy[0][0] == 0);
|
||||
|
||||
auto pendingEventWithMedia = room->postJson(u"m.room.message"_s,
|
||||
QJsonObject({
|
||||
{u"body"_s, u"Foo"_s},
|
||||
{u"filename"_s, u"foo.jpg"_s},
|
||||
{u"info"_s,
|
||||
QJsonObject{
|
||||
{u"h"_s, 1000},
|
||||
{u"w"_s, 2000},
|
||||
{u"size"_s, 10000},
|
||||
{u"mimetype"_s, u"image/png"_s},
|
||||
}},
|
||||
{u"msgtype"_s, u"m.image"_s},
|
||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
||||
}));
|
||||
RoomManager::instance().maximizeMedia(pendingEventWithMedia);
|
||||
QVERIFY(spy.size() == 2);
|
||||
QVERIFY(spy[1][0] == 0);
|
||||
}
|
||||
|
||||
void RoomManagerTest::testResolveMatrixLinks()
|
||||
{
|
||||
// Test if resolving a non-joined room will bring up the confirmation dialog.
|
||||
const QSignalSpy askToJoinSpy(&RoomManager::instance(), &RoomManager::askJoinRoom);
|
||||
RoomManager::instance().resolveResource(QStringLiteral("matrix:r/testbuild:matrix.org"), QStringLiteral("join"));
|
||||
QTRY_COMPARE(askToJoinSpy.size(), 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN(RoomManagerTest)
|
||||
#include "roommanagertest.moc"
|
||||
371
autotests/server.cpp
Normal file
371
autotests/server.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QHttpServerResponder>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
#include <QUuid>
|
||||
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
QString generateEventId()
|
||||
{
|
||||
return u"$"_s + QString::fromLatin1(QCryptographicHash::hash(QUuid::createUuid().toString().toLatin1(), QCryptographicHash::Sha1).toBase64());
|
||||
}
|
||||
|
||||
QString generateRoomId()
|
||||
{
|
||||
return u"!%1:localhost:1234"_s
|
||||
.arg(QString::fromLatin1(QCryptographicHash::hash(QUuid::createUuid().toString().toLatin1(), QCryptographicHash::Sha1).toBase64()))
|
||||
.replace(u'/', QChar());
|
||||
}
|
||||
|
||||
Server::Server()
|
||||
{
|
||||
}
|
||||
|
||||
void Server::start()
|
||||
{
|
||||
QObject::connect(Quotient::NetworkAccessManager::instance(),
|
||||
&QNetworkAccessManager::sslErrors,
|
||||
Quotient::NetworkAccessManager::instance(),
|
||||
[](QNetworkReply *reply) {
|
||||
reply->ignoreSslErrors();
|
||||
});
|
||||
m_server.route(u"/.well-known/matrix/client"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
||||
responder.write(QJsonDocument(QJsonObject{
|
||||
{u"m.homeserver"_s, QJsonObject{{u"base_url"_s, u"https://localhost:1234"_s}}},
|
||||
}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
m_server.route(u"/_matrix/client/versions"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
||||
responder.write(QJsonDocument(QJsonObject{
|
||||
{u"versions"_s,
|
||||
QJsonArray{
|
||||
u"v1.0"_s,
|
||||
u"v1.1"_s,
|
||||
u"v1.2"_s,
|
||||
u"v1.3"_s,
|
||||
u"v1.4"_s,
|
||||
u"v1.5"_s,
|
||||
u"v1.6"_s,
|
||||
u"v1.7"_s,
|
||||
u"v1.8"_s,
|
||||
u"v1.9"_s,
|
||||
u"v1.10"_s,
|
||||
u"v1.11"_s,
|
||||
u"v1.12"_s,
|
||||
u"v1.13"_s,
|
||||
}},
|
||||
}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
m_server.route(u"/_matrix/client/v3/capabilities"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
||||
responder.write(
|
||||
QJsonDocument(QJsonObject{{u"capabilities"_s,
|
||||
QJsonObject{
|
||||
{u"m.room_versions"_s, QJsonObject{{u"m.available"_s, QJsonObject{{u"1"_s, u"stable"_s}}}, {u"default"_s, u"1"_s}}},
|
||||
}}}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
m_server.route(u"/_matrix/client/v3/account/whoami"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
||||
responder.write(QJsonDocument(QJsonObject{
|
||||
{u"device_id"_s, u"device_id_1234"_s},
|
||||
{u"user_id"_s, u"@user:localhost:1234"_s},
|
||||
}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
|
||||
m_server.route(u"/_matrix/client/v3/login"_s, QHttpServerRequest::Method::Post, [](QHttpServerResponder &responder) {
|
||||
// TODO
|
||||
// if data["identifier"]["user"] != "user" or data["password"] != "1234":
|
||||
// abort(403)
|
||||
responder.write(QJsonDocument(QJsonObject{
|
||||
{u"access_token"_s, u"token_login"_s},
|
||||
{u"device_id"_s, u"device_1234"_s},
|
||||
{u"user_id"_s, u"@user:localhost:1234"_s},
|
||||
}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
|
||||
m_server.route(u"/_matrix/client/v3/login"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
||||
responder.write(QJsonDocument(QJsonObject{
|
||||
{u"flows"_s, QJsonArray{QJsonObject{{u"type"_s, u"m.login.password"_s}}}},
|
||||
}),
|
||||
QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
|
||||
m_server.route(u"/_matrix/client/v3/rooms/<arg>/invite"_s,
|
||||
QHttpServerRequest::Method::Post,
|
||||
[this](const QString &roomId, QHttpServerResponder &responder, const QHttpServerRequest &request) {
|
||||
Changes changes;
|
||||
changes.invitations += Changes::InviteUser{
|
||||
.userId = QJsonDocument::fromJson(request.body()).object()[u"user_id"_s].toString(),
|
||||
.roomId = roomId,
|
||||
};
|
||||
m_state += changes;
|
||||
responder.write(QJsonDocument(QJsonObject{}), QHttpServerResponder::StatusCode::Ok);
|
||||
});
|
||||
|
||||
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, this, &Server::sync);
|
||||
|
||||
QSslConfiguration config;
|
||||
QFile key(QStringLiteral(DATA_DIR) + u"/localhost.key"_s);
|
||||
void(key.open(QFile::ReadOnly));
|
||||
config.setPrivateKey(QSslKey(&key, QSsl::Rsa));
|
||||
config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(DATA_DIR) + u"/localhost.crt"_s).front());
|
||||
m_sslServer.setSslConfiguration(config);
|
||||
if (!m_sslServer.listen(QHostAddress::LocalHost, 1234) || !m_server.bind(&m_sslServer)) {
|
||||
qFatal() << "Server failed to listen on a port.";
|
||||
return;
|
||||
} else {
|
||||
qWarning() << "Server listening";
|
||||
}
|
||||
}
|
||||
|
||||
QString Server::createRoom(const QString &matrixId)
|
||||
{
|
||||
const auto roomId = generateRoomId();
|
||||
Changes changes;
|
||||
changes.newRooms += Changes::NewRoom{
|
||||
.initialMembers = {matrixId},
|
||||
.roomId = {roomId},
|
||||
.tags = {},
|
||||
};
|
||||
m_state += changes;
|
||||
return roomId;
|
||||
}
|
||||
|
||||
void Server::inviteUser(const QString &roomId, const QString &matrixId)
|
||||
{
|
||||
Changes changes;
|
||||
changes.invitations += Changes::InviteUser{
|
||||
.userId = matrixId,
|
||||
.roomId = roomId,
|
||||
};
|
||||
m_state += changes;
|
||||
}
|
||||
|
||||
void Server::banUser(const QString &roomId, const QString &matrixId)
|
||||
{
|
||||
Changes changes;
|
||||
changes.bans += Changes::BanUser{
|
||||
.userId = matrixId,
|
||||
.roomId = roomId,
|
||||
};
|
||||
m_state += changes;
|
||||
}
|
||||
|
||||
void Server::joinUser(const QString &roomId, const QString &matrixId)
|
||||
{
|
||||
Changes changes;
|
||||
changes.joins += Changes::JoinUser{
|
||||
.userId = matrixId,
|
||||
.roomId = roomId,
|
||||
};
|
||||
m_state += changes;
|
||||
}
|
||||
|
||||
QString Server::createServerNoticesRoom(const QString &matrixId)
|
||||
{
|
||||
const auto roomId = generateRoomId();
|
||||
Changes changes;
|
||||
changes.newRooms += Changes::NewRoom{
|
||||
.initialMembers = {matrixId},
|
||||
.roomId = {roomId},
|
||||
.tags = {u"m.server_notice"_s},
|
||||
};
|
||||
m_state += changes;
|
||||
return roomId;
|
||||
}
|
||||
|
||||
QString Server::sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content)
|
||||
{
|
||||
Changes changes;
|
||||
const auto eventId = generateEventId();
|
||||
changes.events += Changes::Event{
|
||||
.fullJson = QJsonObject{{u"type"_s, eventType},
|
||||
{u"content"_s, content},
|
||||
{u"sender"_s, u"@foo:server.com"_s},
|
||||
{u"event_id"_s, eventId},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, roomId}},
|
||||
};
|
||||
m_state += changes;
|
||||
return eventId;
|
||||
}
|
||||
|
||||
void Server::sync(const QHttpServerRequest &request, QHttpServerResponder &responder)
|
||||
{
|
||||
QJsonObject joinRooms;
|
||||
auto token = request.query().queryItemValue(u"since"_s).toInt();
|
||||
|
||||
for (const auto &change : m_state.mid(token)) {
|
||||
for (const auto &newRoom : change.newRooms) {
|
||||
QJsonArray stateEvents;
|
||||
stateEvents += QJsonObject{
|
||||
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
|
||||
{u"event_id"_s, generateEventId()},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, newRoom.roomId},
|
||||
{u"sender"_s, newRoom.initialMembers[0]},
|
||||
{u"state_key"_s, QString()},
|
||||
{u"type"_s, u"m.room.create"_s},
|
||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||
};
|
||||
for (const auto &member : newRoom.initialMembers) {
|
||||
stateEvents += QJsonObject{
|
||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
||||
{u"event_id"_s, generateEventId()},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, newRoom.roomId},
|
||||
{u"sender"_s, member},
|
||||
{u"state_key"_s, member},
|
||||
{u"type"_s, u"m.room.member"_s},
|
||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||
};
|
||||
}
|
||||
|
||||
auto room = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents}}}};
|
||||
|
||||
QJsonArray roomAccountData;
|
||||
QJsonObject tags;
|
||||
for (const auto &tag : newRoom.tags) {
|
||||
tags[tag] = QJsonObject();
|
||||
}
|
||||
if (!tags.empty()) {
|
||||
roomAccountData += QJsonObject{{u"type"_s, u"m.tag"_s}, {u"content"_s, QJsonObject{{u"tags"_s, tags}}}};
|
||||
}
|
||||
|
||||
if (roomAccountData.size() > 0) {
|
||||
room[u"account_data"] = QJsonObject{{u"events"_s, roomAccountData}};
|
||||
}
|
||||
|
||||
joinRooms[newRoom.roomId] = room;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &change : m_state.mid(token)) {
|
||||
for (const auto &invitation : change.invitations) {
|
||||
// TODO: The invitation could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
||||
auto stateEvents = joinRooms[invitation.roomId][u"state"_s][u"events"_s].toArray();
|
||||
stateEvents += QJsonObject{
|
||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"invite"_s}}},
|
||||
{u"event_id"_s, generateEventId()},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, invitation.roomId},
|
||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
||||
{u"state_key"_s, invitation.userId},
|
||||
{u"type"_s, u"m.room.member"_s},
|
||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||
};
|
||||
if (joinRooms.contains(invitation.roomId)) {
|
||||
auto room = joinRooms[invitation.roomId].toObject();
|
||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
||||
joinRooms[invitation.roomId] = room;
|
||||
} else {
|
||||
joinRooms[invitation.roomId] = QJsonObject{{u"state"_s,
|
||||
QJsonObject{
|
||||
{u"events"_s, stateEvents},
|
||||
}}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &change : m_state.mid(token)) {
|
||||
for (const auto &ban : change.bans) {
|
||||
// TODO: The ban could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
||||
auto stateEvents = joinRooms[ban.roomId][u"state"_s][u"events"_s].toArray();
|
||||
stateEvents += QJsonObject{
|
||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"ban"_s}}},
|
||||
{u"event_id"_s, generateEventId()},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, ban.roomId},
|
||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
||||
{u"state_key"_s, ban.userId},
|
||||
{u"type"_s, u"m.room.member"_s},
|
||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||
};
|
||||
if (joinRooms.contains(ban.roomId)) {
|
||||
auto room = joinRooms[ban.roomId].toObject();
|
||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
||||
joinRooms[ban.roomId] = room;
|
||||
} else {
|
||||
joinRooms[ban.roomId] = QJsonObject{{u"state"_s,
|
||||
QJsonObject{
|
||||
{u"events"_s, stateEvents},
|
||||
}}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &change : m_state.mid(token)) {
|
||||
for (const auto &join : change.joins) {
|
||||
// TODO: The join could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
||||
auto stateEvents = joinRooms[join.roomId][u"state"_s][u"events"_s].toArray();
|
||||
stateEvents += QJsonObject{
|
||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
||||
{u"event_id"_s, generateEventId()},
|
||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||
{u"room_id"_s, join.roomId},
|
||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
||||
{u"state_key"_s, join.userId},
|
||||
{u"type"_s, u"m.room.member"_s},
|
||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||
};
|
||||
if (joinRooms.contains(join.roomId)) {
|
||||
auto room = joinRooms[join.roomId].toObject();
|
||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
||||
joinRooms[join.roomId] = room;
|
||||
} else {
|
||||
joinRooms[join.roomId] = QJsonObject{{u"state"_s,
|
||||
QJsonObject{
|
||||
{u"events"_s, stateEvents},
|
||||
}}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &change : m_state.mid(token)) {
|
||||
for (const auto &event : change.events) {
|
||||
// TODO the room might be in a different join state.
|
||||
auto timeline = joinRooms[event.fullJson[u"room_id"_s].toString()][u"timeline"_s][u"events"_s].toArray();
|
||||
timeline += event.fullJson;
|
||||
if (joinRooms.contains(event.fullJson[u"room_id"_s].toString())) {
|
||||
auto room = joinRooms[event.fullJson[u"room_id"_s].toString()].toObject();
|
||||
room[u"timeline"_s] = QJsonObject{{u"events"_s, timeline}};
|
||||
joinRooms[event.fullJson[u"room_id"_s].toString()] = room;
|
||||
} else {
|
||||
joinRooms[event.fullJson[u"room_id"_s].toString()] = QJsonObject{
|
||||
{u"timeline"_s, QJsonObject{{u"events"_s, timeline}}},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject syncData = {
|
||||
// {u"account_data"_s, QJsonObject {}},
|
||||
// {u"presence"_s, QJsonObject {}},
|
||||
{u"next_batch"_s, QString::number(m_state.size())},
|
||||
};
|
||||
|
||||
QJsonObject rooms;
|
||||
if (!joinRooms.isEmpty()) {
|
||||
rooms[u"join"_s] = joinRooms;
|
||||
}
|
||||
|
||||
if (!rooms.empty()) {
|
||||
syncData[u"rooms"_s] = rooms;
|
||||
}
|
||||
|
||||
qWarning() << syncData;
|
||||
responder.write(QJsonDocument(syncData), QHttpServerResponder::StatusCode::Ok);
|
||||
}
|
||||
78
autotests/server.h
Normal file
78
autotests/server.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include <QHttpServer>
|
||||
#include <QJsonObject>
|
||||
#include <QSslServer>
|
||||
|
||||
struct Changes {
|
||||
struct NewRoom {
|
||||
QStringList initialMembers;
|
||||
QString roomId;
|
||||
QStringList tags;
|
||||
};
|
||||
QList<NewRoom> newRooms;
|
||||
|
||||
struct InviteUser {
|
||||
QString userId;
|
||||
QString roomId;
|
||||
};
|
||||
QList<InviteUser> invitations;
|
||||
|
||||
struct BanUser {
|
||||
QString userId;
|
||||
QString roomId;
|
||||
};
|
||||
QList<BanUser> bans;
|
||||
|
||||
struct JoinUser {
|
||||
QString userId;
|
||||
QString roomId;
|
||||
};
|
||||
QList<JoinUser> joins;
|
||||
|
||||
struct Event {
|
||||
QJsonObject fullJson;
|
||||
};
|
||||
QList<Event> events;
|
||||
};
|
||||
|
||||
struct RoomData {
|
||||
QStringList members;
|
||||
QString id;
|
||||
QStringList tags;
|
||||
};
|
||||
|
||||
class Server : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Server();
|
||||
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Create a room and place the user with id matrixId in it.
|
||||
* Returns the room's id
|
||||
*/
|
||||
QString createRoom(const QString &matrixId);
|
||||
|
||||
void inviteUser(const QString &roomId, const QString &matrixId);
|
||||
void banUser(const QString &roomId, const QString &matrixId);
|
||||
void joinUser(const QString &roomId, const QString &matrixId);
|
||||
|
||||
/**
|
||||
* Create a server notices room.
|
||||
*/
|
||||
QString createServerNoticesRoom(const QString &matrixId);
|
||||
QString sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content);
|
||||
|
||||
private:
|
||||
QHttpServer m_server;
|
||||
QSslServer m_sslServer;
|
||||
|
||||
void sync(const QHttpServerRequest &request, QHttpServerResponder &responder);
|
||||
|
||||
QList<Changes> m_state;
|
||||
};
|
||||
87
autotests/servernoticestest.cpp
Normal file
87
autotests/servernoticestest.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class ServerNoticesTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
NeoChatConnection *connection = nullptr;
|
||||
Server server;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void test();
|
||||
};
|
||||
|
||||
void ServerNoticesTest::initTestCase()
|
||||
{
|
||||
Connection::setRoomType<NeoChatRoom>();
|
||||
server.start();
|
||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||
auto accountManager = new AccountManager(true);
|
||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
||||
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
|
||||
QVERIFY(connection);
|
||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
||||
RoomManager::instance().setConnection(connection);
|
||||
|
||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
||||
// We need to wait for two syncs, as the next one won't have the changes yet
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
||||
QVERIFY(room);
|
||||
}
|
||||
|
||||
void ServerNoticesTest::test()
|
||||
{
|
||||
auto roomTreeModel = RoomManager::instance().roomTreeModel();
|
||||
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 0);
|
||||
auto sortFilterRoomTreeModel = RoomManager::instance().sortFilterRoomTreeModel();
|
||||
const auto roomId = server.createServerNoticesRoom(u"@user:localhost:1234"_s);
|
||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
const auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
||||
QVERIFY(connection->room(roomId)->isServerNoticeRoom());
|
||||
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 1);
|
||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
|
||||
server.sendEvent(roomId,
|
||||
u"m.room.message"_s,
|
||||
QJsonObject{
|
||||
{u"body"_s, u"Foo"_s},
|
||||
{u"format"_s, u"org.matrix.custom.html"_s},
|
||||
{u"formatted_body"_s, u"Foo"_s},
|
||||
{u"msgtype"_s, u"m.text"_s},
|
||||
});
|
||||
QVERIFY(syncSpy.wait());
|
||||
QVERIFY(syncSpy.wait());
|
||||
sortFilterRoomTreeModel->invalidate();
|
||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 0);
|
||||
room->markAllMessagesAsRead();
|
||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(ServerNoticesTest)
|
||||
#include "servernoticestest.moc"
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QTest>
|
||||
#include <Quotient/events/event.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
@@ -31,8 +32,8 @@ public:
|
||||
{
|
||||
if (!syncFileName.isEmpty()) {
|
||||
QFile testSyncFile;
|
||||
testSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + syncFileName);
|
||||
testSyncFile.open(QIODevice::ReadOnly);
|
||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
||||
Q_UNUSED(testSyncFile.open(QIODevice::ReadOnly));
|
||||
const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
||||
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object());
|
||||
update(std::move(roomData));
|
||||
@@ -45,8 +46,8 @@ inline Quotient::event_ptr_tt<EventT> loadEventFromFile(const QString &eventFile
|
||||
{
|
||||
if (!eventFileName.isEmpty()) {
|
||||
QFile testEventFile;
|
||||
testEventFile.setFileName(QLatin1String(DATA_DIR) + u'/' + eventFileName);
|
||||
testEventFile.open(QIODevice::ReadOnly);
|
||||
testEventFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + eventFileName);
|
||||
Q_UNUSED(testEventFile.open(QIODevice::ReadOnly));
|
||||
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
|
||||
return Quotient::loadEvent<EventT>(testSyncJson);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
#include <Kirigami/Platform/PlatformTheme>
|
||||
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
@@ -33,7 +34,10 @@ private Q_SLOTS:
|
||||
void stripDisallowedTags();
|
||||
void stripDisallowedAttributes();
|
||||
void emptyCodeTags();
|
||||
void formatBlockQuote();
|
||||
void addStyle_data();
|
||||
void addStyle();
|
||||
void dontAddStyle_data();
|
||||
void dontAddStyle();
|
||||
|
||||
void sendSimpleStringCase();
|
||||
void sendSingleParaMarkup();
|
||||
@@ -44,7 +48,10 @@ private Q_SLOTS:
|
||||
void sendCustomEmoji();
|
||||
void sendCustomEmojiCode_data();
|
||||
void sendCustomEmojiCode();
|
||||
void sendCustomTags_data();
|
||||
void sendCustomTags();
|
||||
|
||||
void receiveSpacelessSelfClosingTag();
|
||||
void receiveStripReply();
|
||||
void receivePlainTextIn();
|
||||
|
||||
@@ -58,51 +65,63 @@ private Q_SLOTS:
|
||||
void receiveRichStrikethrough();
|
||||
void receiveRichtextIn();
|
||||
void receiveRichMxcUrl();
|
||||
void receiveRichPlainUrl_data();
|
||||
void receiveRichPlainUrl();
|
||||
void receiveRichEmote();
|
||||
void receiveRichEdited_data();
|
||||
void receiveRichEdited();
|
||||
void receiveLineSeparator();
|
||||
void receiveRichCodeUrl();
|
||||
void receiveRichColor();
|
||||
|
||||
void componentOutput_data();
|
||||
void componentOutput();
|
||||
|
||||
void updateSpoiler_data();
|
||||
void updateSpoiler();
|
||||
};
|
||||
|
||||
void TextHandlerTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
connection->setAccountData("im.ponies.user_emotes"_ls,
|
||||
QJsonObject{{"images"_ls,
|
||||
QJsonObject{{"test"_ls,
|
||||
QJsonObject{{"body"_ls, "Test custom emoji"_ls},
|
||||
{"url"_ls, "mxc://example.org/test"_ls},
|
||||
{"usage"_ls, QJsonArray{"emoticon"_ls}}}}}}});
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
connection->setAccountData(u"im.ponies.user_emotes"_s,
|
||||
QJsonObject{{"images"_L1,
|
||||
QJsonObject{{"test"_L1,
|
||||
QJsonObject{{"body"_L1, "Test custom emoji"_L1},
|
||||
{"url"_L1, "mxc://example.org/test"_L1},
|
||||
{"usage"_L1, QJsonArray{"emoticon"_L1}}}}}}});
|
||||
CustomEmojiModel::instance().setConnection(static_cast<NeoChatConnection *>(connection));
|
||||
|
||||
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-texthandler-sync.json"));
|
||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-texthandler-sync.json"_s);
|
||||
}
|
||||
|
||||
void TextHandlerTest::allowedAttributes()
|
||||
{
|
||||
const QString testInputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>");
|
||||
const QString testOutputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>");
|
||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
const QString testInputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
||||
const QString testOutputString1S = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
||||
const QString testOutputString1R = u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
|
||||
theme->alternateBackgroundColor().name());
|
||||
// Handle urls where the href has either single (') or double (") quotes.
|
||||
const QString testInputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>");
|
||||
const QString testOutputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>");
|
||||
const QString testInputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
||||
const QString testOutputString2S = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
||||
const QString testOutputString2R =
|
||||
u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a><a href='https://kde.org' style=\"text-decoration: none;\">link</a>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString1);
|
||||
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString1);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1);
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString1S);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1R);
|
||||
|
||||
testTextHandler.setData(testInputString2);
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString2);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2);
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString2S);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2R);
|
||||
}
|
||||
|
||||
void TextHandlerTest::stripDisallowedTags()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> <body>Disallowed</body>");
|
||||
const QString testOutputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> Disallowed");
|
||||
const QString testInputString = u"<p>Allowed</p> <span>Allowed</span> <body>Disallowed</body>"_s;
|
||||
const QString testOutputString = u"<p>Allowed</p> <span>Allowed</span> Disallowed"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -113,8 +132,8 @@ void TextHandlerTest::stripDisallowedTags()
|
||||
|
||||
void TextHandlerTest::stripDisallowedAttributes()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p style=\"font-size:50px;\" color=#FFFFFF>Test</p>");
|
||||
const QString testOutputString = QStringLiteral("<p>Test</p>");
|
||||
const QString testInputString = u"<p style=\"font-size:50px;\" color=#FFFFFF>Test</p>"_s;
|
||||
const QString testOutputString = u"Test"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -129,8 +148,8 @@ void TextHandlerTest::stripDisallowedAttributes()
|
||||
*/
|
||||
void TextHandlerTest::emptyCodeTags()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<pre><code></code></pre>");
|
||||
const QString testOutputString = QStringLiteral("<pre><code></code></pre>");
|
||||
const QString testInputString = u"<pre><code></code></pre>"_s;
|
||||
const QString testOutputString = u"<pre><code></code></pre>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -139,20 +158,60 @@ void TextHandlerTest::emptyCodeTags()
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::formatBlockQuote()
|
||||
void TextHandlerTest::addStyle_data()
|
||||
{
|
||||
auto input = QStringLiteral("<blockquote>\n<p>Lorem Ispum</p>\n</blockquote>");
|
||||
auto expectedOutput = QStringLiteral("<blockquote><table><tr><td>\u201CLorem Ispum\u201D</td></tr></table></blockquote>");
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a>"_s;
|
||||
QTest::newRow("table")
|
||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
|
||||
<< u"<table style=\"width: 100%; border-collapse: collapse; border: 1px; border-style: solid;\"><tr><th style=\"border: 1px solid black; padding: 3px;\">Company</th><th style=\"border: 1px solid black; padding: 3px;\">Contact</th><th style=\"border: 1px solid black; padding: 3px;\">Country</th></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Alfreds Futterkiste</td><td style=\"border: 1px solid black; padding: 3px;\">Maria Anders</td><td style=\"border: 1px solid black; padding: 3px;\">Germany</td></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Centro comercial Moctezuma</td><td style=\"border: 1px solid black; padding: 3px;\">Francisco Chang</td><td style=\"border: 1px solid black; padding: 3px;\">Mexico</td></tr></table>"_s;
|
||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
|
||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
|
||||
theme->alternateBackgroundColor().name());
|
||||
}
|
||||
|
||||
void TextHandlerTest::addStyle()
|
||||
{
|
||||
QFETCH(QString, testInputString);
|
||||
QFETCH(QString, testOutputString);
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(input);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), expectedOutput);
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::dontAddStyle_data()
|
||||
{
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\">link</a>"_s;
|
||||
QTest::newRow("table")
|
||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
|
||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s;
|
||||
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
|
||||
<< u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
||||
}
|
||||
|
||||
void TextHandlerTest::dontAddStyle()
|
||||
{
|
||||
QFETCH(QString, testInputString);
|
||||
QFETCH(QString, testOutputString);
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::sendSimpleStringCase()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
|
||||
const QString testOutputString = QStringLiteral("<p>This data should just be put in a paragraph.</p>");
|
||||
const QString testInputString = u"This data should just be left alone."_s;
|
||||
const QString testOutputString = u"This data should just be left alone."_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -162,11 +221,10 @@ void TextHandlerTest::sendSimpleStringCase()
|
||||
|
||||
void TextHandlerTest::sendSingleParaMarkup()
|
||||
{
|
||||
const QString testInputString = QStringLiteral(
|
||||
"Text para with **bold**, *italic*, [link](https://kde.org), , `inline code`.");
|
||||
const QString testOutputString = QStringLiteral(
|
||||
"<p>Text para with <strong>bold</strong>, <em>italic</em>, <a href=\"https://kde.org\">link</a>, <img "
|
||||
"src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\">, <code>inline code</code>.</p>");
|
||||
const QString testInputString =
|
||||
u"Text para with **bold**, *italic*, [link](https://kde.org), , `inline code`."_s;
|
||||
const QString testOutputString =
|
||||
u"Text para with <strong>bold</strong>, <em>italic</em>, <a href=\"https://kde.org\">link</a>, <img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\">, <code>inline code</code>."_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -177,11 +235,9 @@ void TextHandlerTest::sendSingleParaMarkup()
|
||||
void TextHandlerTest::sendMultipleSectionMarkup()
|
||||
{
|
||||
const QString testInputString =
|
||||
QStringLiteral("Text para\n> blockquote\n* List 1\n* List 2\n1. one\n2. two\n# Heading 1\n## Heading 2\nhorizontal rule\n\n---\n```\ncodeblock\n```");
|
||||
const QString testOutputString = QStringLiteral(
|
||||
"<p>Text para</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>\n<ul>\n<li>List 1</li>\n<li>List "
|
||||
"2</li>\n</ul>\n<ol>\n<li>one</li>\n<li>two</li>\n</ol>\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<p>horizontal "
|
||||
"rule</p>\n<hr>\n<pre><code>codeblock\n</code></pre>");
|
||||
u"Text para\n> blockquote\n* List 1\n* List 2\n1. one\n2. two\n# Heading 1\n## Heading 2\nhorizontal rule\n\n---\n```\ncodeblock\n```"_s;
|
||||
const QString testOutputString =
|
||||
u"<p>Text para</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>\n<ul>\n<li>List 1</li>\n<li>List 2</li>\n</ul>\n<ol>\n<li>one</li>\n<li>two</li>\n</ol>\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<p>horizontal rule</p>\n<hr>\n<pre><code>codeblock\n</code></pre>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -191,8 +247,8 @@ void TextHandlerTest::sendMultipleSectionMarkup()
|
||||
|
||||
void TextHandlerTest::sendBadLinks()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("[link](kde.org), ");
|
||||
const QString testOutputString = QStringLiteral("<p><a>link</a>, <img alt=\"image\"></p>");
|
||||
const QString testInputString = u"[link](kde.org), "_s;
|
||||
const QString testOutputString = u"<a>link</a>, <img alt=\"image\">"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -205,9 +261,9 @@ void TextHandlerTest::sendBadLinks()
|
||||
*/
|
||||
void TextHandlerTest::sendEscapeCode()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("```\n<p>Test <span style=\"font-size:50px;\">some</span> code</p>\n```");
|
||||
const QString testInputString = u"```\n<p>Test <span style=\"font-size:50px;\">some</span> code</p>\n```"_s;
|
||||
const QString testOutputString =
|
||||
QStringLiteral("<pre><code><p>Test <span style="font-size:50px;">some</span> code</p>\n</code></pre>");
|
||||
u"<pre><code><p>Test <span style="font-size:50px;">some</span> code</p>\n</code></pre>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -217,8 +273,8 @@ void TextHandlerTest::sendEscapeCode()
|
||||
|
||||
void TextHandlerTest::sendCodeClass()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("```html\nsome code\n```\n<pre><code class=\"code-underline\">some more code</code></pre>");
|
||||
const QString testOutputString = QStringLiteral("<pre><code class=\"language-html\">some code\n</code></pre>\n<pre><code>some more code</code></pre>");
|
||||
const QString testInputString = u"```html\nsome code\n```\n<pre><code class=\"code-underline\">some more code</code></pre>"_s;
|
||||
const QString testOutputString = u"<pre><code class=\"language-html\">some code\n</code></pre>\n<pre><code>some more code</code></pre>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -228,9 +284,9 @@ void TextHandlerTest::sendCodeClass()
|
||||
|
||||
void TextHandlerTest::sendCustomEmoji()
|
||||
{
|
||||
const QString testInputString = QStringLiteral(":test:");
|
||||
const QString testOutputString = QStringLiteral(
|
||||
"<p><img data-mx-emoticon=\"\" src=\"mxc://example.org/test\" alt=\":test:\" title=\":test:\" height=\"32\" vertical-align=\"middle\" /></p>");
|
||||
const QString testInputString = u":test:"_s;
|
||||
const QString testOutputString =
|
||||
u"<img data-mx-emoticon=\"\" src=\"mxc://example.org/test\" alt=\":test:\" title=\":test:\" height=\"32\" vertical-align=\"middle\" />"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -243,8 +299,8 @@ void TextHandlerTest::sendCustomEmojiCode_data()
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
QTest::newRow("inline") << QStringLiteral("`:test:`") << QStringLiteral("<p><code>:test:</code></p>");
|
||||
QTest::newRow("block") << QStringLiteral("```\n:test:\n```") << QStringLiteral("<pre><code>:test:\n</code></pre>");
|
||||
QTest::newRow("inline") << u"`:test:`"_s << u"<code>:test:</code>"_s;
|
||||
QTest::newRow("block") << u"```\n:test:\n```"_s << u"<pre><code>:test:\n</code></pre>"_s;
|
||||
}
|
||||
|
||||
// Custom emojis in code blocks should be left alone.
|
||||
@@ -259,12 +315,58 @@ void TextHandlerTest::sendCustomEmojiCode()
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::sendCustomTags_data()
|
||||
{
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
// spoiler
|
||||
QTest::newRow("incomplete spoiler") << u"||test"_s << u"||test"_s;
|
||||
QTest::newRow("complete spoiler") << u"||test||"_s << u"<span data-mx-spoiler>test</span>"_s;
|
||||
QTest::newRow("multiple spoiler") << u"||apple||banana||pear||"_s << u"<span data-mx-spoiler>apple</span>banana<span data-mx-spoiler>pear</span>"_s;
|
||||
QTest::newRow("inside code block spoiler") << u"```||apple||```"_s << u"<code>||apple||</code>"_s;
|
||||
QTest::newRow("outside code block spoiler") << u"||apple|| ```||banana||``` ||pear||"_s
|
||||
<< u"<span data-mx-spoiler>apple</span> <code>||banana||</code> <span data-mx-spoiler>pear</span>"_s;
|
||||
QTest::newRow("complex spoiler") << u"Between `formFactor == Horizontal||Vertical` and `location == top||left||bottom||right`"_s
|
||||
<< u"Between <code>formFactor == Horizontal||Vertical</code> and <code>location == top||left||bottom||right</code>"_s;
|
||||
|
||||
// strikethrough
|
||||
QTest::newRow("incomplete strikethrough") << u"~~test"_s << u"~~test"_s;
|
||||
QTest::newRow("complete strikethrough") << u"~~test~~"_s << u"<del>test</del>"_s;
|
||||
QTest::newRow("inside code block strikethrough") << u"```~~apple~~```"_s << u"<code>~~apple~~</code>"_s;
|
||||
QTest::newRow("outside code block strikethrough") << u"~~apple~~ ```~~banana~~``` ~~pear~~"_s
|
||||
<< u"<del>apple</del> <code>~~banana~~</code> <del>pear</del>"_s;
|
||||
}
|
||||
|
||||
void TextHandlerTest::sendCustomTags()
|
||||
{
|
||||
QFETCH(QString, testInputString);
|
||||
QFETCH(QString, testOutputString);
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveSpacelessSelfClosingTag()
|
||||
{
|
||||
const QString testInputString = u"Test...<br/>...ing"_s;
|
||||
const QString testRichOutputString = u"Test...<br/>...ing"_s;
|
||||
const QString testPlainOutputString = u"Test...\n...ing"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testRichOutputString);
|
||||
QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText), testPlainOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveStripReply()
|
||||
{
|
||||
const QString testInputString = QStringLiteral(
|
||||
"<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a><a "
|
||||
"href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />Message replied to.</blockquote></mx-reply>Reply message.");
|
||||
const QString testOutputString = QStringLiteral("Reply message.");
|
||||
const QString testInputString =
|
||||
u"<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />Message replied to.</blockquote></mx-reply>Reply message."_s;
|
||||
const QString testOutputString = u"Reply message."_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -278,9 +380,10 @@ void TextHandlerTest::receiveRichInPlainOut_data()
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
QTest::newRow("ampersand") << QStringLiteral("a & b") << QStringLiteral("a & b");
|
||||
QTest::newRow("quote") << QStringLiteral(""a and b"") << QStringLiteral("\"a and b\"");
|
||||
QTest::newRow("new line") << QStringLiteral("new<br>line") << QStringLiteral("new\nline");
|
||||
QTest::newRow("ampersand") << u"a & b"_s << u"a & b"_s;
|
||||
QTest::newRow("quote") << u""a and b""_s << u"\"a and b\""_s;
|
||||
QTest::newRow("new line") << u"new<br>line"_s << u"new\nline"_s;
|
||||
QTest::newRow("unescape") << u"can't"_s << u"can't"_s;
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichInPlainOut()
|
||||
@@ -296,13 +399,14 @@ void TextHandlerTest::receiveRichInPlainOut()
|
||||
|
||||
void TextHandlerTest::receivePlainTextIn()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org.");
|
||||
const QString testOutputStringRich = QStringLiteral("<plain text in tag bracket><br>Test link <a href=\"https://kde.org\">https://kde.org</a>.");
|
||||
QString testOutputStringPlain = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org.");
|
||||
const QString testInputString = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
||||
const QString testOutputStringRich =
|
||||
u"<plain text in tag bracket><br>Test link <a href=\"https://kde.org\" style=\"text-decoration: none;\">https://kde.org</a>."_s;
|
||||
QString testOutputStringPlain = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
||||
|
||||
// Make sure quotes are maintained in a plain string.
|
||||
const QString testInputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\"");
|
||||
const QString testOutputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\"");
|
||||
const QString testInputString2 = u"last line is \"Time to switch to a new topic.\""_s;
|
||||
const QString testOutputString2 = u"last line is \"Time to switch to a new topic.\""_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -317,12 +421,12 @@ void TextHandlerTest::receivePlainTextIn()
|
||||
|
||||
void TextHandlerTest::receiveStripNewlines()
|
||||
{
|
||||
const QString testInputStringPlain = QStringLiteral("Test\nmany\nnew\nlines.");
|
||||
const QString testInputStringRich = QStringLiteral("Test<br>many<br />new<br>lines.");
|
||||
const QString testOutputString = QStringLiteral("Test many new lines.");
|
||||
const QString testInputStringPlain = u"Test\nmany\nnew\nlines."_s;
|
||||
const QString testInputStringRich = u"Test<br>many<br />new<br>lines."_s;
|
||||
const QString testOutputString = u"Test many new lines."_s;
|
||||
|
||||
const QString testInputStringPlain2 = QStringLiteral("* List\n* Items");
|
||||
const QString testOutputString2 = QStringLiteral("List Items");
|
||||
const QString testInputStringPlain2 = u"* List\n* Items"_s;
|
||||
const QString testOutputString2 = u"List Items"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputStringPlain);
|
||||
@@ -344,8 +448,8 @@ void TextHandlerTest::receiveStripNewlines()
|
||||
*/
|
||||
void TextHandlerTest::receivePlainStripHtml()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>");
|
||||
const QString testOutputString = QStringLiteral("Test Some code <strong>with tags</strong>");
|
||||
const QString testInputString = u"<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"_s;
|
||||
const QString testOutputString = u"Test Some code <strong>with tags</strong>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -355,8 +459,8 @@ void TextHandlerTest::receivePlainStripHtml()
|
||||
|
||||
void TextHandlerTest::receivePlainStripMarkup()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("**bold** `<p>inline code</p>` *italic*");
|
||||
const QString testOutputString = QStringLiteral("bold <p>inline code</p> italic");
|
||||
const QString testInputString = u"**bold** `<p>inline code</p>` *italic*"_s;
|
||||
const QString testOutputString = u"bold <p>inline code</p> italic"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -366,8 +470,8 @@ void TextHandlerTest::receivePlainStripMarkup()
|
||||
|
||||
void TextHandlerTest::receiveRichUserPill()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>");
|
||||
const QString testOutputString = QStringLiteral("<p><b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b></p>");
|
||||
const QString testInputString = u"<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"_s;
|
||||
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\" style=\"text-decoration: none;\">@alice:example.org</a></b>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -377,8 +481,8 @@ void TextHandlerTest::receiveRichUserPill()
|
||||
|
||||
void TextHandlerTest::receiveRichStrikethrough()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p><del>Test</del></p>");
|
||||
const QString testOutputString = QStringLiteral("<p><s>Test</s></p>");
|
||||
const QString testInputString = u"<p><del>Test</del></p>"_s;
|
||||
const QString testOutputString = u"<s>Test</s>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -388,8 +492,8 @@ void TextHandlerTest::receiveRichStrikethrough()
|
||||
|
||||
void TextHandlerTest::receiveRichtextIn()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>");
|
||||
const QString testOutputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>");
|
||||
const QString testInputString = u"<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"_s;
|
||||
const QString testOutputString = u"<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -399,15 +503,10 @@ void TextHandlerTest::receiveRichtextIn()
|
||||
|
||||
void TextHandlerTest::receiveRichMxcUrl()
|
||||
{
|
||||
const QString testInputString = QStringLiteral(
|
||||
"<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73\" "
|
||||
"alt=\"image\">");
|
||||
const QString testOutputString = QStringLiteral(
|
||||
"<img "
|
||||
"src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" "
|
||||
"alt=\"image\"><img "
|
||||
"src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" "
|
||||
"alt=\"image\">");
|
||||
const QString testInputString =
|
||||
u"<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73\" alt=\"image\">"_s;
|
||||
const QString testOutputString =
|
||||
u"<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" alt=\"image\">"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -415,6 +514,34 @@ void TextHandlerTest::receiveRichMxcUrl()
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichPlainUrl_data()
|
||||
{
|
||||
QTest::addColumn<QString>("input");
|
||||
QTest::addColumn<QString>("output");
|
||||
|
||||
// This is an actual link that caused trouble which is why it's so long. Keeping
|
||||
// so we can confirm consistent behaviour for complex urls.
|
||||
QTest::addRow("link 1")
|
||||
<< u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s
|
||||
<< u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\" style=\"text-decoration: none;\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\" style=\"text-decoration: none;\">Link already rich</a>"_s;
|
||||
|
||||
// Another real case. The linkification wasn't handling it when a single link
|
||||
// contains what looks like and email. It was broken into 3 but needs to
|
||||
// be just single link.
|
||||
QTest::addRow("link 2")
|
||||
<< u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s
|
||||
<< u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\" style=\"text-decoration: none;\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
|
||||
|
||||
QTest::addRow("email")
|
||||
<< uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s
|
||||
<< uR"(<a href="mailto:email@example.com" style="text-decoration: none;">email@example.com</a> <a href="mailto:email@example.com" style="text-decoration: none;">Link already rich</a>)"_s;
|
||||
QTest::addRow("mxid")
|
||||
<< u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s
|
||||
<< u"<b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">Link already rich</a></b>"_s;
|
||||
QTest::addRow("mxid with prefix") << u"a @user:kde.org b"_s
|
||||
<< u"a <b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">@user:kde.org</a></b> b"_s;
|
||||
}
|
||||
|
||||
/**
|
||||
* For when your rich input string has a plain text url left in.
|
||||
*
|
||||
@@ -423,67 +550,13 @@ void TextHandlerTest::receiveRichMxcUrl()
|
||||
*/
|
||||
void TextHandlerTest::receiveRichPlainUrl()
|
||||
{
|
||||
// This is an actual link that caused trouble which is why it's so long. Keeping
|
||||
// so we can confirm consistent behaviour for complex urls.
|
||||
const QString testInputStringLink1 = QStringLiteral(
|
||||
"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im "
|
||||
"<a "
|
||||
"href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
|
||||
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>");
|
||||
const QString testOutputStringLink1 = QStringLiteral(
|
||||
"<a "
|
||||
"href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
|
||||
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/"
|
||||
"!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a "
|
||||
"href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
|
||||
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>");
|
||||
|
||||
// Another real case. The linkification wasn't handling it when a single link
|
||||
// contains what looks like and email. It was been broken into 3 but needs to
|
||||
// be just single link.
|
||||
const QString testInputStringLink2 = QStringLiteral("https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/");
|
||||
const QString testOutputStringLink2 = QStringLiteral(
|
||||
"<a "
|
||||
"href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/"
|
||||
"CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>");
|
||||
|
||||
QString testInputStringEmail = QStringLiteral(R"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)");
|
||||
QString testOutputStringEmail =
|
||||
QStringLiteral(R"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)");
|
||||
|
||||
QString testInputStringMxId = QStringLiteral("@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>");
|
||||
QString testOutputStringMxId = QStringLiteral(
|
||||
"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>");
|
||||
QFETCH(QString, input);
|
||||
QFETCH(QString, output);
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputStringLink1);
|
||||
testTextHandler.setData(input);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink1);
|
||||
|
||||
testTextHandler.setData(testInputStringLink2);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink2);
|
||||
|
||||
testTextHandler.setData(testInputStringEmail);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringEmail);
|
||||
|
||||
testTextHandler.setData(testInputStringMxId);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
|
||||
}
|
||||
|
||||
// Test that user pill is add to an emote message.
|
||||
// N.B. The second message in the test timeline is marked as an emote.
|
||||
void TextHandlerTest::receiveRichEmote()
|
||||
{
|
||||
auto event = room->messageEvents().at(1).get();
|
||||
auto author = room->user(event->senderId());
|
||||
const QString testInputString = QStringLiteral("This is an emote.");
|
||||
const QString testOutputString = QStringLiteral("* <a href=\"https://matrix.to/#/@example:example.org\" style=\"color:")
|
||||
+ Utils::getUserColor(author->hueF()).name() + QStringLiteral("\">@example:example.org</a> This is an emote.");
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, event), testOutputString);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), output);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichEdited_data()
|
||||
@@ -491,12 +564,12 @@ void TextHandlerTest::receiveRichEdited_data()
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
|
||||
QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>");
|
||||
QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>")
|
||||
<< QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>");
|
||||
QTest::newRow("blockquote")
|
||||
<< QStringLiteral("<blockquote>Edited</blockquote>")
|
||||
<< QStringLiteral("<blockquote><table><tr><td>\u201CEdited\u201D</td></tr></table></blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
|
||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
|
||||
QTest::newRow("basic") << u"Edited"_s << u"Edited <span style=\"color:%1\">(edited)</span>"_s.arg(theme ? theme->disabledTextColor().name() : u"#000000"_s);
|
||||
QTest::newRow("multiple paragraphs") << u"<p>Edited</p>\n<p>Edited</p>"_s
|
||||
<< u"<p>Edited</p>\n<p>Edited <span style=\"color:%1\">(edited)</span></p>"_s.arg(
|
||||
theme ? theme->disabledTextColor().name() : u"#000000"_s);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichEdited()
|
||||
@@ -507,24 +580,116 @@ void TextHandlerTest::receiveRichEdited()
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(2).get()), testOutputString);
|
||||
const auto event = eventCast<const Quotient::RoomMessageEvent>(room->messageEvents().at(2).get());
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, event, false, event->isReplaced()), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveLineSeparator()
|
||||
{
|
||||
auto text = QStringLiteral("foo\u2028bar");
|
||||
auto text = u"foo\u2028bar"_s;
|
||||
TextHandler textHandler;
|
||||
textHandler.setData(text);
|
||||
QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), QStringLiteral("foo bar"));
|
||||
QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), u"foo bar"_s);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichCodeUrl()
|
||||
{
|
||||
auto input = QStringLiteral("<code>https://kde.org</code>");
|
||||
auto input = u"<code>https://kde.org</code>"_s;
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(input);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), input);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichColor()
|
||||
{
|
||||
const QString testInputString =
|
||||
u"<span data-mx-color=\"#ff00be\">¯</span><span data-mx-color=\"#ff3b1d\">\\</span><span data-mx-color=\"#ffa600\">_</span><span data-mx-color=\"#64d200\">(</span><span data-mx-color=\"#00e261\">ツ</span><span data-mx-color=\"#00e7ff\">)</span><span data-mx-color=\"#00e1ff\">_</span><span data-mx-color=\"#00bdff\">/</span><span data-mx-color=\"#ff60ff\">¯</span>"_s;
|
||||
const QString testOutputString =
|
||||
u"<span style=\"color: #ff00be;\">¯</span><span style=\"color: #ff3b1d;\">\\</span><span style=\"color: #ffa600;\">_</span><span style=\"color: #64d200;\">(</span><span style=\"color: #00e261;\">ツ</span><span style=\"color: #00e7ff;\">)</span><span style=\"color: #00e1ff;\">_</span><span style=\"color: #00bdff;\">/</span><span style=\"color: #ff60ff;\">¯</span>"_s;
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::componentOutput_data()
|
||||
{
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QList<MessageComponent>>("testOutputComponents");
|
||||
|
||||
QTest::newRow("multiple paragraphs") << u"<p>Text</p>\n<p>Text</p>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
||||
QTest::newRow("code") << u"<p>Text</p>\n<pre><code class=\"language-html\">Some code\n</code></pre>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||
MessageComponent{MessageComponentType::Code, u"Some code"_s, QVariantMap{{u"class"_s, u"html"_s}}}};
|
||||
QTest::newRow("quote") << u"<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||
MessageComponent{MessageComponentType::Quote, u"“blockquote”"_s, {}}};
|
||||
QTest::newRow("multiple paragraph quote") << u"<blockquote>\n<p>blockquote</p>\n<p>next paragraph</p>\n</blockquote>"_s
|
||||
<< QList<MessageComponent>{
|
||||
MessageComponent{MessageComponentType::Quote, u"<p>“blockquote</p>\n<p>next paragraph”</p>"_s, {}}};
|
||||
QTest::newRow("no tag first paragraph") << u"Text\n<p>Text</p>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
||||
QTest::newRow("no tag last paragraph") << u"<p>Text</p>\nText"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
||||
QTest::newRow("inline code") << u"<p><code>https://kde.org</code></p>\n<p>Text</p>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"<code>https://kde.org</code>"_s, {}},
|
||||
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
||||
QTest::newRow("inline code single block") << u"<code>https://kde.org</code>"_s
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"<code>https://kde.org</code>"_s, {}}};
|
||||
QTest::newRow("long start tag")
|
||||
<< u"Ah, you mean something like<br/><pre data-md=\"```\"><code class=\"language-qml\"># main.qml\nimport CustomQml\n...\nControls.TextField { id: someField }\nCustomQml {\n someTextProperty: someField.text\n}\n</code></pre>Sure you can, it's still local to the same file where you defined the id"_s
|
||||
<< QList<MessageComponent>{
|
||||
MessageComponent{MessageComponentType::Text, u"Ah, you mean something like<br/>"_s, {}},
|
||||
MessageComponent{
|
||||
MessageComponentType::Code,
|
||||
u"# main.qml\nimport CustomQml\n...\nControls.TextField { id: someField }\nCustomQml {\n someTextProperty: someField.text\n}"_s,
|
||||
QVariantMap{{u"class"_s, u"qml"_s}}},
|
||||
MessageComponent{MessageComponentType::Text, u"Sure you can, it's still local to the same file where you defined the id"_s, {}}};
|
||||
}
|
||||
|
||||
void TextHandlerTest::componentOutput()
|
||||
{
|
||||
QFETCH(QString, testInputString);
|
||||
QFETCH(QList<MessageComponent>, testOutputComponents);
|
||||
|
||||
TextHandler testTextHandler;
|
||||
QCOMPARE(testTextHandler.textComponents(testInputString), testOutputComponents);
|
||||
}
|
||||
|
||||
void TextHandlerTest::updateSpoiler_data()
|
||||
{
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
QTest::addColumn<QString>("testOutputString");
|
||||
QTest::addColumn<bool>("spoilerRevealed");
|
||||
|
||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
QTest::newRow("same length") << u"<span data-mx-spoiler style=\"color: #123456; background: #123456;\">Test<span>"_s
|
||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
|
||||
theme->alternateBackgroundColor().name())
|
||||
<< false;
|
||||
QTest::newRow("different length") << u"<span data-mx-spoiler style=\"color: short; background: looooooooooong;\">Test<span>"_s
|
||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
|
||||
theme->alternateBackgroundColor().name())
|
||||
<< false;
|
||||
QTest::newRow("spoiler revealed")
|
||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(theme->alternateBackgroundColor().name())
|
||||
<< u"<span data-mx-spoiler style=\"color: %1; background: %2;\">Test<span>"_s.arg(theme->textColor().name(), theme->alternateBackgroundColor().name())
|
||||
<< true;
|
||||
}
|
||||
|
||||
void TextHandlerTest::updateSpoiler()
|
||||
{
|
||||
QFETCH(QString, testInputString);
|
||||
QFETCH(QString, testOutputString);
|
||||
QFETCH(bool, spoilerRevealed);
|
||||
|
||||
QCOMPARE(TextHandler::updateSpoilerText(this, testInputString, spoilerRevealed), testOutputString);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TextHandlerTest)
|
||||
#include "texthandlertest.moc"
|
||||
|
||||
@@ -10,20 +10,20 @@
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "enums/delegatetype.h"
|
||||
#include "models/messageeventmodel.h"
|
||||
#include "models/timelinemessagemodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class MessageEventModelTest : public QObject
|
||||
class TimelineMessageModelTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
MessageEventModel *model = nullptr;
|
||||
TimelineMessageModel *model = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
@@ -40,71 +40,70 @@ private Q_SLOTS:
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
void MessageEventModelTest::initTestCase()
|
||||
void TimelineMessageModelTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||
}
|
||||
|
||||
void MessageEventModelTest::init()
|
||||
void TimelineMessageModelTest::init()
|
||||
{
|
||||
QCOMPARE(model, nullptr);
|
||||
model = new MessageEventModel;
|
||||
model = new TimelineMessageModel;
|
||||
}
|
||||
|
||||
// Make sure that basic empty rooms can be switched without crashing.
|
||||
void MessageEventModelTest::switchEmptyRoom()
|
||||
void TimelineMessageModelTest::switchEmptyRoom()
|
||||
{
|
||||
auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org"));
|
||||
auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org"));
|
||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s);
|
||||
|
||||
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
||||
|
||||
QCOMPARE(model->room(), nullptr);
|
||||
model->setRoom(firstRoom);
|
||||
QCOMPARE(spy.count(), 1);
|
||||
QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org"));
|
||||
QCOMPARE(model->room()->id(), u"#firstRoom:kde.org"_s);
|
||||
model->setRoom(secondRoom);
|
||||
QCOMPARE(spy.count(), 2);
|
||||
QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org"));
|
||||
QCOMPARE(model->room()->id(), u"#secondRoom:kde.org"_s);
|
||||
model->setRoom(nullptr);
|
||||
QCOMPARE(spy.count(), 3);
|
||||
QCOMPARE(model->room(), nullptr);
|
||||
}
|
||||
|
||||
// Make sure that rooms with some events can be switched without crashing
|
||||
void MessageEventModelTest::switchSyncedRoom()
|
||||
void TimelineMessageModelTest::switchSyncedRoom()
|
||||
{
|
||||
auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
|
||||
auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
|
||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||
|
||||
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
||||
|
||||
QCOMPARE(model->room(), nullptr);
|
||||
model->setRoom(firstRoom);
|
||||
QCOMPARE(spy.count(), 1);
|
||||
QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org"));
|
||||
QCOMPARE(model->room()->id(), u"#firstRoom:kde.org"_s);
|
||||
model->setRoom(secondRoom);
|
||||
QCOMPARE(spy.count(), 2);
|
||||
QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org"));
|
||||
QCOMPARE(model->room()->id(), u"#secondRoom:kde.org"_s);
|
||||
model->setRoom(nullptr);
|
||||
QCOMPARE(spy.count(), 3);
|
||||
QCOMPARE(model->room(), nullptr);
|
||||
}
|
||||
|
||||
void MessageEventModelTest::simpleTimeline()
|
||||
void TimelineMessageModelTest::simpleTimeline()
|
||||
{
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
|
||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||
|
||||
model->setRoom(room);
|
||||
QCOMPARE(model->rowCount(), 2);
|
||||
|
||||
QCOMPARE(model->data(model->index(0), MessageEventModel::DelegateTypeRole), DelegateType::State);
|
||||
QCOMPARE(model->data(model->index(0)), QStringLiteral("changed their display name to Example Changed"));
|
||||
QCOMPARE(model->data(model->index(0), TimelineMessageModel::DelegateTypeRole), DelegateType::State);
|
||||
QCOMPARE(model->data(model->index(0)), u"changed their display name to Example Changed"_s);
|
||||
|
||||
QCOMPARE(model->data(model->index(1)), QStringLiteral("<b>This is an example<br>text message</b>"));
|
||||
QCOMPARE(model->data(model->index(1), MessageEventModel::DelegateTypeRole), DelegateType::Message);
|
||||
QCOMPARE(model->data(model->index(1), MessageEventModel::PlainText), QStringLiteral("This is an example\ntext message"));
|
||||
QCOMPARE(model->data(model->index(1), MessageEventModel::EventIdRole), QStringLiteral("$153456789:example.org"));
|
||||
QCOMPARE(model->data(model->index(1)), u"<b>This is an example<br>text message</b>"_s);
|
||||
QCOMPARE(model->data(model->index(1), TimelineMessageModel::DelegateTypeRole), DelegateType::Message);
|
||||
QCOMPARE(model->data(model->index(1), TimelineMessageModel::EventIdRole), u"$153456789:example.org"_s);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)");
|
||||
QCOMPARE(model->data(model->index(-1)), QVariant());
|
||||
@@ -112,33 +111,37 @@ void MessageEventModelTest::simpleTimeline()
|
||||
QCOMPARE(model->data(model->index(model->rowCount())), QVariant());
|
||||
}
|
||||
|
||||
// Sync some events into the MessageEventModel's current room and don't crash.
|
||||
void MessageEventModelTest::syncNewEvents()
|
||||
// Sync some events into the TimelineMessageModel's current room and don't crash.
|
||||
void TimelineMessageModelTest::syncNewEvents()
|
||||
{
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
|
||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s);
|
||||
QSignalSpy spy(room, SIGNAL(aboutToAddNewMessages(Quotient::RoomEventsRange)));
|
||||
|
||||
model->setRoom(room);
|
||||
QCOMPARE(model->rowCount(), 0);
|
||||
|
||||
room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json"));
|
||||
room->syncNewEvents(u"test-messageventmodel-sync.json"_s);
|
||||
|
||||
QCOMPARE(model->rowCount(), 2);
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
// Check the adding of pending events to the room doesn't cause any issues in the model.
|
||||
void MessageEventModelTest::pendingEvent()
|
||||
void TimelineMessageModelTest::pendingEvent()
|
||||
{
|
||||
QSignalSpy spyInsert(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
|
||||
QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
|
||||
QSignalSpy spyChanged(model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex, const QList<int> &)));
|
||||
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
|
||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s);
|
||||
model->setRoom(room);
|
||||
QCOMPARE(model->rowCount(), 0);
|
||||
|
||||
auto txnId = room->postPlainText("New plain message"_ls);
|
||||
#if Quotient_VERSION_MINOR > 9
|
||||
auto txnId = room->postText("New plain message"_L1);
|
||||
#else
|
||||
auto txnId = room->postPlainText("New plain message"_L1);
|
||||
#endif
|
||||
QCOMPARE(model->rowCount(), 1);
|
||||
QCOMPARE(spyInsert.count(), 1);
|
||||
|
||||
@@ -146,26 +149,30 @@ void MessageEventModelTest::pendingEvent()
|
||||
QCOMPARE(model->rowCount(), 0);
|
||||
QCOMPARE(spyRemove.count(), 1);
|
||||
|
||||
txnId = room->postPlainText("New plain message"_ls);
|
||||
#if Quotient_VERSION_MINOR > 9
|
||||
txnId = room->postText("New plain message"_L1);
|
||||
#else
|
||||
txnId = room->postPlainText("New plain message"_L1);
|
||||
#endif
|
||||
QCOMPARE(model->rowCount(), 1);
|
||||
QCOMPARE(spyInsert.count(), 2);
|
||||
|
||||
// We need to manually set the transaction ID of the new message as it will be
|
||||
// different every time.
|
||||
QFile testSyncFile;
|
||||
testSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-pending-sync.json"));
|
||||
testSyncFile.open(QIODevice::ReadOnly);
|
||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + u"test-pending-sync.json"_s);
|
||||
QVERIFY(testSyncFile.open(QIODevice::ReadOnly));
|
||||
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
||||
auto root = testSyncJson.object();
|
||||
auto timeline = root["timeline"_ls].toObject();
|
||||
auto events = timeline["events"_ls].toArray();
|
||||
auto timeline = root["timeline"_L1].toObject();
|
||||
auto events = timeline["events"_L1].toArray();
|
||||
auto firstEvent = events[0].toObject();
|
||||
firstEvent.insert(QLatin1String("unsigned"), QJsonObject{{QLatin1String("transaction_id"), txnId}});
|
||||
firstEvent.insert("unsigned"_L1, QJsonObject{{"transaction_id"_L1, txnId}});
|
||||
events[0] = firstEvent;
|
||||
timeline.insert("events"_ls, events);
|
||||
root.insert("timeline"_ls, timeline);
|
||||
timeline.insert("events"_L1, events);
|
||||
root.insert("timeline"_L1, timeline);
|
||||
testSyncJson.setObject(root);
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testSyncJson.object());
|
||||
SyncRoomData roomData(u"@bob:kde.org"_s, JoinState::Join, testSyncJson.object());
|
||||
room->update(std::move(roomData));
|
||||
|
||||
QCOMPARE(model->rowCount(), 1);
|
||||
@@ -175,7 +182,7 @@ void MessageEventModelTest::pendingEvent()
|
||||
auto isPendingChanged = false;
|
||||
for (auto signal : spyChanged) {
|
||||
auto roles = signal.at(2).toList();
|
||||
if (roles.contains(MessageEventModel::IsPendingRole)) {
|
||||
if (roles.contains(TimelineMessageModel::IsPendingRole)) {
|
||||
isPendingChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -183,33 +190,33 @@ void MessageEventModelTest::pendingEvent()
|
||||
}
|
||||
|
||||
// Make sure that the signals are disconnecting correctly when a room is switched.
|
||||
void MessageEventModelTest::disconnect()
|
||||
void TimelineMessageModelTest::disconnect()
|
||||
{
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
|
||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s);
|
||||
model->setRoom(room);
|
||||
|
||||
QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
|
||||
|
||||
model->setRoom(nullptr);
|
||||
room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json"));
|
||||
room->syncNewEvents(u"test-messageventmodel-sync.json"_s);
|
||||
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
void MessageEventModelTest::idToRow()
|
||||
void TimelineMessageModelTest::idToRow()
|
||||
{
|
||||
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
|
||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
||||
model->setRoom(room);
|
||||
|
||||
QCOMPARE(model->eventIdToRow(QStringLiteral("$153456789:example.org")), 0);
|
||||
QCOMPARE(model->indexforEventId(u"$153456789:example.org"_s).row(), 0);
|
||||
}
|
||||
|
||||
void MessageEventModelTest::cleanup()
|
||||
void TimelineMessageModelTest::cleanup()
|
||||
{
|
||||
delete model;
|
||||
model = nullptr;
|
||||
QCOMPARE(model, nullptr);
|
||||
}
|
||||
|
||||
QTEST_MAIN(MessageEventModelTest)
|
||||
#include "messageeventmodeltest.moc"
|
||||
QTEST_MAIN(TimelineMessageModelTest)
|
||||
#include "timelinemessagemodeltest.moc"
|
||||
@@ -17,7 +17,6 @@ class WindowControllerTest : public QObject
|
||||
|
||||
private Q_SLOTS:
|
||||
void nullWindow();
|
||||
void geometry();
|
||||
void showAndRaise();
|
||||
void toggle();
|
||||
|
||||
@@ -30,32 +29,10 @@ void WindowControllerTest::nullWindow()
|
||||
auto &instance = WindowController::instance();
|
||||
QCOMPARE(instance.window(), nullptr);
|
||||
|
||||
instance.restoreGeometry();
|
||||
instance.saveGeometry();
|
||||
instance.showAndRaiseWindow({});
|
||||
instance.toggleWindow();
|
||||
}
|
||||
|
||||
void WindowControllerTest::geometry()
|
||||
{
|
||||
auto &instance = WindowController::instance();
|
||||
|
||||
QWindow window;
|
||||
window.setGeometry(0, 0, 200, 200);
|
||||
instance.setWindow(&window);
|
||||
QCOMPARE(instance.window(), &window);
|
||||
|
||||
instance.saveGeometry();
|
||||
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||
KConfigGroup windowGroup = stateConfig->group(QStringLiteral("Window"));
|
||||
QCOMPARE(KWindowConfig::hasSavedWindowSize(windowGroup), true);
|
||||
|
||||
window.setGeometry(0, 0, 400, 400);
|
||||
QCOMPARE(window.geometry(), QRect(0, 0, 400, 400));
|
||||
instance.restoreGeometry();
|
||||
QCOMPARE(window.geometry(), QRect(0, 0, 200, 200));
|
||||
}
|
||||
|
||||
void WindowControllerTest::showAndRaise()
|
||||
{
|
||||
auto &instance = WindowController::instance();
|
||||
|
||||
36
memorytests/CMakeLists.txt
Normal file
36
memorytests/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
qt_add_executable(timeline_memtest
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(timeline_memtest PRIVATE neochatplugin Timelineplugin)
|
||||
target_link_libraries(timeline_memtest PUBLIC
|
||||
Qt::Core
|
||||
Qt::Quick
|
||||
Qt::Qml
|
||||
Qt::Gui
|
||||
Qt::QuickControls2
|
||||
Qt::Widgets
|
||||
KF6::I18nQml
|
||||
QuotientQt6
|
||||
LibNeoChat
|
||||
Timeline
|
||||
)
|
||||
|
||||
ecm_add_qml_module(timeline_memtest URI org.kde.neochat.timeline_memtest GENERATE_PLUGIN_SOURCE
|
||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/timeline_memtest
|
||||
QML_FILES
|
||||
Main.qml
|
||||
SOURCES
|
||||
memtesttimelinemodel.cpp
|
||||
memtesttimelinemodel.h
|
||||
DEPENDENCIES
|
||||
QtCore
|
||||
QtQuick
|
||||
IMPORTS
|
||||
org.kde.neochat.timeline
|
||||
)
|
||||
34
memorytests/Main.qml
Normal file
34
memorytests/Main.qml
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
QQC2.ApplicationWindow {
|
||||
id: root
|
||||
|
||||
title: "Timeline Memory Test"
|
||||
|
||||
minimumWidth: Kirigami.Units.gridUnit * 30
|
||||
minimumHeight: Kirigami.Units.gridUnit * 30
|
||||
|
||||
visible: true
|
||||
|
||||
QQC2.ScrollView {
|
||||
width: root.width
|
||||
height: root.height
|
||||
|
||||
contentItem: ListView {
|
||||
cacheBuffer: 1000000
|
||||
model: messageFilterModel
|
||||
|
||||
delegate: EventDelegate {
|
||||
room: memTestTimelineModel.room
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
memorytests/main.cpp
Normal file
34
memorytests/main.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <KLocalizedQmlContext>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "memtesttimelinemodel.h"
|
||||
#include "models/messagefiltermodel.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
KLocalization::setupLocalizedContext(&engine);
|
||||
|
||||
MemTestTimelineModel *memTestTimelineModel = new MemTestTimelineModel;
|
||||
MessageFilterModel *messageFilterModel = new MessageFilterModel(nullptr, memTestTimelineModel);
|
||||
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
|
||||
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
|
||||
|
||||
engine.loadFromModule("org.kde.neochat.timeline_memtest", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
379
memorytests/memtest-sync.json
Normal file
379
memorytests/memtest-sync.json
Normal file
@@ -0,0 +1,379 @@
|
||||
{
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"$1000000000000:example.org": {
|
||||
"m.read": {
|
||||
"@alice:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000000:example.org": {
|
||||
"m.read": {
|
||||
"@bob:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@tim:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@example:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@jeff:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@tina:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@sally:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1000000000003:example.org": {
|
||||
"m.read": {
|
||||
"@fred:example.org": {
|
||||
"ts": 1000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Example",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582555PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "alice:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Bob",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "bob:example.org",
|
||||
"state_key": "@bob:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Tim",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "tim:example.org",
|
||||
"state_key": "@tim:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Jeff",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "jeff:example.org",
|
||||
"state_key": "@jeff:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Tina",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "tina:example.org",
|
||||
"state_key": "@tina:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Sally",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "sally:example.org",
|
||||
"state_key": "@sally:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Fred",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "fred:example.org",
|
||||
"state_key": "@fred:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an example text message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "This is an example<br>text message",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": 0,
|
||||
"origin_server_ts": 1000000000000,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "This is a highlight @bob:example.org",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": 1,
|
||||
"origin_server_ts": 1000000000001,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1233
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"event_id": 1,
|
||||
"key": "👍",
|
||||
"rel_type": "m.annotation"
|
||||
}
|
||||
},
|
||||
"origin_server_ts": 1000000000002,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@alice:example.org",
|
||||
"type": "m.reaction",
|
||||
"unsigned": {
|
||||
"age": 390159120
|
||||
},
|
||||
"event_id": 2,
|
||||
"age": 390159120
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "reply",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "reply",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": 0
|
||||
}
|
||||
},
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"origin_server_ts": 1000000000003,
|
||||
"sender": "@alice:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 98
|
||||
},
|
||||
"event_id": 3,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"age": 96845207,
|
||||
"content": {
|
||||
"body": "Lat: 51.7035, Lon: -1.14394",
|
||||
"geo_uri": "geo:51.7035,-1.14394",
|
||||
"msgtype": "m.location",
|
||||
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
|
||||
"org.matrix.msc3488.asset": {
|
||||
"type": "m.pin"
|
||||
},
|
||||
"org.matrix.msc3488.location": {
|
||||
"uri": "geo:51.7035,-1.14394"
|
||||
}
|
||||
},
|
||||
"event_id": 4,
|
||||
"origin_server_ts": 1000000000004,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 96845207
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");\n\n return app.exec();\n}\n</code></pre>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": 5,
|
||||
"origin_server_ts": 1000000000005,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@bob:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1233
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": 6,
|
||||
"origin_server_ts": 1000000000006,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": 7,
|
||||
"origin_server_ts": 1000000000007,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
}
|
||||
36
memorytests/memtesttimelinemodel.cpp
Normal file
36
memorytests/memtesttimelinemodel.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "memtesttimelinemodel.h"
|
||||
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
MemTestTimelineModel::MemTestTimelineModel(QObject *parent)
|
||||
: MessageModel(parent)
|
||||
{
|
||||
beginResetModel();
|
||||
m_connection = Connection::makeMockConnection(u"@bob:example.org"_s);
|
||||
m_room = new MemTestRoom(m_connection, u"#memtestroom:example.org"_s, u"memtest-sync.json"_s);
|
||||
|
||||
for (const auto &eventIt : m_room->messageEvents()) {
|
||||
Q_EMIT newEventAdded(eventIt.event());
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<const RoomEvent>> MemTestTimelineModel::getEventForIndex(QModelIndex index) const
|
||||
{
|
||||
return *m_room->messageEvents().at(index.row()).event();
|
||||
}
|
||||
|
||||
int MemTestTimelineModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return m_room->messageEvents().size();
|
||||
}
|
||||
|
||||
#include "moc_memtesttimelinemodel.cpp"
|
||||
121
memorytests/memtesttimelinemodel.h
Normal file
121
memorytests/memtesttimelinemodel.h
Normal file
@@ -0,0 +1,121 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <Quotient/events/roomevent.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "models/messagemodel.h"
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class Connection;
|
||||
}
|
||||
|
||||
class NeoChatRoom;
|
||||
|
||||
class MemTestRoom : public NeoChatRoom
|
||||
{
|
||||
public:
|
||||
MemTestRoom(Quotient::Connection *connection, const QString &roomName, const QString &syncFileName = {})
|
||||
: NeoChatRoom(connection, roomName, Quotient::JoinState::Join)
|
||||
{
|
||||
syncNewEvents(syncFileName);
|
||||
}
|
||||
|
||||
void update(Quotient::SyncRoomData &&data, bool fromCache = false)
|
||||
{
|
||||
Room::updateData(std::move(data), fromCache);
|
||||
}
|
||||
|
||||
void syncNewEvents(const QString &syncFileName)
|
||||
{
|
||||
if (!syncFileName.isEmpty()) {
|
||||
QFile testSyncFile;
|
||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
||||
auto ok = testSyncFile.open(QIODevice::ReadOnly);
|
||||
if (!ok) {
|
||||
qWarning() << "Failed to open" << testSyncFile.fileName() << testSyncFile.errorString();
|
||||
}
|
||||
|
||||
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()).object();
|
||||
auto timelineJson = testSyncJson["timeline"_L1].toObject();
|
||||
timelineJson["events"_L1] = multiplyEvents(timelineJson["events"_L1].toArray(), 100);
|
||||
testSyncJson["timeline"_L1] = timelineJson;
|
||||
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson);
|
||||
update(std::move(roomData));
|
||||
}
|
||||
}
|
||||
|
||||
QJsonArray multiplyEvents(QJsonArray events, int factor)
|
||||
{
|
||||
QJsonArray newArray;
|
||||
int eventNum = 0;
|
||||
int ts = 0;
|
||||
|
||||
for (int i = 0; i < factor; ++i) {
|
||||
for (const auto &event : events) {
|
||||
auto eventObject = event.toObject();
|
||||
auto contentJson = eventObject["content"_L1].toObject();
|
||||
if (contentJson.contains("m.relates_to"_L1)) {
|
||||
auto relatesToJson = contentJson["m.relates_to"_L1].toObject();
|
||||
if (relatesToJson.contains("m.in_reply_to"_L1)) {
|
||||
auto replyJson = relatesToJson["m.in_reply_to"_L1].toObject();
|
||||
const auto currentId = eventObject["event_id"_L1].toInt();
|
||||
const auto currentReplyId = replyJson["event_id"_L1].toInt();
|
||||
replyJson["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum - (currentId - currentReplyId)));
|
||||
relatesToJson["m.in_reply_to"_L1] = replyJson;
|
||||
} else if (relatesToJson.contains("event_id"_L1)) {
|
||||
const auto currentId = eventObject["event_id"_L1].toInt();
|
||||
const auto currentRelationId = relatesToJson["event_id"_L1].toInt();
|
||||
relatesToJson["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum - (currentId - currentRelationId)));
|
||||
}
|
||||
contentJson["m.relates_to"_L1] = relatesToJson;
|
||||
eventObject["content"_L1] = contentJson;
|
||||
}
|
||||
eventObject["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum));
|
||||
eventObject["origin_server_ts"_L1] = ts;
|
||||
auto unsignedJson = eventObject["unsigned"_L1].toObject();
|
||||
unsignedJson["age"_L1] = ts;
|
||||
eventObject["unsigned"_L1] = unsignedJson;
|
||||
newArray.append(eventObject);
|
||||
++eventNum;
|
||||
++ts;
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class MemTestTimelineModel
|
||||
*
|
||||
* This is a special version of the MessageModel design to load an unchanging set
|
||||
* of events from a json file so that timeline memory optimisations can be measured.
|
||||
*/
|
||||
class MemTestTimelineModel : public MessageModel
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
explicit MemTestTimelineModel(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Number of rows in the model.
|
||||
*
|
||||
* @sa QAbstractItemModel::rowCount
|
||||
*/
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
private:
|
||||
QPointer<Quotient::Connection> m_connection;
|
||||
|
||||
std::vector<Quotient::RoomEventPtr> m_events;
|
||||
|
||||
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const override;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,8 @@ Name[eu]=NeoChat
|
||||
Name[fi]=NeoChat
|
||||
Name[fr]=NeoChat
|
||||
Name[gl]=NeoChat
|
||||
Name[he]=NeoChat
|
||||
Name[hi]=नियोचैट
|
||||
Name[hu]=NeoChat
|
||||
Name[ia]=Neochat
|
||||
Name[id]=NeoChat
|
||||
@@ -26,6 +28,7 @@ Name[it]=NeoChat
|
||||
Name[ka]=NeoChat
|
||||
Name[ko]=NeoChat
|
||||
Name[lt]=NeoChat
|
||||
Name[lv]=NeoChat
|
||||
Name[nl]=NeoChat
|
||||
Name[nn]=NeoChat
|
||||
Name[pa]=ਨਿਓ-ਚੈਟ
|
||||
@@ -34,13 +37,13 @@ Name[pt]=NeoChat
|
||||
Name[pt_BR]=NeoChat
|
||||
Name[ro]=NeoChat
|
||||
Name[ru]=NeoChat
|
||||
Name[sa]=नवचैट्
|
||||
Name[sk]=NeoChat
|
||||
Name[sl]=NeoChat
|
||||
Name[sv]=NeoChat
|
||||
Name[ta]=நியோச்சாட்
|
||||
Name[tr]=NeoChat
|
||||
Name[uk]=NeoChat
|
||||
Name[x-test]=xxNeoChatxx
|
||||
Name[zh_CN]=NeoChat
|
||||
Name[zh_TW]=NeoChat
|
||||
GenericName=Matrix Client
|
||||
@@ -58,6 +61,8 @@ GenericName[eu]=Matrix bezeroa
|
||||
GenericName[fi]=Matrix-asiakas
|
||||
GenericName[fr]=Client « Matrix »
|
||||
GenericName[gl]=Cliente de Matrix
|
||||
GenericName[he]=לקוח Matrix
|
||||
GenericName[hi]=मैट्रिक्स क्लाइंट
|
||||
GenericName[hu]=Matrix kliens
|
||||
GenericName[ia]=Cliente de Matrice
|
||||
GenericName[id]=Klien Matrix
|
||||
@@ -65,7 +70,8 @@ GenericName[ie]=Cliente de Matrix
|
||||
GenericName[it]=Client Matrix
|
||||
GenericName[ka]=Matrix -ის კლიენტი
|
||||
GenericName[ko]=Matrix 클라이언트
|
||||
GenericName[lt]=Matrix kliento programą
|
||||
GenericName[lt]=Matrix kliento programa
|
||||
GenericName[lv]=„Matrix“ klients
|
||||
GenericName[nl]=Matrix-client
|
||||
GenericName[nn]=Matrix-klient
|
||||
GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ
|
||||
@@ -74,54 +80,48 @@ GenericName[pt]=Cliente de Matrix
|
||||
GenericName[pt_BR]=Cliente Matrix
|
||||
GenericName[ro]=Client Matrix
|
||||
GenericName[ru]=Клиент Matrix
|
||||
GenericName[sa]=मैट्रिक्स क्लाइंट
|
||||
GenericName[sk]=Matrix Client
|
||||
GenericName[sl]=Odjemalec Matrix
|
||||
GenericName[sv]=Matrix-klient
|
||||
GenericName[ta]=Matrix வாங்கி
|
||||
GenericName[tr]=Matrix İstemcisi
|
||||
GenericName[uk]=Клієнт Matrix
|
||||
GenericName[x-test]=xxMatrix Clientxx
|
||||
GenericName[zh_CN]=Matrix 客户端
|
||||
GenericName[zh_TW]=Matrix 用戶端
|
||||
Comment=Client for the Matrix protocol
|
||||
Comment[ar]=عميل لميفاق ماتركس
|
||||
Comment[az]=Matrix protokolu üçün müştəri
|
||||
Comment[ca]=Client per al protocol Matrix
|
||||
Comment[ca@valencia]=Client per al protocol Matrix
|
||||
Comment[de]=Programm für das Matrix-Protokoll
|
||||
Comment[el]=Πελάτης για το πρωτόκολλο Matrix
|
||||
Comment[en_GB]=Client for the Matrix protocol
|
||||
Comment[eo]=Kliento por la Matrix-protokolo
|
||||
Comment[es]=Cliente para el protocolo Matrix
|
||||
Comment[eu]=Matrix protokolorako bezeroa
|
||||
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||
Comment[fr]=Client pour le protocole « Matrix »
|
||||
Comment[gl]=Cliente para o protocolo Matrix.
|
||||
Comment[hu]=Kliens a Matrix protokollhoz
|
||||
Comment[ia]=Cliente per le protocollo de Matrix
|
||||
Comment[id]=Klien untuk protokol Matrix
|
||||
Comment[ie]=Un cliente del protocol Matrix
|
||||
Comment[it]=Client per il protocollo Matrix
|
||||
Comment[ka]=კლიენტი Matrix-ის პროტოკოლისთვის
|
||||
Comment[ko]=Matrix 프로토콜용 클라이언트
|
||||
Comment[lt]=Matrix protokolo kliento programa
|
||||
Comment[nl]=Client voor het Matrix-protocol
|
||||
Comment[nn]=Klient for Matrix-protokollen
|
||||
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
|
||||
Comment[pl]=Program obsługi protokołu Matriksa
|
||||
Comment[pt]=Cliente para o protocolo Matrix
|
||||
Comment[pt_BR]=Cliente para o protocolo Matrix
|
||||
Comment[ro]=Client pentru protocolul Matrix
|
||||
Comment[ru]=Клиент для протокола Matrix
|
||||
Comment[sk]=Klient protokolu Matrix
|
||||
Comment[sl]=Odjemalec za protokol Matrix
|
||||
Comment[sv]=Klient för protokollet Matrix
|
||||
Comment[ta]=Matrix நெறிமுறைக்கான வாங்கி
|
||||
Comment[tr]=Matrix protokolü için istemci
|
||||
Comment[uk]=Клієнт протоколу Matrix
|
||||
Comment[x-test]=xxClient for the Matrix protocolxx
|
||||
Comment[zh_CN]=为 Matrix 协议打造的客户端
|
||||
Comment[zh_TW]=Matrix 通訊協定的用戶端
|
||||
Comment=Chat on Matrix
|
||||
Comment[ar]=دردش على ماتركس
|
||||
Comment[ca]=Xat a Matrix
|
||||
Comment[ca@valencia]=Xat a Matrix
|
||||
Comment[de]=Über Matrix unterhalten
|
||||
Comment[en_GB]=Chat on Matrix
|
||||
Comment[eo]=Babilo en Matrix
|
||||
Comment[es]=Chat en Matrix
|
||||
Comment[eu]=Berriketa Matrix-en
|
||||
Comment[fi]=Keskustele Matrixissä
|
||||
Comment[fr]=Clavarder sur Matrix
|
||||
Comment[gl]=Charle en Matrix
|
||||
Comment[he]=התכתבות דרך Matrix
|
||||
Comment[hi]=मैट्रिक्स पर चैट करें
|
||||
Comment[hu]=Csevegés Matrixon
|
||||
Comment[ia]=Conversation en ditecto sur Matrix
|
||||
Comment[it]= su Matrix
|
||||
Comment[ka]=ჩატი Matrix-ზე
|
||||
Comment[ko]=Matrix에서 대화하기
|
||||
Comment[lv]=Tērzējiet „Matrix“ tīklā
|
||||
Comment[nl]=Chat op Matrix
|
||||
Comment[pl]=Rozmawiaj na Matriksie
|
||||
Comment[pt_BR]=Bate papo na Matrix
|
||||
Comment[ro]=Discutați pe Matrix
|
||||
Comment[ru]=Общение в Matrix
|
||||
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु
|
||||
Comment[sl]=Klepet na Matrixu
|
||||
Comment[sv]=Chatta på Matrix
|
||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
||||
Comment[tr]=Matrix üzerinde sohbet edin
|
||||
Comment[uk]=Спілкування у Matrix
|
||||
Comment[zh_CN]=在 Matrix 上聊天
|
||||
Comment[zh_TW]=在 Matrix 上聊天
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
Exec=neochat %u
|
||||
Terminal=false
|
||||
|
||||
11043
po/ar/neochat.po
11043
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
10003
po/ast/neochat.po
10003
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
12080
po/az/neochat.po
12080
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:exemple.org o matrix:r/root:exemple.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:example.org o matrix:r/root:example.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
10376
po/ca/neochat.po
10376
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
10283
po/cs/neochat.po
10283
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
10829
po/da/neochat.po
10829
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
11373
po/de/neochat.po
11373
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
11906
po/el/neochat.po
11906
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
11564
po/en_GB/neochat.po
11564
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
9874
po/eo/neochat.po
9874
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
10791
po/es/neochat.po
10791
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
10008
po/eu/neochat.po
10008
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
10061
po/fi/neochat.po
10061
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
11113
po/fr/neochat.po
11113
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
7002
po/ga/neochat.po
Normal file
7002
po/ga/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
7803
po/gl/neochat.po
Normal file
7803
po/gl/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
7297
po/he/neochat.po
Normal file
7297
po/he/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
7737
po/hi/neochat.po
Normal file
7737
po/hi/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
11371
po/hu/neochat.po
11371
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
11021
po/ia/neochat.po
11021
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
11961
po/id/neochat.po
11961
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
11562
po/ie/neochat.po
11562
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
10824
po/it/neochat.po
10824
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
9982
po/ja/neochat.po
9982
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
9821
po/ka/neochat.po
9821
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
9613
po/ko/neochat.po
9613
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
10454
po/lt/neochat.po
10454
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
7763
po/lv/neochat.po
Normal file
7763
po/lv/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
11033
po/nl/neochat.po
11033
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
10548
po/nn/neochat.po
10548
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
11899
po/pa/neochat.po
11899
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
11073
po/pl/neochat.po
11073
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
11925
po/pt/neochat.po
11925
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
122
po/pt_BR/docs/neochat/man-neochat.1.docbook
Normal file
122
po/pt_BR/docs/neochat/man-neochat.1.docbook
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Brazilian-Portuguese "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>Manual do Usuário do NeoChat</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>NeoChat man page.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>01/11/2022</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
>NeoChat</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>
|
||||
<command
|
||||
>neochat</command>
|
||||
</refentrytitle>
|
||||
<manvolnum
|
||||
>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname
|
||||
>neochat</refname>
|
||||
<refpurpose
|
||||
>Cliente para interação com o protocolo de mensagens Matrix.</refpurpose>
|
||||
</refnamediv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis
|
||||
><command
|
||||
>neochat</command
|
||||
> <arg choice="opt"
|
||||
><replaceable
|
||||
>URI</replaceable
|
||||
></arg
|
||||
> </cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1 id="description">
|
||||
<title
|
||||
>Descrição</title>
|
||||
<para
|
||||
>O <command
|
||||
>neochat</command
|
||||
> é um aplicativo de bate-papo para o protocolo Matrix. Ele funciona tanto em computadores quanto em dispositivos móveis. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Opções</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>O URI da matriz para um usuário ou uma sala. Por exemplo, matrix:u/usuário:exemplo.org e matrix:r/root:exemplo.org. Isso fará com que o NeoChat tente abrir a sala ou conversa especificada. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Relatar bugs</title>
|
||||
<para
|
||||
>Você pode reportar erros e solicitar novas funcionalidades em <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
||||
></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Veja também</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Lista de perguntas frequentes sobre o Matrix <ulink url="https://matrix.org/faq/"
|
||||
>https://matrix.org/faq/</ulink
|
||||
> </member>
|
||||
<member
|
||||
>kf5options(7)</member>
|
||||
<member
|
||||
>qt5options(7)</member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="copyright"
|
||||
><title
|
||||
>Direitos autorais</title>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Licença: GNU General Public Versão 3 ou posterior <ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
11412
po/pt_BR/neochat.po
11412
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
7049
po/ro/neochat.po
Normal file
7049
po/ro/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
122
po/ru/docs/neochat/man-neochat.1.docbook
Normal file
122
po/ru/docs/neochat/man-neochat.1.docbook
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Russian "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>Руководство пользователя NeoChat</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>man-страница NeoChat.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>2022-11-01</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
>NeoChat</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>
|
||||
<command
|
||||
>neochat</command>
|
||||
</refentrytitle>
|
||||
<manvolnum
|
||||
>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname
|
||||
>neochat</refname>
|
||||
<refpurpose
|
||||
>Клиент для взаимодействия с протоколом обмена сообщениями Matrix</refpurpose>
|
||||
</refnamediv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis
|
||||
><command
|
||||
>neochat</command
|
||||
> <arg choice="opt"
|
||||
><replaceable
|
||||
>URI</replaceable
|
||||
></arg
|
||||
> </cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1 id="description">
|
||||
<title
|
||||
>Описание</title>
|
||||
<para
|
||||
><command
|
||||
>neochat</command
|
||||
> — приложение для настольных и мобильных устройств, позволяющее общаться в чатах с помощью протокола Matrix. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Параметры</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>URI-адрес пользователя или комнаты в Matrix, например: matrix:u/user:example.org и matrix:r/root:example.org. NeoChat попытается открыть указанную комнату или беседу. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Отчёты об ошибках</title>
|
||||
<para
|
||||
>Сообщать об ошибках и отправлять предложения по улучшению можно по адресу <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
||||
></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Смотрите также</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Список наиболее часто задаваемых вопросов о Matrix <ulink url="https://matrix.org/faq/"
|
||||
>https://matrix.org/faq/</ulink
|
||||
> </member>
|
||||
<member
|
||||
>kf5options(7)</member>
|
||||
<member
|
||||
>qt5options(7)</member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="copyright"
|
||||
><title
|
||||
>Авторские права</title>
|
||||
<para
|
||||
>Авторские права © Tobias Fella, 2020–2022 </para>
|
||||
<para
|
||||
>Авторские права © Carl Schwan, 2020–2022 </para>
|
||||
<para
|
||||
>Лицензия: стандартная общественная лицензия GNU версии 3 или любой более поздней версии <<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user