/*
 * Copyright (C) 2015-2016 University of Dundee & Open Microscopy Environment.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package integration.chmod;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import ome.model.internal.Permissions;
import ome.util.Utils;
import omero.RLong;
import omero.RType;
import omero.ServerError;
import omero.cmd.Chmod2;
import omero.cmd.Delete2;
import omero.gateway.util.Requests;
import omero.model.Annotation;
import omero.model.CommentAnnotationI;
import omero.model.Dataset;
import omero.model.DatasetImageLink;
import omero.model.DatasetImageLinkI;
import omero.model.Experiment;
import omero.model.Experimenter;
import omero.model.ExperimenterGroup;
import omero.model.ExperimenterGroupI;
import omero.model.ExperimenterI;
import omero.model.Folder;
import omero.model.FolderImageLink;
import omero.model.FolderImageLinkI;
import omero.model.IObject;
import omero.model.Image;
import omero.model.ImageAnnotationLink;
import omero.model.ImageAnnotationLinkI;
import omero.model.Instrument;
import omero.model.Pixels;
import omero.model.Plate;
import omero.model.RectangleI;
import omero.model.Roi;
import omero.model.RoiI;
import omero.model.TagAnnotation;
import omero.model.TagAnnotationI;
import omero.model.Thumbnail;
import omero.sys.EventContext;
import omero.sys.Parameters;
import omero.sys.ParametersI;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableMap;

import integration.AbstractServerTest;

/**
 * Tests that only appropriate users may use {@link Chmod2} and that others' data is then deleted only when appropriate.
 * @author m.t.b.carroll@dundee.ac.uk
 * @since 5.1.2
 */
public class PermissionsTest extends AbstractServerTest {

    private final List<Long> testImages = Collections.synchronizedList(new ArrayList<Long>());

    private ExperimenterGroup systemGroup;
    private EventContext userOtherGroup, adminOtherGroup;

    /**
     * Set up admin and non-admin users who are not a member of the groups created by tests.
     * @throws Exception unexpected
     */
    @BeforeClass
    public void setupOtherGroup() throws Exception {
        systemGroup = new ExperimenterGroupI(iAdmin.getSecurityRoles().systemGroupId, false);
        userOtherGroup = newUserAndGroup("rw----");
        final ExperimenterGroup group = new ExperimenterGroupI(userOtherGroup.groupId, false);
        adminOtherGroup = newUserInGroup(group, false);
        addUsers(systemGroup, Collections.singletonList(adminOtherGroup.userId), false);
    }

    /**
     * Clear the list of test images.
     */
    @BeforeClass
    public void clearTestImages() {
        testImages.clear();
    }

    /**
     * Delete the test images then clear the list.
     * @throws Exception unexpected
     */
    @AfterClass
    public void deleteTestImages() throws Exception {
        final Delete2 delete = Requests.delete().target("Image").id(testImages).build();
        doChange(root, root.getSession(), delete, true, null, 2);
        clearTestImages();
    }

    /**
     * Add a comment and a ROI to the given image.
     * @param imageId an image ID
     * @return the new model objects
     * @throws ServerError unexpected
     */
    private List<IObject> annotateImage(long imageId) throws ServerError {
        final ParametersI params = new ParametersI().addId(imageId);
        final Image image = (Image) iQuery.findByQuery("FROM Image i JOIN FETCH i.pixels WHERE i.id = :id", params);

        final List<IObject> annotationObjects = new ArrayList<IObject>();

        for (final Annotation annotation : new Annotation[] {new CommentAnnotationI(), new TagAnnotationI()}) {
            ImageAnnotationLink link = new ImageAnnotationLinkI();
            link.setParent((Image) image.proxy());
            link.setChild(annotation);
            link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link);
            annotationObjects.add(link.proxy());
            annotationObjects.add(link.getChild().proxy());
        }

        Roi roi = new RoiI();
        roi.addShape(new RectangleI());
        roi.setImage((Image) image.proxy());
        roi = (Roi) iUpdate.saveAndReturnObject(roi);
        annotationObjects.add(roi.proxy());
        annotationObjects.add(roi.getShape(0).proxy());

        Thumbnail thumbnail = mmFactory.createThumbnail();
        thumbnail.setPixels((Pixels) image.getPrimaryPixels().proxy());
        thumbnail = (Thumbnail) iUpdate.saveAndReturnObject(thumbnail);
        annotationObjects.add(thumbnail.proxy());

        return annotationObjects;
    }

    /**
     * Test that a specific case of using {@link Chmod2} on an annotated image behaves as expected.
     * @param isGroupOwner if the user submitting the {@link Chmod2} request is an owner of the target group
     * @param isGroupMember if the user submitting the {@link Chmod2} request is a member of the target group
     * @param isDataOwner if the user submitting the {@link Chmod2} request owns the data in the group
     * @param isAdmin if the user submitting the {@link Chmod2} request is a member of the system group
     * @param fromPerms the permissions on the group before the chmod
     * @param toPerms the permissions on the group after the chmod
     * @param isExpectSuccess if the chmod is expected to succeed
     * @param isExpectDeleteOther if the chmod is expected to cause another user's annotations to be removed from a user's image
     * @throws Exception unexpected
     */
    @Test(dataProvider = "chmod annotation test cases")
    public void testChmodAnnotation(boolean isGroupOwner, boolean isGroupMember, boolean isDataOwner, boolean isAdmin,
            String fromPerms, String toPerms, boolean isExpectSuccess, boolean isExpectDeleteOther) throws Exception {

        /* set up the users and group for this test case */

        final EventContext importer, annotator, chmodder;
        final ExperimenterGroup dataGroup;

        importer = newUserAndGroup(fromPerms, isGroupOwner && isDataOwner);

        final long dataGroupId = importer.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        if (isDataOwner) {
            chmodder = importer;
        } else if (isGroupMember) {
            chmodder = newUserInGroup(dataGroup, isGroupOwner);
        } else {
            chmodder = isAdmin ? adminOtherGroup : userOtherGroup;
        }

        if (isAdmin && chmodder != adminOtherGroup) {
            addUsers(systemGroup, Collections.singletonList(chmodder.userId), false);
        }

        if ("rwra--".equals(fromPerms)) {
            if (isGroupMember && !isDataOwner) {
                annotator = chmodder;
            } else {
                annotator = newUserInGroup(dataGroup, false);
            }
        } else {
            annotator = null;
        }

        /* note which objects were used to annotate an image */

        final List<IObject> ownerAnnotations, otherAnnotations;

        /* import and annotate an image */

        init(importer);
        final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy();
        final long imageId = image.getId().getValue();
        testImages.add(imageId);
        ownerAnnotations = annotateImage(imageId);

        /* perhaps have another user annotate the image */

        if (annotator == null) {
            otherAnnotations = Collections.<IObject>emptyList();
        } else {
            init(annotator);
            otherAnnotations = annotateImage(image.getId().getValue());
        }

        /* perform the chmod */

        init(chmodder);
        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms(toPerms).build();
        doChange(client, factory, chmod, isExpectSuccess);

        if (!isExpectSuccess) {
            return;
        }

        /* check that the group's permissions are as requested */

        logRootIntoGroup(dataGroupId);
        final ExperimenterGroup changedGroup = (ExperimenterGroup) iQuery.get("ExperimenterGroup", dataGroupId);
        final long actualPermissions = changedGroup.getDetails().getPermissions().getPerm1();
        final long expectedPermissions = (Long) Utils.internalForm(Permissions.parseString(toPerms));
        Assert.assertEquals(actualPermissions, expectedPermissions);

        /* pluck the tag from the other user's annotations */

        final TagAnnotation tag;

        if (annotator == null) {
            tag = null;
        } else {
            final Iterator<IObject> annotationIterator = otherAnnotations.iterator();
            while (true) {
                final IObject annotation = annotationIterator.next();
                if (annotation instanceof TagAnnotation) {
                    annotationIterator.remove();
                    tag = (TagAnnotation) annotation;
                    break;
                }
            }
        }

        /* check that exactly the expected object deletions have occurred */

        assertExists(image);
        if (tag != null) {
            assertExists(tag);
        }
        assertAllExist(ownerAnnotations);
        if (isExpectDeleteOther) {
            assertNoneExist(otherAnnotations);
        } else {
            assertAllExist(otherAnnotations);
        }
    }

    /**
     * @return a variety of test cases for annotation chmod
     */
    @DataProvider(name = "chmod annotation test cases")
    public Object[][] provideChmodAnnotationCases() {
        int index = 0;
        final int IS_GROUP_OWNER = index++;
        final int IS_GROUP_MEMBER = index++;
        final int IS_DATA_OWNER = index++;
        final int IS_ADMIN = index++;
        final int FROM_PERMS = index++;
        final int TO_PERMS = index++;
        final int IS_EXPECT_SUCCESS = index++;
        final int IS_EXPECT_DELETE_OTHER = index++;

        final boolean[] booleanCases = new boolean[]{false, true};
        final String[] permsCases = new String[]{"rw----", "rwra--"};

        final List<Object[]> testCases = new ArrayList<Object[]>();

        for (final boolean isGroupOwner : booleanCases) {
            for (final boolean isGroupMember : booleanCases) {
                for (final boolean isDataOwner : booleanCases) {
                    for (final boolean isAdmin : booleanCases) {
                        if (!isGroupMember && (isGroupOwner || isDataOwner)) {
                            /* test case does not make sense */
                            continue;
                        }

                        for (final String fromPerms : permsCases) {
                            for (final String toPerms : permsCases) {
                                if (fromPerms.equals(toPerms)) {
                                    /* not a permissions change */
                                    continue;
                                }
                                final Object[] testCase = new Object[index];
                                testCase[IS_GROUP_OWNER] = isGroupOwner;
                                testCase[IS_GROUP_MEMBER] = isGroupMember;
                                testCase[IS_DATA_OWNER] = isDataOwner;
                                testCase[IS_ADMIN] = isAdmin;
                                testCase[FROM_PERMS] = fromPerms;
                                testCase[TO_PERMS] = toPerms;
                                testCase[IS_EXPECT_SUCCESS] = isAdmin || isGroupOwner;
                                testCase[IS_EXPECT_DELETE_OTHER] = "rwra--".equals(fromPerms) && "rw----".equals(toPerms);
                                // DEBUG: if (isGroupOwner == true && isGroupMember == true && isDataOwner == true &&
                                //            isAdmin == true && "rwra--".equals(fromPerms) && "rw----".equals(toPerms))
                                testCases.add(testCase);
                            }
                        }
                    }
                }
            }
        }

        return testCases.toArray(new Object[testCases.size()][]);
    }

    /**
     * Test a specific case of using {@link Chmod2} on an image that is in a dataset or folder.
     * @param isImageOwner if the user who owns the container also owns the image
     * @param isLinkOwner if the user who owns the container also linked the image to the container
     * @param isInDataset if the image is in a dataset, otherwise a folder
     * @throws Exception unexpected
     */
    @Test(dataProvider = "chmod container test cases")
    public void testChmodContainerReadWriteToPrivate(boolean isImageOwner, boolean isLinkOwner, boolean isInDataset)
            throws Exception {

        /* set up the users and group for this test case */

        final EventContext containerOwner, imageOwner, linkOwner, chmodder;
        final ExperimenterGroup dataGroup;

        containerOwner = newUserAndGroup("rwrw--");

        final long dataGroupId = containerOwner.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        if (isImageOwner) {
            imageOwner = containerOwner;
            linkOwner = isLinkOwner ? containerOwner : newUserInGroup(dataGroup, false);
        } else {
            imageOwner = newUserInGroup(dataGroup, false);
            linkOwner = isLinkOwner ? containerOwner : imageOwner;
        }

        chmodder = newUserInGroup(dataGroup, true);

        /* create a container */

        init(containerOwner);
        IObject container = isInDataset ? mmFactory.simpleDataset() : mmFactory.simpleFolder();
        container = iUpdate.saveAndReturnObject(container).proxy();

        /* create an image */

        init(imageOwner);
        final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy();
        final long imageId = image.getId().getValue();
        testImages.add(imageId);

        /* move the image into the container */

        init(linkOwner);
        final IObject link;
        if (isInDataset) {
            final DatasetImageLink linkDI = new DatasetImageLinkI();
            linkDI.setParent((Dataset) container);
            linkDI.setChild(image);
            link = iUpdate.saveAndReturnObject(linkDI);
        } else {
            final FolderImageLink linkFI = new FolderImageLinkI();
            linkFI.setParent((Folder) container);
            linkFI.setChild(image);
            link = iUpdate.saveAndReturnObject(linkFI);
        }

        /* perform the chmod */

        init(chmodder);
        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms("rw----").build();
        doChange(client, factory, chmod, true);

        /* check that exactly the expected object deletions have occurred */

        logRootIntoGroup(dataGroupId);
        assertExists(container);
        assertExists(image);
        if (containerOwner == imageOwner) {
            assertExists(link);
        } else {
            assertDoesNotExist(link);
        }
    }

    /**
     * @return a variety of test cases for container chmod
     */
    @DataProvider(name = "chmod container test cases")
    public Object[][] provideChmodContainerCases() {
        int index = 0;
        final int IS_IMAGE_OWNER = index++;
        final int IS_LINK_OWNER = index++;
        final int IS_IN_DATASET = index++;

        final boolean[] booleanCases = new boolean[]{false, true};

        final List<Object[]> testCases = new ArrayList<Object[]>();

        for (final boolean isImageOwner : booleanCases) {
            for (final boolean isLinkOwner : booleanCases) {
                for (final boolean isInDataset : booleanCases) {
                    final Object[] testCase = new Object[index];
                    testCase[IS_IMAGE_OWNER] = isImageOwner;
                    testCase[IS_LINK_OWNER] = isLinkOwner;
                    testCase[IS_IN_DATASET] = isInDataset;
                    // DEBUG: if (isImageOwner == true && isLinkOwner == true && isInDataset = false)
                    testCases.add(testCase);
                }
            }
        }

        return testCases.toArray(new Object[testCases.size()][]);
    }

    /**
     * Test that a mixed-owner folder hierarchy is unlinked on group downgrade from read-write to private.
     * @throws Exception unexpected
     */
    @Test(groups = "broken")
    public void testDeleteMixedFolderHierarchy() throws Exception {

        /* set up the users and group for this test case */

        final EventContext alice, bob;
        final ExperimenterGroup dataGroup;

        alice = newUserAndGroup("rwrw--", true);

        final long dataGroupId = alice.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        bob = newUserInGroup(dataGroup, false);

        /* set up the folders */

        init(alice);
        Folder topFolder = mmFactory.simpleFolder();
        topFolder = (Folder) iUpdate.saveAndReturnObject(topFolder).proxy();

        init(bob);
        Folder bottomFolder = mmFactory.simpleFolder();
        bottomFolder.setParentFolder(topFolder);
        bottomFolder = (Folder) iUpdate.saveAndReturnObject(bottomFolder).proxy();

        /* check that the hierarchy is correctly constructed */

        init(alice);
        Folder aliceFolder = (Folder) iQuery.get("Folder", topFolder.getId().getValue());
        Folder bobFolder = (Folder) iQuery.get("Folder", bottomFolder.getId().getValue());
        Assert.assertEquals(aliceFolder.getDetails().getOwner().getId().getValue(), alice.userId);
        Assert.assertEquals(bobFolder.getDetails().getOwner().getId().getValue(), bob.userId);
        Assert.assertEquals(bobFolder.getParentFolder().getId().getValue(), aliceFolder.getId().getValue());

        /* perform the chmod */

        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms("rw----").build();
        doChange(chmod);

        /* check that the folders are intact but now unlinked */

        aliceFolder = (Folder) iQuery.get("Folder", topFolder.getId().getValue());
        bobFolder = (Folder) iQuery.get("Folder", bottomFolder.getId().getValue());
        Assert.assertEquals(aliceFolder.getDetails().getOwner().getId().getValue(), alice.userId);
        Assert.assertEquals(bobFolder.getDetails().getOwner().getId().getValue(), bob.userId);
        Assert.assertNull(bobFolder.getParentFolder());  /* currently fails to unlink */
    }

    /**
     * Test chmod on a group wherein an image's instrument is shared with another's image.
     * @param toPerms the permissions on the group after the chmod
     * @throws Exception unexpected
     */
    @Test(dataProvider = "private-group failure test cases")
    public void testSharedInstrument(String toPerms) throws Exception {

        /* set up the users and group for this test case */

        final EventContext imageOwner, projectionOwner, chmodder;
        final ExperimenterGroup dataGroup;

        imageOwner = newUserAndGroup("rwrw--");

        final long dataGroupId = imageOwner.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        projectionOwner = newUserInGroup(dataGroup, false);
        chmodder = newUserInGroup(dataGroup, true);

        /* create an image with an instrument */

        init(imageOwner);
        Image image = mmFactory.createImage();
        image.setInstrument(mmFactory.createInstrument());
        image = (Image) iUpdate.saveAndReturnObject(image);
        final long imageId = image.getId().getValue();
        testImages.add(imageId);
        final Instrument instrument = (Instrument) image.getInstrument().proxy();
        image = (Image) image.proxy();

        /* another user projects the image */

        init(projectionOwner);
        Image projection = mmFactory.createImage();
        projection.setInstrument(instrument);
        projection = (Image) iUpdate.saveAndReturnObject(projection);
        final long projectionId = projection.getId().getValue();
        testImages.add(projectionId);
        projection = (Image) projection.proxy();

        /* perform the chmod */

        final boolean isExpectSuccess = !"rw----".equals(toPerms);

        init(chmodder);
        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms(toPerms).build();
        doChange(client, factory, chmod, isExpectSuccess);

        if (!isExpectSuccess) {
            return;
        }

        /* check that all the objects still exist */

        logRootIntoGroup(dataGroupId);
        assertExists(image);
        assertExists(projection);
        assertExists(instrument);
    }


    /**
     * Test chmod on a group wherein an image is used in the same experiment as another's image.
     * @param toPerms the permissions on the group after the chmod
     * @throws Exception unexpected
     */
    @Test(dataProvider = "private-group failure test cases")
    public void testSharedExperiment(String toPerms) throws Exception {

        /* set up the users and group for this test case */

        final EventContext imageOwner, otherImageOwner, chmodder;
        final ExperimenterGroup dataGroup;

        imageOwner = newUserAndGroup("rwrw--");

        final long dataGroupId = imageOwner.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        otherImageOwner = newUserInGroup(dataGroup, false);
        chmodder = newUserInGroup(dataGroup, true);

        /* create an image with an experiment */

        init(imageOwner);
        Image image = mmFactory.createImage();
        image.setExperiment(mmFactory.simpleExperiment());
        image = (Image) iUpdate.saveAndReturnObject(image);
        final long imageId = image.getId().getValue();
        testImages.add(imageId);
        final Experiment experiment = (Experiment) image.getExperiment().proxy();
        image = (Image) image.proxy();

        /* another user's image is part of the same experiment */

        init(otherImageOwner);
        Image otherImage = mmFactory.createImage();
        otherImage.setExperiment(experiment);
        otherImage = (Image) iUpdate.saveAndReturnObject(otherImage);
        final long otherImageId = otherImage.getId().getValue();
        testImages.add(otherImageId);
        otherImage = (Image) otherImage.proxy();

        /* perform the chmod */

        final boolean isExpectSuccess = !"rw----".equals(toPerms);

        init(chmodder);
        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms(toPerms).build();
        doChange(client, factory, chmod, isExpectSuccess);

        if (!isExpectSuccess) {
            return;
        }

        /* check that all the objects still exist */

        logRootIntoGroup(dataGroupId);
        assertExists(image);
        assertExists(otherImage);
        assertExists(experiment);
    }

    /**
     * Test chmod on a group wherein a plate's images are owned by a different user who has them in their dataset.
     * @param toPerms the permissions on the group after the chmod
     * @throws Exception unexpected
     */
    @Test(dataProvider = "private-group failure test cases")
    public void testDatasetToPlate(String toPerms) throws Exception {

        /* set up the users and group for this test case */

        final EventContext datasetOwner, plateOwner, chmodder;
        final ExperimenterGroup dataGroup;

        datasetOwner = newUserAndGroup("rwrw--");

        final long dataGroupId = datasetOwner.groupId;
        dataGroup = new ExperimenterGroupI(dataGroupId, false);

        plateOwner = newUserInGroup(dataGroup, false);
        chmodder = newUserInGroup(dataGroup, true);

        /* create a plate */

        init(plateOwner);
        Plate plate = mmFactory.createPlate(2, 2, 1, 1, false);
        plate = (Plate) iUpdate.saveAndReturnObject(plate).proxy();
        final long plateId = plate.getId().getValue();

        /* find the plate's images */

        final List<Long> imageIds = new ArrayList<Long>();
        final String hql = "SELECT image.id FROM WellSample where well.id IN (SELECT id FROM Well WHERE plate.id = :id)";
        final Parameters params = new ParametersI().addId(plateId);
        for (final List<RType> result : iQuery.projection(hql, params)) {
            final Long imageId = ((RLong) result.get(0)).getValue();
            imageIds.add(imageId);
        }

        /* the images should be owned by the dataset owner */

        logRootIntoGroup(dataGroupId);
        final Experimenter datasetOwnerActual = new ExperimenterI(datasetOwner.userId, false);
        final List<IObject> images = iQuery.findAllByQuery("FROM Image WHERE id IN (:ids)", new ParametersI().addIds(imageIds));
        Assert.assertEquals(images.size(), imageIds.size());
        for (final IObject image : images) {
            image.getDetails().setOwner(datasetOwnerActual);
        }
        iUpdate.saveCollection(images);

        /* create the dataset and link the images to it */

        init(datasetOwner);
        final Dataset dataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset()).proxy();
        final long datasetId = dataset.getId().getValue();

        final List<DatasetImageLink> links = new ArrayList<DatasetImageLink>(images.size());
        for (final IObject image : images) {
            DatasetImageLink link = new DatasetImageLinkI();
            link.setParent(dataset);
            link.setChild((Image) image.proxy());
            links.add((DatasetImageLink) iUpdate.saveAndReturnObject(link).proxy());
        }

        /* perform the chmod */

        final boolean isExpectSuccess = !"rw----".equals(toPerms);

        init(chmodder);
        final Chmod2 chmod = Requests.chmod().target(dataGroup).toPerms(toPerms).build();
        doChange(client, factory, chmod, isExpectSuccess);

        logRootIntoGroup(dataGroupId);

        if (isExpectSuccess) {

            /* check that all the objects still exist */

            assertExists(dataset);
            assertAllExist(images);
            assertAllExist(links);
            assertExists(plate);
        }

        /* delete the objects as clean-up */

        final Delete2 delete = new Delete2();
        delete.targetObjects = ImmutableMap.of(
                "Dataset", Collections.singletonList(datasetId),
                "Plate", Collections.singletonList(plateId));
        doChange(client, factory, delete, true);
    }

    /**
     * @return group permissions for private-group failure test cases
     */
    @DataProvider(name = "private-group failure test cases")
    public Object[][] providePrivateGroupFailureCases() {
        int index = 0;
        final int GROUP_PERMS = index++;

        final String[] permsCases = new String[]{"rw----", "rwr---", "rwra--", "rwrw--"};

        final List<Object[]> testCases = new ArrayList<Object[]>();

        for (final String groupPerms : permsCases) {
            final Object[] testCase = new Object[index];
            testCase[GROUP_PERMS] = groupPerms;
            // DEBUG: if ("rwr---".equals(groupPerms))
            testCases.add(testCase);
        }

        return testCases.toArray(new Object[testCases.size()][]);
    }
}
