Add Additional tests to WindowsFileDelegateTest

This adds tests for WindowsFileDelegate.getDfsShareAclView()
and WindowsFileDelegate.getDfsUncActiveStorageUnc() using
JNA fakes to simulate the Netapi32Ex DFS calls.

This brings the WindowsFileDelegate up to 88% coverage and the
adaptor as a whole to 93% line coverage and 88% branch coverage.

Code Review: http://codereview.appspot.com/90470043
diff --git a/src/com/google/enterprise/adaptor/fs/WinApi.java b/src/com/google/enterprise/adaptor/fs/WinApi.java
index b0e5f61..4e2eeae 100644
--- a/src/com/google/enterprise/adaptor/fs/WinApi.java
+++ b/src/com/google/enterprise/adaptor/fs/WinApi.java
@@ -102,6 +102,9 @@
       public Pointer Storage;
       protected DFS_STORAGE_INFO[] StorageInfos;
   
+      public DFS_INFO_3() {
+      }
+
       public DFS_INFO_3(Pointer m) {
         useMemory(m);
         read();
@@ -146,6 +149,9 @@
       public WString ServerName;
       public WString ShareName;
   
+      public DFS_STORAGE_INFO() {
+      }
+
       public DFS_STORAGE_INFO(Pointer m) {
         useMemory(m);
         read();
diff --git a/src/com/google/enterprise/adaptor/fs/WindowsFileDelegate.java b/src/com/google/enterprise/adaptor/fs/WindowsFileDelegate.java
index b2356af..ff23659 100644
--- a/src/com/google/enterprise/adaptor/fs/WindowsFileDelegate.java
+++ b/src/com/google/enterprise/adaptor/fs/WindowsFileDelegate.java
@@ -151,7 +151,7 @@
             ace = new WinNT.ACCESS_DENIED_ACE(share);
             break;
           default:
-            throw new IllegalArgumentException("Unknwon ACE type " +
+            throw new IllegalArgumentException("Unsupported ACE type " +
                 aceType);
         }
         ACEs[i] = ace;
diff --git a/test/com/google/enterprise/adaptor/fs/TestWindowsAclViews.java b/test/com/google/enterprise/adaptor/fs/TestWindowsAclViews.java
index 86ce7c8..478593d 100644
--- a/test/com/google/enterprise/adaptor/fs/TestWindowsAclViews.java
+++ b/test/com/google/enterprise/adaptor/fs/TestWindowsAclViews.java
@@ -73,8 +73,8 @@
    * This byte buffer is suitable for reading back via 
    * <code>new WinNT.SECURITY_DESCRIPTOR_RELATIVE(Memory)</code>.
    */
-  protected final byte[] buildDaclMemory(WinNT.ACCESS_ACEStructure... aces)
-      throws Exception {
+  protected static final byte[] buildDaclMemory(
+      WinNT.ACCESS_ACEStructure... aces) throws Exception {
     WinNT.ACL acl = new WinNT.ACL();
     WinNT.SECURITY_DESCRIPTOR_RELATIVE securityDescriptor =
         new WinNT.SECURITY_DESCRIPTOR_RELATIVE();
diff --git a/test/com/google/enterprise/adaptor/fs/WindowsFileDelegateTest.java b/test/com/google/enterprise/adaptor/fs/WindowsFileDelegateTest.java
index ca2c3bf..d855c72 100644
--- a/test/com/google/enterprise/adaptor/fs/WindowsFileDelegateTest.java
+++ b/test/com/google/enterprise/adaptor/fs/WindowsFileDelegateTest.java
@@ -14,19 +14,40 @@
 
 package com.google.enterprise.adaptor.fs;
 
+import static com.google.enterprise.adaptor.fs.AclView.user;
+import static com.google.enterprise.adaptor.fs.AclView.group;
+import static com.google.enterprise.adaptor.fs.AclView.GenericPermission.*;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+import static java.nio.file.attribute.AclEntryFlag.*;
+import static java.nio.file.attribute.AclEntryPermission.*;
+import static java.nio.file.attribute.AclEntryType.*;
+
 import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
 import com.google.common.io.CharStreams;
 import com.google.enterprise.adaptor.Acl;
 import com.google.enterprise.adaptor.DocIdPusher;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import com.google.enterprise.adaptor.fs.WinApi.Netapi32Ex;
 
 import org.junit.*;
 import org.junit.rules.ExpectedException;
 
+import com.sun.jna.Memory;
+import com.sun.jna.Pointer;
+import com.sun.jna.WString;
+import com.sun.jna.platform.win32.LMErr;
+import com.sun.jna.platform.win32.Win32Exception;
+import com.sun.jna.platform.win32.WinError;
+import com.sun.jna.platform.win32.WinNT;
+import com.sun.jna.platform.win32.WinDef.DWORD;
+import com.sun.jna.platform.win32.WinDef.ULONG;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -68,6 +89,217 @@
   }
 
   @Test
+  public void testGetDfsShareAclView() throws Exception {
+    // The *_OBJECT_ACE_TYPEs will get filtered out by newAclEntry().
+    AclFileAttributeView expectedAcl = new AclView(
+        group("AccessAllowedAce").type(ALLOW).perms(GENERIC_READ)
+        .flags(FILE_INHERIT, DIRECTORY_INHERIT),
+        user("AccessDeniedAce").type(DENY).perms(GENERIC_READ)
+        .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+
+    AclFileAttributeView aclView = getDfsShareAclView(
+        new AceBuilder()
+        .setSid(AccountSid.group("AccessAllowedAce", null))
+        .setType(WinNT.ACCESS_ALLOWED_ACE_TYPE)
+        .setPerms(WinNT.GENERIC_READ)
+        .setFlags(WinNT.OBJECT_INHERIT_ACE, WinNT.CONTAINER_INHERIT_ACE)
+        .build(),
+        new AceBuilder()
+        .setSid(AccountSid.user("AccessAllowedObjectAce", null))
+        .setType(WinNT.ACCESS_ALLOWED_OBJECT_ACE_TYPE)
+        .setPerms(WinNT.GENERIC_ALL)
+        .setFlags(WinNT.OBJECT_INHERIT_ACE)
+        .build(),
+        new AceBuilder()
+        .setSid(AccountSid.user("AccessDeniedAce", null))
+        .setType(WinNT.ACCESS_DENIED_ACE_TYPE)
+        .setPerms(WinNT.GENERIC_READ)
+        .setFlags(WinNT.OBJECT_INHERIT_ACE, WinNT.CONTAINER_INHERIT_ACE)
+        .build(),
+        new AceBuilder()
+        .setSid(AccountSid.group("AccessDeniedObjectAce", null))
+        .setType(WinNT.ACCESS_DENIED_OBJECT_ACE_TYPE)
+        .setPerms(WinNT.GENERIC_ALL)
+        .setFlags(WinNT.OBJECT_INHERIT_ACE)
+        .build());
+
+    assertNotNull(aclView);
+    assertEquals(expectedAcl.getAcl(), aclView.getAcl());
+  }
+
+  @Test
+  public void testGetDfsShareAclViewUnsupportedAceType() throws Exception {
+    thrown.expect(IllegalArgumentException.class);
+    AclFileAttributeView aclView = getDfsShareAclView(
+        new AceBuilder()
+        .setSid(AccountSid.group("SystemAuditAce", null))
+        .setType(WinNT.SYSTEM_AUDIT_ACE_TYPE)
+        .setPerms(WinNT.GENERIC_ALL)
+        .setFlags(WinNT.OBJECT_INHERIT_ACE, WinNT.CONTAINER_INHERIT_ACE)
+        .build());
+  }
+
+  private static AclFileAttributeView getDfsShareAclView(
+      WinNT.ACCESS_ACEStructure... aces) throws Exception {
+    byte[] dacl = buildDaclMemory(aces);
+    final Memory memory = new Memory(dacl.length);
+    memory.write(0, dacl, 0, dacl.length);
+
+    Netapi32Ex netapi = new UnsupportedNetapi32() {
+        @Override
+        public int NetDfsGetSecurity(String dfsPath, int securityInfo,
+            PointerByReference bufptr, IntByReference bufsz) {
+          bufptr.setValue(memory);
+          bufsz.setValue((int)(memory.size()));
+          return WinError.ERROR_SUCCESS;
+        }
+        @Override
+        public int NetApiBufferFree(Pointer buf) {
+          return WinError.ERROR_SUCCESS;
+        }
+      };
+
+    WindowsAclFileAttributeViews wafav =
+        new TestAclFileAttributeViews(null, null, null, netapi, null);
+    WindowsFileDelegate delegate = new WindowsFileDelegate(null, netapi, wafav);
+
+    return delegate.getDfsShareAclView(Paths.get("\\\\host\\share"));
+  }
+
+  @Test
+  public void testGetDfsShareAclViewError() throws Exception {
+    Netapi32Ex netapi = new UnsupportedNetapi32() {
+        @Override
+        public int NetDfsGetSecurity(String dfsPath, int securityInfo,
+            PointerByReference bufptr, IntByReference bufsz) {
+          return WinError.ERROR_ACCESS_DENIED;
+        }
+        @Override
+        public int NetApiBufferFree(Pointer buf) {
+          return WinError.ERROR_SUCCESS;
+        }
+      };
+
+    WindowsAclFileAttributeViews wafav =
+        new TestAclFileAttributeViews(null, null, null, netapi, null);
+    WindowsFileDelegate delegate = new WindowsFileDelegate(null, netapi, wafav);
+
+    thrown.expect(Win32Exception.class);
+    delegate.getDfsShareAclView(Paths.get("\\\\host\\share"));
+  }
+
+  @Test
+  public void testGetDfsUncActiveStorageUncError() throws Exception {
+    Netapi32Ex netapi = new UnsupportedNetapi32() {
+        @Override
+        public int NetDfsGetInfo(String dfsPath, String server, String share,
+            int level, PointerByReference bufptr) {
+          return WinError.ERROR_ACCESS_DENIED;
+        }
+      };
+    assertNull(getDfsUncActiveStorageUnc(netapi));
+  }
+
+  @Test
+  public void testGetDfsUncActiveStorageUncNoStorage() throws Exception {
+    final Netapi32Ex.DFS_INFO_3 info = new Netapi32Ex.DFS_INFO_3();
+    info.NumberOfStorages = new DWORD(0);
+    info.Storage = new Memory(1);	// Cannot supply length of 0.
+    info.write();
+
+    thrown.expect(IOException.class);
+    getDfsUncActiveStorageUnc(info);
+  }
+
+  @Test
+  public void testGetDfsUncActiveStorageUncSingleActiveStorage()
+      throws Exception {
+    Netapi32Ex.DFS_STORAGE_INFO storeInfo = new Netapi32Ex.DFS_STORAGE_INFO();
+    storeInfo.State = new ULONG(Netapi32Ex.DFS_STORAGE_STATE_ONLINE);
+    storeInfo.ServerName = new WString("server");
+    storeInfo.ShareName = new WString("share");
+    storeInfo.write();
+
+    final Netapi32Ex.DFS_INFO_3 info = new Netapi32Ex.DFS_INFO_3();
+    info.NumberOfStorages = new DWORD(1);
+    info.Storage = storeInfo.getPointer();
+    info.write();
+
+    assertEquals(Paths.get("\\\\server\\share"),
+                 getDfsUncActiveStorageUnc(info));
+  }
+
+  @Test
+  public void testGetDfsUncActiveStorageUncNoActiveStorage() throws Exception {
+    Netapi32Ex.DFS_STORAGE_INFO storeInfo = new Netapi32Ex.DFS_STORAGE_INFO();
+    storeInfo.State = new ULONG(0);
+    storeInfo.ServerName = new WString("server");
+    storeInfo.ShareName = new WString("share");
+    storeInfo.write();
+
+    final Netapi32Ex.DFS_INFO_3 info = new Netapi32Ex.DFS_INFO_3();
+    info.NumberOfStorages = new DWORD(1);
+    info.Storage = storeInfo.getPointer();
+    info.write();
+
+    thrown.expect(IOException.class);
+    getDfsUncActiveStorageUnc(info);
+  }
+
+  @Test
+  public void testGetDfsUncActiveStorageUncSomeActiveStorage()
+      throws Exception {
+    Netapi32Ex.DFS_STORAGE_INFO[] storeInfos = (Netapi32Ex.DFS_STORAGE_INFO[])
+        new Netapi32Ex.DFS_STORAGE_INFO().toArray(3);
+    storeInfos[0].State = new ULONG(0);
+    storeInfos[0].ServerName = new WString("inactive");
+    storeInfos[0].ShareName = new WString("inactive");
+    storeInfos[0].write();
+    // The first active storage should be returned.
+    storeInfos[1].State = new ULONG(Netapi32Ex.DFS_STORAGE_STATE_ONLINE);
+    storeInfos[1].ServerName = new WString("server");
+    storeInfos[1].ShareName = new WString("share");
+    storeInfos[1].write();
+    storeInfos[2].State = new ULONG(Netapi32Ex.DFS_STORAGE_STATE_ONLINE);
+    storeInfos[2].ServerName = new WString("active");
+    storeInfos[2].ShareName = new WString("active");
+    storeInfos[2].write();
+
+    final Netapi32Ex.DFS_INFO_3 info = new Netapi32Ex.DFS_INFO_3();
+    info.NumberOfStorages = new DWORD(3);
+    info.Storage = storeInfos[0].getPointer();
+    info.write();
+
+    assertEquals(Paths.get("\\\\server\\share"),
+                 getDfsUncActiveStorageUnc(info));
+  }
+
+  private static Path getDfsUncActiveStorageUnc(
+      final Netapi32Ex.DFS_INFO_3 info) throws Exception {
+    Netapi32Ex netapi = new UnsupportedNetapi32() {
+        @Override
+        public int NetDfsGetInfo(String dfsPath, String server, String share,
+            int level, PointerByReference bufptr) {
+          bufptr.setValue(info.getPointer());
+          return LMErr.NERR_Success;
+        }
+        @Override
+        public int NetApiBufferFree(Pointer buf) {
+          return WinError.ERROR_SUCCESS;
+        }
+      };
+
+    return getDfsUncActiveStorageUnc(netapi);
+  }
+
+  private static Path getDfsUncActiveStorageUnc(Netapi32Ex netapi)
+      throws Exception {
+    WindowsFileDelegate delegate = new WindowsFileDelegate(null, netapi, null);
+    Path dfsPath = Paths.get("\\\\host\\share");
+    return delegate.getDfsUncActiveStorageUnc(dfsPath);
+  }
+
+  @Test
   public void testNewDocIdLocalFiles() throws Exception {
     Path dir = newTempDir("testDir");
     Path file = newTempFile(dir, "test");