Back to index

lightning-sunbird  0.9+nobinonly
testXalan.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Axel Hecht.
00019  * Portions created by the Initial Developer are Copyright (C) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Axel Hecht <axel@pike.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "txStandaloneXSLTProcessor.h"
00040 #include "nsXPCOM.h"
00041 #include <fstream.h>
00042 #include "nsDoubleHashtable.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsILocalFile.h"
00045 #include "nsISimpleEnumerator.h"
00046 #include "nsString.h"
00047 #include "nsVoidArray.h"
00048 #include "prenv.h"
00049 #include "prsystem.h"
00050 #include "nsDirectoryServiceUtils.h"
00051 #include "nsDirectoryServiceDefs.h"
00052 
00053 #ifdef NS_TRACE_MALLOC
00054 #include "nsTraceMalloc.h"
00055 #endif
00056 #ifdef MOZ_JPROF
00057 #include "jprof.h"
00058 #endif
00059 
00063 void printHelp()
00064 {
00065   cerr << "testXalan [-o output-file] [category]*" << endl << endl;
00066   cerr << "Options:";
00067   cerr << endl << endl;
00068   cerr << "\t-o  specify output file (default: write to stdout)";
00069   cerr << endl << endl;
00070   cerr << "\t Specify XALAN_DIR in your environement." << endl;
00071   cerr << endl;
00072 }
00073 
00077 class txRDFOut
00078 {
00079 public:
00080     explicit txRDFOut(ostream* aOut)
00081         : mOut(aOut), mSuccess(0), mFail(0), mParent(nsnull)
00082     {
00083     }
00084     explicit txRDFOut(const nsACString& aName, txRDFOut* aParent)
00085         : mName(aName), mOut(aParent->mOut), mSuccess(0), mFail(0),
00086           mParent(aParent)
00087     {
00088     }
00089     ~txRDFOut()
00090     {
00091         *mOut << "  <RDF:Description about=\"urn:x-buster:conf" <<
00092             mName.get() <<
00093             "\">\n" <<
00094             "    <NC:orig_succCount NC:parseType=\"Integer\">" <<
00095             mSuccess <<
00096             "</NC:orig_succCount>\n" <<
00097             "    <NC:orig_failCount NC:parseType=\"Integer\">" <<
00098             mFail <<
00099             "</NC:orig_failCount>\n" <<
00100             "  </RDF:Description>" << endl;
00101     }
00102 
00103     void feed(const nsACString& aTest, PRBool aSuccess)
00104     {
00105         *mOut << "  <RDF:Description about=\"urn:x-buster:" <<
00106             PromiseFlatCString(aTest).get() <<
00107             "\"\n                   NC:orig_succ=\"";
00108         if (aSuccess) {
00109             *mOut << "yes";
00110             succeeded();
00111         }
00112         else {
00113             *mOut << "no";
00114             failed();
00115         }
00116         *mOut << "\" />\n";
00117     }
00118 
00119     void succeeded()
00120     {
00121         if (mParent)
00122             mParent->succeeded();
00123         ++mSuccess;
00124     }
00125     void failed()
00126     {
00127         if (mParent)
00128             mParent->failed();
00129         ++mFail;
00130     }
00131 private:
00132     nsCAutoString mName;
00133     ostream* mOut;
00134     PRUint32 mSuccess, mFail;
00135     txRDFOut* mParent;
00136 };
00137 
00138 static void
00139 readToString(istream& aIstream, nsACString& aString)
00140 {
00141     static char buffer[1024];
00142     int read = 0;
00143     do {
00144         aIstream.read(buffer, 1024);
00145         read = aIstream.gcount();
00146         aString.Append(Substring(buffer, buffer + read));
00147     } while (!aIstream.eof());
00148 }
00149 
00155 static nsresult
00156 setupXalan(const char* aPath, nsIFile** aConf, nsIFile** aConfGold,
00157            nsIFile** aTemp)
00158 {
00159     nsresult rv;
00160     nsCOMPtr<nsILocalFile> conf(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
00161                                                   &rv));
00162     NS_ENSURE_SUCCESS(rv, rv);
00163     nsCOMPtr <nsIFile> tmpFile;
00164     rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile));
00165     NS_ENSURE_SUCCESS(rv, rv);
00166     tmpFile->Append(NS_LITERAL_STRING("xalan.out"));
00167     rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
00168     rv = conf->InitWithNativePath(nsDependentCString(aPath));
00169     NS_ENSURE_SUCCESS(rv, rv);
00170     nsCOMPtr<nsIFile> gold;
00171     rv = conf->Clone(getter_AddRefs(gold));
00172     NS_ENSURE_SUCCESS(rv, rv);
00173     rv = conf->Append(NS_LITERAL_STRING("conf"));
00174     NS_ENSURE_SUCCESS(rv, rv);
00175     PRBool isDir;
00176     rv = conf->IsDirectory(&isDir);
00177     if (NS_FAILED(rv) || !isDir) {
00178         return NS_ERROR_FILE_NOT_DIRECTORY;
00179     }
00180     rv = gold->Append(NS_LITERAL_STRING("conf-gold"));
00181     NS_ENSURE_SUCCESS(rv, rv);
00182     rv = gold->IsDirectory(&isDir);
00183     if (NS_FAILED(rv) || !isDir || !conf || !gold) {
00184         return NS_ERROR_FILE_NOT_DIRECTORY;
00185     }
00186     // got conf and conf-gold subdirectories
00187     *aConf = conf;
00188     NS_ADDREF(*aConf);
00189     *aConfGold = gold;
00190     NS_ADDREF(*aConfGold);
00191     *aTemp = tmpFile;
00192     NS_ADDREF(*aTemp);
00193     return NS_OK;
00194 }
00195 
00199 void runCategory(nsIFile* aConfCat, nsIFile* aGoldCat, nsIFile* aRefTmp,
00200                  txRDFOut* aOut)
00201 {
00202     nsresult rv;
00203     //clone the nsIFiles, so that we can return easily
00204     nsCOMPtr<nsIFile> conf, gold;
00205     aConfCat->Clone(getter_AddRefs(conf));
00206     aGoldCat->Clone(getter_AddRefs(gold));
00207     nsCAutoString catName, refTmp;
00208     conf->GetNativeLeafName(catName);
00209     aRefTmp->GetNativePath(refTmp);
00210     txRDFOut results(catName, aOut);
00211     nsCOMPtr<nsISimpleEnumerator> tests;
00212     rv = conf->GetDirectoryEntries(getter_AddRefs(tests));
00213     if (NS_FAILED(rv))
00214         return;
00215     PRBool hasMore, isFile;
00216     nsCAutoString leaf;
00217     NS_NAMED_LITERAL_CSTRING(xsl, ".xsl");
00218     while (NS_SUCCEEDED(tests->HasMoreElements(&hasMore)) && hasMore) {
00219         nsCOMPtr<nsILocalFile> test;
00220         tests->GetNext(getter_AddRefs(test));
00221         test->GetNativeLeafName(leaf);
00222         if (xsl.Equals(Substring(leaf, leaf.Length()-4, 4))) {
00223             // we have a stylesheet, let's look for source and reference
00224             nsAFlatCString::char_iterator start, ext;
00225             leaf.BeginWriting(start);
00226             leaf.EndWriting(ext);
00227             ext -= 2;
00228             // overwrite extension with .xml
00229             *ext = 'm'; // this one was easy
00230             nsCOMPtr<nsIFile> source;
00231             conf->Clone(getter_AddRefs(source));
00232             rv = source->AppendNative(leaf);
00233             if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(source->IsFile(&isFile)) &&
00234                 isFile) {
00235                 nsCOMPtr<nsIFile> reference;
00236                 gold->Clone(getter_AddRefs(reference));
00237                 // overwrite extension with .out
00238                 --ext;
00239                 nsCharTraits<char>::copy(ext, "out", 3);
00240                 rv = reference->AppendNative(leaf);
00241                 if (NS_SUCCEEDED(rv) &&
00242                     NS_SUCCEEDED(reference->IsFile(&isFile)) &&
00243                     isFile) {
00244                     nsCAutoString src, style, refPath;
00245                     test->GetNativePath(style);
00246                     source->GetNativePath(src);
00247                     reference->GetNativePath(refPath);
00248                     if (PR_GetDirectorySeparator() =='\\') {
00249                         src.ReplaceChar('\\','/');
00250                         style.ReplaceChar('\\','/');
00251                         refPath.ReplaceChar('\\','/');
00252                     }
00253                     SimpleErrorObserver obs;
00254                     txStandaloneXSLTProcessor proc;
00255                     fstream result(refTmp.get(),
00256                                    ios::in | ios::out | ios::trunc);
00257                     rv = proc.transform(src, style, result, obs);
00258                     PRBool success = PR_FALSE;
00259                     if (NS_SUCCEEDED(rv)) {
00260                         result.flush();
00261                         PRInt64 resultSize, refSize;
00262                         aRefTmp->GetFileSize(&resultSize);
00263                         reference->GetFileSize(&refSize);
00264                         result.seekg(0);
00265                         int toread = (int)resultSize;
00266                         nsCString resContent, refContent;
00267                         resContent.SetCapacity(toread);
00268                         readToString(result, resContent);
00269                         result.close();
00270                         ifstream refStream(refPath.get());
00271                         toread = (int)refSize;
00272                         refContent.SetCapacity(toread);
00273                         readToString(refStream, refContent);
00274                         refStream.close();
00275                         success = resContent.Equals(refContent);
00276                     }
00277                     ext--;
00278                     results.feed(Substring(start, ext), success);
00279                 }
00280             }
00281         }
00282     }
00283 }
00287 int main(int argc, char** argv)
00288 {
00289 #ifdef NS_TRACE_MALLOC
00290     NS_TraceMallocStartupArgs(argc, argv);
00291 #endif
00292 #ifdef MOZ_JPROF
00293     setupProfilingStuff();
00294 #endif
00295     char* xalan = PR_GetEnv("XALAN_DIR");
00296     if (!xalan) {
00297         printHelp();
00298         return 1;
00299     }
00300     nsresult rv;
00301     rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
00302     NS_ENSURE_SUCCESS(rv, rv);
00303 
00304     nsCOMPtr<nsIFile> conf, gold, resFile;
00305     rv = setupXalan(xalan, getter_AddRefs(conf), getter_AddRefs(gold),
00306                     getter_AddRefs(resFile));
00307     if (NS_FAILED(rv)) {
00308         NS_ShutdownXPCOM(nsnull);
00309         printHelp();
00310         return -1;
00311     }
00312 
00313     //-- handle output stream
00314     ostream* resultOutput = &cout;
00315     ofstream resultFileStream;
00316 
00317     int argn = 1;
00318     // skip -- gnu style options
00319     while (argn < argc) {
00320         nsDependentCString opt(argv[argn]);
00321         if (!Substring(opt, 0, 2).EqualsLiteral("--")) {
00322             break;
00323         }
00324         ++argn;
00325     }
00326     if (argn < argc) {
00327         nsDependentCString opt(argv[argn]);
00328         if (Substring(opt, 0, 2).EqualsLiteral("-o")) {
00329             if (opt.Length() > 2) {
00330                 const nsAFlatCString& fname = 
00331                     PromiseFlatCString(Substring(opt, 2, opt.Length()-2));
00332                 resultFileStream.open(fname.get(), ios::out);
00333             }
00334             else {
00335                 ++argn;
00336                 if (argn < argc) {
00337                     resultFileStream.open(argv[argn], ios::out);
00338                 }
00339             }
00340             if (!resultFileStream) {
00341                 cerr << "error opening output file" << endl;
00342                 PRBool exists;
00343                 if (NS_SUCCEEDED(resFile->Exists(&exists)) && exists)
00344                     resFile->Remove(PR_FALSE);
00345                 NS_ShutdownXPCOM(nsnull);
00346                 return -1;
00347             }
00348             ++argn;
00349             resultOutput = &resultFileStream;
00350         }
00351     }
00352 
00353     if (!txXSLTProcessor::init()) {
00354         PRBool exists;
00355         if (NS_SUCCEEDED(resFile->Exists(&exists)) && exists)
00356             resFile->Remove(PR_FALSE);
00357         NS_ShutdownXPCOM(nsnull);
00358         return 1;
00359     }
00360 
00361     *resultOutput << "<?xml version=\"1.0\"?>\n" << 
00362         "<RDF:RDF xmlns:NC=\"http://home.netscape.com/NC-rdf#\"\n" <<
00363         "         xmlns:RDF=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">" << endl;
00364 
00365     txRDFOut* rdfOut = new txRDFOut(resultOutput);
00366     nsCOMPtr<nsIFile> tempFile;
00367     if (argn < argc) {
00368         // categories are specified
00369         while (argn < argc) {
00370             nsDependentCString cat(argv[argn++]);
00371             rv = conf->AppendNative(cat);
00372             if (NS_SUCCEEDED(rv)) {
00373                 rv = gold->AppendNative(cat);
00374                 if (NS_SUCCEEDED(rv)) {
00375                     runCategory(conf, gold, resFile, rdfOut);
00376                     rv = gold->GetParent(getter_AddRefs(tempFile));
00377                     NS_ASSERTION(NS_SUCCEEDED(rv), "can't go back?");
00378                     gold = tempFile;
00379                 }
00380                 rv = conf->GetParent(getter_AddRefs(tempFile));
00381                 NS_ASSERTION(NS_SUCCEEDED(rv), "can't go back?");
00382                 conf = tempFile;
00383             }
00384         }
00385     }
00386     else {
00387         // no category specified, do everything
00388         nsCOMPtr<nsISimpleEnumerator> cats;
00389         rv = conf->GetDirectoryEntries(getter_AddRefs(cats));
00390         PRBool hasMore, isDir;
00391         nsCAutoString leaf;
00392         while (NS_SUCCEEDED(cats->HasMoreElements(&hasMore)) && hasMore) {
00393             nsCOMPtr<nsILocalFile> cat;
00394             cats->GetNext(getter_AddRefs(cat));
00395             rv = cat->IsDirectory(&isDir);
00396             if (NS_SUCCEEDED(rv) && isDir) {
00397                 rv = cat->GetNativeLeafName(leaf);
00398                 if (NS_SUCCEEDED(rv) && 
00399                     !leaf.EqualsLiteral("CVS")) {
00400                     rv = gold->AppendNative(leaf);
00401                     if (NS_SUCCEEDED(rv)) {
00402                         runCategory(cat, gold, resFile, rdfOut);
00403                         rv = gold->GetParent(getter_AddRefs(tempFile));
00404                         gold = tempFile;
00405                     }
00406                 }
00407             }
00408         }
00409     }
00410     delete rdfOut;
00411     rdfOut = nsnull;
00412     *resultOutput << "</RDF:RDF>" << endl;
00413     PRBool exists;
00414     if (NS_SUCCEEDED(resFile->Exists(&exists)) && exists)
00415         resFile->Remove(PR_FALSE);
00416     resultFileStream.close();
00417     txXSLTProcessor::shutdown();
00418     rv = NS_ShutdownXPCOM(nsnull);
00419 #ifdef NS_TRACE_MALLOC
00420     NS_TraceMallocShutdown();
00421 #endif
00422     NS_ENSURE_SUCCESS(rv, rv);
00423     return 0;
00424 }