[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    [PATCH] URI, URL, FOO, URN
From:       Frans Englich <frans.englich () telia ! com>
Date:       2005-03-14 1:27:34
Message-ID: 200503140127.34236.frans.englich () telia ! com
[Download RAW message or body]

Hello,

I'm working on an OASIS XML Catalogs[1] implementation, and for that I need 
support for the URI type URNs[RFC 3151], in particular the publicid 
namespace[RFC 2141].

The attached patch is a "KURN" class with accompanying test cases, which it 
passes. AFAICT, it is feature complete and covers everything which is needed 
for a Catalog implementation, for example. I would preferrably see URN 
functionality in kdecore.

While I'm just fine with the attached class for my needs, I suspect it doesn't 
play well with kdecore/KURL, whose design I'm a bit confused by. KURL handles 
URL functionality, /plus/ its superset URI. By that principle any URI 
functionality such as URN should be put in KURL, which is quite illogical, 
IMO. I find that design non-oop, and too broad, since for example both URN 
and publicid is rarely used functionality. So, the different functionalities 
are "multi-plexed" in KURL instead of factoring it in classes, but by that 
principle the class should have been named KURI, IMHO. 

What are the plans for KDE 4? To split KURL into KURI and KURL? The Catalog 
implementation will live in kdenonbeta/kdom and hence first becomes relevant 
for KDE 4, so I can live with a temporary solution, such as housing the class 
there, or to (preferrably) have it in kdecore/, inherting KURL as it does 
now. It's nice functionality afterall.

Also, the patch itself needs sanity-reviewal, I don't know where I should rely 
more on KURL, if the decode/encode loops are correctly approached, etc. 

In other words, some clear answers are needed :)


Cheers,

		Frans

1.

The specification:
http://www.oasis-open.org/committees/entity/spec.html

An user oriented overview:
http://xml.apache.org/commons/components/resolver/resolver-article.html

["kurn.diff" (text/x-diff)]

Index: Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/kdecore/Makefile.am,v
retrieving revision 1.360
diff -u -3 -p -r1.360 Makefile.am
--- Makefile.am	7 Jan 2005 23:09:18 -0000	1.360
+++ Makefile.am	14 Mar 2005 01:15:03 -0000
@@ -59,7 +59,7 @@ include_HEADERS = kconfig.h kconfigskele
 	kcalendarsystem.h kcalendarsystemfactory.h kmacroexpander.h \
 	kmanagerselection.h kmountpoint.h kuser.h klockfile.h \
 	kidna.h ktempdir.h kshell.h fixx11h.h kxerrorhandler.h kdelibs_export.h \
-	kdemacros.h kde_file.h kswap.h
+	kdemacros.h kde_file.h kswap.h kurn.h
 
 libkdefakes_la_SOURCES = fakes.c vsnprintf.c
 libkdefakes_la_LDFLAGS = -version-info 6:0:2
@@ -100,7 +100,7 @@ libkdecore_la_SOURCES = libintl.cpp kapp
 	kcmdlineargs.cpp kaboutdata.cpp kcompletionbase.cpp knotifyclient.cpp \
 	kaudioplayer.cpp kdcoppropertyproxy.cpp \
 	ksockaddr.cpp kextsock.cpp netsupp.cpp kprocio.cpp kbufferedio.cpp \
-	kpixmapprovider.cpp kurldrag.cpp \
+	kpixmapprovider.cpp kurldrag.cpp kurn.cpp \
 	kmdcodec.cpp ksocks.cpp fakes.c vsnprintf.c \
 	ksycoca.cpp ksycocadict.cpp ksycocafactory.cpp ksycoca.skel \
 	kxmessages.cpp kstartupinfo.cpp kcatalogue.cpp kasyncio.cpp \
Index: kurn.cpp
===================================================================
RCS file: kurn.cpp
diff -N kurn.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ kurn.cpp	14 Mar 2005 01:15:03 -0000
@@ -0,0 +1,275 @@
+/* This file is part of the KDE libraries
+ *
+ * Copyright (C) 2005 Frans Englich 	<frans.englich@telia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include <qstring.h>
+
+#include <kdebug.h>
+
+#include "kurn.h"
+
+/**
+ * Case insensitive QString-comparision.
+ */
+#define isInsCaseEqual(a, b) (a.length() == b.length() && (b.find(a, 0, false) != -1))
+
+/*
+ * Related documentation:
+ *
+ * + RFC 3151 -- URN Syntax
+ * + RFC 2141 -- A URN Namespace for Public Identifiers
+ * + OASIS XML Catalogs, section 6.4 - "URN 'Unwrapping'"
+ */
+
+/*
+ * TODO:
+ * + Perform lexical validation in isValidNSS() and isValidNID().
+ */
+
+class KURN::Private
+{
+public:
+	Private():
+		isURN(false),
+		hasValidNSS(false),
+		hasValidNID(false),
+		hasPublicID(false)
+	{ }
+
+	bool isURN :1;
+	bool hasValidNSS :1;
+	bool hasValidNID :1;
+	bool hasPublicID :1;
+	QString nid;
+	QString nss;
+	QString publicID; /* Un-encoded version of nss */
+};
+
+KURN::KURN(const QString& uri): KURL(uri.stripWhiteSpace()), d(new Private())
+{
+	init();
+}
+
+KURN::KURN(const KURL& uri): KURL(uri.url().stripWhiteSpace()), d(new Private())
+{
+	init();
+}
+
+KURN::KURN( const char* urn): KURL(QString(urn).stripWhiteSpace()), d(new Private())
+{
+	init();
+}
+
+KURN::~KURN()
+{
+	delete d;
+}
+
+bool KURN::isValidNID(const QString& nid) const
+{
+	if(isInsCaseEqual(nid, QString("urn"))) /* Reserved */
+		return false;
+	else
+		return true;
+}
+
+bool KURN::isValidNSS(const QString& /*nss*/) const
+{
+	return true;
+}
+
+bool KURN::operator==(const KURN &urn)
+{
+	if(namespaceSpecific() == urn.namespaceSpecific() &&
+			isInsCaseEqual(urn.namespaceID(), namespaceID()) &&
+			urn.isValid() &&
+			isValid())
+		return true;
+	else
+		return false;
+}
+
+void KURN::setNamespaceID(const QString& nid)
+{
+	d->nid = nid;
+
+	d->hasValidNID = isValidNID(nid);
+
+	if(d->nid == "publicid")
+		d->hasPublicID = true;
+	else
+	{
+		d->publicID = QString::null;
+		d->hasPublicID = false;
+	}
+}
+
+void KURN::setNamespaceSpecific(const QString& nss)
+{
+	d->nss = nss;
+	d->hasValidNSS = isValidNSS(nss);
+	d->publicID = QString::null;
+
+	/* Normalize %-encoding */
+	const uint length = d->nss.length();
+	for(uint i = 0; i < length; i++)
+		if(d->nss.at(i) == '%')
+		{
+			d->nss.replace(i + 1, 2, d->nss.mid(i + 1, 2).upper());
+			i += 2;
+		}
+
+	if(hasPublicID())
+	{
+		/* Decode the URN into a XML Public ID */
+		const uint length = d->nss.length();
+		for(uint i = 0; i < length; i++)
+		{
+			const QChar c = d->nss.at(i);
+			if(c == '+')
+				d->publicID += " ";
+
+			else if(c == ':')
+				d->publicID += "//";
+
+			else if(c == ';')
+				d->publicID += "::";
+			else if(c == '%')
+			{
+				const QString hex = d->nss.mid(i+1, 2);
+
+				if(hex == "23")
+					d->publicID += '#';
+				else if(hex == "25")
+					d->publicID += '%';
+				else if(hex == "27")
+					d->publicID += '\'';
+				else if(hex == "2B")
+					d->publicID += '+';
+				else if(hex == "2F")
+					d->publicID += '/';
+				else if(hex == "3A")
+					d->publicID += ':';
+				else if(hex == "3B")
+					d->publicID += ';';
+				else if(hex == "3F")
+					d->publicID += '?';
+				else
+					d->publicID += hex;
+				
+				i += 2;
+			}
+			else
+				d->publicID += c;
+		}
+		d->publicID = d->publicID.simplifyWhiteSpace();
+	}
+}
+
+void KURN::init()
+{
+	const QString uri = url();
+
+	/* Put the position of the colon between nss and nid in sepPos */
+	const int sepPos = uri.find(":", 4);
+	setNamespaceID(uri.mid(4, sepPos-4));
+	setNamespaceSpecific(uri.mid(sepPos + 1)); /* +1 == No colon */
+
+	kdDebug() << "URI:" << uri << " NID: " << d->nid << " NSS: " << d->nss << endl;
+
+	if(uri.startsWith("urn:", false) || uri.isEmpty())
+		d->isURN = true;
+	else
+		d->isURN = false;
+
+}
+
+KURN KURN::fromPublicID(const QString& pub)
+{
+	/* See RFC3151, section 1.1 - "Public Identifiers" */
+	QString npub = pub.simplifyWhiteSpace();
+
+	const uint length = npub.length();
+	for(uint i = 0; i < length; i++)
+	{
+		const QChar c = npub.at(i);
+		if(c == ' ')
+			npub.replace(i, 1, '+');
+		else if(c == '+')
+		{
+			npub.replace(i, 1, "%2B");
+			i += 2;
+		}
+		else if(c == ':')
+			if( npub.at(i+1) == ':')
+				npub.replace(i, 2, ';');
+			else
+			{
+				npub.replace(i, 1, "%3A");
+				i += 2;
+			}
+		else if(c == '/')
+			if(npub.at(i+1) == '/')
+				npub.replace(i, 2, ':');
+			else
+			{
+				npub.replace(i, 1, "%2F");
+				i += 2;
+			}
+	}
+	
+	return KURN(KURL::fromPathOrURL("urn:publicid:" + npub)); /* KURL performs ordinary URI encoding */
+}
+
+void KURN::setURN(const QString& urn)
+{
+	parse(urn);
+	init();
+}
+
+QString KURN::urn() const
+{
+	return "urn:" + namespaceID() + ":" + namespaceSpecific();
+}
+
+bool KURN::isValid() const
+{
+	return d->hasValidNID && d->hasValidNSS && d->isURN;
+}
+
+QString KURN::namespaceID() const
+{
+	return d->nid;
+}
+
+bool KURN::hasPublicID() const
+{
+	return d->hasPublicID;
+}
+
+QString KURN::publicID() const
+{
+	return d->publicID;
+}
+
+QString KURN::namespaceSpecific() const
+{
+	return d->nss;
+}
+
Index: kurn.h
===================================================================
RCS file: kurn.h
diff -N kurn.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ kurn.h	14 Mar 2005 01:15:03 -0000
@@ -0,0 +1,196 @@
+/* This file is part of the KDE libraries
+ *
+ * Copyright (C) 2005 Frans Englich 	<frans.englich@telia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#ifndef kurn_h
+#define kurn_h
+
+#include <kurl.h>
+
+class QString;
+
+/**
+ * @short A class for handling URNs, as per RFC 2141, with
+ * support for the publicid namespace.
+ *
+ * \
+ *
+ * @author Frans Englich <frans.englich@telia.com>
+ */
+class KURN: public KURL
+{
+public:
+	/**
+	 * Constructs a KURN from @p urn, which is assumed to be a valid, properly encoded,
+	 * URN.
+	 *
+	 * @p urn is assumed to be a valid, that is encoded, URN.
+	 * @param urn an URN string to construct
+	 */
+	KURN(const QString& urn);
+
+	/**
+	 * This is an overloaded member function, provided for convenience.
+	 * It behaves essentially like the above function.
+	 */
+	KURN(const KURL& urn);
+
+	/**
+	 * This is an overloaded member function, provided for convenience.
+	 * It behaves essentially like the above function.
+	 */
+	KURN( const char* urn);
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~KURN();
+
+	/**
+	 * Determines whether the URN is in the publicid namespace, as per
+	 * RFC 3151.
+	 *
+	 * @returns true if the URN is in the publicid namespace
+	 */
+	bool hasPublicID() const;
+
+	/**
+	 * Sets the namespace specific string of the URN to @p nss.
+	 */
+	void setNamespaceSpecific(const QString& nss);
+
+	/**
+	 * Sets the URN's namespace ID to @p nid.
+	 *
+	 * @param nid the namespace id to set
+	 */
+	void setNamespaceID( const QString& nid);
+
+	/**
+	 * Retrieves the namespace identifer of the URN. For example, for the
+	 * URN "urn:oasis:names:tc:entity:xmlns" is "oasis" returned.
+	 *
+	 * @returns the namespace identifier
+	 */
+	QString namespaceID() const;
+
+	/**
+	 * Comparishion operator. Two URNs are considered equal if their
+	 * namespace identifier's are case-insensitively equal, and that the
+	 * namespace specific strings are case-sensitively equal. If a
+	 * particular namespace imposes other semantics on lexical equalness for
+	 * the namespace specific string, this function must be re-implemented.
+	 *
+	 * @returns true if the two URNs are considered equal.
+	 */
+	bool operator==(const KURN &urn);
+
+	/**
+	 * Retrieves the namespace specific part of the URN. For example, for
+	 * the URN "urn:oasis:names:tc:entity:xmlns" is "names:tc:entity:xmlns"
+	 * returned.
+	 *
+	 * @returns the namespace specific string
+	 */
+	QString namespaceSpecific() const;
+
+	/**
+	 * Retrieves the contained XML Public ID in an unwrapped, unencoded
+	 * representation. If you want the Public ID in its encoded form,
+	 * use namespaceSpecific(), or urn().
+	 *
+	 * For example:
+	 * \code
+	 * KURN dsssl("urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN");
+	 * //dsssl.publicID() == "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN");
+	 * \endcode
+	 *
+	 * If the URN is not in the publicid namespace, an
+	 * empty string is returned.
+	 *
+	 * @returns a public ID
+	 */
+	QString publicID() const;
+
+	/**
+	 * Returns a complete URN. This is typically a normalized for of what was
+	 * passed in one of the constructors.
+	 */
+	QString urn() const;
+
+	/**
+	 * Determines whether the contained URI is a valid URN. In other words,
+	 * the contained URI may very well be a valid URI, but simply not be
+	 * an URN, or be an invalid URN.
+	 *
+	 * @returns true if the URN is valid
+	 */
+	bool isValid() const;
+
+	/**
+	 * Sets the object to house @p urn. This is identical to
+	 * calling a constructor with @p urn. @p urn is assumed to
+	 * be a valid URN.
+	 *
+	 * @param urn the URN to represent
+	 */
+	void setURN( const QString& urn );
+
+	/**
+	 * Constructs an URN in the publicid namespace with the
+	 * Public Identifier @p pub. For example:
+	 *
+	 * \code
+	 * KURN urn = KURN::fromPublicID("-//OASIS//DTD Docbook XML V4.1.2//EN");
+	 * //urn.urn() == "urn:publicid:-:OASIS:DTD+Docbook+XML+V4.1.2:EN"
+	 * \endcode
+	 *
+	 * @param pub the public identifier to construct an URN for
+	 * @returns an URN in the publicid with @p pub
+	 */
+	static KURN fromPublicID(const QString& pub);
+
+protected:
+	
+	/**
+	 * Determines whether @p nid is a valid Namespace Identifier.
+	 *
+	 * @param nid the identifier to validate
+	 * @returns true if @p nid is a valid nid
+	 */
+	bool isValidNID(const QString& nid) const;
+
+	/**
+	 * Determines whether @p nss is a valid Namespace Specific String. Reimplement this
+	 * function to do namespace specific validation, beyond what the RFC mandates.
+	 *
+	 * @param nss the namespace string to validate
+	 * @param returns true if @p nss is considered a valid namespace specific string
+	 */
+	bool isValidNSS(const QString& nss) const;
+
+	void init();
+
+private:
+
+	class Private;
+	Private* const d;
+};
+
+#endif // kurn_h
Index: tests/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/kdecore/tests/Makefile.am,v
retrieving revision 1.50
diff -u -3 -p -r1.50 Makefile.am
--- tests/Makefile.am	24 Nov 2004 12:22:34 -0000	1.50
+++ tests/Makefile.am	14 Mar 2005 01:15:03 -0000
@@ -28,9 +28,10 @@ check_PROGRAMS = kconfigtest klocaletest
 	cplusplustest kiconloadertest kresolvertest kmdcodectest knotifytest \
 	ksortablevaluelisttest krfcdatetest testqtargs kprociotest \
 	kcharsetstest kcalendartest kmacroexpandertest kshelltest \
-	kxerrorhandlertest startserviceby kstdacceltest kglobaltest
+	kxerrorhandlertest startserviceby kstdacceltest kglobaltest \
+	kurntest
 
-TESTS = kurltest kstdacceltest
+TESTS = kurltest kstdacceltest kurntest
 
 noinst_HEADERS = kconfigtest.h klocaletest.h kprocesstest.h KIDLTest.h \
 		kipctest.h kprociotest.h
@@ -45,6 +46,7 @@ klocaletest_SOURCES = klocaletest.cpp
 #kcatalogue_SOURCES = kcatalogue.cpp libintl.cpp
 ksimpleconfigtest_SOURCES = ksimpleconfigtest.cpp
 kurltest_SOURCES = kurltest.cpp
+kurntest_SOURCES = kurntest.cpp
 kstddirstest_SOURCES = kstddirstest.cpp
 kprocesstest_SOURCES = kprocesstest.cpp
 kuniqueapptest_SOURCES = kuniqueapptest.cpp
Index: tests/kurntest.cpp
===================================================================
RCS file: tests/kurntest.cpp
diff -N tests/kurntest.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/kurntest.cpp	14 Mar 2005 01:15:03 -0000
@@ -0,0 +1,193 @@
+/* This file is part of the KDE libraries
+ *
+ * Copyright (C) 2005 Frans Englich 	<frans.englich@telia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include <stdlib.h>
+
+#include <qstring.h>
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kurn.h>
+
+static uint numErrors = 0;
+static uint numSucessess = 0;
+
+/**
+ * Compares @p a to @p b, and if they're not equal the program exits. In either case is
+ * a debug statement printed.
+ *
+ * @param desc a description of the test, such as the function call
+ * @param a the value to be compared to @p b
+ * @param b the value @p a is compared to
+ */
+void check(QString desc, QString a, QString b)
+{
+	if (a.isEmpty())
+		a = QString::null;
+
+	if (b.isEmpty())
+		b = QString::null;
+
+	const QString msg = desc + \
+			" Expected: \"" + b + "\", " + "got \"" + a + "\".";
+	if (a == b)
+	{
+		kdDebug() << "SUCCESS: " << msg << endl;
+		numSucessess++;
+	}
+	else
+	{
+		kdDebug() << "FAILURE: " << msg << endl;
+		numErrors++;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	KApplication::disableAutoDcopRegistration();
+	KCmdLineArgs::init( argc, argv, "kurltest", 0, 0, 0, 0 );
+	KApplication app( false, false );
+
+	KURN simple("urn:simple:test:yup:tup");
+
+	check("KURN::urn()", simple.urn(), "urn:simple:test:yup:tup");
+	check("KURN::namespaceID()", simple.namespaceID(), "simple");
+	check("KURN::namespaceSpecific()", simple.namespaceSpecific(), "test:yup:tup");
+	check("KURN::isValid()", simple.isValid() ? "true": "false", "true");
+	check("KURN::publicID()", simple.publicID(), "");
+	check("KURN::hasPublicID()", simple.hasPublicID() ? "true": "false", "false");
+
+	simple.setURN("urn:again:foo:no:no"); /* Ensure that values are actually changed */
+	check("KURN::namespaceID()", simple.namespaceID(), "again");
+	check("KURN::namespaceSpecific()", simple.namespaceSpecific(), "foo:no:no");
+	check("KURN::isValid()", simple.isValid() ? "true": "false", "true");
+	check("KURN::publicID()", simple.publicID(), "");
+	check("KURN::hasPublicID()", simple.hasPublicID() ? "true": "false", "false");
+
+	KURN pub("urn:publicid:yo:foo"); /* Simple public ID functionality */
+	check("KURN::namespaceID()", pub.namespaceID(), "publicid");
+	check("KURN::namespaceSpecific()", pub.namespaceSpecific(), "yo:foo");
+	check("KURN::isValid()", pub.isValid() ? "true": "false", "true");
+	check("KURN::publicID()", pub.publicID(), "yo//foo");
+	check("KURN::hasPublicID()", pub.hasPublicID() ? "true": "false", "true");
+
+	/* Examples from the RFC */
+	KURN dsssl("urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN");
+	check("KURN::publicID()", dsssl.publicID(), "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN");
+
+	KURN latin("urn:publicid:ISO+8879%3A1986:ENTITIES+Added+Latin+1:EN");
+	check("KURN::publicID()", latin.publicID(), "ISO 8879:1986//ENTITIES Added Latin 1//EN");
+
+	KURN oasis("urn:publicid:-:OASIS:DTD+DocBook+XML+V4.1.2:EN");
+	check("KURN::publicID()", oasis.publicID(), "-//OASIS//DTD DocBook XML V4.1.2//EN");
+
+	KURN book("urn:publicid:%2B:IDN+example.org:DTD+XML+Bookmarks+1.0:EN:XML");
+	check("KURN::publicID()", book.publicID(), "+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML");
+
+	KURN arbor("urn:publicid:-:ArborText;prod:DTD+Help+Document;19970708:EN");
+	check("KURN::publicID()", arbor.publicID(), "-//ArborText::prod//DTD Help Document::19970708//EN");
+
+	KURN foo("urn:publicid:foo");
+	check("KURN::publicID()", foo.publicID(), "foo");
+
+	KURN math("urn:publicid:3%2B3=6");
+	check("KURN::publicID()", math.publicID(), "3+3=6");
+ 	
+	/* NIDs equal to "urn" are reserved, not those simply starting with "urn" */
+	math.setURN("urn:urnig:test");
+	check("KURN::isValid()", math.isValid() ? "true": "false", "true");
+
+	KURN acme("urn:publicid:-:Acme,+Inc.:DTD+Book+Version+1.0");
+	check("KURN::publicID()", acme.publicID(), "-//Acme, Inc.//DTD Book Version 1.0");
+
+	/* Try to shake it off */
+	acme.setURN("urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN");
+	check("KURN::publicID()", acme.publicID(), "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN");
+	acme.setURN("urn:again:foo:no:no");
+	check("KURN::namespaceID()", acme.namespaceID(), "again");
+	check("KURN::namespaceSpecific()", acme.namespaceSpecific(), "foo:no:no");
+	check("KURN::isValid()", acme.isValid() ? "true": "false", "true");
+	check("KURN::publicID()", acme.publicID(), "");
+	check("KURN::hasPublicID()", acme.hasPublicID() ? "true": "false", "false");
+
+	/* Test equalness code */
+	check("KURN(\"URN:foo:a123,456\") == KURN(\"urn:foo:a123,456\")",
+			(KURN("URN:foo:a123,456") == KURN("urn:foo:a123,456"))
+			? "true" : "false", "true");
+	check("(KURN(\"URN:foo:a123,456\") == KURN(\"urn:FOO:a123,456\")",
+			(KURN("URN:foo:a123,456") == KURN("urn:FOO:a123,456"))
+			? "true" : "false", "true");
+	check("(KURN(\"urn:foo:A123,456\") == KURN(\"Urn:foo:a123,456\")",
+			(KURN("urn:foo:A123,456") == KURN("Urn:foo:a123,456"))
+			? "true" : "false", "false");
+	check("(KURN(\"urn:foo:a123%2C456\") == KURN(\"URN:FOO:a123%2c456\")",
+			(KURN("urn:foo:a123%2C456") == KURN("URN:FOO:a123%2c456"))
+			? "true" : "false", "true");
+	check("(KURN(\"urn:foo:a123%2C456\") == KURN(\"urn:FOO:a123,456\")",
+			(KURN("urn:foo:a123%2C456") == KURN("urn:FOO:a123,456"))
+			? "true" : "false", "false");
+
+
+	/* ...and the other way around */
+
+	check("KURN::fromPublicID(\"ISO/IEC 10179:1996//DTD DSSSL Architecture//EN\").urn()",
+			KURN::fromPublicID("ISO/IEC 10179:1996//DTD DSSSL Architecture//EN").urn(),
+			"urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN");
+	check("KURN::fromPublicID(\"ISO 8879:1986//ENTITIES Added Latin 1//EN\").urn()",
+			KURN::fromPublicID("ISO 8879:1986//ENTITIES Added Latin 1//EN").urn(),
+			"urn:publicid:ISO+8879%3A1986:ENTITIES+Added+Latin+1:EN");
+	check("KURN::fromPublicID(\"+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML\").urn()",
+			KURN::fromPublicID("+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML").urn(),
+			"urn:publicid:%2B:IDN+example.org:DTD+XML+Bookmarks+1.0:EN:XML");
+	check("KURN::fromPublicID(\"-//ArborText::prod//DTD Help Document::19970708//EN\").urn()",
+			KURN::fromPublicID("-//ArborText::prod//DTD Help Document::19970708//EN").urn(),
+			"urn:publicid:-:ArborText;prod:DTD+Help+Document;19970708:EN");
+
+	check("KURN::fromPublicID(\"foo\").urn()",
+			KURN::fromPublicID("foo").urn(),
+			"urn:publicid:foo");
+
+	check("KURN::fromPublicID(\"3+3=6\").urn()",
+			KURN::fromPublicID("3+3=6").urn(),
+			"urn:publicid:3%2B3=6");
+
+	check("KURN::fromPublicID(\"-//Acme, Inc.//DTD Book Version 1.0\").urn()",
+			KURN::fromPublicID("-//Acme, Inc.//DTD Book Version 1.0").urn(),
+			"urn:publicid:-:Acme,+Inc.:DTD+Book+Version+1.0");
+
+	/* Test altering various parts */
+	oasis.setNamespaceID("yo");
+	check("oasis.publicID()", oasis.publicID(), "");
+	check("oasis.hasPublicID", oasis.hasPublicID() ? "true" : "false", "false");
+	check("oasis.namespaceSpecific()", oasis.namespaceSpecific(), "-:OASIS:DTD+DocBook+XML+V4.1.2:EN");
+	check("oasis.urn()", oasis.urn(), "urn:yo:-:OASIS:DTD+DocBook+XML+V4.1.2:EN");
+
+	if(numErrors)
+	{
+		kdDebug() << "*** FAILURE: " << numErrors << " tests failed, " << numSucessess
+			<< " succeeded. ***" << endl;
+		exit(1);
+	}
+	else
+		kdDebug() << "*** SUCCESS: All tests, " << numSucessess << ", succeeded. ***" << endl;
+
+}
+


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic