/*
 *  Copyright (C) 2017 Cojen.org
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cojen.tupl.core;

import org.junit.*;
import static org.junit.Assert.*;

import org.cojen.tupl.*;

import static org.cojen.tupl.TestUtils.*;

/**
 * Tests specialized union view operations. See MergeViewTest for more tests.
 *
 * @author Brian S O'Neill
 */
public class UnionViewTest {
    public static void main(String[] args) throws Exception {
        org.junit.runner.JUnitCore.main(UnionViewTest.class.getName());
    }

    @Before
    public void createTempDb() throws Exception {
        var config = new DatabaseConfig();
        config.directPageAccess(false);
        config.maxCacheSize(100000000);
        mDb = Database.open(config);
    }

    @After
    public void teardown() throws Exception {
        mDb.close();
        mDb = null;
    }

    protected Database mDb;

    /* FIXME: remove
    @Test
    public void unlockCombine() throws Exception {
        // Stepping over entries with an updater should combine locks and then unlock them
        // together.

        final int keyCount = 10;

        var indexes = new Index[4];
        for (int i=0; i<indexes.length; i++) {
            indexes[i] = mDb.openIndex("test-" + i);
            for (int j=0; j<keyCount; j++) {
                byte[] key = ("key-" + j).getBytes();
                byte[] value = ("value-" + i).getBytes();
                indexes[i].store(null, key, value);
            }
        }

        View union;
        {
            View v1 = indexes[0].viewUnion(null, indexes[1]);
            View v2 = indexes[2].viewUnion(null, indexes[3]);
            union = v1.viewUnion(null, v2);
        }

        Transaction txn = mDb.newTransaction();

        // Null transaction means that another one should be defined internally.
        EntryUpdater up = union.newUpdater(null);

        byte[] value = "value-0".getBytes();

        int j=0;
        while (true) {
            byte[] key = ("key-" + j).getBytes();
            fastAssertArrayEquals(key, up.key());
            fastAssertArrayEquals(value, up.value());

            // Verify that lock is held by updater.
            for (int i=0; i<indexes.length; i++) {
                Index ix = indexes[i];
                assertEquals(LockResult.TIMED_OUT_LOCK, txn.tryLockUpgradable(ix.id(), key, 0));
            }

            boolean more = up.step();
            j++;

            // Verify that lock is released by updater.
            for (int i=0; i<indexes.length; i++) {
                Index ix = indexes[i];
                assertEquals(LockResult.ACQUIRED, txn.tryLockUpgradable(ix.id(), key, 0));
                txn.unlock();
            }

            if (!more) {
                break;
            }
        }

        assertEquals(keyCount, j);

        // Verify all locks are available.
        for (int i=0; i<indexes.length; i++) {
            Index ix = indexes[i];
            for (j=0; j<keyCount; j++) {
                byte[] key = ("key-" + j).getBytes();
                assertEquals(LockResult.ACQUIRED, txn.tryLockUpgradable(ix.id(), key, 0));
            }
        }

        txn.reset();
    }
    */

    @Test
    public void doubleReverseCount() throws Exception {
        Index empty = mDb.openIndex("empty");
        Index ix = mDb.openIndex("test");

        byte[] k1 = {0};
        byte[] k2 = {0, 0};
        byte[] k3 = {0, 0, 0};

        ix.store(null, k1, k1);
        ix.store(null, k2, k2);
        ix.store(null, k3, k3);

        assertEquals(2, ix.count(k1, k3));

        View view = ix.viewReverse().viewUnion(Combiner.first(), empty.viewReverse());
        view = view.viewReverse();

        assertEquals(2, view.count(k1, k3));
    }
}

@@ -1330,19 +1330,21 @@
 Size(100
+_
 000
+_
 000);%0A  
@@ -1486,24 +1486,24 @@
 ull;%0A    %7D%0A%0A
+
     protecte
@@ -1523,2310 +1523,8 @@
 b;%0A%0A
-    /* FIXME: remove%0A    @Test%0A    public void unlockCombine() throws Exception %7B%0A        // Stepping over entries with an updater should combine locks and then unlock them%0A        // together.%0A%0A        final int keyCount = 10;%0A%0A        var indexes = new Index%5B4%5D;%0A        for (int i=0; i%3Cindexes.length; i++) %7B%0A            indexes%5Bi%5D = mDb.openIndex(%22test-%22 + i);%0A            for (int j=0; j%3CkeyCount; j++) %7B%0A                byte%5B%5D key = (%22key-%22 + j).getBytes();%0A                byte%5B%5D value = (%22value-%22 + i).getBytes();%0A                indexes%5Bi%5D.store(null, key, value);%0A            %7D%0A        %7D%0A%0A        View union;%0A        %7B%0A            View v1 = indexes%5B0%5D.viewUnion(null, indexes%5B1%5D);%0A            View v2 = indexes%5B2%5D.viewUnion(null, indexes%5B3%5D);%0A            union = v1.viewUnion(null, v2);%0A        %7D%0A%0A        Transaction txn = mDb.newTransaction();%0A%0A        // Null transaction means that another one should be defined internally.%0A        EntryUpdater up = union.newUpdater(null);%0A%0A        byte%5B%5D value = %22value-0%22.getBytes();%0A%0A        int j=0;%0A        while (true) %7B%0A            byte%5B%5D key = (%22key-%22 + j).getBytes();%0A            fastAssertArrayEquals(key, up.key());%0A            fastAssertArrayEquals(value, up.value());%0A%0A            // Verify that lock is held by updater.%0A            for (int i=0; i%3Cindexes.length; i++) %7B%0A                Index ix = indexes%5Bi%5D;%0A                assertEquals(LockResult.TIMED_OUT_LOCK, txn.tryLockUpgradable(ix.id(), key, 0));%0A            %7D%0A%0A            boolean more = up.step();%0A            j++;%0A%0A            // Verify that lock is released by updater.%0A            for (int i=0; i%3Cindexes.length; i++) %7B%0A                Index ix = indexes%5Bi%5D;%0A                assertEquals(LockResult.ACQUIRED, txn.tryLockUpgradable(ix.id(), key, 0));%0A                txn.unlock();%0A            %7D%0A%0A            if (!more) %7B%0A                break;%0A            %7D%0A        %7D%0A%0A        assertEquals(keyCount, j);%0A%0A        // Verify all locks are available.%0A        for (int i=0; i%3Cindexes.length; i++) %7B%0A            Index ix = indexes%5Bi%5D;%0A            for (j=0; j%3CkeyCount; j++) %7B%0A                byte%5B%5D key = (%22key-%22 + j).getBytes();%0A                assertEquals(LockResult.ACQUIRED, txn.tryLockUpgradable(ix.id(), key, 0));%0A            %7D%0A        %7D%0A%0A        txn.reset();%0A    %7D%0A    */%0A%0A
     

Remove an obsolete test.