1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkData.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkOSFile.h"
10dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org#include "SkRandom.h"
11dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org#include "SkStream.h"
1229d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com#include "Test.h"
13dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SK_BUILD_FOR_WIN
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <unistd.h>
1629d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com#include <fcntl.h>
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_SIZE    (256 * 1024)
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
22a936e37cc76614868f5b489395bceeb340cc04cdcommit-bot@chromium.org                             const void* src, size_t len, int repeat) {
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkAutoSMalloc<256> storage(len);
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void* tmp = storage.get();
25d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < repeat; ++i) {
27a936e37cc76614868f5b489395bceeb340cc04cdcommit-bot@chromium.org        size_t bytes = stream->read(tmp, len);
28a936e37cc76614868f5b489395bceeb340cc04cdcommit-bot@chromium.org        REPORTER_ASSERT(reporter, bytes == len);
29a936e37cc76614868f5b489395bceeb340cc04cdcommit-bot@chromium.org        REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
30a936e37cc76614868f5b489395bceeb340cc04cdcommit-bot@chromium.org    }
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // expect EOF
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t bytes = stream->read(tmp, 1);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    REPORTER_ASSERT(reporter, 0 == bytes);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // isAtEnd might not return true until after the first failing read.
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    REPORTER_ASSERT(reporter, stream->isAtEnd());
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
4029d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    SkString path = SkOSPath::Join(tmpDir, "wstream_test");
4129d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com
4229d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    const char s[] = "abcdefghijklmnopqrstuvwxyz";
4329d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com
4429d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    {
4529d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        SkFILEWStream writer(path.c_str());
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!writer.isValid()) {
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int i = 0; i < 100; ++i) {
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            writer.write(s, 26);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFILEStream stream(path.c_str());
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, stream.isValid());
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, &stream, s, 26, 100);
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
61d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, stream2.get(), s, 26, 100);
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        FILE* file = ::fopen(path.c_str(), "rb");
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership);
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, stream.isValid());
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, &stream, s, 26, 100);
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, stream2.get(), s, 26, 100);
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void TestWStream(skiatest::Reporter* reporter) {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDynamicMemoryWStream  ds;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char s[] = "abcdefghijklmnopqrstuvwxyz";
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int i;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (i = 0; i < 100; i++) {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, ds.write(s, 26));
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char* dst = new char[100 * 26 + 1];
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst[100*26] = '*';
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ds.copyTo(dst);
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    REPORTER_ASSERT(reporter, dst[100*26] == '*');
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (i = 0; i < 100; i++) {
90d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream());
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, ds.getOffset() == 0);
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, stream.get(), s, 26, 100);
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate());
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, stream2.get(), s, 26, 100);
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkStreamAsset> stream3(stream->fork());
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, stream3->isAtEnd());
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        char tmp;
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        size_t bytes = stream->read(&tmp, 1);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, 0 == bytes);
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        stream3->rewind();
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_loop_stream(reporter, stream3.get(), s, 26, 100);
109bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com    }
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
111bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com    for (i = 0; i < 100; i++) {
112bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com        REPORTER_ASSERT(reporter, ds.write(s, 26));
113bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com    }
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkData> data(ds.copyToData());
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, 100 * 26 == data->size());
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
12357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com        // Test that this works after a copyToData.
12457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com        SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream());
12557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com        REPORTER_ASSERT(reporter, ds.getOffset() == 0);
12657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com        test_loop_stream(reporter, stream.get(), s, 26, 100);
12757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate());
129bc7d2fb5be746f6e0d9bd60c9e181eec20fe31eareed@android.com        test_loop_stream(reporter, stream2.get(), s, 26, 100);
130bc7d2fb5be746f6e0d9bd60c9e181eec20fe31eareed@android.com    }
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    delete[] dst;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkString tmpDir = skiatest::Test::GetTmpDir();
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!tmpDir.isEmpty()) {
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        test_filestreams(reporter, tmpDir.c_str());
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void TestPackedUInt(skiatest::Reporter* reporter) {
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // so we test values around each of those transitions (and a few others)
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const size_t sizes[] = {
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t i;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char buffer[sizeof(sizes) * 4];
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMemoryWStream wstream(buffer, sizeof(buffer));
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
15529d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        bool success = wstream.writePackedUInt(sizes[i]);
15629d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        REPORTER_ASSERT(reporter, success);
15729d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    }
15829d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    wstream.flush();
15929d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com
16029d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    SkMemoryStream rstream(buffer, sizeof(buffer));
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        size_t n = rstream.readPackedUInt();
16329d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        if (sizes[i] != n) {
16429d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com            SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n);
16529d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        }
16629d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com        REPORTER_ASSERT(reporter, sizes[i] == n);
16729d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com    }
16829d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com}
16929d4e638641d6d089a0361619ff2a583fd1a827fhalcanary@google.com
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Test that setting an SkMemoryStream to a NULL data does not result in a crash when calling
171dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org// methods that access fData.
172dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.orgstatic void TestDereferencingData(SkMemoryStream* memStream) {
173dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    memStream->read(NULL, 0);
174dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    memStream->getMemoryBase();
175dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    SkAutoDataUnref data(memStream->copyToData());
176dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org}
177dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org
178dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.orgstatic void TestNullData() {
179dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    SkData* nullData = NULL;
180dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    SkMemoryStream memStream(nullData);
181dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    TestDereferencingData(&memStream);
182dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org
183dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    memStream.setData(nullData);
184dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org    TestDereferencingData(&memStream);
185dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org
186dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org}
187dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org
1883a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.comDEF_TEST(Stream, reporter) {
1893a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.com    TestWStream(reporter);
1903a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.com    TestPackedUInt(reporter);
1913a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.com    TestNullData();
1923a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.com}
1933a8ebd9e71dab5c6640c40b8576dbe0d901c261bhalcanary@google.com