ome.services.blitz.test.utests.FilePathRestrictionsTest.java Source code

Java tutorial

Introduction

Here is the source code for ome.services.blitz.test.utests.FilePathRestrictionsTest.java

Source

/*
 * Copyright (C) 2013 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 ome.services.blitz.test.utests;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import ome.services.blitz.repo.path.FilePathRestrictions;

import org.apache.commons.collections.CollectionUtils;
import org.testng.Assert;
import org.testng.annotations.Test;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;

/**
 * @author m.t.b.carroll@dundee.ac.uk
 * @since 5.0
 */

@Test(groups = { "fs" })
public class FilePathRestrictionsTest {

    /**
     * Test that an empty rule set cannot be combined.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testCombineNoRules() {
        FilePathRestrictions.combineFilePathRestrictions();
    }

    /**
     * Test that one may with rule sets created with mostly nulls.
     */
    @Test
    public void testNullSafety() {
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(null, null, null, null, ImmutableSet.of('A')));
    }

    /**
     * Test that rule sets may be combined if they have safe characters in common.
     */
    @Test
    public void testCombineSafeCharacters() {
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(null, null, null, null, ImmutableSet.of('A', 'B')),
                new FilePathRestrictions(null, null, null, null, ImmutableSet.of('B', 'C')));
    }

    /**
     * Test that rule sets may not be combined if they do not have safe characters in common.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testCombineNoSafeCharacters() {
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(null, null, null, null, ImmutableSet.of('A', 'B')),
                new FilePathRestrictions(null, null, null, null, ImmutableSet.of('C', 'D')));
    }

    /**
     * Test that rule sets may be combined if their mappings have safe characters in common.
     */
    @Test
    public void testCombineTransformation() {
        final SetMultimap<Integer, Integer> transformationMatrixX = HashMultimap.create();
        transformationMatrixX.put(0, 65);
        transformationMatrixX.put(0, 66);
        final SetMultimap<Integer, Integer> transformationMatrixY = HashMultimap.create();
        transformationMatrixY.put(0, 66);
        transformationMatrixY.put(0, 67);
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(transformationMatrixX, null, null, null, ImmutableSet.of('A')),
                new FilePathRestrictions(transformationMatrixY, null, null, null, ImmutableSet.of('A')));
    }

    /**
     * Test that rule sets may not be combined if their mappings have only unsafe characters in common.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testCombineUnsafeTransformation() {
        final SetMultimap<Integer, Integer> transformationMatrixX = HashMultimap.create();
        transformationMatrixX.put(0, 65);
        transformationMatrixX.put(0, 1);
        final SetMultimap<Integer, Integer> transformationMatrixY = HashMultimap.create();
        transformationMatrixY.put(0, 1);
        transformationMatrixY.put(0, 66);
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(transformationMatrixX, null, null, null, ImmutableSet.of('A')),
                new FilePathRestrictions(transformationMatrixY, null, null, null, ImmutableSet.of('A')));
    }

    /**
     * Test that rule sets may not be combined if their mappings have no safe characters in common.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testCombineNoTransformation() {
        final SetMultimap<Integer, Integer> transformationMatrixX = HashMultimap.create();
        transformationMatrixX.put(0, 65);
        transformationMatrixX.put(0, 66);
        final SetMultimap<Integer, Integer> transformationMatrixY = HashMultimap.create();
        transformationMatrixY.put(0, 67);
        transformationMatrixY.put(0, 68);
        FilePathRestrictions.combineFilePathRestrictions(
                new FilePathRestrictions(transformationMatrixX, null, null, null, ImmutableSet.of('A')),
                new FilePathRestrictions(transformationMatrixY, null, null, null, ImmutableSet.of('A')));
    }

    /**
     * Assert that an actual multimap is as expected regardless of order.
     * @param actual the actual value
     * @param expected the expected value
     */
    private void assertEqualMultimaps(Multimap<Integer, Integer> actual, Multimap<Integer, Integer> expected) {
        Assert.assertTrue(CollectionUtils.isEqualCollection(actual.keySet(), expected.keySet()));
        for (final Integer key : expected.keySet()) {
            Assert.assertTrue(CollectionUtils.isEqualCollection(actual.get(key), expected.get(key)));
        }
    }

    /**
     * Test that two complex sets of rules combined as expected.
     * (On a rainy day this test could be broken up into several smaller tests.)
     */
    @Test
    public void testCombineRules() {
        /* these variables define the X set of rules to combine */

        final SetMultimap<Integer, Integer> transformationMatrixX = HashMultimap.create();
        final Set<String> unsafePrefixesX = new HashSet<String>();
        final Set<String> unsafeSuffixesX = new HashSet<String>();
        final Set<String> unsafeNamesX = new HashSet<String>();
        final Set<Character> safeCharactersX = new HashSet<Character>();

        /* these variables define the Y set of rules to combine */

        final SetMultimap<Integer, Integer> transformationMatrixY = HashMultimap.create();
        final Set<String> unsafePrefixesY = new HashSet<String>();
        final Set<String> unsafeSuffixesY = new HashSet<String>();
        final Set<String> unsafeNamesY = new HashSet<String>();
        final Set<Character> safeCharactersY = new HashSet<Character>();

        /* these variables define the expected result of combining X and Y */

        final SetMultimap<Integer, Integer> transformationMatrixXY = HashMultimap.create();
        final Set<String> unsafePrefixesXY = new HashSet<String>();
        final Set<String> unsafeSuffixesXY = new HashSet<String>();
        final Set<String> unsafeNamesXY = new HashSet<String>();
        final Set<Character> safeCharactersXY = new HashSet<Character>();

        /* automatically map control characters to the safe characters;
         * we will remove and replace any that are to be tested specially */

        for (int codePoint = 0; codePoint < 0x100; codePoint++) {
            if (Character.getType(codePoint) == Character.CONTROL) {
                transformationMatrixXY.put(codePoint, 65);
            }
        }

        /* choose four control characters and remove them from the transformation matrix */

        final Iterator<Integer> controlCodePointIterator = transformationMatrixXY.keySet().iterator();
        final int controlCharacterP = controlCodePointIterator.next();
        final int controlCharacterQ = controlCodePointIterator.next();
        final int controlCharacterR = controlCodePointIterator.next();
        final int controlCharacterS = controlCodePointIterator.next();

        transformationMatrixXY.removeAll(controlCharacterP);
        transformationMatrixXY.removeAll(controlCharacterQ);
        transformationMatrixXY.removeAll(controlCharacterR);
        transformationMatrixXY.removeAll(controlCharacterS);

        /* set up test case for combining control character mappings */

        transformationMatrixX.put(controlCharacterP, 65);
        transformationMatrixX.put(controlCharacterP, 67);
        transformationMatrixX.put(controlCharacterQ, 65);
        transformationMatrixX.put(controlCharacterQ, 66);
        transformationMatrixX.put(controlCharacterR, 66);

        transformationMatrixY.put(controlCharacterQ, 66);
        transformationMatrixY.put(controlCharacterR, 66);
        transformationMatrixY.put(controlCharacterS, 68);

        transformationMatrixXY.put(controlCharacterP, 65);
        transformationMatrixXY.put(controlCharacterP, 67);
        transformationMatrixXY.put(controlCharacterQ, 66);
        transformationMatrixXY.put(controlCharacterR, 66);
        transformationMatrixXY.put(controlCharacterS, 68);

        /* choose four non-control characters and remove them from the transformation matrix */

        int[] normalCodePoints = new int[4];
        int index = 0;
        int codePoint = 0;
        while (index < normalCodePoints.length) {
            if (Character.getType(codePoint) != Character.CONTROL) {
                normalCodePoints[index++] = codePoint;
                transformationMatrixXY.removeAll(codePoint);
            }
            codePoint++;
        }
        int normalCharacterP = normalCodePoints[0];
        int normalCharacterQ = normalCodePoints[1];
        int normalCharacterR = normalCodePoints[2];
        int normalCharacterS = normalCodePoints[3];

        /* set up test case for combining non-control character mappings */

        transformationMatrixX.put(normalCharacterP, 65);
        transformationMatrixX.put(normalCharacterP, 67);
        transformationMatrixX.put(normalCharacterQ, 65);
        transformationMatrixX.put(normalCharacterQ, 66);
        transformationMatrixX.put(normalCharacterR, 66);

        transformationMatrixY.put(normalCharacterQ, 66);
        transformationMatrixY.put(normalCharacterR, 66);
        transformationMatrixY.put(normalCharacterS, 68);

        transformationMatrixXY.put(normalCharacterP, 65);
        transformationMatrixXY.put(normalCharacterP, 67);
        transformationMatrixXY.put(normalCharacterQ, 66);
        transformationMatrixXY.put(normalCharacterR, 66);
        transformationMatrixXY.put(normalCharacterS, 68);

        /* set up test cases for combining proscribed strings */

        unsafePrefixesX.add("XP");
        unsafePrefixesX.add("YP");

        unsafePrefixesY.add("YP");
        unsafePrefixesY.add("ZP");

        unsafePrefixesXY.add("XP");
        unsafePrefixesXY.add("YP");
        unsafePrefixesXY.add("ZP");

        unsafeSuffixesX.add("XS");
        unsafeSuffixesX.add("YS");

        unsafeSuffixesY.add("YS");
        unsafeSuffixesY.add("ZS");

        unsafeSuffixesXY.add("XS");
        unsafeSuffixesXY.add("YS");
        unsafeSuffixesXY.add("ZS");

        unsafeNamesX.add("XN");
        unsafeNamesX.add("YN");

        unsafeNamesY.add("YN");
        unsafeNamesY.add("ZN");

        unsafeNamesXY.add("XN");
        unsafeNamesXY.add("YN");
        unsafeNamesXY.add("ZN");

        /* set up test case for combining safe characters */

        safeCharactersX.add('A');
        safeCharactersX.add('B');

        safeCharactersY.add('A');

        safeCharactersXY.add('A');

        /* perform the combination */

        final FilePathRestrictions rulesX = new FilePathRestrictions(transformationMatrixX, unsafePrefixesX,
                unsafeSuffixesX, unsafeNamesX, safeCharactersX);
        final FilePathRestrictions rulesY = new FilePathRestrictions(transformationMatrixY, unsafePrefixesY,
                unsafeSuffixesY, unsafeNamesY, safeCharactersY);
        final FilePathRestrictions rulesXY = FilePathRestrictions.combineFilePathRestrictions(rulesX, rulesY);

        /* test that the combination is as expected in all respects */

        Assert.assertTrue(CollectionUtils.isEqualCollection(rulesXY.safeCharacters, safeCharactersXY));
        Assert.assertTrue(CollectionUtils.isEqualCollection(rulesXY.unsafePrefixes, unsafePrefixesXY));
        Assert.assertTrue(CollectionUtils.isEqualCollection(rulesXY.unsafeSuffixes, unsafeSuffixesXY));
        Assert.assertTrue(CollectionUtils.isEqualCollection(rulesXY.unsafeNames, unsafeNamesXY));
        assertEqualMultimaps(rulesXY.transformationMatrix, transformationMatrixXY);

        /* given a mapping choice, prefer the safe character */

        Assert.assertEquals((int) rulesXY.transformationMap.get(controlCharacterP), 65);
        Assert.assertEquals((int) rulesXY.transformationMap.get(normalCharacterP), 65);
    }

    /**
     * Test that transformation matrices are transitively closed upon combination.
     */
    @Test
    public void testTransitiveTransformationClosure() {
        final SetMultimap<Integer, Integer> transformationMatrixX = HashMultimap.create();
        final SetMultimap<Integer, Integer> transformationMatrixY = HashMultimap.create();
        final SetMultimap<Integer, Integer> transformationMatrixZ = HashMultimap.create();
        final SetMultimap<Integer, Integer> transformationMatrixXYZ = HashMultimap.create();

        for (int codePoint = 0; codePoint < 0x100; codePoint++) {
            if (Character.getType(codePoint) == Character.CONTROL) {
                transformationMatrixXYZ.put(codePoint, 90);
            }
        }

        /*
         * 65  66
         *       
         *      67   68
         *          
         *      70   69
         */

        transformationMatrixX.put(65, 66);
        transformationMatrixX.put(65, 67);

        transformationMatrixY.put(66, 67);
        transformationMatrixY.put(66, 68);

        transformationMatrixZ.put(67, 70);
        transformationMatrixZ.put(68, 69);

        transformationMatrixXYZ.put(65, 69);
        transformationMatrixXYZ.put(65, 70);
        transformationMatrixXYZ.put(66, 69);
        transformationMatrixXYZ.put(66, 70);
        transformationMatrixXYZ.put(67, 70);
        transformationMatrixXYZ.put(68, 69);

        final Set<Character> safeCharacters = ImmutableSet.of('Z');

        final FilePathRestrictions rulesX = new FilePathRestrictions(transformationMatrixX, null, null, null,
                safeCharacters);
        final FilePathRestrictions rulesY = new FilePathRestrictions(transformationMatrixY, null, null, null,
                safeCharacters);
        final FilePathRestrictions rulesZ = new FilePathRestrictions(transformationMatrixZ, null, null, null,
                safeCharacters);

        final FilePathRestrictions rulesXYZ = FilePathRestrictions.combineFilePathRestrictions(rulesX, rulesY,
                rulesZ);
        assertEqualMultimaps(rulesXYZ.transformationMatrix, transformationMatrixXYZ);

        final FilePathRestrictions rulesZYX = FilePathRestrictions.combineFilePathRestrictions(rulesZ, rulesY,
                rulesX);
        assertEqualMultimaps(rulesZYX.transformationMatrix, transformationMatrixXYZ);
    }

    /**
     * Test that cyclic transformation matrices do not cause an infinite loop.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public void testCyclicTransformationCombination() {
        final SetMultimap<Integer, Integer> transformationMatrix = HashMultimap.create();
        transformationMatrix.put(0, 0);

        final FilePathRestrictions rules = new FilePathRestrictions(transformationMatrix, null, null, null,
                ImmutableSet.of('A'));
        FilePathRestrictions.combineFilePathRestrictions(rules);
    }
}