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 }