You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sc...@apache.org on 2017/01/25 22:40:39 UTC

[12/33] maven git commit: [MNG-5977] Improve output readability of our MavenTransferListener implementations

[MNG-5977] Improve output readability of our MavenTransferListener implementations

* Applied a general decimal formatter which automatically scales file sizes between [0,10) (one decimal digit) and [10,1000) (whole numbers) along with proper size and time units
* The progress meter will now properly
** tell the amount of transfers along with file names (in debug mode) and absolute progress by size
** visually seperate parallel transfers with " | "
* Optimized and reduced padding to the cases where it actually is necessary
* Padding has to be applied to every event which can succeed with progress update
* Synchronize all calls to console to avoid race conditions where output is terminated by a carriage return only. If no sync is done, SLF4J or INIT/SUCCEEDED update can interleave and overwrite the progress while being shorter as the progress itself.
* Replaced the concurrent hash map with a synchronized linked hash map to retain order of the progress meter. It will behave now like a queue.
* Work around a rounding bug existed upto Java 7
  See http://stackoverflow.com/q/22797964/696632 and Oracle's bugfix
  Announcement: http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html

Race conditions cannot be avoided if -T is employed since one does not have access to the output stream of a SLF4J backend to synchronize on.


Project: http://git-wip-us.apache.org/repos/asf/maven/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/149cce7a
Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/149cce7a
Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/149cce7a

Branch: refs/heads/MNG-5958
Commit: 149cce7a867956efeaf72d527f61297bf2471b1e
Parents: deefd93
Author: Michael Osipov <mi...@apache.org>
Authored: Thu Feb 18 00:28:50 2016 +0100
Committer: Michael Osipov <19...@gmx.net>
Committed: Mon Jan 23 11:18:15 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/maven/cli/MavenCli.java     |  10 +-
 .../transfer/AbstractMavenTransferListener.java | 209 +++++++++++--
 .../transfer/ConsoleMavenTransferListener.java  | 112 ++++---
 .../transfer/Slf4jMavenTransferListener.java    |  38 +--
 .../maven/cli/transfer/FileSizeFormatTest.java  | 313 +++++++++++++++++++
 5 files changed, 595 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven/blob/149cce7a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 176ce4d..2b9f099 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -1005,13 +1005,13 @@ public class MavenCli
         // present supplied by the user. The rule is that we only allow the execution of one ConfigurationProcessor.
         // If there is more than one then we execute the one supplied by the user, otherwise we execute the
         // the default SettingsXmlConfigurationProcessor.
-        // 
+        //
         int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
 
         if ( userSuppliedConfigurationProcessorCount == 0 )
         {
             //
-            // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to 
+            // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to
             // have to honour its existence forever. So let's run it.
             //
             configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest );
@@ -1288,7 +1288,7 @@ public class MavenCli
             // If we're logging to a file then we don't want the console transfer listener as it will spew
             // download progress all over the place
             //
-            transferListener = getConsoleTransferListener();
+            transferListener = getConsoleTransferListener( cliRequest.commandLine.hasOption( CLIManager.DEBUG ) );
         }
         else
         {
@@ -1588,9 +1588,9 @@ public class MavenCli
     // Customizations available via the CLI
     //
 
-    protected TransferListener getConsoleTransferListener()
+    protected TransferListener getConsoleTransferListener( boolean printResourceNames )
     {
-        return new ConsoleMavenTransferListener( System.out );
+        return new ConsoleMavenTransferListener( System.out, printResourceNames );
     }
 
     protected TransferListener getBatchTransferListener()

http://git-wip-us.apache.org/repos/asf/maven/blob/149cce7a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
index 58b1a5d..21822be 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
@@ -24,6 +24,7 @@ import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.util.Locale;
 
+import org.apache.commons.lang3.Validate;
 import org.eclipse.aether.transfer.AbstractTransferListener;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
@@ -33,6 +34,178 @@ public abstract class AbstractMavenTransferListener
     extends AbstractTransferListener
 {
 
+    // CHECKSTYLE_OFF: LineLength
+    /**
+     * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
+     * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
+     * and <code>###0</code> for numbers between 10 and 1000+ by default.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
+     * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
+     * @see <a
+     *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
+     */
+    // CHECKSTYLE_ON: LineLength
+    // TODO Move me to Maven Shared Utils
+    static class FileSizeFormat
+    {
+        static enum ScaleUnit
+        {
+            BYTE
+            {
+                @Override
+                public long bytes()
+                {
+                    return 1L;
+                }
+
+                @Override
+                public String symbol()
+                {
+                    return "B";
+                }
+            },
+            KILOBYTE
+            {
+                @Override
+                public long bytes()
+                {
+                    return 1000L;
+                }
+
+                @Override
+                public String symbol()
+                {
+                    return "kB";
+                }
+            },
+            MEGABYTE
+            {
+                @Override
+                public long bytes()
+                {
+                    return KILOBYTE.bytes() * KILOBYTE.bytes();
+                }
+
+                @Override
+                public String symbol()
+                {
+                    return "MB";
+                }
+            },
+            GIGABYTE
+            {
+                @Override
+                public long bytes()
+                {
+                    return MEGABYTE.bytes() * KILOBYTE.bytes();
+                };
+
+                @Override
+                public String symbol()
+                {
+                    return "GB";
+                }
+            };
+
+            public abstract long bytes();
+            public abstract String symbol();
+
+            public static ScaleUnit getScaleUnit( long size )
+            {
+                Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
+
+                if ( size >= GIGABYTE.bytes() )
+                {
+                    return GIGABYTE;
+                }
+                else if ( size >= MEGABYTE.bytes() )
+                {
+                    return MEGABYTE;
+                }
+                else if ( size >= KILOBYTE.bytes() )
+                {
+                    return KILOBYTE;
+                }
+                else
+                {
+                    return BYTE;
+                }
+            }
+        }
+
+        private DecimalFormat smallFormat;
+        private DecimalFormat largeFormat;
+
+        public FileSizeFormat( Locale locale )
+        {
+            smallFormat = new DecimalFormat( "#0.0", new DecimalFormatSymbols( locale ) );
+            largeFormat = new DecimalFormat( "###0", new DecimalFormatSymbols( locale ) );
+        }
+
+        public String format( long size )
+        {
+            return format( size, null );
+        }
+
+        public String format( long size, ScaleUnit unit )
+        {
+            return format( size, unit, false );
+        }
+
+        public String format( long size, ScaleUnit unit, boolean omitSymbol )
+        {
+            Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
+
+            if ( unit == null )
+            {
+                unit = ScaleUnit.getScaleUnit( size );
+            }
+
+            double scaledSize = (double) size / unit.bytes();
+            String scaledSymbol = " " + unit.symbol();
+
+            if ( omitSymbol )
+            {
+                scaledSymbol = "";
+            }
+
+            if ( unit == ScaleUnit.BYTE )
+            {
+                return largeFormat.format( size ) + scaledSymbol;
+            }
+
+            if ( scaledSize < 0.05 || scaledSize >= 10.0 )
+            {
+                return largeFormat.format( scaledSize ) + scaledSymbol;
+            }
+            else
+            {
+                return smallFormat.format( scaledSize ) + scaledSymbol;
+            }
+        }
+
+        public String formatProgress( long progressedSize, long size )
+        {
+            Validate.isTrue( progressedSize >= 0L, "progressed file size cannot be negative: %s", progressedSize );
+            Validate.isTrue( size >= 0L && progressedSize <= size || size < 0L,
+                "progressed file size cannot be greater than size: %s > %s", progressedSize, size );
+
+            if ( size >= 0L && progressedSize != size )
+            {
+                ScaleUnit unit = ScaleUnit.getScaleUnit( size );
+                String formattedProgressedSize = format( progressedSize, unit, true );
+                String formattedSize = format( size, unit );
+
+                return formattedProgressedSize + "/" + formattedSize;
+            }
+            else
+            {
+                return format( progressedSize );
+            }
+        }
+    }
+
     protected PrintStream out;
 
     protected AbstractMavenTransferListener( PrintStream out )
@@ -43,9 +216,10 @@ public abstract class AbstractMavenTransferListener
     @Override
     public void transferInitiated( TransferEvent event )
     {
-        String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
+        String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
 
-        out.println( message + ": " + event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
+        TransferResource resource = event.getResource();
+        out.println( action + ": " + resource.getRepositoryUrl() + resource.getResourceName() );
     }
 
     @Override
@@ -53,7 +227,7 @@ public abstract class AbstractMavenTransferListener
         throws TransferCancelledException
     {
         TransferResource resource = event.getResource();
-
+        // TODO This needs to be colorized
         out.println( "[WARNING] " + event.getException().getMessage() + " for " + resource.getRepositoryUrl()
             + resource.getResourceName() );
     }
@@ -63,28 +237,21 @@ public abstract class AbstractMavenTransferListener
     {
         TransferResource resource = event.getResource();
         long contentLength = event.getTransferredBytes();
-        if ( contentLength >= 0 )
-        {
-            String type = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
-            String len = contentLength >= 1024 ? toKB( contentLength ) + " KB" : contentLength + " B";
 
-            String throughput = "";
-            long duration = System.currentTimeMillis() - resource.getTransferStartTime();
-            if ( duration > 0 )
-            {
-                DecimalFormat format = new DecimalFormat( "0.0", new DecimalFormatSymbols( Locale.ENGLISH ) );
-                double kbPerSec = ( contentLength / 1024.0 ) / ( duration / 1000.0 );
-                throughput = " at " + format.format( kbPerSec ) + " KB/sec";
-            }
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+        String result = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
+        String len = format.format( contentLength );
 
-            out.println( type + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len
-                + throughput + ")" );
+        String throughput = "";
+        long duration = System.currentTimeMillis() - resource.getTransferStartTime();
+        if ( duration > 0L )
+        {
+            double bytesPerSecond = contentLength / ( duration / 1000.0 );
+            throughput = " at " + format.format( (long) bytesPerSecond ) + "/s";
         }
-    }
 
-    protected long toKB( long bytes )
-    {
-        return ( bytes + 1023 ) / 1024;
+        out.println( result + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len
+            + throughput + ")" );
     }
 
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/149cce7a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
index 5f87836..1ad943b 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
@@ -20,9 +20,13 @@ package org.apache.maven.cli.transfer;
  */
 
 import java.io.PrintStream;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.commons.lang3.StringUtils;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
 import org.eclipse.aether.transfer.TransferResource;
@@ -36,32 +40,58 @@ public class ConsoleMavenTransferListener
     extends AbstractMavenTransferListener
 {
 
-    private Map<TransferResource, Long> downloads = new ConcurrentHashMap<>();
+    private Map<TransferResource, Long> transfers = Collections.synchronizedMap(
+                                                        new LinkedHashMap<TransferResource, Long>() );
 
+    private boolean printResourceNames;
     private int lastLength;
 
-    public ConsoleMavenTransferListener( PrintStream out )
+    public ConsoleMavenTransferListener( PrintStream out, boolean printResourceNames )
     {
         super( out );
+        this.printResourceNames = printResourceNames;
     }
 
     @Override
-    public void transferProgressed( TransferEvent event )
+    public synchronized void transferInitiated( TransferEvent event )
+    {
+        overridePreviousTransfer( event );
+
+        super.transferInitiated( event );
+    }
+
+    @Override
+    public synchronized void transferCorrupted( TransferEvent event )
+        throws TransferCancelledException
+    {
+        overridePreviousTransfer( event );
+
+        super.transferCorrupted( event );
+    }
+
+    @Override
+    public synchronized void transferProgressed( TransferEvent event )
         throws TransferCancelledException
     {
         TransferResource resource = event.getResource();
-        downloads.put( resource, event.getTransferredBytes() );
+        transfers.put( resource, event.getTransferredBytes() );
 
-        StringBuilder buffer = new StringBuilder( 64 );
+        StringBuilder buffer = new StringBuilder( 128 );
+        buffer.append( "Progress (" ).append(  transfers.size() ).append( "): " );
 
-        for ( Map.Entry<TransferResource, Long> entry : downloads.entrySet() )
+        synchronized ( transfers )
         {
-            long total = entry.getKey().getContentLength();
-            Long complete = entry.getValue();
-            // NOTE: This null check guards against http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312056
-            if ( complete != null )
+            Iterator<Map.Entry<TransferResource, Long>> entries = transfers.entrySet().iterator();
+            while ( entries.hasNext() )
             {
-                buffer.append( getStatus( complete, total ) ).append( "  " );
+                Map.Entry<TransferResource, Long> entry = entries.next();
+                long total = entry.getKey().getContentLength();
+                Long complete = entry.getValue();
+                buffer.append( getStatus( entry.getKey().getResourceName(), complete, total ) );
+                if ( entries.hasNext() )
+                {
+                    buffer.append( " | " );
+                }
             }
         }
 
@@ -69,28 +99,29 @@ public class ConsoleMavenTransferListener
         lastLength = buffer.length();
         pad( buffer, pad );
         buffer.append( '\r' );
-
-        out.print( buffer.toString() );
+        out.print( buffer );
+        out.flush();
     }
 
-    private String getStatus( long complete, long total )
+    private String getStatus( String resourceName, long complete, long total )
     {
-        if ( total >= 1024 )
-        {
-            return toKB( complete ) + "/" + toKB( total ) + " KB ";
-        }
-        else if ( total >= 0 )
-        {
-            return complete + "/" + total + " B ";
-        }
-        else if ( complete >= 1024 )
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+        StringBuilder status = new StringBuilder();
+
+        if ( printResourceNames )
         {
-            return toKB( complete ) + " KB ";
+            status.append( StringUtils.substringAfterLast( resourceName,  "/" ) );
+            status.append( " (" );
         }
-        else
+
+        status.append( format.formatProgress( complete, total ) );
+
+        if ( printResourceNames )
         {
-            return complete + " B ";
+            status.append( ")" );
         }
+
+        return status.toString();
     }
 
     private void pad( StringBuilder buffer, int spaces )
@@ -105,29 +136,34 @@ public class ConsoleMavenTransferListener
     }
 
     @Override
-    public void transferSucceeded( TransferEvent event )
+    public synchronized void transferSucceeded( TransferEvent event )
     {
-        transferCompleted( event );
+        transfers.remove( event.getResource() );
+        overridePreviousTransfer( event );
 
         super.transferSucceeded( event );
     }
 
     @Override
-    public void transferFailed( TransferEvent event )
+    public synchronized void transferFailed( TransferEvent event )
     {
-        transferCompleted( event );
+        transfers.remove( event.getResource() );
+        overridePreviousTransfer( event );
 
         super.transferFailed( event );
     }
 
-    private void transferCompleted( TransferEvent event )
+    private void overridePreviousTransfer( TransferEvent event )
     {
-        downloads.remove( event.getResource() );
-
-        StringBuilder buffer = new StringBuilder( 64 );
-        pad( buffer, lastLength );
-        buffer.append( '\r' );
-        out.print( buffer.toString() );
+        if ( lastLength > 0 )
+        {
+            StringBuilder buffer = new StringBuilder( 128 );
+            pad( buffer, lastLength );
+            buffer.append( '\r' );
+            out.print( buffer );
+            out.flush();
+            lastLength = 0;
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/149cce7a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
index bb72db3..ac5333e 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
@@ -19,10 +19,9 @@ package org.apache.maven.cli.transfer;
  * under the License.
  */
 
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
 import java.util.Locale;
 
+import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat;
 import org.eclipse.aether.transfer.AbstractTransferListener;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
@@ -50,9 +49,10 @@ public class Slf4jMavenTransferListener
     @Override
     public void transferInitiated( TransferEvent event )
     {
-        String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
+        String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
 
-        out.info( message + ": " + event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
+        TransferResource resource = event.getResource();
+        out.info( action + ": " + resource.getRepositoryUrl() + resource.getResourceName() );
     }
 
     @Override
@@ -60,7 +60,6 @@ public class Slf4jMavenTransferListener
         throws TransferCancelledException
     {
         TransferResource resource = event.getResource();
-
         out.warn( event.getException().getMessage() + " for " + resource.getRepositoryUrl()
             + resource.getResourceName() );
     }
@@ -70,28 +69,21 @@ public class Slf4jMavenTransferListener
     {
         TransferResource resource = event.getResource();
         long contentLength = event.getTransferredBytes();
-        if ( contentLength >= 0 )
-        {
-            String type = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
-            String len = contentLength >= 1024 ? toKB( contentLength ) + " KB" : contentLength + " B";
 
-            String throughput = "";
-            long duration = System.currentTimeMillis() - resource.getTransferStartTime();
-            if ( duration > 0 )
-            {
-                DecimalFormat format = new DecimalFormat( "0.0", new DecimalFormatSymbols( Locale.ENGLISH ) );
-                double kbPerSec = ( contentLength / 1024.0 ) / ( duration / 1000.0 );
-                throughput = " at " + format.format( kbPerSec ) + " KB/sec";
-            }
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+        String result = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
+        String len = format.format( contentLength );
 
-            out.info( type + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len
-                + throughput + ")" );
+        String throughput = "";
+        long duration = System.currentTimeMillis() - resource.getTransferStartTime();
+        if ( duration > 0L )
+        {
+            double bytesPerSecond = contentLength / ( duration / 1000.0 );
+            throughput = " at " + format.format( (long) bytesPerSecond ) + "/s";
         }
-    }
 
-    protected long toKB( long bytes )
-    {
-        return ( bytes + 1023 ) / 1024;
+        out.info( result + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len
+            + throughput + ")" );
     }
 
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/149cce7a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
new file mode 100644
index 0000000..43939d1
--- /dev/null
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
@@ -0,0 +1,313 @@
+package org.apache.maven.cli.transfer;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Locale;
+
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat;
+import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat.ScaleUnit;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+public class FileSizeFormatTest {
+
+    @Test( expected = IllegalArgumentException.class )
+    public void testNegativeSize()
+    {
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+        long negativeSize = -100L;
+        format.format( negativeSize );
+    }
+
+    @Test
+    public void testSize()
+    {
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+        long _0_bytes = 0L;
+        assertEquals( "0 B", format.format( _0_bytes ) );
+
+        long _5_bytes = 5L;
+        assertEquals( "5 B", format.format( _5_bytes ) );
+
+        long _10_bytes = 10L;
+        assertEquals( "10 B", format.format( _10_bytes ) );
+
+        long _15_bytes = 15L;
+        assertEquals( "15 B", format.format( _15_bytes ) );
+
+        long _999_bytes = 999L;
+        assertEquals( "999 B", format.format( _999_bytes ) );
+
+        long _1000_bytes = 1000L;
+        assertEquals( "1.0 kB", format.format( _1000_bytes ) );
+
+        long _5500_bytes = 5500L;
+        assertEquals( "5.5 kB", format.format( _5500_bytes ) );
+
+        long _10_kilobytes = 10L * 1000L;
+        assertEquals( "10 kB", format.format( _10_kilobytes ) );
+
+        long _15_kilobytes = 15L * 1000L;
+        assertEquals( "15 kB", format.format( _15_kilobytes ) );
+
+        long _999_kilobytes = 999L * 1000L;
+        assertEquals( "999 kB", format.format( _999_kilobytes ) );
+
+        long _1000_kilobytes = 1000L * 1000L;
+        assertEquals( "1.0 MB", format.format( _1000_kilobytes ) );
+
+        long _5500_kilobytes = 5500L * 1000L;
+        assertEquals( "5.5 MB", format.format( _5500_kilobytes ) );
+
+        long _10_megabytes = 10L * 1000L * 1000L;
+        assertEquals( "10 MB", format.format( _10_megabytes ) );
+
+        long _15_megabytes = 15L * 1000L * 1000L;
+        assertEquals( "15 MB", format.format( _15_megabytes ) );
+
+        long _999_megabytes = 999L * 1000L * 1000L;
+        assertEquals( "999 MB", format.format( _999_megabytes ) );
+
+        long _1000_megabytes = 1000L * 1000L * 1000L;
+        assertEquals( "1.0 GB", format.format( _1000_megabytes ) );
+
+        long _5500_megabytes = 5500L * 1000L * 1000L;
+        assertEquals( "5.5 GB", format.format( _5500_megabytes ) );
+
+        long _10_gigabytes = 10L * 1000L * 1000L * 1000L;
+        assertEquals( "10 GB", format.format( _10_gigabytes ) );
+
+        long _15_gigabytes = 15L * 1000L * 1000L * 1000L;
+        assertEquals( "15 GB", format.format( _15_gigabytes ) );
+
+        long _1000_gigabytes = 1000L * 1000L * 1000L * 1000L;
+        assertEquals( "1000 GB", format.format( _1000_gigabytes ) );
+    }
+
+    @Test
+    public void testSizeWithSelectedScaleUnit()
+    {
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+        long _0_bytes = 0L;
+        assertEquals( "0 B", format.format( _0_bytes ) );
+        assertEquals( "0 B", format.format( _0_bytes, ScaleUnit.BYTE ) );
+        assertEquals( "0 kB", format.format( _0_bytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _0_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _0_bytes, ScaleUnit.GIGABYTE ) );
+
+        long _5_bytes = 5L;
+        assertEquals( "5 B", format.format( _5_bytes ) );
+        assertEquals( "5 B", format.format( _5_bytes, ScaleUnit.BYTE ) );
+        assertEquals( "0 kB", format.format( _5_bytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _5_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _5_bytes, ScaleUnit.GIGABYTE ) );
+
+
+        long _49_bytes = 49L;
+        assertEquals( "49 B", format.format( _49_bytes ) );
+        assertEquals( "49 B", format.format( _49_bytes, ScaleUnit.BYTE ) );
+        assertEquals( "0 kB", format.format( _49_bytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _49_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _49_bytes, ScaleUnit.GIGABYTE ) );
+
+        long _50_bytes = 50L;
+        assertEquals( "50 B", format.format( _50_bytes ) );
+        assertEquals( "50 B", format.format( _50_bytes, ScaleUnit.BYTE ) );
+        if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
+        {
+            assertEquals( "0.1 kB", format.format( _50_bytes, ScaleUnit.KILOBYTE ) );
+        }
+        assertEquals( "0 MB", format.format( _50_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _50_bytes, ScaleUnit.GIGABYTE ) );
+
+        long _999_bytes = 999L;
+        assertEquals( "999 B", format.format( _999_bytes ) );
+        assertEquals( "999 B", format.format( _999_bytes, ScaleUnit.BYTE ) );
+        assertEquals( "1.0 kB", format.format( _999_bytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _999_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _999_bytes, ScaleUnit.GIGABYTE ) );
+
+        long _1000_bytes = 1000L;
+        assertEquals( "1.0 kB", format.format( _1000_bytes ) );
+        assertEquals( "1000 B", format.format( _1000_bytes, ScaleUnit.BYTE ) );
+        assertEquals( "1.0 kB", format.format( _1000_bytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _1000_bytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _1000_bytes, ScaleUnit.GIGABYTE ) );
+
+        long _49_kilobytes = 49L * 1000L;
+        assertEquals( "49 kB", format.format( _49_kilobytes ) );
+        assertEquals( "49000 B", format.format( _49_kilobytes, ScaleUnit.BYTE ) );
+        assertEquals( "49 kB", format.format( _49_kilobytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "0 MB", format.format( _49_kilobytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _49_kilobytes, ScaleUnit.GIGABYTE ) );
+
+        long _50_kilobytes = 50L * 1000L;
+        assertEquals( "50 kB", format.format( _50_kilobytes ) );
+        assertEquals( "50000 B", format.format( _50_kilobytes, ScaleUnit.BYTE ) );
+        assertEquals( "50 kB", format.format( _50_kilobytes, ScaleUnit.KILOBYTE ) );
+        if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
+        {
+            assertEquals( "0.1 MB", format.format( _50_kilobytes, ScaleUnit.MEGABYTE ) );
+        }
+        assertEquals( "0 GB", format.format( _50_kilobytes, ScaleUnit.GIGABYTE ) );
+
+        long _999_kilobytes = 999L * 1000L;
+        assertEquals( "999 kB", format.format( _999_kilobytes ) );
+        assertEquals( "999000 B", format.format( _999_kilobytes, ScaleUnit.BYTE ) );
+        assertEquals( "999 kB", format.format( _999_kilobytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "1.0 MB", format.format( _999_kilobytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _999_kilobytes, ScaleUnit.GIGABYTE ) );
+
+        long _1000_kilobytes = 1000L * 1000L;
+        assertEquals( "1.0 MB", format.format( _1000_kilobytes ) );
+        assertEquals( "1000000 B", format.format( _1000_kilobytes, ScaleUnit.BYTE ) );
+        assertEquals( "1000 kB", format.format( _1000_kilobytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "1.0 MB", format.format( _1000_kilobytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _1000_kilobytes, ScaleUnit.GIGABYTE ) );
+
+        long _49_megabytes = 49L * 1000L * 1000L;
+        assertEquals( "49 MB", format.format( _49_megabytes ) );
+        assertEquals( "49000000 B", format.format( _49_megabytes, ScaleUnit.BYTE ) );
+        assertEquals( "49000 kB", format.format( _49_megabytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "49 MB", format.format( _49_megabytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "0 GB", format.format( _49_megabytes, ScaleUnit.GIGABYTE ) );
+
+        long _50_megabytes = 50L * 1000L * 1000L;
+        assertEquals( "50 MB", format.format( _50_megabytes ) );
+        assertEquals( "50000000 B", format.format( _50_megabytes, ScaleUnit.BYTE ) );
+        assertEquals( "50000 kB", format.format( _50_megabytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "50 MB", format.format( _50_megabytes, ScaleUnit.MEGABYTE ) );
+        if ( SystemUtils.isJavaVersionAtLeast( JavaVersion.JAVA_1_8 ) )
+        {
+            assertEquals( "0.1 GB", format.format( _50_megabytes, ScaleUnit.GIGABYTE ) );
+        }
+
+        long _999_megabytes = 999L * 1000L * 1000L;
+        assertEquals( "999 MB", format.format( _999_megabytes ) );
+        assertEquals( "999000000 B", format.format( _999_megabytes, ScaleUnit.BYTE ) );
+        assertEquals( "999000 kB", format.format( _999_megabytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "999 MB", format.format( _999_megabytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "1.0 GB", format.format( _999_megabytes, ScaleUnit.GIGABYTE ) );
+
+        long _1000_megabytes = 1000L * 1000L * 1000L;
+        assertEquals( "1.0 GB", format.format( _1000_megabytes ) );
+        assertEquals( "1000000000 B", format.format( _1000_megabytes, ScaleUnit.BYTE ) );
+        assertEquals( "1000000 kB", format.format( _1000_megabytes, ScaleUnit.KILOBYTE ) );
+        assertEquals( "1000 MB", format.format( _1000_megabytes, ScaleUnit.MEGABYTE ) );
+        assertEquals( "1.0 GB", format.format( _1000_megabytes, ScaleUnit.GIGABYTE ) );
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void testNegativeProgessedSize()
+    {
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+        long negativeProgessedSize = -100L;
+        format.formatProgress( negativeProgessedSize, 10L );
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void testNegativeProgessedSizeBiggerThanSize()
+    {
+        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+        format.formatProgress( 100L, 10L );
+    }
+
+    @Test
+    public void testProgressedSizeWithoutSize()
+    {
+         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+         long _0_bytes = 0L;
+         assertEquals( "0 B", format.formatProgress( _0_bytes, -1L ) );
+
+         long _1000_bytes = 1000L;
+         assertEquals( "1.0 kB", format.formatProgress( _1000_bytes, -1L ) );
+
+         long _1000_kilobytes = 1000L * 1000L;
+         assertEquals( "1.0 MB", format.formatProgress( _1000_kilobytes, -1L ) );
+
+         long _1000_megabytes = 1000L * 1000L * 1000L;
+         assertEquals( "1.0 GB", format.formatProgress( _1000_megabytes, -1L ) );
+
+    }
+
+    @Test
+    public void testProgressedBothZero()
+    {
+         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+         long _0_bytes = 0L;
+         assertEquals( "0 B", format.formatProgress( _0_bytes, _0_bytes ) );
+    }
+
+    @Test
+    public void testProgressedSizeWithSize()
+    {
+         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+
+         long _0_bytes = 0L;
+         long _400_bytes = 400L;
+         long _800_bytes = 2L * _400_bytes;
+         assertEquals( "0/800 B", format.formatProgress( _0_bytes, _800_bytes ) );
+         assertEquals( "400/800 B", format.formatProgress( _400_bytes, _800_bytes ) );
+         assertEquals( "800 B", format.formatProgress( _800_bytes, _800_bytes ) );
+
+         long _4000_bytes = 4000L;
+         long _8000_bytes = 2L * _4000_bytes;
+         long _50_kilobytes = 50000L;
+         assertEquals( "0/8.0 kB", format.formatProgress( _0_bytes, _8000_bytes ) );
+         assertEquals( "0.4/8.0 kB", format.formatProgress( _400_bytes, _8000_bytes ) );
+         assertEquals( "4.0/8.0 kB", format.formatProgress( _4000_bytes, _8000_bytes ) );
+         assertEquals( "8.0 kB", format.formatProgress( _8000_bytes, _8000_bytes ) );
+         assertEquals( "8.0/50 kB", format.formatProgress( _8000_bytes, _50_kilobytes ) );
+         assertEquals( "16/50 kB", format.formatProgress( 2L * _8000_bytes, _50_kilobytes ) );
+         assertEquals( "50 kB", format.formatProgress( _50_kilobytes, _50_kilobytes ) );
+
+         long _500_kilobytes = 500000L;
+         long _1000_kilobytes = 2L * _500_kilobytes;;
+         long _5000_kilobytes = 5L * _1000_kilobytes;
+         long _15_megabytes = 3L * _5000_kilobytes;
+         assertEquals( "0/5.0 MB", format.formatProgress( _0_bytes, _5000_kilobytes ) );
+         assertEquals( "0.5/5.0 MB", format.formatProgress( _500_kilobytes, _5000_kilobytes ) );
+         assertEquals( "1.0/5.0 MB", format.formatProgress( _1000_kilobytes, _5000_kilobytes ) );
+         assertEquals( "5.0 MB", format.formatProgress( _5000_kilobytes, _5000_kilobytes ) );
+         assertEquals( "5.0/15 MB", format.formatProgress( _5000_kilobytes, _15_megabytes ) );
+         assertEquals( "15 MB", format.formatProgress( _15_megabytes, _15_megabytes ) );
+
+         long _500_megabytes = 500000000L;
+         long _1000_megabytes = 2L * _500_megabytes;
+         long _5000_megabytes = 5L * _1000_megabytes;
+         long _15_gigabytes = 3L * _5000_megabytes;
+         assertEquals( "0/500 MB", format.formatProgress( _0_bytes, _500_megabytes ) );
+         assertEquals( "1.0/5.0 GB", format.formatProgress( _1000_megabytes, _5000_megabytes ) );
+         assertEquals( "5.0 GB", format.formatProgress( _5000_megabytes, _5000_megabytes ) );
+         assertEquals( "5.0/15 GB", format.formatProgress( _5000_megabytes, _15_gigabytes ) );
+         assertEquals( "15 GB", format.formatProgress( _15_gigabytes, _15_gigabytes ) );
+    }
+
+}