jaroslav@489: /** jaroslav@489: * Back 2 Browser Bytecode Translator jaroslav@489: * Copyright (C) 2012 Jaroslav Tulach jaroslav@489: * jaroslav@489: * This program is free software: you can redistribute it and/or modify jaroslav@489: * it under the terms of the GNU General Public License as published by jaroslav@489: * the Free Software Foundation, version 2 of the License. jaroslav@489: * jaroslav@489: * This program is distributed in the hope that it will be useful, jaroslav@489: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@489: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@489: * GNU General Public License for more details. jaroslav@489: * jaroslav@489: * You should have received a copy of the GNU General Public License jaroslav@489: * along with this program. Look for COPYING file in the top folder. jaroslav@489: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@489: */ jaroslav@489: package org.apidesign.bck2brwsr.htmlpage; jaroslav@489: jaroslav@499: import java.util.ArrayList; jaroslav@766: import java.util.Collections; jaroslav@761: import java.util.Iterator; jaroslav@499: import java.util.List; jaroslav@761: import java.util.ListIterator; jaroslav@491: import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; jaroslav@489: import org.apidesign.bck2brwsr.htmlpage.api.Page; jaroslav@490: import org.apidesign.bck2brwsr.htmlpage.api.Property; jaroslav@489: import static org.testng.Assert.*; jaroslav@505: import org.testng.annotations.BeforeMethod; jaroslav@489: import org.testng.annotations.Test; jaroslav@489: jaroslav@489: /** jaroslav@489: * jaroslav@489: * @author Jaroslav Tulach jaroslav@489: */ jaroslav@490: @Page(xhtml = "Empty.html", className = "Model", properties = { jaroslav@499: @Property(name = "value", type = int.class), jaroslav@766: @Property(name = "count", type = int.class), jaroslav@760: @Property(name = "unrelated", type = long.class), jaroslav@764: @Property(name = "names", type = String.class, array = true), jaroslav@764: @Property(name = "values", type = int.class, array = true) jaroslav@490: }) jaroslav@489: public class ModelTest { jaroslav@505: private Model model; jaroslav@505: private static Model leakedModel; jaroslav@505: jaroslav@505: @BeforeMethod jaroslav@505: public void createModel() { jaroslav@505: model = new Model(); jaroslav@505: } jaroslav@505: jaroslav@490: @Test public void classGeneratedWithSetterGetter() { jaroslav@505: model.setValue(10); jaroslav@505: assertEquals(10, model.getValue(), "Value changed"); jaroslav@489: } jaroslav@491: jaroslav@491: @Test public void computedMethod() { jaroslav@505: model.setValue(4); jaroslav@505: assertEquals(16, model.getPowerValue()); jaroslav@491: } jaroslav@491: jaroslav@760: @Test public void arrayIsMutable() { jaroslav@760: assertEquals(model.getNames().size(), 0, "Is empty"); jaroslav@760: model.getNames().add("Jarda"); jaroslav@760: assertEquals(model.getNames().size(), 1, "One element"); jaroslav@760: } jaroslav@760: jaroslav@761: @Test public void arrayChangesNotified() { jaroslav@761: MockKnockout my = new MockKnockout(); jaroslav@761: MockKnockout.next = my; jaroslav@761: jaroslav@761: model.applyBindings(); jaroslav@761: jaroslav@761: model.getNames().add("Hello"); jaroslav@761: jaroslav@761: assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); jaroslav@761: assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); jaroslav@761: jaroslav@761: my.mutated.clear(); jaroslav@761: jaroslav@761: Iterator it = model.getNames().iterator(); jaroslav@761: assertEquals(it.next(), "Hello"); jaroslav@761: it.remove(); jaroslav@761: jaroslav@761: assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); jaroslav@761: assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); jaroslav@761: jaroslav@761: my.mutated.clear(); jaroslav@761: jaroslav@761: ListIterator lit = model.getNames().listIterator(); jaroslav@761: lit.add("Jarda"); jaroslav@761: jaroslav@761: assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); jaroslav@761: assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); jaroslav@761: } jaroslav@761: jaroslav@764: @Test public void autoboxedArray() { jaroslav@764: MockKnockout my = new MockKnockout(); jaroslav@764: MockKnockout.next = my; jaroslav@764: jaroslav@764: model.applyBindings(); jaroslav@764: jaroslav@764: model.getValues().add(10); jaroslav@764: jaroslav@764: assertEquals(model.getValues().get(0), Integer.valueOf(10), "Really ten"); jaroslav@764: } jaroslav@766: jaroslav@766: @Test public void derivedArrayProp() { jaroslav@766: MockKnockout my = new MockKnockout(); jaroslav@766: MockKnockout.next = my; jaroslav@766: jaroslav@766: model.applyBindings(); jaroslav@766: jaroslav@766: model.setCount(10); jaroslav@766: jaroslav@766: List arr = model.getRepeat(); jaroslav@766: assertEquals(arr.size(), 10, "Ten items: " + arr); jaroslav@766: jaroslav@766: my.mutated.clear(); jaroslav@766: jaroslav@766: model.setCount(5); jaroslav@766: jaroslav@766: arr = model.getRepeat(); jaroslav@766: assertEquals(arr.size(), 5, "Five items: " + arr); jaroslav@766: jaroslav@766: assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated); jaroslav@766: assertTrue(my.mutated.contains("repeat"), "Array is in there: " + my.mutated); jaroslav@766: assertTrue(my.mutated.contains("count"), "Count is in there: " + my.mutated); jaroslav@766: } jaroslav@764: jaroslav@499: @Test public void derivedPropertiesAreNotified() { jaroslav@499: MockKnockout my = new MockKnockout(); jaroslav@499: MockKnockout.next = my; jaroslav@499: jaroslav@505: model.applyBindings(); jaroslav@499: jaroslav@505: model.setValue(33); jaroslav@499: jaroslav@499: assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated); jaroslav@499: assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated); jaroslav@499: assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated); jaroslav@499: jaroslav@499: my.mutated.clear(); jaroslav@499: jaroslav@505: model.setUnrelated(44); jaroslav@499: assertEquals(my.mutated.size(), 1, "One property changed"); jaroslav@499: assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated"); jaroslav@499: } jaroslav@499: jaroslav@500: @Test public void computedPropertyCannotWriteToModel() { jaroslav@505: leakedModel = model; jaroslav@500: try { jaroslav@505: String res = model.getNotAllowedWrite(); jaroslav@500: fail("We should not be allowed to write to the model: " + res); jaroslav@500: } catch (IllegalStateException ex) { jaroslav@500: // OK, we can't read jaroslav@500: } jaroslav@500: } jaroslav@500: jaroslav@500: @Test public void computedPropertyCannotReadToModel() { jaroslav@505: leakedModel = model; jaroslav@500: try { jaroslav@505: String res = model.getNotAllowedRead(); jaroslav@500: fail("We should not be allowed to read from the model: " + res); jaroslav@500: } catch (IllegalStateException ex) { jaroslav@500: // OK, we can't read jaroslav@500: } jaroslav@500: } jaroslav@500: jaroslav@491: @ComputedProperty jaroslav@491: static int powerValue(int value) { jaroslav@491: return value * value; jaroslav@491: } jaroslav@499: jaroslav@500: @ComputedProperty jaroslav@500: static String notAllowedRead() { jaroslav@505: return "Not allowed callback: " + leakedModel.getUnrelated(); jaroslav@500: } jaroslav@500: jaroslav@500: @ComputedProperty jaroslav@500: static String notAllowedWrite() { jaroslav@505: leakedModel.setUnrelated(11); jaroslav@500: return "Not allowed callback!"; jaroslav@500: } jaroslav@500: jaroslav@766: @ComputedProperty jaroslav@766: static List repeat(int count) { jaroslav@766: return Collections.nCopies(count, "Hello"); jaroslav@766: } jaroslav@766: jaroslav@499: static class MockKnockout extends Knockout { jaroslav@499: List mutated = new ArrayList(); jaroslav@499: jaroslav@499: @Override jaroslav@499: public void valueHasMutated(String prop) { jaroslav@499: mutated.add(prop); jaroslav@499: } jaroslav@499: } jaroslav@489: }