1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary Unit tests for String#align and String#indent
  27  * @run main AlignIndent
  28  */
  29 
  30 import java.util.Arrays;
  31 import java.util.List;
  32 import java.util.stream.Collectors;
  33 import java.util.stream.Stream;
  34 
  35 public class AlignIndent {
  36     static final List<String> ENDS = List.of("", "\n", "   \n", "\n\n", "\n\n\n");
  37     static final List<String> MIDDLES = List.of(
  38             "",
  39             "xyz",
  40             "   xyz",
  41             "      xyz",
  42             "xyz   ",
  43             "   xyz   ",
  44             "      xyz   ",
  45             "xyz\u2022",
  46             "   xyz\u2022",
  47             "xyz\u2022   ",
  48             "   xyz\u2022   ",
  49             "   // comment"
  50     );
  51 
  52     public static void main(String[] args) {
  53         test1();
  54         test2();
  55         test3();
  56     }
  57 
  58     /*
  59      * Test String#align() functionality.
  60      */
  61     static void test1() {
  62         for (String prefix : ENDS) {
  63             for (String suffix : ENDS) {
  64                 for (String middle : MIDDLES) {
  65                     {
  66                         String input = prefix + "   abc   \n" + middle + "\n   def   \n" + suffix;
  67                         String output = input.align();
  68 
  69                         String[] inLines = input.split("\\R");
  70                         String[] outLines = output.split("\\R");
  71 
  72                         String[] inLinesBody = getBody(inLines);
  73 
  74                         if (inLinesBody.length < outLines.length) {
  75                             report("String::align()", "Result has more lines than expected", input, output);
  76                         } else if (inLinesBody.length > outLines.length) {
  77                             report("String::align()", "Result has fewer lines than expected", input, output);
  78                         }
  79 
  80                         int indent = -1;
  81                         for (int i = 0; i < inLinesBody.length; i++) {
  82                             String in = inLinesBody[i];
  83                             String out = outLines[i];
  84                             if (!out.isBlank()) {
  85                                 int offset = in.indexOf(out);
  86                                 if (offset == -1) {
  87                                     report("String::align()", "Portions of line are missing", input, output);
  88                                 }
  89                                 if (indent == -1) {
  90                                     indent = offset;
  91                                 } else if (offset != indent) {
  92                                     report("String::align()",
  93                                             "Inconsistent indentation in result", input, output);
  94                                 }
  95                             }
  96                         }
  97                     }
  98                 }
  99             }
 100         }
 101     }
 102 
 103     /*
 104      * Test String#align(int n) functionality.
 105      */
 106     static void test2() {
 107         for (int adjust : new int[] {-8, -7, -4, -3, -2, -1, 0, 1, 2, 3, 4, 7, 8}) {
 108             for (String prefix : ENDS) {
 109                 for (String suffix : ENDS) {
 110                     for (String middle : MIDDLES) {
 111                         {
 112                             String input = prefix + "   abc   \n" + middle + "\n   def   \n" + suffix;
 113                             String output = input.align(adjust);
 114                             String expected = input.align().indent(adjust);
 115 
 116                             if (!output.equals(expected)) {
 117                                 report("String::align(int n)",
 118                                         "Result inconsistent with align().indent(n)", expected, output);
 119                             }
 120                         }
 121                     }
 122                 }
 123             }
 124         }
 125     }
 126 
 127     /*
 128      * Test String#indent(int n) functionality.
 129      */
 130     static void test3() {
 131         for (int adjust : new int[] {-8, -7, -4, -3, -2, -1, 0, 1, 2, 3, 4, 7, 8}) {
 132             for (String prefix : ENDS) {
 133                 for (String suffix : ENDS) {
 134                     for (String middle : MIDDLES) {
 135                         String input = prefix + "   abc   \n" + middle + "\n   def   \n" + suffix;
 136                         String output = input.indent(adjust);
 137 
 138                         Stream<String> stream = input.lines();
 139                         if (adjust > 0) {
 140                             final String spaces = " ".repeat(adjust);
 141                             stream = stream.map(s -> s.isBlank() ? s : spaces + s);
 142                         } else if (adjust < 0) {
 143                             stream = stream.map(s -> s.substring(Math.min(-adjust, indexOfNonWhitespace(s))));
 144                         }
 145                         String expected = stream.collect(Collectors.joining("\n", "", "\n"));
 146 
 147                         if (!output.equals(expected)) {
 148                             report("String::indent(int n)",
 149                                     "Result indentation not as expected", expected, output);
 150                         }
 151                     }
 152                 }
 153             }
 154         }
 155     }
 156 
 157     public static int indexOfNonWhitespace(String s) {
 158         int left = 0;
 159         while (left < s.length()) {
 160             char ch = s.charAt(left);
 161             if (ch != ' ' && ch != '\t' && !Character.isWhitespace(ch)) {
 162                 break;
 163             }
 164             left++;
 165         }
 166         return left;
 167     }
 168 
 169 
 170     private static String[] getBody(String[] inLines) {
 171         int from = -1, to = -1;
 172         for (int i = 0; i < inLines.length; i++) {
 173             String line = inLines[i];
 174             if (!line.isBlank()) {
 175                 if (from == -1) {
 176                     from = i;
 177                 }
 178                 to = i + 1;
 179             }
 180         }
 181         return Arrays.copyOfRange(inLines, from, to);
 182     }
 183 
 184     /*
 185      * Report difference in result.
 186      */
 187     static void report(String test, String message, String input, String output) {
 188         System.err.println("Testing " + test + ": " + message);
 189         System.err.println();
 190         System.err.println("Input: length = " + input.length());
 191         System.err.println("_".repeat(40));
 192         System.err.print(input.replaceAll(" ", "."));
 193         System.err.println("_".repeat(40));
 194         System.err.println();
 195         System.err.println("Output: length = " + output.length());
 196         System.err.println("_".repeat(40));
 197         System.err.print(output.replaceAll(" ", "."));
 198         System.err.println("_".repeat(40));
 199         throw new RuntimeException();
 200     }
 201 }