2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.uiDesigner
.core
;
18 import com
.intellij
.openapi
.application
.PluginPathManager
;
19 import com
.intellij
.openapi
.util
.io
.FileUtil
;
20 import com
.intellij
.uiDesigner
.compiler
.AsmCodeGenerator
;
21 import com
.intellij
.uiDesigner
.compiler
.FormErrorInfo
;
22 import com
.intellij
.uiDesigner
.compiler
.NestedFormLoader
;
23 import com
.intellij
.uiDesigner
.compiler
.Utils
;
24 import com
.intellij
.uiDesigner
.lw
.CompiledClassPropertiesProvider
;
25 import com
.intellij
.uiDesigner
.lw
.LwRootContainer
;
26 import junit
.framework
.TestCase
;
27 import org
.objectweb
.asm
.ClassWriter
;
30 import javax
.swing
.border
.EtchedBorder
;
31 import javax
.swing
.border
.TitledBorder
;
33 import java
.io
.ByteArrayInputStream
;
35 import java
.io
.FileInputStream
;
36 import java
.io
.InputStream
;
37 import java
.lang
.reflect
.Field
;
38 import java
.nio
.charset
.Charset
;
39 import java
.util
.HashMap
;
45 public class AsmCodeGeneratorTest
extends TestCase
{
46 private MyNestedFormLoader myNestedFormLoader
;
47 private MyClassLoader myClassLoader
;
49 protected void setUp() throws Exception
{
51 myNestedFormLoader
= new MyNestedFormLoader();
52 myClassLoader
= new MyClassLoader(getClass().getClassLoader());
55 protected void tearDown() throws Exception
{
57 myNestedFormLoader
= null;
61 private AsmCodeGenerator
initCodeGenerator(final String formFileName
, final String className
) throws Exception
{
62 final String testDataPath
= PluginPathManager
.getPluginHomePath("ui-designer") + "/testData/";
63 return initCodeGenerator(formFileName
, className
, testDataPath
);
66 private AsmCodeGenerator
initCodeGenerator(final String formFileName
, final String className
, final String testDataPath
) throws Exception
{
67 String formPath
= testDataPath
+ formFileName
;
68 String javaPath
= testDataPath
+ className
+ ".java";
69 com
.sun
.tools
.javac
.Main
.compile(new String
[] { javaPath
} );
70 String classPath
= testDataPath
+ className
+ ".class";
71 final LwRootContainer rootContainer
= loadFormData(formPath
);
72 final AsmCodeGenerator codeGenerator
= new AsmCodeGenerator(rootContainer
, myClassLoader
, myNestedFormLoader
, false,
73 new ClassWriter(ClassWriter
.COMPUTE_FRAMES
));
74 final FileInputStream classStream
= new FileInputStream(classPath
);
76 codeGenerator
.patchClass(classStream
);
80 FileUtil
.delete(new File(classPath
));
85 private LwRootContainer
loadFormData(final String formPath
) throws Exception
{
86 String formData
= new String(FileUtil
.loadFileText(new File(formPath
)));
87 final CompiledClassPropertiesProvider provider
= new CompiledClassPropertiesProvider(getClass().getClassLoader());
88 return Utils
.getRootContainer(formData
, provider
);
91 private Class
loadAndPatchClass(final String formFileName
, final String className
) throws Exception
{
92 final AsmCodeGenerator codeGenerator
= initCodeGenerator(formFileName
, className
);
94 byte[] patchedData
= getVerifiedPatchedData(codeGenerator
);
97 FileOutputStream fos = new FileOutputStream("C:\\yole\\FormPreview27447\\MainPatched.class");
98 fos.write(patchedData);
102 return myClassLoader
.doDefineClass(className
, patchedData
);
105 private byte[] getVerifiedPatchedData(final AsmCodeGenerator codeGenerator
) {
106 byte[] patchedData
= codeGenerator
.getPatchedData();
107 FormErrorInfo
[] errors
= codeGenerator
.getErrors();
108 FormErrorInfo
[] warnings
= codeGenerator
.getWarnings();
109 if (errors
.length
== 0 && warnings
.length
== 0) {
110 assertNotNull("Class patching failed but no errors or warnings were returned", patchedData
);
112 else if (errors
.length
> 0) {
113 assertTrue(errors
[0].getErrorMessage(), false);
116 assertTrue(warnings
[0].getErrorMessage(), false);
121 private JComponent
getInstrumentedRootComponent(final String formFileName
, final String className
) throws Exception
{
122 Class cls
= loadAndPatchClass(formFileName
, className
);
123 Field rootComponentField
= cls
.getField("myRootComponent");
124 rootComponentField
.setAccessible(true);
125 Object instance
= cls
.newInstance();
126 return (JComponent
)rootComponentField
.get(instance
);
129 public void testSimple() throws Exception
{
130 JComponent rootComponent
= getInstrumentedRootComponent("TestSimple.form", "BindingTest");
131 assertNotNull(rootComponent
);
134 public void testNoSuchField() throws Exception
{
135 AsmCodeGenerator generator
= initCodeGenerator("TestNoSuchField.form", "BindingTest");
136 assertEquals("Cannot bind: field does not exist: BindingTest.myNoSuchField", generator
.getErrors() [0].getErrorMessage());
139 public void testStaticField() throws Exception
{
140 AsmCodeGenerator generator
= initCodeGenerator("TestStaticField.form", "BindingTest");
141 assertEquals("Cannot bind: field is static: BindingTest.myStaticField", generator
.getErrors() [0].getErrorMessage());
144 public void testFinalField() throws Exception
{
145 AsmCodeGenerator generator
= initCodeGenerator("TestFinalField.form", "BindingTest");
146 assertEquals("Cannot bind: field is final: BindingTest.myFinalField", generator
.getErrors() [0].getErrorMessage());
149 public void testPrimitiveField() throws Exception
{
150 AsmCodeGenerator generator
= initCodeGenerator("TestPrimitiveField.form", "BindingTest");
151 assertEquals("Cannot bind: field is of primitive type: BindingTest.myIntField", generator
.getErrors() [0].getErrorMessage());
154 public void testIncompatibleTypeField() throws Exception
{
155 AsmCodeGenerator generator
= initCodeGenerator("TestIncompatibleTypeField.form", "BindingTest");
156 assertEquals("Cannot bind: Incompatible types. Cannot assign javax.swing.JPanel to field BindingTest.myStringField", generator
.getErrors() [0].getErrorMessage());
159 public void testGridLayout() throws Exception
{
160 JComponent rootComponent
= getInstrumentedRootComponent("TestGridConstraints.form", "BindingTest");
161 assertTrue(rootComponent
.getLayout() instanceof GridLayoutManager
);
162 GridLayoutManager gridLayout
= (GridLayoutManager
) rootComponent
.getLayout();
163 assertEquals(1, gridLayout
.getRowCount());
164 assertEquals(1, gridLayout
.getColumnCount());
167 public void testGridConstraints() throws Exception
{
168 JComponent rootComponent
= getInstrumentedRootComponent("TestGridConstraints.form", "BindingTest");
169 assertEquals(1, rootComponent
.getComponentCount());
170 GridLayoutManager gridLayout
= (GridLayoutManager
) rootComponent
.getLayout();
171 final GridConstraints constraints
= gridLayout
.getConstraints(0);
172 assertEquals(1, constraints
.getColSpan());
173 assertEquals(1, constraints
.getRowSpan());
176 public void testIntProperty() throws Exception
{
177 JComponent rootComponent
= getInstrumentedRootComponent("TestIntProperty.form", "BindingTest");
178 assertEquals(1, rootComponent
.getComponentCount());
179 JTextField textField
= (JTextField
) rootComponent
.getComponent(0);
180 assertEquals(37, textField
.getColumns());
181 assertEquals(false, textField
.isEnabled());
184 public void testDoubleProperty() throws Exception
{
185 JSplitPane splitPane
= (JSplitPane
)getInstrumentedRootComponent("TestDoubleProperty.form", "BindingTest");
186 assertEquals(0.1f
, splitPane
.getResizeWeight(), 0.001f
);
189 public void testStringProperty() throws Exception
{
190 JComponent rootComponent
= getInstrumentedRootComponent("TestGridConstraints.form", "BindingTest");
191 JButton btn
= (JButton
) rootComponent
.getComponent(0);
192 assertEquals("MyTestButton", btn
.getText());
195 public void testSplitPane() throws Exception
{
196 JSplitPane splitPane
= (JSplitPane
)getInstrumentedRootComponent("TestSplitPane.form", "BindingTest");
197 assertTrue(splitPane
.getLeftComponent() instanceof JLabel
);
198 assertTrue(splitPane
.getRightComponent() instanceof JCheckBox
);
201 public void testTabbedPane() throws Exception
{
202 JTabbedPane tabbedPane
= (JTabbedPane
) getInstrumentedRootComponent("TestTabbedPane.form", "BindingTest");
203 assertEquals(2, tabbedPane
.getTabCount());
204 assertEquals("First", tabbedPane
.getTitleAt(0));
205 assertEquals("Test Value", tabbedPane
.getTitleAt(1));
206 assertTrue(tabbedPane
.getComponentAt(0) instanceof JLabel
);
207 assertTrue(tabbedPane
.getComponentAt(1) instanceof JButton
);
210 public void testScrollPane() throws Exception
{
211 JScrollPane scrollPane
= (JScrollPane
)getInstrumentedRootComponent("TestScrollPane.form", "BindingTest");
212 assertTrue(scrollPane
.getViewport().getView() instanceof JList
);
215 public void testBorder() throws Exception
{
216 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestBorder.form", "BindingTest");
217 assertTrue(panel
.getBorder() instanceof TitledBorder
);
218 TitledBorder border
= (TitledBorder
) panel
.getBorder();
219 assertEquals("BorderTitle", border
.getTitle());
220 assertTrue(border
.getBorder() instanceof EtchedBorder
);
223 public void testMnemonic() throws Exception
{
224 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestMnemonics.form", "BindingTest");
225 JLabel label
= (JLabel
) panel
.getComponent(0);
226 assertEquals("Mnemonic", label
.getText());
227 assertEquals('M', label
.getDisplayedMnemonic());
228 assertEquals(3, label
.getDisplayedMnemonicIndex());
231 public void testMnemonicFromProperty() throws Exception
{
232 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestMnemonicsProperty.form", "BindingTest");
233 JLabel label
= (JLabel
) panel
.getComponent(0);
234 assertEquals("Mnemonic", label
.getText());
235 assertEquals('M', label
.getDisplayedMnemonic());
236 assertEquals(3, label
.getDisplayedMnemonicIndex());
239 public void testGridBagLayout() throws Exception
{
240 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestGridBag.form", "BindingTest");
241 assertTrue(panel
.getLayout() instanceof GridBagLayout
);
242 GridBagLayout gridBag
= (GridBagLayout
) panel
.getLayout();
243 JButton btn
= (JButton
) panel
.getComponent(0);
244 GridBagConstraints gbc
= gridBag
.getConstraints(btn
);
246 assertEquals(2, gbc
.gridheight
);
247 assertEquals(2, gbc
.gridwidth
);
248 assertEquals(1.0, gbc
.weightx
, 0.01);
249 assertEquals(new Insets(1, 2, 3, 4), gbc
.insets
);
250 assertEquals(GridBagConstraints
.HORIZONTAL
, gbc
.fill
);
251 assertEquals(GridBagConstraints
.NORTHWEST
, gbc
.anchor
);
254 public void testGridBagSpacer() throws Exception
{
255 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestGridBagSpacer.form", "BindingTest");
256 assertTrue(panel
.getLayout() instanceof GridBagLayout
);
257 assertTrue(panel
.getComponent(0) instanceof JLabel
);
258 assertTrue(panel
.getComponent(1) instanceof JPanel
);
260 GridBagLayout gridBag
= (GridBagLayout
) panel
.getLayout();
261 GridBagConstraints gbc
= gridBag
.getConstraints(panel
.getComponent(0));
262 assertEquals(0.0, gbc
.weightx
, 0.01);
263 assertEquals(0.0, gbc
.weighty
, 0.01);
264 gbc
= gridBag
.getConstraints(panel
.getComponent(1));
265 assertEquals(0.0, gbc
.weightx
, 0.01);
266 assertEquals(1.0, gbc
.weighty
, 0.01);
269 public void testLabelFor() throws Exception
{
270 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestLabelFor.form", "BindingTest");
271 JTextField textField
= (JTextField
) panel
.getComponent(0);
272 JLabel label
= (JLabel
) panel
.getComponent(1);
273 assertEquals(textField
, label
.getLabelFor());
276 public void testFieldReference() throws Exception
{
277 Class cls
= loadAndPatchClass("TestFieldReference.form", "FieldReferenceTest");
278 JPanel instance
= (JPanel
) cls
.newInstance();
279 assertEquals(1, instance
.getComponentCount());
282 public void testChainedConstructor() throws Exception
{
283 Class cls
= loadAndPatchClass("TestChainedConstructor.form", "ChainedConstructorTest");
284 Field scrollPaneField
= cls
.getField("myScrollPane");
285 Object instance
= cls
.newInstance();
286 JScrollPane scrollPane
= (JScrollPane
) scrollPaneField
.get(instance
);
287 assertNotNull(scrollPane
.getViewport().getView());
290 public void testConditionalMethodCall() throws Exception
{
291 JPanel panel
= (JPanel
) getInstrumentedRootComponent("TestConditionalMethodCall.form", "ConditionalMethodCallTest");
292 assertNotNull(panel
);
295 public void testMethodCallInSuper() throws Exception
{
296 Class cls
= loadAndPatchClass("TestMethodCallInSuper.form", "MethodCallInSuperTest");
297 JDialog instance
= (JDialog
) cls
.newInstance();
298 assertEquals(1, instance
.getContentPane().getComponentCount());
301 public void testIdeadev14081() throws Exception
{
302 // NOTE: That doesn't really reproduce the bug as it's dependent on a particular instrumentation sequence used during form preview
303 // (the nested form is instrumented with a new AsmCodeGenerator instance directly in the middle of instrumentation of the current form)
304 final String testDataPath
= PluginPathManager
.getPluginHomePath("ui-designer") + File
.separatorChar
+ "testData" + File
.separatorChar
+
305 File
.separatorChar
+ "formEmbedding" + File
.separatorChar
+ "Ideadev14081" + File
.separatorChar
;
306 AsmCodeGenerator embeddedClassGenerator
= initCodeGenerator("Embedded.form", "Embedded", testDataPath
);
307 byte[] embeddedPatchedData
= getVerifiedPatchedData(embeddedClassGenerator
);
308 myClassLoader
.doDefineClass("Embedded", embeddedPatchedData
);
309 myNestedFormLoader
.registerNestedForm("Embedded.form", testDataPath
+ "Embedded.form");
310 AsmCodeGenerator mainClassGenerator
= initCodeGenerator("Main.form", "Main", testDataPath
);
311 byte[] mainPatchedData
= getVerifiedPatchedData(mainClassGenerator
);
314 FileOutputStream fos = new FileOutputStream("C:\\yole\\FormPreview27447\\MainPatched.class");
315 fos.write(mainPatchedData);
319 final Class mainClass
= myClassLoader
.doDefineClass("Main", mainPatchedData
);
320 Object instance
= mainClass
.newInstance();
323 private static class MyClassLoader
extends ClassLoader
{
324 private final byte[] myTestProperties
= Charset
.defaultCharset().encode(TEST_PROPERTY_CONTENT
).array();
325 private static final String TEST_PROPERTY_CONTENT
= "test=Test Value\nmnemonic=Mne&monic";
327 public MyClassLoader(ClassLoader parent
) {
331 public Class
doDefineClass(String name
, byte[] data
) {
332 return defineClass(name
, data
, 0, data
.length
);
335 public Class
<?
> loadClass(String name
) throws ClassNotFoundException
{
336 return super.loadClass(name
);
339 public InputStream
getResourceAsStream(String name
) {
340 if (name
.equals("TestProperties.properties")) {
341 return new ByteArrayInputStream(myTestProperties
, 0, TEST_PROPERTY_CONTENT
.length());
343 return super.getResourceAsStream(name
);
347 private class MyNestedFormLoader
implements NestedFormLoader
{
348 private final Map
<String
, String
> myFormMap
= new HashMap
<String
, String
>();
350 public void registerNestedForm(String formName
, String fileName
) {
351 myFormMap
.put(formName
, fileName
);
354 public LwRootContainer
loadForm(String formFileName
) throws Exception
{
355 final String fileName
= myFormMap
.get(formFileName
);
356 if (fileName
!= null) {
357 return loadFormData(fileName
);
359 throw new UnsupportedOperationException("No nested form found for name " + formFileName
);
362 public String
getClassToBindName(LwRootContainer container
) {
363 return container
.getClassToBind();