1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  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
17package libcore.java.util.prefs;
18
19import java.io.File;
20import java.io.IOException;
21import java.io.OutputStream;
22import java.util.Arrays;
23import java.util.prefs.BackingStoreException;
24import java.util.prefs.NodeChangeEvent;
25import java.util.prefs.NodeChangeListener;
26import java.util.prefs.PreferenceChangeEvent;
27import java.util.prefs.PreferenceChangeListener;
28import java.util.prefs.Preferences;
29import java.util.prefs.PreferencesFactory;
30import junit.framework.TestCase;
31import libcore.io.IoUtils;
32
33public final class OldPreferencesTest extends TestCase {
34
35    private static final boolean ENCOURAGE_RACES = false;
36
37    private static final String longKey;
38    private static final String longValue;
39
40    static {
41        StringBuilder key = new StringBuilder(Preferences.MAX_KEY_LENGTH);
42        for (int i = 0; i < Preferences.MAX_KEY_LENGTH; i++) {
43            key.append('a');
44        }
45        longKey = key.toString();
46
47        StringBuilder value = new StringBuilder(Preferences.MAX_VALUE_LENGTH);
48        for (int i = 0; i < Preferences.MAX_VALUE_LENGTH; i++) {
49            value.append('a');
50        }
51        longValue = value.toString();
52    }
53
54    private PreferencesFactory defaultFactory;
55
56    @Override
57    protected void setUp() throws Exception {
58        super.setUp();
59        final File tmpDir = IoUtils.createTemporaryDirectory("OldPreferenceTest");
60        defaultFactory = Preferences.setPreferencesFactory(
61                new PreferencesTest.TestPreferencesFactory(tmpDir.getAbsolutePath()));
62
63        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
64        for (String child : pref.childrenNames()) {
65            pref.node(child).removeNode();
66        }
67        pref.clear();
68    }
69
70    @Override
71    protected void tearDown() throws Exception {
72        Preferences.setPreferencesFactory(defaultFactory);
73    }
74
75    public void testAbstractMethods() throws IOException, BackingStoreException {
76        Preferences p = new MockPreferences();
77        p.absolutePath();
78        p.childrenNames();
79        p.clear();
80        p.exportNode(null);
81        p.exportSubtree(null);
82        p.flush();
83        p.get(null, null);
84        p.getBoolean(null, false);
85        p.getByteArray(null, null);
86        p.getFloat(null, 0.1f);
87        p.getDouble(null, 0.1);
88        p.getInt(null, 1);
89        p.getLong(null, 1l);
90        p.isUserNode();
91        p.keys();
92        p.name();
93        p.node(null);
94        p.nodeExists(null);
95        p.parent();
96        p.put(null, null);
97        p.putBoolean(null, false);
98        p.putByteArray(null, null);
99        p.putDouble(null, 1);
100        p.putFloat(null, 1f);
101        p.putInt(null, 1);
102        p.putLong(null, 1l);
103        p.remove(null);
104        p.removeNode();
105        p.addNodeChangeListener(null);
106        p.addPreferenceChangeListener(null);
107        p.removeNodeChangeListener(null);
108        p.removePreferenceChangeListener(null);
109        p.sync();
110        p.toString();
111    }
112
113    public void testConstructor() {
114        MockPreferences mp = new MockPreferences();
115        assertEquals(mp.getClass(), MockPreferences.class);
116    }
117
118    public void testToString() {
119        Preferences p1 = Preferences.userNodeForPackage(Preferences.class);
120        assertNotNull(p1.toString());
121
122        Preferences p2 = Preferences.systemRoot();
123        assertNotNull(p2.toString());
124
125        Preferences p3 = Preferences.userRoot();
126        assertNotNull(p3.toString());
127    }
128
129    public void testAbsolutePath() {
130        Preferences p = Preferences.userNodeForPackage(Preferences.class);
131        assertEquals("/java/util/prefs", p.absolutePath());
132
133    }
134
135    public void testChildrenNames() throws BackingStoreException {
136        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
137
138        Preferences child1 = pref.node("child1");
139
140        pref.node("child2");
141        pref.node("child3");
142        child1.node("subchild1");
143
144        assertSame(pref, child1.parent());
145        assertEquals(3, pref.childrenNames().length);
146        assertEquals("child1", pref.childrenNames()[0]);
147        assertEquals(1, child1.childrenNames().length);
148        assertEquals("subchild1", child1.childrenNames()[0]);
149    }
150
151    public void testClear() throws BackingStoreException {
152        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
153        pref.put("testClearKey", "testClearValue");
154        pref.put("testClearKey1", "testClearValue1");
155        assertEquals("testClearValue", pref.get("testClearKey", null));
156        assertEquals("testClearValue1", pref.get("testClearKey1", null));
157        pref.clear();
158        assertNull(pref.get("testClearKey", null));
159        assertNull(pref.get("testClearKey1", null));
160    }
161
162    public void testGet() throws BackingStoreException {
163        Preferences root = Preferences.userNodeForPackage(Preferences.class);
164        Preferences pref = root.node("mock");
165        assertNull(pref.get("", null));
166        assertEquals("default", pref.get("key", "default"));
167        assertNull(pref.get("key", null));
168        pref.put("testGetkey", "value");
169        assertNull(pref.get("testGetKey", null));
170        assertEquals("value", pref.get("testGetkey", null));
171
172        try {
173            pref.get(null, "abc");
174            fail();
175        } catch (NullPointerException expected) {
176        }
177        pref.get("", "abc");
178        pref.get("key", null);
179        pref.get("key", "");
180        pref.putFloat("floatKey", 1.0f);
181        assertEquals("1.0", pref.get("floatKey", null));
182
183        pref.removeNode();
184        try {
185            pref.get("key", "abc");
186            fail();
187        } catch (IllegalStateException expected) {
188        }
189        try {
190            pref.get(null, "abc");
191            fail();
192        } catch (NullPointerException expected) {
193        }
194    }
195
196    public void testGetBoolean() {
197        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
198        try {
199            pref.getBoolean(null, false);
200            fail();
201        } catch (NullPointerException expected) {
202        }
203
204        pref.put("testGetBooleanKey", "false");
205        pref.put("testGetBooleanKey2", "value");
206        assertFalse(pref.getBoolean("testGetBooleanKey", true));
207        assertTrue(pref.getBoolean("testGetBooleanKey2", true));
208    }
209
210    public void testGetByteArray() {
211        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
212        try {
213            pref.getByteArray(null, new byte[0]);
214            fail();
215        } catch (NullPointerException expected) {
216        }
217        byte[] b64Array = new byte[] { 0x59, 0x57, 0x4a, 0x6a };// BASE64
218
219        pref.put("testGetByteArrayKey", "abc=");
220        pref.put("testGetByteArrayKey2", new String(b64Array));
221        pref.put("invalidKey", "<>?");
222        assertTrue(Arrays.equals(new byte[] { 105, -73 }, pref.getByteArray(
223                "testGetByteArrayKey", new byte[0])));
224        assertTrue(Arrays.equals(new byte[] { 'a', 'b', 'c' }, pref
225                .getByteArray("testGetByteArrayKey2", new byte[0])));
226        assertTrue(Arrays.equals(new byte[0], pref.getByteArray("invalidKey",
227                new byte[0])));
228
229        pref.putByteArray("testGetByteArrayKey3", b64Array);
230        pref.putByteArray("testGetByteArrayKey4", "abc".getBytes());
231        assertTrue(Arrays.equals(b64Array, pref.getByteArray(
232                "testGetByteArrayKey3", new byte[0])));
233        assertTrue(Arrays.equals("abc".getBytes(), pref.getByteArray(
234                "testGetByteArrayKey4", new byte[0])));
235    }
236
237    public void testGetDouble() {
238        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
239        try {
240            pref.getDouble(null, 0);
241            fail();
242        } catch (NullPointerException expected) {
243        }
244
245        pref.put("testGetDoubleKey", "1");
246        pref.put("testGetDoubleKey2", "value");
247        pref.putDouble("testGetDoubleKey3", 1);
248        pref.putInt("testGetDoubleKey4", 1);
249        assertEquals(1.0, pref.getDouble("testGetDoubleKey", 0.0), 0);
250        assertEquals(0.0, pref.getDouble("testGetDoubleKey2", 0.0), 0);
251        assertEquals(1.0, pref.getDouble("testGetDoubleKey3", 0.0), 0);
252        assertEquals(1.0, pref.getDouble("testGetDoubleKey4", 0.0), 0);
253    }
254
255    public void testGetFloat() {
256        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
257        try {
258            pref.getFloat(null, 0f);
259            fail();
260        } catch (NullPointerException expected) {
261        }
262        pref.put("testGetFloatKey", "1");
263        pref.put("testGetFloatKey2", "value");
264        assertEquals(1f, pref.getFloat("testGetFloatKey", 0f), 0);
265        assertEquals(0f, pref.getFloat("testGetFloatKey2", 0f), 0);
266    }
267
268    public void testGetInt() {
269        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
270        try {
271            pref.getInt(null, 0);
272            fail();
273        } catch (NullPointerException expected) {
274        }
275
276        pref.put("testGetIntKey", "1");
277        pref.put("testGetIntKey2", "value");
278        assertEquals(1, pref.getInt("testGetIntKey", 0));
279        assertEquals(0, pref.getInt("testGetIntKey2", 0));
280    }
281
282    public void testGetLong() {
283        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
284        try {
285            pref.getLong(null, 0);
286            fail();
287        } catch (NullPointerException expected) {
288        }
289
290        pref.put("testGetLongKey", "1");
291        pref.put("testGetLongKey2", "value");
292        assertEquals(1, pref.getInt("testGetLongKey", 0));
293        assertEquals(0, pref.getInt("testGetLongKey2", 0));
294    }
295
296    public void testIsUserNode() {
297        Preferences pref1 = Preferences.userNodeForPackage(Preferences.class);
298        assertTrue(pref1.isUserNode());
299
300        Preferences pref2 = Preferences.systemNodeForPackage(Preferences.class);
301        assertFalse(pref2.isUserNode());
302    }
303
304    public void testKeys() throws BackingStoreException {
305        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
306        pref.clear();
307
308        pref.put("key0", "value");
309        pref.put("key1", "value1");
310        pref.put("key2", "value2");
311        pref.put("key3", "value3");
312
313        String[] keys = pref.keys();
314        assertEquals(4, keys.length);
315        for (String key : keys) {
316            assertEquals(0, key.indexOf("key"));
317            assertEquals(4, key.length());
318        }
319    }
320
321    public void testName() {
322        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
323        Preferences child = pref.node("mock");
324        assertEquals("mock", child.name());
325    }
326
327    public void testNode() throws BackingStoreException {
328        StringBuilder name = new StringBuilder(Preferences.MAX_NAME_LENGTH);
329        for (int i = 0; i < Preferences.MAX_NAME_LENGTH; i++) {
330            name.append('a');
331        }
332        String longName = name.toString();
333
334        Preferences root = Preferences.userRoot();
335        Preferences parent = Preferences.userNodeForPackage(Preferences.class);
336        Preferences pref = parent.node("mock");
337
338        try {
339            pref.node(null);
340            fail();
341        } catch (NullPointerException expected) {
342        }
343        try {
344            pref.node("/java/util/prefs/");
345            fail();
346        } catch (IllegalArgumentException expected) {
347        }
348        try {
349            pref.node("/java//util/prefs");
350            fail();
351        } catch (IllegalArgumentException expected) {
352        }
353        try {
354            pref.node(longName + "a");
355            fail();
356        } catch (IllegalArgumentException expected) {
357        }
358        assertNotNull(pref.node(longName));
359
360        assertSame(root, pref.node("/"));
361
362        Preferences prefs = pref.node("/java/util/prefs");
363        assertSame(prefs, parent);
364
365        assertSame(pref, pref.node(""));
366    }
367
368    public void testNodeExists() throws BackingStoreException {
369
370        Preferences parent = Preferences.userNodeForPackage(Preferences.class);
371        Preferences pref = parent.node("mock");
372
373        try {
374            pref.nodeExists(null);
375            fail();
376        } catch (NullPointerException expected) {
377        }
378        try {
379            pref.nodeExists("/java/util/prefs/");
380            fail();
381        } catch (IllegalArgumentException expected) {
382        }
383        try {
384            pref.nodeExists("/java//util/prefs");
385            fail();
386        } catch (IllegalArgumentException expected) {
387        }
388
389        assertTrue(pref.nodeExists("/"));
390
391        assertTrue(pref.nodeExists("/java/util/prefs"));
392
393        assertTrue(pref.nodeExists(""));
394
395        assertFalse(pref.nodeExists("child"));
396        Preferences grandchild = pref.node("child/grandchild");
397        assertTrue(pref.nodeExists("child"));
398        assertTrue(pref.nodeExists("child/grandchild"));
399        grandchild.removeNode();
400        assertTrue(pref.nodeExists("child"));
401        assertFalse(pref.nodeExists("child/grandchild"));
402        assertFalse(grandchild.nodeExists(""));
403
404        assertFalse(pref.nodeExists("child2/grandchild"));
405        pref.node("child2/grandchild");
406        assertTrue(pref.nodeExists("child2/grandchild"));
407    }
408
409    public void testParent() {
410        Preferences parent = Preferences.userNodeForPackage(Preferences.class);
411        Preferences pref = parent.node("mock");
412
413        assertSame(parent, pref.parent());
414    }
415
416    public void testPut() throws BackingStoreException {
417        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
418        pref.put("", "emptyvalue");
419        assertEquals("emptyvalue", pref.get("", null));
420        pref.put("testPutkey", "value1");
421        assertEquals("value1", pref.get("testPutkey", null));
422        pref.put("testPutkey", "value2");
423        assertEquals("value2", pref.get("testPutkey", null));
424
425        pref.put("", "emptyvalue");
426        assertEquals("emptyvalue", pref.get("", null));
427
428        try {
429            pref.put(null, "value");
430            fail();
431        } catch (NullPointerException expected) {
432        }
433        try {
434            pref.put("key", null);
435            fail();
436        } catch (NullPointerException expected) {
437        }
438        pref.put(longKey, longValue);
439        try {
440            pref.put(longKey + 1, longValue);
441            fail();
442        } catch (IllegalArgumentException expected) {
443        }
444        try {
445            pref.put(longKey, longValue + 1);
446            fail();
447        } catch (IllegalArgumentException expected) {
448        }
449
450        pref.removeNode();
451        try {
452            pref.put(longKey, longValue + 1);
453            fail();
454        } catch (IllegalArgumentException expected) {
455        }
456
457        try {
458            pref.put(longKey, longValue);
459            fail();
460        } catch (IllegalStateException expected) {
461        }
462    }
463
464    public void testPutBoolean() {
465        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
466        try {
467            pref.putBoolean(null, false);
468            fail();
469        } catch (NullPointerException expected) {
470        }
471        pref.putBoolean(longKey, false);
472        try {
473            pref.putBoolean(longKey + "a", false);
474            fail();
475        } catch (IllegalArgumentException expected) {
476        }
477        pref.putBoolean("testPutBooleanKey", false);
478        assertEquals("false", pref.get("testPutBooleanKey", null));
479        assertFalse(pref.getBoolean("testPutBooleanKey", true));
480    }
481
482    public void testPutDouble() {
483        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
484        try {
485            pref.putDouble(null, 3);
486            fail();
487        } catch (NullPointerException expected) {
488        }
489        pref.putDouble(longKey, 3);
490        try {
491            pref.putDouble(longKey + "a", 3);
492            fail();
493        } catch (IllegalArgumentException expected) {
494        }
495        pref.putDouble("testPutDoubleKey", 3);
496        assertEquals("3.0", pref.get("testPutDoubleKey", null));
497        assertEquals(3, pref.getDouble("testPutDoubleKey", 0), 0);
498    }
499
500    public void testPutFloat() {
501        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
502        try {
503            pref.putFloat(null, 3f);
504            fail();
505        } catch (NullPointerException expected) {
506        }
507        pref.putFloat(longKey, 3f);
508        try {
509            pref.putFloat(longKey + "a", 3f);
510            fail();
511        } catch (IllegalArgumentException expected) {
512        }
513        pref.putFloat("testPutFloatKey", 3f);
514        assertEquals("3.0", pref.get("testPutFloatKey", null));
515        assertEquals(3f, pref.getFloat("testPutFloatKey", 0), 0);
516    }
517
518    public void testPutInt() {
519        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
520        try {
521            pref.putInt(null, 3);
522            fail();
523        } catch (NullPointerException expected) {
524        }
525        pref.putInt(longKey, 3);
526        try {
527            pref.putInt(longKey + "a", 3);
528            fail();
529        } catch (IllegalArgumentException expected) {
530        }
531        pref.putInt("testPutIntKey", 3);
532        assertEquals("3", pref.get("testPutIntKey", null));
533        assertEquals(3, pref.getInt("testPutIntKey", 0));
534    }
535
536    public void testPutLong() {
537        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
538        try {
539            pref.putLong(null, 3L);
540            fail();
541        } catch (NullPointerException expected) {
542        }
543        pref.putLong(longKey, 3L);
544        try {
545            pref.putLong(longKey + "a", 3L);
546            fail();
547        } catch (IllegalArgumentException expected) {
548        }
549        pref.putLong("testPutLongKey", 3L);
550        assertEquals("3", pref.get("testPutLongKey", null));
551        assertEquals(3L, pref.getLong("testPutLongKey", 0));
552    }
553
554    public void testPutByteArray() {
555        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
556        try {
557            pref.putByteArray(null, new byte[0]);
558            fail();
559        } catch (NullPointerException expected) {
560        }
561        try {
562            pref.putByteArray("testPutByteArrayKey4", null);
563            fail();
564        } catch (NullPointerException expected) {
565        }
566
567        pref.putByteArray(longKey, new byte[0]);
568        try {
569            pref.putByteArray(longKey + "a", new byte[0]);
570            fail();
571        } catch (IllegalArgumentException expected) {
572        }
573        byte[] longArray = new byte[(int) (Preferences.MAX_VALUE_LENGTH * 0.74)];
574        byte[] longerArray = new byte[(int) (Preferences.MAX_VALUE_LENGTH * 0.75) + 1];
575        pref.putByteArray(longKey, longArray);
576        try {
577            pref.putByteArray(longKey, longerArray);
578            fail();
579        } catch (IllegalArgumentException expected) {
580        }
581
582        pref.putByteArray("testPutByteArrayKey", new byte[0]);
583        assertEquals("", pref.get("testPutByteArrayKey", null));
584        assertTrue(Arrays.equals(new byte[0], pref.getByteArray(
585                "testPutByteArrayKey", null)));
586
587        pref.putByteArray("testPutByteArrayKey3", new byte[] { 'a', 'b', 'c' });
588        assertEquals("YWJj", pref.get("testPutByteArrayKey3", null));
589        assertTrue(Arrays.equals(new byte[] { 'a', 'b', 'c' }, pref
590                .getByteArray("testPutByteArrayKey3", null)));
591    }
592
593    public void testRemove() throws BackingStoreException {
594        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
595        pref.remove("key");
596
597        pref.put("key", "value");
598        assertEquals("value", pref.get("key", null));
599        pref.remove("key");
600        assertNull(pref.get("key", null));
601
602        pref.remove("key");
603
604        try {
605            pref.remove(null);
606            fail();
607        } catch (NullPointerException expected) {
608        }
609
610        pref.removeNode();
611        try {
612            pref.remove("key");
613            fail();
614        } catch (IllegalStateException expected) {
615        }
616    }
617
618    public void testRemoveNode() throws BackingStoreException {
619        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
620        Preferences child = pref.node("child");
621        Preferences child1 = pref.node("child1");
622        Preferences grandchild = child.node("grandchild");
623
624        pref.removeNode();
625
626        assertFalse(child.nodeExists(""));
627        assertFalse(child1.nodeExists(""));
628        assertFalse(grandchild.nodeExists(""));
629        assertFalse(pref.nodeExists(""));
630    }
631
632    public void testAddNodeChangeListener() throws BackingStoreException {
633        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
634        try {
635            pref.addNodeChangeListener(null);
636            fail();
637        } catch (NullPointerException expected) {
638        }
639
640        Preferences child1 = null;
641
642        MockNodeChangeListener nl = null;
643        // To get existed node doesn't create the change event
644        try {
645            nl = new MockNodeChangeListener();
646            pref.addNodeChangeListener(nl);
647            child1 = pref.node("mock1");
648            nl.waitForEvent(1);
649            assertEquals(1, nl.getAdded());
650            nl.reset();
651            pref.node("mock1");
652            // There shouldn't be an event, but wait in case one arrives...
653            try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
654            assertEquals(0, nl.getAdded());
655            nl.reset();
656        } finally {
657            pref.removeNodeChangeListener(nl);
658            child1.removeNode();
659        }
660        // same listener can be added twice, and must be removed twice
661        try {
662            nl = new MockNodeChangeListener();
663            pref.addNodeChangeListener(nl);
664            pref.addNodeChangeListener(nl);
665            child1 = pref.node("mock2");
666            nl.waitForEvent(2);
667            assertEquals(2, nl.getAdded());
668            nl.reset();
669        } finally {
670            pref.removeNodeChangeListener(nl);
671            pref.removeNodeChangeListener(nl);
672            child1.removeNode();
673        }
674        // test remove event
675        try {
676            nl = new MockNodeChangeListener();
677            pref.addNodeChangeListener(nl);
678            child1 = pref.node("mock3");
679            child1.removeNode();
680            nl.waitForEvent(2);
681            assertEquals(1, nl.getRemoved());
682            nl.reset();
683        } finally {
684            pref.removeNodeChangeListener(nl);
685        }
686        // test remove event with two listeners
687        try {
688            nl = new MockNodeChangeListener();
689            pref.addNodeChangeListener(nl);
690            pref.addNodeChangeListener(nl);
691            child1 = pref.node("mock6");
692            child1.removeNode();
693            nl.waitForEvent(4);
694            assertEquals(2, nl.getRemoved());
695            nl.reset();
696        } finally {
697            pref.removeNodeChangeListener(nl);
698            pref.removeNodeChangeListener(nl);
699        }
700        // test add/remove indirect children, or remove several children at the
701        // same time
702        Preferences child3;
703        try {
704            nl = new MockNodeChangeListener();
705            child1 = pref.node("mock4");
706            child1.addNodeChangeListener(nl);
707            pref.node("mock4/mock5");
708            nl.waitForEvent(1);
709            assertEquals(1, nl.getAdded());
710            nl.reset();
711            child3 = pref.node("mock4/mock5/mock6");
712            // There shouldn't be an event, but wait in case one arrives...
713            try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
714            assertEquals(0, nl.getAdded());
715            nl.reset();
716
717            child3.removeNode();
718            // There shouldn't be an event, but wait in case one arrives...
719            try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
720            assertEquals(0, nl.getRemoved());
721            nl.reset();
722
723            pref.node("mock4/mock7");
724            nl.waitForEvent(1);
725            assertEquals(1, nl.getAdded());
726            nl.reset();
727
728            child1.removeNode();
729            nl.waitForEvent(2);
730            assertEquals(2, nl.getRemoved());
731            nl.reset();
732        } finally {
733            try {
734                child1.removeNode();
735            } catch (Exception ignored) {
736            }
737        }
738    }
739
740    public void testAddPreferenceChangeListener() throws Exception {
741        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
742        MockPreferenceChangeListener pl = null;
743
744        try {
745            pref.addPreferenceChangeListener(null);
746            fail();
747        } catch (NullPointerException expected) {
748        }
749
750        // To get existed node doesn't create the change event
751        try {
752            pl = new MockPreferenceChangeListener();
753            pref.addPreferenceChangeListener(pl);
754            pref.putInt("mock1", 123);
755            pl.waitForEvent(1);
756            assertEquals(1, pl.getChanged());
757            pref.putLong("long_key", Long.MAX_VALUE);
758            pl.waitForEvent(2);
759            assertEquals(2, pl.getChanged());
760            pl.reset();
761            try {
762                pref.clear();
763                pl.waitForEvent(2);
764                assertEquals(2, pl.getChanged());
765            } catch(BackingStoreException bse) {
766                pl.reset();
767                fail("BackingStoreException is thrown");
768            }
769            pl.reset();
770        } finally {
771            pref.removePreferenceChangeListener(pl);
772            //child1.removeNode();
773        }
774
775        // same listener can be added twice, and must be removed twice
776        try {
777            pl = new MockPreferenceChangeListener();
778            pref.addPreferenceChangeListener(pl);
779            pref.addPreferenceChangeListener(pl);
780            pref.putFloat("float_key", Float.MIN_VALUE);
781            pl.waitForEvent(2);
782            assertEquals(2, pl.getChanged());
783            pl.reset();
784        } finally {
785            pref.removePreferenceChangeListener(pl);
786            pref.removePreferenceChangeListener(pl);
787
788        }
789        // test remove event
790        try {
791            pl = new MockPreferenceChangeListener();
792            pref.addPreferenceChangeListener(pl);
793            pref.putDouble("double_key", Double.MAX_VALUE);
794            pl.waitForEvent(1);
795            assertEquals(1, pl.getChanged());
796            try {
797                pref.clear();
798                pl.waitForEvent(3);
799                assertEquals(3, pl.getChanged());
800            } catch(BackingStoreException bse) {
801                fail("BackingStoreException is thrown");
802            }
803            pl.reset();
804        } finally {
805            pref.removePreferenceChangeListener(pl);
806        }
807        // test remove event with two listeners
808        try {
809            pl = new MockPreferenceChangeListener();
810            pref.addPreferenceChangeListener(pl);
811            pref.addPreferenceChangeListener(pl);
812            pref.putByteArray("byte_array_key", new byte [] {1 ,2 , 3});
813            try {
814                pref.clear();
815                pl.waitForEvent(4);
816                assertEquals(4, pl.getChanged());
817            } catch(BackingStoreException bse) {
818                fail("BackingStoreException is thrown");
819            }
820            pl.reset();
821        } finally {
822            pref.removePreferenceChangeListener(pl);
823            pref.removePreferenceChangeListener(pl);
824        }
825
826    }
827
828    public void testRemoveNodeChangeListener() {
829        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
830        try {
831            pref.removeNodeChangeListener(null);
832            fail();
833        } catch (IllegalArgumentException expected) {
834        }
835        MockNodeChangeListener l1 = new MockNodeChangeListener();
836        MockNodeChangeListener l2 = new MockNodeChangeListener();
837        pref.addNodeChangeListener(l1);
838        pref.addNodeChangeListener(l1);
839
840        pref.removeNodeChangeListener(l1);
841        pref.removeNodeChangeListener(l1);
842        try {
843            pref.removeNodeChangeListener(l1);
844            fail();
845        } catch (IllegalArgumentException expected) {
846        }
847        try {
848            pref.removeNodeChangeListener(l2);
849            fail();
850        } catch (IllegalArgumentException expected) {
851        }
852    }
853
854    public void testRemovePreferenceChangeListener() {
855        Preferences pref = Preferences.userNodeForPackage(Preferences.class);
856        try {
857            pref.removePreferenceChangeListener(null);
858            fail();
859        } catch (IllegalArgumentException expected) {
860        }
861        MockPreferenceChangeListener l1 = new MockPreferenceChangeListener();
862        MockPreferenceChangeListener l2 = new MockPreferenceChangeListener();
863        pref.addPreferenceChangeListener(l1);
864        pref.addPreferenceChangeListener(l1);
865        try {
866            pref.removePreferenceChangeListener(l2);
867            fail();
868        } catch (IllegalArgumentException expected) {
869        }
870        pref.removePreferenceChangeListener(l1);
871        pref.removePreferenceChangeListener(l1);
872        try {
873            pref.removePreferenceChangeListener(l1);
874            fail();
875        } catch (IllegalArgumentException expected) {
876        }
877
878    }
879
880    static class MockNodeChangeListener implements NodeChangeListener {
881        private int added = 0;
882        private int removed = 0;
883        private int eventCount = 0;
884
885        public void waitForEvent(int count) {
886            synchronized (this) {
887                while (eventCount < count) {
888                    try {
889                        wait();
890                    } catch (InterruptedException ignored) {
891                    }
892                }
893            }
894        }
895
896        public void childAdded(NodeChangeEvent e) {
897            if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
898            synchronized (this) {
899                ++eventCount;
900                ++added;
901                notifyAll();
902            }
903        }
904
905        public void childRemoved(NodeChangeEvent e) {
906            if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
907            synchronized (this) {
908                ++eventCount;
909                ++removed;
910                notifyAll();
911            }
912        }
913
914        public synchronized int getAdded() {
915            return added;
916        }
917
918        public synchronized int getRemoved() {
919            return removed;
920        }
921
922        public synchronized void reset() {
923            eventCount = 0;
924            added = 0;
925            removed = 0;
926        }
927    }
928
929    private static class MockPreferenceChangeListener implements PreferenceChangeListener {
930        private int changed = 0;
931        private int eventCount = 0;
932
933        public void waitForEvent(int count) {
934            synchronized (this) {
935                while (eventCount < count) {
936                    try {
937                        wait();
938                    } catch (InterruptedException ignored) {
939                    }
940                }
941            }
942        }
943
944        public void preferenceChange(PreferenceChangeEvent pce) {
945            if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
946            synchronized (this) {
947                ++eventCount;
948                ++changed;
949                notifyAll();
950            }
951        }
952
953        public synchronized int getChanged() {
954            return changed;
955        }
956
957        public synchronized void reset() {
958            eventCount = 0;
959            changed = 0;
960        }
961    }
962
963    @SuppressWarnings("unused")
964    static class MockPreferences extends Preferences {
965
966        @Override
967        public String absolutePath() {
968            return null;
969        }
970
971        @Override
972        public String[] childrenNames() throws BackingStoreException {
973            return null;
974        }
975
976        @Override
977        public void clear() throws BackingStoreException {
978        }
979
980        @Override
981        public void exportNode(OutputStream ostream) throws IOException, BackingStoreException {
982        }
983
984        @Override
985        public void exportSubtree(OutputStream ostream) throws IOException, BackingStoreException {
986        }
987
988        @Override
989        public void flush() throws BackingStoreException {
990        }
991
992        @Override
993        public String get(String key, String deflt) {
994            return null;
995        }
996
997        @Override
998        public boolean getBoolean(String key, boolean deflt) {
999            return false;
1000        }
1001
1002        @Override
1003        public byte[] getByteArray(String key, byte[] deflt) {
1004            return null;
1005        }
1006
1007        @Override
1008        public double getDouble(String key, double deflt) {
1009            return 0;
1010        }
1011
1012        @Override
1013        public float getFloat(String key, float deflt) {
1014            return 0;
1015        }
1016
1017        @Override
1018        public int getInt(String key, int deflt) {
1019            return 0;
1020        }
1021
1022        @Override
1023        public long getLong(String key, long deflt) {
1024            return 0;
1025        }
1026
1027        @Override
1028        public boolean isUserNode() {
1029            return false;
1030        }
1031
1032        @Override
1033        public String[] keys() throws BackingStoreException {
1034            return null;
1035        }
1036
1037        @Override
1038        public String name() {
1039            return null;
1040        }
1041
1042        @Override
1043        public Preferences node(String name) {
1044            return null;
1045        }
1046
1047        @Override
1048        public boolean nodeExists(String name) throws BackingStoreException {
1049            return false;
1050        }
1051
1052        @Override
1053        public Preferences parent() {
1054            return null;
1055        }
1056
1057        @Override
1058        public void put(String key, String value) {
1059        }
1060
1061        @Override
1062        public void putBoolean(String key, boolean value) {
1063        }
1064
1065        @Override
1066        public void putByteArray(String key, byte[] value) {
1067        }
1068
1069        @Override
1070        public void putDouble(String key, double value) {
1071        }
1072
1073        @Override
1074        public void putFloat(String key, float value) {
1075        }
1076
1077        @Override
1078        public void putInt(String key, int value) {
1079        }
1080
1081        @Override
1082        public void putLong(String key, long value) {
1083        }
1084
1085        @Override
1086        public void remove(String key) {
1087        }
1088
1089        @Override
1090        public void removeNode() throws BackingStoreException {
1091        }
1092
1093        @Override
1094        public void addNodeChangeListener(NodeChangeListener ncl) {
1095        }
1096
1097        @Override
1098        public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
1099        }
1100
1101        @Override
1102        public void removeNodeChangeListener(NodeChangeListener ncl) {
1103        }
1104
1105        @Override
1106        public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
1107        }
1108
1109        @Override
1110        public void sync() throws BackingStoreException {
1111        }
1112
1113        @Override
1114        public String toString() {
1115            return null;
1116        }
1117    }
1118}
1119