Repository: google/swift-benchmark (swift)

Issue:
Right-justify time output in the console
Currently, it's sometimes a little difficult to compare the benchmark output. It'd be better to right-justify to make it easy to compare across different performance scales. (See sample output below.)

```
name                                                                   time            std                   iterations  
-----------------------------------------------------------------------------------------------------------------------
NonBlockingCondition: notify one, no waiters                           49.0 ns         ± 218.03171899854937  1000000     
NonBlockingCondition: notify all, no waiters                           48.0 ns         ± 259.1237923013594   1000000     
NonBlockingCondition: preWait, cancelWait                              62.0 ns         ± 318.1394131555278   1000000     
NonBlockingCondition: preWait, notify, cancelWait                      95.0 ns         ± 383.7078986828835   1000000     
NonBlockingCondition: preWait, notify, commitWait                      180.0 ns        ± 530.3777998534739   745911      
NonBlockingThreadPool: join, one level                                 688.0 ns        ± 181484.56500114241  7751        
NonBlockingThreadPool: join, two levels                                2328.5 ns       ± 362158.9014454464   1294        
NonBlockingThreadPool: join, three levels                              4993.0 ns       ± 380630.33014058863  941         
NonBlockingThreadPool: join, four levels, three on thread pool thread  5930.5 ns       ± 397880.22706779756  914         
NonBlockingThreadPool: parallel for, one level                         4987256.5 ns    ± 958287.8800861727   28          
NonBlockingThreadPool: parallel for, two levels                        4492208.0 ns    ± 666873.9680715388   32          
AdjacencyList: build a fully-connected graph of size 10                45450.0 ns      ± 11900.774671466019  2643        
AdjacencyList: build a fully-connected graph of size 100               4368357.0 ns    ± 332722.03091855097  33          
AdjacencyList: build a fully-connected graph of size 1000              432393589.5 ns  ± 5835349.92137541    2  
```

Pull request:
Fixes #25 

before
```
name                          time             std         iterations
---------------------------------------------------------------------
add string no capacity        40215.0 ns       ±  24.40 %  32485
add string reserved capacity  4316510990.0 ns  ±   0.58 %  2
```

after
```
name                          time            std         iterations
--------------------------------------------------------------------
add string no capacity            40214.0 ns  ±  23.67 %  32319
add string reserved capacity  432951866.0 ns  ±   2.09 %  3
```

Patch:
diff --git a/Sources/Benchmark/BenchmarkReporter.swift b/Sources/Benchmark/BenchmarkReporter.swift
index 020d045..cac8cbd 100644
--- a/Sources/Benchmark/BenchmarkReporter.swift
+++ b/Sources/Benchmark/BenchmarkReporter.swift
@@ -14,6 +14,33 @@
 
 import Foundation
 
+extension String {
+    func leftPadding(toLength: Int, withPad: String) -> String {
+        let stringLength = self.count
+        if stringLength <= toLength {
+            return String(repeating: withPad, count: toLength - stringLength) + self
+        } else {
+            #if DEBUG
+            //When call fatalError(), stop all program (that include debug).
+            //So return String in debug.
+            return "Triggar fatalError"
+            #endif
+            fatalError("'toLength' must be greater than or equal to 'stringLength'.\n")
+        }
+    }
+}
+
+func paddingEachCell(cell: String, index: Int, columnIndex: Int, length: Int) -> String {
+    var paddedCell = ""
+    if index != 0 && columnIndex == 1 {
+        paddedCell = cell.leftPadding(toLength: length, withPad:" ")
+    } else {
+        paddedCell = cell.padding(
+            toLength: length, withPad: " ", startingAt: 0)
+    }
+    return paddedCell
+}
+
 protocol BenchmarkReporter {
     mutating func report(running name: String, suite: String)
     mutating func report(finishedRunning name: String, suite: String, nanosTaken: UInt64)
@@ -68,10 +95,9 @@ struct PlainTextReporter: BenchmarkReporter {
         print("")
         for index in 0...results.count {
             for columnIndex in 0..<columns.count {
-                let cell = columns[columnIndex][index]
-                let padded = cell.padding(
-                    toLength: widths[columnIndex], withPad: " ", startingAt: 0)
-                print(padded, terminator: "  ")
+                let paddedCell = paddingEachCell(cell: columns[columnIndex][index],
+                    index: index, columnIndex: columnIndex, length: widths[columnIndex])
+                print(paddedCell, terminator: "  ")
             }
             print("")
             if index == 0 {
@@ -81,4 +107,4 @@ struct PlainTextReporter: BenchmarkReporter {
             }
         }
     }
-}
+}
\ No newline at end of file


Test patch:
diff --git a/Tests/BenchmarkTests/BenchmarkReporterTests.swift b/Tests/BenchmarkTests/BenchmarkReporterTests.swift
new file mode 100644
index 0000000..9f0afb7
--- /dev/null
+++ b/Tests/BenchmarkTests/BenchmarkReporterTests.swift
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+//
+// Licensed 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 XCTest
+
+@testable import Benchmark
+
+final class BenchmarkReporterTests: XCTestCase {
+
+    func testPaddingLeft() throws {
+        let testText = "testText"
+        XCTAssertEqual(testText.leftPadding(toLength: testText.count, withPad:" "), "testText")
+        XCTAssertEqual(testText.leftPadding(toLength: testText.count + 3, withPad:" "), "   testText")
+        XCTAssertEqual(testText.leftPadding(toLength: testText.count - 1, withPad:" "), "Triggar fatalError")
+    }
+
+    func testPaddingEachCell() throws {
+        let dummyName = ["00", "10", "20"]
+        let dummyTime = ["01", "11", "21"]
+        let dummyStd = ["02", "12", "22"]
+        let dummyIterations = ["03", "13", "23"]
+        let columuns = [dummyName, dummyTime, dummyStd, dummyIterations]
+
+        for index in 0..<dummyName.count {
+            for columnIndex in 0..<columuns.count {
+                let cell = columuns[columnIndex][index]
+                let paddedCell = paddingEachCell(cell: cell,
+                    index: index, columnIndex: columnIndex, length: cell.count + 1)
+                if index != 0 && columnIndex == 1 {
+                    XCTAssertEqual(paddedCell, " \(index)\(columnIndex)")
+                } else {
+                    XCTAssertEqual(paddedCell, "\(index)\(columnIndex) ")
+                }
+            }
+        }
+    }
+
+    static var allTests = [
+        ("testPaddingLeft", testPaddingLeft),
+        ("testPaddingEachCell", testPaddingEachCell)
+    ]
+}
\ No newline at end of file
diff --git a/Tests/BenchmarkTests/XCTTestManifests.swift b/Tests/BenchmarkTests/XCTTestManifests.swift
index bde6292..18158f2 100644
--- a/Tests/BenchmarkTests/XCTTestManifests.swift
+++ b/Tests/BenchmarkTests/XCTTestManifests.swift
@@ -21,6 +21,7 @@ import XCTest
             testCase(BenchmarkRunnerTests.allTests),
             testCase(BenchmarkSettingTests.allTests),
             testCase(StatsTests.allTests),
+            testCase(BenchmarkReporterTests.allTests),
         ]
     }
 #endif