View Javadoc

1   //$Id: DDTDataRepository.java 376 2011-05-22 22:12:20Z jg_hamburg $
2   /********************************************************************************
3    * DDTUnit, a Datadriven Approach to Unit- and Moduletesting
4    * Copyright (c) 2004, Joerg and Kai Gellien
5    * All rights reserved.
6    *
7    * The Software is provided under the terms of the Common Public License 1.0
8    * as provided with the distribution of DDTUnit in the file cpl-v10.html.
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   *     + Redistributions of source code must retain the above copyright
14   *       notice, this list of conditions and the following disclaimer.
15   *
16   *     + Redistributions in binary form must reproduce the above
17   *       copyright notice, this list of conditions and the following
18   *       disclaimer in the documentation and/or other materials provided
19   *       with the distribution.
20   *
21   *     + Neither the name of the authors or DDTUnit, nor the
22   *       names of its contributors may be used to endorse or promote
23   *       products derived from this software without specific prior
24   *       written permission.
25   *
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
30   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   ********************************************************************************/
38  package junitx.ddtunit.data;
39  
40  import java.util.Iterator;
41  import java.util.Map;
42  import java.util.Set;
43  
44  import junitx.ddtunit.data.db.DbDataRestorer;
45  import junitx.ddtunit.util.DDTConfiguration;
46  import junitx.ddtunit.util.SoftHashMap;
47  
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  /**
52   * Data repository containing test data per test class. <br/>Implementation as
53   * singleton.
54   * 
55   * @author jg
56   */
57  public class DDTDataRepository extends DataSet {
58  
59  	private static DDTDataRepository repository;
60  
61  	private Map clusterDataSets;
62  
63  	private Logger log = LoggerFactory.getLogger(DDTDataRepository.class);
64  
65  	/**
66  	 * Default constructor
67  	 * 
68  	 * @param hardCacheSize
69  	 *            defines number of elements that can not be deleted by garbadge
70  	 *            collection
71  	 */
72  	private DDTDataRepository(int hardCacheSize) {
73  		super("DDTUnitDataRepository", null);
74  		this.clusterDataSets = new SoftHashMap(hardCacheSize);
75  	}
76  
77  	/**
78  	 * @return DDTDataRepository as singleton
79  	 */
80  	public static DDTDataRepository getInstance() {
81  		if (repository == null) {
82  			repository = new DDTDataRepository(DDTConfiguration.getInstance()
83  					.getHardCacheSize());
84  		}
85  		return repository;
86  	}
87  
88  	/**
89  	 * Check existance of testdata concerning provided class data.
90  	 * 
91  	 * @param classId
92  	 *            of class data used for test
93  	 * @return true if data is found
94  	 */
95  	public boolean containsKey(String classId) {
96  		boolean contains = false;
97  		contains = this.clusterDataSets.containsKey(classId);
98  		log.debug("containsKey(" + classId + ")=" + contains);
99  		return contains;
100 	}
101 
102 	/**
103 	 * Add {@link TestClusterDataSet}to repository.
104 	 * 
105 	 * @param classId
106 	 * @param dataSet
107 	 */
108 	public void put(String classId, IDataSet dataSet) {
109 		this.clusterDataSets.put(classId, dataSet);
110 		log.debug("put(" + classId + ") - size " + this.size());
111 	}
112 
113 	/**
114 	 * Get TestClusterDataSet associated to the specified method of a class.
115 	 * 
116 	 * @param resource
117 	 *            name of resource of test class data
118 	 * @param clusterId
119 	 *            to identify dataSet used unter test
120 	 * @return DataSet to process
121 	 */
122 	public TestClusterDataSet get(String resource, String clusterId) {
123 		if (!containsKey(clusterId)) {
124 			restore(resource, clusterId);
125 		}
126 		return (TestClusterDataSet) this.clusterDataSets.get(clusterId);
127 	}
128 
129 	/**
130 	 * Restore test object definition from provided xml resource
131 	 * 
132 	 * @param resource
133 	 *            name of xml file
134 	 * @param clusterId
135 	 *            specifiing the testdata cluster to process from within xml
136 	 *            resource
137 	 */
138 	public IDataSet restore(String resource, String clusterId) {
139 		try {
140 			// check for special key in resource - db:
141 			IDataSet dataSet = null;
142 			if (resource.startsWith("/db:")) {
143 				IDataSetSerializer dbRetriever = new DbDataRestorer();
144 				dataSet = dbRetriever.restore(resource, clusterId);
145 			} else {
146 				IDataSetSerializer xmlRetriever = new XmlDataRestorer(this);
147 				dataSet = xmlRetriever.restore(resource, clusterId);
148 			}
149 			put(clusterId, dataSet);
150 			log.debug("restore(" + resource + ", " + clusterId + ")");
151 			return dataSet;
152 		} catch (DDTTestDataException ex) {
153 			throw ex;
154 		} catch (Throwable ex) {
155 			throw new DDTTestDataException(ex.getMessage(), ex);
156 		}
157 	}
158 
159 	/**
160 	 * Find associated object data associated to specified search criteria.
161 	 * @param dataSet to search in
162 	 * @param searchCriteria
163 	 * @return
164 	 */
165 
166 	@SuppressWarnings("rawtypes")
167 	static public Object find(IDataSet dataSet, SearchCriteria searchedData) {
168 		String methodName = searchedData.getMethodName();
169 		assert (methodName != null);
170 		TestClusterDataSet classDataSet = (TestClusterDataSet) dataSet;
171 		
172 		if (classDataSet.get(methodName) == null) {
173 			throw new RuntimeException("Metoden " + methodName + " finns inte i -DDT.xml!!");
174 		} else if (classDataSet.size(methodName) == 0) {
175 			throw new RuntimeException("Metoden " + methodName + " saknar testdata (0 definitioner)!");
176 		} else {
177 			Iterator testIterator = classDataSet.getTestEntries(methodName);
178 
179 			while (testIterator != null && testIterator.hasNext()) {
180 				Map.Entry testEntry = (Map.Entry) testIterator.next();
181 				TestDataSet testDataSet = (TestDataSet) testEntry.getValue();
182 				boolean found = false;
183 				for (Iterator<SearchParameter> iter = searchedData.getIterator(); iter.hasNext();) {
184 					SearchParameter parameter = iter.next();
185 					String testDataId = parameter.getTestDataId();
186 					TypedObject testDataObject = testDataSet.getObject(testDataId);
187 					if (testDataObject == null) {
188 						throw new IllegalArgumentException("Testdatat saknar object med id=\"" + testDataId + "\"!");
189 					}
190 					Object testDataValue = testDataObject.getValue();
191 					@SuppressWarnings("unchecked")
192 					int compare = parameter.getComparator().compare(parameter.getSearchedObject(), testDataValue);
193 					if (compare == 0) {
194 						found = true;
195 						break;
196 					}
197 				}
198 				if (found) {
199 					String assertDataId = searchedData.getAssertDataId();
200 					AssertObject assertObject = testDataSet.getAssert(assertDataId);
201 					if (assertObject == null) {
202 						throw new RuntimeException("Testdatat saknar assert med id=\"" + assertDataId + "\"!");
203 					}
204 					Object result = assertObject.getValue();
205 					//Fixa en reflection-throw som kan kasta Throwable!
206 					if (result instanceof Throwable) {
207 						throw (RuntimeException) result;
208 					}
209 					return result;
210 				}
211 			}
212 			// Not found testdata
213 			throw new IllegalArgumentException("Sökt testdata saknas i metoden " + methodName);
214 		}
215 	}
216 
217 	/**
218 	 * @return number of entries in repository
219 	 */
220 	public int size() {
221 		log.debug("size = " + this.clusterDataSets.size());
222 		return this.clusterDataSets.size();
223 	}
224 
225 	public Set entrySet() {
226 		return this.clusterDataSets.entrySet();
227 	}
228 }