You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 19:31:59 UTC

svn commit: r1075107 [1/2] - in /aries/tags/testsupport-0.1-incubating: ./ testsupport-unit/ testsupport-unit/src/ testsupport-unit/src/main/ testsupport-unit/src/main/java/ testsupport-unit/src/main/java/org/ testsupport-unit/src/main/java/org/apache/...

Author: zoe
Date: Sun Feb 27 18:31:58 2011
New Revision: 1075107

URL: http://svn.apache.org/viewvc?rev=1075107&view=rev
Log:
Restore testsupport 0.1

Added:
    aries/tags/testsupport-0.1-incubating/
    aries/tags/testsupport-0.1-incubating/LICENSE
    aries/tags/testsupport-0.1-incubating/NOTICE
    aries/tags/testsupport-0.1-incubating/pom.xml
    aries/tags/testsupport-0.1-incubating/testsupport-unit/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/pom.xml
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleContextMock.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleMock.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/MockInitialContextFactoryBuilder.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/ArchiveFixture.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/Assert.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultInvocationHandler.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultMethodCallHandlers.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultReturnTypeHandlers.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/ExceptionListener.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/MethodCall.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/MethodCallHandler.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/ReturnTypeHandler.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/Skeleton.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/annotations/
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/annotations/InjectSkeleton.java
    aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/annotations/Singleton.java

Added: aries/tags/testsupport-0.1-incubating/LICENSE
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/LICENSE?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/LICENSE (added)
+++ aries/tags/testsupport-0.1-incubating/LICENSE Sun Feb 27 18:31:58 2011
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

Added: aries/tags/testsupport-0.1-incubating/NOTICE
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/NOTICE?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/NOTICE (added)
+++ aries/tags/testsupport-0.1-incubating/NOTICE Sun Feb 27 18:31:58 2011
@@ -0,0 +1,8 @@
+
+Apache Aries
+Copyright 2009-2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+

Added: aries/tags/testsupport-0.1-incubating/pom.xml
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/pom.xml?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/pom.xml (added)
+++ aries/tags/testsupport-0.1-incubating/pom.xml Sun Feb 27 18:31:58 2011
@@ -0,0 +1,48 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.apache.aries</groupId>
+        <artifactId>java5-parent</artifactId>
+        <version>0.1-incubating</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.aries.testsupport</groupId>
+    <artifactId>testsupport</artifactId>
+    <name>Apache Aries Test Support</name>
+    <version>0.1-incubating</version>
+    <packaging>pom</packaging>
+
+    <description>
+        Test Support for OSGi
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/incubator/aries/tags/testsupport-0.1-incubating</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/aries/tags/testsupport-0.1-incubating</developerConnection>
+        <url>http://svn.apache.org/viewvc/incubator/aries/tags/testsupport-0.1-incubating</url>
+    </scm>
+
+    <modules>
+        <module>testsupport-unit</module>
+    </modules>
+
+</project>

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/pom.xml
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/pom.xml?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/pom.xml (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/pom.xml Sun Feb 27 18:31:58 2011
@@ -0,0 +1,52 @@
+
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to you under the Apache License, Version
+    2.0 (the "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+    applicable law or agreed to in writing, software distributed under
+    the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+    OR CONDITIONS OF ANY KIND, either express or implied. See the
+    License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.aries.testsupport</groupId>
+    <artifactId>testsupport</artifactId>
+    <version>0.1-incubating</version>
+  </parent>
+
+  <artifactId>org.apache.aries.testsupport.unit</artifactId>
+  <packaging>bundle</packaging>
+  <name>Apache Aries Unit Test Support</name>
+  <description>
+      This bundle provides unit test support.
+  </description>
+
+    <properties>
+        <aries.osgi.export.pkg>
+            org.apache.aries.*
+        </aries.osgi.export.pkg>
+    </properties>
+
+   <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleContextMock.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleContextMock.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleContextMock.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleContextMock.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,763 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.mocks;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import junit.framework.AssertionFailedError;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import org.apache.aries.unittest.mocks.Skeleton;
+
+/**
+ *
+ */
+/**
+ * This class is a partial implementation of BundleContext. Its main function
+ * is to provide a service registry implementation
+ */
+public class BundleContextMock
+{
+  /** The service registry */
+  private static Map<String, List<ServiceData>> registry = new HashMap<String, List<ServiceData>>();
+  /** A list of bundles installed into the runtime */
+  private static List<Bundle> bundles = new ArrayList<Bundle>();
+  /** A list of service listeners */
+  private static List<ServiceListener> listeners = new ArrayList<ServiceListener>();
+  /** The next service id to be assigned */
+  private static long nextId = 0;
+
+  private static class MockServiceFactory implements ServiceFactory
+  {
+    private final Object service;
+    
+    public MockServiceFactory(Object obj)
+    {
+      service = obj;
+    }
+    
+    public Object getService(Bundle arg0, ServiceRegistration arg1)
+    {
+      return service;
+    }
+
+    public void ungetService(Bundle arg0, ServiceRegistration arg1, Object arg2)
+    {
+    }
+  }
+  
+  private static class FilteredServiceListener implements ServiceListener
+  {
+    private Filter filter;
+    private final ServiceListener listener;
+    
+    public FilteredServiceListener(String f, ServiceListener l)
+    {
+      listener = l;
+      
+      if (f != null) {
+        try {
+          filter = FrameworkUtil.createFilter(f);
+        } catch (InvalidSyntaxException e) {
+          AssertionFailedError err = new AssertionFailedError("The filter " + f + " is invalid");
+          err.initCause(e);
+          
+          throw err;
+        }
+      }
+    }
+
+    public void serviceChanged(ServiceEvent arg0)
+    {
+      if (matches(arg0)) listener.serviceChanged(arg0);
+    }
+
+    private boolean matches(ServiceEvent arg0)
+    {
+      if (filter == null) return true;
+      
+      ServiceReference ref = arg0.getServiceReference();
+      
+      if (Skeleton.isSkeleton(ref)) {
+        Object template = Skeleton.getSkeleton(ref).getTemplateObject();
+        
+        if (template instanceof ServiceData) {
+          return filter.match(((ServiceData)template).getProperties());
+        }
+      }
+      
+      return filter.match(ref);
+    }
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+      if (obj == null) return false;
+      else if (obj instanceof FilteredServiceListener) {
+        return listener.equals(((FilteredServiceListener)obj).listener);
+      }
+      
+      return false;
+    }
+    
+    @Override
+    public int hashCode()
+    {
+      return listener.hashCode();
+    }
+  }
+  
+  /**
+   * This class represents the information registered about a service. It also
+   * implements part of the ServiceRegistration and ServiceReference interfaces.
+   */
+  private class ServiceData implements Comparable<ServiceReference>
+  {
+    /** The service that was registered */
+    private ServiceFactory serviceImpl;
+    /** the service properties */
+    @SuppressWarnings("unused")
+    private final Hashtable<String, Object> serviceProps = new Hashtable<String, Object>();
+    /** The interfaces the service publishes with */
+    private String[] interfaceNames;
+    /** The bundle that defines this service */
+    private Bundle registeringBundle;
+
+    /**
+     * This method unregisters the service from the registry.
+     */
+    public void unregister()
+    {
+      for (String interfaceName : interfaceNames) {
+        List<ServiceData> list = registry.get(interfaceName);
+        if (list != null) {
+          list.remove(this);
+          if (list.isEmpty()) {
+            registry.remove(interfaceName);
+          }
+        }
+      }
+      notifyAllListeners(ServiceEvent.UNREGISTERING);
+      registeringBundle = null;
+    }
+
+    /**
+     * This method is used to register the service data in the registry
+     */
+    public void register()
+    {
+      for (String interfaceName : interfaceNames) {
+        List<ServiceData> list = registry.get(interfaceName);
+        if (list == null) {
+          list = new ArrayList<ServiceData>();
+          registry.put(interfaceName, list);
+        }
+        list.add(this);
+      }
+      notifyAllListeners(ServiceEvent.REGISTERED);
+    }
+    
+    private void notifyAllListeners(int eventType) {
+      List<ServiceListener> copy = new ArrayList<ServiceListener>(listeners.size());
+      copy.addAll(listeners);
+      for(ServiceListener listener : copy) {
+        listener.serviceChanged(new ServiceEvent(eventType, Skeleton.newMock(this, ServiceReference.class)));
+      }
+    }
+    
+    /**
+     * Change the service properties
+     * @param newProps
+     */
+    public void setProperties(Dictionary<String,Object> newProps)
+    {
+      // make sure we don't overwrite framework properties
+      newProps.put(Constants.OBJECTCLASS, serviceProps.get(Constants.OBJECTCLASS));
+      newProps.put(Constants.SERVICE_ID, serviceProps.get(Constants.SERVICE_ID));
+
+      Enumeration<String> keys = newProps.keys();
+      
+      serviceProps.clear();
+      while (keys.hasMoreElements()) {
+        String key = keys.nextElement();
+        serviceProps.put(key, newProps.get(key));
+      }
+      
+      notifyAllListeners(ServiceEvent.MODIFIED);
+    }
+    
+    /**
+     * This implements the isAssignableTo method from ServiceReference.
+     * 
+     * @param b
+     * @param className
+     * @return true if the referenced service can be assigned to the requested
+     *              class name.
+     */
+    public boolean isAssignableTo(Bundle b, String className)
+    {
+      boolean result = false;
+      
+      for (String iName : interfaceNames)
+      {
+        result = iName.equals(className);
+        
+        if (result) break;
+      }
+      
+      return result;
+    }
+    
+    /**
+     * Returns the requested service property.
+     * @param key the property to return.
+     * @return the property value.
+     */
+    public Object getProperty(String key)
+    {
+      return serviceProps.get(key);
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+      if(o == null) return false;
+      
+      if(o == this) return true;
+      
+      if (o instanceof ServiceData) {
+        ServiceData other = (ServiceData) o;
+        return serviceImpl == other.serviceImpl;
+      }
+      
+      return false;
+    }
+    
+    @Override
+    public int hashCode()
+    {
+      return serviceImpl.hashCode();
+    }
+    
+    /**
+     * @return the keys of all the service properties.
+     */
+    public String[] getPropertyKeys()
+    {
+      Enumeration<String> e = serviceProps.keys();
+      
+      String[] toReturn = new String[serviceProps.size()];
+      
+      for(int i = 0 ; i < serviceProps.size(); i++)
+        toReturn[i] = e.nextElement();
+      
+      return toReturn;
+    }
+    
+    /**
+     * @return the bundle this service reference was registered against.
+     */
+    public Bundle getBundle()
+    {
+      return registeringBundle;
+    }
+    
+    /**
+     * @return a service reference for this service registration.
+     */
+    public ServiceReference getReference()
+    {
+      return Skeleton.newMock(this, ServiceReference.class);
+    }
+    
+    public Hashtable<String, Object> getProperties()
+    {
+      return new Hashtable<String, Object>(serviceProps);
+    }
+
+    /**
+     * Implement the standard behaviour of the registry
+     */
+    public int compareTo(ServiceReference o) {
+      Integer rank = (Integer) serviceProps.get(Constants.SERVICE_RANKING);
+      if(rank == null)
+        rank = 0;
+      
+      Integer otherRank = (Integer) o.getProperty(Constants.SERVICE_RANKING);
+      if(otherRank == null)
+        otherRank = 0;
+      //Higher rank = higher order
+      int result = rank.compareTo(otherRank);
+      
+      if(result == 0) {
+        Long id = (Long) serviceProps.get(Constants.SERVICE_ID);
+        Long otherId = (Long) o.getProperty(Constants.SERVICE_ID);
+        //higher id = lower order
+        return otherId.compareTo(id);
+      }
+      return result;
+    }
+  }
+
+  /** The bundle associated with this bundle context */
+  private Bundle bundle;
+
+  /**
+   * Default constructor, widely used in the tests.
+   */
+  public BundleContextMock()
+  {
+    bundle = Skeleton.newMock(new BundleMock("test." + new Random(System.currentTimeMillis()).nextInt(),
+                              new Hashtable<Object, Object>()), Bundle.class);
+  }
+  
+  /**
+   * Constructor used by BundleMock, it ensures the bundle and its context are wired together correctly.
+   * 
+   * TODO We have to many Bundle mocks objects for a single OSGi bundle, we need to update this.
+   * 
+   * @param b
+   */
+  public BundleContextMock(Bundle b)
+  {
+    bundle = b;
+  }
+  
+  /**
+   * This checks that we have at least one service with this interface name.
+   * 
+   * @param interfaceName the name of the interface.
+   */
+  public static void assertServiceExists(String interfaceName)
+  {
+    assertTrue("No service registered with interface " + interfaceName + ". Services found: " + registry.keySet(), registry.containsKey(interfaceName));
+  }
+  
+  /**
+   * This checks that we have at no services with this interface name.
+   * 
+   * @param interfaceName the name of the interface.
+   */
+  public static void assertNoServiceExists(String interfaceName)
+  {
+    assertFalse("Services registered with interface " + interfaceName + ". Services found: " + registry.keySet(), registry.containsKey(interfaceName));
+  }
+  
+  /**
+   * This implements the registerService method from BundleContext.
+   * 
+   * @param interFace
+   * @param service
+   * @param properties
+   * @return the ServiceRegistration object for this service.
+   */
+  public ServiceRegistration registerService(String interFace, final Object service, Dictionary<String, Object> properties)
+  {
+    // validate that the service implements interFace
+    try {
+      Class<?> clazz = Class.forName(interFace, false, service.getClass().getClassLoader());
+      
+      if (!!!clazz.isInstance(service) && !!!(service instanceof ServiceFactory)) {
+        throw new AssertionFailedError("The service " + service + " does not implement " + interFace);
+      }
+    } catch (ClassNotFoundException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+
+    ServiceFactory factory = new MockServiceFactory(service);
+    return registerService(new String[] {interFace}, factory, properties);
+  }
+  
+  /**
+   * This implements the registerService method from BundleContext.
+   * 
+   * @param interfaces
+   * @param service
+   * @param properties
+   * @return the ServiceRegistration object for this service.
+   */
+  public ServiceRegistration registerService(String[] interfaces, Object service, Dictionary<String, Object> properties)
+  {
+    if (properties == null) properties = new Hashtable<String, Object>();
+    
+    ServiceData data = new ServiceData();
+    // cast the service to a service factory because in our framework we only ever register
+    // a service factory. If we every put a non-service factory object in that is a failure.
+    properties.put(Constants.OBJECTCLASS, interfaces);
+    properties.put(Constants.SERVICE_ID, nextId++);
+    if (service instanceof ServiceFactory) {
+      data.serviceImpl = (ServiceFactory)service;
+    } else {
+      data.serviceImpl = new MockServiceFactory(service);
+    }
+    data.interfaceNames = interfaces;
+    data.registeringBundle = bundle;
+    
+    Enumeration<String> keys = properties.keys();
+    
+    while (keys.hasMoreElements()) {
+      String key = keys.nextElement();
+      data.serviceProps.put(key, properties.get(key));
+    }
+    
+    data.register();
+    
+    return Skeleton.newMock(data, ServiceRegistration.class);
+  }
+
+  /**
+   * This helper method is used to get the service from the registry with the
+   * given interface name.
+   * 
+   * <p>This should really return multiple services.
+   * </p>
+   * 
+   * @param interfaceName the interface name.
+   * @param bundle        the bundle name.
+   * @return the registered service.
+   */
+  public static Object getService(String interfaceName, Bundle bundle)
+  {
+    List<ServiceData> datum = registry.get(interfaceName);
+    
+    if (datum == null) return null;
+    else if (datum.isEmpty()) return null;
+    // this is safe for now, but may not be when we do other scoped components.
+    else {
+      ServiceRegistration reg = Skeleton.newMock(ServiceRegistration.class);
+      return datum.iterator().next().serviceImpl.getService(bundle, reg);
+    }
+  }
+  
+  /**
+   * A mock implementation of the getServiceReferences method. It does not currently
+   * process the filter, this is probably a bit hard, so we might cheat when we do.
+   * 
+   * <p>Note this does not check that the service classes are visible to the
+   *   caller as OSGi does. It is equivalent to getAllServiceReferences.
+   * </p>
+   * 
+   * @param className the name of the class the lookup is for.
+   * @param filter
+   * @return an array of matching service references.
+   * @throws InvalidSyntaxException
+   */
+  public ServiceReference[] getServiceReferences(String className, String filter) throws InvalidSyntaxException
+  {
+    List<ServiceData> data = new ArrayList<ServiceData>();
+    
+    if (className != null) {
+      List<ServiceData> tmpData = registry.get(className);
+      if (tmpData != null) data.addAll(tmpData);
+    } else {
+      data = new ArrayList<ServiceData>();
+      for (List<ServiceData> value : registry.values())
+      data.addAll(value);
+    }
+    
+    ServiceReference[] refs;
+
+    if (data == null) {
+      refs = null;
+    } else {
+      
+      if (filter != null) {
+        Filter f = FrameworkUtil.createFilter(filter);
+        
+        Iterator<ServiceData> it = data.iterator();
+        
+        while (it.hasNext()) {
+          ServiceData sd = it.next();
+          
+          if (!!!f.match(sd.getProperties())) it.remove();
+        }
+      }
+      
+      if (data.isEmpty()) return null;
+      
+      refs = new ServiceReference[data.size()];
+      for (int i = 0; i < refs.length; i++) {
+        refs[i] = Skeleton.newMock(data.get(i), ServiceReference.class);
+      }
+    }
+    
+    return refs;
+  }
+  
+  /**
+   * Gets the first matching service reference.
+   * 
+   * @param className the class name wanted.
+   * @return the matchine service, or null if one cannot be found.
+   */
+  public ServiceReference getServiceReference(String className)
+  {
+    ServiceReference[] refs;
+    try {
+      refs = getServiceReferences(className, null);
+      if (refs != null) return refs[0];
+      
+      return null;
+    } catch (InvalidSyntaxException e) {
+      // should never happen.
+      e.printStackTrace();
+    }
+    return null;
+  }
+  
+  /**
+   * This method finds all the service references in the registry with the
+   * matching class name and filter.
+   * 
+   * @param className
+   * @param filter
+   * @return the matching service references.
+   * @throws InvalidSyntaxException
+   */
+  public ServiceReference[] getAllServiceReferences(String className, String filter) throws InvalidSyntaxException
+  {
+    return getServiceReferences(className, filter);
+  }
+  
+  /**
+   * Retrieve a service from the registry.
+   * @param ref the service reference.
+   * @return    the returned service.
+   */
+  public Object getService(ServiceReference ref)
+  {
+    ServiceData data = (ServiceData)Skeleton.getSkeleton(ref).getTemplateObject();
+    
+    return data.serviceImpl.getService(getBundle(), Skeleton.newMock(data, ServiceRegistration.class));
+  }
+  
+  /**
+   * This method implements the installBundle method from BundleContext. It
+   * makes use of the java.util.jar package to parse the manifest from the input
+   * stream.
+   * 
+   * @param location the location of the bundle.
+   * @param is       the input stream to read from.
+   * @return         the created bundle.
+   * @throws BundleException
+   */
+  public Bundle installBundle(String location, InputStream is) throws BundleException
+  {
+    Bundle b;
+    JarInputStream jis;
+    try {
+      jis = new JarInputStream(is);
+
+      Manifest man = jis.getManifest();
+      
+      b = createBundle(man, null);
+      
+    } catch (IOException e) {
+      throw new BundleException(e.getMessage(), e);
+    }
+    
+    return b;
+  }
+
+  /**
+   * Create a mock bundle correctly configured using the supplied manifest and
+   * location.
+   * 
+   * @param man      the manifest to load.
+   * @param location the location on disk.
+   * @return the created bundle
+   * @throws MalformedURLException
+   */
+  private Bundle createBundle(Manifest man, String location) throws MalformedURLException
+  {
+    Attributes attribs = man.getMainAttributes();
+    String symbolicName = attribs.getValue(Constants.BUNDLE_SYMBOLICNAME);
+    
+    Hashtable<Object, Object> attribMap = new Hashtable<Object, Object>();
+    
+    for (Map.Entry<Object, Object> entry : attribs.entrySet()) {
+      Attributes.Name name = (Attributes.Name)entry.getKey();
+      attribMap.put(name.toString(), entry.getValue());
+    }
+    
+    BundleMock mock = new BundleMock(symbolicName, attribMap, location);
+
+    mock.addToClassPath(new File("build/unittest/classes").toURL());
+
+    Bundle b = Skeleton.newMock(mock, Bundle.class);
+    
+    bundles.add(b);
+
+    return b;
+  }
+  
+  /**
+   * Asks to install an OSGi bundle from the given location.
+   * 
+   * @param location the location of the bundle on the file system.
+   * @return the installed bundle.
+   * @throws BundleException
+   */
+  public Bundle installBundle(String location) throws BundleException
+  {
+    try {
+      URI uri = new URI(location.replaceAll(" ", "%20"));
+
+      File baseDir = new File(uri);
+      Manifest man = null;
+      //check if it is a directory
+      if (baseDir.isDirectory()){
+      man = new Manifest(new FileInputStream(new File(baseDir, "META-INF/MANIFEST.MF")));
+      }
+      //if it isn't assume it is a jar file
+      else{
+        InputStream is = new FileInputStream(baseDir);
+        JarInputStream jis = new JarInputStream(is);
+        man = jis.getManifest();
+        jis.close();
+        if (man == null){
+          throw new BundleException("Null manifest");
+        }
+      }
+      
+      return createBundle(man, location);
+    } catch (IOException e) {
+      throw new BundleException(e.getMessage(), e);
+    } catch (URISyntaxException e) {
+      // TODO Auto-generated catch block
+      throw new BundleException(e.getMessage(), e);
+    }
+  }
+  
+  /**
+   * @return all the bundles in the system
+   */
+    public Bundle[] getBundles()
+  {
+    return bundles.toArray(new Bundle[bundles.size()]);
+  }
+  
+  /**
+   * Add a service listener.
+   * 
+   * @param listener
+   * @param filter
+   */
+  public void addServiceListener(ServiceListener listener, String filter)
+  {
+    listeners.add(new FilteredServiceListener(filter, listener));
+  }
+
+  /**
+   * Add a service listener.
+   * 
+   * @param listener
+   */
+  public void addServiceListener(ServiceListener listener) 
+  {
+    listeners.add(listener);
+  }
+  
+  /**
+   * Remove a service listener
+   * @param listener
+   */
+  public void removeServiceListener(ServiceListener listener)
+  {
+    listeners.remove(new FilteredServiceListener(null, listener));
+  }
+  
+  public String getProperty(String name)
+  {
+    if (Constants.FRAMEWORK_VERSION.equals(name)) {
+      return "4.1";
+    }
+    /*added System.getProperty so that tests can set a system property
+     * but it is retrieved via the BundleContext.
+     * This allows tests to emulate different properties being set on the
+     * context, helpful for the feature pack launcher/kernel relationship
+     */
+    else if (System.getProperty(name) != null){
+      return System.getProperty(name);
+    }
+    
+    return "";
+  }
+  
+  /**
+   * @return the bundle associated with this bundle context (if we created one).
+   */
+  public Bundle getBundle()
+  {
+    return bundle;
+  }
+  
+  /**
+   * This method clears the service registry.
+   */
+  public static void clear()
+  {
+    registry.clear();
+    bundles.clear();
+    listeners.clear();
+    nextId = 0;
+  }
+  
+  public static List<ServiceListener> getServiceListeners()
+  {
+    return listeners;
+  }
+
+  public void addBundle(Bundle b)
+  {
+    bundles.add(b);
+  }
+}
\ No newline at end of file

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleMock.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleMock.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleMock.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/BundleMock.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,391 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.mocks;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+import junit.framework.AssertionFailedError;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+import org.apache.aries.unittest.mocks.MethodCall;
+import org.apache.aries.unittest.mocks.MethodCallHandler;
+import org.apache.aries.unittest.mocks.Skeleton;
+import org.apache.aries.unittest.mocks.annotations.Singleton;
+
+@Singleton
+public class BundleMock
+{
+  private final String symbolicName;
+  private final Dictionary<?, ?> headers;
+  private final BundleContext bc;
+  private String location;
+  private BundleClassLoader cl;
+  
+  private class BundleClassLoader extends URLClassLoader implements BundleReference
+  {
+    List<Bundle> otherBundlesToCheck = new ArrayList<Bundle>();
+    
+    public BundleClassLoader(URL[] urls)
+    {
+      super(urls);
+    }
+
+    public BundleClassLoader(URL[] urls, ClassLoader parent)
+    {
+      super(urls, parent);
+    }
+    
+    public void addBundle(Bundle ... otherBundles)
+    {
+      otherBundlesToCheck.addAll(Arrays.asList(otherBundles));
+    }
+    
+    public Bundle[] getBundles()
+    {
+      return otherBundlesToCheck.toArray(new Bundle[otherBundlesToCheck.size()]);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+      Class<?> result = null;
+      for (Bundle b : otherBundlesToCheck) {
+        try {
+          result = b.loadClass(name);
+        } catch (ClassNotFoundException e) {
+          // do nothing here.
+        }
+        
+        if (result != null) return result;
+      }
+      
+      return super.findClass(name);
+    }
+
+    public Bundle getBundle()
+    {
+      return Skeleton.newMock(BundleMock.this, Bundle.class);
+    }
+  }
+  
+  public BundleMock(String name, Dictionary<?, ?> bundleHeaders)
+  {
+    symbolicName = name;
+    headers = bundleHeaders;
+    bc = Skeleton.newMock(new BundleContextMock(Skeleton.newMock(this, Bundle.class)), BundleContext.class);
+    
+    cl = AccessController.doPrivileged(new PrivilegedAction<BundleClassLoader>() {
+
+      public BundleClassLoader run()
+      {
+        return new BundleClassLoader(new URL[0], this.getClass().getClassLoader());
+      }
+    });
+  }
+  
+  public BundleMock(String name, Dictionary<?,?> bundleHeaders, boolean dummy)
+  {
+    this(name, bundleHeaders);
+    
+    cl = null;
+  }
+  
+  public BundleMock(String name, Dictionary<?, ?> bundleHeaders, String location)
+  {
+    this(name, bundleHeaders);
+    this.location = location;
+        
+    if (location != null) {
+      String cp = (String)bundleHeaders.get(Constants.BUNDLE_CLASSPATH);
+      
+      if (cp == null) cp = ".";
+      
+      String[] cpEntries = cp.split(",");
+      
+      final List<URL> urls = new ArrayList<URL>();
+      
+      try {
+        for (String cpEntry : cpEntries) {
+          if (".".equals(cpEntry.trim())) {
+            urls.add(new URL(location));
+          } else {
+            urls.add(new URL(location + "/" + cpEntry));
+          }
+        }
+        
+        cl = AccessController.doPrivileged(new PrivilegedAction<BundleClassLoader>() {
+          public BundleClassLoader run()
+          {
+            return new BundleClassLoader(urls.toArray(new URL[urls.size()]));
+          }
+        });
+      } catch (MalformedURLException e) {
+        Error err = new AssertionFailedError("The location was not a valid url");
+        err.initCause(e);
+        throw err;
+      }
+    }
+  }
+  
+  private static class PrivateDataFileHandler implements MethodCallHandler
+  {
+    private final File location;
+    
+    public PrivateDataFileHandler(File f)
+    {
+      this.location = f;
+    }
+    
+    public Object handle(MethodCall call, Skeleton parent)
+    {
+      File privateStorage = new File(location.getAbsolutePath(), "_private");
+      if (!!!privateStorage.exists())
+        privateStorage.mkdirs();
+      
+      return new File(privateStorage, (String) call.getArguments()[0]);
+    }
+  }
+  
+  public BundleMock(String name, Dictionary<?, ?> properties, File location) throws Exception
+  {
+    this(name,properties,location.toURL().toExternalForm());
+    
+    Skeleton bcSkel = Skeleton.getSkeleton(bc);
+    bcSkel.registerMethodCallHandler(
+        new MethodCall(BundleContext.class,"getDataFile", new Object[] { String.class }),
+        new PrivateDataFileHandler(location)
+    );
+  }
+  
+  public String getSymbolicName()
+  {
+    return symbolicName;
+  }
+  
+  public Dictionary<?, ?> getHeaders()
+  {
+    return headers;
+  }
+  
+  public Enumeration<URL> findEntries(String baseDir, String matchRule, boolean recurse)
+  {
+    System.err.println("findEntries: " + baseDir + ", " + matchRule + ", " + recurse);
+    File base;
+    try {
+      base = new File(new File(new URL(location.replaceAll(" ", "%20")).toURI()), baseDir);
+      System.err.println("Base dir: " + base);
+    } catch (Exception e) {
+      Error err = new AssertionFailedError("Unable to findEntries from " + location);
+      err.initCause(e);
+      throw err;
+    }
+    
+    if (matchRule.equals("*.xml")) matchRule = ".*\\.xml";
+    else matchRule = matchRule.replaceAll("\\*", ".*");
+    
+    System.err.println("matchrule: " + matchRule);
+    
+    final Pattern p = Pattern.compile(matchRule);
+    
+    File[] files = base.listFiles(new FileFilter(){
+      public boolean accept(File pathname)
+      {
+        return pathname.isFile() &&
+               p.matcher(pathname.getName()).matches();
+      }
+    });
+    
+    Vector<URL> v = new Vector<URL>();
+    
+    if (files != null) {
+      for (File f : files) {
+        try {
+          v.add(f.toURL());
+        } catch (MalformedURLException e) {
+          // TODO Auto-generated catch block
+          e.printStackTrace();
+        }
+      }
+    } else {
+      System.err.println("no matching files");
+    }
+    
+    if (v.isEmpty()) {
+      return null;
+    } else {
+      System.err.println(v);
+      return v.elements();
+    }
+  }
+  
+  public URL getResource(String name)
+  {
+    if (cl != null) return cl.getResource(name);
+    
+    try {
+      File f = new File(name);
+      if(f.exists() || "Entities.jar".equals(name)) return f.toURL();
+      else return null;
+    } catch (MalformedURLException e) {
+      Error err = new AssertionFailedError("The resource " + name + " could not be found.");
+      err.initCause(e);
+      throw err;
+    }
+  }
+  
+  public Enumeration<URL> getResources(String name)
+  {
+    if (cl != null)
+    {
+      try {
+        return cl.getResources(name);
+      } catch (IOException e) {
+      // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+    else {
+      final URL resource = getResource(name);
+      
+      if(resource != null) {
+        return new Enumeration<URL>() {
+
+          boolean hasMore = true;
+          public boolean hasMoreElements()
+          {
+            return hasMore;
+          }
+
+          public URL nextElement()
+          {
+            hasMore = false;
+            return resource;
+          }
+          
+        };
+      }
+    }
+    return new Enumeration<URL>(){
+      public URL nextElement()
+      {
+        return null;
+      }
+
+      public boolean hasMoreElements()
+      {
+        return false;
+      }
+    };
+    
+  }
+  
+  public Class<?> loadClass(String name) throws ClassNotFoundException
+  {
+    if (cl != null) return Class.forName(name, false, cl);
+    
+    throw new ClassNotFoundException("Argh, things went horribly wrong trying to load " + name);
+  }
+  
+  public String getLocation()
+  {
+    try {
+      return (location == null) ? new File(symbolicName + ".jar").toURL().toString() : location;
+    } catch (MalformedURLException e) {
+      Error err = new AssertionFailedError("We could not generate a valid url for the bundle");
+      err.initCause(e);
+      throw err;
+    }
+  }
+  
+  public BundleContext getBundleContext()
+  {
+    return bc;
+  }
+
+  public Version getVersion()
+  {
+    String res = (String) headers.get("Bundle-Version");
+    if (res != null)
+      return new Version(res);
+    else
+      return new Version("0.0.0");
+  }
+  
+  public int getState()
+  {
+    return Bundle.ACTIVE;
+  }
+
+  public void addToClassPath(URL ... urls)
+  {
+    if (cl != null) {
+      URL[] existingURLs = cl.getURLs();
+      final URL[] mergedURLs = new URL[urls.length + existingURLs.length];
+      int i = 0;
+      for (; i < existingURLs.length; i++) {
+        mergedURLs[i] = existingURLs[i];
+      }
+      
+      for (int j = 0; j < urls.length; j++, i++) {
+        mergedURLs[i] = urls[j];
+      }
+      
+      BundleClassLoader newCl = AccessController.doPrivileged(new PrivilegedAction<BundleClassLoader>() {
+
+        public BundleClassLoader run()
+        {
+          return new BundleClassLoader(mergedURLs, cl.getParent());
+        }
+        
+      });
+      newCl.addBundle(cl.getBundles());
+      cl = newCl;
+    }
+  }
+    
+  public void addBundleToClassPath(Bundle ... bundles) {
+    if (cl != null) {
+      cl.addBundle(bundles);
+    }
+  }
+
+  public ClassLoader getClassLoader()
+  {
+    return cl;
+  }
+}
\ No newline at end of file

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/MockInitialContextFactoryBuilder.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/MockInitialContextFactoryBuilder.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/MockInitialContextFactoryBuilder.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/mocks/MockInitialContextFactoryBuilder.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.mocks;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.NamingManager;
+
+import org.apache.aries.unittest.mocks.MethodCall;
+import org.apache.aries.unittest.mocks.Skeleton;
+
+public class MockInitialContextFactoryBuilder implements InitialContextFactoryBuilder
+{
+  private static InitialContextFactory icf;
+  
+  public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment)
+      throws NamingException
+  {
+    return icf;
+  }
+  
+  public static void start(Context ctx) throws NamingException
+  {
+    if (icf == null) {
+      NamingManager.setInitialContextFactoryBuilder(new MockInitialContextFactoryBuilder());
+    }
+    
+    icf = Skeleton.newMock(InitialContextFactory.class);
+    getSkeleton().setReturnValue(new MethodCall(InitialContextFactory.class, "getInitialContext", Hashtable.class), ctx);
+  }
+  
+  public static Skeleton getSkeleton()
+  {
+    return Skeleton.getSkeleton(icf);
+  }
+}
\ No newline at end of file

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/ArchiveFixture.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/ArchiveFixture.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/ArchiveFixture.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/fixture/ArchiveFixture.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,473 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.aries.unittest.fixture;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.osgi.framework.Constants;
+
+/**
+ * Utility class for creating archive-based fixtures such as EBA archives, jar files etc.
+ * This class provides a flow based api for defining such fixtures. For example, a simple EBA archive could 
+ * be defined as such:
+ * 
+ * <code>
+ * ArchiveFixtures.ZipFixture zip = ArchiveFixtures.newZip()
+ *   .jar("test.jar")
+ *     .manifest()
+ *       .symbolicName("com.ibm.test")
+ *       .version("2.0.0")
+ *     .end()
+ *     .file("random.txt", "Some text")
+ *   .end();
+ * </code>
+ * 
+ * This defines a zip archive containing a single jar file (hence no application manifest). The jar file itself has
+ * a manifest and a text file.
+ * 
+ * To actually create the physical archive use the <code>writeOut</code> method on the archive fixture.
+ */
+public class ArchiveFixture
+{
+  /**
+   * Create a new zip file fixture
+   * @return
+   */
+  public static ZipFixture newZip() {
+    return new ZipFixture(null);
+  }
+  
+  /**
+   * Create a new jar file fixture
+   * @return
+   */
+  public static JarFixture newJar() {
+    return new JarFixture(null);
+  }
+  
+  /**
+   * Utility to copy an InputStream into an OutputStream. Closes the InputStream afterwards.
+   * @param in
+   * @param out
+   * @throws IOException
+   */
+  private static void copy(InputStream in, OutputStream out) throws IOException
+  {
+    try {
+      int len;
+      byte[] b = new byte[1024];
+      while ((len = in.read(b)) != -1)
+        out.write(b,0,len);
+    }
+    finally {
+      in.close();
+    }
+  }
+
+  /**
+   * Base interface for every fixture.
+   */
+  public interface Fixture {
+    /**
+     * Write the physical representation of the fixture to the given OutputStream
+     * @param out
+     * @throws IOException
+     */
+    void writeOut(OutputStream out) throws IOException;
+  }
+  
+  /**
+   * Abstract base class for fixtures. Archive fixtures are by nature hierarchical.
+   */
+  public static abstract class AbstractFixture implements Fixture {
+    private ZipFixture parent;
+    
+    protected AbstractFixture(ZipFixture parent) {
+      this.parent = parent;
+    }
+    
+    /**
+     * Ends the current flow target and returns the parent flow target. For example, in the
+     * following code snippet the <code>end</code> after <code>.version("2.0.0")</code> marks
+     * the end of the manifest. Commands after that relate to the parent jar file of the manifest.
+     * 
+     * <code>
+     * ArchiveFixtures.ZipFixture zip = ArchiveFixtures.newZip()
+     *   .jar("test.jar")
+     *     .manifest()
+     *       .symbolicName("com.ibm.test")
+     *       .version("2.0.0")
+     *     .end()
+     *     .file("random.txt", "Some text")
+     *   .end();
+     * </code>
+     * @return
+     */
+    public ZipFixture end() {
+      return (parent == null) ? (ZipFixture) this : parent;
+    }
+  }
+
+  /**
+   * Simple fixture for text files.
+   */
+  public static class FileFixture extends AbstractFixture {
+    private StringBuffer text = new StringBuffer();
+    
+    protected FileFixture(ZipFixture parent) {
+      super(parent);
+    }
+    
+    /**
+     * Add a line to the file fixture. The EOL character is added automatically.
+     * @param line
+     * @return
+     */
+    public FileFixture line(String line) {
+      text.append(line);
+      text.append("\n");
+      return this;
+    }
+    
+    public void writeOut(OutputStream out) throws IOException {
+      out.write(text.toString().getBytes());
+    }
+  }
+  
+  public static class IStreamFixture extends AbstractFixture {
+    private byte[] bytes;
+    
+    protected IStreamFixture(ZipFixture parent, InputStream input) throws IOException {
+      super(parent);
+
+      ByteArrayOutputStream output = new ByteArrayOutputStream();
+      try {
+        copy(input, output);
+      } finally {
+        output.close();
+      }
+      
+      bytes = output.toByteArray();
+    }
+
+    public void writeOut(OutputStream out) throws IOException {
+      copy(new ByteArrayInputStream(bytes), out);
+    }
+  }
+  
+  /**
+   * Fixture for (bundle) manifests. By default, they contain the lines
+   * 
+   * <code>
+   * Manifest-Version: 1
+   * Bundle-ManifestVersion: 2
+   * </code>
+   */
+  public static class ManifestFixture extends AbstractFixture {
+    private Manifest mf;
+    
+    protected Manifest getManifest()
+    {
+      return mf;
+    }
+    
+    protected ManifestFixture(ZipFixture parent) {
+      super(parent);
+      mf = new Manifest();
+      mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1");
+      mf.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+    }
+    
+    /**
+     * Set the symbolic name of the bundle
+     * @param name
+     * @return
+     */
+    public ManifestFixture symbolicName(String name)
+    {
+      mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, name);
+      return this;
+    }
+    
+    /**
+     * Set the version of the bundle
+     * @param version
+     * @return
+     */
+    public ManifestFixture version(String version)
+    {
+      mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, version);
+      return this;
+    }
+    
+    /**
+     * Add a custom attribute to the manifest. Use the more specific methods for symbolic name and version.
+     * @param name
+     * @param value
+     * @return
+     */
+    public ManifestFixture attribute(String name, String value)
+    {
+      mf.getMainAttributes().putValue(name, value);
+      return this;
+    }
+    
+    public void writeOut(OutputStream out) throws IOException
+    {
+      mf.write(out);
+    }
+  }
+
+  /**
+   * Fixture for a jar archive. It offers the same functionality as zip fixtures.
+   * The main difference is that in a jar archive the manifest will be output as the first file,
+   * regardless of when it is added.
+   */
+  public static class JarFixture extends ZipFixture {
+    private ManifestFixture mfFixture;
+    
+    protected JarFixture(ZipFixture parent) {
+      super(parent);
+    }
+    
+    @Override
+    public ManifestFixture manifest()
+    {
+      if (mfFixture != null)
+        throw new IllegalStateException("Only one manifest allowed, you dummy ;)");
+      
+      mfFixture = new ManifestFixture(this);
+      return mfFixture;
+    }
+    
+    @Override
+    public void writeOut(OutputStream out) throws IOException
+    {
+      if (bytes == null) {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        JarOutputStream jout;
+        if (mfFixture != null)
+          jout = new JarOutputStream(bout, mfFixture.getManifest());
+        else
+          jout = new JarOutputStream(bout);
+        
+        try {
+          writeAllEntries(jout);
+        } finally {
+          jout.close();
+        }
+        
+        bytes = bout.toByteArray();
+      }
+      
+      ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
+      copy(bin, out);
+    }
+  }
+  
+  /**
+   * Base fixture for any kind of zip archive. Zip archives can contain any number of child archives 
+   * given by an archive type and a path. The order in which these child archives are added is important
+   * because it will be the order in which they are added to the zip.
+   */
+  public static class ZipFixture extends AbstractFixture {
+    protected static class ChildFixture {
+      public String path;
+      public Fixture fixture;
+      
+      public ChildFixture(String path, Fixture fixture)
+      {
+        this.path = path;
+        this.fixture = fixture;
+      }
+    }
+    
+    protected List<ChildFixture> children = new ArrayList<ChildFixture>();
+    protected byte[] bytes = null;
+    
+    protected ZipFixture(ZipFixture parent) {
+      super(parent);
+    }
+        
+    /**
+     * Create a child zip fixture at the given target.
+     * @param path
+     * @return
+     */
+    public ZipFixture zip(String path) {
+      ZipFixture res = new ZipFixture(this);
+      children.add(new ChildFixture(path, res));
+      
+      return res;
+    }
+    
+    /**
+     * Create a child jar fixture at the given path.
+     * @param path
+     * @return
+     */
+    public ZipFixture jar(String path) {
+      JarFixture res = new JarFixture(this);
+      children.add(new ChildFixture(path, res));
+      
+      return res;
+    }
+    
+    /**
+     * Create a complete child file fixture at the given path and with the content.
+     * Note: this will return the current zip fixture and not the file fixture.
+     * 
+     * @param path
+     * @param content
+     * @return
+     */
+    public ZipFixture file(String path, String content) 
+    {
+      return file(path).line(content).end();
+    }
+    
+    /**
+     * Create an empty file fixture at the given path.
+     * 
+     * @param path
+     * @return
+     */
+    public FileFixture file(String path)
+    {
+      FileFixture res = new FileFixture(this);
+      children.add(new ChildFixture(path, res));
+      
+      return res;
+    }
+    
+    /**
+     * Create a binary file with the content from the input stream
+     * @param path
+     * @param input
+     * @return
+     */
+    public ZipFixture binary(String path, InputStream input) throws IOException {
+      
+      if (input == null) throw new IllegalArgumentException("Provided input stream cannot be null");
+      
+      IStreamFixture child = new IStreamFixture(this, input);
+      children.add(new ChildFixture(path, child));
+      
+      return this;
+    }
+    
+    /**
+     * Create a binary file that is populated from content on the classloader
+     * @param path
+     * @param resourcePath Path that the resource can be found in the current classloader
+     * @return
+     */
+    public ZipFixture binary(String path, String resourcePath) throws IOException {
+      return binary(path, getClass().getClassLoader().getResourceAsStream(resourcePath));
+    }
+    
+    /**
+     * Create a manifest fixture at the given path.
+     * @return
+     */
+    public ManifestFixture manifest()
+    {
+      ManifestFixture res = new ManifestFixture(this);
+      children.add(new ChildFixture("META-INF/MANIFEST.MF", res));
+      
+      return res;
+    }
+    
+    /**
+     * Ensure that the necessary directory entries for the entry are available
+     * in the zip file. Newly created entries are added to the set of directories.
+     * 
+     * @param zout
+     * @param entry
+     * @param existingDirs
+     * @throws IOException
+     */
+    private void mkDirs(ZipOutputStream zout, String entry, Set<String> existingDirs) throws IOException
+    {
+      String[] parts = entry.split("/");
+      String dirName = "";
+      for (int i=0;i<parts.length-1;i++) {
+        dirName += parts[i] + "/";
+        if (!!!existingDirs.contains(dirName)) {
+          ZipEntry ze = new ZipEntry(dirName);
+          zout.putNextEntry(ze);
+          zout.closeEntry();
+          
+          existingDirs.add(dirName);
+        }
+      }
+    }
+    
+    /**
+     * Add all entries to the ZipOutputStream
+     * @param zout
+     * @throws IOException
+     */
+    protected void writeAllEntries(ZipOutputStream zout) throws IOException
+    {
+      Set<String> dirs = new HashSet<String>();
+      
+      for (ChildFixture child : children) {
+        mkDirs(zout, child.path, dirs);
+        
+        ZipEntry ze = new ZipEntry(child.path);
+        zout.putNextEntry(ze);
+        child.fixture.writeOut(zout);
+        zout.closeEntry();
+      }      
+    }
+    
+    public void writeOut(OutputStream out) throws IOException 
+    {
+      /*
+       * For better reuse this method delegate the writing to writeAllEntries, which
+       * can be reused by the JarFixture.
+       */
+      ByteArrayOutputStream bout = new ByteArrayOutputStream();
+      ZipOutputStream zout = new ZipOutputStream(bout);
+      try {
+        writeAllEntries(zout);
+      } finally {
+        zout.close();
+      }
+      
+      bytes = bout.toByteArray();
+
+      ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
+      copy(bin, out);
+    }
+  }
+
+}

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/Assert.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/Assert.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/Assert.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/junit/Assert.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.unittest.junit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * A library of useful assertion routines.
+ */
+public class Assert
+{
+  /**
+   * This method checks that the two objects have the same hashCode. If the
+   * equalsObjects parameter is true then the objects must also be .equals equal
+   * if the equalsObject parameter is false then they must not be .equals equal.
+   * 
+   * @param <T> 
+   * @param obj  the first object.
+   * @param obj2 the second object.
+   * @param equalObjects whether the objects are also equal.
+   */
+  public static <T> void assertHashCodeEquals(T obj, T obj2, boolean equalObjects)
+  {
+    assertEquals("The hashCodes were different, bad, bad, bad", obj.hashCode(), obj2.hashCode());
+    assertEquals("The two objects are not equal", equalObjects, obj.equals(obj2));
+  }
+
+  /**
+   * This method makes sure that the hashCodes are not equal. And that they
+   * are not .equals. This is because two objects of the same type cannot be
+   * .equals if they have different hashCodes.
+   * 
+   * @param <T> 
+   * @param obj
+   * @param obj2
+   */
+  public static <T> void assertHashCodeNotEquals(T obj, T obj2)
+  {
+    assertFalse("The the two hashCodes should be different: " + obj.hashCode() + ", " + obj2.hashCode(), obj.hashCode() == obj2.hashCode());
+    assertFalse("The two objects not equal", obj.equals(obj2));
+  }
+  
+  /**
+   * This method asserts that the equals contract is upheld by type T.
+   * 
+   * @param <T>
+   * @param info    an instance of T
+   * @param info2   a different instance of T that is .equal to info
+   * @param info3   an instance of T that is not equal to info
+   */
+  public static <T> void assertEqualsContract(T info, T info2, T info3)
+  {
+    Object other = new Object();
+    if (info.getClass() == Object.class) other = "A string";
+    
+    assertEquals(info, info);
+    assertFalse(info.equals(null));
+    assertTrue("Equals should be commutative", info.equals(info2) == info2.equals(info) && info2.equals(info3) == info3.equals(info2));
+    assertTrue("If two objects are equal, then they must both be equal (or not equal) to a third", info.equals(info3) == info2.equals(info3));
+    assertFalse("An object should not equal an object of a disparate type", info.equals(other));
+  }
+}
\ No newline at end of file

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultInvocationHandler.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultInvocationHandler.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultInvocationHandler.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultInvocationHandler.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.unittest.mocks;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * <p>This invocation handler is used by the Skeleton when nothing else is
+ *   matched. If the return type is an interface it creates a dynamic proxy
+ *   backed by the associated skeleton for return, if it is a class with a
+ *   default constructor that will be returned.
+ * </p>
+ */
+public class DefaultInvocationHandler implements InvocationHandler
+{
+  /** The skeleton this handler is associated with */
+  private Skeleton _s;
+  
+  /* ------------------------------------------------------------------------ */
+  /* DefaultInvocationHandler constructor                                    
+  /* ------------------------------------------------------------------------ */
+  /**
+   * Creates an instance called by the specified skeleton.
+   *
+   * @param s The caller.
+   */
+  public DefaultInvocationHandler(Skeleton s)
+  {
+    this._s = s;
+  }
+  
+  /* ------------------------------------------------------------------------ */
+  /* invoke method                                    
+  /* ------------------------------------------------------------------------ */
+  /**
+   * Invoked when no ReturnType or MethodCall Handlers are defined.
+   * 
+   * @param target     The target object that was invoked. 
+   * @param method     The method that was invoked.
+   * @param arguments  The arguments that were passed.
+   * @return           A proxy or null.
+   * @throws Throwable
+   */
+  public Object invoke(Object target, Method method, Object[] arguments)
+      throws Throwable
+  {
+    Class<?> returnType = method.getReturnType();
+    Object obj = null;
+    
+    if (returnType.isInterface())
+    {
+      obj = createProxy(new Class[] { returnType });
+    }
+    else 
+    {
+      try
+      {
+        obj = returnType.newInstance();
+      }
+      catch (Exception e)
+      {
+        // if this occurs then assume no default constructor was visible.
+      }
+    }
+    
+    return obj;
+  }
+  
+  /* ------------------------------------------------------------------------ */
+  /* createProxy method                                    
+  /* ------------------------------------------------------------------------ */
+  /**
+   * Creates and returns a proxy backed by the associated skeleton, that 
+   * implements the specified interfaces. Null is returned if the return
+   * type array contains non interfaces.
+   * 
+   * @param returnTypes The classes.
+   * @return            The proxy or null.
+   */
+  public Object createProxy(Class<?> ... returnTypes)
+  {
+    Object result = null;
+    
+    boolean allInterfaces = true;
+    for(int i = 0; (allInterfaces && i<returnTypes.length); i++)
+       allInterfaces = returnTypes[i].isInterface();
+    
+    if (allInterfaces)
+    {
+      result = _s.createMock(returnTypes);
+    }
+    return result;
+  }
+}

Added: aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultMethodCallHandlers.java
URL: http://svn.apache.org/viewvc/aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultMethodCallHandlers.java?rev=1075107&view=auto
==============================================================================
--- aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultMethodCallHandlers.java (added)
+++ aries/tags/testsupport-0.1-incubating/testsupport-unit/src/main/java/org/apache/aries/unittest/mocks/DefaultMethodCallHandlers.java Sun Feb 27 18:31:58 2011
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.unittest.mocks;
+
+/**
+ * <p>This class contains method call handlers for some default method handling.
+ * </p>
+ *
+ * <p>This class provides handlers for the toString, equals and hashCode
+ *   methods. They reproduce the default Object implementations for dynamic
+ *   mock objects, these can be overridden.
+ * </p>
+ */
+public class DefaultMethodCallHandlers
+{
+  /** A MethodCall representing the equals method */
+  private static MethodCall _equals;
+  /** A MethodCall representing the toString method */
+  private static MethodCall _toString;
+  /** A MethodCall representing the hashCode method */
+  private static MethodCall _hashCode;
+
+  /* ------------------------------------------------------------------------ */
+  /* static initializer
+  /* ------------------------------------------------------------------------ */
+  static
+  {
+    _equals = new MethodCall(Object.class, "equals", new Object[] {Object.class});
+    _toString = new MethodCall(Object.class, "toString", new Object[0]);
+    _hashCode = new MethodCall(Object.class, "hashCode", new Object[0]);
+  }
+
+  /**
+   * The Default MethodCallHandler for the equals method, performs an == check.
+   */
+  public static final MethodCallHandler EQUALS_HANDLER = new MethodCallHandler()
+  {
+    public Object handle(MethodCall methodCall, Skeleton parent) throws Exception
+    {
+      Object obj = methodCall.getInvokedObject();
+      Object toObj = methodCall.getArguments()[0];
+      
+      if (toObj == null) return false;
+      
+      if(parent.getTemplateObject() != null){
+        try {
+          if(Skeleton.isSkeleton(toObj) &&Skeleton.getSkeleton(toObj).getTemplateObject() != null){
+            return parent.getTemplateObject().equals(Skeleton.getSkeleton(toObj).getTemplateObject());
+          } else {
+            return false;
+          }
+        } catch (IllegalArgumentException iae) {
+          return parent.getTemplateObject().equals(toObj);
+        }
+      }
+        
+
+      return obj == toObj ? Boolean.TRUE : Boolean.FALSE;
+    }
+  };
+
+  /**
+   * The Default MethodCallHandler for the toString method, reproduces
+   * <classname>@<hashCode>
+   */
+  public static final MethodCallHandler TOSTRING_HANDLER = new MethodCallHandler()
+  {
+    public Object handle(MethodCall methodCall, Skeleton parent) throws Exception
+    {
+      if(parent.getTemplateObject() != null)
+        return parent.getTemplateObject().toString();
+      Object obj = methodCall.getInvokedObject();
+      return obj.getClass().getName() + "@" + System.identityHashCode(obj);
+    }
+  };
+
+  /**
+   * The Default MethodCallHandler for the hashCode method, returns the
+   * identity hashCode.
+   */
+  public static final MethodCallHandler HASHCODE_HANDLER = new MethodCallHandler()
+  {
+    public Object handle(MethodCall methodCall, Skeleton parent) throws Exception
+    {
+      if(parent.getTemplateObject() != null)
+        return parent.getTemplateObject().hashCode();
+      
+      return Integer.valueOf(System.identityHashCode(methodCall.getInvokedObject()));
+    }
+  };
+
+  /* ------------------------------------------------------------------------ */
+  /* registerDefaultHandlers method
+  /* ------------------------------------------------------------------------ */
+  /**
+   * This method registers the DefaultMethodCall Handlers with the specified
+   * skeleton.
+   *
+   * @param s a skeleton
+   */
+  public static void registerDefaultHandlers(Skeleton s)
+  {
+    s.registerMethodCallHandler(_equals, EQUALS_HANDLER);
+    s.registerMethodCallHandler(_toString, TOSTRING_HANDLER);
+    s.registerMethodCallHandler(_hashCode, HASHCODE_HANDLER);
+  }
+
+  /* ------------------------------------------------------------------------ */
+  /* isDefaultMethodCall method
+  /* ------------------------------------------------------------------------ */
+  /**
+   * This method returns true if and only if the specified call represents a
+   * default method call.
+   *
+   * @param call the call
+   * @return see above.
+   */
+  public static boolean isDefaultMethodCall(MethodCall call)
+  {
+    return _toString.equals(call) || _equals.equals(call) || _hashCode.equals(call);
+  }
+}