Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.os.cts;
     17 
     18 import java.lang.reflect.Constructor;
     19 import java.lang.reflect.InvocationTargetException;
     20 import java.lang.reflect.Method;
     21 
     22 import android.os.WorkSource;
     23 import android.test.AndroidTestCase;
     24 
     25 public class WorkSourceTest extends AndroidTestCase {
     26     private Constructor<WorkSource> mConstructWS;
     27     private Object[] mConstructWSArgs = new Object[1];
     28     private Method mAddUid;
     29     private Object[] mAddUidArgs = new Object[1];
     30     private Method mAddUidName;
     31     private Object[] mAddUidNameArgs = new Object[2];
     32     private Method mAddReturningNewbs;
     33     private Object[] mAddReturningNewbsArgs = new Object[1];
     34     private Method mSetReturningDiffs;
     35     private Object[] mSetReturningDiffsArgs = new Object[1];
     36     private Method mStripNames;
     37     private Object[] mStripNamesArgs = new Object[0];
     38 
     39     @Override
     40     protected void setUp() throws Exception {
     41         super.setUp();
     42         mConstructWS = WorkSource.class.getConstructor(new Class[] { int.class });
     43         mAddUid = WorkSource.class.getMethod("add", new Class[] { int.class });
     44         mAddUidName = WorkSource.class.getMethod("add", new Class[] { int.class, String.class });
     45         mAddReturningNewbs = WorkSource.class.getMethod("addReturningNewbs", new Class[] { WorkSource.class });
     46         mSetReturningDiffs = WorkSource.class.getMethod("setReturningDiffs", new Class[] { WorkSource.class });
     47         mStripNames = WorkSource.class.getMethod("stripNames", new Class[] {  });
     48     }
     49 
     50     private WorkSource wsNew(int uid) throws IllegalArgumentException,
     51             InstantiationException, IllegalAccessException, InvocationTargetException {
     52         mConstructWSArgs[0] = uid;
     53         return mConstructWS.newInstance(mConstructWSArgs);
     54     }
     55 
     56     private WorkSource wsNew(int[] uids) throws IllegalArgumentException,
     57             InstantiationException, IllegalAccessException, InvocationTargetException {
     58         WorkSource ws = new WorkSource();
     59         for (int i=0; i<uids.length; i++) {
     60             wsAdd(ws, uids[i]);
     61         }
     62         checkWorkSource("Constructed", ws, uids);
     63         return ws;
     64     }
     65 
     66     private WorkSource wsNew(int[] uids, String[] names) throws IllegalArgumentException,
     67             InstantiationException, IllegalAccessException, InvocationTargetException {
     68         WorkSource ws = new WorkSource();
     69         for (int i=0; i<uids.length; i++) {
     70             wsAdd(ws, uids[i], names[i]);
     71         }
     72         checkWorkSource("Constructed", ws, uids, names);
     73         return ws;
     74     }
     75 
     76     private boolean wsAdd(WorkSource ws, int uid) throws IllegalArgumentException,
     77             InstantiationException, IllegalAccessException, InvocationTargetException {
     78         mAddUidArgs[0] = uid;
     79         return (Boolean)mAddUid.invoke(ws, mAddUidArgs);
     80     }
     81 
     82     private boolean wsAdd(WorkSource ws, int uid, String name) throws IllegalArgumentException,
     83             InstantiationException, IllegalAccessException, InvocationTargetException {
     84         mAddUidNameArgs[0] = uid;
     85         mAddUidNameArgs[1] = name;
     86         return (Boolean)mAddUidName.invoke(ws, mAddUidNameArgs);
     87     }
     88 
     89     private WorkSource wsAddReturningNewbs(WorkSource ws, WorkSource other) throws IllegalArgumentException,
     90             InstantiationException, IllegalAccessException, InvocationTargetException {
     91         mAddReturningNewbsArgs[0] = other;
     92         return (WorkSource)mAddReturningNewbs.invoke(ws, mAddReturningNewbsArgs);
     93     }
     94 
     95     private WorkSource[] wsSetReturningDiffs(WorkSource ws, WorkSource other) throws IllegalArgumentException,
     96             InstantiationException, IllegalAccessException, InvocationTargetException {
     97         mSetReturningDiffsArgs[0] = other;
     98         return (WorkSource[])mSetReturningDiffs.invoke(ws, mSetReturningDiffsArgs);
     99     }
    100 
    101     private WorkSource wsStripNames(WorkSource ws) throws IllegalArgumentException,
    102             InstantiationException, IllegalAccessException, InvocationTargetException {
    103         return (WorkSource)mStripNames.invoke(ws);
    104     }
    105 
    106     private void printArrays(StringBuilder sb, int[] uids, String[] names) {
    107         sb.append("{ ");
    108         for (int i=0; i<uids.length; i++) {
    109             if (i > 0) sb.append(", ");
    110             sb.append(uids[i]);
    111             if (names != null) {
    112                 sb.append(" ");
    113                 sb.append(names[i]);
    114             }
    115         }
    116         sb.append(" }");
    117     }
    118 
    119     private void failWorkSource(String op, WorkSource ws, int[] uids) {
    120         StringBuilder sb = new StringBuilder();
    121         sb.append(op);
    122         sb.append(": Expected: ");
    123         printArrays(sb, uids, null);
    124         sb.append(", got: ");
    125         sb.append(ws);
    126         fail(sb.toString());
    127     }
    128 
    129     private void failWorkSource(String op, WorkSource ws, int[] uids, String[] names) {
    130         StringBuilder sb = new StringBuilder();
    131         sb.append(op);
    132         sb.append(": Expected: ");
    133         printArrays(sb, uids, names);
    134         sb.append(", got: ");
    135         sb.append(ws);
    136         fail(sb.toString());
    137     }
    138 
    139     private void checkWorkSource(String op, WorkSource ws, int[] uids) {
    140         if (ws == null || uids == null) {
    141             if (ws != null) {
    142                 fail(op + ": WorkSource is not null " + ws +", but expected null");
    143             }
    144             if (uids != null) {
    145                 fail(op + "WorkSource is null, but expected non-null: " + uids);
    146             }
    147             return;
    148         }
    149         if (ws.size() != uids.length) {
    150             failWorkSource(op, ws, uids);
    151         }
    152         for (int i=0; i<uids.length; i++) {
    153             if (uids[i] != ws.get(i)) {
    154                 failWorkSource(op, ws, uids);
    155             }
    156         }
    157     }
    158 
    159     private void checkWorkSource(String op, WorkSource ws, int[] uids, String[] names) {
    160         if (ws == null || uids == null) {
    161             if (ws != null) {
    162                 fail(op + ": WorkSource is not null " + ws +", but expected null");
    163             }
    164             if (uids != null) {
    165                 fail(op + "WorkSource is null, but expected non-null: " + uids);
    166             }
    167             return;
    168         }
    169         if (ws.size() != uids.length) {
    170             failWorkSource(op, ws, uids, names);
    171         }
    172         for (int i=0; i<uids.length; i++) {
    173             if (uids[i] != ws.get(i) || !names[i].equals(ws.getName(i))) {
    174                 failWorkSource(op, ws, uids, names);
    175             }
    176         }
    177     }
    178 
    179     public void testConstructEmpty() {
    180         checkWorkSource("Empty", new WorkSource(), new int[] { });
    181     }
    182 
    183     public void testConstructSingle() throws Exception {
    184         checkWorkSource("Single 1", wsNew(1), new int[] { 1 });
    185     }
    186 
    187     public void testAddRawOrdered() throws Exception {
    188         WorkSource ws = wsNew(1);
    189         wsAdd(ws, 2);
    190         checkWorkSource("First", ws, new int[] { 1 , 2 });
    191         wsAdd(ws, 20);
    192         checkWorkSource("Second", ws, new int[] { 1 , 2, 20 });
    193         wsAdd(ws, 100);
    194         checkWorkSource("Third", ws, new int[] { 1, 2, 20, 100 });
    195     }
    196 
    197     public void testAddRawRevOrdered() throws Exception {
    198         WorkSource ws = wsNew(100);
    199         wsAdd(ws, 20);
    200         checkWorkSource("First", ws, new int[] { 20, 100 });
    201         wsAdd(ws, 2);
    202         checkWorkSource("Second", ws, new int[] { 2, 20, 100 });
    203         wsAdd(ws, 1);
    204         checkWorkSource("Third", ws, new int[] { 1, 2, 20, 100 });
    205     }
    206 
    207     public void testAddRawUnordered() throws Exception {
    208         WorkSource ws = wsNew(10);
    209         wsAdd(ws, 2);
    210         checkWorkSource("First", ws, new int[] { 2, 10 });
    211         wsAdd(ws, 5);
    212         checkWorkSource("Second", ws, new int[] { 2, 5, 10 });
    213         wsAdd(ws, 1);
    214         checkWorkSource("Third", ws, new int[] { 1, 2, 5, 10 });
    215         wsAdd(ws, 100);
    216         checkWorkSource("Fourth", ws, new int[] { 1, 2, 5, 10, 100 });
    217     }
    218 
    219     public void testAddWsOrdered() throws Exception {
    220         WorkSource ws = wsNew(1);
    221         ws.add(wsNew(2));
    222         checkWorkSource("First", ws, new int[] { 1 , 2 });
    223         ws.add(wsNew(20));
    224         checkWorkSource("Second", ws, new int[] { 1 , 2, 20 });
    225         ws.add(wsNew(100));
    226         checkWorkSource("Third", ws, new int[] { 1 , 2, 20, 100 });
    227     }
    228 
    229     public void testAddWsRevOrdered() throws Exception {
    230         WorkSource ws = wsNew(100);
    231         ws.add(wsNew(20));
    232         checkWorkSource("First", ws, new int[] { 20, 100 });
    233         ws.add(wsNew(2));
    234         checkWorkSource("Second", ws, new int[] { 2, 20, 100 });
    235         ws.add(wsNew(1));
    236         checkWorkSource("Third", ws, new int[] { 1, 2, 20, 100 });
    237     }
    238 
    239     public void testAddWsUnordered() throws Exception {
    240         WorkSource ws = wsNew(10);
    241         ws.add(wsNew(2));
    242         checkWorkSource("First", ws, new int[] { 2, 10 });
    243         ws.add(wsNew(5));
    244         checkWorkSource("Second", ws, new int[] { 2, 5, 10 });
    245         ws.add(wsNew(1));
    246         checkWorkSource("Third", ws, new int[] { 1, 2, 5, 10 });
    247         ws.add(wsNew(100));
    248         checkWorkSource("Fourth", ws, new int[] { 1, 2, 5, 10, 100 });
    249     }
    250 
    251     private void doTestCombineTwoUids(int[] lhs, int[] rhs, int[] expected, int[] newbs,
    252             int[] gones) throws Exception {
    253         WorkSource ws1 = wsNew(lhs);
    254         WorkSource ws2 = wsNew(rhs);
    255         ws1.add(ws2);
    256         checkWorkSource("Add result", ws1, expected);
    257         ws1 = wsNew(lhs);
    258         WorkSource wsNewbs = wsAddReturningNewbs(ws1, ws2);
    259         checkWorkSource("AddReturning result", ws1, expected);
    260         checkWorkSource("Newbs", wsNewbs, newbs);
    261         ws1 = wsNew(lhs);
    262         WorkSource[] res = wsSetReturningDiffs(ws1, ws2);
    263         checkWorkSource("SetReturning result", ws1, rhs);
    264         checkWorkSource("Newbs", res[0], newbs);
    265         checkWorkSource("Gones", res[1], gones);
    266     }
    267 
    268     private int[] makeRepeatingIntArray(String[] stringarray, int value) {
    269         if (stringarray == null) {
    270             return null;
    271         }
    272         int[] res = new int[stringarray.length];
    273         for (int i=0; i<stringarray.length; i++) {
    274             res[i] = value;
    275         }
    276         return res;
    277     }
    278 
    279     private void doTestCombineTwoNames(String[] lhsnames, String[] rhsnames,
    280             String[] expectednames, String[] newbnames,
    281             String[] gonenames) throws Exception {
    282         int[] lhs = makeRepeatingIntArray(lhsnames, 0);
    283         int[] rhs = makeRepeatingIntArray(rhsnames, 0);
    284         int[] expected = makeRepeatingIntArray(expectednames, 0);
    285         int[] newbs = makeRepeatingIntArray(newbnames, 0);
    286         int[] gones = makeRepeatingIntArray(gonenames, 0);
    287         doTestCombineTwoUidsNames(lhs, lhsnames, rhs, rhsnames, expected, expectednames,
    288                 newbs, newbnames, gones, gonenames);
    289     }
    290 
    291     private void doTestCombineTwoUidsNames(int[] lhs, String[] lhsnames, int[] rhs, String[] rhsnames,
    292             int[] expected, String[] expectednames, int[] newbs, String[] newbnames,
    293             int[] gones, String[] gonenames) throws Exception {
    294         WorkSource ws1 = wsNew(lhs, lhsnames);
    295         WorkSource ws2 = wsNew(rhs, rhsnames);
    296         ws1.add(ws2);
    297         checkWorkSource("Add result", ws1, expected, expectednames);
    298         ws1 = wsNew(lhs, lhsnames);
    299         WorkSource wsNewbs = wsAddReturningNewbs(ws1, ws2);
    300         checkWorkSource("AddReturning result", ws1, expected, expectednames);
    301         checkWorkSource("Newbs", wsNewbs, newbs, newbnames);
    302         ws1 = wsNew(lhs, lhsnames);
    303         WorkSource[] res = wsSetReturningDiffs(ws1, ws2);
    304         checkWorkSource("SetReturning result", ws1, rhs, rhsnames);
    305         checkWorkSource("Newbs", res[0], newbs, newbnames);
    306         checkWorkSource("Gones", res[1], gones, gonenames);
    307     }
    308 
    309     private String[] makeRepeatingStringArray(int[] intarray, String value) {
    310         if (intarray == null) {
    311             return null;
    312         }
    313         String[] res = new String[intarray.length];
    314         for (int i=0; i<intarray.length; i++) {
    315             res[i] = value;
    316         }
    317         return res;
    318     }
    319 
    320     private String[] makeStringArray(int[] intarray) {
    321         if (intarray == null) {
    322             return null;
    323         }
    324         String[] res = new String[intarray.length];
    325         for (int i=0; i<intarray.length; i++) {
    326             res[i] = Character.toString((char)('A' + intarray[i]));
    327         }
    328         return res;
    329     }
    330 
    331     private void doTestCombineTwo(int[] lhs, int[] rhs, int[] expected, int[] newbs,
    332             int[] gones) throws Exception {
    333         doTestCombineTwoUids(lhs, rhs, expected, newbs, gones);
    334         doTestCombineTwoUidsNames(lhs, makeRepeatingStringArray(lhs, "A"),
    335                 rhs, makeRepeatingStringArray(rhs, "A"),
    336                 expected, makeRepeatingStringArray(expected, "A"),
    337                 newbs, makeRepeatingStringArray(newbs, "A"),
    338                 gones, makeRepeatingStringArray(gones, "A"));
    339         doTestCombineTwoNames(makeStringArray(lhs), makeStringArray(rhs),
    340                 makeStringArray(expected), makeStringArray(newbs), makeStringArray(gones));
    341     }
    342 
    343     public void testCombineMultiFront() throws Exception {
    344         doTestCombineTwo(
    345                 new int[] { 10, 20, 30, 40 },
    346                 new int[] { 1, 2, 15, 16 },
    347                 new int[] { 1, 2, 10, 15, 16, 20, 30, 40 },
    348                 new int[] { 1, 2, 15, 16 },
    349                 new int[] { 10, 20, 30, 40 });
    350     }
    351 
    352     public void testCombineMultiMiddle() throws Exception {
    353         doTestCombineTwo(
    354                 new int[] { 10, 20, 30, 40 },
    355                 new int[] { 12, 14, 22 },
    356                 new int[] { 10, 12, 14, 20, 22, 30, 40 },
    357                 new int[] { 12, 14, 22 },
    358                 new int[] { 10, 20, 30, 40 });
    359     }
    360 
    361     public void testCombineMultiEnd() throws Exception {
    362         doTestCombineTwo(
    363                 new int[] { 10, 20, 30, 40 },
    364                 new int[] { 35, 45, 50 },
    365                 new int[] { 10, 20, 30, 35, 40, 45, 50 },
    366                 new int[] { 35, 45, 50 },
    367                 new int[] { 10, 20, 30, 40 });
    368     }
    369 
    370     public void testCombineMultiFull() throws Exception {
    371         doTestCombineTwo(
    372                 new int[] { 10, 20, 30, 40 },
    373                 new int[] { 1, 2, 15, 35, 50 },
    374                 new int[] { 1, 2, 10, 15, 20, 30, 35, 40, 50 },
    375                 new int[] { 1, 2, 15, 35, 50 },
    376                 new int[] { 10, 20, 30, 40 });
    377     }
    378 
    379     public void testCombineMultiSame() throws Exception {
    380         doTestCombineTwo(
    381                 new int[] { 10, 20, 30, 40 },
    382                 new int[] { 10, 20, 30 },
    383                 new int[] { 10, 20, 30, 40 },
    384                 null,
    385                 new int[] { 40 });
    386     }
    387 
    388     public void testCombineMultiSomeSame() throws Exception {
    389         doTestCombineTwo(
    390                 new int[] { 10, 20, 30, 40 },
    391                 new int[] { 1, 30, 40 },
    392                 new int[] { 1, 10, 20, 30, 40 },
    393                 new int[] { 1 },
    394                 new int[] { 10, 20 });
    395     }
    396 
    397     public void testCombineMultiSomeSameUidsNames() throws Exception {
    398         doTestCombineTwoUidsNames(
    399                 new int[]    { 10,  10,  20,  30,  30,  30,  40 },
    400                 new String[] { "A", "B", "A", "A", "B", "C", "A" },
    401                 new int[]    { 1,   30,  40,  50 },
    402                 new String[] { "A", "A", "B", "A" },
    403                 new int[]    { 1,   10,  10,  20,  30,  30,  30,  40,  40,  50 },
    404                 new String[] { "A", "A", "B", "A", "A", "B", "C", "A", "B", "A" },
    405                 new int[]    { 1,   40,  50 },
    406                 new String[] { "A", "B", "A" },
    407                 new int[]    { 10,  10,  20,  30,  30,  40 },
    408                 new String[] { "A", "B", "A", "B", "C", "A" });
    409     }
    410 
    411     private void doTestRemoveUids(int[] lhs, int[] rhs, int[] result, boolean diff) throws Exception {
    412         WorkSource ws1 = wsNew(lhs);
    413         WorkSource ws2 = wsNew(rhs);
    414         boolean diffres = ws1.remove(ws2);
    415         if (diffres != diff) {
    416             StringBuilder sb = new StringBuilder();
    417             sb.append("Expected diff ");
    418             sb.append(diff);
    419             sb.append(" but got ");
    420             sb.append(diffres);
    421             sb.append(" when removing ");
    422             sb.append(ws2);
    423             sb.append(" from ");
    424             sb.append(ws1);
    425             fail(sb.toString());
    426         }
    427         checkWorkSource("Remove", ws1, result);
    428     }
    429 
    430     private void doTestRemoveNames(String[] lhsnames, String[] rhsnames,
    431             String[] resultnames, boolean diff) throws Exception {
    432         int[] lhs = makeRepeatingIntArray(lhsnames, 0);
    433         int[] rhs = makeRepeatingIntArray(rhsnames, 0);
    434         int[] result = makeRepeatingIntArray(resultnames, 0);
    435         WorkSource ws1 = wsNew(lhs, lhsnames);
    436         WorkSource ws2 = wsNew(rhs, rhsnames);
    437         boolean diffres = ws1.remove(ws2);
    438         if (diffres != diff) {
    439             StringBuilder sb = new StringBuilder();
    440             sb.append("Expected diff ");
    441             sb.append(diff);
    442             sb.append(" but got ");
    443             sb.append(diffres);
    444             sb.append(" when removing ");
    445             sb.append(ws2);
    446             sb.append(" from ");
    447             sb.append(ws1);
    448             fail(sb.toString());
    449         }
    450         checkWorkSource("Remove", ws1, result, resultnames);
    451     }
    452 
    453     private void doTestRemoveUidsNames(int[] lhs, String[] lhsnames, int[] rhs, String[] rhsnames,
    454             int[] result, String[] resultnames, boolean diff) throws Exception {
    455         WorkSource ws1 = wsNew(lhs, lhsnames);
    456         WorkSource ws2 = wsNew(rhs, rhsnames);
    457         boolean diffres = ws1.remove(ws2);
    458         if (diffres != diff) {
    459             StringBuilder sb = new StringBuilder();
    460             sb.append("Expected diff ");
    461             sb.append(diff);
    462             sb.append(" but got ");
    463             sb.append(diffres);
    464             sb.append(" when removing ");
    465             sb.append(ws2);
    466             sb.append(" from ");
    467             sb.append(ws1);
    468             fail(sb.toString());
    469         }
    470         checkWorkSource("Remove", ws1, result, resultnames);
    471     }
    472 
    473     private void doTestRemove(int[] lhs, int[] rhs, int[] result, boolean diff) throws Exception {
    474         doTestRemoveUids(lhs, rhs, result, diff);
    475         doTestRemoveUidsNames(lhs, makeRepeatingStringArray(lhs, "A"),
    476                 rhs, makeRepeatingStringArray(rhs, "A"),
    477                 result, makeRepeatingStringArray(result, "A"),
    478                 diff);
    479         doTestRemoveNames(makeStringArray(lhs), makeStringArray(rhs),
    480                 makeStringArray(result), diff);
    481     }
    482 
    483     public void testRemoveNone() throws Exception {
    484         doTestRemove(
    485                 new int[] { 10, 20, 30, 40 },
    486                 new int[] { 1, 2, 35, 50 },
    487                 new int[] { 10, 20, 30, 40 },
    488                 false);
    489     }
    490 
    491     public void testRemoveMultiFront() throws Exception {
    492         doTestRemove(
    493                 new int[] { 10, 20, 30, 40 },
    494                 new int[] { 1, 2, 10, 30 },
    495                 new int[] { 20, 40 },
    496                 true);
    497     }
    498 
    499     public void testRemoveMultiMiddle() throws Exception {
    500         doTestRemove(
    501                 new int[] { 10, 20, 30, 40 },
    502                 new int[] { 20, 30 },
    503                 new int[] { 10, 40 },
    504                 true);
    505     }
    506 
    507     public void testRemoveMultiEnd() throws Exception {
    508         doTestRemove(
    509                 new int[] { 10, 20, 30, 40 },
    510                 new int[] { 30, 40, 50 },
    511                 new int[] { 10, 20 },
    512                 true);
    513     }
    514 
    515     public void testRemoveMultiFull() throws Exception {
    516         doTestRemove(
    517                 new int[] { 10, 20, 30, 40 },
    518                 new int[] { 1, 2, 20, 25, 35, 40 },
    519                 new int[] { 10, 30 },
    520                 true);
    521     }
    522 
    523     public void testRemoveMultiAll() throws Exception {
    524         doTestRemove(
    525                 new int[] { 10, 20, 30, 40 },
    526                 new int[] { 10, 20, 30, 40 },
    527                 new int[] { },
    528                 true);
    529     }
    530 
    531     private void doTestStripNames(int[] uids, String[] names, int[] expected) throws Exception {
    532         WorkSource ws1 = wsNew(uids, names);
    533         WorkSource res = wsStripNames(ws1);
    534         checkWorkSource("StripNames", res, expected);
    535     }
    536 
    537     public void testStripNamesSimple() throws Exception {
    538         doTestStripNames(
    539                 new int[]    { 10,  20,  30,  40 },
    540                 new String[] { "A", "A", "A", "A" },
    541                 new int[]    { 10, 20, 30, 40 });
    542     }
    543 
    544     public void testStripNamesFull() throws Exception {
    545         doTestStripNames(
    546                 new int[]    { 10,  10,  10,  10 },
    547                 new String[] { "A", "B", "C", "D" },
    548                 new int[]    { 10 });
    549     }
    550 
    551     public void testStripNamesComplex() throws Exception {
    552         doTestStripNames(
    553                 new int[]    { 10,  20,  20,  30,  40,  40 },
    554                 new String[] { "A", "A", "B", "A", "A", "B" },
    555                 new int[]    { 10, 20, 30, 40 });
    556     }
    557 }
    558