1 /* 2 * Copyright (c) 2012, 2013, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * This file is available under and governed by the GNU General Public 26 * License version 2 only, as published by the Free Software Foundation. 27 * However, the following notice accompanied the original version of this 28 * file: 29 * 30 * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos 31 * 32 * All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions are met: 36 * 37 * * Redistributions of source code must retain the above copyright notice, 38 * this list of conditions and the following disclaimer. 39 * 40 * * Redistributions in binary form must reproduce the above copyright notice, 41 * this list of conditions and the following disclaimer in the documentation 42 * and/or other materials provided with the distribution. 43 * 44 * * Neither the name of JSR-310 nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 51 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 52 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 53 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 54 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 55 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 56 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 57 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 */ 60 package test.java.time.format; 61 62 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 63 import static java.time.temporal.ChronoField.DAY_OF_WEEK; 64 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 65 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 66 import static java.time.temporal.ChronoField.YEAR; 67 import static org.testng.Assert.assertEquals; 68 69 import java.text.ParsePosition; 70 import java.time.LocalDate; 71 import java.time.YearMonth; 72 import java.time.ZoneOffset; 73 import java.time.format.DateTimeFormatter; 74 import java.time.format.DateTimeFormatterBuilder; 75 import java.time.format.SignStyle; 76 import java.time.format.TextStyle; 77 import java.time.temporal.Temporal; 78 import java.time.temporal.TemporalAccessor; 79 import java.util.HashMap; 80 import java.util.Locale; 81 import java.util.Map; 82 83 import org.testng.annotations.BeforeMethod; 84 import org.testng.annotations.DataProvider; 85 import org.testng.annotations.Test; 86 87 /** 88 * Test DateTimeFormatterBuilder. 89 */ 90 @Test 91 public class TestDateTimeFormatterBuilder { 92 93 private DateTimeFormatterBuilder builder; 94 95 @BeforeMethod 96 public void setUp() { 97 builder = new DateTimeFormatterBuilder(); 98 } 99 100 //----------------------------------------------------------------------- 101 @Test 102 public void test_toFormatter_empty() throws Exception { 103 DateTimeFormatter f = builder.toFormatter(); 104 assertEquals(f.toString(), ""); 105 } 106 107 //----------------------------------------------------------------------- 108 @Test 109 public void test_parseCaseSensitive() throws Exception { 110 builder.parseCaseSensitive(); 111 DateTimeFormatter f = builder.toFormatter(); 112 assertEquals(f.toString(), "ParseCaseSensitive(true)"); 113 } 114 115 @Test 116 public void test_parseCaseInsensitive() throws Exception { 117 builder.parseCaseInsensitive(); 118 DateTimeFormatter f = builder.toFormatter(); 119 assertEquals(f.toString(), "ParseCaseSensitive(false)"); 120 } 121 122 //----------------------------------------------------------------------- 123 @Test 124 public void test_parseStrict() throws Exception { 125 builder.parseStrict(); 126 DateTimeFormatter f = builder.toFormatter(); 127 assertEquals(f.toString(), "ParseStrict(true)"); 128 } 129 130 @Test 131 public void test_parseLenient() throws Exception { 132 builder.parseLenient(); 133 DateTimeFormatter f = builder.toFormatter(); 134 assertEquals(f.toString(), "ParseStrict(false)"); 135 } 136 137 //----------------------------------------------------------------------- 138 @Test 139 public void test_appendValue_1arg() throws Exception { 140 builder.appendValue(DAY_OF_MONTH); 141 DateTimeFormatter f = builder.toFormatter(); 142 assertEquals(f.toString(), "Value(DayOfMonth)"); 143 } 144 145 @Test(expectedExceptions=NullPointerException.class) 146 public void test_appendValue_1arg_null() throws Exception { 147 builder.appendValue(null); 148 } 149 150 //----------------------------------------------------------------------- 151 @Test 152 public void test_appendValue_2arg() throws Exception { 153 builder.appendValue(DAY_OF_MONTH, 3); 154 DateTimeFormatter f = builder.toFormatter(); 155 assertEquals(f.toString(), "Value(DayOfMonth,3)"); 156 } 157 158 @Test(expectedExceptions=NullPointerException.class) 159 public void test_appendValue_2arg_null() throws Exception { 160 builder.appendValue(null, 3); 161 } 162 163 @Test(expectedExceptions=IllegalArgumentException.class) 164 public void test_appendValue_2arg_widthTooSmall() throws Exception { 165 builder.appendValue(DAY_OF_MONTH, 0); 166 } 167 168 @Test(expectedExceptions=IllegalArgumentException.class) 169 public void test_appendValue_2arg_widthTooBig() throws Exception { 170 builder.appendValue(DAY_OF_MONTH, 20); 171 } 172 173 //----------------------------------------------------------------------- 174 @Test 175 public void test_appendValue_3arg() throws Exception { 176 builder.appendValue(DAY_OF_MONTH, 2, 3, SignStyle.NORMAL); 177 DateTimeFormatter f = builder.toFormatter(); 178 assertEquals(f.toString(), "Value(DayOfMonth,2,3,NORMAL)"); 179 } 180 181 @Test(expectedExceptions=NullPointerException.class) 182 public void test_appendValue_3arg_nullField() throws Exception { 183 builder.appendValue(null, 2, 3, SignStyle.NORMAL); 184 } 185 186 @Test(expectedExceptions=IllegalArgumentException.class) 187 public void test_appendValue_3arg_minWidthTooSmall() throws Exception { 188 builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); 189 } 190 191 @Test(expectedExceptions=IllegalArgumentException.class) 192 public void test_appendValue_3arg_minWidthTooBig() throws Exception { 193 builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); 194 } 195 196 @Test(expectedExceptions=IllegalArgumentException.class) 197 public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { 198 builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); 199 } 200 201 @Test(expectedExceptions=IllegalArgumentException.class) 202 public void test_appendValue_3arg_maxWidthTooBig() throws Exception { 203 builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); 204 } 205 206 @Test(expectedExceptions=IllegalArgumentException.class) 207 public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { 208 builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); 209 } 210 211 @Test(expectedExceptions=NullPointerException.class) 212 public void test_appendValue_3arg_nullSignStyle() throws Exception { 213 builder.appendValue(DAY_OF_MONTH, 2, 3, null); 214 } 215 216 //----------------------------------------------------------------------- 217 @Test 218 public void test_appendValue_subsequent2_parse3() throws Exception { 219 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); 220 DateTimeFormatter f = builder.toFormatter(); 221 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); 222 TemporalAccessor parsed = f.parseUnresolved("123", new ParsePosition(0)); 223 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 224 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 225 } 226 227 @Test 228 public void test_appendValue_subsequent2_parse4() throws Exception { 229 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); 230 DateTimeFormatter f = builder.toFormatter(); 231 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); 232 TemporalAccessor parsed = f.parseUnresolved("0123", new ParsePosition(0)); 233 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 234 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 235 } 236 237 @Test 238 public void test_appendValue_subsequent2_parse5() throws Exception { 239 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2).appendLiteral('4'); 240 DateTimeFormatter f = builder.toFormatter(); 241 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)'4'"); 242 TemporalAccessor parsed = f.parseUnresolved("01234", new ParsePosition(0)); 243 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 244 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 245 } 246 247 @Test 248 public void test_appendValue_subsequent3_parse6() throws Exception { 249 builder 250 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 251 .appendValue(MONTH_OF_YEAR, 2) 252 .appendValue(DAY_OF_MONTH, 2); 253 DateTimeFormatter f = builder.toFormatter(); 254 assertEquals(f.toString(), "Value(Year,4,10,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)"); 255 TemporalAccessor parsed = f.parseUnresolved("20090630", new ParsePosition(0)); 256 assertEquals(parsed.getLong(YEAR), 2009L); 257 assertEquals(parsed.getLong(MONTH_OF_YEAR), 6L); 258 assertEquals(parsed.getLong(DAY_OF_MONTH), 30L); 259 } 260 261 //----------------------------------------------------------------------- 262 @Test(expectedExceptions=NullPointerException.class) 263 public void test_appendValueReduced_null() throws Exception { 264 builder.appendValueReduced(null, 2, 2000); 265 } 266 267 @Test 268 public void test_appendValueReduced() throws Exception { 269 builder.appendValueReduced(YEAR, 2, 2000); 270 DateTimeFormatter f = builder.toFormatter(); 271 assertEquals(f.toString(), "ReducedValue(Year,2,2000)"); 272 TemporalAccessor parsed = f.parseUnresolved("12", new ParsePosition(0)); 273 assertEquals(parsed.getLong(YEAR), 2012L); 274 } 275 276 @Test 277 public void test_appendValueReduced_subsequent_parse() throws Exception { 278 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValueReduced(YEAR, 2, 2000); 279 DateTimeFormatter f = builder.toFormatter(); 280 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)ReducedValue(Year,2,2000)"); 281 TemporalAccessor parsed = f.parseUnresolved("123", new ParsePosition(0)); 282 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 283 assertEquals(parsed.getLong(YEAR), 2023L); 284 } 285 286 //----------------------------------------------------------------------- 287 //----------------------------------------------------------------------- 288 //----------------------------------------------------------------------- 289 @Test 290 public void test_appendFraction_4arg() throws Exception { 291 builder.appendFraction(MINUTE_OF_HOUR, 1, 9, false); 292 DateTimeFormatter f = builder.toFormatter(); 293 assertEquals(f.toString(), "Fraction(MinuteOfHour,1,9)"); 294 } 295 296 @Test(expectedExceptions=NullPointerException.class) 297 public void test_appendFraction_4arg_nullRule() throws Exception { 298 builder.appendFraction(null, 1, 9, false); 299 } 300 301 @Test(expectedExceptions=IllegalArgumentException.class) 302 public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { 303 builder.appendFraction(DAY_OF_MONTH, 1, 9, false); 304 } 305 306 @Test(expectedExceptions=IllegalArgumentException.class) 307 public void test_appendFraction_4arg_minTooSmall() throws Exception { 308 builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); 309 } 310 311 @Test(expectedExceptions=IllegalArgumentException.class) 312 public void test_appendFraction_4arg_minTooBig() throws Exception { 313 builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); 314 } 315 316 @Test(expectedExceptions=IllegalArgumentException.class) 317 public void test_appendFraction_4arg_maxTooSmall() throws Exception { 318 builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); 319 } 320 321 @Test(expectedExceptions=IllegalArgumentException.class) 322 public void test_appendFraction_4arg_maxTooBig() throws Exception { 323 builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); 324 } 325 326 @Test(expectedExceptions=IllegalArgumentException.class) 327 public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { 328 builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); 329 } 330 331 //----------------------------------------------------------------------- 332 //----------------------------------------------------------------------- 333 //----------------------------------------------------------------------- 334 @Test 335 public void test_appendText_1arg() throws Exception { 336 builder.appendText(MONTH_OF_YEAR); 337 DateTimeFormatter f = builder.toFormatter(); 338 assertEquals(f.toString(), "Text(MonthOfYear)"); 339 } 340 341 @Test(expectedExceptions=NullPointerException.class) 342 public void test_appendText_1arg_null() throws Exception { 343 builder.appendText(null); 344 } 345 346 //----------------------------------------------------------------------- 347 @Test 348 public void test_appendText_2arg() throws Exception { 349 builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT); 350 DateTimeFormatter f = builder.toFormatter(); 351 assertEquals(f.toString(), "Text(MonthOfYear,SHORT)"); 352 } 353 354 @Test(expectedExceptions=NullPointerException.class) 355 public void test_appendText_2arg_nullRule() throws Exception { 356 builder.appendText(null, TextStyle.SHORT); 357 } 358 359 @Test(expectedExceptions=NullPointerException.class) 360 public void test_appendText_2arg_nullStyle() throws Exception { 361 builder.appendText(MONTH_OF_YEAR, (TextStyle) null); 362 } 363 364 //----------------------------------------------------------------------- 365 @Test 366 public void test_appendTextMap() throws Exception { 367 Map<Long, String> map = new HashMap<>(); 368 map.put(1L, "JNY"); 369 map.put(2L, "FBY"); 370 map.put(3L, "MCH"); 371 map.put(4L, "APL"); 372 map.put(5L, "MAY"); 373 map.put(6L, "JUN"); 374 map.put(7L, "JLY"); 375 map.put(8L, "AGT"); 376 map.put(9L, "SPT"); 377 map.put(10L, "OBR"); 378 map.put(11L, "NVR"); 379 map.put(12L, "DBR"); 380 builder.appendText(MONTH_OF_YEAR, map); 381 DateTimeFormatter f = builder.toFormatter(); 382 assertEquals(f.toString(), "Text(MonthOfYear)"); // TODO: toString should be different? 383 } 384 385 @Test(expectedExceptions=NullPointerException.class) 386 public void test_appendTextMap_nullRule() throws Exception { 387 builder.appendText(null, new HashMap<Long, String>()); 388 } 389 390 @Test(expectedExceptions=NullPointerException.class) 391 public void test_appendTextMap_nullStyle() throws Exception { 392 builder.appendText(MONTH_OF_YEAR, (Map<Long, String>) null); 393 } 394 395 //----------------------------------------------------------------------- 396 //----------------------------------------------------------------------- 397 //----------------------------------------------------------------------- 398 @Test 399 public void test_appendOffsetId() throws Exception { 400 builder.appendOffsetId(); 401 DateTimeFormatter f = builder.toFormatter(); 402 assertEquals(f.toString(), "Offset(+HH:MM:ss,'Z')"); 403 } 404 405 @DataProvider(name="offsetPatterns") 406 Object[][] data_offsetPatterns() { 407 return new Object[][] { 408 {"+HH", 2, 0, 0, "+02"}, 409 {"+HH", -2, 0, 0, "-02"}, 410 {"+HH", 2, 30, 0, "+02"}, 411 {"+HH", 2, 0, 45, "+02"}, 412 {"+HH", 2, 30, 45, "+02"}, 413 414 {"+HHMM", 2, 0, 0, "+0200"}, 415 {"+HHMM", -2, 0, 0, "-0200"}, 416 {"+HHMM", 2, 30, 0, "+0230"}, 417 {"+HHMM", 2, 0, 45, "+0200"}, 418 {"+HHMM", 2, 30, 45, "+0230"}, 419 420 {"+HH:MM", 2, 0, 0, "+02:00"}, 421 {"+HH:MM", -2, 0, 0, "-02:00"}, 422 {"+HH:MM", 2, 30, 0, "+02:30"}, 423 {"+HH:MM", 2, 0, 45, "+02:00"}, 424 {"+HH:MM", 2, 30, 45, "+02:30"}, 425 426 {"+HHMMss", 2, 0, 0, "+0200"}, 427 {"+HHMMss", -2, 0, 0, "-0200"}, 428 {"+HHMMss", 2, 30, 0, "+0230"}, 429 {"+HHMMss", 2, 0, 45, "+020045"}, 430 {"+HHMMss", 2, 30, 45, "+023045"}, 431 432 {"+HH:MM:ss", 2, 0, 0, "+02:00"}, 433 {"+HH:MM:ss", -2, 0, 0, "-02:00"}, 434 {"+HH:MM:ss", 2, 30, 0, "+02:30"}, 435 {"+HH:MM:ss", 2, 0, 45, "+02:00:45"}, 436 {"+HH:MM:ss", 2, 30, 45, "+02:30:45"}, 437 438 {"+HHMMSS", 2, 0, 0, "+020000"}, 439 {"+HHMMSS", -2, 0, 0, "-020000"}, 440 {"+HHMMSS", 2, 30, 0, "+023000"}, 441 {"+HHMMSS", 2, 0, 45, "+020045"}, 442 {"+HHMMSS", 2, 30, 45, "+023045"}, 443 444 {"+HH:MM:SS", 2, 0, 0, "+02:00:00"}, 445 {"+HH:MM:SS", -2, 0, 0, "-02:00:00"}, 446 {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, 447 {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, 448 {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, 449 }; 450 } 451 452 @Test(dataProvider="offsetPatterns") 453 public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { 454 builder.appendOffset(pattern, "Z"); 455 DateTimeFormatter f = builder.toFormatter(); 456 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 457 assertEquals(f.format(offset), expected); 458 } 459 460 @Test(dataProvider="offsetPatterns") 461 public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { 462 builder.appendOffset(pattern, "Z"); 463 DateTimeFormatter f = builder.toFormatter(); 464 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 465 ZoneOffset parsed = f.parse(expected, ZoneOffset::from); 466 assertEquals(f.format(parsed), expected); 467 } 468 469 @DataProvider(name="badOffsetPatterns") 470 Object[][] data_badOffsetPatterns() { 471 return new Object[][] { 472 {"HH"}, 473 {"HHMM"}, 474 {"HH:MM"}, 475 {"HHMMss"}, 476 {"HH:MM:ss"}, 477 {"HHMMSS"}, 478 {"HH:MM:SS"}, 479 {"+H"}, 480 {"+HMM"}, 481 {"+HHM"}, 482 {"+A"}, 483 }; 484 } 485 486 @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) 487 public void test_appendOffset_badPattern(String pattern) throws Exception { 488 builder.appendOffset(pattern, "Z"); 489 } 490 491 @Test(expectedExceptions=NullPointerException.class) 492 public void test_appendOffset_3arg_nullText() throws Exception { 493 builder.appendOffset("+HH:MM", null); 494 } 495 496 @Test(expectedExceptions=NullPointerException.class) 497 public void test_appendOffset_3arg_nullPattern() throws Exception { 498 builder.appendOffset(null, "Z"); 499 } 500 501 //----------------------------------------------------------------------- 502 //----------------------------------------------------------------------- 503 //----------------------------------------------------------------------- 504 @Test 505 public void test_appendZoneId() throws Exception { 506 builder.appendZoneId(); 507 DateTimeFormatter f = builder.toFormatter(); 508 assertEquals(f.toString(), "ZoneId()"); 509 } 510 511 @Test 512 public void test_appendZoneText_1arg() throws Exception { 513 builder.appendZoneText(TextStyle.FULL); 514 DateTimeFormatter f = builder.toFormatter(); 515 assertEquals(f.toString(), "ZoneText(FULL)"); 516 } 517 518 @Test(expectedExceptions=NullPointerException.class) 519 public void test_appendZoneText_1arg_nullText() throws Exception { 520 builder.appendZoneText(null); 521 } 522 523 //----------------------------------------------------------------------- 524 //----------------------------------------------------------------------- 525 //----------------------------------------------------------------------- 526 @Test 527 public void test_padNext_1arg() { 528 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); 529 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); 530 } 531 532 @Test(expectedExceptions=IllegalArgumentException.class) 533 public void test_padNext_1arg_invalidWidth() throws Exception { 534 builder.padNext(0); 535 } 536 537 //----------------------------------------------------------------------- 538 @Test 539 public void test_padNext_2arg_dash() throws Exception { 540 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); 541 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); 542 } 543 544 @Test(expectedExceptions=IllegalArgumentException.class) 545 public void test_padNext_2arg_invalidWidth() throws Exception { 546 builder.padNext(0, '-'); 547 } 548 549 //----------------------------------------------------------------------- 550 @Test 551 public void test_padOptional() throws Exception { 552 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') 553 .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() 554 .appendLiteral(':').appendValue(YEAR); 555 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); 556 assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); 557 } 558 559 //----------------------------------------------------------------------- 560 //----------------------------------------------------------------------- 561 //----------------------------------------------------------------------- 562 @Test 563 public void test_optionalStart_noEnd() throws Exception { 564 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); 565 DateTimeFormatter f = builder.toFormatter(); 566 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)Value(DayOfWeek)]"); 567 } 568 569 @Test 570 public void test_optionalStart2_noEnd() throws Exception { 571 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalStart().appendValue(DAY_OF_WEEK); 572 DateTimeFormatter f = builder.toFormatter(); 573 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]]"); 574 } 575 576 @Test 577 public void test_optionalStart_doubleStart() throws Exception { 578 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH); 579 DateTimeFormatter f = builder.toFormatter(); 580 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 581 } 582 583 //----------------------------------------------------------------------- 584 @Test 585 public void test_optionalEnd() throws Exception { 586 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK); 587 DateTimeFormatter f = builder.toFormatter(); 588 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)]Value(DayOfWeek)"); 589 } 590 591 @Test 592 public void test_optionalEnd2() throws Exception { 593 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH) 594 .optionalStart().appendValue(DAY_OF_WEEK).optionalEnd().appendValue(DAY_OF_MONTH).optionalEnd(); 595 DateTimeFormatter f = builder.toFormatter(); 596 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]Value(DayOfMonth)]"); 597 } 598 599 @Test 600 public void test_optionalEnd_doubleStartSingleEnd() throws Exception { 601 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); 602 DateTimeFormatter f = builder.toFormatter(); 603 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 604 } 605 606 @Test 607 public void test_optionalEnd_doubleStartDoubleEnd() throws Exception { 608 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().optionalEnd(); 609 DateTimeFormatter f = builder.toFormatter(); 610 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 611 } 612 613 @Test 614 public void test_optionalStartEnd_immediateStartEnd() throws Exception { 615 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalEnd().appendValue(DAY_OF_MONTH); 616 DateTimeFormatter f = builder.toFormatter(); 617 assertEquals(f.toString(), "Value(MonthOfYear)Value(DayOfMonth)"); 618 } 619 620 @Test(expectedExceptions=IllegalStateException.class) 621 public void test_optionalEnd_noStart() throws Exception { 622 builder.optionalEnd(); 623 } 624 625 //----------------------------------------------------------------------- 626 //----------------------------------------------------------------------- 627 //----------------------------------------------------------------------- 628 @DataProvider(name="validPatterns") 629 Object[][] dataValid() { 630 return new Object[][] { 631 {"'a'", "'a'"}, 632 {"''", "''"}, 633 {"'!'", "'!'"}, 634 {"!", "'!'"}, 635 636 {"'hello_people,][)('", "'hello_people,][)('"}, 637 {"'hi'", "'hi'"}, 638 {"'yyyy'", "'yyyy'"}, 639 {"''''", "''"}, 640 {"'o''clock'", "'o''clock'"}, 641 642 {"G", "Text(Era,SHORT)"}, 643 {"GG", "Text(Era,SHORT)"}, 644 {"GGG", "Text(Era,SHORT)"}, 645 {"GGGG", "Text(Era)"}, 646 {"GGGGG", "Text(Era,NARROW)"}, 647 648 {"u", "Value(Year)"}, 649 {"uu", "ReducedValue(Year,2,2000)"}, 650 {"uuu", "Value(Year,3,19,NORMAL)"}, 651 {"uuuu", "Value(Year,4,19,EXCEEDS_PAD)"}, 652 {"uuuuu", "Value(Year,5,19,EXCEEDS_PAD)"}, 653 654 {"y", "Value(YearOfEra)"}, 655 {"yy", "ReducedValue(YearOfEra,2,2000)"}, 656 {"yyy", "Value(YearOfEra,3,19,NORMAL)"}, 657 {"yyyy", "Value(YearOfEra,4,19,EXCEEDS_PAD)"}, 658 {"yyyyy", "Value(YearOfEra,5,19,EXCEEDS_PAD)"}, 659 660 {"Y", "Localized(WeekBasedYear)"}, 661 {"YY", "Localized(ReducedValue(WeekBasedYear,2,2000))"}, 662 {"YYY", "Localized(WeekBasedYear,3,19,NORMAL)"}, 663 {"YYYY", "Localized(WeekBasedYear,4,19,EXCEEDS_PAD)"}, 664 {"YYYYY", "Localized(WeekBasedYear,5,19,EXCEEDS_PAD)"}, 665 666 {"M", "Value(MonthOfYear)"}, 667 {"MM", "Value(MonthOfYear,2)"}, 668 {"MMM", "Text(MonthOfYear,SHORT)"}, 669 {"MMMM", "Text(MonthOfYear)"}, 670 {"MMMMM", "Text(MonthOfYear,NARROW)"}, 671 672 {"L", "Value(MonthOfYear)"}, 673 {"LL", "Value(MonthOfYear,2)"}, 674 {"LLL", "Text(MonthOfYear,SHORT_STANDALONE)"}, 675 {"LLLL", "Text(MonthOfYear,FULL_STANDALONE)"}, 676 {"LLLLL", "Text(MonthOfYear,NARROW_STANDALONE)"}, 677 678 {"D", "Value(DayOfYear)"}, 679 {"DD", "Value(DayOfYear,2)"}, 680 {"DDD", "Value(DayOfYear,3)"}, 681 682 {"d", "Value(DayOfMonth)"}, 683 {"dd", "Value(DayOfMonth,2)"}, 684 685 {"F", "Value(AlignedDayOfWeekInMonth)"}, 686 687 {"Q", "Value(QuarterOfYear)"}, 688 {"QQ", "Value(QuarterOfYear,2)"}, 689 {"QQQ", "Text(QuarterOfYear,SHORT)"}, 690 {"QQQQ", "Text(QuarterOfYear)"}, 691 {"QQQQQ", "Text(QuarterOfYear,NARROW)"}, 692 693 {"q", "Value(QuarterOfYear)"}, 694 {"qq", "Value(QuarterOfYear,2)"}, 695 {"qqq", "Text(QuarterOfYear,SHORT_STANDALONE)"}, 696 {"qqqq", "Text(QuarterOfYear,FULL_STANDALONE)"}, 697 {"qqqqq", "Text(QuarterOfYear,NARROW_STANDALONE)"}, 698 699 {"E", "Text(DayOfWeek,SHORT)"}, 700 {"EE", "Text(DayOfWeek,SHORT)"}, 701 {"EEE", "Text(DayOfWeek,SHORT)"}, 702 {"EEEE", "Text(DayOfWeek)"}, 703 {"EEEEE", "Text(DayOfWeek,NARROW)"}, 704 705 {"e", "Localized(DayOfWeek,1)"}, 706 {"ee", "Localized(DayOfWeek,2)"}, 707 {"eee", "Text(DayOfWeek,SHORT)"}, 708 {"eeee", "Text(DayOfWeek)"}, 709 {"eeeee", "Text(DayOfWeek,NARROW)"}, 710 711 {"c", "Localized(DayOfWeek,1)"}, 712 {"ccc", "Text(DayOfWeek,SHORT_STANDALONE)"}, 713 {"cccc", "Text(DayOfWeek,FULL_STANDALONE)"}, 714 {"ccccc", "Text(DayOfWeek,NARROW_STANDALONE)"}, 715 716 {"a", "Text(AmPmOfDay,SHORT)"}, 717 718 {"H", "Value(HourOfDay)"}, 719 {"HH", "Value(HourOfDay,2)"}, 720 721 {"K", "Value(HourOfAmPm)"}, 722 {"KK", "Value(HourOfAmPm,2)"}, 723 724 {"k", "Value(ClockHourOfDay)"}, 725 {"kk", "Value(ClockHourOfDay,2)"}, 726 727 {"h", "Value(ClockHourOfAmPm)"}, 728 {"hh", "Value(ClockHourOfAmPm,2)"}, 729 730 {"m", "Value(MinuteOfHour)"}, 731 {"mm", "Value(MinuteOfHour,2)"}, 732 733 {"s", "Value(SecondOfMinute)"}, 734 {"ss", "Value(SecondOfMinute,2)"}, 735 736 {"S", "Fraction(NanoOfSecond,1,1)"}, 737 {"SS", "Fraction(NanoOfSecond,2,2)"}, 738 {"SSS", "Fraction(NanoOfSecond,3,3)"}, 739 {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"}, 740 741 {"A", "Value(MilliOfDay)"}, 742 {"AA", "Value(MilliOfDay,2)"}, 743 {"AAA", "Value(MilliOfDay,3)"}, 744 745 {"n", "Value(NanoOfSecond)"}, 746 {"nn", "Value(NanoOfSecond,2)"}, 747 {"nnn", "Value(NanoOfSecond,3)"}, 748 749 {"N", "Value(NanoOfDay)"}, 750 {"NN", "Value(NanoOfDay,2)"}, 751 {"NNN", "Value(NanoOfDay,3)"}, 752 753 {"z", "ZoneText(SHORT)"}, 754 {"zz", "ZoneText(SHORT)"}, 755 {"zzz", "ZoneText(SHORT)"}, 756 {"zzzz", "ZoneText(FULL)"}, 757 758 {"VV", "ZoneId()"}, 759 760 {"Z", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 761 {"ZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 762 {"ZZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 763 764 {"X", "Offset(+HHmm,'Z')"}, // LDML/almost SimpleDateFormat 765 {"XX", "Offset(+HHMM,'Z')"}, // LDML/SimpleDateFormat 766 {"XXX", "Offset(+HH:MM,'Z')"}, // LDML/SimpleDateFormat 767 {"XXXX", "Offset(+HHMMss,'Z')"}, // LDML 768 {"XXXXX", "Offset(+HH:MM:ss,'Z')"}, // LDML 769 770 {"x", "Offset(+HHmm,'+00')"}, // LDML 771 {"xx", "Offset(+HHMM,'+0000')"}, // LDML 772 {"xxx", "Offset(+HH:MM,'+00:00')"}, // LDML 773 {"xxxx", "Offset(+HHMMss,'+0000')"}, // LDML 774 {"xxxxx", "Offset(+HH:MM:ss,'+00:00')"}, // LDML 775 776 {"ppH", "Pad(Value(HourOfDay),2)"}, 777 {"pppDD", "Pad(Value(DayOfYear,2),3)"}, 778 779 {"yyyy[-MM[-dd", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, 780 {"yyyy[-MM[-dd]]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, 781 {"yyyy[-MM[]-dd]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, 782 783 {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + 784 "'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"}, 785 786 {"w", "Localized(WeekOfWeekBasedYear,1)"}, 787 {"ww", "Localized(WeekOfWeekBasedYear,2)"}, 788 {"W", "Localized(WeekOfMonth,1)"}, 789 }; 790 } 791 792 @Test(dataProvider="validPatterns") 793 public void test_appendPattern_valid(String input, String expected) throws Exception { 794 builder.appendPattern(input); 795 DateTimeFormatter f = builder.toFormatter(); 796 assertEquals(f.toString(), expected); 797 } 798 799 //----------------------------------------------------------------------- 800 @DataProvider(name="invalidPatterns") 801 Object[][] dataInvalid() { 802 return new Object[][] { 803 {"'"}, 804 {"'hello"}, 805 {"'hel''lo"}, 806 {"'hello''"}, 807 {"{"}, 808 {"}"}, 809 {"{}"}, 810 {"]"}, 811 {"yyyy]"}, 812 {"yyyy]MM"}, 813 {"yyyy[MM]]"}, 814 815 {"aa"}, 816 {"aaa"}, 817 {"aaaa"}, 818 {"aaaaa"}, 819 {"aaaaaa"}, 820 {"MMMMMM"}, 821 {"LLLLLL"}, 822 {"QQQQQQ"}, 823 {"qqqqqq"}, 824 {"EEEEEE"}, 825 {"eeeeee"}, 826 {"cc"}, 827 {"cccccc"}, 828 {"ddd"}, 829 {"DDDD"}, 830 {"FF"}, 831 {"FFF"}, 832 {"hhh"}, 833 {"HHH"}, 834 {"kkk"}, 835 {"KKK"}, 836 {"mmm"}, 837 {"sss"}, 838 {"OO"}, 839 {"OOO"}, 840 {"OOOOO"}, 841 {"XXXXXX"}, 842 {"ZZZZZZ"}, 843 {"zzzzz"}, 844 {"V"}, 845 {"VVV"}, 846 {"VVVV"}, 847 {"VVVVV"}, 848 849 {"RO"}, 850 851 {"p"}, 852 {"pp"}, 853 {"p:"}, 854 855 {"f"}, 856 {"ff"}, 857 {"f:"}, 858 {"fy"}, 859 {"fa"}, 860 {"fM"}, 861 862 {"www"}, 863 {"WW"}, 864 }; 865 } 866 867 @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) 868 public void test_appendPattern_invalid(String input) throws Exception { 869 try { 870 builder.appendPattern(input); 871 } catch (IllegalArgumentException ex) { 872 throw ex; 873 } 874 } 875 876 //----------------------------------------------------------------------- 877 @DataProvider(name="patternPrint") 878 Object[][] data_patternPrint() { 879 return new Object[][] { 880 {"Q", date(2012, 2, 10), "1"}, 881 {"QQ", date(2012, 2, 10), "01"}, 882 {"QQQ", date(2012, 2, 10), "Q1"}, 883 {"QQQQ", date(2012, 2, 10), "1st quarter"}, 884 {"QQQQQ", date(2012, 2, 10), "1"}, 885 }; 886 } 887 888 @Test(dataProvider="patternPrint") 889 public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { 890 DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); 891 String test = f.format(temporal); 892 assertEquals(test, expected); 893 } 894 895 private static Temporal date(int y, int m, int d) { 896 return LocalDate.of(y, m, d); 897 } 898 899 }