1 10 package com.hp.hpl.jena.graph.test; 11 12 import com.hp.hpl.jena.datatypes.*; 13 import com.hp.hpl.jena.datatypes.xsd.*; 14 import com.hp.hpl.jena.datatypes.xsd.impl.XMLLiteralType; 15 import com.hp.hpl.jena.graph.*; 16 import com.hp.hpl.jena.graph.impl.*; 17 import com.hp.hpl.jena.graph.query.*; 18 import com.hp.hpl.jena.rdf.model.*; 19 import com.hp.hpl.jena.shared.impl.JenaParameters; 20 import com.hp.hpl.jena.vocabulary.XSD; 21 import com.hp.hpl.jena.enhanced.EnhNode; 22 23 import junit.framework.TestCase; 24 import junit.framework.TestSuite; 25 26 import java.math.*; 27 import java.util.*; 28 import java.io.*; 29 30 import org.apache.xerces.impl.dv.util.Base64; 31 import org.apache.xerces.impl.dv.util.HexBin; 32 33 40 public class TestTypedLiterals extends TestCase { 41 42 43 private Model m = ModelFactory.createDefaultModel(); 44 45 52 53 56 public TestTypedLiterals( String name ) { 57 super( name ); 58 } 59 60 63 public static TestSuite suite() { 64 return new TestSuite( TestTypedLiterals.class ); 65 } 66 67 70 public void testUnknown() { 71 String typeURI = "urn:x-hp-dt:unknown"; 72 String typeURI2 = "urn:x-hp-dt:unknown2"; 73 74 boolean originalFlag = JenaParameters.enableSilentAcceptanceOfUnknownDatatypes; 75 JenaParameters.enableSilentAcceptanceOfUnknownDatatypes = true; 76 Literal l1 = m.createTypedLiteral("foo", typeURI); 77 Literal l3 = m.createTypedLiteral("15", typeURI); 78 Literal l5 = m.createTypedLiteral("foo", typeURI2); 79 Literal l6 = m.createLiteral("foo", "lang1"); 80 Literal l7 = m.createLiteral("foo"); 81 JenaParameters.enableSilentAcceptanceOfUnknownDatatypes = originalFlag; 82 84 assertNotNull(l1); 85 assertNotNull(l3); 86 assertNotNull(l5); 87 88 assertDiffer("datatype sensitive", l1, l5); 90 assertDiffer("value sensitive", l1, l3); 91 assertDiffer("typed and plain differ", l1, l6); 92 93 try { 95 int i = l3.getInt(); 96 assertTrue("Allowed int conversion", false); 97 } catch (DatatypeFormatException e) {} 98 assertEquals("Extract value", l1.getValue(), "foo"); 99 assertEquals("Extract xml tag", l1.getWellFormed(), false); 100 101 JenaParameters.enableSilentAcceptanceOfUnknownDatatypes = false; 102 boolean foundException = false; 103 try { 104 Literal l8 = m.createTypedLiteral("food", typeURI+"3"); 105 } catch (DatatypeFormatException e2) { 106 foundException = true; 107 } 108 JenaParameters.enableSilentAcceptanceOfUnknownDatatypes = originalFlag; 109 assertTrue("Detected unknown datatype", foundException); 110 } 111 112 115 public void testUserDef() { 116 RDFDatatype rtype = RationalType.theRationalType; 118 TypeMapper.getInstance().registerDatatype(rtype); 119 120 121 Literal l1 = m.createTypedLiteral("3/5", rtype); 122 Literal l3 = m.createTypedLiteral("7/5", rtype); 123 124 assertNotNull(l1); 126 assertNotNull(l3); 127 128 assertDiffer("values should be tested!", l1, l3); 130 131 assertSame("Datatype incorrect", l1.getDatatype(), rtype); 133 assertEquals("Datatype uri incorrect", l1.getDatatypeURI(), RationalType.theTypeURI); 134 Object val = l1.getValue(); 135 assertTrue("Value space check", val instanceof Rational); 136 assertTrue("Value check", ((Rational)val).getNumerator() == 3); 137 assertTrue("Value check", ((Rational)val).getDenominator() == 5); 138 try { 139 int i = l1.getInt(); 140 assertTrue("Allowed int conversion", false); 141 } catch (DatatypeFormatException e) {} 142 assertEquals("Extract xml tag", l1.getWellFormed(), false); 143 } 144 145 public void testXMLLiteral() { 146 Literal ll; 147 148 ll = m.createLiteral("<bad",true); 149 150 assertTrue("Error checking must be off.",((EnhNode)ll).asNode().getLiteral().isXML()); 151 ll = m.createTypedLiteral("<bad/>",XMLLiteralType.theXMLLiteralType); 152 assertFalse("Error checking must be on.",((EnhNode)ll).asNode().getLiteral().isXML()); 153 ll = m.createTypedLiteral("<good></good>",XMLLiteralType.theXMLLiteralType); 154 assertTrue("Well-formed XMLLiteral.",((EnhNode)ll).asNode().getLiteral().isXML()); 155 156 } 157 158 161 public void testXSDbasics() { 162 String xsdIntURI = "http://www.w3.org/2001/XMLSchema#int"; 163 164 Literal l1 = m.createTypedLiteral(42); Literal l2 = m.createTypedLiteral("42", XSDDatatype.XSDint); 167 Literal l4 = m.createTypedLiteral("63"); 169 assertSameValueAs("Default map failed", l1, l2); 170 assertEquals("Value wrong", l1.getValue(), new Integer (42)); 171 assertEquals("class wrong", l1.getValue().getClass(), Integer .class); 172 assertEquals("Value accessor problem", l1.getInt(), 42); 173 assertEquals("wrong type name", l2.getDatatypeURI(), xsdIntURI); 174 assertEquals("wrong type", l2.getDatatype(), XSDDatatype.XSDint); 175 assertDiffer("Not value sensitive", l1, l4); 176 checkIllegalLiteral("zap", XSDDatatype.XSDint); 177 checkIllegalLiteral("42.1", XSDDatatype.XSDint); 178 179 Literal l5 = m.createTypedLiteral("42", XSDDatatype.XSDnonNegativeInteger); 180 assertSameValueAs("type coercion", l2, l5); 181 182 l1 = m.createTypedLiteral(42.42); l2 = m.createTypedLiteral("42.42", XSDDatatype.XSDfloat); 185 Literal l3 = m.createTypedLiteral("42.42", XSDDatatype.XSDdouble); 186 187 assertEquals("class wrong", l1.getValue().getClass(), Double .class); 188 assertFloatEquals("value wrong", ((Double )(l1.getValue())).floatValue(), 42.42); 189 assertEquals("class wrong", l2.getValue().getClass(), Float .class); 190 assertFloatEquals("value wrong", ((Float )(l2.getValue())).floatValue(), 42.42); 191 assertFloatEquals("Value accessor problem", l1.getFloat(), 42.42); 192 assertEquals("wrong type", l2.getDatatype(), XSDDatatype.XSDfloat); 193 assertSameValueAs("equality fn", l1, l3); 194 195 checkLegalLiteral("12345", XSDDatatype.XSDlong, Long .class, new Long (12345)); 197 checkLegalLiteral("-12345", XSDDatatype.XSDlong, Long .class, new Long (-12345)); 198 checkIllegalLiteral("2.3", XSDDatatype.XSDlong); 199 200 checkLegalLiteral("1234", XSDDatatype.XSDshort, Short .class, new Short ((short)1234)); 201 checkLegalLiteral("-1234", XSDDatatype.XSDshort, Short .class, new Short ((short)-1234)); 202 checkLegalLiteral("32767", XSDDatatype.XSDshort, Short .class, new Short ((short)32767)); 203 checkLegalLiteral("-32768", XSDDatatype.XSDshort, Short .class, new Short ((short)-32768)); 204 checkIllegalLiteral("32769", XSDDatatype.XSDshort); 205 checkIllegalLiteral("2.3", XSDDatatype.XSDshort); 206 207 checkLegalLiteral("42", XSDDatatype.XSDbyte, Byte .class, new Byte ((byte)42)); 208 checkLegalLiteral("-42", XSDDatatype.XSDbyte, Byte .class, new Byte ((byte)-42)); 209 checkLegalLiteral("127", XSDDatatype.XSDbyte, Byte .class, new Byte ((byte)127)); 210 checkLegalLiteral("-128", XSDDatatype.XSDbyte, Byte .class, new Byte ((byte)-128)); 211 checkIllegalLiteral("32769", XSDDatatype.XSDbyte); 212 checkIllegalLiteral("128", XSDDatatype.XSDbyte); 213 checkIllegalLiteral("2.3", XSDDatatype.XSDbyte); 214 215 checkLegalLiteral("12345", XSDDatatype.XSDunsignedLong, Long .class, new Long (12345)); 217 checkLegalLiteral("+12345", XSDDatatype.XSDunsignedLong, Long .class, new Long (12345)); 218 checkLegalLiteral("9223372036854775808", XSDDatatype.XSDunsignedLong, BigInteger.class, new BigInteger("9223372036854775808")); 219 checkIllegalLiteral("-12345", XSDDatatype.XSDunsignedLong); 220 221 checkLegalLiteral("12345", XSDDatatype.XSDunsignedInt, Long .class, new Long (12345)); 222 checkLegalLiteral("2147483648", XSDDatatype.XSDunsignedInt, Long .class, new Long (2147483648l)); 223 checkIllegalLiteral("-12345", XSDDatatype.XSDunsignedInt); 224 225 checkLegalLiteral("1234", XSDDatatype.XSDunsignedShort, Integer .class, new Integer (1234)); 226 checkLegalLiteral("32679", XSDDatatype.XSDunsignedShort, Integer .class, new Integer (32679)); 227 checkIllegalLiteral("-12345", XSDDatatype.XSDunsignedShort); 228 229 checkLegalLiteral("123", XSDDatatype.XSDunsignedByte, Short .class, new Short ((short)123)); 230 checkLegalLiteral("129", XSDDatatype.XSDunsignedByte, Short .class, new Short ((short)129)); 231 checkIllegalLiteral("-123", XSDDatatype.XSDunsignedByte); 232 233 checkLegalLiteral("12345", XSDDatatype.XSDinteger, Long .class, new Long (12345)); 235 checkLegalLiteral("0", XSDDatatype.XSDinteger, Long .class, new Long (0)); 236 checkLegalLiteral("-12345", XSDDatatype.XSDinteger, Long .class, new Long (-12345)); 237 checkLegalLiteral("9223372036854775808", XSDDatatype.XSDinteger, BigInteger.class, new BigInteger("9223372036854775808")); 238 239 checkLegalLiteral("12345", XSDDatatype.XSDpositiveInteger, Long .class, new Long (12345)); 240 checkIllegalLiteral("0", XSDDatatype.XSDpositiveInteger); 241 checkIllegalLiteral("-12345", XSDDatatype.XSDpositiveInteger); 242 checkLegalLiteral("9223372036854775808", XSDDatatype.XSDpositiveInteger, BigInteger.class, new BigInteger("9223372036854775808")); 243 244 checkLegalLiteral("12345", XSDDatatype.XSDnonNegativeInteger, Long .class, new Long (12345)); 245 checkLegalLiteral("0", XSDDatatype.XSDnonNegativeInteger, Long .class, new Long (0)); 246 checkIllegalLiteral("-12345", XSDDatatype.XSDnonNegativeInteger); 247 checkLegalLiteral("9223372036854775808", XSDDatatype.XSDnonNegativeInteger, BigInteger.class, new BigInteger("9223372036854775808")); 248 249 checkLegalLiteral("-12345", XSDDatatype.XSDnegativeInteger, Long .class, new Long (-12345)); 250 checkIllegalLiteral("0", XSDDatatype.XSDnegativeInteger); 251 checkIllegalLiteral("12345", XSDDatatype.XSDnegativeInteger); 252 checkLegalLiteral("-9223372036854775808", XSDDatatype.XSDnegativeInteger, BigInteger.class, new BigInteger("-9223372036854775808")); 253 254 checkLegalLiteral("-12345", XSDDatatype.XSDnonPositiveInteger, Long .class, new Long (-12345)); 255 checkLegalLiteral("0", XSDDatatype.XSDnonPositiveInteger, Long .class, new Long (0)); 256 checkIllegalLiteral("12345", XSDDatatype.XSDnonPositiveInteger); 257 checkLegalLiteral("-9223372036854775808", XSDDatatype.XSDnonPositiveInteger, BigInteger.class, new BigInteger("-9223372036854775808")); 258 259 checkLegalLiteral("12345", XSDDatatype.XSDdecimal, Long .class, new Long ("12345")); 260 checkLegalLiteral("0.0", XSDDatatype.XSDdecimal, Long .class, new Long ("0")); 261 checkLegalLiteral("42.45", XSDDatatype.XSDdecimal, BigDecimal.class, new BigDecimal("42.45")); 262 checkLegalLiteral("9223372036854775808.1234", XSDDatatype.XSDdecimal, BigDecimal.class, new BigDecimal("9223372036854775808.1234")); 263 checkLegalLiteral("123.4", XSDDatatype.XSDdecimal, BigDecimal.class, new BigDecimal("123.4")); 264 checkIllegalLiteral("123,4", XSDDatatype.XSDdecimal); 265 266 checkLegalLiteral("true", XSDDatatype.XSDboolean, Boolean .class, new Boolean (true)); 268 checkLegalLiteral("false", XSDDatatype.XSDboolean, Boolean .class, new Boolean (false)); 269 l1 = m.createTypedLiteral(true); 270 assertEquals("boolean mapping", XSDDatatype.XSDboolean, l1.getDatatype()); 271 272 checkLegalLiteral("hello world", XSDDatatype.XSDstring, String .class, "hello world"); 274 l1 = m.createTypedLiteral("foo bar"); 275 assertEquals("string mapping", XSDDatatype.XSDstring, l1.getDatatype()); 276 277 } 278 279 282 public void testMiscEquality() { 283 Literal l1 = m.createTypedLiteral("10", "http://www.w3.org/2001/XMLSchema#integer"); 284 Literal l3 = m.createTypedLiteral("010", "http://www.w3.org/2001/XMLSchema#integer"); 285 assertSameValueAs("Int lex form", l1, l3); 286 287 l1 = m.createTypedLiteral("1", XSDDatatype.XSDint); 288 l3 = m.createTypedLiteral("1", XSDDatatype.XSDnonNegativeInteger); 289 290 assertSameValueAs("numeric comparisons", l1, l3); 291 } 292 293 297 public void testOverloads() { 298 boolean old = JenaParameters.enableEagerLiteralValidation; 300 try { 301 JenaParameters.enableEagerLiteralValidation = true; 302 303 boolean test1 = false; 305 try { 306 Literal l1 = m.createTypedLiteral("foo", "http://www.w3.org/2001/XMLSchema#integer"); 307 } catch (DatatypeFormatException e1 ) { 308 test1 = true; 309 } 310 assertTrue("detected illegal string, direct", test1); 311 312 boolean test2 = false; 313 try { 314 Object foo = "foo"; 315 Literal l1 = m.createTypedLiteral(foo, "http://www.w3.org/2001/XMLSchema#integer"); 316 } catch (DatatypeFormatException e2 ) { 317 test2 = true; 318 } 319 assertTrue("detected illegal string, overloaded", test2); 320 321 Calendar testCal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 323 testCal.set(1999, 4, 30, 15, 9, 32); 324 testCal.set(Calendar.MILLISECOND, 0); Literal lc = m.createTypedLiteral((Object )testCal); 326 assertEquals("calendar overloading test", m.createTypedLiteral("1999-05-30T15:09:32Z", XSDDatatype.XSDdateTime), lc ); 327 328 } finally { 329 JenaParameters.enableEagerLiteralValidation = old; 330 } 331 } 332 333 336 public void testPlainSameValueAs() { 337 Literal lString = m.createTypedLiteral("10", XSDDatatype.XSDstring ); 338 Literal lPlain = m.createTypedLiteral("10", (RDFDatatype)null ); 339 Literal lPlain3 = m.createTypedLiteral("10", (String )null ); 340 Literal lPlain2 = m.createLiteral("10"); 341 Literal lInt = m.createTypedLiteral("10", XSDDatatype.XSDint ); 342 343 assertSameValueAs("Null type = plain literal", lPlain, lPlain2); 344 assertSameValueAs("Null type = plain literal", lPlain, lPlain3); 345 assertSameValueAs("Null type = plain literal", lPlain2, lPlain3); 346 assertTrue("null type", lPlain3.getDatatype() == null); 347 assertDiffer("String != int", lString, lInt); 348 assertDiffer("Plain != int", lPlain, lInt); 349 assertDiffer("Plain != int", lPlain2, lInt); 350 351 if (JenaParameters.enablePlainLiteralSameAsString) { 353 assertSameValueAs("String != plain??", lString, lPlain); 354 assertSameValueAs("String != plain??", lString, lPlain2); 355 } else { 356 assertDiffer("String != plain??", lString, lPlain); 357 assertDiffer("String != plain??", lString, lPlain2); 358 } 359 360 } 361 362 368 public void testUserDefined() throws IOException { 369 String uri = "http://www.daml.org/2001/03/daml+oil-ex-dt"; 370 String filename = "testing/xsd/daml+oil-ex-dt.xsd"; 371 TypeMapper tm = TypeMapper.getInstance(); 372 List typenames = XSDDatatype.loadUserDefined(uri, new FileReader(filename), null, tm); 373 assertIteratorValues(typenames.iterator(), new Object [] { 374 uri + "#XSDEnumerationHeight", 375 uri + "#over12", 376 uri + "#over17", 377 uri + "#over59", 378 uri + "#clothingsize" }); 379 380 RDFDatatype heightType = tm.getSafeTypeByName(uri + "#XSDEnumerationHeight"); 382 checkLegalLiteral("short", heightType, String .class, "short"); 383 checkLegalLiteral("tall", heightType, String .class, "tall"); 384 checkIllegalLiteral("shortish", heightType); 385 386 RDFDatatype over12Type = tm.getSafeTypeByName(uri + "#over12"); 388 checkLegalLiteral("15", over12Type, Long .class, new Long (15)); 389 checkIllegalLiteral("12", over12Type); 390 391 RDFDatatype clothingsize = tm.getSafeTypeByName(uri + "#clothingsize"); 393 checkLegalLiteral("42", clothingsize, Long .class, new Long (42)); 394 checkLegalLiteral("short", clothingsize, String .class, "short"); 395 396 LiteralLabel iOver12 = m.createTypedLiteral("13", over12Type).asNode().getLiteral(); 398 LiteralLabel iDecimal14 = m.createTypedLiteral("14", XSDDatatype.XSDdecimal).asNode().getLiteral(); 399 LiteralLabel iDecimal10 = m.createTypedLiteral("10", XSDDatatype.XSDdecimal).asNode().getLiteral(); 400 LiteralLabel iString = m.createTypedLiteral("15", XSDDatatype.XSDstring).asNode().getLiteral(); 401 LiteralLabel iPlain = m.createLiteral("foo").asNode().getLiteral(); 402 403 assertTrue(over12Type.isValidLiteral(iOver12)); 404 assertTrue(over12Type.isValidLiteral(iDecimal14)); 405 assertTrue( ! over12Type.isValidLiteral(iDecimal10)); 406 assertTrue( ! over12Type.isValidLiteral(iString)); 407 assertTrue( ! over12Type.isValidLiteral(iPlain)); 408 409 assertTrue(XSDDatatype.XSDdecimal.isValidLiteral(iOver12)); 410 assertTrue(XSDDatatype.XSDdecimal.isValidLiteral(iDecimal14)); 411 assertTrue(XSDDatatype.XSDdecimal.isValidLiteral(iDecimal10)); 412 assertTrue( ! XSDDatatype.XSDdecimal.isValidLiteral(iString)); 413 assertTrue( ! XSDDatatype.XSDdecimal.isValidLiteral(iPlain)); 414 415 assertTrue(XSDDatatype.XSDstring.isValidLiteral(iString)); 416 assertTrue(XSDDatatype.XSDstring.isValidLiteral(iPlain)); 417 assertTrue( ! XSDDatatype.XSDstring.isValidLiteral(iOver12)); 418 assertTrue( ! XSDDatatype.XSDstring.isValidLiteral(iDecimal10)); 419 assertTrue( ! XSDDatatype.XSDstring.isValidLiteral(iDecimal14)); 420 } 421 422 425 public void testDateTime() { 426 Literal l1 = m.createTypedLiteral("P1Y2M3DT5H6M7.5S", XSDDatatype.XSDduration); 428 assertEquals("duration data type", XSDDatatype.XSDduration, l1.getDatatype()); 429 assertEquals("duration java type", XSDDuration.class, l1.getValue().getClass()); 430 assertEquals("duration value", 1, ((XSDDuration)l1.getValue()).getYears()); 431 assertEquals("duration value", 2, ((XSDDuration)l1.getValue()).getMonths()); 432 assertEquals("duration value", 3, ((XSDDuration)l1.getValue()).getDays()); 433 assertEquals("duration value", 5, ((XSDDuration)l1.getValue()).getHours()); 434 assertEquals("duration value", 6, ((XSDDuration)l1.getValue()).getMinutes()); 435 assertEquals("duration value", 7, ((XSDDuration)l1.getValue()).getFullSeconds()); 436 assertFloatEquals("duration value", 18367.5, ((XSDDuration)l1.getValue()).getTimePart()); 437 assertEquals("serialization", "P1Y2M3DT5H6M7.5S", l1.getValue().toString()); 438 assertEquals("equality test", l1, m.createTypedLiteral("P1Y2M3DT5H6M7.5S", XSDDatatype.XSDduration)); 439 assertTrue("inequality test", l1 != m.createTypedLiteral("P1Y2M2DT5H6M7.5S", XSDDatatype.XSDduration)); 440 441 l1 = m.createTypedLiteral("1999-05-31T02:09:32Z", XSDDatatype.XSDdateTime); 443 XSDDateTime xdt = (XSDDateTime)l1.getValue(); 444 assertEquals("dateTime data type", XSDDatatype.XSDdateTime, l1.getDatatype()); 445 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 446 assertEquals("dateTime value", 1999, xdt.getYears()); 447 assertEquals("dateTime value", 5, xdt.getMonths()); 448 assertEquals("dateTime value", 31, xdt.getDays()); 449 assertEquals("dateTime value", 2, xdt.getHours()); 450 assertEquals("dateTime value", 9, xdt.getMinutes()); 451 assertEquals("dateTime value", 32, xdt.getFullSeconds()); 452 assertEquals("serialization", "1999-05-31T02:09:32Z", l1.getValue().toString()); 453 Calendar cal = xdt.asCalendar(); 454 Calendar testCal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 455 testCal.set(1999, 4, 31, 2, 9, 32); 456 464 testCal.set(Calendar.MILLISECOND, 0); assertEquals("calendar value", cal, testCal); 466 assertEquals("equality test", l1, m.createTypedLiteral("1999-05-31T02:09:32Z", XSDDatatype.XSDdateTime)); 467 assertTrue("inequality test", l1 != m.createTypedLiteral("1999-04-31T02:09:32Z", XSDDatatype.XSDdateTime)); 468 469 Calendar testCal2 = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 470 testCal2.set(1999, 4, 30, 15, 9, 32); 471 testCal2.set(Calendar.MILLISECOND, 0); Literal lc = m.createTypedLiteral(testCal2); 473 assertEquals("calendar 24 hour test", m.createTypedLiteral("1999-05-30T15:09:32Z", XSDDatatype.XSDdateTime), lc ); 474 475 assertEquals("calendar value", cal, testCal); 476 assertEquals("equality test", l1, m.createTypedLiteral("1999-05-31T02:09:32Z", XSDDatatype.XSDdateTime)); 477 478 Calendar testCal3 = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 479 testCal3.clear(); 480 testCal3.set(1999, Calendar.JANUARY, 30, 15, 9, 32); 481 lc = m.createTypedLiteral(testCal3); 482 assertEquals("1999-01-30T15:09:32Z", lc.getLexicalForm()); 483 String urib="rdf://test.com#"; 484 String uri1=urib+"1"; 485 String urip=urib+"prop"; 486 String testN3 = "<"+uri1+"> <"+urip+"> \""+lc.getLexicalForm()+"\"^^<"+lc.getDatatypeURI()+"> ."; 487 java.io.StringReader sr = new java.io.StringReader (testN3); 488 m.read(sr, urib, "N3"); 489 assertTrue(m.contains(m.getResource(uri1),m.getProperty(urip))); 490 Resource r1 = m.getResource(uri1); 491 Property p = m.getProperty(urip); 492 XSDDateTime returnedDateTime = (XSDDateTime) r1.getProperty(p).getLiteral().getValue(); 493 assertEquals("deserialized calendar value", testCal3, returnedDateTime.asCalendar()); 494 495 Calendar testCal4 = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 497 testCal4.set(1999, 4, 30, 15, 9, 32); 498 testCal4.set(Calendar.MILLISECOND, 25); 499 Literal lc4 = m.createTypedLiteral(testCal4); 500 assertEquals("serialization", "1999-05-30T15:09:32.25Z", lc4.getValue().toString()); 501 assertEquals("calendar ms test", m.createTypedLiteral("1999-05-30T15:09:32.25Z", XSDDatatype.XSDdateTime), lc4 ); 502 XSDDateTime dt4 = (XSDDateTime)lc4.getValue(); 503 assertEquals(dt4.asCalendar(), testCal4); 504 505 l1 = m.createTypedLiteral("1999-05-31", XSDDatatype.XSDdate); 507 assertEquals("dateTime data type", XSDDatatype.XSDdate, l1.getDatatype()); 508 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 509 xdt = (XSDDateTime)l1.getValue(); 510 assertEquals("dateTime value", 1999, xdt.getYears()); 511 assertEquals("dateTime value", 5, xdt.getMonths()); 512 assertEquals("dateTime value", 31, xdt.getDays()); 513 try { 514 xdt.getHours(); 515 assertTrue("Failed to prevent illegal access", false); 516 } catch (IllegalDateTimeFieldException e) {} 517 518 l1 = m.createTypedLiteral("12:56:32", XSDDatatype.XSDtime); 520 assertEquals("dateTime data type", XSDDatatype.XSDtime, l1.getDatatype()); 521 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 522 xdt = (XSDDateTime)l1.getValue(); 523 assertEquals("dateTime value", 12, xdt.getHours()); 524 assertEquals("dateTime value", 56, xdt.getMinutes()); 525 assertEquals("dateTime value", 32, xdt.getFullSeconds()); 526 try { 527 xdt.getDays(); 528 assertTrue("Failed to prevent illegal access", false); 529 } catch (IllegalDateTimeFieldException e) {} 530 531 l1 = m.createTypedLiteral("1999-05", XSDDatatype.XSDgYearMonth); 533 assertEquals("dateTime data type", XSDDatatype.XSDgYearMonth, l1.getDatatype()); 534 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 535 xdt = (XSDDateTime)l1.getValue(); 536 assertEquals("dateTime value", 1999, xdt.getYears()); 537 assertEquals("dateTime value", 5, xdt.getMonths()); 538 try { 539 xdt.getDays(); 540 assertTrue("Failed to prevent illegal access", false); 541 } catch (IllegalDateTimeFieldException e) {} 542 543 l1 = m.createTypedLiteral("1999", XSDDatatype.XSDgYear); 545 assertEquals("dateTime data type", XSDDatatype.XSDgYear, l1.getDatatype()); 546 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 547 xdt = (XSDDateTime)l1.getValue(); 548 assertEquals("dateTime value", 1999, xdt.getYears()); 549 try { 550 xdt.getMonths(); 551 assertTrue("Failed to prevent illegal access", false); 552 } catch (IllegalDateTimeFieldException e) {} 553 554 l1 = m.createTypedLiteral("--05--", XSDDatatype.XSDgMonth); 556 assertEquals("dateTime data type", XSDDatatype.XSDgMonth, l1.getDatatype()); 557 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 558 xdt = (XSDDateTime)l1.getValue(); 559 assertEquals("dateTime value", 5, xdt.getMonths()); 560 try { 561 xdt.getYears(); 562 assertTrue("Failed to prevent illegal access", false); 563 } catch (IllegalDateTimeFieldException e) {} 564 565 l1 = m.createTypedLiteral("--05-25", XSDDatatype.XSDgMonthDay); 567 assertEquals("dateTime data type", XSDDatatype.XSDgMonthDay, l1.getDatatype()); 568 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 569 xdt = (XSDDateTime)l1.getValue(); 570 assertEquals("dateTime value", 5, xdt.getMonths()); 571 assertEquals("dateTime value", 25, xdt.getDays()); 572 try { 573 xdt.getYears(); 574 assertTrue("Failed to prevent illegal access", false); 575 } catch (IllegalDateTimeFieldException e) {} 576 577 l1 = m.createTypedLiteral("---25", XSDDatatype.XSDgDay); 579 assertEquals("dateTime data type", XSDDatatype.XSDgDay, l1.getDatatype()); 580 assertEquals("dateTime java type", XSDDateTime.class, l1.getValue().getClass()); 581 xdt = (XSDDateTime)l1.getValue(); 582 assertEquals("dateTime value", 25, xdt.getDays()); 583 try { 584 xdt.getMonths(); 585 assertTrue("Failed to prevent illegal access", false); 586 } catch (IllegalDateTimeFieldException e) {} 587 588 Calendar ncal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 590 ncal.set(2003, 11, 8, 10, 50, 42); 591 ncal.set(Calendar.MILLISECOND, 0); 592 l1 = m.createTypedLiteral(ncal); 593 assertEquals("DateTime from date", XSDDatatype.XSDdateTime, l1.getDatatype()); 594 assertEquals("DateTime from date", XSDDateTime.class, l1.getValue().getClass()); 595 assertEquals("DateTime from date", "2003-12-08T10:50:42Z", l1.getValue().toString()); 596 597 SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, "America/Los_Angeles"); 601 602 pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000); 604 pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000); 605 606 ncal = new GregorianCalendar(pdt); 608 ncal.set(2004, 02, 21, 12, 50, 42); ncal.set(Calendar.MILLISECOND, 0); 610 l1 = m.createTypedLiteral(ncal); 612 assertEquals("DateTime from date", XSDDatatype.XSDdateTime, l1.getDatatype()); 613 assertEquals("DateTime from date", XSDDateTime.class, l1.getValue().getClass()); 614 assertEquals("DateTime from date", "2004-03-21T20:50:42Z", l1.getValue().toString()); 615 ncal = new GregorianCalendar(pdt); 617 ncal.set(2004, 03, 21, 12, 50, 42); ncal.set(Calendar.MILLISECOND, 0); 619 l1 = m.createTypedLiteral(ncal); 621 assertEquals("DateTime from date", XSDDatatype.XSDdateTime, l1.getDatatype()); 622 assertEquals("DateTime from date", XSDDateTime.class, l1.getValue().getClass()); 623 assertEquals("DateTime from date", "2004-04-21T19:50:42Z", l1.getValue().toString()); 624 626 } 627 628 631 public void testTypedQueries() { 632 Model model = ModelFactory.createDefaultModel(); 633 Property p = model.createProperty("urn:x-eg/p"); 634 Literal l1 = model.createTypedLiteral("10", "http://www.w3.org/2001/XMLSchema#integer"); 635 Literal l2 = model.createTypedLiteral("010", "http://www.w3.org/2001/XMLSchema#integer"); 636 assertSameValueAs("sameas test", l1, l2); 637 Resource a = model.createResource("urn:x-eg/a"); 638 a.addProperty(p, l1); 639 assertTrue(model.getGraph().find(null, p.asNode(), l1.asNode()).hasNext()); 640 assertTrue(model.getGraph().find(null, p.asNode(), l2.asNode()).hasNext()); 641 assertTrue(model.getGraph().find(a.asNode(), p.asNode(), l2.asNode()).hasNext()); 642 Query q = new Query(); 643 q.addMatch(a.asNode(), p.asNode(), l2.asNode()); 644 Iterator qi = model.getGraph().queryHandler().prepareBindings(q, new Node[] {}).executeBindings(); 645 assertTrue(qi.hasNext()); 646 assertTrue(model.listStatements( a, p, l2 ).hasNext()); 649 } 650 651 654 public void testIsValidLiteral() { 655 Literal l = m.createTypedLiteral("1000", XSDDatatype.XSDinteger); 656 LiteralLabel ll = l.asNode().getLiteral(); 657 assertTrue(XSDDatatype.XSDlong.isValidLiteral(ll)); 658 assertTrue(XSDDatatype.XSDint.isValidLiteral(ll)); 659 assertTrue(XSDDatatype.XSDshort.isValidLiteral(ll)); 660 assertTrue(XSDDatatype.XSDunsignedInt.isValidLiteral(ll)); 661 assertTrue(XSDDatatype.XSDunsignedLong.isValidLiteral(ll)); 662 assertTrue(XSDDatatype.XSDunsignedShort.isValidLiteral(ll)); 663 assertTrue(XSDDatatype.XSDpositiveInteger.isValidLiteral(ll)); 664 assertTrue(XSDDatatype.XSDdecimal.isValidLiteral(ll)); 665 assertTrue( ! XSDDatatype.XSDstring.isValidLiteral(ll)); 666 assertTrue( ! XSDDatatype.XSDbyte.isValidLiteral(ll)); 667 assertTrue( ! XSDDatatype.XSDnegativeInteger.isValidLiteral(ll)); 668 669 l = m.createTypedLiteral("-2", XSDDatatype.XSDinteger); 670 ll = l.asNode().getLiteral(); 671 assertTrue(XSDDatatype.XSDlong.isValidLiteral(ll)); 672 assertTrue(XSDDatatype.XSDint.isValidLiteral(ll)); 673 assertTrue(XSDDatatype.XSDshort.isValidLiteral(ll)); 674 assertTrue(! XSDDatatype.XSDunsignedInt.isValidLiteral(ll)); 675 assertTrue(! XSDDatatype.XSDunsignedLong.isValidLiteral(ll)); 676 assertTrue(! XSDDatatype.XSDunsignedShort.isValidLiteral(ll)); 677 assertTrue(XSDDatatype.XSDdecimal.isValidLiteral(ll)); 678 assertTrue(! XSDDatatype.XSDpositiveInteger.isValidLiteral(ll)); 679 assertTrue( ! XSDDatatype.XSDstring.isValidLiteral(ll)); 680 assertTrue(XSDDatatype.XSDbyte.isValidLiteral(ll)); 681 assertTrue(XSDDatatype.XSDnegativeInteger.isValidLiteral(ll)); 682 683 l = m.createTypedLiteral("4.5", XSDDatatype.XSDfloat); 684 ll = l.asNode().getLiteral(); 685 assertTrue(! XSDDatatype.XSDdouble.isValidLiteral(ll)); 686 assertTrue(! XSDDatatype.XSDdecimal.isValidLiteral(ll)); 687 688 Literal l2 = m.createTypedLiteral("foo", XSDDatatype.XSDstring); 689 assertTrue(XSDDatatype.XSDstring.isValidLiteral(l2.asNode().getLiteral())); 690 assertTrue(XSDDatatype.XSDnormalizedString.isValidLiteral(l2.asNode().getLiteral())); 691 assertTrue( ! XSDDatatype.XSDint.isValidLiteral(l2.asNode().getLiteral())); 692 693 l = m.createTypedLiteral("foo bar"); 694 ll = l.asNode().getLiteral(); 695 assertTrue(XSDDatatype.XSDstring.isValidLiteral(ll)); 696 assertTrue(! XSDDatatype.XSDint.isValidLiteral(ll)); 697 698 l = m.createTypedLiteral("12"); 699 ll = l.asNode().getLiteral(); 700 assertTrue(XSDDatatype.XSDstring.isValidLiteral(ll)); 701 assertTrue(! XSDDatatype.XSDint.isValidLiteral(ll)); 702 703 assertTrue(XSDDatatype.XSDnonNegativeInteger.isValidValue(new Long (10))); 705 assertTrue(XSDDatatype.XSDnonNegativeInteger.isValidValue(new Integer (10))); 706 assertTrue(!XSDDatatype.XSDnonNegativeInteger.isValidValue(new Long (-10))); 707 assertTrue(!XSDDatatype.XSDnonNegativeInteger.isValidValue("10")); 708 709 assertTrue(XSDDatatype.XSDfloat.isValidValue(new Float ("2.3"))); 713 assertTrue(XSDDatatype.XSDdouble.isValidValue(new Double ("2.3"))); 714 assertTrue( ! XSDDatatype.XSDfloat.isValidValue(new Integer ("2"))); 715 assertTrue( ! XSDDatatype.XSDfloat.isValidValue(new Double ("2.3"))); 716 } 717 718 721 public void testBinary() { 722 byte[] data = new byte[]{12,42,99}; 724 Literal l = m.createTypedLiteral(data); 725 LiteralLabel ll = l.asNode().getLiteral(); 726 assertEquals("binary test 1", ll.getDatatype(), XSDDatatype.XSDbase64Binary); 727 assertEquals("binary test 2", Base64.encode(data), ll.getLexicalForm()); 728 729 LiteralLabel l2 = m.createTypedLiteral(ll.getLexicalForm(), XSDDatatype.XSDbase64Binary).asNode().getLiteral(); 731 Object data2 = l2.getValue(); 732 assertTrue("binary test 3", data2 instanceof byte[]); 733 byte[] data2b = (byte[])data2; 734 assertEquals("binary test 4", data2b[0], 12); 735 assertEquals("binary test 5", data2b[1], 42); 736 assertEquals("binary test 6", data2b[2], 99); 737 assertEquals(l2, ll); 738 739 l2 = m.createTypedLiteral("DCpj", XSDDatatype.XSDbase64Binary).asNode().getLiteral(); 740 data2 = l2.getValue(); 741 assertTrue("binary test 3", data2 instanceof byte[]); 742 data2b = ((byte[])data2); 743 assertEquals("binary test 4", data2b[0], 12); 744 assertEquals("binary test 5", data2b[1], 42); 745 assertEquals("binary test 6", data2b[2], 99); 746 747 l = m.createTypedLiteral(data, XSDDatatype.XSDhexBinary); 749 ll = l.asNode().getLiteral(); 750 assertEquals("binary test 1b", ll.getDatatype(), XSDDatatype.XSDhexBinary); 751 assertEquals("binary test 2b", HexBin.encode(data), ll.getLexicalForm()); 752 753 l2 = m.createTypedLiteral(ll.getLexicalForm(), XSDDatatype.XSDhexBinary).asNode().getLiteral(); 755 data2 = l2.getValue(); 756 assertTrue("binary test 3b", data2 instanceof byte[]); 757 data2b = ((byte[])data2); 758 assertEquals("binary test 4b", data2b[0], 12); 759 assertEquals("binary test 5b", data2b[1], 42); 760 assertEquals("binary test 6b", data2b[2], 99); 761 assertEquals(l2, ll); 762 763 Literal la = m.createTypedLiteral("GpM7", XSDDatatype.XSDbase64Binary); 764 Literal lb = m.createTypedLiteral("GpM7", XSDDatatype.XSDbase64Binary); 765 assertTrue("equality test", la.sameValueAs(lb)); 766 } 767 768 772 public void XXtestBinaryBug() throws IOException { 773 Model orig = ModelFactory.createDefaultModel(); 774 Resource r = orig.createResource("http://jena.hpl.hp.com/test#r"); 775 Property p = orig.createProperty("http://jena.hpl.hp.com/test#p"); 776 Literal l = orig.createTypedLiteral("GpM7", XSDDatatype.XSDbase64Binary); 777 orig.add(r, p, l); 778 for (int i = 0; i < 150; i++) { 780 l = orig.createTypedLiteral(new byte[]{(byte)i, (byte)i, (byte)i}); 781 orig.add(orig.createResource("urn:x-hp:" + i), p, l); 782 } 783 ByteArrayOutputStream out = new ByteArrayOutputStream(1000); 784 orig.write(out, "RDF/XML-ABBREV"); 785 out.close(); 786 InputStream ins = new ByteArrayInputStream(out.toByteArray()); 787 Model m2 = ModelFactory.createDefaultModel(); 788 m2.read(ins, null); 789 ins.close(); 790 assertTrue(orig.isIsomorphicWith(m2)); 791 } 792 793 796 public void testDateTimeBug() { 797 String XSDDateURI = XSD.date.getURI(); 799 TypeMapper typeMapper=TypeMapper.getInstance(); 800 RDFDatatype dt = typeMapper.getSafeTypeByName(XSDDateURI); 801 Object obj = dt.parse("2003-05-21"); 802 Literal literal = m.createTypedLiteral(obj, dt); String serialization = literal.toString(); 803 Object value2 = dt.parse(obj.toString()); 804 assertEquals(obj, value2); 805 806 RDFDatatype dateType = XSDDatatype.XSDdate; 808 Literal l = m.createTypedLiteral("2003-05-21", dateType); 809 810 checkSerialization("2003-05-21", XSDDatatype.XSDdate); 812 checkSerialization("2003-05-21T12:56:10Z", XSDDatatype.XSDdateTime); 813 checkSerialization("2003-05", XSDDatatype.XSDgYearMonth); 814 checkSerialization("2003", XSDDatatype.XSDgYear); 815 checkSerialization("--05", XSDDatatype.XSDgMonth); 816 checkSerialization("--05-12", XSDDatatype.XSDgMonthDay); 817 checkSerialization("---12", XSDDatatype.XSDgDay); 818 } 819 820 823 public void testFlags() { 824 boolean originalFlag = JenaParameters.enableEagerLiteralValidation; 825 JenaParameters.enableEagerLiteralValidation = true; 826 boolean foundException = false; 827 try { 828 Literal l = m.createTypedLiteral("fool", XSDDatatype.XSDint); 829 } catch (DatatypeFormatException e1) { 830 foundException = true; 831 } 832 JenaParameters.enableEagerLiteralValidation = originalFlag; 833 assertTrue("Early datatype format exception", foundException); 834 835 JenaParameters.enableEagerLiteralValidation = false; 836 foundException = false; 837 Literal l = null; 838 try { 839 l = m.createTypedLiteral("fool", XSDDatatype.XSDint); 840 } catch (DatatypeFormatException e1) { 841 JenaParameters.enableEagerLiteralValidation = originalFlag; 842 assertTrue("Delayed datatype format validation", false); 843 } 844 try { 845 l.getValue(); 846 } catch (DatatypeFormatException e2) { 847 foundException = true; 848 } 849 JenaParameters.enableEagerLiteralValidation = originalFlag; 850 assertTrue("Early datatype format exception", foundException); 851 852 originalFlag = JenaParameters.enablePlainLiteralSameAsString; 853 Literal l1 = m.createLiteral("test string"); 854 Literal l2 = m.createTypedLiteral("test string", XSDDatatype.XSDstring); 855 JenaParameters.enablePlainLiteralSameAsString = true; 856 boolean ok1 = l1.sameValueAs(l2); 857 JenaParameters.enablePlainLiteralSameAsString = false; 858 boolean ok2 = ! l1.sameValueAs(l2); 859 JenaParameters.enablePlainLiteralSameAsString = originalFlag; 860 assertTrue( ok1 ); 861 assertTrue( ok2 ); 862 } 863 864 867 public void testLexicalDistinction() { 868 Literal l1 = m.createTypedLiteral("3.0", XSDDatatype.XSDdecimal); 869 Literal l2 = m.createTypedLiteral("3.00", XSDDatatype.XSDdecimal); 870 Literal l3 = m.createTypedLiteral("3.0", XSDDatatype.XSDdecimal); 871 assertSameValueAs("lexical form does not affect value", l1, l2); 872 assertSameValueAs("lexical form does not affect value", l3, l2); 873 assertTrue("lexical form affects equality", ! l1.equals(l2)); 874 assertTrue("lexical form affects equality", l1.equals(l3)); 875 876 l1 = m.createTypedLiteral("3", XSDDatatype.XSDint); 878 l2 = m.createTypedLiteral(" 3 ", XSDDatatype.XSDint); 879 l3 = m.createTypedLiteral("3", XSDDatatype.XSDint); 880 assertSameValueAs("lexical form does not affect value", l1, l2); 881 assertSameValueAs("lexical form does not affect value", l3, l2); 882 assertTrue("lexical form affects equality", ! l1.equals(l2)); 883 assertTrue("lexical form affects equality", l1.equals(l3)); 884 } 885 886 889 private void assertDiffer( String title, Literal x, Literal y ) { 890 assertTrue( title, !x.sameValueAs( y ) ); 891 } 892 893 896 private void assertSameValueAs( String title, Literal x, Literal y ) { 897 assertTrue( title, x.sameValueAs( y ) ); 898 } 899 900 903 private void assertFloatEquals(String title, double x, double y) { 904 assertTrue(title, Math.abs(x - y) < 0.001); 905 } 906 907 911 public void checkIllegalLiteral(String lex, RDFDatatype dtype) { 912 try { 913 Literal l = m.createTypedLiteral(lex, dtype); 914 l.getValue(); 915 assertTrue("Failed to catch '" + lex + "' as an illegal " + dtype, false); 916 } catch (DatatypeFormatException e1) { 917 } 919 } 920 921 924 public void checkLegalLiteral(String lex, RDFDatatype dtype, Class jtype, Object value) { 925 Literal l = m.createTypedLiteral(lex, dtype); 926 assertEquals(l.getValue().getClass(), jtype); 927 assertEquals(l.getValue(), value); 928 assertEquals(l.getDatatype(), dtype); 929 } 930 931 934 public void checkSerialization(String lex, RDFDatatype dtype) { 935 Literal l = m.createTypedLiteral(lex, dtype); 936 assertEquals(l.getValue().toString(), lex); 937 } 938 939 940 public void assertIteratorValues(Iterator it, Object [] vals) { 941 boolean[] found = new boolean[vals.length]; 942 for (int i = 0; i < vals.length; i++) found[i] = false; 943 while (it.hasNext()) { 944 Object n = it.next(); 945 boolean gotit = false; 946 for (int i = 0; i < vals.length; i++) { 947 if (n.equals(vals[i])) { 948 gotit = true; 949 found[i] = true; 950 } 951 } 952 assertTrue(gotit); 953 } 954 for (int i = 0; i < vals.length; i++) { 955 assertTrue(found[i]); 956 } 957 } 958 959 960 } 961 962 966 class RationalType extends BaseDatatype { 967 public static final String theTypeURI = "urn:x-hp-dt:rational"; 968 public static final RDFDatatype theRationalType = new RationalType(); 969 970 971 private RationalType() { 972 super(theTypeURI); 973 } 974 975 979 public String unparse(Object value) { 980 Rational r = (Rational) value; 981 return Integer.toString(r.getNumerator()) + "/" + r.getDenominator(); 982 } 983 984 988 public Object parse(String lexicalForm) throws DatatypeFormatException { 989 int index = lexicalForm.indexOf("/"); 990 if (index == -1) { 991 throw new DatatypeFormatException(lexicalForm, theRationalType, ""); 992 } 993 try { 994 int numerator = Integer.parseInt(lexicalForm.substring(0, index)); 995 int denominator = Integer.parseInt(lexicalForm.substring(index+1)); 996 return new Rational(numerator, denominator); 997 } catch (NumberFormatException e) { 998 throw new DatatypeFormatException(lexicalForm, theRationalType, ""); 999 } 1000 } 1001 1002 1007 public boolean isEqual(LiteralLabel value1, LiteralLabel value2) { 1008 return value1.getDatatype() == value2.getDatatype() 1009 && value1.getValue().equals(value2.getValue()); 1010 } 1011 1012} 1013 1014 1018class Rational { 1019 private int numerator; 1020 private int denominator; 1021 1022 Rational(int numerator, int denominator) { 1023 this.numerator = numerator; 1024 this.denominator = denominator; 1025 } 1026 1030 public int getDenominator() { 1031 return denominator; 1032 } 1033 1034 1038 public int getNumerator() { 1039 return numerator; 1040 } 1041 1042 1046 public void setDenominator(int denominator) { 1047 this.denominator = denominator; 1048 } 1049 1050 1054 public void setNumerator(int numerator) { 1055 this.numerator = numerator; 1056 } 1057 1058 1061 public String toString() { 1062 return "rational[" + numerator + "/" + denominator + "]"; 1063 } 1064 1065 1068 public boolean equals(Object o) { 1069 if (o == null || !(o instanceof Rational)) return false; 1070 Rational or = (Rational)o; 1071 return (numerator == or.numerator && denominator == or.denominator); 1072 } 1073} 1074 1075 1076 1105 1106 | Popular Tags |