001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.form.translator; 016 017 import org.apache.tapestry.IMarkupWriter; 018 import org.apache.tapestry.IRequestCycle; 019 import org.apache.tapestry.form.FormComponentContributorContext; 020 import org.apache.tapestry.form.FormComponentContributorTestCase; 021 import org.apache.tapestry.form.IFormComponent; 022 import org.apache.tapestry.form.ValidationMessages; 023 import org.apache.tapestry.json.JSONObject; 024 import org.apache.tapestry.valid.ValidationConstraint; 025 import org.apache.tapestry.valid.ValidationStrings; 026 import org.apache.tapestry.valid.ValidatorException; 027 import static org.easymock.EasyMock.expect; 028 import org.testng.annotations.Test; 029 030 import java.text.DecimalFormatSymbols; 031 import java.util.Locale; 032 033 /** 034 * Tests for {@link org.apache.tapestry.form.translator.NumberTranslator} 035 * 036 * @author Howard Lewis Ship 037 * @since 4.0 038 */ 039 @Test 040 public class TestNumberTranslator extends FormComponentContributorTestCase 041 { 042 public void test_Default_Format() 043 { 044 NumberTranslator translator = new NumberTranslator(); 045 046 testFormat(translator, new Integer(10), "10"); 047 } 048 049 public void test_Omit_Zero() 050 { 051 NumberTranslator translator = new NumberTranslator("pattern=0.00,omitZero=true"); 052 053 testFormat(translator, new Integer(0), ""); 054 055 assertEquals(translator.getValueForEmptyInput(), null); 056 } 057 058 public void test_Omit_Zero_Off() 059 { 060 NumberTranslator translator = new NumberTranslator("!omitZero,pattern=0.00"); 061 062 testFormat(translator, new Integer(0), "0.00"); 063 } 064 065 public void test_Custom_Format() 066 { 067 NumberTranslator translator = new NumberTranslator(); 068 069 translator.setPattern("$#0.00"); 070 071 testFormat(translator, new Integer(10), "$10.00"); 072 } 073 074 public void test_Initializer_Format() 075 { 076 NumberTranslator translator = new NumberTranslator("pattern=#0%"); 077 078 testFormat(translator, new Double(0.10), "10%"); 079 } 080 081 private void testFormat(Translator translator, Number number, String expected) 082 { 083 IFormComponent field = newField(); 084 085 String result = translator.format(field, Locale.ENGLISH, number); 086 087 assertEquals(result, expected); 088 } 089 090 public void test_Null_Format() 091 throws Exception 092 { 093 NumberTranslator translator = new NumberTranslator("pattern=0.00,omitZero"); 094 IFormComponent field = newField(); 095 ValidationMessages messages = newMock(ValidationMessages.class); 096 097 replay(); 098 099 Number num = (Number)translator.parse(field, messages, ""); 100 101 assert num == null; 102 103 verify(); 104 } 105 106 public void test_Null_Format_Pattern() 107 { 108 NumberTranslator translator = new NumberTranslator(); 109 110 replay(); 111 112 String result = translator.format(_component, null, null); 113 114 assertEquals("", result); 115 116 verify(); 117 } 118 119 public void test_Localized_Format() 120 { 121 IFormComponent field = newField(); 122 NumberTranslator translator = new NumberTranslator(); 123 translator.setPattern("#,###"); 124 125 replay(); 126 127 Integer input = new Integer(10999999); 128 String result = translator.format(field, Locale.FRENCH, input); 129 DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.FRENCH); 130 131 verify(); 132 133 assertEquals(result, "10" + sym.getGroupingSeparator() + "999" + sym.getGroupingSeparator() + "999"); 134 } 135 136 public void test_Default_Parse() throws Exception 137 { 138 NumberTranslator translator = new NumberTranslator(); 139 140 testParse(translator, "0.1", new Double(0.1)); 141 } 142 143 public void test_Custom_Parse() throws Exception 144 { 145 NumberTranslator translator = new NumberTranslator(); 146 147 translator.setPattern("#%"); 148 149 testParse(translator, "10%", new Double(0.1)); 150 } 151 152 public void test_Trimmed_Parse() throws Exception 153 { 154 NumberTranslator translator = new NumberTranslator(); 155 156 translator.setTrim(true); 157 158 testParse(translator, " 100 ", new Long(100)); 159 } 160 161 private void testParse(Translator translator, String number, Number expected) throws Exception 162 { 163 IFormComponent field = newField(); 164 165 ValidationMessages messages = newMock(ValidationMessages.class); 166 167 trainGetLocale(messages, Locale.ENGLISH); 168 169 replay(); 170 171 Number result = (Number) translator.parse(field, messages, number); 172 173 assertEquals(expected, result); 174 175 verify(); 176 177 } 178 179 public void test_Failed_Parse_Default_Message() 180 { 181 NumberTranslator translator = new NumberTranslator(); 182 183 testFailedParse(translator, null); 184 } 185 186 public void test_Failed_Parse_Custom_Message() 187 { 188 NumberTranslator translator = new NumberTranslator(); 189 190 String message = "Field Name is an invalid number."; 191 192 translator.setMessage(message); 193 194 testFailedParse(translator, message); 195 } 196 197 private void testFailedParse(Translator translator, String messageOverride) 198 { 199 IFormComponent field = newField("Number Field"); 200 201 ValidationMessages messages = newMock(ValidationMessages.class); 202 203 trainGetLocale(messages, Locale.ENGLISH); 204 205 trainBuildMessage( 206 messages, 207 messageOverride, 208 ValidationStrings.INVALID_NUMBER, 209 new Object[] 210 { "Number Field", "#" }, 211 "invalid number"); 212 213 replay(); 214 215 try 216 { 217 System.out.println(translator.parse(field, messages, "Bad-Number")); 218 219 unreachable(); 220 } 221 catch (ValidatorException e) 222 { 223 assertEquals("invalid number", e.getMessage()); 224 assertEquals(ValidationConstraint.NUMBER_FORMAT, e.getConstraint()); 225 } 226 227 verify(); 228 } 229 230 public void test_Render_Contribution() 231 { 232 NumberTranslator translator = new NumberTranslator(); 233 IFormComponent field = newField("Number Field", "numberField", 1); 234 235 JSONObject json = new JSONObject(); 236 237 IMarkupWriter writer = newWriter(); 238 IRequestCycle cycle = newCycle(); 239 240 FormComponentContributorContext context = newMock(FormComponentContributorContext.class); 241 242 expect(context.getProfile()).andReturn(json); 243 244 trainGetLocale(context, Locale.ENGLISH); 245 246 trainBuildMessage(context, null, ValidationStrings.INVALID_NUMBER, 247 new Object[] { "Number Field", "#" }, "invalid number message"); 248 249 replay(); 250 251 translator.renderContribution(writer, cycle, context, field); 252 253 verify(); 254 255 assertEquals(json.toString(), 256 "{\"constraints\":{\"numberField\":" + 257 "[[tapestry.form.validation.isReal,null,{places:0,decimal:\".\",separator:\"\"}]]}," + 258 "\"numberField\":{\"constraints\":[\"invalid number message\"]}}"); 259 } 260 261 public void test_Render_Grouping_Separator() 262 { 263 NumberTranslator translator = new NumberTranslator(); 264 translator.setPattern("###,##"); 265 IFormComponent field = newField("Number Field", "numberField", 1); 266 267 JSONObject json = new JSONObject(); 268 269 IMarkupWriter writer = newWriter(); 270 IRequestCycle cycle = newCycle(); 271 272 FormComponentContributorContext context = newMock(FormComponentContributorContext.class); 273 274 expect(context.getProfile()).andReturn(json); 275 276 trainGetLocale(context, Locale.US); 277 278 trainBuildMessage(context, null, ValidationStrings.INVALID_NUMBER, new String[] { "Number Field", "#,##" }, 279 "invalid number message"); 280 281 replay(); 282 283 translator.renderContribution(writer, cycle, context, field); 284 285 verify(); 286 287 assertEquals(json.toString(), 288 "{\"constraints\":{\"numberField\":" + 289 "[[tapestry.form.validation.isReal,null," + 290 "{places:0,decimal:\".\",separator:\",\",groupSize:2}]]}," + 291 "\"numberField\":{\"constraints\":[\"invalid number message\"]}}"); 292 } 293 294 public void test_Message_Render_Contribution() 295 { 296 NumberTranslator translator = new NumberTranslator(); 297 IFormComponent field = newField("Number Field", "myfield", 1); 298 299 String messageOverride = "You entered a bunk value for {0}. I should look like {1}. Watch out for ''this''!"; 300 301 IMarkupWriter writer = newWriter(); 302 IRequestCycle cycle = newCycle(); 303 304 JSONObject json = new JSONObject(); 305 306 FormComponentContributorContext context = newMock(FormComponentContributorContext.class); 307 308 expect(context.getProfile()).andReturn(json); 309 310 trainGetLocale(context, Locale.ENGLISH); 311 312 trainBuildMessage( 313 context, 314 messageOverride, 315 ValidationStrings.INVALID_NUMBER, 316 new Object[] { "Number Field", "#" }, 317 "Blah Blah 'Field Name' Blah."); 318 319 replay(); 320 321 translator.setMessage(messageOverride); 322 323 translator.renderContribution(writer, cycle, context, field); 324 325 verify(); 326 327 assertEquals(json.toString(), 328 "{\"constraints\":{\"myfield\":[[tapestry.form.validation.isReal,null," + 329 "{places:0,decimal:\".\",separator:\"\"}]]}," + 330 "\"myfield\":{\"constraints\":[\"Blah Blah 'Field Name' Blah.\"]}}"); 331 } 332 333 public void test_Trim_Render_Contribution() 334 { 335 IFormComponent field = newField("Number Field", "myfield", 2); 336 337 NumberTranslator translator = new NumberTranslator(); 338 JSONObject json = new JSONObject(); 339 340 IMarkupWriter writer = newWriter(); 341 IRequestCycle cycle = newCycle(); 342 343 FormComponentContributorContext context = newMock(FormComponentContributorContext.class); 344 345 expect(context.getProfile()).andReturn(json); 346 347 trainGetLocale(context, Locale.ENGLISH); 348 349 trainBuildMessage(context, null, ValidationStrings.INVALID_NUMBER, new Object[] 350 { "Number Field", "#" }, "invalid number message"); 351 352 expect(context.getProfile()).andReturn(json); 353 354 replay(); 355 356 translator.setTrim(true); 357 358 translator.renderContribution(writer, cycle, context, field); 359 360 verify(); 361 362 assertEquals(json.toString(), 363 "{\"trim\":[\"myfield\"]," + 364 "\"constraints\":{\"myfield\":[[tapestry.form.validation.isReal,null," + 365 "{places:0,decimal:\".\",separator:\"\"}]]}," + 366 "\"myfield\":{\"constraints\":[\"invalid number message\"]}}"); 367 } 368 }