• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.sdkuilib.internal.repository.sdkman2;
18 
19 import com.android.sdklib.internal.repository.BrokenPackage;
20 import com.android.sdklib.internal.repository.MockAddonPackage;
21 import com.android.sdklib.internal.repository.MockBrokenPackage;
22 import com.android.sdklib.internal.repository.MockEmptyPackage;
23 import com.android.sdklib.internal.repository.MockExtraPackage;
24 import com.android.sdklib.internal.repository.MockPlatformPackage;
25 import com.android.sdklib.internal.repository.MockPlatformToolPackage;
26 import com.android.sdklib.internal.repository.MockToolPackage;
27 import com.android.sdklib.internal.repository.Package;
28 import com.android.sdklib.internal.repository.SdkRepoSource;
29 import com.android.sdklib.internal.repository.SdkSource;
30 import com.android.sdklib.repository.PkgProps;
31 import com.android.sdkuilib.internal.repository.MockUpdaterData;
32 
33 import java.util.Properties;
34 
35 import junit.framework.TestCase;
36 
37 public class PackagesDiffLogicTest extends TestCase {
38 
39     private PackagesDiffLogic m;
40     private MockUpdaterData u;
41 
42     @Override
setUp()43     protected void setUp() throws Exception {
44         super.setUp();
45 
46         u = new MockUpdaterData();
47         m = new PackagesDiffLogic(u);
48     }
49 
50     @Override
tearDown()51     protected void tearDown() throws Exception {
52         super.tearDown();
53     }
54 
55     // ----
56     //
57     // Test Details Note: the way load is implemented in PackageLoader, the
58     // loader processes each source and then for each source the packages are added
59     // to a list and the sorting algorithm is called with that list. Thus for
60     // one load, many calls to the sortByX/Y happen, with the list progressively
61     // being populated.
62     // However when the user switches sorting algorithm, the package list is not
63     // reloaded and is processed at once.
64 
testSortByApi_Empty()65     public void testSortByApi_Empty() {
66         m.updateStart();
67         assertFalse(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[0]));
68         assertFalse(m.updateEnd(true /*sortByApi*/));
69 
70         // We also keep these 2 categories even if they contain nothing
71         assertEquals(
72                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
73                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=0>\n",
74                getTree(m, true /*displaySortByApi*/));
75     }
76 
testSortByApi_AddSamePackage()77     public void testSortByApi_AddSamePackage() {
78         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
79 
80         m.updateStart();
81         // First insert local packages
82         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
83                 new MockEmptyPackage(src1, "some pkg", 1)
84         }));
85 
86         assertEquals(
87                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
88                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
89                 "-- <INSTALLED, pkg:MockEmptyPackage 'some pkg' rev=1>\n",
90                 getTree(m, true /*displaySortByApi*/));
91 
92         // Insert the next source
93         // Same package as the one installed, so we don't display it
94         assertFalse(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
95                 new MockEmptyPackage(src1, "some pkg", 1)
96         }));
97 
98         assertFalse(m.updateEnd(true /*sortByApi*/));
99 
100         assertEquals(
101                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
102                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
103                 "-- <INSTALLED, pkg:MockEmptyPackage 'some pkg' rev=1>\n",
104                 getTree(m, true /*displaySortByApi*/));
105     }
106 
testSortByApi_AddOtherPackage()107     public void testSortByApi_AddOtherPackage() {
108         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
109 
110         m.updateStart();
111         // First insert local packages
112         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
113                 new MockEmptyPackage(src1, "some pkg", 1)
114         }));
115 
116         assertEquals(
117                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
118                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
119                 "-- <INSTALLED, pkg:MockEmptyPackage 'some pkg' rev=1>\n",
120                 getTree(m, true /*displaySortByApi*/));
121 
122         // Insert the next source
123         // Not the same package as the one installed, so we'll display it
124         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
125                 new MockEmptyPackage(src1, "other pkg", 1)
126         }));
127 
128         assertFalse(m.updateEnd(true /*sortByApi*/));
129 
130         assertEquals(
131                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
132                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
133                 "-- <INSTALLED, pkg:MockEmptyPackage 'some pkg' rev=1>\n" +
134                 "-- <NEW, pkg:MockEmptyPackage 'other pkg' rev=1>\n",
135                 getTree(m, true /*displaySortByApi*/));
136     }
137 
testSortByApi_Update1()138     public void testSortByApi_Update1() {
139         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
140 
141         // Typical case: user has a locally installed package in revision 1
142         // The display list after sort should show that installed package.
143         m.updateStart();
144         // First insert local packages
145         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
146                 new MockEmptyPackage(src1, "type1", 1)
147         }));
148 
149         assertEquals(
150                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
151                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
152                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1>\n",
153                 getTree(m, true /*displaySortByApi*/));
154 
155         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
156                 new MockEmptyPackage(src1, "type1", 4),
157                 new MockEmptyPackage(src1, "type1", 2)
158         }));
159 
160         assertFalse(m.updateEnd(true /*sortByApi*/));
161 
162         assertEquals(
163                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
164                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
165                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=4>\n",
166                 getTree(m, true /*displaySortByApi*/));
167     }
168 
testSortByApi_Reload()169     public void testSortByApi_Reload() {
170         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
171 
172         // First load reveals a package local package and its update
173         m.updateStart();
174         // First insert local packages
175         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
176                 new MockEmptyPackage(src1, "type1", 1)
177         }));
178         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
179                 new MockEmptyPackage(src1, "type1", 2)
180         }));
181 
182         assertFalse(m.updateEnd(true /*sortByApi*/));
183 
184         assertEquals(
185                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
186                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
187                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
188                 getTree(m, true /*displaySortByApi*/));
189 
190         // Now simulate a reload that clears the package list and creates similar
191         // objects but not the same references. The only difference is that updateXyz
192         // returns false since nothing changes.
193 
194         m.updateStart();
195         // First insert local packages
196         assertFalse(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
197                 new MockEmptyPackage(src1, "type1", 1)
198         }));
199         assertFalse(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
200                 new MockEmptyPackage(src1, "type1", 2)
201         }));
202 
203         assertFalse(m.updateEnd(true /*sortByApi*/));
204 
205         assertEquals(
206                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
207                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
208                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
209                 getTree(m, true /*displaySortByApi*/));
210     }
211 
testSortByApi_InstallPackage()212     public void testSortByApi_InstallPackage() {
213         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
214 
215         // First load reveals a new package
216         m.updateStart();
217         // No local packages at first
218         assertFalse(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[0]));
219         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
220                 new MockEmptyPackage(src1, "type1", 1)
221         }));
222 
223         assertFalse(m.updateEnd(true /*sortByApi*/));
224 
225         assertEquals(
226                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
227                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
228                 "-- <NEW, pkg:MockEmptyPackage 'type1' rev=1>\n",
229                 getTree(m, true /*displaySortByApi*/));
230 
231         // Install it.
232         m.updateStart();
233         // local packages
234         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
235                 new MockEmptyPackage(src1, "type1", 1)
236         }));
237         assertFalse(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
238                 new MockEmptyPackage(src1, "type1", 1)
239         }));
240 
241         assertFalse(m.updateEnd(true /*sortByApi*/));
242 
243         assertEquals(
244                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
245                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
246                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1>\n",
247                 getTree(m, true /*displaySortByApi*/));
248 
249         // Load reveals an update
250         m.updateStart();
251         // local packages
252         assertFalse(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
253                 new MockEmptyPackage(src1, "type1", 1)
254         }));
255         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
256                 new MockEmptyPackage(src1, "type1", 2)
257         }));
258 
259         assertFalse(m.updateEnd(true /*sortByApi*/));
260 
261         assertEquals(
262                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
263                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
264                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
265                 getTree(m, true /*displaySortByApi*/));
266     }
267 
testSortByApi_DeletePackage()268     public void testSortByApi_DeletePackage() {
269         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
270 
271         // We have an installed package
272         m.updateStart();
273         // local packages
274         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
275                 new MockEmptyPackage(src1, "type1", 1)
276         }));
277         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
278                 new MockEmptyPackage(src1, "type1", 2)
279         }));
280 
281         assertFalse(m.updateEnd(true /*sortByApi*/));
282 
283         assertEquals(
284                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
285                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
286                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
287                 getTree(m, true /*displaySortByApi*/));
288 
289         // User now deletes the installed package.
290         m.updateStart();
291         // No local packages
292         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[0]));
293         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
294                 new MockEmptyPackage(src1, "type1", 1)
295         }));
296 
297         assertFalse(m.updateEnd(true /*sortByApi*/));
298 
299         assertEquals(
300                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
301                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
302                 "-- <NEW, pkg:MockEmptyPackage 'type1' rev=1>\n",
303                 getTree(m, true /*displaySortByApi*/));
304     }
305 
testSortByApi_NoRemoteSources()306     public void testSortByApi_NoRemoteSources() {
307         SdkSource src1 = new SdkRepoSource("http://example.com/url1", "repo1");
308         SdkSource src2 = new SdkRepoSource("http://example.com/url2", "repo2");
309 
310         // We have a couple installed packages
311         m.updateStart();
312         // local packages
313         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
314                 new MockToolPackage(src1, 10, 3),
315                 new MockPlatformToolPackage(src1, 3),
316                 new MockExtraPackage(src2, "carrier", "custom_rom", 1, 0),
317                 new MockExtraPackage(src2, "android", "usb_driver", 5, 3),
318         }));
319         // and no remote sources have been loaded (e.g. because there's no network)
320         assertFalse(m.updateEnd(true /*sortByApi*/));
321 
322         assertEquals(
323                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
324                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
325                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
326                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
327                 "-- <INSTALLED, pkg:Android USB Driver package, revision 5>\n" +
328                 "-- <INSTALLED, pkg:Carrier Custom Rom package, revision 1>\n",
329                 getTree(m, true /*displaySortByApi*/));
330 
331         assertEquals(
332                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
333                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
334                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
335                 "PkgCategorySource <source=repo2 (example.com), #items=2>\n" +
336                 "-- <INSTALLED, pkg:Android USB Driver package, revision 5>\n" +
337                 "-- <INSTALLED, pkg:Carrier Custom Rom package, revision 1>\n",
338                 getTree(m, false /*displaySortByApi*/));
339     }
340 
testSortByApi_CompleteUpdate()341     public void testSortByApi_CompleteUpdate() {
342         SdkSource src1 = new SdkRepoSource("http://1.example.com/url1", "repo1");
343         SdkSource src2 = new SdkRepoSource("http://2.example.com/url2", "repo2");
344 
345         // Resulting categories are sorted by Tools, descending platform API and finally Extras.
346         // Addons are sorted by name within their API.
347         // Extras are sorted by vendor name.
348         // The order packages are added to the mAllPkgItems list is purposedly different from
349         // the final order we get.
350 
351         // First update has the typical tools and a couple extras
352         m.updateStart();
353 
354         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
355                 new MockToolPackage(src1, 10, 3),
356                 new MockPlatformToolPackage(src1, 3),
357                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
358         }));
359         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
360                 new MockToolPackage(src1, 10, 3),
361                 new MockPlatformToolPackage(src1, 3),
362                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
363                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
364         }));
365         assertFalse(m.updateEnd(true /*sortByApi*/));
366 
367         assertEquals(
368                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
369                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
370                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
371                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
372                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
373                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
374                 getTree(m, true /*displaySortByApi*/));
375 
376         // Next update adds platforms and addon, sorted in a category based on their API level
377         m.updateStart();
378         MockPlatformPackage p1;
379         MockPlatformPackage p2;
380 
381         assertTrue(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
382                 new MockToolPackage(src1, 10, 3),
383                 new MockPlatformToolPackage(src1, 3),
384                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
385                 // second update
386                 p1 = new MockPlatformPackage(src1, 1, 2, 3),  // API 1
387                 new MockPlatformPackage(src1, 3, 6, 3),
388                 new MockAddonPackage(src2, "addon A", p1, 5),
389         }));
390         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
391                 new MockToolPackage(src1, 10, 3),
392                 new MockPlatformToolPackage(src1, 3),
393                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
394                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
395                 // second update
396                 p2 = new MockPlatformPackage(src1, 2, 4, 3),    // API 2
397         }));
398         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
399                 new MockAddonPackage(src2, "addon C", p2, 9),
400                 new MockAddonPackage(src2, "addon A", p1, 6),
401                 new MockAddonPackage(src2, "addon B", p2, 7),
402                 // the rev 8 update will be ignored since there's a rev 9 coming after
403                 new MockAddonPackage(src2, "addon B", p2, 8),
404                 new MockAddonPackage(src2, "addon B", p2, 9),
405         }));
406         assertFalse(m.updateEnd(true /*sortByApi*/));
407 
408         assertEquals(
409                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
410                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
411                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
412                 "PkgCategoryApi <API=API 3, label=Android android-3 (API 3), #items=1>\n" +
413                 "-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
414                 "PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=3>\n" +
415                 "-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
416                 "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
417                 "-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
418                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
419                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
420                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
421                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
422                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
423                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
424                 getTree(m, true /*displaySortByApi*/));
425 
426         // Reloading the same thing should have no impact except for the update methods
427         // returning false when they don't change the current list.
428         m.updateStart();
429 
430         assertFalse(m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
431                 new MockToolPackage(src1, 10, 3),
432                 new MockPlatformToolPackage(src1, 3),
433                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
434                 // second update
435                 p1 = new MockPlatformPackage(src1, 1, 2, 3),
436                 new MockPlatformPackage(src1, 3, 6, 3),
437                 new MockAddonPackage(src2, "addon A", p1, 5),
438         }));
439         assertFalse(m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
440                 new MockToolPackage(src1, 10, 3),
441                 new MockPlatformToolPackage(src1, 3),
442                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
443                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
444                 // second update
445                 p2 = new MockPlatformPackage(src1, 2, 4, 3),
446         }));
447         assertTrue(m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
448                 new MockAddonPackage(src2, "addon C", p2, 9),
449                 new MockAddonPackage(src2, "addon A", p1, 6),
450                 new MockAddonPackage(src2, "addon B", p2, 7),
451                 // the rev 8 update will be ignored since there's a rev 9 coming after
452                 // however as a side effect it makes the update method return true as it
453                 // incorporated the update.
454                 new MockAddonPackage(src2, "addon B", p2, 8),
455                 new MockAddonPackage(src2, "addon B", p2, 9),
456         }));
457         assertFalse(m.updateEnd(true /*sortByApi*/));
458 
459         assertEquals(
460                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
461                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
462                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
463                 "PkgCategoryApi <API=API 3, label=Android android-3 (API 3), #items=1>\n" +
464                 "-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
465                 "PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=3>\n" +
466                 "-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
467                 "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
468                 "-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
469                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
470                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
471                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n" +
472                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
473                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
474                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
475                 getTree(m, true /*displaySortByApi*/));
476     }
477 
478     // ----
479 
testSortBySource_Empty()480     public void testSortBySource_Empty() {
481         m.updateStart();
482         assertFalse(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[0]));
483         // UpdateEnd returns true since it removed the synthetic "unknown source" category
484         assertTrue(m.updateEnd(false /*sortByApi*/));
485 
486         assertTrue(m.getCategories(false /*sortByApi*/).isEmpty());
487 
488         assertEquals(
489                 "",
490                 getTree(m, false /*displaySortByApi*/));
491     }
492 
testSortBySource_AddPackages()493     public void testSortBySource_AddPackages() {
494         // Since we're sorting by source, items are grouped under their source
495         // even if installed. The 'local' source is only for installed items for
496         // which we don't know the source.
497         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
498 
499         m.updateStart();
500         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
501                 new MockEmptyPackage(src1, "known source", 2),
502                 new MockEmptyPackage(null, "unknown source", 3),
503         }));
504 
505         assertEquals(
506                 "PkgCategorySource <source=Local Packages (no.source), #items=1>\n" +
507                 "-- <INSTALLED, pkg:MockEmptyPackage 'unknown source' rev=3>\n" +
508                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
509                 "-- <INSTALLED, pkg:MockEmptyPackage 'known source' rev=2>\n",
510                 getTree(m, false /*displaySortByApi*/));
511 
512         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
513                 new MockEmptyPackage(src1, "new", 1),
514         }));
515 
516         assertFalse(m.updateEnd(false /*sortByApi*/));
517 
518         assertEquals(
519                 "PkgCategorySource <source=Local Packages (no.source), #items=1>\n" +
520                 "-- <INSTALLED, pkg:MockEmptyPackage 'unknown source' rev=3>\n" +
521                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
522                 "-- <NEW, pkg:MockEmptyPackage 'new' rev=1>\n" +
523                 "-- <INSTALLED, pkg:MockEmptyPackage 'known source' rev=2>\n",
524                 getTree(m, false /*displaySortByApi*/));
525     }
526 
testSortBySource_Update1()527     public void testSortBySource_Update1() {
528 
529         // Typical case: user has a locally installed package in revision 1
530         // The display list after sort should show that instaled package.
531         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
532         m.updateStart();
533         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
534                 new MockEmptyPackage(src1, "type1", 1),
535         }));
536 
537         assertEquals(
538                 "PkgCategorySource <source=Local Packages (no.source), #items=0>\n" +
539                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
540                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1>\n",
541                 getTree(m, false /*displaySortByApi*/));
542 
543         // Edge case: the source reveals an update in revision 2. It is ignored since
544         // we already have a package in rev 4.
545 
546         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
547                 new MockEmptyPackage(src1, "type1", 4),
548                 new MockEmptyPackage(src1, "type1", 2),
549         }));
550 
551         assertTrue(m.updateEnd(false /*sortByApi*/));
552 
553         assertEquals(
554                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
555                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=4>\n",
556                 getTree(m, false /*displaySortByApi*/));
557     }
558 
testSortBySource_Reload()559     public void testSortBySource_Reload() {
560 
561         // First load reveals a package local package and its update
562         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
563         m.updateStart();
564         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
565                 new MockEmptyPackage(src1, "type1", 1),
566         }));
567         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
568                 new MockEmptyPackage(src1, "type1", 2),
569         }));
570         assertTrue(m.updateEnd(false /*sortByApi*/));
571 
572         assertEquals(
573                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
574                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
575                 getTree(m, false /*displaySortByApi*/));
576 
577         // Now simulate a reload that clears the package list and creates similar
578         // objects but not the same references. Update methods return false since
579         // they don't change anything.
580         m.updateStart();
581         assertFalse(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
582                 new MockEmptyPackage(src1, "type1", 1),
583         }));
584         assertFalse(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
585                 new MockEmptyPackage(src1, "type1", 2),
586         }));
587         assertTrue(m.updateEnd(false /*sortByApi*/));
588 
589         assertEquals(
590                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
591                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
592                 getTree(m, false /*displaySortByApi*/));
593     }
594 
testSortBySource_InstallPackage()595     public void testSortBySource_InstallPackage() {
596 
597         // First load reveals a new package
598         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
599         m.updateStart();
600         // no local package
601         assertFalse(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[0]));
602         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
603                 new MockEmptyPackage(src1, "type1", 1),
604         }));
605         assertTrue(m.updateEnd(false /*sortByApi*/));
606 
607         assertEquals(
608                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
609                 "-- <NEW, pkg:MockEmptyPackage 'type1' rev=1>\n",
610                 getTree(m, false /*displaySortByApi*/));
611 
612 
613         // Install it. The display only shows the installed one, 'hiding' the remote package
614         m.updateStart();
615         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
616                 new MockEmptyPackage(src1, "type1", 1),
617         }));
618         assertFalse(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
619                 new MockEmptyPackage(src1, "type1", 1),
620         }));
621         assertTrue(m.updateEnd(false /*sortByApi*/));
622 
623         assertEquals(
624                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
625                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1>\n",
626                 getTree(m, false /*displaySortByApi*/));
627 
628         // Now we have an update
629         m.updateStart();
630         assertFalse(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
631                 new MockEmptyPackage(src1, "type1", 1),
632         }));
633         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
634                 new MockEmptyPackage(src1, "type1", 2),
635         }));
636         assertTrue(m.updateEnd(false /*sortByApi*/));
637 
638         assertEquals(
639                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
640                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n",
641                 getTree(m, false /*displaySortByApi*/));
642     }
643 
testSortBySource_DeletePackage()644     public void testSortBySource_DeletePackage() {
645         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
646 
647         // Start with an installed package and its matching remote package
648         m.updateStart();
649         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
650                 new MockEmptyPackage(src1, "type1", 1),
651         }));
652         assertFalse(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
653                 new MockEmptyPackage(src1, "type1", 1),
654         }));
655         assertTrue(m.updateEnd(false /*sortByApi*/));
656 
657         assertEquals(
658                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
659                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1>\n",
660                 getTree(m, false /*displaySortByApi*/));
661 
662         // User now deletes the installed package.
663         m.updateStart();
664         // no local package
665         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[0]));
666         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
667                 new MockEmptyPackage(src1, "type1", 1),
668         }));
669         assertTrue(m.updateEnd(false /*sortByApi*/));
670 
671         assertEquals(
672                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
673                 "-- <NEW, pkg:MockEmptyPackage 'type1' rev=1>\n",
674                 getTree(m, false /*displaySortByApi*/));
675     }
676 
testSortBySource_CompleteUpdate()677     public void testSortBySource_CompleteUpdate() {
678         SdkSource src1 = new SdkRepoSource("http://1.example.com/url1", "repo1");
679         SdkSource src2 = new SdkRepoSource("http://2.example.com/url2", "repo2");
680 
681         // First update has the typical tools and a couple extras
682         m.updateStart();
683 
684         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
685                 new MockToolPackage(src1, 10, 3),
686                 new MockPlatformToolPackage(src1, 3),
687                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
688         }));
689         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
690                 new MockToolPackage(src1, 10, 3),
691                 new MockPlatformToolPackage(src1, 3),
692                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
693                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
694         }));
695         assertTrue(m.updateEnd(false /*sortByApi*/));
696 
697         assertEquals(
698                 "PkgCategorySource <source=repo1 (1.example.com), #items=4>\n" +
699                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
700                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
701                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
702                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n",
703                 getTree(m, false /*displaySortByApi*/));
704 
705         // Next update adds platforms and addon, sorted in a category based on their API level
706         m.updateStart();
707         MockPlatformPackage p1;
708         MockPlatformPackage p2;
709 
710         assertTrue(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
711                 new MockToolPackage(src1, 10, 3),
712                 new MockPlatformToolPackage(src1, 3),
713                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
714                 // second update
715                 p1 = new MockPlatformPackage(src1, 1, 2, 3),  // API 1
716                 new MockPlatformPackage(src1, 3, 6, 3),       // API 3
717                 new MockAddonPackage(src2, "addon A", p1, 5),
718         }));
719         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
720                 new MockToolPackage(src1, 10, 3),
721                 new MockPlatformToolPackage(src1, 3),
722                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
723                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
724                 // second update
725                 p2 = new MockPlatformPackage(src1, 2, 4, 3),    // API 2
726         }));
727         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src2, new Package[] {
728                 new MockAddonPackage(src2, "addon C", p2, 9),
729                 new MockAddonPackage(src2, "addon A", p1, 6),
730                 new MockAddonPackage(src2, "addon B", p2, 7),
731                 // the rev 8 update will be ignored since there's a rev 9 coming after
732                 new MockAddonPackage(src2, "addon B", p2, 8),
733                 new MockAddonPackage(src2, "addon B", p2, 9),
734         }));
735         assertTrue(m.updateEnd(false /*sortByApi*/));
736 
737         assertEquals(
738                 "PkgCategorySource <source=repo1 (1.example.com), #items=7>\n" +
739                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
740                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
741                 "-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
742                 "-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
743                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
744                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
745                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n" +
746                 "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
747                 "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
748                 "-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
749                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n",
750                 getTree(m, false /*displaySortByApi*/));
751 
752         // Reloading the same thing should have no impact except for the update methods
753         // returning false when they don't change the current list.
754         m.updateStart();
755 
756         assertFalse(m.updateSourcePackages(false /*sortByApi*/, null /*locals*/, new Package[] {
757                 new MockToolPackage(src1, 10, 3),
758                 new MockPlatformToolPackage(src1, 3),
759                 new MockExtraPackage(src1, "android", "usb_driver", 4, 3),
760                 // second update
761                 p1 = new MockPlatformPackage(src1, 1, 2, 3),
762                 new MockPlatformPackage(src1, 3, 6, 3),
763                 new MockAddonPackage(src2, "addon A", p1, 5),
764         }));
765         assertFalse(m.updateSourcePackages(false /*sortByApi*/, src1, new Package[] {
766                 new MockToolPackage(src1, 10, 3),
767                 new MockPlatformToolPackage(src1, 3),
768                 new MockExtraPackage(src1, "carrier", "custom_rom", 1, 0),
769                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
770                 // second update
771                 p2 = new MockPlatformPackage(src1, 2, 4, 3),
772         }));
773         assertTrue(m.updateSourcePackages(false /*sortByApi*/, src2, new Package[] {
774                 new MockAddonPackage(src2, "addon C", p2, 9),
775                 new MockAddonPackage(src2, "addon A", p1, 6),
776                 new MockAddonPackage(src2, "addon B", p2, 7),
777                 // the rev 8 update will be ignored since there's a rev 9 coming after
778                 // however as a side effect it makes the update method return true as it
779                 // incorporated the update.
780                 new MockAddonPackage(src2, "addon B", p2, 8),
781                 new MockAddonPackage(src2, "addon B", p2, 9),
782         }));
783         assertTrue(m.updateEnd(false /*sortByApi*/));
784 
785         assertEquals(
786                 "PkgCategorySource <source=repo1 (1.example.com), #items=7>\n" +
787                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
788                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
789                 "-- <INSTALLED, pkg:SDK Platform Android android-3, API 3, revision 6>\n" +
790                 "-- <NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
791                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
792                 "-- <INSTALLED, pkg:Android USB Driver package, revision 4, updated by:Android USB Driver package, revision 5>\n" +
793                 "-- <NEW, pkg:Carrier Custom Rom package, revision 1>\n" +
794                 "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
795                 "-- <NEW, pkg:addon B by vendor 2, Android API 2, revision 7, updated by:addon B by vendor 2, Android API 2, revision 9>\n" +
796                 "-- <NEW, pkg:addon C by vendor 2, Android API 2, revision 9>\n" +
797                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5, updated by:addon A by vendor 1, Android API 1, revision 6>\n",
798                 getTree(m, false /*displaySortByApi*/));
799     }
800 
801     // ----
802 
testIsFirstLoadComplete()803     public void testIsFirstLoadComplete() {
804         // isFirstLoadComplete is a simple toggle that goes from true to false when read once
805         assertTrue(m.isFirstLoadComplete());
806         assertFalse(m.isFirstLoadComplete());
807         assertFalse(m.isFirstLoadComplete());
808     }
809 
testCheckNewUpdateItems_NewOnly()810     public void testCheckNewUpdateItems_NewOnly() {
811         // Populate the list with a few items and an update
812         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
813         m.updateStart();
814         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
815                 new MockEmptyPackage(src1, "has update", 1),
816                 new MockEmptyPackage(src1, "no update", 4)
817         });
818         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
819                 new MockEmptyPackage(src1, "has update", 2),
820                 new MockEmptyPackage(src1, "new stuff", 3),
821         });
822         m.updateEnd(true /*sortByApi*/);
823         // Nothing is checked at first
824         assertEquals(
825                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
826                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=3>\n" +
827                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
828                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
829                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
830                 getTree(m, true /*displaySortByApi*/));
831         assertEquals(
832                 "PkgCategorySource <source=repo1 (example.com), #items=3>\n" +
833                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
834                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
835                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
836                 getTree(m, false /*displaySortByApi*/));
837 
838         // Now request to check new items only
839         m.checkNewUpdateItems(true, false);
840 
841         assertEquals(
842                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
843                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=3>\n" +
844                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
845                 "-- < * NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
846                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
847                 getTree(m, true /*displaySortByApi*/));
848         assertEquals(
849                 "PkgCategorySource <source=repo1 (example.com), #items=3>\n" +
850                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
851                 "-- < * NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
852                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
853                 getTree(m, false /*displaySortByApi*/));
854     }
855 
testCheckNewUpdateItems_UpdateOnly()856     public void testCheckNewUpdateItems_UpdateOnly() {
857         // Populate the list with a few items and an update
858         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
859         m.updateStart();
860         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
861                 new MockEmptyPackage(src1, "has update", 1),
862                 new MockEmptyPackage(src1, "no update", 4)
863         });
864         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
865                 new MockEmptyPackage(src1, "has update", 2),
866                 new MockEmptyPackage(src1, "new stuff", 3),
867         });
868         m.updateEnd(true /*sortByApi*/);
869         // Nothing is checked at first
870         assertEquals(
871                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
872                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=3>\n" +
873                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
874                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
875                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
876                 getTree(m, true /*displaySortByApi*/));
877         assertEquals(
878                 "PkgCategorySource <source=repo1 (example.com), #items=3>\n" +
879                 "-- <INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
880                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
881                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
882                 getTree(m, false /*displaySortByApi*/));
883 
884         // Now request to check update items only
885         m.checkNewUpdateItems(false, true);
886 
887         assertEquals(
888                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
889                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=3>\n" +
890                 "-- < * INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
891                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
892                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
893                 getTree(m, true /*displaySortByApi*/));
894         assertEquals(
895                 "PkgCategorySource <source=repo1 (example.com), #items=3>\n" +
896                 "-- < * INSTALLED, pkg:MockEmptyPackage 'has update' rev=1, updated by:MockEmptyPackage 'has update' rev=2>\n" +
897                 "-- <NEW, pkg:MockEmptyPackage 'new stuff' rev=3>\n" +
898                 "-- <INSTALLED, pkg:MockEmptyPackage 'no update' rev=4>\n",
899                 getTree(m, false /*displaySortByApi*/));
900     }
901 
testCheckNewUpdateItems_SelectInitial()902     public void testCheckNewUpdateItems_SelectInitial() {
903         // Populate the list with typical items: tools, platforms tools, extras, 2 platforms.
904         // With nothing installed, this should pick the tools, extras and the top platform.
905 
906         SdkSource src1 = new SdkRepoSource("http://1.example.com/url1", "repo1");
907         SdkSource src2 = new SdkRepoSource("http://2.example.com/url2", "repo2");
908 
909         m.updateStart();
910         MockPlatformPackage p1;
911         MockPlatformPackage p2;
912 
913         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
914                 new MockToolPackage(src1, 10, 3),
915                 new MockPlatformToolPackage(src1, 3),
916                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
917                 p1 = new MockPlatformPackage(src1, 1, 2, 3),    // API 1
918                 p2 = new MockPlatformPackage(src1, 2, 4, 3),    // API 2
919         });
920         m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
921                 new MockAddonPackage(src2, "addon A", p1, 5),
922                 new MockAddonPackage(src2, "addon B", p2, 7),
923                 new MockExtraPackage(src2, "carrier", "custom_rom", 1, 0),
924         });
925         m.updateEnd(true /*sortByApi*/);
926 
927         m.checkNewUpdateItems(true, true);
928 
929         assertEquals(
930                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
931                 "-- < * NEW, pkg:Android SDK Tools, revision 10>\n" +
932                 "-- < * NEW, pkg:Android SDK Platform-tools, revision 3>\n" +
933                 "PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=2>\n" +
934                 "-- < * NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
935                 "-- < * NEW, pkg:addon B by vendor 2, Android API 2, revision 7>\n" +
936                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
937                 "-- <NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
938                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
939                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
940                 "-- < * NEW, pkg:Android USB Driver package, revision 5>\n" +
941                 "-- < * NEW, pkg:Carrier Custom Rom package, revision 1>\n",
942                 getTree(m, true /*displaySortByApi*/));
943         assertEquals(
944                 "PkgCategorySource <source=repo1 (1.example.com), #items=5>\n" +
945                 "-- < * NEW, pkg:Android SDK Tools, revision 10>\n" +
946                 "-- < * NEW, pkg:Android SDK Platform-tools, revision 3>\n" +
947                 "-- < * NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
948                 "-- <NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
949                 "-- < * NEW, pkg:Android USB Driver package, revision 5>\n" +
950                 "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
951                 "-- < * NEW, pkg:addon B by vendor 2, Android API 2, revision 7>\n" +
952                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
953                 "-- < * NEW, pkg:Carrier Custom Rom package, revision 1>\n",
954                 getTree(m, false /*displaySortByApi*/));
955 
956         // API 1 was not suggested for install since it was totally uninstalled.
957         // Now if at least one item of API 1 is installed, the rest will be offered for install too.
958         m.clear();
959         m.updateStart();
960         m.updateSourcePackages(true /*sortByApi*/, null /*source*/, new Package[] {
961                 new MockToolPackage(src1, 10, 3),
962                 // addon for API 1 is installed but not the platform
963                 new MockAddonPackage(src2, "addon A", p1, 5),
964         });
965         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
966                 new MockToolPackage(src1, 10, 3),
967                 new MockPlatformToolPackage(src1, 3),
968                 new MockExtraPackage(src1, "android", "usb_driver", 5, 3),
969                 p1,    // API 1
970                 p2,    // API 2
971         });
972         m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
973                 new MockAddonPackage(src2, "addon A", p1, 5),
974                 new MockAddonPackage(src2, "addon B", p2, 7),
975                 new MockExtraPackage(src2, "carrier", "custom_rom", 1, 0),
976         });
977         m.updateEnd(true /*sortByApi*/);
978 
979         m.checkNewUpdateItems(true, true);
980 
981         assertEquals(
982                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
983                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
984                 "-- < * NEW, pkg:Android SDK Platform-tools, revision 3>\n" +
985                 "PkgCategoryApi <API=API 2, label=Android android-2 (API 2), #items=2>\n" +
986                 "-- < * NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
987                 "-- < * NEW, pkg:addon B by vendor 2, Android API 2, revision 7>\n" +
988                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
989                 "-- < * NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
990                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
991                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
992                 "-- < * NEW, pkg:Android USB Driver package, revision 5>\n" +
993                 "-- < * NEW, pkg:Carrier Custom Rom package, revision 1>\n",
994                 getTree(m, true /*displaySortByApi*/));
995         assertEquals(
996                 "PkgCategorySource <source=repo1 (1.example.com), #items=5>\n" +
997                 "-- <INSTALLED, pkg:Android SDK Tools, revision 10>\n" +
998                 "-- < * NEW, pkg:Android SDK Platform-tools, revision 3>\n" +
999                 "-- < * NEW, pkg:SDK Platform Android android-2, API 2, revision 4>\n" +
1000                 "-- < * NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1001                 "-- < * NEW, pkg:Android USB Driver package, revision 5>\n" +
1002                 "PkgCategorySource <source=repo2 (2.example.com), #items=3>\n" +
1003                 "-- < * NEW, pkg:addon B by vendor 2, Android API 2, revision 7>\n" +
1004                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
1005                 "-- < * NEW, pkg:Carrier Custom Rom package, revision 1>\n",
1006                 getTree(m, false /*displaySortByApi*/));
1007     }
1008 
testCheckUncheckAllItems()1009     public void testCheckUncheckAllItems() {
1010         // Populate the list with a couple items and an update
1011         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
1012         m.updateStart();
1013         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1014                 new MockEmptyPackage(src1, "type1", 1)
1015         });
1016         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
1017                 new MockEmptyPackage(src1, "type1", 2),
1018                 new MockEmptyPackage(src1, "type3", 3),
1019         });
1020         m.updateEnd(true /*sortByApi*/);
1021         // Nothing is checked at first
1022         assertEquals(
1023                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1024                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1025                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1026                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1027                 getTree(m, true /*displaySortByApi*/));
1028 
1029         // Manually check the items in the sort-by-API case, but not the source
1030         for (PkgItem item : m.getAllPkgItems(true /*byApi*/, false /*bySource*/)) {
1031             item.setChecked(true);
1032         }
1033 
1034         // by-api sort should be checked but not by source
1035         assertEquals(
1036                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1037                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1038                 "-- < * INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1039                 "-- < * NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1040                 getTree(m, true /*displaySortByApi*/));
1041         assertEquals(
1042                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1043                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1044                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1045                 getTree(m, false /*displaySortByApi*/));
1046 
1047         // now uncheck them all
1048         m.uncheckAllItems();
1049 
1050         assertEquals(
1051                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1052                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1053                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1054                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1055                 getTree(m, true /*displaySortByApi*/));
1056         assertEquals(
1057                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1058                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1059                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1060                 getTree(m, false /*displaySortByApi*/));
1061 
1062         // Manually check the items in both by-api and by-source
1063         for (PkgItem item : m.getAllPkgItems(true /*byApi*/, true /*bySource*/)) {
1064             item.setChecked(true);
1065         }
1066 
1067         assertEquals(
1068                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1069                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1070                 "-- < * INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1071                 "-- < * NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1072                 getTree(m, true /*displaySortByApi*/));
1073         assertEquals(
1074                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1075                 "-- < * INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1076                 "-- < * NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1077                 getTree(m, false /*displaySortByApi*/));
1078 
1079         // now uncheck them all
1080         m.uncheckAllItems();
1081 
1082         assertEquals(
1083                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1084                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1085                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1086                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1087                 getTree(m, true /*displaySortByApi*/));
1088         assertEquals(
1089                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1090                 "-- <INSTALLED, pkg:MockEmptyPackage 'type1' rev=1, updated by:MockEmptyPackage 'type1' rev=2>\n" +
1091                 "-- <NEW, pkg:MockEmptyPackage 'type3' rev=3>\n",
1092                 getTree(m, false /*displaySortByApi*/));
1093     }
1094 
1095     // ----
1096 
testLocalIsNewer()1097     public void testLocalIsNewer() {
1098         // This tests an edge case that typically happens only during development where
1099         // one would have a local package which revision number is larger than what the
1100         // remove repositories can offer. In this case we don't want to offer the remote
1101         // package as an "upgrade" nor as a downgrade.
1102 
1103         // Populate the list with local revisions 5 and lower remote revisions 3
1104         SdkSource src1 = new SdkRepoSource("http://example.com/url", "repo1");
1105         m.updateStart();
1106         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1107                 new MockToolPackage(        src1, 5, 5),
1108                 new MockPlatformToolPackage(src1, 5),
1109         });
1110         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
1111                 new MockToolPackage(        src1, 3, 3),
1112                 new MockPlatformToolPackage(src1, 3),
1113         });
1114         m.updateEnd(true /*sortByApi*/);
1115 
1116         // The remote packages in rev 3 are hidden by the local packages in rev 5
1117         assertEquals(
1118                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
1119                 "-- <INSTALLED, pkg:Android SDK Tools, revision 5>\n" +
1120                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 5>\n" +
1121                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=0>\n",
1122                 getTree(m, true /*displaySortByApi*/));
1123         assertEquals(
1124                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1125                 "-- <INSTALLED, pkg:Android SDK Tools, revision 5>\n" +
1126                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 5>\n",
1127                 getTree(m, false /*displaySortByApi*/));
1128     }
1129 
testSourceDups()1130     public void testSourceDups() {
1131         // This tests an edge case were 2 remote repositories are giving the
1132         // same kind of packages. We don't want to merge them together or treat
1133         // them as upgrades to each other, unless they have the same hostname.
1134 
1135         // repo1, 2 and 3 have the same hostname so redundancy is ok
1136         SdkSource src1 = new SdkRepoSource("http://example.com/url1", "repo1");
1137         SdkSource src2 = new SdkRepoSource("http://example.com/url2", "repo2");
1138         SdkSource src3 = new SdkRepoSource("http://example.com/url3", "repo3");
1139         // repo4 has a different hostname so its packages won't hide the ones from the other repos
1140         SdkSource src4 = new SdkRepoSource("http://4.example.com/url4", "repo4");
1141         MockPlatformPackage p1 = null;
1142 
1143         m.updateStart();
1144         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1145                 new MockToolPackage(        src1, 3, 3),
1146                 new MockPlatformToolPackage(src1, 3),
1147                 p1 = new MockPlatformPackage(src1, 1, 2, 3),    // API 1
1148         });
1149         m.updateSourcePackages(true /*sortByApi*/, src2, new Package[] {
1150                 new MockAddonPackage(src2, "addon A", p1, 5),
1151                 new MockAddonPackage(src2, "addon B", p1, 6),
1152         });
1153         m.updateSourcePackages(true /*sortByApi*/, src3, new Package[] {
1154                 new MockAddonPackage(src3, "addon A", p1, 5), // same as  addon A rev 5 from src2
1155                 new MockAddonPackage(src3, "addon B", p1, 7), // upgrades addon B rev 6 from src2
1156         });
1157         m.updateSourcePackages(true /*sortByApi*/, src4, new Package[] {
1158                 new MockAddonPackage(src4, "addon A", p1, 5), // same as  addon A rev 5 from src2
1159                 new MockAddonPackage(src4, "addon B", p1, 7), // upgrades addon B rev 6 from src2
1160         });
1161         m.updateEnd(true /*sortByApi*/);
1162 
1163         // The remote packages in rev 3 are hidden by the local packages in rev 5
1164         assertEquals(
1165                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=2>\n" +
1166                 "-- <INSTALLED, pkg:Android SDK Tools, revision 3>\n" +
1167                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
1168                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=5>\n" +
1169                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1170                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" + // from src2+3
1171                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" + // from scr4
1172                 "-- <NEW, pkg:addon B by vendor 1, Android API 1, revision 7>\n" + // from src2+3
1173                 "-- <NEW, pkg:addon B by vendor 1, Android API 1, revision 7>\n" + // from src4
1174                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=0>\n",
1175                 getTree(m, true /*displaySortByApi*/));
1176         assertEquals(
1177                 "PkgCategorySource <source=repo1 (example.com), #items=3>\n" +
1178                 "-- <INSTALLED, pkg:Android SDK Tools, revision 3>\n" +
1179                 "-- <INSTALLED, pkg:Android SDK Platform-tools, revision 3>\n" +
1180                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1181                 "PkgCategorySource <source=repo2 (example.com), #items=1>\n" +
1182                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
1183                 "PkgCategorySource <source=repo3 (example.com), #items=1>\n" +
1184                 "-- <NEW, pkg:addon B by vendor 1, Android API 1, revision 7>\n" +
1185                 "PkgCategorySource <source=repo4 (4.example.com), #items=2>\n" +
1186                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 5>\n" +
1187                 "-- <NEW, pkg:addon B by vendor 1, Android API 1, revision 7>\n",
1188                 getTree(m, false /*displaySortByApi*/));
1189     }
1190 
testRenamedExtraPackage()1191     public void testRenamedExtraPackage() {
1192         // Starting with schemas repo v5 and addon v3, an extra package can be renamed
1193         // using the "old-paths" attribute. This test checks that the diff logic will
1194         // match an old extra and its new name together.
1195 
1196         // First scenario: local pkg "old_path1" and remote pkg "new_path2".
1197         // Since the new package does not provide an old_paths attribute, the
1198         // new package is not treated as an update.
1199 
1200         SdkSource src1 = new SdkRepoSource("http://example.com/url1", "repo1");
1201         m.updateStart();
1202         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1203                 new MockExtraPackage(src1, "vendor1", "old_path1", 1, 1),
1204         });
1205         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
1206                 new MockExtraPackage(src1, "vendor1", "new_path2", 2, 1),
1207         });
1208         m.updateEnd(true /*sortByApi*/);
1209 
1210         assertEquals(
1211                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1212                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=2>\n" +
1213                 "-- <NEW, pkg:Vendor1 New Path2 package, revision 2>\n" +
1214                 "-- <INSTALLED, pkg:Vendor1 Old Path1 package, revision 1>\n",
1215                 getTree(m, true /*displaySortByApi*/));
1216         assertEquals(
1217                 "PkgCategorySource <source=repo1 (example.com), #items=2>\n" +
1218                 "-- <NEW, pkg:Vendor1 New Path2 package, revision 2>\n" +
1219                 "-- <INSTALLED, pkg:Vendor1 Old Path1 package, revision 1>\n",
1220                 getTree(m, false /*displaySortByApi*/));
1221 
1222         // Now, start again, but this time the new package uses the old-path attribute
1223         Properties props = new Properties();
1224         props.setProperty(PkgProps.EXTRA_OLD_PATHS, "old_path1;oldpath2");
1225         m.clear();
1226 
1227         m.updateStart();
1228         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1229                 new MockExtraPackage(src1, "vendor1", "old_path1", 1, 1),
1230         });
1231         m.updateSourcePackages(true /*sortByApi*/, src1, new Package[] {
1232                 new MockExtraPackage(src1, props, "vendor1", "new_path2", 2),
1233         });
1234         m.updateEnd(true /*sortByApi*/);
1235 
1236         assertEquals(
1237                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1238                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
1239                 "-- <INSTALLED, pkg:Vendor1 Old Path1 package, revision 1, updated by:Vendor1 New Path2 package, revision 2>\n",
1240                 getTree(m, true /*displaySortByApi*/));
1241         assertEquals(
1242                 "PkgCategorySource <source=repo1 (example.com), #items=1>\n" +
1243                 "-- <INSTALLED, pkg:Vendor1 Old Path1 package, revision 1, updated by:Vendor1 New Path2 package, revision 2>\n",
1244                 getTree(m, false /*displaySortByApi*/));
1245     }
1246 
1247 
testBrokenAddon()1248     public void testBrokenAddon() {
1249 
1250         SdkSource src1 = new SdkRepoSource("http://1.example.com/url1", "repo1");
1251         SdkSource src2 = new SdkRepoSource("http://2.example.com/url2", "repo2");
1252 
1253         MockPlatformPackage p1 = null;
1254         MockAddonPackage a1 = null;
1255 
1256         // User has a platform + addon locally installed
1257         m.updateStart();
1258         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1259                 p1 = new MockPlatformPackage(src1, 1, 2, 3),    // API 1
1260                 a1 = new MockAddonPackage(src2, "addon A", p1, 4),
1261         });
1262         m.updateSourcePackages(true /*sortByApi*/, src1 /*locals*/, new Package[] {
1263                 p1
1264         });
1265         m.updateSourcePackages(true /*sortByApi*/, src2 /*locals*/, new Package[] {
1266                 a1
1267         });
1268         m.updateEnd(true /*sortByApi*/);
1269         assertEquals(
1270                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1271                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
1272                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1273                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 4>\n" +
1274                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=0>\n",
1275                 getTree(m, true /*displaySortByApi*/));
1276         assertEquals(
1277                 "PkgCategorySource <source=repo1 (1.example.com), #items=1>\n" +
1278                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1279                 "PkgCategorySource <source=repo2 (2.example.com), #items=1>\n" +
1280                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 4>\n",
1281                 getTree(m, false /*displaySortByApi*/));
1282 
1283         // Now user deletes the platform on disk and reload.
1284         // The local package parser will only find a broken addon.
1285         m.updateStart();
1286         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1287                 new MockBrokenPackage(BrokenPackage.MIN_API_LEVEL_NOT_SPECIFIED, 1),
1288         });
1289         m.updateSourcePackages(true /*sortByApi*/, src1 /*locals*/, new Package[] {
1290                 new MockPlatformPackage(src1, 1, 2, 3)
1291         });
1292         m.updateSourcePackages(true /*sortByApi*/, src2 /*locals*/, new Package[] {
1293                 new MockAddonPackage(src2, "addon A", p1, 4)
1294         });
1295         m.updateEnd(true /*sortByApi*/);
1296         assertEquals(
1297                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1298                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
1299                 "-- <NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1300                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 4>\n" +
1301                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=1>\n" +
1302                 "-- <INSTALLED, pkg:Broken package for API 1>\n",
1303                 getTree(m, true /*displaySortByApi*/));
1304         assertEquals(
1305                 "PkgCategorySource <source=repo1 (1.example.com), #items=1>\n" +
1306                 "-- <NEW, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1307                 "PkgCategorySource <source=repo2 (2.example.com), #items=1>\n" +
1308                 "-- <NEW, pkg:addon A by vendor 1, Android API 1, revision 4>\n" +
1309                 "PkgCategorySource <source=Local Packages (no.source), #items=1>\n" +
1310                 "-- <INSTALLED, pkg:Broken package for API 1>\n",
1311                 getTree(m, false /*displaySortByApi*/));
1312 
1313         // Now user restores the missing platform on disk.
1314         m.updateStart();
1315         m.updateSourcePackages(true /*sortByApi*/, null /*locals*/, new Package[] {
1316                 p1 = new MockPlatformPackage(src1, 1, 2, 3),    // API 1
1317                 a1 = new MockAddonPackage(src2, "addon A", p1, 4),
1318         });
1319         m.updateSourcePackages(true /*sortByApi*/, src1 /*locals*/, new Package[] {
1320                 p1
1321         });
1322         m.updateSourcePackages(true /*sortByApi*/, src2 /*locals*/, new Package[] {
1323                 a1
1324         });
1325         m.updateEnd(true /*sortByApi*/);
1326         assertEquals(
1327                 "PkgCategoryApi <API=TOOLS, label=Tools, #items=0>\n" +
1328                 "PkgCategoryApi <API=API 1, label=Android android-1 (API 1), #items=2>\n" +
1329                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1330                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 4>\n" +
1331                 "PkgCategoryApi <API=EXTRAS, label=Extras, #items=0>\n",
1332                 getTree(m, true /*displaySortByApi*/));
1333         assertEquals(
1334                 "PkgCategorySource <source=repo1 (1.example.com), #items=1>\n" +
1335                 "-- <INSTALLED, pkg:SDK Platform Android android-1, API 1, revision 2>\n" +
1336                 "PkgCategorySource <source=repo2 (2.example.com), #items=1>\n" +
1337                 "-- <INSTALLED, pkg:addon A by vendor 1, Android API 1, revision 4>\n",
1338                 getTree(m, false /*displaySortByApi*/));
1339     }
1340 
1341     // ----
1342 
1343     /**
1344      * Simulates the display we would have in the Packages Tree.
1345      * This always depends on mCurrentCategories like the tree does.
1346      * The display format is something like:
1347      * <pre>
1348      *   PkgCategory &lt;description&gt;
1349      *   -- &lt;PkgItem description&gt;
1350      * </pre>
1351      */
getTree(PackagesDiffLogic l, boolean displaySortByApi)1352     public String getTree(PackagesDiffLogic l, boolean displaySortByApi) {
1353         StringBuilder sb = new StringBuilder();
1354 
1355         for (PkgCategory cat : m.getCategories(displaySortByApi)) {
1356             sb.append(cat.toString()).append('\n');
1357             for (PkgItem item : cat.getItems()) {
1358                 sb.append("-- ").append(item.toString()).append('\n');
1359             }
1360         }
1361 
1362         return sb.toString();
1363     }
1364 }
1365