1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "gtest/gtest.h"
7 
8 #include "nsITransactionManager.h"
9 #include "nsComponentManagerUtils.h"
10 #include "mozilla/Likely.h"
11 
12 static int32_t sConstructorCount = 0;
13 static int32_t sDoCount = 0;
14 static int32_t *sDoOrderArr = 0;
15 static int32_t sUndoCount = 0;
16 static int32_t *sUndoOrderArr = 0;
17 static int32_t sRedoCount = 0;
18 static int32_t *sRedoOrderArr = 0;
19 
20 int32_t sSimpleTestDoOrderArr[] = {
21     1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,
22     16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,
23     31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,
24     46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,
25     61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
26     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
27     91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105,
28     106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
29     121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131};
30 
31 int32_t sSimpleTestUndoOrderArr[] = {41,  40,  39,  38,  62,  39,  38,  37,
32                                      69,  71,  70,  111, 110, 109, 108, 107,
33                                      106, 105, 104, 103, 102, 131, 130, 129,
34                                      128, 127, 126, 125, 124, 123, 122};
35 
36 static int32_t sSimpleTestRedoOrderArr[] = {38, 39, 70};
37 
38 int32_t sAggregateTestDoOrderArr[] = {
39     1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,
40     16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,
41     31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,
42     46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,
43     61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
44     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
45     91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105,
46     106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
47     121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
48     136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
49     151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
50     166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
51     181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
52     196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
53     211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
54     226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
55     241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
56     256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
57     271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285,
58     286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300,
59     301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315,
60     316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330,
61     331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345,
62     346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360,
63     361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375,
64     376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390,
65     391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405,
66     406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
67     421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435,
68     436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450,
69     451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465,
70     466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480,
71     481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
72     496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510,
73     511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525,
74     526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540,
75     541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555,
76     556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570,
77     571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585,
78     586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600,
79     601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615,
80     616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630,
81     631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645,
82     646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660,
83     661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675,
84     676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690,
85     691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705,
86     706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720,
87     721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735,
88     736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750,
89     751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765,
90     766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780,
91     781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795,
92     796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810,
93     811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825,
94     826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840,
95     841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855,
96     856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870,
97     871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885,
98     886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900,
99     901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913};
100 
101 int32_t sAggregateTestUndoOrderArr[] = {
102     287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273,
103     272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 434, 433,
104     432, 431, 430, 429, 428, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264,
105     263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 479, 478, 477, 476,
106     475, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 480,
107     485, 484, 483, 482, 481, 480, 773, 772, 771, 770, 769, 768, 767, 766, 765,
108     764, 763, 762, 761, 760, 759, 758, 757, 756, 755, 754, 753, 752, 751, 750,
109     749, 748, 747, 746, 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, 735,
110     734, 733, 732, 731, 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, 720,
111     719, 718, 717, 716, 715, 714, 713, 712, 711, 710, 709, 708, 707, 706, 705,
112     704, 913, 912, 911, 910, 909, 908, 907, 906, 905, 904, 903, 902, 901, 900,
113     899, 898, 897, 896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885,
114     884, 883, 882, 881, 880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870,
115     869, 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855,
116     854, 853, 852, 851, 850, 849, 848, 847, 846, 845, 844};
117 
118 int32_t sAggregateTestRedoOrderArr[] = {
119     260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
120     273, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486};
121 
122 int32_t sSimpleBatchTestDoOrderArr[] = {
123     1,  2,  3,  4,   5,   6,   7,   8,   9,   10,  11, 12, 13, 14, 15, 16,
124     17, 18, 19, 20,  21,  22,  23,  24,  25,  26,  27, 28, 29, 30, 31, 32,
125     33, 34, 35, 36,  37,  38,  39,  40,  41,  42,  43, 44, 45, 46, 47, 48,
126     49, 50, 51, 52,  53,  54,  55,  56,  57,  58,  59, 60, 61, 62, 63, 64,
127     65, 66, 67, 68,  69,  70,  71,  72,  73,  74,  75, 76, 77, 78, 79, 80,
128     81, 82, 83, 84,  85,  86,  87,  88,  89,  90,  91, 92, 93, 94, 95, 96,
129     97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107};
130 
131 int32_t sSimpleBatchTestUndoOrderArr[] = {
132     43, 42, 41, 20, 19,  18,  17,  16,  15,  14,  13,  12,  11, 10, 9,
133     8,  7,  6,  5,  4,   3,   2,   1,   43,  42,  41,  63,  62, 61, 60,
134     59, 58, 57, 56, 55,  54,  53,  52,  51,  50,  49,  48,  47, 46, 45,
135     44, 65, 67, 66, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98};
136 
137 int32_t sSimpleBatchTestRedoOrderArr[] = {1,  2,  3,  4,  5,  6,  7,  8,
138                                           9,  10, 11, 12, 13, 14, 15, 16,
139                                           17, 18, 19, 20, 41, 42, 43, 66};
140 
141 int32_t sAggregateBatchTestDoOrderArr[] = {
142     1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,
143     16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,
144     31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,
145     46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,
146     61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
147     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
148     91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105,
149     106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
150     121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
151     136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
152     151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
153     166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
154     181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
155     196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
156     211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
157     226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
158     241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
159     256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
160     271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285,
161     286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300,
162     301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315,
163     316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330,
164     331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345,
165     346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360,
166     361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375,
167     376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390,
168     391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405,
169     406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
170     421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435,
171     436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450,
172     451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465,
173     466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480,
174     481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
175     496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510,
176     511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525,
177     526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540,
178     541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555,
179     556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570,
180     571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585,
181     586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600,
182     601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615,
183     616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630,
184     631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645,
185     646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660,
186     661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675,
187     676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690,
188     691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705,
189     706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720,
190     721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735,
191     736, 737, 738, 739, 740, 741, 742, 743, 744, 745};
192 
193 int32_t sAggregateBatchTestUndoOrderArr[] = {
194     301, 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, 287,
195     286, 285, 284, 283, 282, 281, 140, 139, 138, 137, 136, 135, 134, 133, 132,
196     131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
197     116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102,
198     101, 100, 99,  98,  97,  96,  95,  94,  93,  92,  91,  90,  89,  88,  87,
199     86,  85,  84,  83,  82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,
200     71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,
201     56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,
202     41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,
203     26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,
204     11,  10,  9,   8,   7,   6,   5,   4,   3,   2,   1,   301, 300, 299, 298,
205     297, 296, 295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283,
206     282, 281, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429,
207     428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414,
208     413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399,
209     398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384,
210     383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 370, 369,
211     368, 367, 366, 365, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354,
212     353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339,
213     338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324,
214     323, 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, 309,
215     308, 307, 306, 305, 304, 303, 302, 451, 450, 449, 448, 447, 465, 464, 463,
216     462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 452, 457, 456, 455, 454,
217     453, 452, 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, 735, 734, 733,
218     732, 731, 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, 720, 719, 718,
219     717, 716, 715, 714, 713, 712, 711, 710, 709, 708, 707, 706, 705, 704, 703,
220     702, 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688,
221     687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 677, 676};
222 
223 int32_t sAggregateBatchTestRedoOrderArr[] = {
224     1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,
225     16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,
226     31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,
227     46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,
228     61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
229     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
230     91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105,
231     106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
232     121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
233     136, 137, 138, 139, 140, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
234     291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 448, 449, 450, 451,
235     452, 453, 454, 455, 456, 457, 458};
236 
237 class TestTransaction : public nsITransaction {
238  protected:
239   virtual ~TestTransaction() = default;
240 
241  public:
TestTransaction()242   TestTransaction() {}
243 
244   NS_DECL_ISUPPORTS
245 };
246 
247 NS_IMPL_ISUPPORTS(TestTransaction, nsITransaction)
248 
249 class SimpleTransaction : public TestTransaction {
250  protected:
251 #define NONE_FLAG 0
252 #define THROWS_DO_ERROR_FLAG 1
253 #define THROWS_UNDO_ERROR_FLAG 2
254 #define THROWS_REDO_ERROR_FLAG 4
255 #define MERGE_FLAG 8
256 #define TRANSIENT_FLAG 16
257 #define BATCH_FLAG 32
258 #define ALL_ERROR_FLAGS \
259   (THROWS_DO_ERROR_FLAG | THROWS_UNDO_ERROR_FLAG | THROWS_REDO_ERROR_FLAG)
260 
261   int32_t mVal;
262   int32_t mFlags;
263 
264  public:
SimpleTransaction(int32_t aFlags=NONE_FLAG)265   explicit SimpleTransaction(int32_t aFlags = NONE_FLAG)
266       : mVal(++sConstructorCount), mFlags(aFlags) {}
267 
268   ~SimpleTransaction() override = default;
269 
DoTransaction()270   NS_IMETHOD DoTransaction() override {
271     //
272     // Make sure DoTransaction() is called in the order we expect!
273     // Notice that we don't check to see if we go past the end of the array.
274     // This is done on purpose since we want to crash if the order array is out
275     // of date.
276     //
277     if (sDoOrderArr) {
278       EXPECT_EQ(mVal, sDoOrderArr[sDoCount]);
279     }
280 
281     ++sDoCount;
282 
283     return (mFlags & THROWS_DO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
284   }
285 
UndoTransaction()286   NS_IMETHOD UndoTransaction() override {
287     //
288     // Make sure UndoTransaction() is called in the order we expect!
289     // Notice that we don't check to see if we go past the end of the array.
290     // This is done on purpose since we want to crash if the order array is out
291     // of date.
292     //
293     if (sUndoOrderArr) {
294       EXPECT_EQ(mVal, sUndoOrderArr[sUndoCount]);
295     }
296 
297     ++sUndoCount;
298 
299     return (mFlags & THROWS_UNDO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
300   }
301 
RedoTransaction()302   NS_IMETHOD RedoTransaction() override {
303     //
304     // Make sure RedoTransaction() is called in the order we expect!
305     // Notice that we don't check to see if we go past the end of the array.
306     // This is done on purpose since we want to crash if the order array is out
307     // of date.
308     //
309     if (sRedoOrderArr) {
310       EXPECT_EQ(mVal, sRedoOrderArr[sRedoCount]);
311     }
312 
313     ++sRedoCount;
314 
315     return (mFlags & THROWS_REDO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
316   }
317 
GetIsTransient(bool * aIsTransient)318   NS_IMETHOD GetIsTransient(bool *aIsTransient) override {
319     if (aIsTransient) {
320       *aIsTransient = (mFlags & TRANSIENT_FLAG) ? true : false;
321     }
322     return NS_OK;
323   }
324 
Merge(nsITransaction * aTransaction,bool * aDidMerge)325   NS_IMETHOD Merge(nsITransaction *aTransaction, bool *aDidMerge) override {
326     if (aDidMerge) {
327       *aDidMerge = (mFlags & MERGE_FLAG) ? true : false;
328     }
329     return NS_OK;
330   }
331 };
332 
333 class AggregateTransaction : public SimpleTransaction {
334  private:
AggregateTransaction(nsITransactionManager * aTXMgr,int32_t aLevel,int32_t aNumber,int32_t aMaxLevel,int32_t aNumChildrenPerNode,int32_t aFlags)335   AggregateTransaction(nsITransactionManager *aTXMgr, int32_t aLevel,
336                        int32_t aNumber, int32_t aMaxLevel,
337                        int32_t aNumChildrenPerNode, int32_t aFlags) {
338     mLevel = aLevel;
339     mNumber = aNumber;
340     mTXMgr = aTXMgr;
341     mFlags = aFlags & (~ALL_ERROR_FLAGS);
342     mErrorFlags = aFlags & ALL_ERROR_FLAGS;
343     mTXMgr = aTXMgr;
344     mMaxLevel = aMaxLevel;
345     mNumChildrenPerNode = aNumChildrenPerNode;
346   }
347 
348   nsITransactionManager *mTXMgr;
349 
350   int32_t mLevel;
351   int32_t mNumber;
352   int32_t mErrorFlags;
353 
354   int32_t mMaxLevel;
355   int32_t mNumChildrenPerNode;
356 
357  public:
AggregateTransaction(nsITransactionManager * aTXMgr,int32_t aMaxLevel,int32_t aNumChildrenPerNode,int32_t aFlags=NONE_FLAG)358   AggregateTransaction(nsITransactionManager *aTXMgr, int32_t aMaxLevel,
359                        int32_t aNumChildrenPerNode,
360                        int32_t aFlags = NONE_FLAG) {
361     mLevel = 1;
362     mNumber = 1;
363     mFlags = aFlags & (~ALL_ERROR_FLAGS);
364     mErrorFlags = aFlags & ALL_ERROR_FLAGS;
365     mTXMgr = aTXMgr;
366     mMaxLevel = aMaxLevel;
367     mNumChildrenPerNode = aNumChildrenPerNode;
368   }
369 
370   ~AggregateTransaction() override = default;
371 
DoTransaction()372   NS_IMETHOD DoTransaction() override {
373     if (mLevel >= mMaxLevel) {
374       // Only leaf nodes can throw errors!
375       mFlags |= mErrorFlags;
376     }
377 
378     nsresult rv = SimpleTransaction::DoTransaction();
379     if (NS_FAILED(rv)) {
380       // fail("QueryInterface() failed for transaction level %d. (%d)\n",
381       //      mLevel, rv);
382       return rv;
383     }
384 
385     if (mLevel >= mMaxLevel) {
386       return NS_OK;
387     }
388 
389     if (mFlags & BATCH_FLAG) {
390       rv = mTXMgr->BeginBatch(nullptr);
391       if (NS_FAILED(rv)) {
392         return rv;
393       }
394     }
395 
396     int32_t cLevel = mLevel + 1;
397 
398     for (int i = 1; i <= mNumChildrenPerNode; i++) {
399       int32_t flags = mErrorFlags & THROWS_DO_ERROR_FLAG;
400 
401       if ((mErrorFlags & THROWS_REDO_ERROR_FLAG) && i == mNumChildrenPerNode) {
402         // Make the rightmost leaf transaction throw the error!
403         flags = THROWS_REDO_ERROR_FLAG;
404         mErrorFlags = mErrorFlags & (~THROWS_REDO_ERROR_FLAG);
405       } else if ((mErrorFlags & THROWS_UNDO_ERROR_FLAG) && i == 1) {
406         // Make the leftmost leaf transaction throw the error!
407         flags = THROWS_UNDO_ERROR_FLAG;
408         mErrorFlags = mErrorFlags & (~THROWS_UNDO_ERROR_FLAG);
409       }
410 
411       flags |= mFlags & BATCH_FLAG;
412 
413       RefPtr<AggregateTransaction> tximpl = new AggregateTransaction(
414           mTXMgr, cLevel, i, mMaxLevel, mNumChildrenPerNode, flags);
415 
416       rv = mTXMgr->DoTransaction(tximpl);
417       if (NS_FAILED(rv)) {
418         if (mFlags & BATCH_FLAG) {
419           mTXMgr->EndBatch(false);
420         }
421         return rv;
422       }
423     }
424 
425     if (mFlags & BATCH_FLAG) {
426       mTXMgr->EndBatch(false);
427     }
428     return rv;
429   }
430 };
431 
432 class TestTransactionFactory {
433  public:
434   virtual TestTransaction *create(nsITransactionManager *txmgr,
435                                   int32_t flags) = 0;
436 };
437 
438 class SimpleTransactionFactory : public TestTransactionFactory {
439  public:
create(nsITransactionManager * txmgr,int32_t flags)440   TestTransaction *create(nsITransactionManager *txmgr,
441                           int32_t flags) override {
442     return (TestTransaction *)new SimpleTransaction(flags);
443   }
444 };
445 
446 class AggregateTransactionFactory : public TestTransactionFactory {
447  private:
448   int32_t mMaxLevel;
449   int32_t mNumChildrenPerNode;
450   int32_t mFixedFlags;
451 
452  public:
AggregateTransactionFactory(int32_t aMaxLevel,int32_t aNumChildrenPerNode,int32_t aFixedFlags=NONE_FLAG)453   AggregateTransactionFactory(int32_t aMaxLevel, int32_t aNumChildrenPerNode,
454                               int32_t aFixedFlags = NONE_FLAG)
455       : mMaxLevel(aMaxLevel),
456         mNumChildrenPerNode(aNumChildrenPerNode),
457         mFixedFlags(aFixedFlags) {}
458 
create(nsITransactionManager * txmgr,int32_t flags)459   TestTransaction *create(nsITransactionManager *txmgr,
460                           int32_t flags) override {
461     return (TestTransaction *)new AggregateTransaction(
462         txmgr, mMaxLevel, mNumChildrenPerNode, flags | mFixedFlags);
463   }
464 };
465 
reset_globals()466 void reset_globals() {
467   sConstructorCount = 0;
468 
469   sDoCount = 0;
470   sDoOrderArr = 0;
471 
472   sUndoCount = 0;
473   sUndoOrderArr = 0;
474 
475   sRedoCount = 0;
476   sRedoOrderArr = 0;
477 }
478 
479 /**
480  * Test behaviors in non-batch mode.
481  **/
quick_test(TestTransactionFactory * factory)482 void quick_test(TestTransactionFactory *factory) {
483   /*******************************************************************
484    *
485    * Create a transaction manager implementation:
486    *
487    *******************************************************************/
488 
489   nsresult rv;
490   nsCOMPtr<nsITransactionManager> mgr =
491       do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &rv);
492   ASSERT_TRUE(NS_SUCCEEDED(rv));
493 
494   /*******************************************************************
495    *
496    * Call DoTransaction() with a null transaction:
497    *
498    *******************************************************************/
499 
500   rv = mgr->DoTransaction(0);
501   EXPECT_EQ(rv, NS_ERROR_NULL_POINTER);
502 
503   /*******************************************************************
504    *
505    * Call UndoTransaction() with an empty undo stack:
506    *
507    *******************************************************************/
508 
509   rv = mgr->UndoTransaction();
510   EXPECT_TRUE(NS_SUCCEEDED(rv));
511 
512   /*******************************************************************
513    *
514    * Call RedoTransaction() with an empty redo stack:
515    *
516    *******************************************************************/
517 
518   rv = mgr->RedoTransaction();
519   EXPECT_TRUE(NS_SUCCEEDED(rv));
520 
521   /*******************************************************************
522    *
523    * Call SetMaxTransactionCount(-1) with empty undo and redo stacks:
524    *
525    *******************************************************************/
526 
527   rv = mgr->SetMaxTransactionCount(-1);
528   EXPECT_TRUE(NS_SUCCEEDED(rv));
529 
530   /*******************************************************************
531    *
532    * Call SetMaxTransactionCount(0) with empty undo and redo stacks:
533    *
534    *******************************************************************/
535 
536   rv = mgr->SetMaxTransactionCount(0);
537   EXPECT_TRUE(NS_SUCCEEDED(rv));
538 
539   /*******************************************************************
540    *
541    * Call SetMaxTransactionCount(10) with empty undo and redo stacks:
542    *
543    *******************************************************************/
544 
545   rv = mgr->SetMaxTransactionCount(10);
546   EXPECT_TRUE(NS_SUCCEEDED(rv));
547 
548   /*******************************************************************
549    *
550    * Call Clear() with empty undo and redo stacks:
551    *
552    *******************************************************************/
553 
554   rv = mgr->Clear();
555   EXPECT_TRUE(NS_SUCCEEDED(rv));
556 
557   /*******************************************************************
558    *
559    * Call GetNumberOfUndoItems() with an empty undo stack:
560    *
561    *******************************************************************/
562 
563   int32_t numitems;
564   rv = mgr->GetNumberOfUndoItems(&numitems);
565   EXPECT_TRUE(NS_SUCCEEDED(rv));
566   EXPECT_EQ(numitems, 0);
567 
568   /*******************************************************************
569    *
570    * Call GetNumberOfRedoItems() with an empty redo stack:
571    *
572    *******************************************************************/
573 
574   rv = mgr->GetNumberOfRedoItems(&numitems);
575   EXPECT_TRUE(NS_SUCCEEDED(rv));
576   EXPECT_EQ(numitems, 0);
577 
578   /*******************************************************************
579    *
580    * Call PeekUndoStack() with an empty undo stack:
581    *
582    *******************************************************************/
583 
584   {
585     nsCOMPtr<nsITransaction> tx;
586     rv = mgr->PeekUndoStack(getter_AddRefs(tx));
587     EXPECT_TRUE(NS_SUCCEEDED(rv));
588     EXPECT_EQ(tx, nullptr);
589   }
590 
591   /*******************************************************************
592    *
593    * Call PeekRedoStack() with an empty undo stack:
594    *
595    *******************************************************************/
596 
597   {
598     nsCOMPtr<nsITransaction> tx;
599     rv = mgr->PeekRedoStack(getter_AddRefs(tx));
600     EXPECT_TRUE(NS_SUCCEEDED(rv));
601     EXPECT_EQ(tx, nullptr);
602   }
603 
604   /*******************************************************************
605    *
606    * Call AddListener() with a null listener pointer:
607    *
608    *******************************************************************/
609 
610   rv = mgr->AddListener(nullptr);
611   EXPECT_EQ(rv, NS_ERROR_NULL_POINTER);
612 
613   /*******************************************************************
614    *
615    * Call RemoveListener() with a null listener pointer:
616    *
617    *******************************************************************/
618 
619   rv = mgr->RemoveListener(nullptr);
620   EXPECT_EQ(rv, NS_ERROR_NULL_POINTER);
621 
622   /*******************************************************************
623    *
624    * Test coalescing by executing a transaction that can merge any
625    * command into itself. Then execute 20 transaction. Afterwards,
626    * we should still have the first transaction sitting on the undo
627    * stack. Then clear the undo and redo stacks.
628    *
629    *******************************************************************/
630 
631   int32_t i;
632   RefPtr<TestTransaction> tximpl;
633   nsCOMPtr<nsITransaction> u1, u2, r1, r2;
634 
635   rv = mgr->SetMaxTransactionCount(10);
636   EXPECT_TRUE(NS_SUCCEEDED(rv));
637 
638   tximpl = factory->create(mgr, MERGE_FLAG);
639   rv = mgr->DoTransaction(tximpl);
640   EXPECT_TRUE(NS_SUCCEEDED(rv));
641 
642   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
643   EXPECT_TRUE(NS_SUCCEEDED(rv));
644   EXPECT_EQ(u1, tximpl);
645 
646   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
647   EXPECT_TRUE(NS_SUCCEEDED(rv));
648 
649   for (i = 1; i <= 20; i++) {
650     tximpl = factory->create(mgr, NONE_FLAG);
651     rv = mgr->DoTransaction(tximpl);
652     EXPECT_TRUE(NS_SUCCEEDED(rv));
653   }
654 
655   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
656   EXPECT_TRUE(NS_SUCCEEDED(rv));
657   EXPECT_EQ(u1, u2);
658 
659   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
660   EXPECT_TRUE(NS_SUCCEEDED(rv));
661   EXPECT_EQ(r1, r2);
662 
663   rv = mgr->GetNumberOfUndoItems(&numitems);
664   EXPECT_TRUE(NS_SUCCEEDED(rv));
665   EXPECT_EQ(numitems, 1);
666 
667   rv = mgr->GetNumberOfRedoItems(&numitems);
668   EXPECT_TRUE(NS_SUCCEEDED(rv));
669   EXPECT_EQ(numitems, 0);
670 
671   rv = mgr->Clear();
672   EXPECT_TRUE(NS_SUCCEEDED(rv));
673 
674   /*******************************************************************
675    *
676    * Execute 20 transactions. Afterwards, we should have 10
677    * transactions on the undo stack:
678    *
679    *******************************************************************/
680 
681   for (i = 1; i <= 20; i++) {
682     tximpl = factory->create(mgr, NONE_FLAG);
683     rv = mgr->DoTransaction(tximpl);
684     EXPECT_TRUE(NS_SUCCEEDED(rv));
685   }
686 
687   rv = mgr->GetNumberOfUndoItems(&numitems);
688   EXPECT_TRUE(NS_SUCCEEDED(rv));
689   EXPECT_EQ(numitems, 10);
690 
691   rv = mgr->GetNumberOfRedoItems(&numitems);
692   EXPECT_TRUE(NS_SUCCEEDED(rv));
693   EXPECT_EQ(numitems, 0);
694 
695   /*******************************************************************
696    *
697    * Execute 20 transient transactions. Afterwards, we should still
698    * have the same 10 transactions on the undo stack:
699    *
700    *******************************************************************/
701 
702   u1 = u2 = r1 = r2 = nullptr;
703 
704   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
705   EXPECT_TRUE(NS_SUCCEEDED(rv));
706 
707   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
708   EXPECT_TRUE(NS_SUCCEEDED(rv));
709 
710   for (i = 1; i <= 20; i++) {
711     tximpl = factory->create(mgr, TRANSIENT_FLAG);
712     rv = mgr->DoTransaction(tximpl);
713     EXPECT_TRUE(NS_SUCCEEDED(rv));
714   }
715 
716   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
717   EXPECT_TRUE(NS_SUCCEEDED(rv));
718   EXPECT_EQ(u1, u2);
719 
720   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
721   EXPECT_TRUE(NS_SUCCEEDED(rv));
722   EXPECT_EQ(r1, r2);
723 
724   rv = mgr->GetNumberOfUndoItems(&numitems);
725   EXPECT_TRUE(NS_SUCCEEDED(rv));
726   EXPECT_EQ(numitems, 10);
727 
728   rv = mgr->GetNumberOfRedoItems(&numitems);
729   EXPECT_TRUE(NS_SUCCEEDED(rv));
730   EXPECT_EQ(numitems, 0);
731 
732   /*******************************************************************
733    *
734    * Undo 4 transactions. Afterwards, we should have 6 transactions
735    * on the undo stack, and 4 on the redo stack:
736    *
737    *******************************************************************/
738 
739   for (i = 1; i <= 4; i++) {
740     rv = mgr->UndoTransaction();
741     EXPECT_TRUE(NS_SUCCEEDED(rv));
742   }
743 
744   rv = mgr->GetNumberOfUndoItems(&numitems);
745   EXPECT_TRUE(NS_SUCCEEDED(rv));
746   EXPECT_EQ(numitems, 6);
747 
748   rv = mgr->GetNumberOfRedoItems(&numitems);
749   EXPECT_TRUE(NS_SUCCEEDED(rv));
750   EXPECT_EQ(numitems, 4);
751 
752   /*******************************************************************
753    *
754    * Redo 2 transactions. Afterwards, we should have 8 transactions
755    * on the undo stack, and 2 on the redo stack:
756    *
757    *******************************************************************/
758 
759   for (i = 1; i <= 2; ++i) {
760     rv = mgr->RedoTransaction();
761     EXPECT_TRUE(NS_SUCCEEDED(rv));
762   }
763 
764   rv = mgr->GetNumberOfUndoItems(&numitems);
765   EXPECT_TRUE(NS_SUCCEEDED(rv));
766   EXPECT_EQ(numitems, 8);
767 
768   rv = mgr->GetNumberOfRedoItems(&numitems);
769   EXPECT_TRUE(NS_SUCCEEDED(rv));
770   EXPECT_EQ(numitems, 2);
771 
772   /*******************************************************************
773    *
774    * Execute a new transaction. The redo stack should get pruned!
775    *
776    *******************************************************************/
777 
778   tximpl = factory->create(mgr, NONE_FLAG);
779   rv = mgr->DoTransaction(tximpl);
780   EXPECT_TRUE(NS_SUCCEEDED(rv));
781 
782   rv = mgr->GetNumberOfUndoItems(&numitems);
783   EXPECT_TRUE(NS_SUCCEEDED(rv));
784   EXPECT_EQ(numitems, 9);
785 
786   rv = mgr->GetNumberOfRedoItems(&numitems);
787   EXPECT_TRUE(NS_SUCCEEDED(rv));
788   EXPECT_EQ(numitems, 0);
789 
790   /*******************************************************************
791    *
792    * Undo 4 transactions then clear the undo and redo stacks.
793    *
794    *******************************************************************/
795 
796   for (i = 1; i <= 4; ++i) {
797     rv = mgr->UndoTransaction();
798     EXPECT_TRUE(NS_SUCCEEDED(rv));
799   }
800 
801   rv = mgr->GetNumberOfUndoItems(&numitems);
802   EXPECT_TRUE(NS_SUCCEEDED(rv));
803   EXPECT_EQ(numitems, 5);
804 
805   rv = mgr->GetNumberOfRedoItems(&numitems);
806   EXPECT_TRUE(NS_SUCCEEDED(rv));
807   EXPECT_EQ(numitems, 4);
808 
809   rv = mgr->Clear();
810   EXPECT_TRUE(NS_SUCCEEDED(rv));
811 
812   rv = mgr->GetNumberOfUndoItems(&numitems);
813   EXPECT_TRUE(NS_SUCCEEDED(rv));
814   EXPECT_EQ(numitems, 0);
815 
816   rv = mgr->GetNumberOfRedoItems(&numitems);
817   EXPECT_TRUE(NS_SUCCEEDED(rv));
818   EXPECT_EQ(numitems, 0);
819 
820   /*******************************************************************
821    *
822    * Execute 5 transactions.
823    *
824    *******************************************************************/
825 
826   for (i = 1; i <= 5; i++) {
827     tximpl = factory->create(mgr, NONE_FLAG);
828     rv = mgr->DoTransaction(tximpl);
829     EXPECT_TRUE(NS_SUCCEEDED(rv));
830   }
831 
832   rv = mgr->GetNumberOfUndoItems(&numitems);
833   EXPECT_TRUE(NS_SUCCEEDED(rv));
834   EXPECT_EQ(numitems, 5);
835 
836   rv = mgr->GetNumberOfRedoItems(&numitems);
837   EXPECT_TRUE(NS_SUCCEEDED(rv));
838   EXPECT_EQ(numitems, 0);
839 
840   /*******************************************************************
841    *
842    * Test transaction DoTransaction() error:
843    *
844    *******************************************************************/
845 
846   tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);
847 
848   u1 = u2 = r1 = r2 = nullptr;
849 
850   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
851   EXPECT_TRUE(NS_SUCCEEDED(rv));
852 
853   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
854   EXPECT_TRUE(NS_SUCCEEDED(rv));
855 
856   rv = mgr->DoTransaction(tximpl);
857   EXPECT_EQ(rv, NS_ERROR_FAILURE);
858 
859   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
860   EXPECT_TRUE(NS_SUCCEEDED(rv));
861   EXPECT_EQ(u1, u2);
862 
863   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
864   EXPECT_TRUE(NS_SUCCEEDED(rv));
865   EXPECT_EQ(r1, r2);
866 
867   rv = mgr->GetNumberOfUndoItems(&numitems);
868   EXPECT_TRUE(NS_SUCCEEDED(rv));
869   EXPECT_EQ(numitems, 5);
870 
871   rv = mgr->GetNumberOfRedoItems(&numitems);
872   EXPECT_TRUE(NS_SUCCEEDED(rv));
873   EXPECT_EQ(numitems, 0);
874 
875   /*******************************************************************
876    *
877    * Test transaction UndoTransaction() error:
878    *
879    *******************************************************************/
880 
881   tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);
882   rv = mgr->DoTransaction(tximpl);
883   EXPECT_TRUE(NS_SUCCEEDED(rv));
884 
885   u1 = u2 = r1 = r2 = nullptr;
886 
887   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
888   EXPECT_TRUE(NS_SUCCEEDED(rv));
889 
890   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
891   EXPECT_TRUE(NS_SUCCEEDED(rv));
892 
893   rv = mgr->UndoTransaction();
894   EXPECT_EQ(rv, NS_ERROR_FAILURE);
895 
896   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
897   EXPECT_TRUE(NS_SUCCEEDED(rv));
898   EXPECT_EQ(u1, u2);
899 
900   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
901   EXPECT_TRUE(NS_SUCCEEDED(rv));
902   EXPECT_EQ(r1, r2);
903 
904   rv = mgr->GetNumberOfUndoItems(&numitems);
905   EXPECT_TRUE(NS_SUCCEEDED(rv));
906   EXPECT_EQ(numitems, 6);
907 
908   rv = mgr->GetNumberOfRedoItems(&numitems);
909   EXPECT_TRUE(NS_SUCCEEDED(rv));
910   EXPECT_EQ(numitems, 0);
911 
912   /*******************************************************************
913    *
914    * Test transaction RedoTransaction() error:
915    *
916    *******************************************************************/
917 
918   tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);
919   rv = mgr->DoTransaction(tximpl);
920   EXPECT_TRUE(NS_SUCCEEDED(rv));
921 
922   //
923   // Execute a normal transaction to be used in a later test:
924   //
925 
926   tximpl = factory->create(mgr, NONE_FLAG);
927   rv = mgr->DoTransaction(tximpl);
928   EXPECT_TRUE(NS_SUCCEEDED(rv));
929 
930   //
931   // Undo the 2 transactions just executed.
932   //
933 
934   for (i = 1; i <= 2; ++i) {
935     rv = mgr->UndoTransaction();
936     EXPECT_TRUE(NS_SUCCEEDED(rv));
937   }
938 
939   //
940   // The RedoErrorTransaction should now be at the top of the redo stack!
941   //
942 
943   u1 = u2 = r1 = r2 = nullptr;
944 
945   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
946   EXPECT_TRUE(NS_SUCCEEDED(rv));
947 
948   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
949   EXPECT_TRUE(NS_SUCCEEDED(rv));
950 
951   rv = mgr->RedoTransaction();
952   EXPECT_EQ(rv, NS_ERROR_FAILURE);
953 
954   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
955   EXPECT_TRUE(NS_SUCCEEDED(rv));
956   EXPECT_EQ(u1, u2);
957 
958   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
959   EXPECT_TRUE(NS_SUCCEEDED(rv));
960   EXPECT_EQ(r1, r2);
961 
962   rv = mgr->GetNumberOfUndoItems(&numitems);
963   EXPECT_TRUE(NS_SUCCEEDED(rv));
964   EXPECT_EQ(numitems, 6);
965 
966   rv = mgr->GetNumberOfRedoItems(&numitems);
967   EXPECT_TRUE(NS_SUCCEEDED(rv));
968   EXPECT_EQ(numitems, 2);
969 
970   /*******************************************************************
971    *
972    * Make sure that setting the transaction manager's max transaction
973    * count to zero, clears both the undo and redo stacks, and executes
974    * all new commands without pushing them on the undo stack!
975    *
976    *******************************************************************/
977 
978   rv = mgr->SetMaxTransactionCount(0);
979   EXPECT_TRUE(NS_SUCCEEDED(rv));
980 
981   rv = mgr->GetNumberOfUndoItems(&numitems);
982   EXPECT_TRUE(NS_SUCCEEDED(rv));
983   EXPECT_EQ(numitems, 0);
984 
985   rv = mgr->GetNumberOfRedoItems(&numitems);
986   EXPECT_TRUE(NS_SUCCEEDED(rv));
987   EXPECT_EQ(numitems, 0);
988 
989   for (i = 1; i <= 20; i++) {
990     tximpl = factory->create(mgr, NONE_FLAG);
991     rv = mgr->DoTransaction(tximpl);
992     EXPECT_TRUE(NS_SUCCEEDED(rv));
993 
994     rv = mgr->GetNumberOfUndoItems(&numitems);
995     EXPECT_TRUE(NS_SUCCEEDED(rv));
996     EXPECT_EQ(numitems, 0);
997 
998     rv = mgr->GetNumberOfRedoItems(&numitems);
999     EXPECT_TRUE(NS_SUCCEEDED(rv));
1000     EXPECT_EQ(numitems, 0);
1001   }
1002 
1003   /*******************************************************************
1004    *
1005    * Make sure that setting the transaction manager's max transaction
1006    * count to something greater than the number of transactions on
1007    * both the undo and redo stacks causes no pruning of the stacks:
1008    *
1009    *******************************************************************/
1010 
1011   rv = mgr->SetMaxTransactionCount(-1);
1012   EXPECT_TRUE(NS_SUCCEEDED(rv));
1013 
1014   // Push 20 transactions on the undo stack:
1015 
1016   for (i = 1; i <= 20; i++) {
1017     tximpl = factory->create(mgr, NONE_FLAG);
1018     rv = mgr->DoTransaction(tximpl);
1019     EXPECT_TRUE(NS_SUCCEEDED(rv));
1020 
1021     rv = mgr->GetNumberOfUndoItems(&numitems);
1022     EXPECT_TRUE(NS_SUCCEEDED(rv));
1023     EXPECT_EQ(numitems, i);
1024 
1025     rv = mgr->GetNumberOfRedoItems(&numitems);
1026     EXPECT_TRUE(NS_SUCCEEDED(rv));
1027     EXPECT_EQ(numitems, 0);
1028   }
1029 
1030   for (i = 1; i <= 10; i++) {
1031     rv = mgr->UndoTransaction();
1032     EXPECT_TRUE(NS_SUCCEEDED(rv));
1033   }
1034   rv = mgr->GetNumberOfUndoItems(&numitems);
1035   EXPECT_TRUE(NS_SUCCEEDED(rv));
1036   EXPECT_EQ(numitems, 10);
1037 
1038   rv = mgr->GetNumberOfRedoItems(&numitems);
1039   EXPECT_TRUE(NS_SUCCEEDED(rv));
1040   EXPECT_EQ(numitems, 10);
1041 
1042   u1 = u2 = r1 = r2 = nullptr;
1043 
1044   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1045   EXPECT_TRUE(NS_SUCCEEDED(rv));
1046 
1047   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1048   EXPECT_TRUE(NS_SUCCEEDED(rv));
1049 
1050   rv = mgr->SetMaxTransactionCount(25);
1051   EXPECT_TRUE(NS_SUCCEEDED(rv));
1052 
1053   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1054   EXPECT_TRUE(NS_SUCCEEDED(rv));
1055   EXPECT_EQ(u1, u2);
1056 
1057   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1058   EXPECT_TRUE(NS_SUCCEEDED(rv));
1059   EXPECT_EQ(r1, r2);
1060 
1061   rv = mgr->GetNumberOfUndoItems(&numitems);
1062   EXPECT_TRUE(NS_SUCCEEDED(rv));
1063   EXPECT_EQ(numitems, 10);
1064 
1065   rv = mgr->GetNumberOfRedoItems(&numitems);
1066   EXPECT_TRUE(NS_SUCCEEDED(rv));
1067   EXPECT_EQ(numitems, 10);
1068 
1069   /*******************************************************************
1070    *
1071    * Test undo stack pruning by setting the transaction
1072    * manager's max transaction count to a number lower than the
1073    * number of transactions on both the undo and redo stacks:
1074    *
1075    *******************************************************************/
1076 
1077   u1 = u2 = r1 = r2 = nullptr;
1078 
1079   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1080   EXPECT_TRUE(NS_SUCCEEDED(rv));
1081 
1082   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1083   EXPECT_TRUE(NS_SUCCEEDED(rv));
1084 
1085   rv = mgr->SetMaxTransactionCount(15);
1086   EXPECT_TRUE(NS_SUCCEEDED(rv));
1087 
1088   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1089   EXPECT_TRUE(NS_SUCCEEDED(rv));
1090   EXPECT_EQ(u1, u2);
1091 
1092   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1093   EXPECT_TRUE(NS_SUCCEEDED(rv));
1094   EXPECT_EQ(r1, r2);
1095 
1096   rv = mgr->GetNumberOfUndoItems(&numitems);
1097   EXPECT_TRUE(NS_SUCCEEDED(rv));
1098   EXPECT_EQ(numitems, 5);
1099 
1100   rv = mgr->GetNumberOfRedoItems(&numitems);
1101   EXPECT_TRUE(NS_SUCCEEDED(rv));
1102   EXPECT_EQ(numitems, 10);
1103 
1104   /*******************************************************************
1105    *
1106    * Test redo stack pruning by setting the transaction
1107    * manager's max transaction count to a number lower than the
1108    * number of transactions on both the undo and redo stacks:
1109    *
1110    *******************************************************************/
1111 
1112   u1 = u2 = r1 = r2 = nullptr;
1113 
1114   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1115   EXPECT_TRUE(NS_SUCCEEDED(rv));
1116 
1117   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1118   EXPECT_TRUE(NS_SUCCEEDED(rv));
1119 
1120   rv = mgr->SetMaxTransactionCount(5);
1121   EXPECT_TRUE(NS_SUCCEEDED(rv));
1122 
1123   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1124   EXPECT_TRUE(NS_SUCCEEDED(rv));
1125   EXPECT_FALSE(u2);
1126 
1127   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1128   EXPECT_TRUE(NS_SUCCEEDED(rv));
1129   EXPECT_EQ(r1, r2);
1130 
1131   rv = mgr->GetNumberOfUndoItems(&numitems);
1132   EXPECT_TRUE(NS_SUCCEEDED(rv));
1133   EXPECT_EQ(numitems, 0);
1134 
1135   rv = mgr->GetNumberOfRedoItems(&numitems);
1136   EXPECT_TRUE(NS_SUCCEEDED(rv));
1137   EXPECT_EQ(numitems, 5);
1138 
1139   /*******************************************************************
1140    *
1141    * Release the transaction manager. Any transactions on the undo
1142    * and redo stack should automatically be released:
1143    *
1144    *******************************************************************/
1145 
1146   rv = mgr->SetMaxTransactionCount(-1);
1147   EXPECT_TRUE(NS_SUCCEEDED(rv));
1148 
1149   // Push 20 transactions on the undo stack:
1150 
1151   for (i = 1; i <= 20; i++) {
1152     tximpl = factory->create(mgr, NONE_FLAG);
1153     rv = mgr->DoTransaction(tximpl);
1154     EXPECT_TRUE(NS_SUCCEEDED(rv));
1155 
1156     rv = mgr->GetNumberOfUndoItems(&numitems);
1157     EXPECT_TRUE(NS_SUCCEEDED(rv));
1158     EXPECT_EQ(numitems, i);
1159 
1160     rv = mgr->GetNumberOfRedoItems(&numitems);
1161     EXPECT_TRUE(NS_SUCCEEDED(rv));
1162     EXPECT_EQ(numitems, 0);
1163   }
1164 
1165   for (i = 1; i <= 10; i++) {
1166     rv = mgr->UndoTransaction();
1167     EXPECT_TRUE(NS_SUCCEEDED(rv));
1168   }
1169 
1170   rv = mgr->GetNumberOfUndoItems(&numitems);
1171   EXPECT_TRUE(NS_SUCCEEDED(rv));
1172   EXPECT_EQ(numitems, 10);
1173 
1174   rv = mgr->GetNumberOfRedoItems(&numitems);
1175   EXPECT_TRUE(NS_SUCCEEDED(rv));
1176   EXPECT_EQ(numitems, 10);
1177 
1178   rv = mgr->Clear();
1179   EXPECT_TRUE(NS_SUCCEEDED(rv));
1180 }
1181 
TEST(TestTXMgr,SimpleTest)1182 TEST(TestTXMgr, SimpleTest) {
1183   /*******************************************************************
1184    *
1185    * Initialize globals for test.
1186    *
1187    *******************************************************************/
1188   reset_globals();
1189   sDoOrderArr = sSimpleTestDoOrderArr;
1190   sUndoOrderArr = sSimpleTestUndoOrderArr;
1191   sRedoOrderArr = sSimpleTestRedoOrderArr;
1192 
1193   /*******************************************************************
1194    *
1195    * Run the quick test.
1196    *
1197    *******************************************************************/
1198 
1199   SimpleTransactionFactory factory;
1200 
1201   quick_test(&factory);
1202 }
1203 
TEST(TestTXMgr,AggregationTest)1204 TEST(TestTXMgr, AggregationTest) {
1205   /*******************************************************************
1206    *
1207    * Initialize globals for test.
1208    *
1209    *******************************************************************/
1210 
1211   reset_globals();
1212   sDoOrderArr = sAggregateTestDoOrderArr;
1213   sUndoOrderArr = sAggregateTestUndoOrderArr;
1214   sRedoOrderArr = sAggregateTestRedoOrderArr;
1215 
1216   /*******************************************************************
1217    *
1218    * Run the quick test.
1219    *
1220    *******************************************************************/
1221 
1222   AggregateTransactionFactory factory(3, 2);
1223 
1224   quick_test(&factory);
1225 }
1226 
1227 /**
1228  * Test behaviors in batch mode.
1229  **/
quick_batch_test(TestTransactionFactory * factory)1230 void quick_batch_test(TestTransactionFactory *factory) {
1231   /*******************************************************************
1232    *
1233    * Create a transaction manager implementation:
1234    *
1235    *******************************************************************/
1236 
1237   nsresult rv;
1238   nsCOMPtr<nsITransactionManager> mgr =
1239       do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &rv);
1240   ASSERT_TRUE(mgr);
1241   ASSERT_TRUE(NS_SUCCEEDED(rv));
1242 
1243   int32_t numitems;
1244 
1245   /*******************************************************************
1246    *
1247    * Make sure an unbalanced call to EndBatch(false) with empty undo stack
1248    * throws an error!
1249    *
1250    *******************************************************************/
1251 
1252   rv = mgr->GetNumberOfUndoItems(&numitems);
1253   EXPECT_TRUE(NS_SUCCEEDED(rv));
1254   EXPECT_EQ(numitems, 0);
1255 
1256   rv = mgr->EndBatch(false);
1257   EXPECT_EQ(rv, NS_ERROR_FAILURE);
1258 
1259   rv = mgr->GetNumberOfUndoItems(&numitems);
1260   EXPECT_TRUE(NS_SUCCEEDED(rv));
1261   EXPECT_EQ(numitems, 0);
1262 
1263   /*******************************************************************
1264    *
1265    * Make sure that an empty batch is not added to the undo stack
1266    * when it is closed.
1267    *
1268    *******************************************************************/
1269 
1270   rv = mgr->GetNumberOfUndoItems(&numitems);
1271   EXPECT_TRUE(NS_SUCCEEDED(rv));
1272   EXPECT_EQ(numitems, 0);
1273 
1274   rv = mgr->BeginBatch(nullptr);
1275   EXPECT_TRUE(NS_SUCCEEDED(rv));
1276 
1277   rv = mgr->GetNumberOfUndoItems(&numitems);
1278   EXPECT_TRUE(NS_SUCCEEDED(rv));
1279   EXPECT_EQ(numitems, 0);
1280 
1281   rv = mgr->EndBatch(false);
1282   EXPECT_TRUE(NS_SUCCEEDED(rv));
1283 
1284   rv = mgr->GetNumberOfUndoItems(&numitems);
1285   EXPECT_TRUE(NS_SUCCEEDED(rv));
1286   EXPECT_EQ(numitems, 0);
1287 
1288   int32_t i;
1289   RefPtr<TestTransaction> tximpl;
1290 
1291   /*******************************************************************
1292    *
1293    * Execute 20 transactions. Afterwards, we should have 1
1294    * transaction on the undo stack:
1295    *
1296    *******************************************************************/
1297 
1298   rv = mgr->BeginBatch(nullptr);
1299   EXPECT_TRUE(NS_SUCCEEDED(rv));
1300 
1301   for (i = 1; i <= 20; i++) {
1302     tximpl = factory->create(mgr, NONE_FLAG);
1303     rv = mgr->DoTransaction(tximpl);
1304     EXPECT_TRUE(NS_SUCCEEDED(rv));
1305   }
1306 
1307   rv = mgr->GetNumberOfUndoItems(&numitems);
1308   EXPECT_TRUE(NS_SUCCEEDED(rv));
1309   EXPECT_EQ(numitems, 0);
1310 
1311   rv = mgr->EndBatch(false);
1312   EXPECT_TRUE(NS_SUCCEEDED(rv));
1313 
1314   rv = mgr->GetNumberOfUndoItems(&numitems);
1315   EXPECT_TRUE(NS_SUCCEEDED(rv));
1316   EXPECT_EQ(numitems, 1);
1317 
1318   nsCOMPtr<nsITransaction> u1, u2, r1, r2;
1319 
1320   /*******************************************************************
1321    *
1322    * Execute 20 transient transactions. Afterwards, we should still
1323    * have the same transaction on the undo stack:
1324    *
1325    *******************************************************************/
1326 
1327   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1328   EXPECT_TRUE(NS_SUCCEEDED(rv));
1329 
1330   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1331   EXPECT_TRUE(NS_SUCCEEDED(rv));
1332 
1333   rv = mgr->BeginBatch(nullptr);
1334   EXPECT_TRUE(NS_SUCCEEDED(rv));
1335 
1336   for (i = 1; i <= 20; i++) {
1337     tximpl = factory->create(mgr, TRANSIENT_FLAG);
1338     rv = mgr->DoTransaction(tximpl);
1339     EXPECT_TRUE(NS_SUCCEEDED(rv));
1340   }
1341 
1342   rv = mgr->EndBatch(false);
1343   EXPECT_TRUE(NS_SUCCEEDED(rv));
1344 
1345   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1346   EXPECT_TRUE(NS_SUCCEEDED(rv));
1347   EXPECT_EQ(u1, u2);
1348 
1349   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1350   EXPECT_TRUE(NS_SUCCEEDED(rv));
1351   EXPECT_EQ(r1, r2);
1352 
1353   rv = mgr->GetNumberOfUndoItems(&numitems);
1354   EXPECT_TRUE(NS_SUCCEEDED(rv));
1355   EXPECT_EQ(numitems, 1);
1356 
1357   rv = mgr->GetNumberOfRedoItems(&numitems);
1358   EXPECT_TRUE(NS_SUCCEEDED(rv));
1359   EXPECT_EQ(numitems, 0);
1360 
1361   /*******************************************************************
1362    *
1363    * Test nested batching. Afterwards, we should have 2 transactions
1364    * on the undo stack:
1365    *
1366    *******************************************************************/
1367 
1368   rv = mgr->BeginBatch(nullptr);
1369   EXPECT_TRUE(NS_SUCCEEDED(rv));
1370 
1371   tximpl = factory->create(mgr, NONE_FLAG);
1372   rv = mgr->DoTransaction(tximpl);
1373   EXPECT_TRUE(NS_SUCCEEDED(rv));
1374 
1375   rv = mgr->GetNumberOfUndoItems(&numitems);
1376   EXPECT_TRUE(NS_SUCCEEDED(rv));
1377   EXPECT_EQ(numitems, 1);
1378 
1379   rv = mgr->BeginBatch(nullptr);
1380   EXPECT_TRUE(NS_SUCCEEDED(rv));
1381 
1382   tximpl = factory->create(mgr, NONE_FLAG);
1383   rv = mgr->DoTransaction(tximpl);
1384   EXPECT_TRUE(NS_SUCCEEDED(rv));
1385 
1386   rv = mgr->GetNumberOfUndoItems(&numitems);
1387   EXPECT_TRUE(NS_SUCCEEDED(rv));
1388   EXPECT_EQ(numitems, 1);
1389 
1390   rv = mgr->BeginBatch(nullptr);
1391   EXPECT_TRUE(NS_SUCCEEDED(rv));
1392 
1393   tximpl = factory->create(mgr, NONE_FLAG);
1394   rv = mgr->DoTransaction(tximpl);
1395   EXPECT_TRUE(NS_SUCCEEDED(rv));
1396 
1397   rv = mgr->GetNumberOfUndoItems(&numitems);
1398   EXPECT_TRUE(NS_SUCCEEDED(rv));
1399   EXPECT_EQ(numitems, 1);
1400 
1401   rv = mgr->EndBatch(false);
1402   EXPECT_TRUE(NS_SUCCEEDED(rv));
1403 
1404   rv = mgr->EndBatch(false);
1405   EXPECT_TRUE(NS_SUCCEEDED(rv));
1406 
1407   rv = mgr->EndBatch(false);
1408   EXPECT_TRUE(NS_SUCCEEDED(rv));
1409 
1410   rv = mgr->GetNumberOfUndoItems(&numitems);
1411   EXPECT_TRUE(NS_SUCCEEDED(rv));
1412   EXPECT_EQ(numitems, 2);
1413 
1414   /*******************************************************************
1415    *
1416    * Undo 2 batch transactions. Afterwards, we should have 0
1417    * transactions on the undo stack and 2 on the redo stack.
1418    *
1419    *******************************************************************/
1420 
1421   for (i = 1; i <= 2; ++i) {
1422     rv = mgr->UndoTransaction();
1423     EXPECT_TRUE(NS_SUCCEEDED(rv));
1424   }
1425 
1426   rv = mgr->GetNumberOfUndoItems(&numitems);
1427   EXPECT_TRUE(NS_SUCCEEDED(rv));
1428   EXPECT_EQ(numitems, 0);
1429 
1430   rv = mgr->GetNumberOfRedoItems(&numitems);
1431   EXPECT_TRUE(NS_SUCCEEDED(rv));
1432   EXPECT_EQ(numitems, 2);
1433 
1434   /*******************************************************************
1435    *
1436    * Redo 2 batch transactions. Afterwards, we should have 2
1437    * transactions on the undo stack and 0 on the redo stack.
1438    *
1439    *******************************************************************/
1440 
1441   for (i = 1; i <= 2; ++i) {
1442     rv = mgr->RedoTransaction();
1443     EXPECT_TRUE(NS_SUCCEEDED(rv));
1444   }
1445 
1446   rv = mgr->GetNumberOfUndoItems(&numitems);
1447   EXPECT_TRUE(NS_SUCCEEDED(rv));
1448   EXPECT_EQ(numitems, 2);
1449 
1450   rv = mgr->GetNumberOfRedoItems(&numitems);
1451   EXPECT_TRUE(NS_SUCCEEDED(rv));
1452   EXPECT_EQ(numitems, 0);
1453 
1454   /*******************************************************************
1455    *
1456    * Call undo. Afterwards, we should have 1 transaction
1457    * on the undo stack, and 1 on the redo stack:
1458    *
1459    *******************************************************************/
1460 
1461   rv = mgr->UndoTransaction();
1462   EXPECT_TRUE(NS_SUCCEEDED(rv));
1463 
1464   rv = mgr->GetNumberOfUndoItems(&numitems);
1465   EXPECT_TRUE(NS_SUCCEEDED(rv));
1466   EXPECT_EQ(numitems, 1);
1467 
1468   rv = mgr->GetNumberOfRedoItems(&numitems);
1469   EXPECT_TRUE(NS_SUCCEEDED(rv));
1470   EXPECT_EQ(numitems, 1);
1471 
1472   /*******************************************************************
1473    *
1474    * Make sure an unbalanced call to EndBatch(false) throws an error and
1475    * doesn't affect the undo and redo stacks!
1476    *
1477    *******************************************************************/
1478 
1479   rv = mgr->EndBatch(false);
1480   EXPECT_EQ(rv, NS_ERROR_FAILURE);
1481 
1482   rv = mgr->GetNumberOfUndoItems(&numitems);
1483   EXPECT_TRUE(NS_SUCCEEDED(rv));
1484   EXPECT_EQ(numitems, 1);
1485 
1486   rv = mgr->GetNumberOfRedoItems(&numitems);
1487   EXPECT_TRUE(NS_SUCCEEDED(rv));
1488   EXPECT_EQ(numitems, 1);
1489 
1490   /*******************************************************************
1491    *
1492    * Make sure that an empty batch is not added to the undo stack
1493    * when it is closed, and that it does not affect the undo and redo
1494    * stacks.
1495    *
1496    *******************************************************************/
1497 
1498   rv = mgr->BeginBatch(nullptr);
1499   EXPECT_TRUE(NS_SUCCEEDED(rv));
1500 
1501   rv = mgr->GetNumberOfUndoItems(&numitems);
1502   EXPECT_TRUE(NS_SUCCEEDED(rv));
1503   EXPECT_EQ(numitems, 1);
1504 
1505   rv = mgr->GetNumberOfRedoItems(&numitems);
1506   EXPECT_TRUE(NS_SUCCEEDED(rv));
1507   EXPECT_EQ(numitems, 1);
1508 
1509   rv = mgr->EndBatch(false);
1510   EXPECT_TRUE(NS_SUCCEEDED(rv));
1511 
1512   rv = mgr->GetNumberOfUndoItems(&numitems);
1513   EXPECT_TRUE(NS_SUCCEEDED(rv));
1514   EXPECT_EQ(numitems, 1);
1515 
1516   rv = mgr->GetNumberOfRedoItems(&numitems);
1517   EXPECT_TRUE(NS_SUCCEEDED(rv));
1518   EXPECT_EQ(numitems, 1);
1519 
1520   /*******************************************************************
1521    *
1522    * Execute a new transaction. The redo stack should get pruned!
1523    *
1524    *******************************************************************/
1525 
1526   rv = mgr->BeginBatch(nullptr);
1527   EXPECT_TRUE(NS_SUCCEEDED(rv));
1528 
1529   for (i = 1; i <= 20; i++) {
1530     tximpl = factory->create(mgr, NONE_FLAG);
1531     rv = mgr->DoTransaction(tximpl);
1532     EXPECT_TRUE(NS_SUCCEEDED(rv));
1533   }
1534 
1535   rv = mgr->GetNumberOfUndoItems(&numitems);
1536   EXPECT_TRUE(NS_SUCCEEDED(rv));
1537   EXPECT_EQ(numitems, 1);
1538 
1539   rv = mgr->GetNumberOfRedoItems(&numitems);
1540   EXPECT_TRUE(NS_SUCCEEDED(rv));
1541   EXPECT_EQ(numitems, 1);
1542 
1543   rv = mgr->EndBatch(false);
1544   EXPECT_TRUE(NS_SUCCEEDED(rv));
1545 
1546   rv = mgr->GetNumberOfUndoItems(&numitems);
1547   EXPECT_TRUE(NS_SUCCEEDED(rv));
1548   EXPECT_EQ(numitems, 2);
1549 
1550   rv = mgr->GetNumberOfRedoItems(&numitems);
1551   EXPECT_TRUE(NS_SUCCEEDED(rv));
1552   EXPECT_EQ(numitems, 0);
1553 
1554   /*******************************************************************
1555    *
1556    * Call undo.
1557    *
1558    *******************************************************************/
1559 
1560   // Move a transaction over to the redo stack, so that we have one
1561   // transaction on the undo stack, and one on the redo stack!
1562 
1563   rv = mgr->UndoTransaction();
1564   EXPECT_TRUE(NS_SUCCEEDED(rv));
1565 
1566   rv = mgr->GetNumberOfUndoItems(&numitems);
1567   EXPECT_TRUE(NS_SUCCEEDED(rv));
1568   EXPECT_EQ(numitems, 1);
1569 
1570   rv = mgr->GetNumberOfRedoItems(&numitems);
1571   EXPECT_TRUE(NS_SUCCEEDED(rv));
1572   EXPECT_EQ(numitems, 1);
1573 
1574   /*******************************************************************
1575    *
1576    * Test transaction DoTransaction() error:
1577    *
1578    *******************************************************************/
1579 
1580   tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);
1581 
1582   u1 = u2 = r1 = r2 = nullptr;
1583 
1584   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1585   EXPECT_TRUE(NS_SUCCEEDED(rv));
1586 
1587   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1588   EXPECT_TRUE(NS_SUCCEEDED(rv));
1589 
1590   rv = mgr->BeginBatch(nullptr);
1591   EXPECT_TRUE(NS_SUCCEEDED(rv));
1592 
1593   rv = mgr->DoTransaction(tximpl);
1594   EXPECT_EQ(rv, NS_ERROR_FAILURE);
1595 
1596   rv = mgr->EndBatch(false);
1597   EXPECT_TRUE(NS_SUCCEEDED(rv));
1598 
1599   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1600   EXPECT_TRUE(NS_SUCCEEDED(rv));
1601   EXPECT_EQ(u1, u2);
1602 
1603   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1604   EXPECT_TRUE(NS_SUCCEEDED(rv));
1605   EXPECT_EQ(r1, r2);
1606 
1607   rv = mgr->GetNumberOfUndoItems(&numitems);
1608   EXPECT_TRUE(NS_SUCCEEDED(rv));
1609   EXPECT_EQ(numitems, 1);
1610 
1611   rv = mgr->GetNumberOfRedoItems(&numitems);
1612   EXPECT_TRUE(NS_SUCCEEDED(rv));
1613   EXPECT_EQ(numitems, 1);
1614 
1615   /*******************************************************************
1616    *
1617    * Test transaction UndoTransaction() error:
1618    *
1619    *******************************************************************/
1620 
1621   tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);
1622 
1623   rv = mgr->BeginBatch(nullptr);
1624   EXPECT_TRUE(NS_SUCCEEDED(rv));
1625 
1626   rv = mgr->DoTransaction(tximpl);
1627   EXPECT_TRUE(NS_SUCCEEDED(rv));
1628 
1629   rv = mgr->EndBatch(false);
1630   EXPECT_TRUE(NS_SUCCEEDED(rv));
1631 
1632   u1 = u2 = r1 = r2 = nullptr;
1633 
1634   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1635   EXPECT_TRUE(NS_SUCCEEDED(rv));
1636 
1637   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1638   EXPECT_TRUE(NS_SUCCEEDED(rv));
1639 
1640   rv = mgr->UndoTransaction();
1641   EXPECT_EQ(rv, NS_ERROR_FAILURE);
1642 
1643   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1644   EXPECT_TRUE(NS_SUCCEEDED(rv));
1645   EXPECT_EQ(u1, u2);
1646 
1647   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1648   EXPECT_TRUE(NS_SUCCEEDED(rv));
1649   EXPECT_EQ(r1, r2);
1650 
1651   rv = mgr->GetNumberOfUndoItems(&numitems);
1652   EXPECT_TRUE(NS_SUCCEEDED(rv));
1653   EXPECT_EQ(numitems, 2);
1654 
1655   rv = mgr->GetNumberOfRedoItems(&numitems);
1656   EXPECT_TRUE(NS_SUCCEEDED(rv));
1657   EXPECT_EQ(numitems, 0);
1658 
1659   /*******************************************************************
1660    *
1661    * Test transaction RedoTransaction() error:
1662    *
1663    *******************************************************************/
1664 
1665   tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);
1666 
1667   rv = mgr->BeginBatch(nullptr);
1668   EXPECT_TRUE(NS_SUCCEEDED(rv));
1669 
1670   rv = mgr->DoTransaction(tximpl);
1671   EXPECT_TRUE(NS_SUCCEEDED(rv));
1672 
1673   rv = mgr->EndBatch(false);
1674   EXPECT_TRUE(NS_SUCCEEDED(rv));
1675 
1676   //
1677   // Execute a normal transaction to be used in a later test:
1678   //
1679 
1680   tximpl = factory->create(mgr, NONE_FLAG);
1681   rv = mgr->DoTransaction(tximpl);
1682   EXPECT_TRUE(NS_SUCCEEDED(rv));
1683 
1684   //
1685   // Undo the 2 transactions just executed.
1686   //
1687 
1688   for (i = 1; i <= 2; ++i) {
1689     rv = mgr->UndoTransaction();
1690     EXPECT_TRUE(NS_SUCCEEDED(rv));
1691   }
1692 
1693   //
1694   // The RedoErrorTransaction should now be at the top of the redo stack!
1695   //
1696 
1697   u1 = u2 = r1 = r2 = nullptr;
1698 
1699   rv = mgr->PeekUndoStack(getter_AddRefs(u1));
1700   EXPECT_TRUE(NS_SUCCEEDED(rv));
1701 
1702   rv = mgr->PeekRedoStack(getter_AddRefs(r1));
1703   EXPECT_TRUE(NS_SUCCEEDED(rv));
1704 
1705   rv = mgr->RedoTransaction();
1706   EXPECT_EQ(rv, NS_ERROR_FAILURE);
1707 
1708   rv = mgr->PeekUndoStack(getter_AddRefs(u2));
1709   EXPECT_TRUE(NS_SUCCEEDED(rv));
1710   EXPECT_EQ(u1, u2);
1711 
1712   rv = mgr->PeekRedoStack(getter_AddRefs(r2));
1713   EXPECT_TRUE(NS_SUCCEEDED(rv));
1714   EXPECT_EQ(r1, r2);
1715 
1716   rv = mgr->GetNumberOfUndoItems(&numitems);
1717   EXPECT_TRUE(NS_SUCCEEDED(rv));
1718   EXPECT_EQ(numitems, 2);
1719 
1720   rv = mgr->GetNumberOfRedoItems(&numitems);
1721   EXPECT_TRUE(NS_SUCCEEDED(rv));
1722   EXPECT_EQ(numitems, 2);
1723 
1724   /*******************************************************************
1725    *
1726    * Make sure that setting the transaction manager's max transaction
1727    * count to zero, clears both the undo and redo stacks, and executes
1728    * all new commands without pushing them on the undo stack!
1729    *
1730    *******************************************************************/
1731 
1732   rv = mgr->SetMaxTransactionCount(0);
1733   EXPECT_TRUE(NS_SUCCEEDED(rv));
1734 
1735   rv = mgr->GetNumberOfUndoItems(&numitems);
1736   EXPECT_TRUE(NS_SUCCEEDED(rv));
1737   EXPECT_EQ(numitems, 0);
1738 
1739   rv = mgr->GetNumberOfRedoItems(&numitems);
1740   EXPECT_TRUE(NS_SUCCEEDED(rv));
1741   EXPECT_EQ(numitems, 0);
1742 
1743   for (i = 1; i <= 20; i++) {
1744     tximpl = factory->create(mgr, NONE_FLAG);
1745 
1746     rv = mgr->BeginBatch(nullptr);
1747     EXPECT_TRUE(NS_SUCCEEDED(rv));
1748 
1749     rv = mgr->DoTransaction(tximpl);
1750     EXPECT_TRUE(NS_SUCCEEDED(rv));
1751 
1752     rv = mgr->EndBatch(false);
1753     EXPECT_TRUE(NS_SUCCEEDED(rv));
1754 
1755     rv = mgr->GetNumberOfUndoItems(&numitems);
1756     EXPECT_TRUE(NS_SUCCEEDED(rv));
1757     EXPECT_EQ(numitems, 0);
1758 
1759     rv = mgr->GetNumberOfRedoItems(&numitems);
1760     EXPECT_TRUE(NS_SUCCEEDED(rv));
1761     EXPECT_EQ(numitems, 0);
1762   }
1763 
1764   /*******************************************************************
1765    *
1766    * Release the transaction manager. Any transactions on the undo
1767    * and redo stack should automatically be released:
1768    *
1769    *******************************************************************/
1770 
1771   rv = mgr->SetMaxTransactionCount(-1);
1772   EXPECT_TRUE(NS_SUCCEEDED(rv));
1773 
1774   // Push 20 transactions on the undo stack:
1775 
1776   for (i = 1; i <= 20; i++) {
1777     tximpl = factory->create(mgr, NONE_FLAG);
1778 
1779     rv = mgr->BeginBatch(nullptr);
1780     EXPECT_TRUE(NS_SUCCEEDED(rv));
1781 
1782     rv = mgr->DoTransaction(tximpl);
1783     EXPECT_TRUE(NS_SUCCEEDED(rv));
1784 
1785     rv = mgr->EndBatch(false);
1786     EXPECT_TRUE(NS_SUCCEEDED(rv));
1787 
1788     rv = mgr->GetNumberOfUndoItems(&numitems);
1789     EXPECT_TRUE(NS_SUCCEEDED(rv));
1790     EXPECT_EQ(numitems, i);
1791 
1792     rv = mgr->GetNumberOfRedoItems(&numitems);
1793     EXPECT_TRUE(NS_SUCCEEDED(rv));
1794     EXPECT_EQ(numitems, 0);
1795   }
1796 
1797   for (i = 1; i <= 10; i++) {
1798     rv = mgr->UndoTransaction();
1799     EXPECT_TRUE(NS_SUCCEEDED(rv));
1800   }
1801   rv = mgr->GetNumberOfUndoItems(&numitems);
1802   EXPECT_TRUE(NS_SUCCEEDED(rv));
1803   EXPECT_EQ(numitems, 10);
1804 
1805   rv = mgr->GetNumberOfRedoItems(&numitems);
1806   EXPECT_TRUE(NS_SUCCEEDED(rv));
1807   EXPECT_EQ(numitems, 10);
1808 
1809   rv = mgr->Clear();
1810   EXPECT_TRUE(NS_SUCCEEDED(rv));
1811 }
1812 
TEST(TestTXMgr,SimpleBatchTest)1813 TEST(TestTXMgr, SimpleBatchTest) {
1814   /*******************************************************************
1815    *
1816    * Initialize globals for test.
1817    *
1818    *******************************************************************/
1819   reset_globals();
1820   sDoOrderArr = sSimpleBatchTestDoOrderArr;
1821   sUndoOrderArr = sSimpleBatchTestUndoOrderArr;
1822   sRedoOrderArr = sSimpleBatchTestRedoOrderArr;
1823 
1824   /*******************************************************************
1825    *
1826    * Run the quick batch test.
1827    *
1828    *******************************************************************/
1829 
1830   SimpleTransactionFactory factory;
1831   quick_batch_test(&factory);
1832 }
1833 
TEST(TestTXMgr,AggregationBatchTest)1834 TEST(TestTXMgr, AggregationBatchTest) {
1835   /*******************************************************************
1836    *
1837    * Initialize globals for test.
1838    *
1839    *******************************************************************/
1840 
1841   reset_globals();
1842   sDoOrderArr = sAggregateBatchTestDoOrderArr;
1843   sUndoOrderArr = sAggregateBatchTestUndoOrderArr;
1844   sRedoOrderArr = sAggregateBatchTestRedoOrderArr;
1845 
1846   /*******************************************************************
1847    *
1848    * Run the quick batch test.
1849    *
1850    *******************************************************************/
1851 
1852   AggregateTransactionFactory factory(3, 2, BATCH_FLAG);
1853 
1854   quick_batch_test(&factory);
1855 }
1856 
1857 /**
1858  * Create 'iterations * (iterations + 1) / 2' transactions;
1859  * do/undo/redo/undo them.
1860  **/
stress_test(TestTransactionFactory * factory,int32_t iterations)1861 void stress_test(TestTransactionFactory *factory, int32_t iterations) {
1862   /*******************************************************************
1863    *
1864    * Create a transaction manager:
1865    *
1866    *******************************************************************/
1867 
1868   nsresult rv;
1869   nsCOMPtr<nsITransactionManager> mgr =
1870       do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &rv);
1871   ASSERT_TRUE(NS_SUCCEEDED(rv));
1872   ASSERT_TRUE(mgr);
1873 
1874   int32_t i, j;
1875 
1876   for (i = 1; i <= iterations; i++) {
1877     /*******************************************************************
1878      *
1879      * Create and execute a bunch of transactions:
1880      *
1881      *******************************************************************/
1882 
1883     for (j = 1; j <= i; j++) {
1884       RefPtr<TestTransaction> tximpl = factory->create(mgr, NONE_FLAG);
1885       rv = mgr->DoTransaction(tximpl);
1886       EXPECT_TRUE(NS_SUCCEEDED(rv));
1887     }
1888 
1889     /*******************************************************************
1890      *
1891      * Undo all the transactions:
1892      *
1893      *******************************************************************/
1894 
1895     for (j = 1; j <= i; j++) {
1896       rv = mgr->UndoTransaction();
1897       EXPECT_TRUE(NS_SUCCEEDED(rv));
1898     }
1899 
1900     /*******************************************************************
1901      *
1902      * Redo all the transactions:
1903      *
1904      *******************************************************************/
1905 
1906     for (j = 1; j <= i; j++) {
1907       rv = mgr->RedoTransaction();
1908       EXPECT_TRUE(NS_SUCCEEDED(rv));
1909     }
1910 
1911     /*******************************************************************
1912      *
1913      * Undo all the transactions again so that they all end up on
1914      * the redo stack for pruning the next time we execute a new
1915      * transaction
1916      *
1917      *******************************************************************/
1918 
1919     for (j = 1; j <= i; j++) {
1920       rv = mgr->UndoTransaction();
1921       EXPECT_TRUE(NS_SUCCEEDED(rv));
1922     }
1923   }
1924 
1925   rv = mgr->Clear();
1926   EXPECT_TRUE(NS_SUCCEEDED(rv));
1927 }
1928 
TEST(TestTXMgr,SimpleStressTest)1929 TEST(TestTXMgr, SimpleStressTest) {
1930   /*******************************************************************
1931    *
1932    * Initialize globals for test.
1933    *
1934    *******************************************************************/
1935 
1936   reset_globals();
1937 
1938   /*******************************************************************
1939    *
1940    * Do the stress test:
1941    *
1942    *******************************************************************/
1943 
1944   SimpleTransactionFactory factory;
1945 
1946   int32_t iterations =
1947 #ifdef DEBUG
1948       10
1949 #else
1950       //
1951       // 1500 iterations sends 1,125,750 transactions through the system!!
1952       //
1953       1500
1954 #endif
1955       ;
1956   stress_test(&factory, iterations);
1957 }
1958 
TEST(TestTXMgr,AggregationStressTest)1959 TEST(TestTXMgr, AggregationStressTest) {
1960   /*******************************************************************
1961    *
1962    * Initialize globals for test.
1963    *
1964    *******************************************************************/
1965 
1966   reset_globals();
1967 
1968   /*******************************************************************
1969    *
1970    * Do the stress test:
1971    *
1972    *******************************************************************/
1973 
1974   AggregateTransactionFactory factory(3, 4);
1975 
1976   int32_t iterations =
1977 #ifdef DEBUG
1978       10
1979 #else
1980       //
1981       // 500 iterations sends 2,630,250 transactions through the system!!
1982       //
1983       500
1984 #endif
1985       ;
1986   stress_test(&factory, iterations);
1987 }
1988 
TEST(TestTXMgr,AggregationBatchStressTest)1989 TEST(TestTXMgr, AggregationBatchStressTest) {
1990   /*******************************************************************
1991    *
1992    * Initialize globals for test.
1993    *
1994    *******************************************************************/
1995 
1996   reset_globals();
1997 
1998   /*******************************************************************
1999    *
2000    * Do the stress test:
2001    *
2002    *******************************************************************/
2003 
2004   AggregateTransactionFactory factory(3, 4, BATCH_FLAG);
2005 
2006   int32_t iterations =
2007 #ifdef DEBUG
2008       10
2009 #else
2010 #if defined(MOZ_ASAN) || defined(MOZ_WIDGET_ANDROID)
2011       // See Bug 929985: 500 is too many for ASAN and Android, 100 is safe.
2012       100
2013 #else
2014       //
2015       // 500 iterations sends 2,630,250 transactions through the system!!
2016       //
2017       500
2018 #endif
2019 #endif
2020       ;
2021   stress_test(&factory, iterations);
2022 }
2023