michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIServiceManager.h" michael@0: #include "nsICharsetConverterManager.h" michael@0: #include "nsUCSupport.h" michael@0: #include "nsString.h" michael@0: #include "nsIStringEnumerator.h" michael@0: #include "nsTArray.h" michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Global functions and data [declaration] michael@0: michael@0: #define ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0])) michael@0: #define SMALL_BUFFER_SIZE 512 michael@0: #define MED_BUFFER_SIZE 1024 michael@0: #define BIG_BUFFER_SIZE 2048 michael@0: michael@0: static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Class nsTestLog [declaration] michael@0: michael@0: /** michael@0: * A Logging class for test programs. michael@0: * michael@0: * This simple test program will not trigger a component registration. So michael@0: * Mozilla has to be run once before running this, so that the necessary michael@0: * components will be registered. Also, please observe that the ContractID's are michael@0: * case sensitive now! michael@0: * michael@0: * @created 28/Mar/2000 michael@0: * @author Catalin Rotaru [CATA] michael@0: */ michael@0: class nsTestLog michael@0: { michael@0: private: michael@0: michael@0: static const char * kTraceDelimiter; michael@0: michael@0: nsAutoCString mTrace; michael@0: michael@0: public: michael@0: michael@0: void AddTrace(const char * aTrace); michael@0: void DelTrace(const char * aTrace); michael@0: void PrintError(const char * aCall, const int aError); michael@0: void PrintError(const char * aCall, const char * aMessage); michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Class nsTestUConv [declaration] michael@0: michael@0: /** michael@0: * The main class of the program. michael@0: * michael@0: * XXX Create a very general set of "bug and regression" test cases and the michael@0: * one in TestTempBug() michael@0: * XXX Apply the new argument style (pointers) to the converters interfaces michael@0: * michael@0: * @created 28/Mar/2000 michael@0: * @author Catalin Rotaru [CATA] michael@0: */ michael@0: class nsTestUConv michael@0: { michael@0: private: michael@0: michael@0: nsTestLog mLog; michael@0: michael@0: /** michael@0: * Run the built-in set of self tests for encoders. michael@0: */ michael@0: nsresult TestEncoders(); michael@0: michael@0: /** michael@0: * Run the built-in set of self tests for decoders. michael@0: */ michael@0: nsresult TestDecoders(); michael@0: michael@0: /** michael@0: * Run the built-in set of self tests for the CharsetManager. michael@0: */ michael@0: nsresult TestCharsetManager(); michael@0: michael@0: /** michael@0: * Display charset detectors and their attributes. michael@0: */ michael@0: nsresult DisplayDetectors(); michael@0: michael@0: /** michael@0: * Display charsets and their attributes. michael@0: */ michael@0: nsresult DisplayCharsets(); michael@0: michael@0: /** michael@0: * Run a temporary debug test. This method is ment as a placeholder when some michael@0: * quick debugging is needed. michael@0: */ michael@0: nsresult TestTempBug(); michael@0: michael@0: nsresult Encode(char16_t ** aSrc, char16_t * aSrcEnd, char ** aDest, michael@0: char * aDestEnd, const nsAFlatCString& aCharset); michael@0: michael@0: /** michael@0: * Bridge methods between the new argument style (poiters) and the old one michael@0: * (lengths). To be removed when the converter interfaces will switch to the michael@0: * new style. michael@0: * michael@0: * This wraps an encoder Convert() call. michael@0: */ michael@0: nsresult ConvertEncode(char16_t ** aSrc, char16_t * aSrcEnd, char ** aDest, michael@0: char * aDestEnd, nsIUnicodeEncoder * aEncoder); michael@0: michael@0: /** michael@0: * This wraps an encoder Finish() call. michael@0: */ michael@0: nsresult FinishEncode(char ** aDest, char * aDestEnd, michael@0: nsIUnicodeEncoder * aEncoder); michael@0: michael@0: void PrintSpaces(int aCount); michael@0: michael@0: public: michael@0: michael@0: /** michael@0: * Main method of the program. michael@0: */ michael@0: nsresult Main(int aArgC, char ** aArgV); michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Global functions and data [implementation] michael@0: michael@0: int main(int argc, char ** argv) michael@0: { michael@0: nsTestUConv testObj; michael@0: nsresult res; michael@0: michael@0: res = testObj.Main(argc, argv); michael@0: return (NS_FAILED(res)); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Class nsTestLog [implementation] michael@0: michael@0: const char * nsTestLog::kTraceDelimiter = "."; michael@0: michael@0: void nsTestLog::AddTrace(const char * aTrace) michael@0: { michael@0: mTrace.Append(aTrace); michael@0: mTrace.Append(kTraceDelimiter); michael@0: } michael@0: michael@0: void nsTestLog::DelTrace(const char * aTrace) michael@0: { michael@0: mTrace.Truncate(mTrace.Length() - strlen(aTrace) - strlen(kTraceDelimiter)); michael@0: } michael@0: michael@0: void nsTestLog::PrintError(const char * aCall, const int aError) michael@0: { michael@0: const char * trace = mTrace.get(); michael@0: printf("ERROR at %s%s code=0x%x.\n", trace, aCall, aError); michael@0: } michael@0: michael@0: void nsTestLog::PrintError(const char * aCall, const char * aMessage) michael@0: { michael@0: const char * trace = mTrace.get(); michael@0: printf("ERROR at %s%s reason: %s.\n", trace, aCall, aMessage); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------- michael@0: // Class nsTestUConv [implementation] michael@0: michael@0: nsresult nsTestUConv::TestEncoders() michael@0: { michael@0: const char * trace = "TestEncoders"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: nsCOMPtr ccMan = michael@0: do_GetService(kCharsetConverterManagerCID, &res); michael@0: if (NS_FAILED(res)) return res; michael@0: michael@0: nsCOMPtr encoders; michael@0: res = ccMan->GetEncoderList(getter_AddRefs(encoders)); michael@0: if (NS_FAILED(res)) return res; michael@0: michael@0: bool hasMore; michael@0: encoders->HasMore(&hasMore); michael@0: michael@0: nsAutoCString charset; michael@0: while (hasMore) { michael@0: encoders->GetNext(charset); michael@0: michael@0: encoders->HasMore(&hasMore); michael@0: } michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::TestDecoders() michael@0: { michael@0: const char * trace = "TestDecoders"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: // XXX write me michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::TestCharsetManager() michael@0: { michael@0: const char * trace = "TestCharsetManager"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: nsAutoString name; michael@0: nsCOMPtr csAtom; michael@0: michael@0: nsCOMPtr ccMan = michael@0: do_GetService(kCharsetConverterManagerCID, &res); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("NS_WITH_SERVICE", res); michael@0: return res; michael@0: } michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::DisplayDetectors() michael@0: { michael@0: const char * trace = "DisplayDetectors"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: nsCOMPtr ccMan = michael@0: do_GetService(kCharsetConverterManagerCID, &res); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("NS_WITH_SERVICE", res); michael@0: return res; michael@0: } michael@0: michael@0: // charset detectors michael@0: nsCOMPtr detectors; michael@0: michael@0: res = ccMan->GetCharsetDetectorList(getter_AddRefs(detectors)); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("GetCharsetDetectorList()", res); michael@0: return res; michael@0: } michael@0: michael@0: printf("***** Character Set Detectors *****\n"); michael@0: michael@0: bool hasMore; michael@0: detectors->HasMore(&hasMore); michael@0: while (hasMore) { michael@0: nsAutoCString detectorName; michael@0: res = detectors->GetNext(detectorName); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("GetNext()", res); michael@0: return res; michael@0: } michael@0: michael@0: printf("%s", detectorName.get()); michael@0: PrintSpaces(36 - detectorName.Length()); // align to hard coded column number michael@0: michael@0: nsAutoString title; michael@0: res = ccMan->GetCharsetTitle(detectorName.get(), title); michael@0: if (NS_FAILED(res)) title.SetLength(0); michael@0: printf("\"%s\"\n", NS_LossyConvertUTF16toASCII(title).get()); michael@0: michael@0: detectors->HasMore(&hasMore); michael@0: } michael@0: michael@0: mLog.DelTrace(trace); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsTestUConv::DisplayCharsets() michael@0: { michael@0: const char * trace = "DisplayCharsets"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: nsCOMPtr ccMan = michael@0: do_GetService(kCharsetConverterManagerCID, &res); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("NS_WITH_SERVICE", res); michael@0: return res; michael@0: } michael@0: michael@0: nsCOMPtr decoders; michael@0: nsCOMPtr encoders; michael@0: michael@0: res = ccMan->GetDecoderList(getter_AddRefs(decoders)); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("GetDecoderList()", res); michael@0: return res; michael@0: } michael@0: michael@0: res = ccMan->GetEncoderList(getter_AddRefs(encoders)); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("GetEncoderList()", res); michael@0: return res; michael@0: } michael@0: michael@0: michael@0: printf("***** Character Sets *****\n"); michael@0: michael@0: uint32_t encCount = 0, decCount = 0; michael@0: uint32_t basicEncCount = 0, basicDecCount = 0; michael@0: michael@0: nsTArray allCharsets; michael@0: michael@0: nsAutoCString charset; michael@0: bool hasMore; michael@0: encoders->HasMore(&hasMore); michael@0: while (hasMore) { michael@0: res = encoders->GetNext(charset); michael@0: if (NS_SUCCEEDED(res)) michael@0: allCharsets.AppendElement(charset); michael@0: michael@0: encoders->HasMore(&hasMore); michael@0: } michael@0: michael@0: nsAutoString prop, str; michael@0: uint32_t count = allCharsets.Length(); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: michael@0: const nsCString& charset = allCharsets[i]; michael@0: printf("%s", charset.get()); michael@0: PrintSpaces(24 - charset.Length()); // align to hard coded column number michael@0: michael@0: michael@0: nsCOMPtr dec; michael@0: res = ccMan->GetUnicodeDecoder(charset.get(), getter_AddRefs(dec)); michael@0: if (NS_FAILED(res)) printf (" "); michael@0: else { michael@0: printf("D"); michael@0: decCount++; michael@0: } michael@0: #ifdef DEBUG michael@0: // show the "basic" decoder classes michael@0: if (dec) { michael@0: nsCOMPtr isBasic = do_QueryInterface(dec); michael@0: if (isBasic) { michael@0: basicDecCount++; michael@0: printf("b"); michael@0: } michael@0: else printf(" "); michael@0: } michael@0: else printf(" "); michael@0: #endif michael@0: michael@0: nsCOMPtr enc; michael@0: res = ccMan->GetUnicodeEncoder(charset.get(), getter_AddRefs(enc)); michael@0: if (NS_FAILED(res)) printf (" "); michael@0: else { michael@0: printf("E"); michael@0: encCount++; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: if (enc) { michael@0: nsCOMPtr isBasic = do_QueryInterface(enc); michael@0: if (isBasic) { michael@0: basicEncCount++; michael@0: printf("b"); michael@0: } michael@0: else printf(" "); michael@0: } michael@0: else printf(" "); michael@0: #endif michael@0: michael@0: printf(" "); michael@0: michael@0: prop.AssignLiteral(".notForBrowser"); michael@0: res = ccMan->GetCharsetData(charset.get(), prop.get(), str); michael@0: if (dec && (NS_FAILED(res))) printf ("B"); michael@0: else printf("X"); michael@0: michael@0: prop.AssignLiteral(".notForComposer"); michael@0: res = ccMan->GetCharsetData(charset.get(), prop.get(), str); michael@0: if (enc && (NS_FAILED(res))) printf ("C"); michael@0: else printf("X"); michael@0: michael@0: prop.AssignLiteral(".notForMailView"); michael@0: res = ccMan->GetCharsetData(charset.get(), prop.get(), str); michael@0: if (dec && (NS_FAILED(res))) printf ("V"); michael@0: else printf("X"); michael@0: michael@0: prop.AssignLiteral(".notForMailEdit"); michael@0: res = ccMan->GetCharsetData(charset.get(), prop.get(), str); michael@0: if (enc && (NS_FAILED(res))) printf ("E"); michael@0: else printf("X"); michael@0: michael@0: printf("(%3d, %3d) ", encCount, decCount); michael@0: res = ccMan->GetCharsetTitle(charset.get(), str); michael@0: if (NS_FAILED(res)) str.SetLength(0); michael@0: NS_LossyConvertUTF16toASCII buff2(str); michael@0: printf(" \"%s\"\n", buff2.get()); michael@0: } michael@0: michael@0: printf("%u of %u decoders are basic (%d%%)\n", michael@0: basicDecCount, decCount, (basicDecCount * 100) / decCount); michael@0: michael@0: printf("%u of %u encoders are basic (%d%%)\n", michael@0: basicEncCount, encCount, (basicEncCount * 100) / encCount); michael@0: mLog.DelTrace(trace); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsTestUConv::TestTempBug() michael@0: { michael@0: const char * trace = "TestTempBug"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: NS_NAMED_LITERAL_CSTRING(charset, "ISO-2022-JP"); michael@0: char16_t src[] = {0x0043, 0x004e, 0x0045, 0x0054, 0x0020, 0x004A, 0x0061, michael@0: 0x0070, 0x0061, 0x006E, 0x0020, 0x7DE8, 0x96C6, 0x5C40}; michael@0: char16_t * srcEnd = src + ARRAY_SIZE(src); michael@0: char dest[BIG_BUFFER_SIZE]; michael@0: char * destEnd = dest + BIG_BUFFER_SIZE; michael@0: michael@0: char16_t * p = src; michael@0: char * q = dest; michael@0: res = Encode(&p, srcEnd, &q, destEnd, charset); michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::Encode(char16_t ** aSrc, char16_t * aSrcEnd, michael@0: char ** aDest, char * aDestEnd, michael@0: const nsAFlatCString& aCharset) michael@0: { michael@0: const char * trace = "Encode"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: nsCOMPtr ccMan = michael@0: do_GetService(kCharsetConverterManagerCID, &res); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("NS_WITH_SERVICE", res); michael@0: return res; michael@0: } michael@0: michael@0: nsCOMPtr enc; michael@0: res = ccMan->GetUnicodeEncoder(aCharset.get(), getter_AddRefs(enc)); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("GetUnicodeEncoder()", res); michael@0: return res; michael@0: } michael@0: michael@0: res = ConvertEncode(aSrc, aSrcEnd, aDest, aDestEnd, enc); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("Convert()", res); michael@0: return res; michael@0: } michael@0: michael@0: res = FinishEncode(aDest, aDestEnd, enc); michael@0: if (NS_FAILED(res)) { michael@0: mLog.PrintError("Finish()", res); michael@0: return res; michael@0: } michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::ConvertEncode(char16_t ** aSrc, char16_t * aSrcEnd, michael@0: char ** aDest, char * aDestEnd, michael@0: nsIUnicodeEncoder * aEncoder) michael@0: { michael@0: char16_t * src = (*aSrc); michael@0: char * dest = (*aDest); michael@0: int32_t srcLen = aSrcEnd - src; michael@0: int32_t destLen = aDestEnd - dest; michael@0: michael@0: nsresult res = aEncoder->Convert(src, &srcLen, dest, &destLen); michael@0: michael@0: (*aSrc) = src + srcLen; michael@0: (*aDest) = dest + destLen; michael@0: return res; michael@0: } michael@0: michael@0: nsresult nsTestUConv::FinishEncode(char ** aDest, char * aDestEnd, michael@0: nsIUnicodeEncoder * aEncoder) michael@0: { michael@0: char * dest = (*aDest); michael@0: int32_t destLen = aDestEnd - dest; michael@0: michael@0: nsresult res = aEncoder->Finish(dest, &destLen); michael@0: michael@0: (*aDest) = dest + destLen; michael@0: return res; michael@0: } michael@0: michael@0: void nsTestUConv::PrintSpaces(int aCount) michael@0: { michael@0: for (int i = 0; i < aCount; i++) printf(" "); michael@0: } michael@0: michael@0: nsresult nsTestUConv::Main(int aArgC, char ** aArgV) michael@0: { michael@0: const char * trace = "Main"; michael@0: mLog.AddTrace(trace); michael@0: nsresult res = NS_OK; michael@0: michael@0: if (aArgC < 2) { michael@0: // no arguments were passed to the program, so we just run the self tests michael@0: res = TestCharsetManager(); michael@0: if (NS_SUCCEEDED(res)) res = TestEncoders(); michael@0: if (NS_SUCCEEDED(res)) res = TestDecoders(); michael@0: } else if (!strcmp(aArgV[1], "-tempbug")) { michael@0: // we are testing a temporary bug michael@0: res = TestTempBug(); michael@0: } else if (!strcmp(aArgV[1], "-display")) { michael@0: // display all the available data michael@0: res = DisplayDetectors(); michael@0: if (NS_SUCCEEDED(res)) res = DisplayCharsets(); michael@0: } michael@0: michael@0: mLog.DelTrace(trace); michael@0: return res; michael@0: }