1 /* 2 * Copyright (c) 2014, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package test.javafx.css; 26 27 import javafx.beans.property.Property; 28 import javafx.collections.FXCollections; 29 import javafx.collections.ObservableList; 30 import javafx.collections.ObservableSet; 31 import javafx.geometry.Insets; 32 import javafx.geometry.Pos; 33 import javafx.scene.effect.Effect; 34 import javafx.scene.effect.InnerShadow; 35 import javafx.scene.paint.Color; 36 import javafx.scene.paint.Paint; 37 import javafx.scene.text.Font; 38 import javafx.util.Duration; 39 import org.junit.Before; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 import org.junit.runners.Parameterized; 43 44 import java.lang.reflect.Method; 45 import java.util.Arrays; 46 import java.util.Collection; 47 import java.util.List; 48 import java.util.function.Function; 49 import javafx.css.CssMetaData; 50 import javafx.css.PseudoClass; 51 import javafx.css.StyleConverter; 52 import javafx.css.Styleable; 53 import javafx.css.StyleableProperty; 54 import javafx.css.StyleablePropertyFactory; 55 import javafx.css.StyleablePropertyFactoryShim; 56 57 import static org.junit.Assert.assertEquals; 58 import static org.junit.Assert.assertNotNull; 59 import static org.junit.Assert.assertNotSame; 60 import static org.junit.Assert.assertSame; 61 import static org.junit.Assert.fail; 62 import static org.junit.runners.Parameterized.Parameters; 63 64 @RunWith(Parameterized.class) 65 public class StyleablePropertyFactory_createMethod_Test { 66 67 @Before public void setup() { 68 StyleablePropertyFactoryShim.clearDataForTesting(MyStyleable.styleablePropertyFactory); 69 StyleablePropertyFactoryShim.clearDataForTesting(MyStyleable1.styleablePropertyFactory); 70 StyleablePropertyFactoryShim.clearDataForTesting(MyStyleable2.styleablePropertyFactory); 71 StyleablePropertyFactoryShim.clearDataForTesting(MyStyleableEnum.styleablePropertyFactory); 72 } 73 74 private static class Data<T> { 75 final String createMethodName; 76 final StyleConverter converter; 77 final T initialValue; 78 79 Data(String createMethodName, StyleConverter converter, T initialValue) { 80 this.createMethodName = createMethodName; 81 this.converter = converter; 82 this.initialValue = initialValue; 83 } 84 } 85 86 private final Data data; 87 public StyleablePropertyFactory_createMethod_Test(Data data) { 88 this.data = data; 89 } 90 91 @Parameters 92 public static Collection<Data[]> data() { 93 94 return Arrays.asList(new Data[][] { 95 { new Data("createStyleableBooleanProperty", StyleConverter.getBooleanConverter(), Boolean.TRUE) }, 96 { new Data("createStyleableColorProperty", StyleConverter.getColorConverter(), Color.YELLOW) }, 97 { new Data("createStyleableDurationProperty", StyleConverter.getDurationConverter(), Duration.millis(30)) }, 98 { new Data("createStyleableEffectProperty", StyleConverter.getEffectConverter(), new InnerShadow(10d, Color.RED)) }, 99 { new Data("createStyleableEnumProperty", StyleConverter.getEnumConverter(Pos.class), Pos.CENTER) }, 100 { new Data("createStyleableFontProperty", StyleConverter.getFontConverter(), Font.font(18)) }, 101 { new Data("createStyleableInsetsProperty", StyleConverter.getInsetsConverter(), new Insets(1,1,1,1)) }, 102 { new Data("createStyleableNumberProperty", StyleConverter.getSizeConverter(), Double.valueOf(42d)) }, 103 { new Data("createStyleablePaintProperty", StyleConverter.getPaintConverter(), Color.BLUE) }, 104 { new Data("createStyleableStringProperty", StyleConverter.getStringConverter(), "ABC") }, 105 { new Data("createStyleableUrlProperty", StyleConverter.getUrlConverter(), "http://oracle.com") } 106 }); 107 108 } 109 110 void check(MyStyleable<?> styleable, StyleConverter<?,?> converter, boolean inherits) { 111 112 assertNotNull(styleable.getProp()); 113 assertSame(styleable, ((Property) styleable.getProp()).getBean()); 114 assertEquals("prop", ((Property) styleable.getProp()).getName()); 115 assertNotNull(styleable.getProp().getCssMetaData()); 116 assertEquals("-my-prop", styleable.getProp().getCssMetaData().getProperty()); 117 if (styleable instanceof MyStyleableEnum) { 118 // for Enum, there is no static Enum converter instance, so assertSame fails 119 assertEquals(converter, styleable.getProp().getCssMetaData().getConverter()); 120 } else { 121 assertSame(converter, styleable.getProp().getCssMetaData().getConverter()); 122 } 123 124 assertEquals(styleable.getProp().getCssMetaData().getInitialValue(null), styleable.getProp().getValue()); 125 assertEquals(styleable.getProp().getCssMetaData().toString(), Boolean.valueOf(inherits), styleable.getProp().getCssMetaData().isInherits()); 126 127 List<CssMetaData<? extends Styleable,?>> list = styleable.getCssMetaData(); 128 assert list != null; 129 assert list.isEmpty() == false; 130 131 for(CssMetaData metaData : list) { 132 if ("-my-prop".equals(metaData.getProperty())) { 133 StyleableProperty prop = metaData.getStyleableProperty(styleable); 134 assert prop == styleable.getProp(); 135 assert prop.getCssMetaData() == metaData; 136 } 137 } 138 139 } 140 141 void check(MyStyleable<?> styleable1, MyStyleable<?> styleable2, StyleConverter converter, boolean inherits) { 142 assertNotSame(styleable1, styleable2); 143 check(styleable1, converter, inherits); 144 check(styleable2, converter, inherits); 145 assertNotSame(styleable1.getProp(), styleable2.getProp()); 146 assertSame(styleable1.getProp().getCssMetaData(), styleable2.getProp().getCssMetaData()); 147 } 148 149 @Test 150 public void theTest() { 151 152 if ("createStyleableEnumProperty".equals(data.createMethodName)) { 153 testEnum(); 154 } else { 155 testOther(); 156 } 157 158 } 159 160 void testEnum() { 161 final Class c = data.initialValue.getClass(); 162 // zero 163 final MyStyleable<?> styleable = new MyStyleableEnum(); 164 styleable.setProp(data.createMethodName, c); 165 166 final MyStyleable<?> other = new MyStyleableEnum(); 167 other.setProp(data.createMethodName, c); 168 169 check(styleable, other, data.converter, false); 170 171 // // one 172 // final MyStyleable<?> styleable1 = new MyStyleable1(); 173 // styleable1.setProp(data.createMethodName, c, data.initialValue); 174 // 175 // final MyStyleable<?> other1 = new MyStyleable1(); 176 // other1.setProp(data.createMethodName, c, data.initialValue); 177 // 178 // check(styleable1, other1, data.converter, false); 179 // 180 // assertNotSame(styleable.getProp().getCssMetaData(), styleable1.getProp().getCssMetaData()); 181 // 182 // // two 183 // final MyStyleable<?> styleable2 = new MyStyleable2(); 184 // styleable2.setProp(data.createMethodName, c, data.initialValue, true); 185 // 186 // final MyStyleable<?> other2 = new MyStyleable2(); 187 // other2.setProp(data.createMethodName, c, data.initialValue, true); 188 // 189 // check(styleable2, other2, data.converter, true); 190 // 191 // assertNotSame(styleable.getProp().getCssMetaData(), styleable2.getProp().getCssMetaData()); 192 // assertNotSame(styleable1.getProp().getCssMetaData(), styleable2.getProp().getCssMetaData()); 193 } 194 195 void testOther() { 196 // zero 197 final MyStyleable<?> styleable = new MyStyleable(); 198 styleable.setProp(data.createMethodName); 199 200 final MyStyleable<?> other = new MyStyleable(); 201 other.setProp(data.createMethodName); 202 203 check(styleable, other, data.converter, data.converter == StyleConverter.getFontConverter()); 204 205 // one 206 final MyStyleable<?> styleable1 = new MyStyleable1(); 207 styleable1.setProp(data.createMethodName, data.initialValue); 208 209 final MyStyleable<?> other1 = new MyStyleable1(); 210 other1.setProp(data.createMethodName, data.initialValue); 211 212 check(styleable1, other1, data.converter, data.converter == StyleConverter.getFontConverter()); 213 214 assertNotSame(styleable.getProp().getCssMetaData(), styleable1.getProp().getCssMetaData()); 215 216 // two 217 final MyStyleable<?> styleable2 = new MyStyleable2(); 218 styleable2.setProp(data.createMethodName, data.initialValue, true); 219 220 final MyStyleable<?> other2 = new MyStyleable2(); 221 other2.setProp(data.createMethodName, data.initialValue, true); 222 223 check(styleable2, other2, data.converter, true); 224 225 assertNotSame(styleable.getProp().getCssMetaData(), styleable2.getProp().getCssMetaData()); 226 assertNotSame(styleable1.getProp().getCssMetaData(), styleable2.getProp().getCssMetaData()); 227 } 228 229 private static class MyStyleable<T> implements Styleable { 230 231 MyStyleable() { 232 } 233 234 static final StyleablePropertyFactory<MyStyleable> styleablePropertyFactory = new StyleablePropertyFactory<>(null); 235 protected StyleablePropertyFactory<? extends MyStyleable> getFactory() { return MyStyleable.styleablePropertyFactory; } 236 237 protected StyleableProperty<T> prop = null; 238 StyleableProperty<T> getProp() { return prop; } 239 240 final protected Function<Styleable, StyleableProperty<T>> function = s -> ((MyStyleable)s).prop; 241 242 void setProp(String createMethodName) { 243 try { 244 Method createMethod = StyleablePropertyFactory.class.getMethod(createMethodName, Styleable.class, String.class, String.class, Function.class); 245 prop = (StyleableProperty<T>) createMethod.invoke(getFactory(), this, "prop", "-my-prop", function); 246 } catch (Exception e) { 247 e.printStackTrace(); 248 fail(e.getMessage()); 249 } 250 } 251 252 void setProp(String createMethodName, Object initialValue) { 253 try { 254 Class c = null; 255 switch(createMethodName) { 256 case "createStyleablePaintProperty": c = Paint.class; break; 257 case "createStyleableNumberProperty": c = Number.class; break; 258 case "createStyleableEffectProperty": c = Effect.class; break; 259 default: 260 if (initialValue instanceof Boolean) c = boolean.class; 261 else c = initialValue.getClass(); 262 break; 263 } 264 Method createMethod = StyleablePropertyFactory.class.getMethod(createMethodName, Styleable.class, String.class, String.class, Function.class, c); 265 prop = (StyleableProperty<T>)createMethod.invoke(getFactory(), this, "prop", "-my-prop", function, initialValue); 266 } catch (Exception e) { 267 e.printStackTrace(); 268 fail(e.toString()); 269 } 270 } 271 272 void setProp(String createMethodName, Object initialValue, boolean inherits) { 273 try { 274 Class c = null; 275 switch(createMethodName) { 276 case "createStyleablePaintProperty": c = Paint.class; break; 277 case "createStyleableNumberProperty": c = Number.class; break; 278 case "createStyleableEffectProperty": c = Effect.class; break; 279 default: 280 if (initialValue instanceof Boolean) c = boolean.class; 281 else c = initialValue.getClass(); 282 break; 283 } 284 Method createMethod = StyleablePropertyFactory.class.getMethod(createMethodName, Styleable.class, String.class, String.class, Function.class, c, boolean.class); 285 prop = (StyleableProperty<T>)createMethod.invoke(getFactory(), this, "prop", "-my-prop", function, initialValue, inherits); 286 } catch (Exception e) { 287 fail(e.getMessage()); 288 } 289 } 290 291 @Override 292 public String getTypeSelector() { 293 return "MyStyleable"; 294 } 295 296 @Override 297 public String getId() { 298 return "my-styleable-id"; 299 } 300 301 private ObservableList<String> styleClass = FXCollections.observableArrayList("my-styleable"); 302 @Override 303 public ObservableList<String> getStyleClass() { 304 return styleClass; 305 } 306 307 @Override 308 public String getStyle() { 309 return null; 310 } 311 312 @Override 313 public Styleable getStyleableParent() { 314 return null; 315 } 316 317 @Override 318 public ObservableSet<PseudoClass> getPseudoClassStates() { 319 return null; 320 } 321 322 @Override 323 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 324 return getFactory().getCssMetaData(); 325 } 326 } 327 328 private static class MyStyleable1<T> extends MyStyleable<T> { 329 MyStyleable1() { super(); } 330 static final StyleablePropertyFactory<MyStyleable1> styleablePropertyFactory = new StyleablePropertyFactory<>(null); 331 protected StyleablePropertyFactory<? extends MyStyleable> getFactory() { return MyStyleable1.styleablePropertyFactory; } 332 333 } 334 335 private static class MyStyleable2<T> extends MyStyleable<T> { 336 MyStyleable2() { super(); } 337 static final StyleablePropertyFactory<MyStyleable2> styleablePropertyFactory = new StyleablePropertyFactory<>(null); 338 protected StyleablePropertyFactory<? extends MyStyleable> getFactory() { return MyStyleable2.styleablePropertyFactory; } 339 340 } 341 342 private static class MyStyleableEnum<T extends Enum<T>> extends MyStyleable<T> { 343 MyStyleableEnum() { super(); } 344 static final StyleablePropertyFactory<MyStyleableEnum> styleablePropertyFactory = new StyleablePropertyFactory<>(null); 345 protected StyleablePropertyFactory<? extends MyStyleable> getFactory() { return MyStyleableEnum.styleablePropertyFactory; } 346 } 347 }