|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| TestSwingSet.java | 100% | 99.2% | 93.3% | 98.6% |
|
||||||||||||||
| 1 |
package swingset;
|
|
| 2 |
|
|
| 3 |
import java.awt.Container;
|
|
| 4 |
import javax.swing.JButton;
|
|
| 5 |
import javax.swing.JCheckBox;
|
|
| 6 |
import javax.swing.JComponent;
|
|
| 7 |
import javax.swing.JFrame;
|
|
| 8 |
import javax.swing.JPanel;
|
|
| 9 |
import javax.swing.JRadioButton;
|
|
| 10 |
import javax.swing.JTabbedPane;
|
|
| 11 |
import javax.swing.JToggleButton;
|
|
| 12 |
|
|
| 13 |
import demo.SwingSet;
|
|
| 14 |
import junit.extensions.TestSetup;
|
|
| 15 |
import junit.extensions.jfcunit.JFCTestCase;
|
|
| 16 |
import junit.extensions.jfcunit.JFCTestHelper;
|
|
| 17 |
import junit.extensions.jfcunit.eventdata.AbstractMouseEventData;
|
|
| 18 |
import junit.extensions.jfcunit.eventdata.JTabbedPaneMouseEventData;
|
|
| 19 |
import junit.extensions.jfcunit.eventdata.MouseEventData;
|
|
| 20 |
import junit.extensions.jfcunit.finder.AbstractButtonFinder;
|
|
| 21 |
import junit.extensions.jfcunit.finder.ComponentFinder;
|
|
| 22 |
import junit.extensions.jfcunit.finder.Finder;
|
|
| 23 |
import junit.extensions.jfcunit.finder.FrameFinder;
|
|
| 24 |
import junit.framework.Test;
|
|
| 25 |
import junit.framework.TestSuite;
|
|
| 26 |
import junit.textui.TestRunner;
|
|
| 27 |
|
|
| 28 |
/**
|
|
| 29 |
* A class written as an example of how to use the jfcUnit
|
|
| 30 |
* framework. This class is used to "test" the SwingSet demo
|
|
| 31 |
* shipped with JDK 1.2.2
|
|
| 32 |
*
|
|
| 33 |
* @author <a href="mailto:vraravam@thoughtworks.com">Vijay Aravamudhan : ThoughtWorks Inc.</a>
|
|
| 34 |
*/
|
|
| 35 |
public class TestSwingSet |
|
| 36 |
extends JFCTestCase {
|
|
| 37 |
// since we are using these tab titles all across...
|
|
| 38 |
/**
|
|
| 39 |
* Tab title for the tab: Buttons.
|
|
| 40 |
*/
|
|
| 41 |
private static final String TABTITLE_BUTTONS = "Buttons"; |
|
| 42 |
|
|
| 43 |
/**
|
|
| 44 |
* Tab title for the tab: RadioButtons.
|
|
| 45 |
*/
|
|
| 46 |
private static final String TABTITLE_RADIOBUTTONS = "RadioButtons"; |
|
| 47 |
|
|
| 48 |
/**
|
|
| 49 |
* Tab title for the tab: ToggleButtons.
|
|
| 50 |
*/
|
|
| 51 |
private static final String TABTITLE_TOGGLEBUTTONS = "ToggleButtons"; |
|
| 52 |
|
|
| 53 |
/**
|
|
| 54 |
* Tab title for the tab: Checkboxes.
|
|
| 55 |
*/
|
|
| 56 |
private static final String TABTITLE_CHECKBOXES = "Checkboxes"; |
|
| 57 |
|
|
| 58 |
/**
|
|
| 59 |
* Tab title for the tab: ListBox.
|
|
| 60 |
*/
|
|
| 61 |
private static final String TABTITLE_LISTBOX = "ListBox"; |
|
| 62 |
|
|
| 63 |
/**
|
|
| 64 |
* Tab title for the tab: ScrollPane.
|
|
| 65 |
*/
|
|
| 66 |
private static final String TABTITLE_SCROLLPANE = "ScrollPane"; |
|
| 67 |
|
|
| 68 |
/**
|
|
| 69 |
* Tab title for the tab: Slider.
|
|
| 70 |
*/
|
|
| 71 |
private static final String TABTITLE_SLIDER = "Slider"; |
|
| 72 |
|
|
| 73 |
/**
|
|
| 74 |
* Static reference to an instance of the JFCTestHelper
|
|
| 75 |
* class.
|
|
| 76 |
*/
|
|
| 77 |
private static JFCTestHelper s_helper = new JFCTestHelper(); |
|
| 78 |
|
|
| 79 |
/**
|
|
| 80 |
* <p>Title: TestSetup for starting the SwingSet app</p>
|
|
| 81 |
* <p>Description: Starts the swingset app.</p>
|
|
| 82 |
* <p>Copyright: Copyright (c) 2003</p>
|
|
| 83 |
* <p>Company: JFCUnit Opensource Project project.</p>
|
|
| 84 |
* @author Kevin Wilson
|
|
| 85 |
* @version 1.0
|
|
| 86 |
*/
|
|
| 87 |
private static class StartApp extends TestSetup { |
|
| 88 |
/**
|
|
| 89 |
* Construct the test decorator, which starts the SwingSet.
|
|
| 90 |
* @param test Test case.
|
|
| 91 |
*/
|
|
| 92 | 1 |
public StartApp(final Test test) {
|
| 93 | 1 |
super(test);
|
| 94 |
} |
|
| 95 |
|
|
| 96 |
/**
|
|
| 97 |
* Start the SwingSet application.
|
|
| 98 |
*/
|
|
| 99 | 1 |
public void setUp() { |
| 100 | 1 |
new Thread(new Runnable() { |
| 101 | 1 |
public void run() { |
| 102 | 1 |
SwingSet.main(new String[] {});
|
| 103 |
} |
|
| 104 |
}).start(); |
|
| 105 | 1 |
try {
|
| 106 | 1 |
Thread.currentThread().sleep(10000); |
| 107 |
} catch (InterruptedException ex) {
|
|
| 108 |
} |
|
| 109 |
} |
|
| 110 |
|
|
| 111 |
/**
|
|
| 112 |
* Tear down the swingset application.
|
|
| 113 |
*/
|
|
| 114 | 1 |
public void tearDown() { |
| 115 |
|
|
| 116 |
} |
|
| 117 |
}; |
|
| 118 |
|
|
| 119 |
/**
|
|
| 120 |
* Construct a TestSwingSet which is wrapped by the
|
|
| 121 |
* start application.
|
|
| 122 |
* @return Test Test suite.
|
|
| 123 |
*/
|
|
| 124 | 1 |
public static Test suite() { |
| 125 | 1 |
return new StartApp(new TestSuite(TestSwingSet.class)); |
| 126 |
} |
|
| 127 |
|
|
| 128 |
|
|
| 129 |
|
|
| 130 |
/**
|
|
| 131 |
* Default JUnit constructor accepting a String.
|
|
| 132 |
*
|
|
| 133 |
* @param name Name of the test method to run
|
|
| 134 |
* (Called by the JUnit framework while building a suite of tests)
|
|
| 135 |
*/
|
|
| 136 | 5 |
public TestSwingSet(final String name) {
|
| 137 | 5 |
super(name);
|
| 138 |
} |
|
| 139 |
|
|
| 140 |
/**
|
|
| 141 |
* A method to "search" for the SwingSet frame and "find"
|
|
| 142 |
* the tab pane inside it.
|
|
| 143 |
*
|
|
| 144 |
* @return The tab pane containing the tabs that we want to test with.
|
|
| 145 |
*/
|
|
| 146 | 5 |
private JTabbedPane getReferenceToTabPane() {
|
| 147 | 5 |
Finder f = null;
|
| 148 | 5 |
f = new FrameFinder("SwingSet"); |
| 149 | 5 |
JFrame frame = (JFrame) f.find(); |
| 150 | 5 |
assertNotNull("Could not find frame: SwingSet", frame);
|
| 151 | 5 |
f = new ComponentFinder(JTabbedPane.class); |
| 152 | 5 |
JTabbedPane tabbedPane = (JTabbedPane) f.find(frame, 0); |
| 153 | 5 |
assertNotNull("Could not find tabbed pane", tabbedPane);
|
| 154 | 5 |
return tabbedPane;
|
| 155 |
} |
|
| 156 |
|
|
| 157 |
/**
|
|
| 158 |
* A helper method to click on the specified component
|
|
| 159 |
* and suspend the thread basedon the specified boolean.
|
|
| 160 |
*
|
|
| 161 |
* Note: Though this method is not considered good programming practice,
|
|
| 162 |
* I have used it so that there is no repetition of code
|
|
| 163 |
*
|
|
| 164 |
* @param evtData The event data container.
|
|
| 165 |
* @param wait boolean specifying whether to suspend the thread
|
|
| 166 |
* after firing the specified event. Since this is an
|
|
| 167 |
* example, the user might wish to see what is happening.
|
|
| 168 |
*/
|
|
| 169 | 79 |
private void clickAndWait(final AbstractMouseEventData evtData, |
| 170 |
final boolean wait) {
|
|
| 171 | 79 |
s_helper.enterClickAndLeave(evtData); |
| 172 | 79 |
awtSleep(); |
| 173 |
|
|
| 174 | 79 |
if (wait) {
|
| 175 | 61 |
try {
|
| 176 | 61 |
Thread.sleep(1000); |
| 177 |
} catch (InterruptedException ie) {
|
|
| 178 |
// don't do anything, but still catch it
|
|
| 179 |
} |
|
| 180 |
} |
|
| 181 |
} |
|
| 182 |
|
|
| 183 |
/**
|
|
| 184 |
* We can also find a component by specifying just the index.
|
|
| 185 |
*
|
|
| 186 |
* @param maxNum The number of similar components which are
|
|
| 187 |
* available - this is specified so as to avoid an
|
|
| 188 |
* ArrayIndexOutOfRange exception.
|
|
| 189 |
* @param compClass The type of objects to be found.
|
|
| 190 |
* @param container The container of the objects to be found.
|
|
| 191 |
* @param msg Part of the error message:
|
|
| 192 |
* <code>"Could not find the " + msg + " for index: "</code>
|
|
| 193 |
*/
|
|
| 194 | 4 |
private void randomClicks(final int maxNum, |
| 195 |
final Class compClass, |
|
| 196 |
final Container container, |
|
| 197 |
final String msg) {
|
|
| 198 | 4 |
JComponent comp; |
| 199 | 4 |
Finder f = new ComponentFinder(compClass);
|
| 200 | 4 |
for (int i = 0; i < 10; i++) { |
| 201 | 40 |
int j = (int) (Math.random() * maxNum); |
| 202 | 40 |
comp = (JComponent) f.find(container, j); |
| 203 | 40 |
assertNotNull("Could not find the " + msg + " for index: " + j, comp); |
| 204 | 40 |
clickAndWait(new MouseEventData(this, comp), true); |
| 205 |
} |
|
| 206 |
} |
|
| 207 |
|
|
| 208 |
/**
|
|
| 209 |
* Tests selecting different tabs.
|
|
| 210 |
* <ul>
|
|
| 211 |
* <li>Specifying the tab titles</li>
|
|
| 212 |
* <li>Random selection using tab index</li>
|
|
| 213 |
* </ul>
|
|
| 214 |
*/
|
|
| 215 | 1 |
public void testSelectingDifferentTabs() { |
| 216 | 1 |
JTabbedPane tabbedPane = getReferenceToTabPane(); |
| 217 |
// select by tab title
|
|
| 218 | 1 |
String[] tabTitles = new String[] {
|
| 219 |
TABTITLE_RADIOBUTTONS, TABTITLE_CHECKBOXES, TABTITLE_LISTBOX, |
|
| 220 |
TABTITLE_SLIDER, TABTITLE_SCROLLPANE}; |
|
| 221 | 1 |
for (int i = 0; i < tabTitles.length; i++) { |
| 222 | 5 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 223 |
tabTitles[i], 1), false);
|
|
| 224 |
} |
|
| 225 |
|
|
| 226 |
// select by tab index
|
|
| 227 | 1 |
int[] tabIndices = new int[] { |
| 228 |
5, 7, 2, 4, 9, 1, 0, 8, 6}; |
|
| 229 | 1 |
for (int i = 0; i < tabIndices.length; i++) { |
| 230 | 9 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, tabIndices[i], |
| 231 |
1), false);
|
|
| 232 |
} |
|
| 233 |
} |
|
| 234 |
|
|
| 235 |
/**
|
|
| 236 |
* Tests selecting different buttons in the <code>TABTITLE_BUTTONS</code> tab.
|
|
| 237 |
* <ul>
|
|
| 238 |
* <li>Specifying the button labels</li>
|
|
| 239 |
* <li>Random selection using button index</li>
|
|
| 240 |
* </ul>
|
|
| 241 |
*/
|
|
| 242 | 1 |
public void testSelectButtons() { |
| 243 | 1 |
JTabbedPane tabbedPane = getReferenceToTabPane(); |
| 244 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 245 |
TABTITLE_BUTTONS, 1), true);
|
|
| 246 |
|
|
| 247 |
// check that the correct tab has focus
|
|
| 248 | 1 |
assertTrue(TABTITLE_BUTTONS + " tab does not have focus",
|
| 249 |
tabbedPane.hasFocus()); |
|
| 250 |
|
|
| 251 | 1 |
JPanel panel = (JPanel) tabbedPane.getSelectedComponent(); |
| 252 | 1 |
Finder f = new AbstractButtonFinder("One"); |
| 253 | 1 |
JButton button1 = (JButton) f.find(panel, 0); |
| 254 | 1 |
assertNotNull("Could not find the button: One", button1);
|
| 255 | 1 |
f = new AbstractButtonFinder("Two"); |
| 256 | 1 |
JButton button2 = (JButton) f.find(panel, 0); |
| 257 | 1 |
assertNotNull("Could not find the button: Two", button2);
|
| 258 | 1 |
f = new AbstractButtonFinder("Three"); |
| 259 | 1 |
JButton button3 = (JButton) f.find(panel, 0); |
| 260 | 1 |
assertNotNull("Could not find the button: Three", button3);
|
| 261 | 1 |
f = new AbstractButtonFinder("Left"); |
| 262 | 1 |
JButton button4 = (JButton) f.find(panel, 0); |
| 263 | 1 |
assertNotNull("Could not find the button: Left", button4);
|
| 264 | 1 |
f = new AbstractButtonFinder("Right"); |
| 265 | 1 |
JButton button5 = (JButton) f.find(panel, 0); |
| 266 | 1 |
assertNotNull("Could not find the button: Right", button5);
|
| 267 |
|
|
| 268 | 1 |
clickAndWait(new MouseEventData(this, button1), true); |
| 269 | 1 |
clickAndWait(new MouseEventData(this, button2), true); |
| 270 | 1 |
clickAndWait(new MouseEventData(this, button3), true); |
| 271 | 1 |
clickAndWait(new MouseEventData(this, button4), true); |
| 272 | 1 |
clickAndWait(new MouseEventData(this, button5), true); |
| 273 |
|
|
| 274 |
// we can also find a component by specifying just the index
|
|
| 275 | 1 |
randomClicks(8, JButton.class, panel, "button"); |
| 276 |
|
|
| 277 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 278 |
TABTITLE_BUTTONS, 1), false);
|
|
| 279 |
} |
|
| 280 |
|
|
| 281 |
/**
|
|
| 282 |
* Tests selecting different radio buttons in the <code>TABTITLE_RADIOBUTTONS</code> tab.
|
|
| 283 |
* <ul>
|
|
| 284 |
* <li>Specifying the button labels</li>
|
|
| 285 |
* <li>Random selection using button index</li>
|
|
| 286 |
* </ul>
|
|
| 287 |
*/
|
|
| 288 | 1 |
public void testSelectRadioButtons() { |
| 289 | 1 |
JTabbedPane tabbedPane = getReferenceToTabPane(); |
| 290 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 291 |
TABTITLE_RADIOBUTTONS, 1), true);
|
|
| 292 |
|
|
| 293 |
// check that the correct tab has focus
|
|
| 294 | 1 |
assertTrue(TABTITLE_RADIOBUTTONS + " tab does not have focus",
|
| 295 |
tabbedPane.hasFocus()); |
|
| 296 |
|
|
| 297 | 1 |
JPanel panel = (JPanel) tabbedPane.getSelectedComponent(); |
| 298 | 1 |
Finder f = new AbstractButtonFinder("One"); |
| 299 | 1 |
JRadioButton button1 = (JRadioButton) f.find(panel, 0); |
| 300 | 1 |
assertNotNull("Could not find the radio button: One", button1);
|
| 301 |
|
|
| 302 | 1 |
f = new AbstractButtonFinder("Two"); |
| 303 | 1 |
JRadioButton button2 = (JRadioButton) f.find(panel, 0); |
| 304 | 1 |
assertNotNull("Could not find the radio button: Two", button2);
|
| 305 | 1 |
f = new AbstractButtonFinder("Three"); |
| 306 | 1 |
JRadioButton button3 = (JRadioButton) f.find(panel, 0); |
| 307 | 1 |
assertNotNull("Could not find the radio button: Three", button3);
|
| 308 | 1 |
f = new AbstractButtonFinder("Left"); |
| 309 | 1 |
JRadioButton button4 = (JRadioButton) f.find(panel, 0); |
| 310 | 1 |
assertNotNull("Could not find the radio button: Left", button4);
|
| 311 | 1 |
f = new AbstractButtonFinder("Center"); |
| 312 | 1 |
JRadioButton button5 = (JRadioButton) f.find(panel, 0); |
| 313 | 1 |
assertNotNull("Could not find the radio button: Center", button5);
|
| 314 | 1 |
f = new AbstractButtonFinder("Right"); |
| 315 | 1 |
JRadioButton button6 = (JRadioButton) f.find(panel, 0); |
| 316 | 1 |
assertNotNull("Could not find the radio button: Right", button6);
|
| 317 |
|
|
| 318 | 1 |
clickAndWait(new MouseEventData(this, button1), true); |
| 319 | 1 |
clickAndWait(new MouseEventData(this, button2), true); |
| 320 | 1 |
clickAndWait(new MouseEventData(this, button3), true); |
| 321 | 1 |
clickAndWait(new MouseEventData(this, button4), true); |
| 322 | 1 |
clickAndWait(new MouseEventData(this, button5), true); |
| 323 | 1 |
clickAndWait(new MouseEventData(this, button6), true); |
| 324 |
|
|
| 325 |
// we can also find a component by specifying just the index
|
|
| 326 | 1 |
randomClicks(9, JRadioButton.class, panel, "radio button"); |
| 327 |
|
|
| 328 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 329 |
TABTITLE_RADIOBUTTONS, 1), false);
|
|
| 330 |
} |
|
| 331 |
|
|
| 332 |
/**
|
|
| 333 |
* Tests selecting different toggle buttons in the <code>TABTITLE_TOGGLEBUTTONS</code> tab.
|
|
| 334 |
* <ul>
|
|
| 335 |
* <li>Specifying the button labels</li>
|
|
| 336 |
* <li>Random selection using button index</li>
|
|
| 337 |
* </ul>
|
|
| 338 |
*/
|
|
| 339 | 1 |
public void testSelectToggleButtons() { |
| 340 | 1 |
JTabbedPane tabbedPane = getReferenceToTabPane(); |
| 341 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 342 |
TABTITLE_TOGGLEBUTTONS, 1), true);
|
|
| 343 |
|
|
| 344 |
// check that the correct tab has focus
|
|
| 345 | 1 |
assertTrue(TABTITLE_TOGGLEBUTTONS + " tab does not have focus",
|
| 346 |
tabbedPane.hasFocus()); |
|
| 347 |
|
|
| 348 | 1 |
JPanel panel = (JPanel) tabbedPane.getSelectedComponent(); |
| 349 | 1 |
Finder f = new AbstractButtonFinder("One"); |
| 350 | 1 |
JToggleButton button1 = (JToggleButton) f.find(panel, 0); |
| 351 | 1 |
assertNotNull("Could not find the button: One", button1);
|
| 352 | 1 |
f = new AbstractButtonFinder("Two"); |
| 353 | 1 |
JToggleButton button2 = (JToggleButton) f.find(panel, 0); |
| 354 | 1 |
assertNotNull("Could not find the button: Two", button2);
|
| 355 | 1 |
f = new AbstractButtonFinder("Three"); |
| 356 | 1 |
JToggleButton button3 = (JToggleButton) f.find(panel, 0); |
| 357 | 1 |
assertNotNull("Could not find the button: Three", button3);
|
| 358 |
|
|
| 359 | 1 |
clickAndWait(new MouseEventData(this, button1), true); |
| 360 | 1 |
clickAndWait(new MouseEventData(this, button2), true); |
| 361 | 1 |
clickAndWait(new MouseEventData(this, button3), true); |
| 362 |
|
|
| 363 |
// we can also find a component by specifying just the index
|
|
| 364 | 1 |
randomClicks(6, JToggleButton.class, panel, "toggle button"); |
| 365 |
|
|
| 366 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 367 |
TABTITLE_TOGGLEBUTTONS, 1), false);
|
|
| 368 |
} |
|
| 369 |
|
|
| 370 |
/**
|
|
| 371 |
* Tests selecting different check boxes in the
|
|
| 372 |
* <code>TABTITLE_CHECKBOXES</code> tab.
|
|
| 373 |
* <ul>
|
|
| 374 |
* <li>Specifying the button labels</li>
|
|
| 375 |
* <li>Random selection using button index</li>
|
|
| 376 |
* </ul>
|
|
| 377 |
*/
|
|
| 378 | 1 |
public void testSelectCheckBoxes() { |
| 379 | 1 |
JTabbedPane tabbedPane = getReferenceToTabPane(); |
| 380 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 381 |
TABTITLE_CHECKBOXES, 1), true);
|
|
| 382 |
|
|
| 383 |
// check that the correct tab has focus
|
|
| 384 | 1 |
assertTrue(TABTITLE_CHECKBOXES + " tab does not have focus",
|
| 385 |
tabbedPane.hasFocus()); |
|
| 386 |
|
|
| 387 | 1 |
JPanel panel = (JPanel) tabbedPane.getSelectedComponent(); |
| 388 | 1 |
Finder f = new ComponentFinder(JCheckBox.class); |
| 389 | 1 |
JCheckBox box1 = (JCheckBox) f.find(panel, 0); |
| 390 | 1 |
assertNotNull("Could not find the check box: One", box1);
|
| 391 | 1 |
JCheckBox box2 = (JCheckBox) f.find(panel, 1); |
| 392 | 1 |
assertNotNull("Could not find the check box: Two", box2);
|
| 393 | 1 |
JCheckBox box3 = (JCheckBox) f.find(panel, 2); |
| 394 | 1 |
assertNotNull("Could not find the check box: Three", box3);
|
| 395 |
|
|
| 396 | 1 |
clickAndWait(new MouseEventData(this, box1), true); |
| 397 | 1 |
clickAndWait(new MouseEventData(this, box2), true); |
| 398 | 1 |
clickAndWait(new MouseEventData(this, box3), true); |
| 399 |
|
|
| 400 |
// we can also find a component by specifying just the index
|
|
| 401 | 1 |
randomClicks(6, JCheckBox.class, panel, "check box"); |
| 402 |
|
|
| 403 | 1 |
clickAndWait(new JTabbedPaneMouseEventData(this, tabbedPane, -1, |
| 404 |
TABTITLE_CHECKBOXES, 1), false);
|
|
| 405 |
} |
|
| 406 |
|
|
| 407 |
/**
|
|
| 408 |
* Main method to run this class from the command line.
|
|
| 409 |
*
|
|
| 410 |
* @param args Command line arguments.
|
|
| 411 |
*/
|
|
| 412 | 0 |
public static void main(final String[] args) { |
| 413 | 0 |
TestRunner.run(TestSwingSet.suite()); |
| 414 |
} |
|
| 415 |
} |
|
| 416 |
|
|
||||||||||