14b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar/*
24b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Copyright (C) 2014 The Android Open Source Project
34b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
44b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
54b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * you may not use this file except in compliance with the License.
64b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * You may obtain a copy of the License at
74b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
84b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
94b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Unless required by applicable law or agreed to in writing, software
114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * See the License for the specific language governing permissions and
144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * limitations under the License.
154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar */
164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarpackage android.support.v7.widget;
184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
19be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Before;
20be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Test;
21be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runner.RunWith;
22be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runners.JUnit4;
234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.ArrayList;
254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.HashSet;
264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.List;
274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.Random;
284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.Set;
294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport android.support.v7.widget.AdapterHelper.UpdateOp;
31f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.SmallTest;
324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport android.util.Log;
334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.ADD;
354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.MOVE;
364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.REMOVE;
374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.UPDATE;
38be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport static org.junit.Assert.*;
394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
40be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar@RunWith(JUnit4.class)
41f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@SmallTest
42be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarpublic class OpReorderTest {
434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private static final String TAG = "OpReorderTest";
454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    List<UpdateOp> mUpdateOps = new ArrayList<UpdateOp>();
474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    List<Item> mAddedItems = new ArrayList<Item>();
484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    List<Item> mRemovedItems = new ArrayList<Item>();
494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    Set<UpdateOp> mRecycledOps = new HashSet<UpdateOp>();
504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    static Random random = new Random(System.nanoTime());
514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    OpReorderer mOpReorderer = new OpReorderer(new OpReorderer.Callback() {
534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        @Override
5421b345f101abc385496f42d250e580d21f1287b6Dake Gu        public UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount, Object payload) {
5521b345f101abc385496f42d250e580d21f1287b6Dake Gu            return new UpdateOp(cmd, startPosition, itemCount, payload);
564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        @Override
594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        public void recycleUpdateOp(UpdateOp op) {
604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            mRecycledOps.add(op);
614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    });
634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    int itemCount = 10;
654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    int updatedItemCount = 0;
664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void setup(int count) {
684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        itemCount = count;
694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        updatedItemCount = itemCount;
704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
72be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Before
73be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    public void setUp() throws Exception {
744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        cleanState();
754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void cleanState() {
784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mUpdateOps = new ArrayList<UpdateOp>();
794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mAddedItems = new ArrayList<Item>();
804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mRemovedItems = new ArrayList<Item>();
814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mRecycledOps = new HashSet<UpdateOp>();
824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        Item.idCounter = 0;
834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
85be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testMoveRemoved() throws Exception {
874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(10);
884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(7, 3);
904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
93be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testMoveRemove() throws Exception {
954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(10);
964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 5);
984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
101be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test1() {
1034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(10);
1044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 5);
1054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 4);
1064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
109be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test2() {
1114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
1134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(1, 1);
1144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
117be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test3() {
1194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(0, 4);
1214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 1);
1224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
125be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test4() {
1274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 0);
1294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 1);
1304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
133be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test5() {
1354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(10);
1364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(8, 1);
1374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(6, 3);
1384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
141be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test6() {
1434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
1454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(0, 3);
1464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
149be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test7() {
1514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 4);
1534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 1);
1544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
157be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test8() {
1594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(4, 3);
1614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 1);
1624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
165be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void test9() {
1674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        setup(5);
1684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(2, 0);
1694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 2);
1704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        process();
1714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
173be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testRandom() throws Exception {
175670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        for (int i = 0; i < 150; i++) {
1764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            try {
1774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                cleanState();
1784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                setup(50);
1794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                for (int j = 0; j < 50; j++) {
1804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    randOp(nextInt(random, nextInt(random, 4)));
1814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
1824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                Log.d(TAG, "running random test " + i);
1834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                process();
1844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } catch (Throwable t) {
1854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new Exception(t.getMessage() + "\n" + opsToString(mUpdateOps));
1864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
190be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testRandomMoveRemove() throws Exception {
192670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        for (int i = 0; i < 1000; i++) {
1934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            try {
1944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                cleanState();
1954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                setup(5);
1964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                orderedRandom(MOVE, REMOVE);
1974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                process();
1984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } catch (Throwable t) {
1994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new Exception(t.getMessage() + "\n" + opsToString(mUpdateOps));
2004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
2014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
204be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
2054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testRandomMoveAdd() throws Exception {
206670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        for (int i = 0; i < 1000; i++) {
2074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            try {
2084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                cleanState();
2094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                setup(5);
2104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                orderedRandom(MOVE, ADD);
2114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                process();
2124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } catch (Throwable t) {
2134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new Exception(t.getMessage() + "\n" + opsToString(mUpdateOps));
2144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
2154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
218be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
2194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testRandomMoveUpdate() throws Exception {
220670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        for (int i = 0; i < 1000; i++) {
2214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            try {
2224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                cleanState();
2234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                setup(5);
2244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                orderedRandom(MOVE, UPDATE);
2254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                process();
2264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } catch (Throwable t) {
2274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                throw new Exception(t.getMessage() + "\n" + opsToString(mUpdateOps));
2284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
2294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private String opsToString(List<UpdateOp> updateOps) {
2334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        StringBuilder sb = new StringBuilder();
2344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (UpdateOp op : updateOps) {
2354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            sb.append("\n").append(op.toString());
2364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return sb.append("\n").toString();
2384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void orderedRandom(int... ops) {
2414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (int op : ops) {
2424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            randOp(op);
2434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void randOp(int cmd) {
2474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        switch (cmd) {
2484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case REMOVE:
2494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (updatedItemCount > 1) {
2504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    int s = nextInt(random, updatedItemCount - 1);
2514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    int len = Math.max(1, nextInt(random, updatedItemCount - s));
2524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    rm(s, len);
2534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
2544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case ADD:
2564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                int s = updatedItemCount == 0 ? 0 : nextInt(random, updatedItemCount);
2574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                add(s, nextInt(random, 50));
2584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case MOVE:
2604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (updatedItemCount >= 2) {
2614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    int from = nextInt(random, updatedItemCount);
2624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    int to;
2634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    do {
2644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        to = nextInt(random, updatedItemCount);
2654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    } while (to == from);
2664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    mv(from, to);
2674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
2684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UPDATE:
2704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (updatedItemCount > 1) {
2714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    s = nextInt(random, updatedItemCount - 1);
2724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    int len = Math.max(1, nextInt(random, updatedItemCount - s));
2734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    up(s, len);
2744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
2754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
2764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    int nextInt(Random random, int n) {
2804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (n == 0) {
2814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return 0;
2824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return random.nextInt(n);
2844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    UpdateOp rm(int start, int count) {
2874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        updatedItemCount -= count;
28821b345f101abc385496f42d250e580d21f1287b6Dake Gu        return record(new UpdateOp(REMOVE, start, count, null));
2894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    UpdateOp mv(int from, int to) {
29221b345f101abc385496f42d250e580d21f1287b6Dake Gu        return record(new UpdateOp(MOVE, from, to, null));
2934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    UpdateOp add(int start, int count) {
2964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        updatedItemCount += count;
29721b345f101abc385496f42d250e580d21f1287b6Dake Gu        return record(new UpdateOp(ADD, start, count, null));
2984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    UpdateOp up(int start, int count) {
30121b345f101abc385496f42d250e580d21f1287b6Dake Gu        return record(new UpdateOp(UPDATE, start, count, null));
3024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    UpdateOp record(UpdateOp op) {
3054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mUpdateOps.add(op);
3064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return op;
3074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void process() {
3104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<Item> items = new ArrayList<Item>(itemCount);
3114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (int i = 0; i < itemCount; i++) {
3124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            items.add(Item.create());
3134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<Item> clones = new ArrayList<Item>(itemCount);
3154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (int i = 0; i < itemCount; i++) {
3164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            clones.add(Item.clone(items.get(i)));
3174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<UpdateOp> rewritten = rewriteOps(mUpdateOps);
3194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertAllMovesAtTheEnd(rewritten);
3214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        apply(items, mUpdateOps);
3234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<Item> originalAdded = mAddedItems;
3244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<Item> originalRemoved = mRemovedItems;
3254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (originalAdded.size() > 0) {
3264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            Item.idCounter = originalAdded.get(0).id;
3274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mAddedItems = new ArrayList<Item>();
3294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mRemovedItems = new ArrayList<Item>();
3304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        apply(clones, rewritten);
3314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // now check equality
3334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertListsIdentical(items, clones);
3344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertHasTheSameItems(originalAdded, mAddedItems);
3354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertHasTheSameItems(originalRemoved, mRemovedItems);
3364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertRecycledOpsAreNotReused(items);
3384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertRecycledOpsAreNotReused(clones);
3394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void assertRecycledOpsAreNotReused(List<Item> items) {
3424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (Item item : items) {
3434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            assertFalse(mRecycledOps.contains(item));
3444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void assertAllMovesAtTheEnd(List<UpdateOp> ops) {
3484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        boolean foundMove = false;
3494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (UpdateOp op : ops) {
3504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (op.cmd == MOVE) {
3514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                foundMove = true;
3524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } else {
3534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                assertFalse(foundMove);
3544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
3554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void assertHasTheSameItems(List<Item> items,
3594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            List<Item> clones) {
3604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        String log = "has the same items\n" + toString(items) + "--\n" + toString(clones);
3614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(log, items.size(), clones.size());
3624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (Item item : items) {
3634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            for (Item clone : clones) {
3644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (item.id == clone.id && item.version == clone.version) {
3654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    clones.remove(clone);
3664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    break;
3674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
3684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
3694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(log, 0, clones.size());
3714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void assertListsIdentical(List<Item> items, List<Item> clones) {
3744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        String log = "is identical\n" + toString(items) + "--\n" + toString(clones);
3754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(items.size(), clones.size());
3764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (int i = 0; i < items.size(); i++) {
3774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            Item.assertIdentical(log, items.get(i), clones.get(i));
3784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
3794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
3804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
3814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void apply(List<Item> items, List<UpdateOp> updateOps) {
3824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (UpdateOp op : updateOps) {
3834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            switch (op.cmd) {
3844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                case UpdateOp.ADD:
3854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    for (int i = 0; i < op.itemCount; i++) {
3864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        final Item newItem = Item.create();
3874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        mAddedItems.add(newItem);
3884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        items.add(op.positionStart + i, newItem);
3894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    }
3904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    break;
3914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                case UpdateOp.REMOVE:
3924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    for (int i = 0; i < op.itemCount; i++) {
3934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        mRemovedItems.add(items.remove(op.positionStart));
3944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    }
3954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    break;
3964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                case UpdateOp.MOVE:
3974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    items.add(op.itemCount, items.remove(op.positionStart));
3984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    break;
3994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                case UpdateOp.UPDATE:
4004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    for (int i = 0; i < op.itemCount; i++) {
4014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        final int index = op.positionStart + i;
4024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                        items.get(index).version = items.get(index).version + 1;
4034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    }
4044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    break;
4054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
4064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
4074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
4094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private List<UpdateOp> rewriteOps(List<UpdateOp> updateOps) {
4104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        List<UpdateOp> copy = new ArrayList<UpdateOp>();
4114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (UpdateOp op : updateOps) {
41221b345f101abc385496f42d250e580d21f1287b6Dake Gu            copy.add(new UpdateOp(op.cmd, op.positionStart, op.itemCount, null));
4134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
4144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mOpReorderer.reorderOps(copy);
4154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return copy;
4164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
418be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_1() {
4204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(10, 15);
4214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 3);
4224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
4244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(7, 12), mUpdateOps.get(1));
4254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 3), mUpdateOps.get(0));
4264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
428be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_2() {
4304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
4314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(4, 2);
4324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
4344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(5, 2), mUpdateOps.get(0));
4354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(3, 6), mUpdateOps.get(1));
4364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
438be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_3() {
4404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
4414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 2);
4424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
4444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(4, 2), mUpdateOps.get(0));
4454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(3, 6), mUpdateOps.get(1));
4464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
448be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_4() {
4504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
4514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 3);
4524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(3, mUpdateOps.size());
4544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(4, 2), mUpdateOps.get(0));
4554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 1), mUpdateOps.get(1));
4564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(2, 5), mUpdateOps.get(2));
4574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
459be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_5() {
4614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 0);
4624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 3);
4634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(3, mUpdateOps.size());
4654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(4, 1), mUpdateOps.get(0));
4664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(1, 2), mUpdateOps.get(1));
4674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(1, 0), mUpdateOps.get(2));
4684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
470be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_6() {
4724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 10);
4734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 3);
4744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(3, mUpdateOps.size());
4764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(4, 2), mUpdateOps.get(0));
4774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 1), mUpdateOps.get(1));
4784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
480be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_7() {
4824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 2);
4834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(6, 2);
4844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
4864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(6, 2), mUpdateOps.get(0));
4874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(3, 2), mUpdateOps.get(1));
4884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
490be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_8() {
4924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 4);
4934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 1);
4944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
4954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(1, mUpdateOps.size());
4964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(4, 1), mUpdateOps.get(0));
4974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
4984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
499be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_9() {
5014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 4);
5024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(4, 1);
5034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(1, mUpdateOps.size());
5054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(3, 1), mUpdateOps.get(0));
5064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
508be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_10() {
5104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
5114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(0, 3);
5124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 2), mUpdateOps.get(0));
5154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(0, 1), mUpdateOps.get(1));
5164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
518be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_11() {
5204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(3, 8);
5214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(7, 3);
5224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(3, 1), mUpdateOps.get(0));
5254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(7, 2), mUpdateOps.get(1));
5264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
528be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_12() {
5304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
5314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(2, 1);
5324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(3, 1), mUpdateOps.get(0));
5354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(1, 2), mUpdateOps.get(1));
5364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
538be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_13() {
5404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
5414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(1, 2);
5424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(1, mUpdateOps.size());
5444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 2), mUpdateOps.get(1));
5454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
547be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_14() {
5494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(4, 2);
5504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 1);
5514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 1), mUpdateOps.get(0));
5544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(2, 3), mUpdateOps.get(1));
5554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
557be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_15() {
5594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(4, 2);
5604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(3, 2);
5614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(1, mUpdateOps.size());
5634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(2, 2), mUpdateOps.get(0));
5644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
566be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveRemove_16() {
5684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(2, 3);
5694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        rm(1, 2);
5704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveRemove(mUpdateOps, 0);
5714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(3, 1), mUpdateOps.get(0));
5734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(rm(1, 1), mUpdateOps.get(1));
5744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
576be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveUpdate_0() {
5784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(1, 3);
5794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        up(1, 2);
5804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveUpdate(mUpdateOps, 0);
5814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(2, mUpdateOps.size());
5824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(up(2, 2), mUpdateOps.get(0));
5834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(1, 3), mUpdateOps.get(1));
5844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
586be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveUpdate_1() {
5884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(0, 2);
5894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        up(0, 4);
5904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveUpdate(mUpdateOps, 0);
5914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(3, mUpdateOps.size());
5924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(up(0, 1), mUpdateOps.get(0));
5934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(up(1, 3), mUpdateOps.get(1));
5944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(0, 2), mUpdateOps.get(2));
5954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
5964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
597be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public void testSwapMoveUpdate_2() {
5994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mv(2, 0);
6004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        up(1, 3);
6014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        swapMoveUpdate(mUpdateOps, 0);
6024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(3, mUpdateOps.size());
6034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(up(3, 1), mUpdateOps.get(0));
6044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(up(0, 2), mUpdateOps.get(1));
6054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        assertEquals(mv(2, 0), mUpdateOps.get(2));
6064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
6074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void swapMoveUpdate(List<UpdateOp> list, int move) {
6094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mOpReorderer.swapMoveUpdate(list, move, list.get(move), move + 1, list.get(move + 1));
6104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
6114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void swapMoveRemove(List<UpdateOp> list, int move) {
6134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mOpReorderer.swapMoveRemove(list, move, list.get(move), move + 1, list.get(move + 1));
6144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
6154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private String toString(List<Item> items) {
6174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        StringBuilder sb = new StringBuilder();
6184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (Item item : items) {
6194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            sb.append(item.toString()).append("\n");
6204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return sb.toString();
6224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
6234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    static class Item {
6254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        static int idCounter = 0;
6274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        int id;
6284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        int version;
6294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        Item(int id, int version) {
6314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            this.id = id;
6324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            this.version = version;
6334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        static Item create() {
6364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return new Item(idCounter++, 1);
6374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        static Item clone(Item other) {
6404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return new Item(other.id, other.version);
6414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        public static void assertIdentical(String logPrefix, Item item1, Item item2) {
6444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            assertEquals(logPrefix + "\n" + item1 + " vs " + item2, item1.id, item2.id);
6454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            assertEquals(logPrefix + "\n" + item1 + " vs " + item2, item1.version, item2.version);
6464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
6484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        @Override
6494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        public String toString() {
6504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return "Item{" +
6514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    "id=" + id +
6524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    ", version=" + version +
6534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    '}';
6544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
6554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
6564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar}
657