Cherry pick r9209 into releases/2.1, uibinder fix for fix negative values in LayoutPanelParser
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.1@9302 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java b/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java
index 2e788dd..3d4bae7 100644
--- a/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java
+++ b/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java
@@ -33,7 +33,7 @@
// This regular expression matches CSS length patterns of the form
// (value)(unit), where the two may be separated by whitespace. Either part
// can be a {class.method} expression.
- private static final Pattern pattern = Pattern.compile("((?:\\{[\\w\\.]+\\})|[\\d\\.]+)\\s*(\\{?[\\w\\.\\%]*\\}?)?");
+ private static final Pattern pattern = Pattern.compile("((?:\\{[\\w\\.]+\\})|[\\+\\-]?[\\d\\.]+)\\s*(\\{?[\\w\\.\\%]*\\}?)?");
private final MortalLogger logger;
private final DoubleAttributeParser doubleParser;
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java
index b816847..a75209d 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java
@@ -1,12 +1,12 @@
/*
* Copyright 2009 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -27,6 +27,8 @@
private static final String ERR_PAIRING = "'%s' must be paired with '%s' or '%s'.";
private static final String ERR_TOO_MANY = "There are too many %s constraints.";
+ private static final String ERR_NEGATIVE_WIDTH = "Attribute 'width' can not be negative.";
+ private static final String ERR_NEGATIVE_HEIGHT = "Attribute 'height' can not be negative.";
private static final String LAYER = "layer";
public void parse(XMLElement elem, String fieldName, JClassType type,
@@ -41,14 +43,16 @@
}
// Get the child widget element.
- String childFieldName = writer.parseElementToField(
- layerElem.consumeSingleChildElement());
+ String childFieldName = writer.parseElementToField(layerElem.consumeSingleChildElement());
writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName);
// Parse the horizontal layout constraints.
String left = layerElem.consumeLengthAttribute("left");
String right = layerElem.consumeLengthAttribute("right");
String width = layerElem.consumeLengthAttribute("width");
+ if (isNegative(width)) {
+ writer.die(layerElem, ERR_NEGATIVE_WIDTH);
+ }
if (left != null) {
if (right != null) {
@@ -76,6 +80,9 @@
String top = layerElem.consumeLengthAttribute("top");
String bottom = layerElem.consumeLengthAttribute("bottom");
String height = layerElem.consumeLengthAttribute("height");
+ if (isNegative(height)) {
+ writer.die(layerElem, ERR_NEGATIVE_HEIGHT);
+ }
if (top != null) {
if (bottom != null) {
@@ -111,4 +118,17 @@
return parent.getNamespaceUri().equals(child.getNamespaceUri())
&& type.equals(child.getLocalName());
}
+
+ /**
+ * @return <code>true</code> if in given <code>value, unit</code> expression
+ * <code>value</code> part is obviously negative.
+ */
+ private boolean isNegative(String expression) {
+ if (expression != null && expression.length() >= 2
+ && expression.charAt(0) == '-') {
+ char secondChar = expression.charAt(1);
+ return Character.isDigit(secondChar);
+ }
+ return false;
+ }
}
diff --git a/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java b/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java
index b6e6407..ed2d73b 100644
--- a/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java
+++ b/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java
@@ -83,6 +83,8 @@
assertEquals(lengthString("1", "EX"), parser.parse("1EX"));
assertEquals(lengthString("2.5", "EM"), parser.parse("2.5em"));
+ assertEquals(lengthString("+1", "EM"), parser.parse("+1em"));
+ assertEquals(lengthString("-1", "EM"), parser.parse("-1em"));
assertEquals(lengthString("1", "EM"), parser.parse("1 em"));
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java
index 5355f70..88fe292 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java
@@ -21,7 +21,6 @@
import org.xml.sax.SAXException;
-import java.io.IOException;
import java.util.Iterator;
/**
@@ -39,7 +38,7 @@
tester = new ElementParserTester(PARSED_TYPE, new LayoutPanelParser());
}
- public void testBadChild() throws SAXException, IOException {
+ public void testBadChild() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:blah/>");
@@ -54,7 +53,7 @@
}
}
- public void testBadValue() throws SAXException, IOException {
+ public void testBadValue() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer left='goosnarg'><g:HTML/></g:layer>");
@@ -69,8 +68,7 @@
}
}
- public void testHappy() throws UnableToCompleteException, SAXException,
- IOException {
+ public void testHappy() throws UnableToCompleteException, SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer>");
@@ -130,21 +128,69 @@
+ "com.google.gwt.dom.client.Style.Unit.EM, 50, foo.unit());" };
tester.parse(b.toString());
+
+ assertStatements(expected);
+ }
+
+ public void testNegativeTopLeft() throws UnableToCompleteException, SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:LayoutPanel>");
+ b.append(" <g:layer left='-1em' width='2px' top='-3mm' height='4px'>");
+ b.append(" <g:Label/>");
+ b.append(" </g:layer>");
+ b.append("</g:LayoutPanel>");
+
+ tester.parse(b.toString());
- Iterator<String> i = tester.writer.statements.iterator();
- for (String e : expected) {
- assertEquals(e, i.next());
- }
- assertFalse(i.hasNext());
- assertNull(tester.logger.died);
+ assertStatements("fieldName.add(<g:Label>);",
+ "fieldName.setWidgetLeftWidth(<g:Label>, "
+ + "-1, com.google.gwt.dom.client.Style.Unit.EM, "
+ + "2, com.google.gwt.dom.client.Style.Unit.PX);",
+ "fieldName.setWidgetTopHeight(<g:Label>, "
+ + "-3, com.google.gwt.dom.client.Style.Unit.MM, "
+ + "4, com.google.gwt.dom.client.Style.Unit.PX);");
}
- public void testLonelyBottom() throws SAXException, IOException {
+ public void testNegativeWidth() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:LayoutPanel>");
+ b.append(" <g:layer left='1em' width='-2px'>");
+ b.append(" <g:Label/>");
+ b.append(" </g:layer>");
+ b.append("</g:LayoutPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ String died = tester.logger.died;
+ assertTrue(died, died.contains("Attribute 'width' can not be negative"));
+ }
+ }
+
+ public void testNegativeHeight() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:LayoutPanel>");
+ b.append(" <g:layer top='1em' height='-2px'>");
+ b.append(" <g:Label/>");
+ b.append(" </g:layer>");
+ b.append("</g:LayoutPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ String died = tester.logger.died;
+ assertTrue(died, died.contains("Attribute 'height' can not be negative"));
+ }
+ }
+
+ public void testLonelyBottom() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer bottom='0'><g:HTML/></g:layer>");
b.append("</g:LayoutPanel>");
-
+
try {
tester.parse(b.toString());
fail();
@@ -154,7 +200,7 @@
}
}
- public void testLonelyLeft() throws SAXException, IOException {
+ public void testLonelyLeft() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer left='0'><g:HTML/></g:layer>");
@@ -169,7 +215,7 @@
}
}
- public void testLonelyRight() throws SAXException, IOException {
+ public void testLonelyRight() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer right='0'><g:HTML/></g:layer>");
@@ -184,7 +230,7 @@
}
}
- public void testLonelyTop() throws SAXException, IOException {
+ public void testLonelyTop() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer top='0'><g:HTML/></g:layer>");
@@ -199,7 +245,7 @@
}
}
- public void testOverConstrained() throws SAXException, IOException {
+ public void testOverConstrainedHorizontally() throws SAXException {
StringBuffer b = new StringBuffer();
b.append("<g:LayoutPanel>");
b.append(" <g:layer left='0' width='0' right='0'><g:HTML/></g:layer>");
@@ -209,8 +255,32 @@
tester.parse(b.toString());
fail();
} catch (UnableToCompleteException e) {
- assertTrue("expect \"too many\" error",
- tester.logger.died.contains("too many"));
+ String died = tester.logger.died;
+ assertTrue(died, died.contains("too many horizontal constraints"));
}
}
+
+ public void testOverConstrainedVertically() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:LayoutPanel>");
+ b.append(" <g:layer top='0' height='0' bottom='0'><g:HTML/></g:layer>");
+ b.append("</g:LayoutPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ String died = tester.logger.died;
+ assertTrue(died, died.contains("too many vertical constraints"));
+ }
+ }
+
+ private void assertStatements(String... expected) {
+ Iterator<String> i = tester.writer.statements.iterator();
+ for (String e : expected) {
+ assertEquals(e, i.next());
+ }
+ assertFalse(i.hasNext());
+ assertNull(tester.logger.died);
+ }
}