Re-init logging to prevent multiple messages when run under the eclipse jUnit plugin.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / arp / ArpTests.java
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 package edu.internet2.middleware.shibboleth.aa.arp;
51
52 import java.io.FileInputStream;
53 import java.io.InputStream;
54 import java.net.MalformedURLException;
55 import java.net.URI;
56 import java.net.URISyntaxException;
57 import java.net.URL;
58 import java.security.Principal;
59 import java.util.Arrays;
60 import java.util.HashSet;
61 import java.util.Properties;
62
63 import junit.framework.TestCase;
64
65 import org.apache.log4j.BasicConfigurator;
66 import org.apache.xerces.parsers.DOMParser;
67 import org.xml.sax.InputSource;
68
69 /**
70  * Validation suite for <code>Arp</code> processing.
71  * 
72  * @ author Walter Hoehn(wassa@columbia.edu)
73  */
74
75 public class ArpTests extends TestCase {
76
77         public ArpTests(String name) {
78                 super(name);
79                 BasicConfigurator.resetConfiguration();
80                 BasicConfigurator.configure();
81         }
82
83         public static void main(String[] args) {
84                 junit.textui.TestRunner.run(ArpTests.class);
85                 BasicConfigurator.configure();
86         }
87         
88
89
90         public void testArpMarshalling() {
91
92                 //Test ARP description
93                 try {
94                         InputStream inStream = new FileInputStream("test/arp1.xml");
95                         DOMParser parser = new DOMParser();
96                         parser.parse(new InputSource(inStream));
97                         Arp arp1 = new Arp();
98                         arp1.marshall(parser.getDocument().getDocumentElement());
99                         assertEquals(
100                                 "ARP Description not marshalled properly",
101                                 arp1.getDescription(),
102                                 "Simplest possible ARP.");
103
104                         //Test Rule description
105                         assertEquals(
106                                 "ARP Rule Description not marshalled properly",
107                                 arp1.getAllRules()[0].getDescription(),
108                                 "Example Rule Description.");
109                 } catch (Exception e) {
110                         fail("Failed to marshall ARP: " + e);
111                 }
112
113                 //Test case where ARP description does not exist
114                 try {
115                         InputStream inStream = new FileInputStream("test/arp2.xml");
116                         DOMParser parser = new DOMParser();
117                         parser.parse(new InputSource(inStream));
118                         Arp arp2 = new Arp();
119                         arp2.marshall(parser.getDocument().getDocumentElement());
120                         assertNull("ARP Description not marshalled properly", arp2.getDescription());
121
122                         //Test case where ARP Rule description does not exist   
123                         assertNull(
124                                 "ARP Rule Description not marshalled properly",
125                                 arp2.getAllRules()[0].getDescription());
126                 } catch (Exception e) {
127                         fail("Failed to marshall ARP.");
128                 }
129
130         }
131
132         public void testMatchingFunctions() {
133
134                 try {
135
136                         /*
137                          * Test Arp Engine function retrieval
138                          */
139
140                         //Lookup a function that doesn't exist
141                         MatchFunction noFunction =
142                                 ArpEngine.lookupMatchFunction(new URI("urn:mace:shibboleth:arp:matchFunction:dummy"));
143                         assertNull("ArpEngine did not return null on dummy function.", noFunction);
144
145                         //Lookup some real functions
146                         MatchFunction exactSharFunction =
147                                 ArpEngine.lookupMatchFunction(new URI("urn:mace:shibboleth:arp:matchFunction:exactShar"));
148                         assertNotNull("ArpEngine did not properly load the Exact SHAR function.", exactSharFunction);
149                         MatchFunction resourceTreeFunction =
150                                 ArpEngine.lookupMatchFunction(new URI("urn:mace:shibboleth:arp:matchFunction:resourceTree"));
151                         assertNotNull(
152                                 "ArpEngine did not properly load the Resource Tree SHAR function.",
153                                 resourceTreeFunction);
154                         MatchFunction regexFunction =
155                                 ArpEngine.lookupMatchFunction(new URI("urn:mace:shibboleth:arp:matchFunction:regexMatch"));
156                         assertNotNull("ArpEngine did not properly load the Regex function.", regexFunction);
157
158                         /* 
159                          * Test the Exact SHAR function (requester)
160                          */
161
162                         assertTrue(
163                                 "Exact SHAR function: false negative",
164                                 exactSharFunction.match("shar.example.edu", "shar.example.edu"));
165                         assertTrue(
166                                 "Exact SHAR function: false negative",
167                                 !exactSharFunction.match("shar.example.edu", "www.example.edu"));
168                         assertTrue(
169                                 "Exact SHAR function: false negative",
170                                 !exactSharFunction.match("example.edu", "shar.example.edu"));
171
172                         //Make sure we properly handle bad input
173                         try {
174                                 exactSharFunction.match(null, null);
175                                 fail("Exact SHAR function seems to take improper input without throwing an exception.");
176                         } catch (ArpException ie) {
177                                 //This is supposed to fail
178                         }
179
180                         /*
181                          * Test the Resource Tree function (resource)
182                          */
183
184                         URL requestURL1 = new URL("http://www.example.edu/test/");
185                         URL requestURL2 = new URL("http://www.example.edu/test/index.html");
186                         URL requestURL3 = new URL("http://www.example.edu/test2/index.html");
187                         URL requestURL4 = new URL("http://www.example.edu/test2/index.html?test1=test1");
188
189                         assertTrue(
190                                 "Resource Tree function: false negative",
191                                 resourceTreeFunction.match("http://www.example.edu/", requestURL1));
192                         assertTrue(
193                                 "Resource Tree function: false positive",
194                                 !resourceTreeFunction.match("https://www.example.edu/", requestURL1));
195                         assertTrue(
196                                 "Resource Tree function: false negative",
197                                 resourceTreeFunction.match("http://www.example.edu:80/", requestURL1));
198                         assertTrue(
199                                 "Resource Tree function: false positive",
200                                 !resourceTreeFunction.match("http://www.example.edu:81/", requestURL1));
201                         assertTrue(
202                                 "Resource Tree function: false negative",
203                                 resourceTreeFunction.match("http://www.example.edu/test/", requestURL1));
204                         assertTrue(
205                                 "Resource Tree function: false negative",
206                                 resourceTreeFunction.match("http://www.example.edu/test/", requestURL2));
207                         assertTrue(
208                                 "Resource Tree function: false negative",
209                                 resourceTreeFunction.match("http://www.example.edu/", requestURL3));
210                         assertTrue(
211                                 "Resource Tree function: false positive",
212                                 !resourceTreeFunction.match("http://www.example.edu/test/", requestURL3));
213                         assertTrue(
214                                 "Resource Tree function: false negative",
215                                 resourceTreeFunction.match("http://www.example.edu/test2/index.html", requestURL3));
216                         assertTrue(
217                                 "Resource Tree function: false negative",
218                                 resourceTreeFunction.match("http://www.example.edu/test2/index.html", requestURL4));
219                         assertTrue(
220                                 "Resource Tree function: false negative",
221                                 resourceTreeFunction.match(
222                                         "http://www.example.edu/test2/index.html?test1=test1",
223                                         requestURL4));
224                         assertTrue(
225                                 "Resource Tree function: false positive",
226                                 !resourceTreeFunction.match(
227                                         "http://www.example.edu/test2/index.html?test1=test1",
228                                         requestURL3));
229
230                         //Make sure we properly handle bad input
231                         try {
232                                 resourceTreeFunction.match(null, null);
233                                 fail("Resource Tree function seems to take improper input without throwing an exception.");
234                         } catch (ArpException ie) {
235                                 //This is supposed to fail
236                         }
237                         try {
238                                 resourceTreeFunction.match("Test", "Test");
239                                 fail("Resource Tree function seems to take improper input without throwing an exception.");
240                         } catch (ArpException ie) {
241                                 //This is supposed to fail
242                         }
243
244                         /*
245                          * Test the Regex function (requester & resource)
246                          */
247
248                         //Try requester regexes
249                         assertTrue(
250                                 "Regex function: false negative",
251                                 regexFunction.match("^shar\\.example\\.edu$", "shar.example.edu"));
252                         assertTrue(
253                                 "Regex function: false negative",
254                                 regexFunction.match("^.*\\.example\\.edu$", "shar.example.edu"));
255                         assertTrue(
256                                 "Regex function: false negative",
257                                 regexFunction.match("^shar[1-9]?\\.example\\.edu$", "shar1.example.edu"));
258                         assertTrue("Regex function: false negative", regexFunction.match(".*\\.edu", "shar.example.edu"));
259                         assertTrue(
260                                 "Regex function: false positive",
261                                 !regexFunction.match("^shar[1-9]\\.example\\.edu$", "shar.example.edu"));
262                         assertTrue(
263                                 "Regex function: false positive",
264                                 !regexFunction.match("^shar\\.example\\.edu$", "www.example.edu"));
265                         assertTrue(
266                                 "Regex function: false positive",
267                                 !regexFunction.match("^shar\\.example\\.edu$", "www.example.com"));
268
269                         //Try resource regexes
270                         assertTrue(
271                                 "Regex function: false negative",
272                                 regexFunction.match("^http://www\\.example\\.edu/.*$", requestURL1));
273                         assertTrue(
274                                 "Regex function: false negative",
275                                 regexFunction.match("^http://www\\.example\\.edu/.*$", requestURL2));
276                         assertTrue(
277                                 "Regex function: false negative",
278                                 regexFunction.match("^http://.*\\.example\\.edu/.*$", requestURL2));
279                         assertTrue(
280                                 "Regex function: false negative",
281                                 regexFunction.match("^https?://.*\\.example\\.edu/.*$", requestURL2));
282                         assertTrue("Regex function: false negative", regexFunction.match(".*", requestURL2));
283                         assertTrue(
284                                 "Regex function: false positive",
285                                 !regexFunction.match("^https?://.*\\.example\\.edu/$", requestURL2));
286                         assertTrue(
287                                 "Regex function: false positive",
288                                 !regexFunction.match("^https?://www\\.example\\.edu/test/$", requestURL3));
289
290                         //Make sure we properly handle bad input
291                         try {
292                                 regexFunction.match(null, null);
293                                 fail("Regex function seems to take improper input without throwing an exception.");
294                         } catch (ArpException ie) {
295                                 //This is supposed to fail
296                         }
297
298                 } catch (ArpException e) {
299                         fail("Encountered a problem loading match function: " + e);
300                 } catch (URISyntaxException e) {
301                         fail("Unable to create URI from test string.");
302                 } catch (MalformedURLException e) {
303                         fail("Couldn't create test URLs: " + e);
304                 }
305
306         }
307
308         public void testRepositories() {
309
310                 /*
311                  * Test the Factory
312                  */
313
314                 //Make sure we fail if no Repository is specified
315                 Properties props = new Properties();
316                 try {
317                         ArpRepositoryFactory.getInstance(props);
318                 } catch (ArpRepositoryException e) {
319                         //This is supposed to fail
320                 }
321
322                 // Make sure we can create an Arp Repository
323                 props.setProperty(
324                         "edu.internet2.middleware.shibboleth.aa.arp.ArpRepository.implementation",
325                         "edu.internet2.middleware.shibboleth.aa.arp.provider.MemoryArpRepository");
326                 ArpRepository repository = null;
327                 try {
328                         repository = ArpRepositoryFactory.getInstance(props);
329                 } catch (ArpRepositoryException e) {
330                         fail("Failed to create memory-based Arp Repository" + e);
331                 }
332                 assertNotNull("Failed to create memory-based Arp Repository: Factory returned null.", repository);
333
334                 /*
335                  * Exercise the Memory Arp Repository
336                  */
337
338                 //Set/retrieve/remove a Site ARP
339                 Arp siteArp1 = new Arp();
340                 siteArp1.setDescription("Test Site Arp 1.");
341                 try {
342                         repository.update(siteArp1);
343                         assertEquals(
344                                 "Memory Repository does not store and retrieve Site ARPs properly.",
345                                 siteArp1,
346                                 repository.getSitePolicy());
347                         repository.remove(repository.getSitePolicy());
348                         assertNull("Memorty Repository does not properly delete Site ARPs.", repository.getSitePolicy());
349                 } catch (ArpRepositoryException e) {
350                         fail("Error adding Site ARP to Memory Repository.");
351                 }
352
353                 //Set/retrieve/delete some user ARPs
354                 Arp userArp1 = new Arp();
355                 userArp1.setDescription("Broken User Arp 1.");
356                 try {
357                         repository.update(userArp1);
358                         assertTrue(
359                                 "Memory Repository does not store and retrieve User ARPs properly.",
360                                 (!userArp1.equals(repository.getUserPolicy(userArp1.getPrincipal()))));
361                 } catch (ArpRepositoryException e) {
362                         fail("Error adding User ARP to Memory Repository.");
363                 }
364
365                 Arp userArp2 = new Arp(new AAPrincipal("TestPrincipal"));
366                 userArp2.setDescription("Test User Arp 2.");
367                 try {
368                         repository.update(userArp2);
369                         assertEquals(
370                                 "Memory Repository does not store and retrieve User ARPs properly.",
371                                 userArp2,
372                                 repository.getUserPolicy(userArp2.getPrincipal()));
373                         repository.remove(repository.getUserPolicy(userArp2.getPrincipal()));
374                         assertNull(
375                                 "Memorty Repository does not properly delete User ARPs.",
376                                 repository.getUserPolicy(userArp2.getPrincipal()));
377                 } catch (ArpRepositoryException e) {
378                         fail("Error adding User ARP to Memory Repository.");
379                 }
380
381         }
382
383         public void testPossibleReleaseSetComputation() {
384                 Properties props = new Properties();
385                 props.setProperty(
386                         "edu.internet2.middleware.shibboleth.aa.arp.ArpRepository.implementation",
387                         "edu.internet2.middleware.shibboleth.aa.arp.provider.MemoryArpRepository");
388                 ArpRepository repository = null;
389                 try {
390                         repository = ArpRepositoryFactory.getInstance(props);
391                 } catch (ArpRepositoryException e) {
392                         fail("Failed to create memory-based Arp Repository" + e);
393                 }
394
395                 try {
396                         Principal principal1 = new AAPrincipal("TestPrincipal");
397                         URL url1 = new URL("http://www.example.edu/");
398                         URI[] list1 = { new URI("urn:mace:eduPerson:1.0:eduPersonAffiliation")};
399                         URI[] list2 =
400                                 {
401                                         new URI("urn:mace:eduPerson:1.0:eduPersonAffiliation"),
402                                         new URI("urn:mace:eduPerson:1.0:eduPersonPrincipalName")};
403                         URI[] list3 = new URI[0];
404                                         
405                         //Test with just a site ARP
406                         InputStream inStream = new FileInputStream("test/arp1.xml");
407                         DOMParser parser = new DOMParser();
408                         parser.parse(new InputSource(inStream));
409                         Arp arp1 = new Arp();
410                         arp1.marshall(parser.getDocument().getDocumentElement());
411                         repository.update(arp1);
412                         ArpEngine engine = new ArpEngine(repository, props);
413                         URI[] possibleAttributes =
414                                 engine.listPossibleReleaseAttributes(principal1, "shar.example.edu", url1);
415                         assertTrue("Incorrectly computed possible release set.", Arrays.equals(possibleAttributes, list1));
416
417                         //Test with site and user ARPs
418                         inStream = new FileInputStream("test/arp7.xml");
419                         parser.parse(new InputSource(inStream));
420                         Arp arp7 = new Arp();
421                         arp7.setPrincipal(principal1);
422                         arp7.marshall(parser.getDocument().getDocumentElement());
423                         repository.update(arp7);
424                         possibleAttributes = engine.listPossibleReleaseAttributes(principal1, "shar.example.edu", url1);
425                         assertTrue("Incorrectly computed possible release set.", Arrays.equals(possibleAttributes, list2));
426                         
427                         //Ensure that explicit denies on any value are not in the release set
428                         inStream = new FileInputStream("test/arp6.xml");
429                         parser.parse(new InputSource(inStream));
430                         Arp arp6 = new Arp();
431                         arp6.setPrincipal(principal1);
432                         arp6.marshall(parser.getDocument().getDocumentElement());
433                         repository.update(arp6);
434                         possibleAttributes = engine.listPossibleReleaseAttributes(principal1, "shar.example.edu", url1);
435                         assertTrue("Incorrectly computed possible release set.", Arrays.equals(possibleAttributes, list3));
436                         
437                 } catch (Exception e) {
438                         e.printStackTrace();
439                         fail("Failed to marshall ARP: " + e);
440                 }
441
442         }
443         
444         public void testArpApplication() {
445                 Properties props = new Properties();
446                 props.setProperty(
447                         "edu.internet2.middleware.shibboleth.aa.arp.ArpRepository.implementation",
448                         "edu.internet2.middleware.shibboleth.aa.arp.provider.MemoryArpRepository");
449                 ArpRepository repository = null;
450                 try {
451                         repository = ArpRepositoryFactory.getInstance(props);
452                 } catch (ArpRepositoryException e) {
453                         fail("Failed to create memory-based Arp Repository" + e);
454                 }
455                 try {
456                         Principal principal1 = new AAPrincipal("TestPrincipal");
457                         URL url1 = new URL("http://www.example.edu/");
458
459                         //Test with just a site ARP
460                         InputStream inStream = new FileInputStream("test/arp1.xml");
461                         DOMParser parser = new DOMParser();
462                         parser.parse(new InputSource(inStream));
463                         Arp arp1 = new Arp();
464                         arp1.marshall(parser.getDocument().getDocumentElement());
465                         repository.update(arp1);
466                         ArpEngine engine = new ArpEngine(repository, props);
467
468                         TestAttribute testAttribute1 =
469                                 new TestAttribute(
470                                         "urn:mace:eduPerson:1.0:eduPersonAffiliation",
471                                         new Object[] { "member@example.edu", "faculty@example.edu" });
472                         TestAttribute testAttribute2 =
473                                 new TestAttribute(
474                                         "urn:mace:eduPerson:1.0:eduPersonPrincipalName",
475                                         new Object[] { "mehoehn@example.edu" });
476                         ArpAttribute[] releaseAttributes =
477                                 engine.filterAttributes(
478                                         new ArpAttribute[] { testAttribute1, testAttribute2 },
479                                         principal1,
480                                         "shar.example.edu",
481                                         url1);
482                         assertEquals(
483                                 "ARP not applied as expected.",
484                                 new HashSet(Arrays.asList(releaseAttributes)),
485                                 new HashSet(Arrays.asList(new ArpAttribute[] { testAttribute1 })));
486
487                         //Test with site and user ARPs
488                         inStream = new FileInputStream("test/arp7.xml");
489                         parser.parse(new InputSource(inStream));
490                         Arp arp7 = new Arp();
491                         arp7.setPrincipal(principal1);
492                         arp7.marshall(parser.getDocument().getDocumentElement());
493                         repository.update(arp7);
494                         releaseAttributes =
495                                 engine.filterAttributes(
496                                         new ArpAttribute[] { testAttribute1, testAttribute2 },
497                                         principal1,
498                                         "shar.example.edu",
499                                         url1);
500                         assertEquals(
501                                 "ARP not applied as expected.",
502                                 new HashSet(Arrays.asList(releaseAttributes)),
503                                 new HashSet(Arrays.asList(new ArpAttribute[] { testAttribute1, testAttribute2 })));
504
505                         //Test with site and user ARPs
506                         releaseAttributes =
507                                 engine.filterAttributes(
508                                         new ArpAttribute[] { testAttribute1, testAttribute2 },
509                                         principal1,
510                                         "shar1.example.edu",
511                                         url1);
512                         assertEquals(
513                                 "ARP not applied as expected.",
514                                 new HashSet(Arrays.asList(releaseAttributes)),
515                                 new HashSet(Arrays.asList(new ArpAttribute[] { testAttribute1 })));
516
517                         //Test with site and user ARPs
518                         inStream = new FileInputStream("test/arp6.xml");
519                         parser.parse(new InputSource(inStream));
520                         Arp arp6 = new Arp();
521                         arp6.setPrincipal(principal1);
522                         arp6.marshall(parser.getDocument().getDocumentElement());
523                         repository.update(arp6);
524                         releaseAttributes =
525                                 engine.filterAttributes(
526                                         new ArpAttribute[] { testAttribute1, testAttribute2 },
527                                         principal1,
528                                         "shar.example.edu",
529                                         url1);
530                         assertEquals(
531                                 "ARP not applied as expected.",
532                                 new HashSet(Arrays.asList(releaseAttributes)),
533                                 new HashSet());
534
535                 } catch (Exception e) {
536                         e.printStackTrace();
537                         fail("Failed to apply ARPs: " + e);
538                 }
539         }
540         
541         public class TestAttribute implements ArpAttribute {
542                 private String name;
543                 private Object[] values;
544
545                 public TestAttribute(String name, Object[] values) {
546                         this.name = name;
547                         this.values = values;
548                 }
549
550                 /**
551                  * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#getName()
552                  */
553                 public String getName() {
554                         return name;
555                 }
556
557                 /**
558                  * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#getValues()
559                  */
560                 public Object[] getValues() {
561                         return values;
562                 }
563
564                 /**
565                  * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#setValues(Object[])
566                  */
567                 public void setValues(Object[] values) {
568                         this.values = values;
569                 }
570
571                 public boolean equals(Object object) {
572                         if (!(object instanceof TestAttribute)) {
573                                 return false;
574                         }
575                         //finish this
576                         return (new HashSet(Arrays.asList(values))).equals(
577                                 Arrays.asList(((TestAttribute) object).getValues()));
578                 }
579
580         }
581
582 }