001: /* Copyright 2002-2005 Elliotte Rusty Harold
002:
003: This library is free software; you can redistribute it and/or modify
004: it under the terms of version 2.1 of the GNU Lesser General Public
005: License as published by the Free Software Foundation.
006:
007: This library is distributed in the hope that it will be useful,
008: but WITHOUT ANY WARRANTY; without even the implied warranty of
009: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: GNU Lesser General Public License for more details.
011:
012: You should have received a copy of the GNU Lesser General Public
013: License along with this library; if not, write to the
014: Free Software Foundation, Inc., 59 Temple Place, Suite 330,
015: Boston, MA 02111-1307 USA
016:
017: You can contact Elliotte Rusty Harold by sending e-mail to
018: elharo@metalab.unc.edu. Please include the word "XOM" in the
019: subject line. The XOM home page is located at http://www.xom.nu/
020: */
021:
022: package nu.xom.tests;
023:
024: import java.io.File;
025: import java.io.IOException;
026:
027: import nu.xom.Attribute;
028: import nu.xom.Builder;
029: import nu.xom.Document;
030: import nu.xom.Element;
031: import nu.xom.IllegalDataException;
032: import nu.xom.IllegalNameException;
033: import nu.xom.MalformedURIException;
034: import nu.xom.NamespaceConflictException;
035: import nu.xom.ParsingException;
036:
037: /**
038: * <p>
039: * Basic tests for the <code>Attribute</code> class.
040: * </p>
041: *
042: * @author Elliotte Rusty Harold
043: * @version 1.1b6
044: *
045: */
046: public class AttributeTest extends XOMTestCase {
047:
048: public AttributeTest(String name) {
049: super (name);
050: }
051:
052: private Attribute a1;
053: private Attribute a2;
054:
055: protected void setUp() {
056: a1 = new Attribute("test", "value");
057: a2 = new Attribute("test", " value ");
058: }
059:
060: public void testGetChildCount() {
061: assertEquals(0, a1.getChildCount());
062: }
063:
064: public void testGetChild() {
065: try {
066: a1.getChild(0);
067: fail("Didn't throw IndexOutofBoundsException");
068: } catch (IndexOutOfBoundsException success) {
069: // success
070: }
071: }
072:
073: public void testConstructor() {
074: assertEquals("test", a1.getLocalName());
075: assertEquals("test", a1.getQualifiedName());
076: assertEquals("", a1.getNamespacePrefix());
077: assertEquals("", a1.getNamespaceURI());
078: assertEquals("value", a1.getValue());
079: assertEquals(" value ", a2.getValue());
080: }
081:
082: public void testConstructor2() {
083:
084: Attribute a1 = new Attribute("name", "value",
085: Attribute.Type.CDATA);
086: assertEquals("name", a1.getLocalName());
087: assertEquals("name", a1.getQualifiedName());
088: assertEquals("", a1.getNamespacePrefix());
089: assertEquals("", a1.getNamespaceURI());
090: assertEquals("value", a1.getValue());
091: assertEquals(Attribute.Type.CDATA, a1.getType());
092: }
093:
094: public void testGetExternalForm() {
095:
096: Attribute a1 = new Attribute("test", "value contains a \"");
097: assertEquals("test=\"value contains a "\"", a1.toXML());
098:
099: Attribute a2 = new Attribute("test", "value contains a '");
100: assertEquals("test=\"value contains a '\"", a2.toXML());
101:
102: }
103:
104: public void testSetLocalName() {
105:
106: Attribute a = new Attribute("name", "value");
107: a.setLocalName("newname");
108: assertEquals("newname", a.getLocalName());
109:
110: try {
111: a.setLocalName("pre:a");
112: fail("Allowed local attribute name containing colon");
113: } catch (IllegalNameException success) {
114: assertNotNull(success.getMessage());
115: }
116:
117: }
118:
119: public void testSetLocalNameInNamespaceQualifiedAttribute() {
120:
121: Attribute a = new Attribute("pre:name",
122: "http://www.example.org", "value");
123: a.setLocalName("newname");
124: assertEquals("newname", a.getLocalName());
125: assertEquals("pre:newname", a.getQualifiedName());
126:
127: }
128:
129: // No xmlns attributes or xmlns:prefix attributes are allowed
130: public void testXmlns() {
131:
132: try {
133: new Attribute("xmlns", "http://www.w3.org/TR");
134: fail("Created attribute with name xmlns");
135: } catch (IllegalNameException success) {
136: assertNotNull(success.getMessage());
137: }
138:
139: try {
140: new Attribute("xmlns:prefix", "http://www.w3.org/TR");
141: fail("Created attribute with name xmlns:prefix");
142: } catch (IllegalNameException success) {
143: assertNotNull(success.getMessage());
144: }
145:
146: // Now try with namespace URI from errata
147: try {
148: new Attribute("xmlns", "http://www.w3.org/2000/xmlns/",
149: "http://www.w3.org/");
150: fail("created xmlns attribute");
151: } catch (IllegalNameException success) {
152: assertNotNull(success.getMessage());
153: }
154:
155: // Now try with namespace URI from errata
156: try {
157: new Attribute("xmlns:pre", "http://www.w3.org/2000/xmlns/",
158: "http://www.w3.org/");
159: fail("created xmlns:pre attribute");
160: } catch (IllegalNameException success) {
161: assertNotNull(success.getMessage());
162: }
163:
164: }
165:
166: /* public void testInternLocalNameAndPrefix() {
167:
168: Attribute a1 = new Attribute("a1:b", "http://www.exmaple.com", "test");
169: Attribute a2 = new Attribute("a2:b", "http://www.exmaple.com", "test");
170: Attribute a3 = new Attribute("a1:c", "http://www.exmaple.com", "test");
171:
172: assertTrue(a1.getNamespacePrefix() == a3.getNamespacePrefix());
173: assertTrue(a1.getLocalName() == a2.getLocalName());
174:
175: } */
176:
177: public void testXMLBase() {
178:
179: String xmlNamespace = "http://www.w3.org/XML/1998/namespace";
180: Attribute a1 = new Attribute("xml:base", xmlNamespace,
181: "http://www.w3.org/");
182: assertEquals("base", a1.getLocalName());
183: assertEquals("xml:base", a1.getQualifiedName());
184: assertEquals(xmlNamespace, a1.getNamespaceURI());
185:
186: a1.setValue("http://www.example.com/>");
187: assertEquals("http://www.example.com/>", a1.getValue());
188:
189: a1.setValue("http://www.example.com/<");
190: assertEquals("http://www.example.com/<", a1.getValue());
191:
192: a1.setValue("http://www.example.com/\u00FE");
193: assertEquals(a1.getValue(), "http://www.example.com/\u00FE");
194:
195: }
196:
197: public void testXmlPrefix() {
198:
199: try {
200: new Attribute("xml:base", "http://www.w3.org/TR");
201: fail("Created attribute with name xml:base");
202: } catch (NamespaceConflictException success) {
203: assertNotNull(success.getMessage());
204: }
205:
206: try {
207: new Attribute("xml:space", "preserve");
208: fail("Created attribute with local name xml:space");
209: } catch (NamespaceConflictException success) {
210: assertNotNull(success.getMessage());
211: }
212:
213: try {
214: new Attribute("xml:lang", "fr-FR");
215: fail("Created attribute with name xml:lang");
216: } catch (NamespaceConflictException success) {
217: assertNotNull(success.getMessage());
218: }
219:
220: String xmlNamespace = "http://www.w3.org/XML/1998/namespace";
221: Attribute a1 = new Attribute("xml:base", xmlNamespace,
222: "http://www.w3.org/");
223: assertEquals("base", a1.getLocalName());
224: assertEquals("xml:base", a1.getQualifiedName());
225: assertEquals(xmlNamespace, a1.getNamespaceURI());
226:
227: Attribute a2 = new Attribute("xml:space", xmlNamespace,
228: "preserve");
229: assertEquals(a2.getLocalName(), "space");
230: assertEquals("xml:space", a2.getQualifiedName());
231: assertEquals(xmlNamespace, a2.getNamespaceURI());
232:
233: Attribute a3 = new Attribute("xml:lang", xmlNamespace, "en-UK");
234: assertEquals("lang", a3.getLocalName());
235: assertEquals("xml:lang", a3.getQualifiedName());
236: assertEquals(xmlNamespace, a3.getNamespaceURI());
237:
238: try {
239: new Attribute("xml:base", "http://www.notTheXMLNamespace",
240: "http://www.w3.org/");
241: fail("remapped xml prefix");
242: } catch (NamespaceConflictException success) {
243: assertNotNull(success.getMessage());
244: }
245:
246: }
247:
248: public void testXMLLangAttributeCanBeEmpty() {
249:
250: String xmlNamespace = "http://www.w3.org/XML/1998/namespace";
251: Attribute a = new Attribute("xml:lang", xmlNamespace, "");
252: assertEquals("", a.getValue());
253:
254: }
255:
256: public void testWrongPrefixNotAllowedWithXMLURI() {
257:
258: try {
259: new Attribute("test:base",
260: "http://www.w3.org/XML/1998/namespace", "value");
261: fail("Allowed XML namespace to be associated with non-xml prefix");
262: } catch (NamespaceConflictException success) {
263: assertNotNull(success.getMessage());
264: }
265:
266: }
267:
268: public void testToString() {
269: assertEquals("[nu.xom.Attribute: test=\"value\"]", a1
270: .toString());
271: assertEquals("[nu.xom.Attribute: test=\" value \"]", a2
272: .toString());
273: }
274:
275: public void testToStringWithLineFeed() {
276:
277: Attribute a = new Attribute("name", "content\ncontent");
278: assertEquals("[nu.xom.Attribute: name=\"content\\ncontent\"]",
279: a.toString());
280:
281: }
282:
283: public void testToStringWithCarriageReturnLineFeed() {
284:
285: Attribute a = new Attribute("name", "content\r\ncontent");
286: assertEquals(
287: "[nu.xom.Attribute: name=\"content\\r\\ncontent\"]", a
288: .toString());
289:
290: }
291:
292: public void testToStringWithCarriageReturn() {
293:
294: Attribute a = new Attribute("name", "content\rcontent");
295: assertEquals("[nu.xom.Attribute: name=\"content\\rcontent\"]",
296: a.toString());
297:
298: }
299:
300: public void testToStringWithLotsOfData() {
301:
302: Attribute a = new Attribute("name",
303: "012345678901234567890123456789012345678901234567890123456789");
304: String s = a.toString();
305: assertEquals(
306: "[nu.xom.Attribute: name=\"01234567890123456789012345678901234...\"]",
307: s);
308:
309: }
310:
311: public void testToXML() {
312: assertEquals("test=\"value\"", a1.toXML());
313: assertEquals("test=\" value \"", a2.toXML());
314: }
315:
316: public void testEscapingWithToXML() {
317:
318: a1.setValue("<");
319: assertEquals("test=\"<\"", a1.toXML());
320: a1.setValue(">");
321: assertEquals("test=\">\"", a1.toXML());
322: a1.setValue("\"");
323: assertEquals("test=\""\"", a1.toXML());
324: a1.setValue("\'");
325: assertEquals("test=\"'\"", a1.toXML());
326: a1.setValue("&");
327: assertEquals("test=\"&\"", a1.toXML());
328:
329: }
330:
331: public void testWhiteSpaceEscapingWithToXML() {
332:
333: a1.setValue(" ");
334: assertEquals("test=\" \"", a1.toXML());
335: a1.setValue("\n");
336: assertEquals("test=\"
\"", a1.toXML());
337: a1.setValue("\r");
338: assertEquals("test=\"
\"", a1.toXML());
339: a1.setValue("\t");
340: assertEquals("test=\"	\"", a1.toXML());
341:
342: }
343:
344: public void testSetValue() {
345:
346: String[] legal = { "Hello", "hello there",
347: " spaces on both ends ", " quotes \" \" quotes",
348: " single \'\' quotes",
349: " both double and single \"\'\"\' quotes",
350: " angle brackets < > <<<", " carriage returns \r\r\r",
351: " ampersands & &&& &name; " };
352:
353: // Things that shouldn't cause an exception
354: for (int i = 0; i < legal.length; i++) {
355: a1.setValue(legal[i]);
356: assertEquals(legal[i], a1.getValue());
357: }
358:
359: try {
360: a1.setValue("test \u0000 test ");
361: fail("Should raise an IllegalDataException");
362: } catch (IllegalDataException ex) {
363: // success
364: assertNotNull(ex.getMessage());
365: }
366:
367: }
368:
369: public void testNames() {
370:
371: String prefix = "testPrefix";
372: String name = "testName";
373: String URI = "http://www.elharo.com/";
374: String value = " here's some data";
375:
376: Attribute a1 = new Attribute(prefix + ":" + name, URI, value);
377: assertEquals(name, a1.getLocalName());
378: assertEquals(prefix + ":" + name, a1.getQualifiedName());
379: assertEquals(URI, a1.getNamespaceURI());
380: }
381:
382: public void testEquals() {
383: Attribute c1 = new Attribute("test", "limit");
384: Attribute c2 = new Attribute("test", "limit");
385: Attribute c3 = new Attribute("retina", "retina test");
386:
387: assertEquals(c1, c1);
388: assertEquals(c1.hashCode(), c1.hashCode());
389: assertTrue(!c1.equals(c2));
390: assertTrue(!c1.equals(c3));
391: assertTrue(!c1.equals(null));
392: assertFalse(c1.equals("limit"));
393: assertFalse(c1.equals(new Element("test")));
394: }
395:
396: public void testTypeEquals() {
397: assertEquals(Attribute.Type.CDATA, Attribute.Type.CDATA);
398: assertTrue(!Attribute.Type.CDATA.equals(Attribute.Type.NMTOKEN));
399: assertTrue(!Attribute.Type.CDATA.equals(null));
400: assertFalse(Attribute.Type.CDATA.equals("CDATA"));
401: assertFalse(Attribute.Type.CDATA.equals(new Element("CDATA")));
402: }
403:
404: public void testCopyConstructor() {
405: Attribute c1 = new Attribute("test", "data");
406: Attribute c2 = new Attribute(c1);
407:
408: assertEquals(c1.getValue(), c2.getValue());
409: assertEquals(c1.getLocalName(), c2.getLocalName());
410: assertEquals(c1.getQualifiedName(), c2.getQualifiedName());
411: assertEquals(c1.getValue(), c2.getValue());
412: assertTrue(!c1.equals(c2));
413: assertNull(c2.getParent());
414:
415: }
416:
417: // Check passing in a string with broken surrogate pairs
418: // and with correct surrogate pairs
419: public void testSurrogates() {
420:
421: String goodString = "test: \uD8F5\uDF80 ";
422: Attribute c = new Attribute("surrogate", goodString);
423: assertEquals(goodString, c.getValue());
424:
425: // Two high-halves
426: try {
427: new Attribute("surrogate", "test: \uD8F5\uDBF0 ");
428: fail("Should raise an IllegalDataException");
429: } catch (IllegalDataException success) {
430: assertEquals("test: \uD8F5\uDBF0 ", success.getData());
431: assertNotNull(success.getMessage());
432: }
433:
434: // Two high-halves
435: try {
436: new Attribute("surrogate", "test: \uD8F5\uD8F5 ");
437: fail("Should raise an IllegalDataException");
438: } catch (IllegalDataException success) {
439: assertEquals("test: \uD8F5\uD8F5 ", success.getData());
440: assertNotNull(success.getMessage());
441: }
442:
443: // One high-half
444: try {
445: new Attribute("surrogate", "test: \uD8F5 ");
446: fail("Should raise an IllegalDataException");
447: } catch (IllegalDataException success) {
448: assertEquals("test: \uD8F5 ", success.getData());
449: assertNotNull(success.getMessage());
450: }
451:
452: // One low half
453: try {
454: new Attribute("surrogate", "test: \uDF80 ");
455: fail("One low half");
456: } catch (IllegalDataException success) {
457: assertEquals("test: \uDF80 ", success.getData());
458: assertNotNull(success.getMessage());
459: }
460:
461: // Low half before high half
462: try {
463: new Attribute("surrogate", "test: \uDCF5\uD8F5 ");
464: fail("Low half before high half");
465: } catch (IllegalDataException success) {
466: assertEquals("test: \uDCF5\uD8F5 ", success.getData());
467: assertNotNull(success.getMessage());
468: }
469:
470: }
471:
472: public void testNullNamespace() {
473: Attribute a = new Attribute("red:prefix",
474: "http://www.example.com", "data");
475: a.setNamespace(null, null);
476: assertEquals("", a.getNamespaceURI());
477: assertEquals("", a.getNamespacePrefix());
478: }
479:
480: public void testChangeNamespaceToSameNamespaceAsElement() {
481: Attribute a = new Attribute("red:prefix",
482: "http://www.example.com", "data");
483: Element e = new Element("pre:test", "http://www.example.org/");
484: e.addAttribute(a);
485: a.setNamespace("pre", "http://www.example.org/");
486: assertEquals("http://www.example.org/", a.getNamespaceURI());
487: assertEquals("pre", a.getNamespacePrefix());
488: assertEquals("http://www.example.org/", e.getNamespaceURI());
489: assertEquals("pre", e.getNamespacePrefix());
490: }
491:
492: public void testSetNamespaceURI() {
493:
494: String name = "red:sakjdhjhd";
495: String uri = "http://www.red.com/";
496: String prefix = "red";
497: Attribute a = new Attribute(name, uri, "");
498:
499: assertEquals(uri, a.getNamespaceURI());
500:
501: String[] legal = { "http://www.is.edu/sakdsk#sjadh",
502: "http://www.is.edu/sakdsk?name=value&name=head",
503: "uri:isbn:0832473864", "http://www.examples.com:80",
504: "http://www.examples.com:80/",
505: "http://www.is.edu/%20sakdsk#sjadh" };
506:
507: String[] illegal = { "http://www.is.edu/%sakdsk#sjadh",
508: "http://www.is.edu/k\u0245kakdsk#sjadh", "!@#$%^&*()",
509: "fred", "#fred", "/fred" };
510:
511: for (int i = 0; i < legal.length; i++) {
512: a.setNamespace(prefix, legal[i]);
513: assertEquals(legal[i], a.getNamespaceURI());
514: }
515:
516: for (int i = 0; i < illegal.length; i++) {
517: try {
518: a.setNamespace(prefix, illegal[i]);
519: fail("Illegal namespace URI allowed");
520: } catch (MalformedURIException success) {
521: assertEquals(illegal[i], success.getData());
522: } catch (IllegalNameException success) {
523: assertNotNull(success.getMessage());
524: }
525: }
526:
527: }
528:
529: public void testSetNamespace() {
530:
531: Attribute a = new Attribute("name", "value");
532: try {
533: a.setNamespace("pre", "");
534: fail("Allowed prefix with empty URI");
535: } catch (NamespaceConflictException success) {
536: assertNotNull(success.getMessage());
537: }
538:
539: try {
540: a.setNamespace("", "http://www.example.com");
541: fail("Allowed empty prefix with non-empty URI");
542: } catch (NamespaceConflictException success) {
543: assertNotNull(success.getMessage());
544: }
545:
546: }
547:
548: public void testNodeProperties() {
549:
550: Attribute a1 = new Attribute("test", "data");
551:
552: assertNull(a1.getParent());
553:
554: Element element = new Element("test");
555: element.addAttribute(a1);
556: assertEquals(element, a1.getParent());
557: assertEquals(a1, element.getAttribute("test"));
558:
559: element.removeAttribute(a1);
560: assertNull(element.getAttribute("test"));
561:
562: }
563:
564: public void testDistinctTypes() {
565:
566: assertTrue(!(Attribute.Type.CDATA
567: .equals(Attribute.Type.UNDECLARED)));
568:
569: assertTrue(!(Attribute.Type.ID.equals(Attribute.Type.CDATA)));
570: assertTrue(!(Attribute.Type.IDREF.equals(Attribute.Type.ID)));
571: assertTrue(!(Attribute.Type.IDREFS.equals(Attribute.Type.IDREF)));
572: assertTrue(!(Attribute.Type.NMTOKEN
573: .equals(Attribute.Type.IDREFS)));
574: assertTrue(!(Attribute.Type.NMTOKENS
575: .equals(Attribute.Type.NMTOKEN)));
576: assertTrue(!(Attribute.Type.NOTATION
577: .equals(Attribute.Type.NMTOKENS)));
578: assertTrue(!(Attribute.Type.ENTITY
579: .equals(Attribute.Type.NOTATION)));
580: assertTrue(!(Attribute.Type.ENTITIES
581: .equals(Attribute.Type.ENTITY)));
582: assertTrue(!(Attribute.Type.ENUMERATION
583: .equals(Attribute.Type.ENTITIES)));
584: assertTrue(!(Attribute.Type.CDATA
585: .equals(Attribute.Type.ENUMERATION)));
586: }
587:
588: public void testAdditionConstraints() {
589:
590: Element element = new Element("test");
591: Attribute a1 = new Attribute("foo:data",
592: "http://www.example.com", "valueFoo");
593: Attribute a2 = new Attribute("bar:data",
594: "http://www.example.com", "valueBar");
595: Attribute a3 = new Attribute("data", "valueFoo");
596: Attribute a4 = new Attribute("data", "valueBar");
597:
598: element.addAttribute(a1);
599: assertEquals("valueFoo", element.getAttributeValue("data",
600: "http://www.example.com"));
601: assertEquals(1, element.getAttributeCount());
602: element.addAttribute(a2);
603: assertEquals(element.getAttributeValue("data",
604: "http://www.example.com"), "valueBar");
605: assertEquals(1, element.getAttributeCount());
606: element.addAttribute(a3);
607: assertEquals(element.getAttributeValue("data"), "valueFoo");
608: assertEquals("valueBar", element.getAttributeValue("data",
609: "http://www.example.com"));
610: assertEquals(2, element.getAttributeCount());
611: element.addAttribute(a4);
612: assertEquals("valueBar", element.getAttributeValue("data"));
613: assertEquals(2, element.getAttributeCount());
614:
615: // an attribute can have two attributes in the same namespace
616: // with different prefixes
617: Attribute a5 = new Attribute("red:ab",
618: "http://www.example.org", "valueRed");
619: Attribute a6 = new Attribute("green:cd",
620: "http://www.example.org", "valueGreen");
621: element.addAttribute(a5);
622: element.addAttribute(a6);
623: assertEquals("valueRed", element.getAttributeValue("ab",
624: "http://www.example.org"));
625: assertEquals("valueGreen", element.getAttributeValue("cd",
626: "http://www.example.org"));
627:
628: }
629:
630: public void testXMLLangCanBeEmptyString() {
631: // per section 2.12 of the XML Rec
632:
633: Attribute a = new Attribute("xml:lang",
634: "http://www.w3.org/XML/1998/namespace", "");
635: assertEquals("", a.getValue());
636:
637: }
638:
639: public void testPunctuationCharactersInToXML() {
640:
641: String data = "=,.!@#$%^*()_-'[]{}+/?;:`|\\";
642: Attribute a = new Attribute("a", data);
643: assertEquals("a=\"" + data + "\"", a.toXML());
644:
645: }
646:
647: // Test for a bug that was caught by other tests; but not
648: // sufficiently isolated by them
649: public void testPrefixedAttributeBug() throws ParsingException,
650: IOException {
651:
652: Builder builder = new Builder();
653: File f = new File("data");
654: f = new File(f, "xtest.xml");
655: Document input = builder.build(f);
656: String s = input.toXML();
657: Document output = builder.build(s, f.toURL().toExternalForm());
658: assertEquals(input, output);
659:
660: }
661: }
|