public void Test_RelationshipInstance(string action, string fromPerms, string toPerms, Direction direction, bool saveBothEnds, bool haveFieldChanges, bool expectAllow)
        {
            if (fromPerms == "modify")
            {
                fromPerms = "read,modify";
            }
            if (toPerms == "modify")
            {
                toPerms = "read,modify";
            }

            // Create schema
            EntityType fromType = new EntityType();

            fromType.Inherits.Add(UserResource.UserResource_Type);
            fromType.Name = Guid.NewGuid().ToString();
            fromType.Save();

            EntityType toType = new EntityType();

            toType.Inherits.Add(UserResource.UserResource_Type);
            toType.Name = Guid.NewGuid().ToString();
            toType.Save();

            Relationship rel = new Relationship();

            rel.Name             = Guid.NewGuid().ToString();
            rel.FromType         = fromType;
            rel.ToType           = toType;
            rel.Cardinality_Enum = CardinalityEnum_Enumeration.ManyToMany;
            rel.Save();

            // Create data
            IEntity toInst = new Entity(toType);

            toInst.Save();
            IEntity fromInst = new Entity(fromType);

            if (action != "Create")
            {
                fromInst.SetRelationships(rel, new EntityRelationshipCollection <IEntity> {
                    toInst
                });
            }
            fromInst.Save();

            // Create test user
            UserAccount userAccount = Entity.Create <UserAccount>();

            userAccount.Name = Guid.NewGuid().ToString();
            userAccount.Save();

            // Grant access
            if (!string.IsNullOrEmpty(fromPerms))
            {
                new AccessRuleFactory().AddAllowByQuery(
                    userAccount.As <Subject>(),
                    fromType.As <SecurableEntity>(),
                    fromPerms.Split(',').Select(pa => new EntityRef(pa)),
                    TestQueries.Entities().ToReport());
            }
            if (!string.IsNullOrEmpty(toPerms))
            {
                new AccessRuleFactory().AddAllowByQuery(
                    userAccount.As <Subject>(),
                    toType.As <SecurableEntity>(),
                    toPerms.Split(',').Select(pa => new EntityRef(pa)),
                    TestQueries.Entities().ToReport());
            }

            // Test

            bool allowed = false;

            try
            {
                using (new SetUser(userAccount))
                {
                    IEntity source = Entity.Get(direction == Direction.Forward ? fromInst.Id : toInst.Id);
                    if (action != "Read")
                    {
                        source = source.AsWritable();
                    }
                    Func <IEntity> target = () => Entity.Get(direction == Direction.Forward ? toInst.Id : fromInst.Id);

                    IEntityRelationshipCollection <IEntity> relCol = null;

                    switch (action)
                    {
                    case "Read":
                        relCol = source.GetRelationships(rel.Id, direction);
                        IEntity entity = relCol.FirstOrDefault();
                        allowed = entity != null;
                        break;

                    case "Create":
                        relCol = new EntityRelationshipCollection <IEntity> {
                            target()
                        };
                        source.SetRelationships(rel, relCol);
                        if (haveFieldChanges)
                        {
                            source.SetField("core:name", Guid.NewGuid().ToString());
                        }
                        if (saveBothEnds)
                        {
                            Entity.Save(new[] { source, target() });
                        }
                        else
                        {
                            source.Save();
                        }
                        allowed = true;
                        break;

                    case "Remove":
                        relCol = source.GetRelationships(rel.Id, direction);
                        relCol.Remove(target());
                        source.SetRelationships(rel, relCol);
                        if (haveFieldChanges)
                        {
                            source.SetField("core:name", Guid.NewGuid().ToString());
                        }
                        if (saveBothEnds)
                        {
                            Entity.Save(new[] { source, target() });
                        }
                        else
                        {
                            source.Save();
                        }
                        allowed = true;
                        break;

                    case "Clear":
                        relCol = source.GetRelationships(rel.Id, direction);
                        relCol.Clear();
                        source.SetRelationships(rel, relCol);
                        if (haveFieldChanges)
                        {
                            source.SetField("core:name", Guid.NewGuid().ToString());
                        }
                        if (saveBothEnds)
                        {
                            Entity.Save(new[] { source, target() });
                        }
                        else
                        {
                            source.Save();
                        }
                        allowed = true;
                        break;

                    default:
                        throw new InvalidOperationException("Unknown " + action);
                    }
                }
                Assert.That(allowed, Is.EqualTo(expectAllow));
            }
            catch (PlatformSecurityException)
            {
                Assert.That(false, Is.EqualTo(expectAllow));
            }
        }