Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc657928 authored by Hyundo Moon's avatar Hyundo Moon Committed by Cherrypicker Worker
Browse files

Add tests for nested classes in BluetoothPbapVcardManager

This CL adds tests for:
- BluetoothPbapVcardManager.ContactCursorFilter
- BluetoothPbapVcardManager.PropertySelector
- BluetoothPbapVcardManager.VCardFilter

Bug: 237467631
Test: atest BluetoothPbapVcardManagerNestedClassesTest
Change-Id: Iecbdeb1d591604d3f5403f06f9b1120973404acd
(cherry picked from commit 183b117a)
Merged-In: Iecbdeb1d591604d3f5403f06f9b1120973404acd
parent 5badd9c7
Loading
Loading
Loading
Loading
+78 −69
Original line number Diff line number Diff line
@@ -315,7 +315,7 @@ public class BluetoothPbapVcardManager {

    final ArrayList<String> getSelectedPhonebookNameList(final int orderByWhat,
            final boolean vcardType21, int needSendBody, int pbSize, byte[] selector,
            String vcardselectorop) {
            String vCardSelectorOperator) {
        ArrayList<String> nameList = new ArrayList<String>();
        PropertySelector vcardselector = new PropertySelector(selector);
        VCardComposer composer = null;
@@ -389,13 +389,13 @@ public class BluetoothPbapVcardManager {
                        Log.v(TAG, "Checking selected bits in the vcard composer" + vcard);
                    }

                    if (!vcardselector.checkVCardSelector(vcard, vcardselectorop)) {
                    if (!vcardselector.checkVCardSelector(vcard, vCardSelectorOperator)) {
                        Log.e(TAG, "vcard selector check fail");
                        vcard = null;
                        pbSize--;
                        continue;
                    } else {
                        String name = vcardselector.getName(vcard);
                        String name = getNameFromVCard(vcard);
                        if (TextUtils.isEmpty(name)) {
                            name = mContext.getString(android.R.string.unknownName);
                        }
@@ -657,14 +657,14 @@ public class BluetoothPbapVcardManager {
    /**
     * Filter contact cursor by certain condition.
     */
    private static final class ContactCursorFilter {
    static final class ContactCursorFilter {
        /**
         *
         * @param contactCursor
         * @param offset
         * @return a cursor containing contact id of {@code offset} contact.
         */
        public static Cursor filterByOffset(Cursor contactCursor, int offset) {
        static Cursor filterByOffset(Cursor contactCursor, int offset) {
            return filterByRange(contactCursor, offset, offset);
        }

@@ -674,9 +674,9 @@ public class BluetoothPbapVcardManager {
         * @param startPoint
         * @param endPoint
         * @return a cursor containing contact ids of {@code startPoint}th to {@code endPoint}th
         * contact.
         * contact. (i.e. [startPoint, endPoint], both points should be greater than 0)
         */
        public static Cursor filterByRange(Cursor contactCursor, int startPoint, int endPoint) {
        static Cursor filterByRange(Cursor contactCursor, int startPoint, int endPoint) {
            final int contactIdColumn = contactCursor.getColumnIndex(Data.CONTACT_ID);
            long previousContactId = -1;
            // As startPoint, endOffset index starts from 1 to n, we set
@@ -1090,7 +1090,7 @@ public class BluetoothPbapVcardManager {
            if (vCardType21 && bit.excludeForV21) {
                return false;
            }
            if (mFilter == null || offset >= mFilter.length) {
            if (mFilter == null || offset > mFilter.length) {
                return true;
            }
            return ((mFilter[mFilter.length - offset] >> bitPos) & 0x01) != 0;
@@ -1147,7 +1147,8 @@ public class BluetoothPbapVcardManager {
        }
    }

    private static class PropertySelector {
    @VisibleForTesting
    static class PropertySelector {
        private enum PropertyMask {
            //               bit    property
            VERSION(0, "VERSION"),
@@ -1166,12 +1167,12 @@ public class BluetoothPbapVcardManager {
            NICKNAME(23, "NICKNAME"),
            DATETIME(28, "DATETIME");

            public final int pos;
            public final String prop;
            public final int mBitPosition;
            public final String mProperty;

            PropertyMask(int pos, String prop) {
                this.pos = pos;
                this.prop = prop;
            PropertyMask(int bitPosition, String property) {
                this.mBitPosition = bitPosition;
                this.mProperty = property;
            }
        }

@@ -1182,71 +1183,51 @@ public class BluetoothPbapVcardManager {
            this.mSelector = selector;
        }

        private boolean checkbit(int attrBit, byte[] selector) {
            int selectorlen = selector.length;
            if (((selector[selectorlen - 1 - ((int) attrBit / 8)] >> (attrBit % 8)) & 0x01) == 0) {
                return false;
            }
            return true;
        }
        boolean checkVCardSelector(String vCard, String vCardSelectorOperator) {
            Log.d(TAG, "vCardSelectorOperator=" + vCardSelectorOperator);

        private boolean checkprop(String vcard, String prop) {
            String[] lines = vcard.split(SEPARATOR);
            boolean isPresent = false;
            for (String line : lines) {
                if (!Character.isWhitespace(line.charAt(0)) && !line.startsWith("=")) {
                    String currentProp = line.split("[;:]")[0];
                    if (prop.equals(currentProp)) {
                        Log.d(TAG, "bit.prop.equals current prop :" + prop);
                        isPresent = true;
                        return isPresent;
                    }
                }
            }
            final boolean checkAtLeastOnePropertyExists = vCardSelectorOperator.equals("0");
            final boolean checkAllPropertiesExist = vCardSelectorOperator.equals("1");

            return isPresent;
        }
            boolean result = true;

        private boolean checkVCardSelector(String vcard, String vcardselectorop) {
            boolean selectedIn = true;
            if (checkAtLeastOnePropertyExists) {
                for (PropertyMask mask : PropertyMask.values()) {
                    if (!checkBit(mask.mBitPosition, mSelector)) {
                        continue;
                    }
                    Log.d(TAG, "checking for prop :" + mask.mProperty);

            for (PropertyMask bit : PropertyMask.values()) {
                if (checkbit(bit.pos, mSelector)) {
                    Log.d(TAG, "checking for prop :" + bit.prop);
                    if (vcardselectorop.equals("0")) {
                        if (checkprop(vcard, bit.prop)) {
                            Log.d(TAG, "bit.prop.equals current prop :" + bit.prop);
                            selectedIn = true;
                            break;
                    if (doesVCardHaveProperty(vCard, mask.mProperty)) {
                        Log.d(TAG, "mask.prop.equals current prop :" + mask.mProperty);
                        return true;
                    } else {
                            selectedIn = false;
                        result = false;
                    }
                    } else if (vcardselectorop.equals("1")) {
                        if (!checkprop(vcard, bit.prop)) {
                            Log.d(TAG, "bit.prop.notequals current prop" + bit.prop);
                            selectedIn = false;
                            return selectedIn;
                        } else {
                            selectedIn = true;
                }
            } else if (checkAllPropertiesExist) {
                for (PropertyMask mask : PropertyMask.values()) {
                    if (!checkBit(mask.mBitPosition, mSelector)) {
                        continue;
                    }
                    Log.d(TAG, "checking for prop :" + mask.mProperty);

                    if (!doesVCardHaveProperty(vCard, mask.mProperty)) {
                        Log.d(TAG, "mask.prop.notequals current prop" + mask.mProperty);
                        return false;
                    }
                }
            return selectedIn;
            }

        private String getName(String vcard) {
            String[] lines = vcard.split(SEPARATOR);
            String name = "";
            for (String line : lines) {
                if (!Character.isWhitespace(line.charAt(0)) && !line.startsWith("=")) {
                    if (line.startsWith("N:")) {
                        name = line.substring(line.lastIndexOf(':'), line.length());
            return result;
        }

        private boolean checkBit(int attrBit, byte[] selector) {
            int offset = (attrBit / 8) + 1;
            if (mSelector == null || offset > mSelector.length) {
                return false;
            }
            }
            Log.d(TAG, "returning name: " + name);
            return name;
            return ((selector[mSelector.length - offset] >> (attrBit % 8)) & 0x01) != 0;
        }
    }

@@ -1307,4 +1288,32 @@ public class BluetoothPbapVcardManager {
            }
        }
    }

    @VisibleForTesting
    static String getNameFromVCard(String vCard) {
        String[] lines = vCard.split(PropertySelector.SEPARATOR);
        String name = "";
        for (String line : lines) {
            if (!Character.isWhitespace(line.charAt(0)) && !line.startsWith("=")) {
                if (line.startsWith("N:")) {
                    name = line.substring(line.lastIndexOf(':') + 1);
                }
            }
        }
        Log.d(TAG, "returning name: " + name);
        return name;
    }

    private static boolean doesVCardHaveProperty(String vCard, String property) {
        String[] lines = vCard.split(PropertySelector.SEPARATOR);
        for (String line : lines) {
            if (!Character.isWhitespace(line.charAt(0)) && !line.startsWith("=")) {
                String currentProperty = line.split("[;:]")[0];
                if (property.equals(currentProperty)) {
                    return true;
                }
            }
        }
        return false;
    }
}
+216 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.bluetooth.pbap;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.provider.ContactsContract;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.pbap.BluetoothPbapVcardManager.ContactCursorFilter;
import com.android.bluetooth.pbap.BluetoothPbapVcardManager.PropertySelector;
import com.android.bluetooth.pbap.BluetoothPbapVcardManager.VCardFilter;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.concurrent.atomic.AtomicInteger;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class BluetoothPbapVcardManagerNestedClassesTest {

    @Mock
    Context mContext;

    @Mock
    Resources mResources;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(mContext.getResources()).thenReturn(mResources);
    }

    @Test
    public void VCardFilter_isPhotoEnabled_whenFilterIncludesPhoto_returnsTrue() {
        final byte photoEnableBit = 1 << 3;
        byte[] filter = new byte[] {photoEnableBit};
        VCardFilter vCardFilter = new VCardFilter(filter);

        assertThat(vCardFilter.isPhotoEnabled()).isTrue();
    }

    @Test
    public void VCardFilter_isPhotoEnabled_whenFilterExcludesPhoto_returnsFalse() {
        byte[] filter = new byte[] {(byte) 0x00};
        VCardFilter vCardFilter = new VCardFilter(filter);

        assertThat(vCardFilter.isPhotoEnabled()).isFalse();
    }

    @Test
    public void VCardFilter_apply_whenFilterIsNull_returnsSameVcard() {
        VCardFilter vCardFilter = new VCardFilter(/*filter=*/null);

        String vCard = "FN:Full Name";
        assertThat(vCardFilter.apply(vCard, /*vCardType21=*/ true)).isEqualTo(vCard);
    }

    @Test
    public void VCardFilter_apply_returnsSameVcard() {
        final String separator = System.getProperty("line.separator");
        String vCard = "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator
                + "X-IRMC-CALL-DATETIME:20170314T173942" + separator;

        byte[] emailExcludeFilter = new byte[] {(byte) 0xFE, (byte) 0xFF};
        VCardFilter vCardFilter = new VCardFilter(/*filter=*/ emailExcludeFilter);
        String expectedVCard = "FN:Test Full Name" + separator
                + "X-IRMC-CALL-DATETIME:20170314T173942" + separator;

        assertThat(vCardFilter.apply(vCard, /*vCardType21=*/ true))
                .isEqualTo(expectedVCard);
    }

    @Test
    public void PropertySelector_checkVCardSelector_atLeastOnePropertyExists_returnsTrue() {
        final String separator = System.getProperty("line.separator");
        String vCard = "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator
                + "TEL:0123456789" + separator;

        byte[] emailSelector = new byte[] {0x01, 0x00};
        PropertySelector selector = new PropertySelector(emailSelector);

        assertThat(selector.checkVCardSelector(vCard, "0")).isTrue();
    }

    @Test
    public void PropertySelector_checkVCardSelector_atLeastOnePropertyExists_returnsFalse() {
        final String separator = System.getProperty("line.separator");
        String vCard = "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator
                + "TEL:0123456789" + separator;

        byte[] organizationSelector = new byte[] {0x01, 0x00, 0x00};
        PropertySelector selector = new PropertySelector(organizationSelector);

        assertThat(selector.checkVCardSelector(vCard, "0")).isFalse();
    }

    @Test
    public void PropertySelector_checkVCardSelector_allPropertiesExist_returnsTrue() {
        final String separator = System.getProperty("line.separator");
        String vCard = "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator
                + "TEL:0123456789" + separator;

        byte[] fullNameAndEmailSelector = new byte[] {0x01, 0x02};
        PropertySelector selector = new PropertySelector(fullNameAndEmailSelector);

        assertThat(selector.checkVCardSelector(vCard, "1")).isTrue();
    }

    @Test
    public void PropertySelector_checkVCardSelector_allPropertiesExist_returnsFalse() {
        final String separator = System.getProperty("line.separator");
        String vCard = "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator
                + "TEL:0123456789" + separator;

        byte[] fullNameAndOrganizationSelector = new byte[] {0x01, 0x00, 0x02};
        PropertySelector selector = new PropertySelector(fullNameAndOrganizationSelector);

        assertThat(selector.checkVCardSelector(vCard, "1")).isFalse();
    }

    @Test
    public void ContactCursorFilter_filterByOffset() {
        Cursor contactCursor = mock(Cursor.class);
        int contactIdColumn = 5;
        when(contactCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
                .thenReturn(contactIdColumn);

        long[] contactIds = new long[] {1001, 1001, 1002, 1002, 1003, 1003, 1004};
        AtomicInteger currentPos = new AtomicInteger(-1);
        when(contactCursor.moveToNext()).thenAnswer(invocation -> {
            if (currentPos.get() < contactIds.length - 1) {
                currentPos.incrementAndGet();
                return true;
            }
            return false;
        });
        when(contactCursor.getLong(contactIdColumn))
                .thenAnswer(invocation -> contactIds[currentPos.get()]);

        int offset = 3;
        Cursor resultCursor = ContactCursorFilter.filterByOffset(contactCursor, offset);

        // Should return cursor containing [1003]
        assertThat(resultCursor.getCount()).isEqualTo(1);
        assertThat(getContactsIdFromCursor(resultCursor, 0)).isEqualTo(1003);
    }

    @Test
    public void ContactCursorFilter_filterByRange() {
        Cursor contactCursor = mock(Cursor.class);
        int contactIdColumn = 5;
        when(contactCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
                .thenReturn(contactIdColumn);

        long[] contactIds = new long[] {1001, 1001, 1002, 1002, 1003, 1003, 1004};
        AtomicInteger currentPos = new AtomicInteger(-1);
        when(contactCursor.moveToNext()).thenAnswer(invocation -> {
            if (currentPos.get() < contactIds.length - 1) {
                currentPos.incrementAndGet();
                return true;
            }
            return false;
        });
        when(contactCursor.getLong(contactIdColumn))
                .thenAnswer(invocation -> contactIds[currentPos.get()]);

        int startPoint = 2;
        int endPoint = 4;
        Cursor resultCursor = ContactCursorFilter.filterByRange(
                contactCursor, startPoint, endPoint);

        // Should return cursor containing [1002, 1003, 1004]
        assertThat(resultCursor.getCount()).isEqualTo(3);
        assertThat(getContactsIdFromCursor(resultCursor, 0)).isEqualTo(1002);
        assertThat(getContactsIdFromCursor(resultCursor, 1)).isEqualTo(1003);
        assertThat(getContactsIdFromCursor(resultCursor, 2)).isEqualTo(1004);
    }

    private long getContactsIdFromCursor(Cursor cursor, int position) {
        int index = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
        cursor.moveToPosition(position);
        return cursor.getLong(index);
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -333,4 +333,14 @@ public class BluetoothPbapVcardManagerTest {

        assertThat(mManager.stripTelephoneNumber(vCard)).isEqualTo(expectedResult);
    }

    @Test
    public void getNameFromVCard() {
        final String separator = System.getProperty("line.separator");
        String vCard = "N:Test Name" + separator
                + "FN:Test Full Name" + separator
                + "EMAIL:android@android.com:" + separator;

        assertThat(BluetoothPbapVcardManager.getNameFromVCard(vCard)).isEqualTo("Test Name");
    }
}