openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupTest.java
author Jesse Glick <jglick@netbeans.org>
Fri, 09 Oct 2009 15:11:13 -0400
changeset 833 0e00857c5827
parent 829 3b2ed3e1f01b
child 836 7bd04a33998f
permissions -rw-r--r--
Warnings.
jtulach@9
     1
/*
jtulach@302
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@189
     3
 *
mzlamal@829
     4
 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
jtulach@189
     5
 *
jtulach@302
     6
 * The contents of this file are subject to the terms of either the GNU
jtulach@302
     7
 * General Public License Version 2 only ("GPL") or the Common
jtulach@302
     8
 * Development and Distribution License("CDDL") (collectively, the
jtulach@302
     9
 * "License"). You may not use this file except in compliance with the
jtulach@302
    10
 * License. You can obtain a copy of the License at
jtulach@302
    11
 * http://www.netbeans.org/cddl-gplv2.html
jtulach@302
    12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jtulach@302
    13
 * specific language governing permissions and limitations under the
jtulach@302
    14
 * License.  When distributing the software, include this License Header
jtulach@302
    15
 * Notice in each file and include the License file at
jtulach@302
    16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
jtulach@302
    17
 * particular file as subject to the "Classpath" exception as provided
jtulach@302
    18
 * by Sun in the GPL Version 2 section of the License file that
jtulach@302
    19
 * accompanied this code. If applicable, add the following below the
jtulach@302
    20
 * License Header, with the fields enclosed by brackets [] replaced by
jtulach@302
    21
 * your own identifying information:
jtulach@189
    22
 * "Portions Copyrighted [year] [name of copyright owner]"
jtulach@189
    23
 *
jtulach@302
    24
 * Contributor(s):
jtulach@302
    25
 *
jtulach@189
    26
 * The Original Software is NetBeans. The Initial Developer of the Original
jtulach@189
    27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
jtulach@9
    28
 * Microsystems, Inc. All Rights Reserved.
jtulach@302
    29
 *
jtulach@302
    30
 * If you wish your version of this file to be governed by only the CDDL
jtulach@302
    31
 * or only the GPL Version 2, indicate your decision by adding
jtulach@302
    32
 * "[Contributor] elects to include this software in this distribution
jtulach@302
    33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jtulach@302
    34
 * single choice of license, a recipient has the option to distribute
jtulach@302
    35
 * your version of this file under either the CDDL, the GPL Version 2 or
jtulach@302
    36
 * to extend the choice of license to its licensees as provided above.
jtulach@302
    37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jtulach@302
    38
 * Version 2 license, then the option applies only if the new code is
jtulach@302
    39
 * made subject to such option by the copyright holder.
jtulach@9
    40
 */
jtulach@9
    41
jtulach@9
    42
package org.openide.util.lookup;
jtulach@9
    43
jtulach@545
    44
import java.util.concurrent.ExecutionException;
jtulach@9
    45
jtulach@9
    46
import java.lang.ref.WeakReference;
jtulach@9
    47
import java.util.*;
jtulach@545
    48
import java.util.concurrent.Executors;
jtulach@545
    49
import java.util.concurrent.TimeUnit;
jtulach@9
    50
import org.netbeans.junit.*;
jtulach@550
    51
import org.openide.util.Lookup;
jtulach@359
    52
import org.openide.util.lookup.AbstractLookup.Pair;
jtulach@9
    53
jglick@833
    54
@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
jtulach@9
    55
public class AbstractLookupTest extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
jtulach@9
    56
    public AbstractLookupTest(java.lang.String testName) {
jtulach@9
    57
        super(testName, null);
jtulach@9
    58
    }
jtulach@189
    59
jtulach@189
    60
    //
jtulach@9
    61
    // Impl of AbstractLookupBaseHid.Impl
jtulach@189
    62
    //
jtulach@189
    63
jtulach@9
    64
    /** Creates the initial abstract lookup.
jtulach@9
    65
     */
jtulach@9
    66
    public Lookup createInstancesLookup (InstanceContent ic) {
jtulach@9
    67
        return new AbstractLookup (ic, new InheritanceTree ());
jtulach@9
    68
    }
jtulach@9
    69
    
jtulach@9
    70
    /** Creates an lookup for given lookup. This class just returns 
jtulach@9
    71
     * the object passed in, but subclasses can be different.
jtulach@9
    72
     * @param lookup in lookup
jtulach@9
    73
     * @return a lookup to use
jtulach@9
    74
     */
jtulach@9
    75
    public Lookup createLookup (Lookup lookup) {
jtulach@9
    76
        return lookup;
jtulach@9
    77
    }
jtulach@9
    78
jtulach@9
    79
    public void clearCaches () {
jtulach@9
    80
    }    
jtulach@9
    81
    
jtulach@9
    82
    public static void main(java.lang.String[] args) {
jtulach@9
    83
        junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupTest.class));
jtulach@9
    84
    }
jtulach@9
    85
    
jtulach@9
    86
    static class LkpResultCanBeGargageCollectedAndClearsTheResult extends AbstractLookup {
jtulach@9
    87
        public int cleared;
jtulach@9
    88
        public int dirty;
jtulach@9
    89
jglick@833
    90
        synchronized @Override boolean cleanUpResult(Template t) {
jtulach@9
    91
            boolean res = super.cleanUpResult (t);
jtulach@9
    92
            if (res) {
jtulach@9
    93
                cleared++;
jtulach@9
    94
            } else {
jtulach@9
    95
                dirty++;
jtulach@9
    96
            }
jtulach@9
    97
jtulach@9
    98
            notifyAll ();
jtulach@9
    99
jtulach@9
   100
            return res;
jtulach@9
   101
        }
jtulach@9
   102
    }
jtulach@9
   103
    public void testResultCanBeGargageCollectedAndClearsTheResult () throws Exception {
jtulach@9
   104
        LkpResultCanBeGargageCollectedAndClearsTheResult lkp = new LkpResultCanBeGargageCollectedAndClearsTheResult ();
jtulach@9
   105
        assertSize ("24 for AbstractLookup, 8 for two ints", 32, lkp);
jtulach@9
   106
        synchronized (lkp) {
jtulach@9
   107
            Lookup.Result res = lkp.lookup (new Lookup.Template (getClass ()));
jtulach@9
   108
            res.allItems();
jtulach@9
   109
            
jtulach@9
   110
            WeakReference ref = new WeakReference (res);
jtulach@9
   111
            res = null;
jtulach@9
   112
            assertGC ("Reference can get cleared", ref);
jtulach@9
   113
         
jtulach@9
   114
            // wait till we 
jtulach@9
   115
            while (lkp.cleared == 0 && lkp.dirty == 0) {
jtulach@9
   116
                lkp.wait ();
jtulach@9
   117
            }
jtulach@9
   118
            
jtulach@9
   119
            assertEquals ("No dirty cleanups", 0, lkp.dirty);
jtulach@9
   120
            assertEquals ("One final cleanup", 1, lkp.cleared);
jtulach@9
   121
        }
jtulach@9
   122
        //assertSize ("Everything has been cleaned to original size", 32, lkp);
jtulach@9
   123
        
jtulach@9
   124
    }
jtulach@9
   125
    
jtulach@9
   126
    public void testPairCannotBeUsedInMoreThanOneLookupAtOnce () throws Exception {
jtulach@9
   127
        /** Simple pair with no data */
jtulach@9
   128
        class EmptyPair extends AbstractLookup.Pair {
jtulach@9
   129
            protected boolean creatorOf(Object obj) { return false; }
jtulach@9
   130
            public String getDisplayName() { return "Empty"; }
jtulach@9
   131
            public String getId() { return "empty"; }
jtulach@9
   132
            public Object getInstance() { return null; }
jtulach@9
   133
            public Class getType() { return Object.class; }
jtulach@9
   134
            protected boolean instanceOf(Class c) { return c == getType (); }
jtulach@9
   135
        } // end of EmptyPair
jtulach@9
   136
        
jtulach@9
   137
        AbstractLookup.Content c1 = new AbstractLookup.Content ();
jtulach@9
   138
        AbstractLookup.Content c2 = new AbstractLookup.Content ();
jtulach@9
   139
        AbstractLookup l1 = new AbstractLookup (c1);
jtulach@9
   140
        AbstractLookup l2 = new AbstractLookup (c2);
jtulach@9
   141
        
jtulach@9
   142
        EmptyPair empty = new EmptyPair ();
jtulach@9
   143
        c1.addPair (empty);
jtulach@9
   144
        Lookup.Result res = l1.lookup (new Lookup.Template (Object.class));
jtulach@9
   145
        assertEquals (
jtulach@9
   146
            "Pair is really found", empty, 
jtulach@9
   147
            res.allItems ().iterator().next ()
jtulach@9
   148
        );
jtulach@9
   149
        try {
jtulach@9
   150
            c2.addPair (empty);
jtulach@9
   151
            fail ("It should not be possible to add pair to two lookups");
jtulach@9
   152
        } catch (IllegalStateException ex) {
jtulach@9
   153
            // ok, exception is fine
jtulach@9
   154
        }
jtulach@9
   155
        assertEquals (
jtulach@9
   156
            "L2 is still empty", Collections.EMPTY_LIST, 
jtulach@9
   157
            new ArrayList (l2.lookup (new Lookup.Template (Object.class)).allItems ())
jtulach@9
   158
        );
jtulach@9
   159
    }
jtulach@9
   160
    
jtulach@9
   161
    public void testInitializationCanBeDoneFromAnotherThread () {
jtulach@9
   162
        class MyLkp extends AbstractLookup implements Runnable {
jtulach@9
   163
            private InstanceContent ic;
jtulach@9
   164
            private boolean direct;
jtulach@9
   165
            
jtulach@9
   166
            public MyLkp (boolean direct) {
jtulach@9
   167
                this (direct, new InstanceContent ());
jtulach@9
   168
            }
jtulach@9
   169
                
jtulach@9
   170
            private MyLkp (boolean direct, InstanceContent ic) {
jtulach@9
   171
                super (ic);
jtulach@9
   172
                this.direct = direct;
jtulach@9
   173
                this.ic = ic;
jtulach@9
   174
            }
jtulach@9
   175
            
jglick@833
   176
            protected @Override void initialize() {
jtulach@9
   177
                if (direct) {
jtulach@9
   178
                    run ();
jtulach@9
   179
                } else {
jtulach@545
   180
                    try {
jtulach@545
   181
                        Executors.newSingleThreadScheduledExecutor().schedule(this, 0, TimeUnit.MICROSECONDS).get();
jtulach@545
   182
                    } catch (InterruptedException ex) {
jtulach@545
   183
                        ex.printStackTrace();
jtulach@545
   184
                    } catch (ExecutionException ex) {
jtulach@545
   185
                        ex.printStackTrace();
jtulach@545
   186
                    }
jtulach@9
   187
                }
jtulach@9
   188
            }
jtulach@9
   189
            
jtulach@9
   190
            public void run () {
jtulach@9
   191
                ic.add (this);
jtulach@9
   192
                ic.remove (this);
jtulach@9
   193
                ic.set (Collections.nCopies(10, this), null);
jtulach@9
   194
                ic.set (Collections.EMPTY_LIST, null);
jtulach@9
   195
                ic.add (AbstractLookupTest.this);
jtulach@9
   196
            }
jtulach@9
   197
        }
jtulach@9
   198
        
jtulach@9
   199
        assertEquals ("The test should be there", this, new MyLkp (true).lookup (Object.class));
jtulach@9
   200
        assertEquals ("and in async mode as well", this, new MyLkp (false).lookup (Object.class));
jtulach@9
   201
    }
jtulach@9
   202
    
jtulach@9
   203
    public void testBeforeLookupIsCalled () {
jtulach@9
   204
        class BeforeL extends AbstractLookup {
jtulach@9
   205
            public ArrayList list = new ArrayList ();
jtulach@9
   206
            public String toAdd;
jtulach@9
   207
            public InstanceContent ic;
jtulach@9
   208
            
jtulach@9
   209
            public BeforeL () {
jtulach@9
   210
                this (new InstanceContent ());
jtulach@9
   211
            }
jtulach@9
   212
            
jtulach@9
   213
            private BeforeL (InstanceContent c) {
jtulach@9
   214
                super (c);
jtulach@9
   215
                this.ic = c;
jtulach@9
   216
            }
jtulach@9
   217
        
jglick@833
   218
            protected @Override void beforeLookup(Template t) {
jtulach@9
   219
                if (toAdd != null) {
jtulach@9
   220
                    list.add (0, new SerialPair (toAdd));
jtulach@9
   221
                    setPairs (list);
jtulach@9
   222
                } else {
jtulach@9
   223
                    ic.add (new Integer (1));
jtulach@9
   224
                }
jtulach@9
   225
            }
jtulach@9
   226
        }
jtulach@9
   227
        
jtulach@9
   228
        BeforeL lookup = new BeforeL ();
jtulach@9
   229
        
jtulach@9
   230
        lookup.toAdd = "First";
jtulach@9
   231
        assertEquals ("First if found", "First", lookup.lookup (String.class));
jtulach@9
   232
        
jtulach@9
   233
        lookup.toAdd = "2";
jtulach@9
   234
        assertEquals ("2 is not first", "2", lookup.lookup (String.class));
jtulach@9
   235
        
jtulach@9
   236
        Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
jtulach@9
   237
        for (int i = 3; i < 20; i++) {
jtulach@9
   238
            lookup.toAdd = String.valueOf (i);
jtulach@9
   239
            assertEquals (i + " items are now there", i, res.allInstances ().size ());
jtulach@9
   240
        }
jtulach@9
   241
        for (int i = 20; i < 35; i++) {
jtulach@9
   242
            lookup.toAdd = String.valueOf (i);
jtulach@9
   243
            assertEquals (i + " items are now there", i, res.allItems ().size ());
jtulach@9
   244
        }
jtulach@9
   245
        
jtulach@9
   246
        assertEquals ("Just strings are there now", 1, res.allClasses ().size ());
jtulach@9
   247
        lookup.toAdd = null; // this will add integer
jtulach@9
   248
        assertEquals ("Two classes now", 2, res.allClasses ().size ());
jtulach@9
   249
    }
jtulach@130
   250
jtulach@130
   251
    public void testInconsistentAfterDeserIssue71744() throws Exception {
jtulach@130
   252
        InheritanceTree inhTree = new InheritanceTree();
jtulach@130
   253
jtulach@130
   254
        AbstractLookup al = new AbstractLookup(new AbstractLookup.Content(), inhTree);
jtulach@130
   255
        {
jtulach@130
   256
jtulach@130
   257
            Collection r = al.lookup(new Lookup.Template(Integer.class)).allInstances();
jtulach@130
   258
            assertEquals("None", 0, r.size());
jtulach@130
   259
        }
jtulach@130
   260
jtulach@130
   261
        ICP item = new ICP(new Integer(10));
jtulach@130
   262
        al.addPair(item);
jtulach@130
   263
        al.removePair(item);
jtulach@130
   264
jtulach@551
   265
        AbstractLookup newLookup = (AbstractLookup)reserialize(al);
jtulach@130
   266
jtulach@130
   267
        newLookup.lookup(Number.class);
jtulach@130
   268
jtulach@130
   269
jtulach@130
   270
        newLookup.addPair(new ICP(new Long(20)));
jtulach@130
   271
jtulach@130
   272
        {
jtulach@130
   273
jtulach@130
   274
            Collection r = newLookup.lookup(new Lookup.Template(Number.class)).allInstances();
jtulach@130
   275
            assertEquals("one", 1, r.size());
jtulach@130
   276
/*
jtulach@130
   277
            Iterator it = r.iterator();
jtulach@130
   278
            assertEquals(new Integer(10), it.next());
jtulach@130
   279
            assertEquals(new Long(20), it.next());*/
jtulach@130
   280
        }
jtulach@130
   281
    }
jtulach@130
   282
jtulach@359
   283
    public void testMatchesIssue130673() {
jtulach@359
   284
        class BrokenPairReturningNullID extends Pair<Object> {
jtulach@359
   285
            @Override
jtulach@359
   286
            protected boolean instanceOf(Class<?> c) {
jtulach@359
   287
                return false;
jtulach@359
   288
            }
jtulach@359
   289
jtulach@359
   290
            @Override
jtulach@359
   291
            protected boolean creatorOf(Object obj) {
jtulach@359
   292
                return false;
jtulach@359
   293
            }
jtulach@359
   294
jtulach@359
   295
            @Override
jtulach@359
   296
            public Object getInstance() {
jtulach@359
   297
                return null;
jtulach@359
   298
            }
jtulach@359
   299
jtulach@359
   300
            @Override
jtulach@359
   301
            public Class<? extends Object> getType() {
jtulach@359
   302
                return null;
jtulach@359
   303
            }
jtulach@359
   304
jtulach@359
   305
            @Override
jtulach@359
   306
            public String getId() {
jtulach@359
   307
                return null;
jtulach@359
   308
            }
jtulach@359
   309
jtulach@359
   310
            @Override
jtulach@359
   311
            public String getDisplayName() {
jtulach@359
   312
                return null;
jtulach@359
   313
            }
jtulach@359
   314
        }
jtulach@359
   315
        BrokenPairReturningNullID broken = new BrokenPairReturningNullID();
jtulach@359
   316
        
jtulach@359
   317
        
jtulach@359
   318
        Lookup.Template<String> t = new Lookup.Template<String>(String.class, "ID", null);
jtulach@359
   319
        boolean not = AbstractLookup.matches(t, broken, true);
jtulach@359
   320
        assertFalse("Does not match the template, but throws no exception", not);
jtulach@359
   321
    }
jtulach@359
   322
    
jtulach@130
   323
    private static final class ICP extends AbstractLookup.Pair {
jtulach@130
   324
        private Number s;
jtulach@130
   325
jtulach@130
   326
        public ICP (Number s) {
jtulach@130
   327
            this.s = s;
jtulach@130
   328
        }
jtulach@130
   329
jtulach@130
   330
jtulach@130
   331
        protected boolean instanceOf(Class c) {
jtulach@130
   332
            return c.isInstance(s);
jtulach@130
   333
        }
jtulach@130
   334
jtulach@130
   335
        protected boolean creatorOf(Object obj) {
jtulach@130
   336
            return s == obj;
jtulach@130
   337
        }
jtulach@130
   338
jtulach@130
   339
        public Object getInstance() {
jtulach@130
   340
            return s;
jtulach@130
   341
        }
jtulach@130
   342
jtulach@130
   343
        public Class getType() {
jtulach@130
   344
            return s.getClass();
jtulach@130
   345
        }
jtulach@130
   346
jtulach@130
   347
        public String getId() {
jtulach@130
   348
            return s.toString();
jtulach@130
   349
        }
jtulach@130
   350
jtulach@130
   351
        public String getDisplayName() {
jtulach@130
   352
            return getId();
jtulach@130
   353
        }
jtulach@130
   354
jtulach@130
   355
    }
jtulach@9
   356
}