chromium/chrome/android/javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.tab;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.StreamUtil;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.chrome.browser.tabmodel.TestTabModelDirectory;
import org.chromium.chrome.browser.tabpersistence.TabStateFileManager;
import org.chromium.content_public.browser.test.NativeLibraryTestUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

/** Tests whether TabState can be restored from disk properly. */
@RunWith(BaseJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
public class WebContentsStateBridgeTest {
    private TestTabModelDirectory mTestTabModelDirectory;

    @Before
    public void setUp() {
        NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
        mTestTabModelDirectory =
                new TestTabModelDirectory(
                        ApplicationProvider.getApplicationContext(),
                        "WebContentsStateBridgeTest",
                        null);
    }

    @After
    public void tearDown() {
        mTestTabModelDirectory.tearDown();
    }

    private static void writeFile(File directory, String filename, byte[] data) throws Exception {
        File file = new File(directory, filename);
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            outputStream.write(data);
        } catch (FileNotFoundException e) {
            assert false : "Failed to create " + filename;
        } finally {
            StreamUtil.closeQuietly(outputStream);
        }
    }

    /** Tests that Chrome doesn't crash parsing a corrupted tab state. crbug/1094239 */
    @Test
    @SmallTest
    public void testLoadCorruptedTabState() throws Exception {
        writeFile(
                mTestTabModelDirectory.getBaseDirectory(),
                "tab0",
                new byte[] {
                    0, 0, 0, 0, 0, 0, 0, 0, // encryption key
                    0, 0, 0, 0, 0, 0, 0, 0, // timestamp
                    0, 0, 0, 0, // length is 0 - (i.e. map 0-length content state)
                    'g', 'a', 'r', 'b', 'a', 'g', 'e'
                });

        File tabStateFile = new File(mTestTabModelDirectory.getBaseDirectory(), "tab0");
        TabState tabState = TabStateFileManager.restoreTabStateInternal(tabStateFile, false);
        // Garbage-in, garbage out. Client code must be tolerant to null TabState
        Assert.assertNotNull(tabState);
        Assert.assertNotNull(tabState.contentsState);
        Assert.assertNotNull(tabState.contentsState.buffer());

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    // Return a null contents state but don't crash.
                    Assert.assertNull(
                            WebContentsStateBridge.restoreContentsFromByteBuffer(
                                    tabState.contentsState, false));
                });
    }
}