package io.airlift.testing;

import java.io.Closeable;
import java.io.IOException;

import static java.util.Objects.requireNonNull;

public final class Closeables
{
    private Closeables()
    {
    }

    /**
     * @deprecated Usage of this method is discouraged, as it may hide real problems.
     * Use {@link #closeAll(Closeable...)} instead and, if necessary, suppress exceptions
     * explicitly.
     */
    @Deprecated
    public static void closeQuietly(Closeable... closeables)
    {
        if (closeables == null) {
            return;
        }
        for (Closeable closeable : closeables) {
            try {
                if (closeable != null) {
                    closeable.close();
                }
            }
            catch (IOException | RuntimeException ignored) {
            }
        }
    }

    public static void closeAll(Closeable... closeables)
            throws IOException
    {
        if (closeables == null) {
            return;
        }
        IOException rootCause = null;
        for (Closeable closeable : closeables) {
            try {
                if (closeable != null) {
                    closeable.close();
                }
            }
            catch (IOException e) {
                if (rootCause == null) {
                    rootCause = e;
                }
                else if (rootCause != e) {
                    // Self-suppression not permitted
                    rootCause.addSuppressed(e);
                }
            }
            catch (Throwable e) {
                if (rootCause == null) {
                    rootCause = new IOException(e);
                }
                else if (rootCause != e) {
                    // Self-suppression not permitted
                    rootCause.addSuppressed(e);
                }
            }
        }
        if (rootCause != null) {
            throw rootCause;
        }
    }

    public static void closeAllRuntimeException(Closeable... closeables)
    {
        if (closeables == null) {
            return;
        }
        RuntimeException rootCause = null;
        for (Closeable closeable : closeables) {
            try {
                if (closeable != null) {
                    closeable.close();
                }
            }
            catch (Throwable e) {
                if (rootCause == null) {
                    rootCause = new RuntimeException(e);
                }
                else if (rootCause != e) {
                    // Self-suppression not permitted
                    rootCause.addSuppressed(e);
                }
            }
        }
        if (rootCause != null) {
            throw rootCause;
        }
    }

    public static <T extends Throwable> T closeAllSuppress(T rootCause, Closeable... closeables)
    {
        requireNonNull(rootCause, "rootCause is null");
        if (closeables == null) {
            return rootCause;
        }
        for (Closeable closeable : closeables) {
            try {
                if (closeable != null) {
                    closeable.close();
                }
            }
            catch (Throwable e) {
                // Self-suppression not permitted
                if (rootCause != e) {
                    rootCause.addSuppressed(e);
                }
            }
        }
        return rootCause;
    }
}

@@ -77,16 +77,85 @@
 ption;%0A%0A
+import static com.google.common.base.Throwables.propagateIfPossible;%0A
 import s
@@ -1000,52 +1000,229 @@
     
-if (closeables == null) %7B%0A            return
+try %7B%0A            closeAll((AutoCloseable%5B%5D) closeables);%0A        %7D%0A        catch (Exception e) %7B%0A            propagateIfPossible(e, IOException.class);%0A            // Unreachable%0A            throw new RuntimeException(e)
 ;%0A  
@@ -1237,23 +1237,188 @@
     
+%7D%0A%0A
     
-IOException
+public static void closeAll(AutoCloseable... closeables)%0A            throws Exception%0A    %7B%0A        if (closeables == null) %7B%0A            return;%0A        %7D%0A        Throwable
  roo
@@ -1437,32 +1437,36 @@
 l;%0A        for (
+Auto
 Closeable closea
@@ -1634,27 +1634,25 @@
  catch (
-IOException
+Throwable
  e) %7B%0A  
@@ -1932,47 +1932,18 @@
     
-    catch (Throwable e) %7B%0A     
+%7D%0A
         
    i
@@ -1930,35 +1930,32 @@
       %7D%0A        
-   
 if (rootCause ==
@@ -1944,33 +1944,33 @@
   if (rootCause 
-=
+!
 = null) %7B%0A      
@@ -1979,304 +1979,96 @@
     
-        rootCause = new IOException(e);%0A                %7D%0A                else if (rootCause != e) %7B%0A                    // Self-suppression not permitted%0A                    rootCause.addSuppressed(e);%0A                %7D%0A            %7D%0A        %7D%0A        if (rootCause != null) %7B%0A            throw 
+propagateIfPossible(rootCause, Exception.class);%0A            throw new RuntimeException(
 root
@@ -2064,32 +2064,33 @@
 eption(rootCause
+)
 ;%0A        %7D%0A    

Support AutoCloseable in closeAll