diff --git a/src/main/java/org/ultramine/permission/NegativePermission.java b/src/main/java/org/ultramine/permission/NegativePermission.java index 0aaeed1..ce6f72e 100644 --- a/src/main/java/org/ultramine/permission/NegativePermission.java +++ b/src/main/java/org/ultramine/permission/NegativePermission.java @@ -10,14 +10,7 @@ { this.permission = permission; this.resolver = PermissionResolver.createInverted(permission.getPermissions()); - this.isChangeable = false; - } - - public NegativePermission(IChangeablePermission permission) - { - this.permission = permission; - this.resolver = PermissionResolver.createInverted(permission.getPermissions()); - this.isChangeable = true; + this.isChangeable = permission instanceof IChangeablePermission; } @Override diff --git a/src/main/java/org/ultramine/permission/PermissionRepository.java b/src/main/java/org/ultramine/permission/PermissionRepository.java index f04de7b..e8bdcab 100644 --- a/src/main/java/org/ultramine/permission/PermissionRepository.java +++ b/src/main/java/org/ultramine/permission/PermissionRepository.java @@ -25,22 +25,26 @@ throw new IllegalArgumentException("Permission already registered"); ProxyPermission proxy = getPermission(permission.getKey()); - proxy.linkPermission(permission); + if (permission instanceof IChangeablePermission) + proxy.linkChangeable((IChangeablePermission)permission); + else + proxy.linkSimple(permission); + permissions.put(permission.getKey(), permission); } - public class ProxyPermission implements IChangeablePermission + public static class ProxyPermission implements IChangeablePermission { private String key; private IPermission wrappedPermission; - private boolean changeable; + private ProxyType proxyType; private List listeners = new ArrayList(); private ProxyPermission(String key) { this.key = key; this.wrappedPermission = new Permission(key); - this.changeable = false; + this.proxyType = ProxyType.DUMMY; } @Override @@ -54,9 +58,9 @@ return wrappedPermission; } - public boolean isChangeable() + public ProxyType getType() { - return changeable; + return proxyType; } @Override @@ -92,36 +96,47 @@ @Override public boolean isDirty() { - return changeable && ((IChangeablePermission)wrappedPermission).isDirty(); + return (proxyType == ProxyType.CHANGEABLE) && ((IChangeablePermission)wrappedPermission).isDirty(); } @Override public void subscribe(IDirtyListener listener) { - if (changeable) - ((IChangeablePermission)wrappedPermission).subscribe(listener); - else - listeners.add(listener); + switch (proxyType) + { + case CHANGEABLE: + ((IChangeablePermission)wrappedPermission).subscribe(listener); + break; + case DUMMY: + listeners.add(listener); + break; + } } @Override public void unsubscribe(IDirtyListener listener) { - if (changeable) - ((IChangeablePermission)wrappedPermission).unsubscribe(listener); - else - listeners.remove(listener); + switch (proxyType) + { + case CHANGEABLE: + ((IChangeablePermission)wrappedPermission).unsubscribe(listener); + break; + case DUMMY: + listeners.remove(listener); + break; + } } - private void linkPermission(IPermission permission) + private void linkSimple(IPermission permission) { wrappedPermission = permission; for (IDirtyListener listener : listeners) listener.makeDirty(); listeners.clear(); + proxyType = ProxyType.SIMPLE; } - private void linkPermission(IChangeablePermission permission) + private void linkChangeable(IChangeablePermission permission) { wrappedPermission = permission; for (IDirtyListener listener : listeners) @@ -130,7 +145,7 @@ listener.makeDirty(); } listeners.clear(); - this.changeable = true; + proxyType = ProxyType.CHANGEABLE; } @Override @@ -150,5 +165,7 @@ { return wrappedPermission.toString(); } + + public static enum ProxyType { DUMMY, SIMPLE, CHANGEABLE } } } diff --git a/src/test/groovy/org/ultramine/permission/PermissionRepositoryTest.groovy b/src/test/groovy/org/ultramine/permission/PermissionRepositoryTest.groovy new file mode 100644 index 0000000..62f72e0 --- /dev/null +++ b/src/test/groovy/org/ultramine/permission/PermissionRepositoryTest.groovy @@ -0,0 +1,144 @@ +package org.ultramine.permission + +import org.spockframework.mock.MockDetector +import spock.lang.Specification + +import static org.ultramine.permission.PermissionRepository.ProxyPermission.ProxyType.* + +class PermissionRepositoryTest extends Specification { + + def "Test get proxy permission permission"() { + setup: + def detector = new MockDetector() + def perm = Mock(IPermission) { + getKey() >> "key" + getName() >> "test" + } + def repository = new PermissionRepository() + + when: "Try to get not registered permission" + def proxy = repository.getPermission("key") + + then: "Returned proxy of dummy permission" + proxy.getWrappedPermission().class == Permission + proxy.getType() == DUMMY + proxy.getName() == "key" + + when: "Register this permission" + repository.registerPermission(perm) + + then: "Proxy linked to added permission" + detector.isMock(proxy.getWrappedPermission()) + proxy.getType() != DUMMY + proxy.getName() == "test" + } + + def "Test registration of existed permission"() { + setup: + def repository = new PermissionRepository() + + when: "Register permission same key twice" + repository.registerPermission(Mock(IPermission) { getKey() >> "key"; getName() >> "1" }) + repository.registerPermission(Mock(IPermission) { getKey() >> "key"; getName() >> "2" }) + + then: "Exception is thrown" + thrown(IllegalArgumentException) + + and: "First permission is not overwritten" + repository.getPermission("key").getName() == "1" + } + + def "Test proxy of IPermission"() { + setup: + def listener = Mock(IDirtyListener) + def perm = Mock(IPermission) { getKey() >> "key" } + def repository = new PermissionRepository() + + when: "Listener is subscribed to proxy permission" + def proxy = repository.getPermission("key") + proxy.subscribe(listener) + + and: "And IPermission is registered" + repository.registerPermission(perm) + + then: "Listener is notified" + 1 * listener.makeDirty() + + and: "Proxy type is SIMPLE" + proxy.getType() == SIMPLE + + when: "Add another lister" + proxy.subscribe(Mock(IDirtyListener)) + + then: "noting is happened" + 0 * perm._ + } + + def "Test proxy of IChangeablePermission"() { + setup: + def listener = Mock(IDirtyListener) + def perm = Mock(IChangeablePermission) { getKey() >> "key" } + def repository = new PermissionRepository() + + when: "Listener is subscribed to proxy permission" + def proxy = repository.getPermission("key") + proxy.subscribe(listener) + + and: "And IPermission is registered" + repository.registerPermission(perm) + + then: "Listener is notified" + 1 * listener.makeDirty() + + and: "Proxy type is CHANGEABLE" + proxy.getType() == CHANGEABLE + + and: "Listener is passed to permission" + 1 * perm.subscribe(listener) + + when: "Add another lister" + proxy.subscribe(Mock(IDirtyListener)) + + then: "Listener is added to permission" + 1 * perm.subscribe(_) + + when: "Remove listener" + proxy.unsubscribe(listener) + + then: "Listener is removed from permission" + 1 * perm.unsubscribe(listener) + } + + def "Test proxy unsubscribe"() { + setup: + def listener = Mock(IDirtyListener) + def perm = Mock(IChangeablePermission) { getKey() >> "key" } + def repository = new PermissionRepository() + + when: "Listener is subscribed and unsubscribe to proxy permission" + def proxy = repository.getPermission("key") + proxy.subscribe(listener) + proxy.unsubscribe(listener) + + and: "And IPermission is registered" + repository.registerPermission(perm) + + then: "0 listener passed to proxy" + 0 * perm.subscribe(_) + } + + def "Test proxy isDirty"() { + setup: + def repository = new PermissionRepository() + repository.registerPermission(Mock(IPermission) { getKey() >> "s" }) + repository.registerPermission(Mock(IChangeablePermission) { getKey() >> "c"; isDirty() >>> [true, false] }) + + expect: "DUMMY and SIMPLE proxies are not dirty" + !repository.getPermission("d").isDirty() + !repository.getPermission("s").isDirty() + + and: "CHANGEABLE proxy dirty check delegated to wrapped permission" + repository.getPermission("c").isDirty() + !repository.getPermission("c").isDirty() + } +}