# HG changeset patch # User Jaroslav Tulach # Date 1358772220 -3600 # Node ID 4198be34b51688855ef79e53c5fedef1d186374f # Parent f9e80d48e9b47f7c4e72badb86be6b0c0622b680 Moving towards testability: Model class does not have any public fields, rather instance onces diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Mon Jan 21 13:43:40 2013 +0100 @@ -24,7 +24,7 @@ * * @author Jaroslav Tulach */ -@ExtraJavaScript(resource = "org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js") +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js") public class Knockout { /** used by tests */ static Knockout next; diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Jan 21 13:43:40 2013 +0100 @@ -94,28 +94,27 @@ try { w.append("package " + pkg + ";\n"); w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); - w.append("class ").append(className).append(" {\n"); + w.append("final class ").append(className).append(" {\n"); w.append(" private static boolean locked;\n"); - w.append(" private ").append(className).append("() {}\n"); - for (String id : pp.ids()) { - String tag = pp.tagNameForId(id); - String type = type(tag); - w.append(" ").append("public static final "). - append(type).append(' ').append(cnstnt(id)).append(" = new "). - append(type).append("(\"").append(id).append("\");\n"); - } - w.append(" static {\n"); + w.append(" public ").append(className).append("() {\n"); if (!initializeOnClick((TypeElement) e, w, pp)) { return false; } w.append(" }\n"); + for (String id : pp.ids()) { + String tag = pp.tagNameForId(id); + String type = type(tag); + w.append(" ").append("public final "). + append(type).append(' ').append(cnstnt(id)).append(" = new "). + append(type).append("(\"").append(id).append("\");\n"); + } List propsGetSet = new ArrayList(); Map> propsDeps = new HashMap>(); generateComputedProperties(w, e.getEnclosedElements(), propsGetSet, propsDeps); generateProperties(w, p.properties(), propsGetSet, propsDeps); - w.append(" private static org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); if (!propsGetSet.isEmpty()) { - w.write("public static void applyBindings() {\n"); + w.write("public " + className + " applyBindings() {\n"); w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings("); w.write(className + ".class, new " + className + "(), "); w.write("new String[] {\n"); @@ -129,8 +128,7 @@ } sep = ",\n"; } - w.write("\n });\n}\n"); - //w.write("static { applyBindings(); }\n"); + w.write("\n });\n return this;\n}\n"); } w.append("}\n"); } finally { @@ -271,12 +269,12 @@ final String tn = typeName(p); String[] gs = toGetSet(p.name(), tn); - w.write("private static " + tn + " prop_" + p.name() + ";\n"); - w.write("public static " + tn + " " + gs[0] + "() {\n"); + w.write("private " + tn + " prop_" + p.name() + ";\n"); + w.write("public " + tn + " " + gs[0] + "() {\n"); w.write(" if (locked) throw new IllegalStateException();\n"); w.write(" return prop_" + p.name() + ";\n"); w.write("}\n"); - w.write("public static void " + gs[1] + "(" + tn + " v) {\n"); + w.write("public void " + gs[1] + "(" + tn + " v) {\n"); w.write(" if (locked) throw new IllegalStateException();\n"); w.write(" prop_" + p.name() + " = v;\n"); w.write(" if (ko != null) {\n"); @@ -312,7 +310,7 @@ final String sn = ee.getSimpleName().toString(); String[] gs = toGetSet(sn, tn); - w.write("public static " + tn + " " + gs[0] + "() {\n"); + w.write("public " + tn + " " + gs[0] + "() {\n"); w.write(" if (locked) throw new IllegalStateException();\n"); int arg = 0; for (VariableElement pe : ee.getParameters()) { diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Jan 21 13:43:40 2013 +0100 @@ -23,6 +23,7 @@ import org.apidesign.bck2brwsr.htmlpage.api.Page; import org.apidesign.bck2brwsr.htmlpage.api.Property; import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** @@ -34,25 +35,31 @@ @Property(name = "unrelated", type = long.class) }) public class ModelTest { + private Model model; + private static Model leakedModel; + + @BeforeMethod + public void createModel() { + model = new Model(); + } + @Test public void classGeneratedWithSetterGetter() { - Class c = Model.class; - assertNotNull(c, "Class for empty page generated"); - Model.setValue(10); - assertEquals(10, Model.getValue(), "Value changed"); + model.setValue(10); + assertEquals(10, model.getValue(), "Value changed"); } @Test public void computedMethod() { - Model.setValue(4); - assertEquals(16, Model.getPowerValue()); + model.setValue(4); + assertEquals(16, model.getPowerValue()); } @Test public void derivedPropertiesAreNotified() { MockKnockout my = new MockKnockout(); MockKnockout.next = my; - Model.applyBindings(); + model.applyBindings(); - Model.setValue(33); + model.setValue(33); assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated); assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated); @@ -60,14 +67,15 @@ my.mutated.clear(); - Model.setUnrelated(44); + model.setUnrelated(44); assertEquals(my.mutated.size(), 1, "One property changed"); assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated"); } @Test public void computedPropertyCannotWriteToModel() { + leakedModel = model; try { - String res = Model.getNotAllowedWrite(); + String res = model.getNotAllowedWrite(); fail("We should not be allowed to write to the model: " + res); } catch (IllegalStateException ex) { // OK, we can't read @@ -75,8 +83,9 @@ } @Test public void computedPropertyCannotReadToModel() { + leakedModel = model; try { - String res = Model.getNotAllowedRead(); + String res = model.getNotAllowedRead(); fail("We should not be allowed to read from the model: " + res); } catch (IllegalStateException ex) { // OK, we can't read @@ -90,12 +99,12 @@ @ComputedProperty static String notAllowedRead() { - return "Not allowed callback: " + Model.getUnrelated(); + return "Not allowed callback: " + leakedModel.getUnrelated(); } @ComputedProperty static String notAllowedWrite() { - Model.setUnrelated(11); + leakedModel.setUnrelated(11); return "Not allowed callback!"; } diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Mon Jan 21 13:43:40 2013 +0100 @@ -43,9 +43,11 @@ */ @Page(xhtml="TestPage.html") public class PageController { + private static final TestPage PAGE = new TestPage(); + @On(event = CLICK, id="pg.button") static void updateTitle() { - TestPage.PG_TITLE.setText("You want this window to be named " + TestPage.PG_TEXT.getValue()); + PAGE.PG_TITLE.setText("You want this window to be named " + PAGE.PG_TEXT.getValue()); } @On(event = CLICK, id={ "pg.title", "pg.text" }) @@ -53,6 +55,6 @@ if (!id.equals("pg.title")) { throw new IllegalStateException(); } - TestPage.PG_TITLE.setText(id); + PAGE.PG_TITLE.setText(id); } } diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 13:43:40 2013 +0100 @@ -17,6 +17,7 @@ */ package org.apidesign.bck2brwsr.mavenhtml; +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; import org.apidesign.bck2brwsr.htmlpage.api.On; import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; import org.apidesign.bck2brwsr.htmlpage.api.Page; @@ -29,34 +30,54 @@ * @author Jaroslav Tulach */ @Page(xhtml="Calculator.xhtml", properties = { - @Property(name = "display", type = double.class) + @Property(name = "memory", type = double.class), + @Property(name = "display", type = double.class), + @Property(name = "operation", type = String.class), + @Property(name = "hover", type = boolean.class) }) public class App { - private static double memory; - private static String operation; + private static final Calculator CALC = new Calculator().applyBindings(); @On(event = CLICK, id="clear") static void clear() { - memory = 0; - operation = null; - Calculator.setDisplay(0); + CALC.setMemory(0); + CALC.setOperation(null); + CALC.setDisplay(0); } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) static void applyOp(String op) { - memory = Calculator.getDisplay(); - operation = op; - Calculator.setDisplay(0); + CALC.setMemory(CALC.getDisplay()); + CALC.setOperation(op); + CALC.setDisplay(0); + } + + @On(event = MOUSE_OVER, id= { "result" }) + static void attemptingIn(String op) { + CALC.setHover(true); + } + @On(event = MOUSE_OUT, id= { "result" }) + static void attemptingOut(String op) { + CALC.setHover(false); } @On(event = CLICK, id="result") static void computeTheValue() { - switch (operation) { - case "plus": Calculator.setDisplay(memory + Calculator.getDisplay()); break; - case "minus": Calculator.setDisplay(memory - Calculator.getDisplay()); break; - case "mul": Calculator.setDisplay(memory * Calculator.getDisplay()); break; - case "div": Calculator.setDisplay(memory / Calculator.getDisplay()); break; - default: throw new IllegalStateException(operation); + CALC.setDisplay(compute( + CALC.getOperation(), + CALC.getMemory(), + CALC.getDisplay() + )); + CALC.setMemory(0); + } + + private static double compute(String op, double memory, double display) { + switch (op) { + case "plus": return memory + display; + case "minus": return memory - display; + case "mul": return memory * display; + case "div": return memory / display; + default: throw new IllegalStateException(op); } } @@ -64,12 +85,26 @@ static void addDigit(String digit) { digit = digit.substring(1); - double v = Calculator.getDisplay(); + double v = CALC.getDisplay(); if (v == 0.0) { - Calculator.setDisplay(Integer.parseInt(digit)); + CALC.setDisplay(Integer.parseInt(digit)); } else { - String txt = Double.toString(v) + digit; - Calculator.setDisplay(Double.parseDouble(txt)); + String txt = Double.toString(v); + if (txt.endsWith(".0")) { + txt = txt.substring(0, txt.length() - 2); + } + txt = txt + digit; + CALC.setDisplay(Double.parseDouble(txt)); } } + + @ComputedProperty + public static String displayPreview( + double display, boolean hover, double memory, String operation + ) { + if (!hover) { + return "Type numbers and perform simple operations! Press '=' to get result."; + } + return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); + } } diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml --- a/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Mon Jan 21 13:43:40 2013 +0100 @@ -81,7 +81,7 @@
diff -r f9e80d48e9b4 -r 4198be34b516 javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 11:55:27 2013 +0100 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 13:43:40 2013 +0100 @@ -36,37 +36,39 @@ @Property(name = "hover", type = boolean.class) }) public class App { + private static final Calculator CALC = new Calculator().applyBindings(); + @On(event = CLICK, id="clear") static void clear() { - Calculator.setMemory(0); - Calculator.setOperation(null); - Calculator.setDisplay(0); + CALC.setMemory(0); + CALC.setOperation(null); + CALC.setDisplay(0); } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) static void applyOp(String op) { - Calculator.setMemory(Calculator.getDisplay()); - Calculator.setOperation(op); - Calculator.setDisplay(0); + CALC.setMemory(CALC.getDisplay()); + CALC.setOperation(op); + CALC.setDisplay(0); } @On(event = MOUSE_OVER, id= { "result" }) static void attemptingIn(String op) { - Calculator.setHover(true); + CALC.setHover(true); } @On(event = MOUSE_OUT, id= { "result" }) static void attemptingOut(String op) { - Calculator.setHover(false); + CALC.setHover(false); } @On(event = CLICK, id="result") static void computeTheValue() { - Calculator.setDisplay(compute( - Calculator.getOperation(), - Calculator.getMemory(), - Calculator.getDisplay() + CALC.setDisplay(compute( + CALC.getOperation(), + CALC.getMemory(), + CALC.getDisplay() )); - Calculator.setMemory(0); + CALC.setMemory(0); } private static double compute(String op, double memory, double display) { @@ -83,16 +85,16 @@ static void addDigit(String digit) { digit = digit.substring(1); - double v = Calculator.getDisplay(); + double v = CALC.getDisplay(); if (v == 0.0) { - Calculator.setDisplay(Integer.parseInt(digit)); + CALC.setDisplay(Integer.parseInt(digit)); } else { String txt = Double.toString(v); if (txt.endsWith(".0")) { txt = txt.substring(0, txt.length() - 2); } txt = txt + digit; - Calculator.setDisplay(Double.parseDouble(txt)); + CALC.setDisplay(Double.parseDouble(txt)); } } @@ -105,8 +107,4 @@ } return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); } - - static { - Calculator.applyBindings(); - } }