static PiPreEntry translate(Group group, PiPipeconf pipeconf, Device device)
            throws PiTranslationException {

        checkNotNull(group);

        final List<OutputInstruction> outInstructions = Lists.newArrayList();
        int truncateMaxLen = PiCloneSessionEntry.DO_NOT_TRUNCATE;
        for (GroupBucket bucket : group.buckets().buckets()) {
            int numInstructionsInBucket = bucket.treatment().allInstructions().size();
            List<OutputInstruction> outputs =
                    getInstructions(bucket, Instruction.Type.OUTPUT, OutputInstruction.class);
            List<TruncateInstruction> truncates =
                    getInstructions(bucket, Instruction.Type.TRUNCATE, TruncateInstruction.class);
            if (outputs.size() != 1) {
                throw new PiTranslationException(
                        "support only groups with just one OUTPUT instruction per bucket");
            }
            outInstructions.add(outputs.get(0));
            if (truncates.size() != 0) {
                if (group.type() != GroupDescription.Type.CLONE) {
                    throw new PiTranslationException("only CLONE group support truncate instruction");
                }
                if (truncates.size() != 1) {
                    throw new PiTranslationException(
                            "support only groups with just one TRUNCATE instruction per bucket");
                }
                int truncateInstMaxLen = truncates.get(0).maxLen();
                if (truncateMaxLen != PiCloneSessionEntry.DO_NOT_TRUNCATE &&
                        truncateMaxLen != truncateInstMaxLen) {
                    throw new PiTranslationException("all TRUNCATE instruction must be the same in a CLONE group");
                }
                truncateMaxLen = truncateInstMaxLen;
            } else if (truncateMaxLen != PiCloneSessionEntry.DO_NOT_TRUNCATE) {
                // No truncate instruction found in this bucket, but previous bucket contains one.
                throw new PiTranslationException("all TRUNCATE instruction must be the same in a CLONE group");
            }
            if (numInstructionsInBucket != outputs.size() + truncates.size()) {
                throw new PiTranslationException("bucket contains unsupported instruction(s)");
            }
        }

        switch (group.type()) {
            case ALL:
                return PiMulticastGroupEntry.builder()
                        .withGroupId(group.id().id())
                        .addReplicas(getReplicas(outInstructions, device))
                        .build();
            case CLONE:
                return PiCloneSessionEntry.builder()
                        .withSessionId(group.id().id())
                        .addReplicas(getReplicas(outInstructions, device))
                        .withMaxPacketLengthBytes(truncateMaxLen)
                        .build();
            default:
                throw new PiTranslationException(format(
                        "group type %s not supported", group.type()));
        }
    }
@Test
    public void testInvalidPreGroups() {
        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_ALL_GROUP, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("support only groups with just one OUTPUT instruction per bucket", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_ALL_GROUP_2, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("only CLONE group support truncate instruction", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_ALL_GROUP_3, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("bucket contains unsupported instruction(s)", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_CLONE_GROUP, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("support only groups with just one OUTPUT instruction per bucket", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_CLONE_GROUP_2, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("all TRUNCATE instruction must be the same in a CLONE group", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_CLONE_GROUP_3, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("support only groups with just one TRUNCATE instruction per bucket", ex.getMessage());
        }

        try {
            PiReplicationGroupTranslatorImpl
                    .translate(INVALID_CLONE_GROUP_4, null, null);
            Assert.fail("Did not get expected exception.");
        } catch (PiTranslationException ex) {
            Assert.assertEquals("all TRUNCATE instruction must be the same in a CLONE group", ex.getMessage());
        }
    }