package com.fsck.k9.controller;


import java.util.Arrays;
import java.util.Random;

import android.support.annotation.NonNull;

import com.fsck.k9.controller.MessagingController.UidReverseComparator;
import com.fsck.k9.mail.Message;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.verification.VerificationMode;

import static org.junit.Assert.*;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


@SuppressWarnings("ConstantConditions")
public class UidReverseComparatorTest {

    private UidReverseComparator comparator;
    private Random random;

    @Before
    public void onBefore() {
        comparator = new UidReverseComparator();
        random = new Random();
    }

    @Test
    public void compare_withTwoNullArguments_shouldReturnZero() throws Exception {
        Message messageLeft = null;
        Message messageRight = null;

        int result = comparator.compare(messageLeft, messageRight);

        assertEquals("result must be 0 when both arguments are null", 0, result);
    }

    @Test
    public void compare_withLeftNullArgument_shouldReturnPositive() throws Exception {
        Message messageLeft = null;
        Message messageRight = mockMessage(1);

        int result = comparator.compare(messageLeft, messageRight);

        assertEquals("result must be 1 when both arguments are null", 1, result);
    }

    @Test
    public void compare_withRightNullArgument_shouldReturnNegative() throws Exception {
        Message messageLeft = mockMessage(1);
        Message messageRight = null;

        int result = comparator.compare(messageLeft, messageRight);

        assertEquals("result must be -1 when both arguments are null", -1, result);
    }

    @Test
    public void compare_twoMessages_shouldReturnOrderByUid() throws Exception {
        Message messageLeft = mockMessage(5);
        Message messageRight = mockMessage(15);

        int result = comparator.compare(messageLeft, messageRight);

        assertEquals("result must be 1 when right message has larger uid than left message", 1, result);
    }

    @Test
    public void testRandomCompare() throws Exception {

        Message[] msgs = new Message[500];
        for (int i = 1; i < msgs.length; i++) {
            if (random.nextInt(10) < 2) {
                msgs[i] = null;

                continue;
            }
            if (random.nextInt(10) < 2) {
                Message numberFormatExceptionMessage = mock(Message.class);
                when(numberFormatExceptionMessage.getUid()).thenReturn("xyz" + i);

                msgs[i] = numberFormatExceptionMessage;
                continue;
            }
            int uid = random.nextInt(200) -100;
            msgs[i] = mockMessage(uid);
        }

        Arrays.sort(msgs, comparator);

        // all objects which are null or unparsable must appear in a contiguous segment at the end
        boolean isNullRange = false;
        for (int i = 1; i < msgs.length; i++) {
            if (msgs[i] == null) {
                isNullRange = true;
                continue;
            }
            verify(msgs[i], atLeastOnce()).getUid();
            if (!isIntParseable(msgs[i].getUid())) {
                isNullRange = true;
                continue;
            }
            assertFalse(isNullRange);
            int id1 = Integer.parseInt(msgs[i-1].getUid());
            int id2 = Integer.parseInt(msgs[i].getUid());
            assertTrue(id1 >= id2);
        }

    }

    private static boolean isIntParseable(String str) {
        try {
            // noinspection ResultOfMethodCallIgnored
            Integer.parseInt(str);
            return true;
        } catch (NullPointerException | NumberFormatException e) {
            return false;
        }
    }

    @NonNull
    private static Message mockMessage(int uid1) {
        Message msg1 = mock(Message.class);
        when(msg1.getUid()).thenReturn(Integer.toString(uid1));
        return msg1;
    }

}
@@ -31,59 +31,8 @@
 ;%0A%0A%0A
-import java.util.Arrays;%0Aimport java.util.Random;%0A%0A
 impo
@@ -180,37 +180,8 @@
 ge;%0A
-import org.hamcrest.Matcher;%0A
 impo
@@ -228,248 +228,92 @@
 st;%0A
-import org.mockito.Mockito;%0Aimport org.mockito.verification.VerificationMode;%0A%0Aimport static org.junit.Assert.*;%0Aimport static org.mockito.Mockito.atLeastOnce;%0Aimport static org.mockito.Mockito.mock;%0Aimport static org.mockito.Mockito.verify
+%0Aimport static org.junit.Assert.assertEquals;%0Aimport static org.mockito.Mockito.mock
 ;%0Aim
@@ -432,17 +432,16 @@
 rTest %7B%0A
-%0A
     priv
@@ -481,34 +481,8 @@
 or;%0A
-    private Random random;
 %0A%0A  
@@ -573,39 +573,8 @@
 ();%0A
-        random = new Random();%0A
     
@@ -1952,1698 +1952,8 @@
  %7D%0A%0A
-    @Test%0A    public void testRandomCompare() throws Exception %7B%0A%0A        Message%5B%5D msgs = new Message%5B500%5D;%0A        for (int i = 1; i %3C msgs.length; i++) %7B%0A            if (random.nextInt(10) %3C 2) %7B%0A                msgs%5Bi%5D = null;%0A%0A                continue;%0A            %7D%0A            if (random.nextInt(10) %3C 2) %7B%0A                Message numberFormatExceptionMessage = mock(Message.class);%0A                when(numberFormatExceptionMessage.getUid()).thenReturn(%22xyz%22 + i);%0A%0A                msgs%5Bi%5D = numberFormatExceptionMessage;%0A                continue;%0A            %7D%0A            int uid = random.nextInt(200) -100;%0A            msgs%5Bi%5D = mockMessage(uid);%0A        %7D%0A%0A        Arrays.sort(msgs, comparator);%0A%0A        // all objects which are null or unparsable must appear in a contiguous segment at the end%0A        boolean isNullRange = false;%0A        for (int i = 1; i %3C msgs.length; i++) %7B%0A            if (msgs%5Bi%5D == null) %7B%0A                isNullRange = true;%0A                continue;%0A            %7D%0A            verify(msgs%5Bi%5D, atLeastOnce()).getUid();%0A            if (!isIntParseable(msgs%5Bi%5D.getUid())) %7B%0A                isNullRange = true;%0A                continue;%0A            %7D%0A            assertFalse(isNullRange);%0A            int id1 = Integer.parseInt(msgs%5Bi-1%5D.getUid());%0A            int id2 = Integer.parseInt(msgs%5Bi%5D.getUid());%0A            assertTrue(id1 %3E= id2);%0A        %7D%0A%0A    %7D%0A%0A    private static boolean isIntParseable(String str) %7B%0A        try %7B%0A            // noinspection ResultOfMethodCallIgnored%0A            Integer.parseInt(str);%0A            return true;%0A        %7D catch (NullPointerException %7C NumberFormatException e) %7B%0A            return false;%0A        %7D%0A    %7D%0A%0A
     
@@ -2151,6 +2151,6 @@
   %7D%0A
-%0A
 %7D
+%0A

Remove test with randomized input