1 /*
2  * Copyright (c) 2013, 2020, 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  * @bug 8017231 8020977 8054221
27  * @summary test  StringJoiner::merge
28  * @modules java.base/jdk.internal.util
29  * @requires vm.bits == "64" & os.maxMemory > 4G
30  * @run testng/othervm -Xmx4g -XX:+CompactStrings MergeTest
31  */
32 
33 import java.util.StringJoiner;
34 import java.util.stream.Stream;
35 import org.testng.annotations.Test;
36 import static jdk.internal.util.ArraysSupport.MAX_ARRAY_LENGTH;
37 import static org.testng.Assert.assertEquals;
38 import static org.testng.Assert.fail;
39 
40 @Test
41 public class MergeTest {
42     private static final String[] PREFIXES = {"", "{", "@#$%"};
43     private static final String[] SUFFIXES = {"", "}", "*&%$"};
44 
45     private static class Fixes {
46         public String pre0, suf0;
47         public String pre1, suf1;
Fixes(String prefix0, String suffix0, String prefix1, String suffix1)48         public Fixes(String prefix0, String suffix0,
49                      String prefix1, String suffix1) {
50             this.pre0 = prefix0;
51             this.suf0 = suffix0;
52             this.pre1 = prefix1;
53             this.suf1 = suffix1;
54         }
55     }
56 
fixesStream()57     private static Stream<Fixes> fixesStream() {
58         Stream.Builder<Fixes> builder = Stream.builder();
59         for (final String prefix0 : PREFIXES) {
60             for (final String suffix0 : SUFFIXES) {
61                 for (final String prefix1 : PREFIXES) {
62                     for (final String suffix1 : SUFFIXES) {
63                         builder.accept(new Fixes(prefix0, suffix0,
64                                                  prefix1, suffix1));
65                     }
66                 }
67             }
68         }
69         return builder.build();
70     }
71 
72     @Test(expectedExceptions = {NullPointerException.class})
testNull()73     public void testNull() {
74         StringJoiner sj = new StringJoiner(",", "{", "}");
75         sj.merge(null);
76     }
77 
testSimple()78     public void testSimple() {
79         fixesStream().forEach(fixes -> {
80             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
81             StringJoiner other = new StringJoiner(",", fixes.pre1, fixes.suf1);
82             Stream.of("a", "b", "c").forEachOrdered(sj::add);
83             Stream.of("d", "e", "f").forEachOrdered(other::add);
84 
85             sj.merge(other);
86             assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d,e,f" + fixes.suf0);
87         });
88     }
89 
testEmptyOther()90     public void testEmptyOther() {
91         fixesStream().forEach(fixes -> {
92             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
93             StringJoiner other = new StringJoiner(",", fixes.pre1, fixes.suf1);
94             Stream.of("a", "b", "c").forEachOrdered(sj::add);
95 
96             sj.merge(other);
97             assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0);
98 
99             other.setEmptyValue("EMPTY");
100             sj.merge(other);
101             assertEquals(sj.toString(), fixes.pre0 + "a,b,c" + fixes.suf0);
102         });
103     }
104 
testEmptyThis()105     public void testEmptyThis() {
106         fixesStream().forEach(fixes -> {
107             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
108             StringJoiner other = new StringJoiner(":", fixes.pre1, fixes.suf1);
109             Stream.of("d", "e", "f").forEachOrdered(other::add);
110 
111             sj.merge(other);
112             assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0);
113 
114             sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY");
115             assertEquals(sj.toString(), "EMPTY");
116             sj.merge(other);
117             assertEquals(sj.toString(), fixes.pre0 + "d:e:f" + fixes.suf0);
118         });
119     }
120 
testEmptyBoth()121     public void testEmptyBoth() {
122         fixesStream().forEach(fixes -> {
123             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
124             StringJoiner other = new StringJoiner(":", fixes.pre1, fixes.suf1);
125 
126             sj.merge(other);
127             assertEquals(sj.toString(), fixes.pre0 + fixes.suf0);
128 
129             other.setEmptyValue("NOTHING");
130             sj.merge(other);
131             assertEquals(sj.toString(), fixes.pre0 + fixes.suf0);
132 
133             sj = new StringJoiner(",", fixes.pre0, fixes.suf0).setEmptyValue("EMPTY");
134             assertEquals(sj.toString(), "EMPTY");
135             sj.merge(other);
136             assertEquals(sj.toString(), "EMPTY");
137         });
138     }
139 
testCascadeEmpty()140     public void testCascadeEmpty() {
141         fixesStream().forEach(fixes -> {
142             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
143             StringJoiner o1 = new StringJoiner(":", fixes.pre1, fixes.suf1).setEmptyValue("Empty1");
144             StringJoiner o2 = new StringJoiner(",", "<", ">").setEmptyValue("Empty2");
145 
146             o1.merge(o2);
147             assertEquals(o1.toString(), "Empty1");
148 
149             sj.merge(o1);
150             assertEquals(sj.toString(), fixes.pre0 + fixes.suf0);
151         });
152     }
153 
testDelimiter()154     public void testDelimiter() {
155         fixesStream().forEach(fixes -> {
156             StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0);
157             StringJoiner other = new StringJoiner(":", fixes.pre1, fixes.suf1);
158             Stream.of("a", "b", "c").forEachOrdered(sj::add);
159             Stream.of("d", "e", "f").forEachOrdered(other::add);
160 
161             sj.merge(other);
162             assertEquals(sj.toString(), fixes.pre0 + "a,b,c,d:e:f" + fixes.suf0);
163         });
164     }
165 
testMergeSelf()166     public void testMergeSelf() {
167         fixesStream().forEach(fixes -> {
168             final StringJoiner sj = new StringJoiner(",", fixes.pre0, fixes.suf0).add("a").add("b");
169             assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b" + fixes.suf0);
170             assertEquals(sj.merge(sj).toString(), fixes.pre0 + "a,b,a,b,a,b,a,b" + fixes.suf0);
171         });
172     }
173 
OOM()174     public void OOM() {
175         String maxString = "*".repeat(MAX_ARRAY_LENGTH);
176 
177         try {
178             StringJoiner sj1 = new StringJoiner("", "", "");
179             sj1.add(maxString);
180             StringJoiner sj2 = new StringJoiner("", "", "");
181             sj2.add(maxString);
182             sj1.merge(sj2);
183             fail("Should have thrown OutOfMemoryError");
184         } catch (OutOfMemoryError ex) {
185             // okay
186         }
187     }
188 }
189