001: /*
002: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package test.org.mandarax.reference;
019:
020: import java.util.Enumeration;
021: import java.util.Vector;
022:
023: import org.mandarax.kernel.InferenceEngine;
024: import org.mandarax.kernel.InferenceException;
025: import org.mandarax.kernel.KnowledgeBase;
026: import org.mandarax.kernel.Query;
027: import org.mandarax.kernel.Replacement;
028: import org.mandarax.kernel.Result;
029: import org.mandarax.kernel.ResultSet;
030:
031: /**
032: * An abstract test case class to test the result set query interface of the inference engine.
033: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
034: * @version 3.4 <7 March 05>
035: * @since 1.7
036: */
037: public abstract class TestResultSet extends MandaraxTestCase {
038:
039: protected KnowledgeBase kb = null;
040: protected InferenceEngine ie = new org.mandarax.reference.ResolutionInferenceEngine();
041:
042: /**
043: * Constructor.
044: * @param aKnowledgeBase a new, uninitialized knowledge base that will be used
045: * @param anInferenceEngine the inference engine that will be tested
046: */
047: public TestResultSet(KnowledgeBase aKnowledgeBase,
048: InferenceEngine anInferenceEngine) {
049: super ("testResultSet");
050: kb = aKnowledgeBase;
051: ie = anInferenceEngine;
052:
053: }
054:
055: /**
056: * Compare two sets of results. Note that the order matters!
057: * @return boolean
058: * @param r1 the expected results
059: * @param r2 the computed results
060: */
061: private boolean compare(Replacement[][] r1, Result[] r2) {
062: int l = r1.length;
063:
064: if (l != r2.length) {
065: return false;
066: }
067:
068: Replacement[] rp1 = null;
069: Replacement[] rp2 = null;
070:
071: // compare results one by one
072: for (int i = 0; i < l; i++) {
073: rp1 = r1[i];
074: rp2 = r2[i].getReplacements();
075:
076: if (!compare(rp1, rp2)) {
077: return false;
078: }
079: }
080:
081: return true;
082: }
083:
084: /**
085: * Compare two sets of replacements. Note that the order of the elements does not matter!
086: * @return boolean
087: * @param r1 the first array of replacements
088: * @param r2 the second array of replacements
089: */
090: private boolean compare(Replacement[] r1, Replacement[] r2) {
091:
092: // handle null
093: if (r1 == null) {
094: return r2 == null;
095: }
096:
097: if (r2 == null) {
098: return r1 == null;
099: }
100:
101: // if the length is different, the arrays do not match, return false
102: if (r1.length != r2.length) {
103: return false;
104: }
105:
106: // work with vectors, that is more convinient
107: Vector v1 = new Vector();
108:
109: for (int i = 0; i < r1.length; i++) {
110: v1.addElement(r1[i]);
111: }
112:
113: Vector v2 = new Vector();
114:
115: for (int j = 0; j < r2.length; j++) {
116: v2.addElement(r2[j]);
117: }
118:
119: return compare(v1, v2);
120: }
121:
122: /**
123: * Compare two sets of replacements. Note that the order of the elements does not matter!
124: * @return boolean
125: * @param v1 the first list of replacements
126: * @param v2 the second list of replacements
127: */
128: private boolean compare(java.util.Vector v1, java.util.Vector v2) {
129: if (v1.isEmpty() && v2.isEmpty()) {
130: return true;
131: }
132:
133: if (v1.size() != v2.size()) {
134: return false;
135: }
136:
137: for (Enumeration e = v1.elements(); e.hasMoreElements();) {
138: Object obj = e.nextElement();
139:
140: if (v2.contains(obj)) {
141: v1.removeElement(obj);
142: v2.removeElement(obj);
143:
144: return compare(v1, v2);
145: }
146: }
147:
148: return false;
149: }
150:
151: /**
152: * Add facts and rules to the knowledge base.
153: * @param knowledge org.mandarax.kernel.KnowledgeBase
154: */
155: public void feedKnowledgeBase(KnowledgeBase knowledge) {
156: knowledge.removeAll();
157: knowledge.add(Person.getRule("isGrandFatherOf", "x", "z",
158: "isFatherOf", "y", "z", "isFatherOf", "x", "y"));
159: knowledge.add(Person.getRule("isOncleOf", "x", "z",
160: "isFatherOf", "y", "z", "isBrotherOf", "x", "y"));
161: knowledge.add(Person.getRule("isOncleOf", "x", "z",
162: "isGrandFatherOf", "y", "z", "isBrotherOf", "x", "y"));
163: knowledge.add(Person.getRule("isGrandFatherOf", "z", "x",
164: "isFatherOf", "y", "x", "isFatherOf", "z", "y"));
165: knowledge.add(Person.getFact("isFatherOf", "Jens", "Max"));
166: knowledge.add(Person.getFact("isFatherOf", "Klaus", "Jens"));
167: knowledge.add(Person.getFact("isBrotherOf", "Lutz", "Klaus"));
168: }
169:
170: /**
171: * Get the cardinality constraint (how many solutions
172: * should be compouted). Default is <code>InferenceEngine.ONE</code>
173: * @return the number of expected results
174: */
175: public int getCardinalityConstraint() {
176: return InferenceEngine.ONE;
177: }
178:
179: /**
180: * Get the exception handling policy.
181: * @return an integer indicating the exception handling policy
182: */
183: public int getExceptionHandlingPolicy() {
184: return InferenceEngine.BUBBLE_EXCEPTIONS;
185: }
186:
187: /**
188: * Get a description of this test case.
189: * This is used by the <code>org.mandarax.demo</code>
190: * package to display the test cases.
191: * @return a brief description of the test case
192: */
193: public String getDescription() {
194: return "Abstract test for the ResultSet interface";
195: }
196:
197: /**
198: * Get the name of the person we are looking for.
199: * More precisely, this is the name of the person expected to
200: * replace the query variable as a result of the query.
201: * @return the name of the person
202: */
203: String getPersonName() {
204: return "Klaus";
205: }
206:
207: /**
208: * Get the query.
209: * @return a query
210: */
211: public Query getQuery() {
212: return Person.getQuery("isGrandFatherOf", "x", "Max");
213: }
214:
215: /**
216: * Sets up the fixture.
217: */
218: protected void setUp() {
219: feedKnowledgeBase(kb);
220: }
221:
222: /**
223: * Run the test.
224: */
225: public void testResultSet() {
226: LOG_TEST.info("Start Testcase " + getClass().getName()
227: + " , test method: " + "testResultSet()");
228: try {
229: ResultSet rs = this .ie.query(getQuery(), kb,
230: getCardinalityConstraint(),
231: getExceptionHandlingPolicy());
232: assertTrue(testResultSet(rs));
233: } catch (InferenceException x) {
234: assertTrue(false);
235: }
236: LOG_TEST.info("Finish Testcase " + getClass().getName()
237: + " , test method: " + "testInferenceEngine()");
238: }
239:
240: /**
241: * Test the result set. Note that the result set is uninitialized (nothing has been fetched).
242: * @param rs the result set
243: * @return false if the test fails and true otherwise
244: */
245: public abstract boolean testResultSet(ResultSet rs);
246: }
|