/* * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.awt.EventQueue; import java.util.ArrayList; import java.util.Arrays; import javax.swing.JPasswordField; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.GapContent; import javax.swing.text.PlainDocument; import javax.swing.text.Segment; import javax.swing.text.StringContent; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.StyleSheet; /** * @test * @bug 8258373 * @summary The JPasswordField#setText() should reset the old internal storage */ public final class CleanInternalStorageOnSetText { public static void main(String[] args) throws Exception { EventQueue.invokeAndWait(() -> { // default case testStorage(false, new JPasswordField()); testStorage(true, new JPasswordField()); // custom Plain String document Document document = new PlainDocument(new StringContent()); testStorage(false, new JPasswordField(document, "", 10)); document = new PlainDocument(new StringContent()); testStorage(true, new JPasswordField(document, "", 10)); // custom Plain GAP document document = new PlainDocument(new GapContent()); testStorage(false, new JPasswordField(document, "", 10)); document = new PlainDocument(new GapContent()); testStorage(true, new JPasswordField(document, "", 10)); // custom HTMLDocument String document document = new HTMLDocument(new StringContent(), new StyleSheet()); testStorage(false, new JPasswordField(document, "", 10)); document = new HTMLDocument(new StringContent(), new StyleSheet()); testStorage(true, new JPasswordField(document, "", 10)); // custom HTMLDocument GAP document document = new HTMLDocument(new GapContent(), new StyleSheet()); testStorage(false, new JPasswordField(document, "", 10)); document = new HTMLDocument(new GapContent(), new StyleSheet()); testStorage(true, new JPasswordField(document, "", 10)); }); } private static void testStorage(boolean makeGap, JPasswordField pf) { test(pf, "123", makeGap); test(pf, "1234567", makeGap); test(pf, "1234567890", makeGap); test(pf, "1".repeat(100), makeGap); test(pf, "1234567890", makeGap); test(pf, "1234567", makeGap); test(pf, "123", makeGap); test(pf, "", makeGap); } private static void test(JPasswordField pf, String text, boolean makeGap) { pf.setText(text); if (makeGap && text.length() > 3) { try { pf.getDocument().remove(1, 2); } catch (BadLocationException e) { throw new RuntimeException(e); } } // if no gaps we can check whole array char[] internalArray = getInternalArray(pf); ArrayList segments = new ArrayList<>(); if (makeGap) { // if gaps exists we can check only part of the array Document doc = pf.getDocument(); int nleft = doc.getLength(); Segment sgm = new Segment(); sgm.setPartialReturn(true); int offs = 0; try { while (nleft > 0) { doc.getText(offs, nleft, sgm); segments.add(sgm); nleft -= sgm.count; offs += sgm.count; } } catch (BadLocationException e) { throw new RuntimeException(e); } } System.err.println("Before = " + Arrays.toString(internalArray)); pf.setText(""); System.err.println("After = " + Arrays.toString(internalArray)); if (!makeGap) { for (char c : internalArray) { if (c != '\u0000' && c != '\n') { throw new RuntimeException(Arrays.toString(internalArray)); } } } else { for (Segment sgm : segments) { for (int i = sgm.offset; i < sgm.count + sgm.offset; i++) { char c = sgm.array[i]; if (c != '\u0000' && c != '\n') { throw new RuntimeException(Arrays.toString(sgm.array)); } } } } } /** * This method returns the reference to the internal data stored by the * document inside JPasswordField. */ private static char[] getInternalArray(JPasswordField pf) { Document doc = pf.getDocument(); int nleft = doc.getLength(); Segment text = new Segment(); int offs = 0; text.setPartialReturn(true); try { doc.getText(offs, nleft, text); } catch (BadLocationException e) { throw new RuntimeException(e); } return text.array; } }