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