michael@0: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 "TestHarness.h" michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIScriptableBase64Encoder.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsStringAPI.h" michael@0: #include michael@0: michael@0: struct Chunk { michael@0: Chunk(uint32_t l, const char* c) michael@0: : mLength(l), mData(c) michael@0: {} michael@0: michael@0: uint32_t mLength; michael@0: const char* mData; michael@0: }; michael@0: michael@0: struct Test { michael@0: Test(Chunk* c, const char* r) michael@0: : mChunks(c), mResult(r) michael@0: {} michael@0: michael@0: Chunk* mChunks; michael@0: const char* mResult; michael@0: }; michael@0: michael@0: static Chunk kTest1Chunks[] = michael@0: { michael@0: Chunk(9, "Hello sir"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest2Chunks[] = michael@0: { michael@0: Chunk(3, "Hel"), michael@0: Chunk(3, "lo "), michael@0: Chunk(3, "sir"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest3Chunks[] = michael@0: { michael@0: Chunk(1, "I"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest4Chunks[] = michael@0: { michael@0: Chunk(2, "Hi"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest5Chunks[] = michael@0: { michael@0: Chunk(1, "B"), michael@0: Chunk(2, "ob"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest6Chunks[] = michael@0: { michael@0: Chunk(2, "Bo"), michael@0: Chunk(1, "b"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest7Chunks[] = michael@0: { michael@0: Chunk(1, "F"), // Carry over 1 michael@0: Chunk(4, "iref"), // Carry over 2 michael@0: Chunk(2, "ox"), // 1 michael@0: Chunk(4, " is "), // 2 michael@0: Chunk(2, "aw"), // 1 michael@0: Chunk(4, "esom"), // 2 michael@0: Chunk(2, "e!"), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Chunk kTest8Chunks[] = michael@0: { michael@0: Chunk(5, "ALL T"), michael@0: Chunk(1, "H"), michael@0: Chunk(4, "ESE "), michael@0: Chunk(2, "WO"), michael@0: Chunk(21, "RLDS ARE YOURS EXCEPT"), michael@0: Chunk(9, " EUROPA. "), michael@0: Chunk(25, "ATTEMPT NO LANDING THERE."), michael@0: Chunk(0, nullptr) michael@0: }; michael@0: michael@0: static Test kTests[] = michael@0: { michael@0: // Test 1, test a simple round string in one chunk michael@0: Test( michael@0: kTest1Chunks, michael@0: "SGVsbG8gc2ly" michael@0: ), michael@0: // Test 2, test a simple round string split into round chunks michael@0: Test( michael@0: kTest2Chunks, michael@0: "SGVsbG8gc2ly" michael@0: ), michael@0: // Test 3, test a single chunk that's 2 short michael@0: Test( michael@0: kTest3Chunks, michael@0: "SQ==" michael@0: ), michael@0: // Test 4, test a single chunk that's 1 short michael@0: Test( michael@0: kTest4Chunks, michael@0: "SGk=" michael@0: ), michael@0: // Test 5, test a single chunk that's 2 short, followed by a chunk of 2 michael@0: Test( michael@0: kTest5Chunks, michael@0: "Qm9i" michael@0: ), michael@0: // Test 6, test a single chunk that's 1 short, followed by a chunk of 1 michael@0: Test( michael@0: kTest6Chunks, michael@0: "Qm9i" michael@0: ), michael@0: // Test 7, test alternating carryovers michael@0: Test( michael@0: kTest7Chunks, michael@0: "RmlyZWZveCBpcyBhd2Vzb21lIQ==" michael@0: ), michael@0: // Test 8, test a longish string michael@0: Test( michael@0: kTest8Chunks, michael@0: "QUxMIFRIRVNFIFdPUkxEUyBBUkUgWU9VUlMgRVhDRVBUIEVVUk9QQS4gQVRURU1QVCBOTyBMQU5ESU5HIFRIRVJFLg==" michael@0: ), michael@0: // Terminator michael@0: Test( michael@0: nullptr, michael@0: nullptr michael@0: ) michael@0: }; michael@0: michael@0: class FakeInputStream MOZ_FINAL : public nsIInputStream michael@0: { michael@0: public: michael@0: michael@0: FakeInputStream() michael@0: : mTestNumber(0), michael@0: mTest(&kTests[0]), michael@0: mChunk(&mTest->mChunks[0]), michael@0: mClosed(false) michael@0: {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIINPUTSTREAM michael@0: michael@0: void Reset(); michael@0: bool NextTest(); michael@0: bool CheckTest(nsACString& aResult); michael@0: bool CheckTest(nsAString& aResult); michael@0: private: michael@0: uint32_t mTestNumber; michael@0: const Test* mTest; michael@0: const Chunk* mChunk; michael@0: bool mClosed; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(FakeInputStream, nsIInputStream) michael@0: michael@0: NS_IMETHODIMP michael@0: FakeInputStream::Close() michael@0: { michael@0: mClosed = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FakeInputStream::Available(uint64_t* aAvailable) michael@0: { michael@0: *aAvailable = 0; michael@0: michael@0: if (mClosed) michael@0: return NS_BASE_STREAM_CLOSED; michael@0: michael@0: const Chunk* chunk = mChunk; michael@0: while (chunk->mLength) { michael@0: *aAvailable += chunk->mLength; michael@0: chunk++; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FakeInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aOut) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FakeInputStream::ReadSegments(nsWriteSegmentFun aWriter, michael@0: void* aClosure, michael@0: uint32_t aCount, michael@0: uint32_t* aRead) michael@0: { michael@0: *aRead = 0; michael@0: michael@0: if (mClosed) michael@0: return NS_BASE_STREAM_CLOSED; michael@0: michael@0: while (mChunk->mLength) { michael@0: uint32_t written = 0; michael@0: michael@0: nsresult rv = (*aWriter)(this, aClosure, mChunk->mData, michael@0: *aRead, mChunk->mLength, &written); michael@0: michael@0: *aRead += written; michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mChunk++; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FakeInputStream::IsNonBlocking(bool* aIsBlocking) michael@0: { michael@0: *aIsBlocking = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: FakeInputStream::Reset() michael@0: { michael@0: mClosed = false; michael@0: mChunk = &mTest->mChunks[0]; michael@0: } michael@0: michael@0: bool michael@0: FakeInputStream::NextTest() michael@0: { michael@0: mTestNumber++; michael@0: mTest = &kTests[mTestNumber]; michael@0: mChunk = &mTest->mChunks[0]; michael@0: mClosed = false; michael@0: michael@0: return mTest->mChunks ? true : false; michael@0: } michael@0: michael@0: bool michael@0: FakeInputStream::CheckTest(nsACString& aResult) michael@0: { michael@0: return !strcmp(aResult.BeginReading(), mTest->mResult) ? true : false; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: static inline int NS_tstrcmp(char16ptr_t x, char16ptr_t y) { michael@0: return wcscmp(x, y); michael@0: } michael@0: #else michael@0: #define NS_tstrcmp strcmp michael@0: #endif michael@0: michael@0: bool michael@0: FakeInputStream::CheckTest(nsAString& aResult) michael@0: { michael@0: return !NS_tstrcmp(aResult.BeginReading(), michael@0: NS_ConvertASCIItoUTF16(mTest->mResult).BeginReading()) michael@0: ? true : false; michael@0: } michael@0: michael@0: int main(int argc, char** argv) michael@0: { michael@0: ScopedXPCOM xpcom("Base64"); michael@0: NS_ENSURE_FALSE(xpcom.failed(), 1); michael@0: michael@0: nsCOMPtr encoder = michael@0: do_CreateInstance("@mozilla.org/scriptablebase64encoder;1"); michael@0: NS_ENSURE_TRUE(encoder, 1); michael@0: michael@0: nsRefPtr stream = new FakeInputStream(); michael@0: do { michael@0: nsString wideString; michael@0: nsCString string; michael@0: michael@0: nsresult rv; michael@0: rv = encoder->EncodeToString(stream, 0, wideString); michael@0: NS_ENSURE_SUCCESS(rv, 1); michael@0: michael@0: stream->Reset(); michael@0: michael@0: rv = encoder->EncodeToCString(stream, 0, string); michael@0: NS_ENSURE_SUCCESS(rv, 1); michael@0: michael@0: if (!stream->CheckTest(wideString) || !stream->CheckTest(string)) michael@0: fail("Failed to convert properly\n"); michael@0: michael@0: } while (stream->NextTest()); michael@0: michael@0: return 0; michael@0: }