undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2025, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key printer
|
||||
* @bug 8153732 8212202 8221263 8221412 8222108 8263311
|
||||
* @requires (os.family == "Windows")
|
||||
* @summary Windows remote printer changes do not reflect in lookupPrintServices()
|
||||
* @run main/manual RemotePrinterStatusRefresh
|
||||
*/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import javax.print.PrintService;
|
||||
import javax.print.PrintServiceLookup;
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import static javax.swing.BorderFactory.createTitledBorder;
|
||||
|
||||
public class RemotePrinterStatusRefresh extends WindowAdapter {
|
||||
|
||||
private static final long TIMEOUT = 15L * 60;
|
||||
|
||||
|
||||
private static final CountDownLatch latch = new CountDownLatch(1);
|
||||
private static volatile RemotePrinterStatusRefresh test;
|
||||
|
||||
private volatile boolean testResult;
|
||||
private volatile boolean testTimedOut;
|
||||
|
||||
private final JFrame frame;
|
||||
|
||||
private JButton refreshButton;
|
||||
private JButton passButton;
|
||||
private JButton failButton;
|
||||
|
||||
private final ServiceItemListModel beforeList;
|
||||
private final ServiceItemListModel afterList;
|
||||
|
||||
private JTextField timeLeft;
|
||||
|
||||
private final Timer timer;
|
||||
private final long startTime;
|
||||
|
||||
|
||||
private static class ServiceItem {
|
||||
private enum State {
|
||||
REMOVED, UNCHANGED, ADDED
|
||||
}
|
||||
|
||||
final String name;
|
||||
State state;
|
||||
|
||||
private ServiceItem(final String name) {
|
||||
this.name = name;
|
||||
state = State.UNCHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof ServiceItem)
|
||||
&& ((ServiceItem) obj).name.equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ServiceItemListModel extends AbstractListModel<ServiceItem> {
|
||||
private final List<ServiceItem> list;
|
||||
|
||||
private ServiceItemListModel(List<ServiceItem> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceItem getElementAt(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
private void refreshList(List<ServiceItem> newList) {
|
||||
list.clear();
|
||||
list.addAll(newList);
|
||||
fireChanged();
|
||||
}
|
||||
|
||||
private void fireChanged() {
|
||||
fireContentsChanged(this, 0, list.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ServiceItemListRenderer extends DefaultListCellRenderer {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list,
|
||||
Object value,
|
||||
int index,
|
||||
boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
Component component =
|
||||
super.getListCellRendererComponent(list, value, index,
|
||||
isSelected, cellHasFocus);
|
||||
switch (((ServiceItem) value).state) {
|
||||
case REMOVED:
|
||||
component.setBackground(Color.RED);
|
||||
component.setForeground(Color.WHITE);
|
||||
break;
|
||||
case ADDED:
|
||||
component.setBackground(Color.GREEN);
|
||||
component.setForeground(Color.BLACK);
|
||||
break;
|
||||
case UNCHANGED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String INSTRUCTIONS_TEXT =
|
||||
"Please follow the steps for this manual test:\n"
|
||||
+ "Step 0: \"Before\" list is populated with currently "
|
||||
+ "configured printers.\n"
|
||||
+ "Step 1: Add or Remove a network printer using "
|
||||
+ "Windows Control Panel.\n"
|
||||
+ "Step 2: Click Refresh."
|
||||
+ "\"After\" list is populated with updated list "
|
||||
+ "of printers.\n"
|
||||
+ "Step 3: Compare the list of printers in \"Before\" and "
|
||||
+ "\"After\" lists.\n"
|
||||
+ " Added printers are highlighted with "
|
||||
+ "green color, removed ones with "
|
||||
+ "red color.\n"
|
||||
+ "Step 4: Click Pass if the list of printers is correctly "
|
||||
+ "updated.\n"
|
||||
+ "Step 5: If the list is not updated, click Refresh again.\n"
|
||||
+ "Step 6: If the list does not update, click Fail.\n"
|
||||
+ "\n"
|
||||
+ "You have to click Refresh to enable Pass and Fail buttons. "
|
||||
+ "If no button is pressed,\n"
|
||||
+ "the test will time out. "
|
||||
+ "Closing the window also fails the test.";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SwingUtilities.invokeAndWait(RemotePrinterStatusRefresh::createUI);
|
||||
|
||||
latch.await();
|
||||
if (!test.testResult) {
|
||||
throw new RuntimeException("Test failed"
|
||||
+ (test.testTimedOut ? " because of time out" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
private static void createUI() {
|
||||
test = new RemotePrinterStatusRefresh();
|
||||
}
|
||||
|
||||
private RemotePrinterStatusRefresh() {
|
||||
frame = new JFrame("RemotePrinterStatusRefresh");
|
||||
frame.addWindowListener(this);
|
||||
|
||||
|
||||
JPanel northPanel = new JPanel(new BorderLayout());
|
||||
northPanel.add(createInfoPanel(), BorderLayout.NORTH);
|
||||
northPanel.add(createInstructionsPanel(), BorderLayout.SOUTH);
|
||||
|
||||
|
||||
beforeList = new ServiceItemListModel(
|
||||
Collections.unmodifiableList(collectPrinterList()));
|
||||
afterList = new ServiceItemListModel(new ArrayList<>());
|
||||
logList("Before:", beforeList.list);
|
||||
|
||||
JPanel listPanel = new JPanel(new GridLayout(1, 2));
|
||||
listPanel.setBorder(createTitledBorder("Print Services"));
|
||||
listPanel.add(createListPanel(beforeList, "Before:", 'b'));
|
||||
listPanel.add(createListPanel(afterList, "After:", 'a'));
|
||||
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(northPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(listPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(createButtonPanel(), BorderLayout.SOUTH);
|
||||
|
||||
|
||||
frame.add(mainPanel);
|
||||
frame.pack();
|
||||
refreshButton.requestFocusInWindow();
|
||||
frame.setVisible(true);
|
||||
|
||||
|
||||
timer = new Timer(1000, this::updateTimeLeft);
|
||||
timer.start();
|
||||
startTime = System.currentTimeMillis();
|
||||
updateTimeLeft(null);
|
||||
}
|
||||
|
||||
private JPanel createInfoPanel() {
|
||||
JLabel javaLabel = new JLabel("Java version:");
|
||||
JTextField javaVersion =
|
||||
new JTextField(System.getProperty("java.runtime.version"));
|
||||
javaVersion.setEditable(false);
|
||||
javaLabel.setLabelFor(javaVersion);
|
||||
|
||||
JLabel timeoutLabel = new JLabel("Time left:");
|
||||
timeLeft = new JTextField();
|
||||
timeLeft.setEditable(false);
|
||||
timeoutLabel.setLabelFor(timeLeft);
|
||||
|
||||
JPanel infoPanel = new JPanel();
|
||||
GroupLayout layout = new GroupLayout(infoPanel);
|
||||
infoPanel.setLayout(layout);
|
||||
infoPanel.setBorder(BorderFactory.createTitledBorder("Info"));
|
||||
layout.setAutoCreateGaps(true);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addComponent(javaLabel)
|
||||
.addComponent(timeoutLabel)
|
||||
)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, true)
|
||||
.addComponent(javaVersion)
|
||||
.addComponent(timeLeft)
|
||||
)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(javaLabel)
|
||||
.addComponent(javaVersion)
|
||||
)
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(timeoutLabel)
|
||||
.addComponent(timeLeft))
|
||||
);
|
||||
return infoPanel;
|
||||
}
|
||||
|
||||
private JPanel createInstructionsPanel() {
|
||||
JPanel instructionsPanel = new JPanel(new BorderLayout());
|
||||
JTextArea instructionText = new JTextArea(INSTRUCTIONS_TEXT);
|
||||
instructionText.setEditable(false);
|
||||
instructionsPanel.setBorder(createTitledBorder("Test Instructions"));
|
||||
instructionsPanel.add(new JScrollPane(instructionText));
|
||||
return instructionsPanel;
|
||||
}
|
||||
|
||||
private JPanel createListPanel(final ServiceItemListModel model,
|
||||
final String title,
|
||||
final char mnemonic) {
|
||||
JPanel panel = new JPanel();
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||
JList<ServiceItem> list = new JList<>(model);
|
||||
list.setCellRenderer(new ServiceItemListRenderer());
|
||||
|
||||
JLabel label = new JLabel(title);
|
||||
label.setLabelFor(list);
|
||||
label.setDisplayedMnemonic(mnemonic);
|
||||
JPanel labelPanel = new JPanel();
|
||||
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.X_AXIS));
|
||||
labelPanel.add(label, BorderLayout.EAST);
|
||||
labelPanel.add(Box.createHorizontalGlue());
|
||||
|
||||
panel.add(labelPanel);
|
||||
panel.add(new JScrollPane(list));
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createButtonPanel() {
|
||||
refreshButton = new JButton("Refresh");
|
||||
refreshButton.addActionListener(this::refresh);
|
||||
|
||||
passButton = new JButton("Pass");
|
||||
passButton.addActionListener(this::pass);
|
||||
passButton.setEnabled(false);
|
||||
|
||||
failButton = new JButton("Fail");
|
||||
failButton.addActionListener(this::fail);
|
||||
failButton.setEnabled(false);
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
|
||||
buttonPanel.add(Box.createHorizontalGlue());
|
||||
buttonPanel.add(refreshButton);
|
||||
buttonPanel.add(passButton);
|
||||
buttonPanel.add(failButton);
|
||||
buttonPanel.add(Box.createHorizontalGlue());
|
||||
return buttonPanel;
|
||||
}
|
||||
|
||||
private static List<ServiceItem> collectPrinterList() {
|
||||
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
|
||||
List<ServiceItem> list = new ArrayList<>(printServices.length);
|
||||
for (PrintService service : printServices) {
|
||||
list.add(new ServiceItem(service.getName()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void logList(final String title, final List<ServiceItem> list) {
|
||||
System.out.println(title);
|
||||
for (ServiceItem item : list) {
|
||||
System.out.println(item.name);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void compareLists(final ServiceItemListModel before, final ServiceItemListModel after) {
|
||||
boolean beforeUpdated = false;
|
||||
boolean afterUpdated = false;
|
||||
|
||||
for (ServiceItem item : before.list) {
|
||||
if (!after.list.contains(item)) {
|
||||
item.state = ServiceItem.State.REMOVED;
|
||||
beforeUpdated = true;
|
||||
} else if (item.state != ServiceItem.State.UNCHANGED) {
|
||||
item.state = ServiceItem.State.UNCHANGED;
|
||||
beforeUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (ServiceItem item : after.list) {
|
||||
if (!before.list.contains(item)) {
|
||||
item.state = ServiceItem.State.ADDED;
|
||||
afterUpdated = true;
|
||||
} else if (item.state != ServiceItem.State.UNCHANGED) {
|
||||
item.state = ServiceItem.State.UNCHANGED;
|
||||
afterUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (beforeUpdated) {
|
||||
before.fireChanged();
|
||||
}
|
||||
if (afterUpdated) {
|
||||
after.fireChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
System.out.println("The window closed");
|
||||
disposeUI();
|
||||
}
|
||||
|
||||
private void disposeUI() {
|
||||
timer.stop();
|
||||
latch.countDown();
|
||||
frame.dispose();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void refresh(ActionEvent e) {
|
||||
System.out.println("Refresh button pressed");
|
||||
afterList.refreshList(collectPrinterList());
|
||||
compareLists(beforeList, afterList);
|
||||
passButton.setEnabled(true);
|
||||
failButton.setEnabled(true);
|
||||
logList("After:", afterList.list);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void pass(ActionEvent e) {
|
||||
System.out.println("Pass button pressed");
|
||||
testResult = true;
|
||||
disposeUI();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void fail(ActionEvent e) {
|
||||
System.out.println("Fail button pressed");
|
||||
testResult = false;
|
||||
disposeUI();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void updateTimeLeft(ActionEvent e) {
|
||||
long elapsed = (System.currentTimeMillis() - startTime) / 1000;
|
||||
long left = TIMEOUT - elapsed;
|
||||
if (left < 0) {
|
||||
testTimedOut = true;
|
||||
disposeUI();
|
||||
}
|
||||
timeLeft.setText(formatTime(left));
|
||||
}
|
||||
|
||||
private static String formatTime(final long seconds) {
|
||||
long minutes = seconds / 60;
|
||||
return String.format("%d:%02d", minutes, seconds - minutes * 60);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue