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 tck.java.time.format; 61 62 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 63 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 64 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 65 import static java.time.temporal.ChronoField.YEAR; 66 import static org.testng.Assert.assertEquals; 67 68 import java.time.LocalDate; 69 import java.time.YearMonth; 70 import java.time.ZoneOffset; 71 import java.time.format.DateTimeFormatter; 72 import java.time.format.DateTimeFormatterBuilder; 73 import java.time.format.SignStyle; 74 import java.time.format.TextStyle; 75 import java.time.temporal.Temporal; 76 import java.util.HashMap; 77 import java.util.Locale; 78 import java.util.Map; 79 80 import org.testng.annotations.BeforeMethod; 81 import org.testng.annotations.DataProvider; 82 import org.testng.annotations.Test; 83 84 /** 85 * Test DateTimeFormatterBuilder. 86 */ 87 @Test 88 public class TCKDateTimeFormatterBuilder { 89 90 private DateTimeFormatterBuilder builder; 91 92 @BeforeMethod 93 public void setUp() { 94 builder = new DateTimeFormatterBuilder(); 95 } 96 97 //----------------------------------------------------------------------- 98 @Test 99 public void test_toFormatter_empty() throws Exception { 100 DateTimeFormatter f = builder.toFormatter(); 101 assertEquals(f.toString(), ""); 102 } 103 104 //----------------------------------------------------------------------- 105 @Test(expectedExceptions=NullPointerException.class) 106 public void test_appendValue_1arg_null() throws Exception { 107 builder.appendValue(null); 108 } 109 110 //----------------------------------------------------------------------- 111 @Test(expectedExceptions=NullPointerException.class) 112 public void test_appendValue_2arg_null() throws Exception { 113 builder.appendValue(null, 3); 114 } 115 116 @Test(expectedExceptions=IllegalArgumentException.class) 117 public void test_appendValue_2arg_widthTooSmall() throws Exception { 118 builder.appendValue(DAY_OF_MONTH, 0); 119 } 120 121 @Test(expectedExceptions=IllegalArgumentException.class) 122 public void test_appendValue_2arg_widthTooBig() throws Exception { 123 builder.appendValue(DAY_OF_MONTH, 20); 124 } 125 126 //----------------------------------------------------------------------- 127 @Test(expectedExceptions=NullPointerException.class) 128 public void test_appendValue_3arg_nullField() throws Exception { 129 builder.appendValue(null, 2, 3, SignStyle.NORMAL); 130 } 131 132 @Test(expectedExceptions=IllegalArgumentException.class) 133 public void test_appendValue_3arg_minWidthTooSmall() throws Exception { 134 builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); 135 } 136 137 @Test(expectedExceptions=IllegalArgumentException.class) 138 public void test_appendValue_3arg_minWidthTooBig() throws Exception { 139 builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); 140 } 141 142 @Test(expectedExceptions=IllegalArgumentException.class) 143 public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { 144 builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); 145 } 146 147 @Test(expectedExceptions=IllegalArgumentException.class) 148 public void test_appendValue_3arg_maxWidthTooBig() throws Exception { 149 builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); 150 } 151 152 @Test(expectedExceptions=IllegalArgumentException.class) 153 public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { 154 builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); 155 } 156 157 @Test(expectedExceptions=NullPointerException.class) 158 public void test_appendValue_3arg_nullSignStyle() throws Exception { 159 builder.appendValue(DAY_OF_MONTH, 2, 3, null); 160 } 161 162 //----------------------------------------------------------------------- 163 @Test(expectedExceptions=NullPointerException.class) 164 public void test_appendValueReduced_null() throws Exception { 165 builder.appendValueReduced(null, 2, 2000); 166 } 167 168 //----------------------------------------------------------------------- 169 //----------------------------------------------------------------------- 170 //----------------------------------------------------------------------- 171 @Test(expectedExceptions=NullPointerException.class) 172 public void test_appendFraction_4arg_nullRule() throws Exception { 173 builder.appendFraction(null, 1, 9, false); 174 } 175 176 @Test(expectedExceptions=IllegalArgumentException.class) 177 public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { 178 builder.appendFraction(DAY_OF_MONTH, 1, 9, false); 179 } 180 181 @Test(expectedExceptions=IllegalArgumentException.class) 182 public void test_appendFraction_4arg_minTooSmall() throws Exception { 183 builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); 184 } 185 186 @Test(expectedExceptions=IllegalArgumentException.class) 187 public void test_appendFraction_4arg_minTooBig() throws Exception { 188 builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); 189 } 190 191 @Test(expectedExceptions=IllegalArgumentException.class) 192 public void test_appendFraction_4arg_maxTooSmall() throws Exception { 193 builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); 194 } 195 196 @Test(expectedExceptions=IllegalArgumentException.class) 197 public void test_appendFraction_4arg_maxTooBig() throws Exception { 198 builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); 199 } 200 201 @Test(expectedExceptions=IllegalArgumentException.class) 202 public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { 203 builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); 204 } 205 206 //----------------------------------------------------------------------- 207 //----------------------------------------------------------------------- 208 //----------------------------------------------------------------------- 209 @Test(expectedExceptions=NullPointerException.class) 210 public void test_appendText_1arg_null() throws Exception { 211 builder.appendText(null); 212 } 213 214 //----------------------------------------------------------------------- 215 @Test(expectedExceptions=NullPointerException.class) 216 public void test_appendText_2arg_nullRule() throws Exception { 217 builder.appendText(null, TextStyle.SHORT); 218 } 219 220 @Test(expectedExceptions=NullPointerException.class) 221 public void test_appendText_2arg_nullStyle() throws Exception { 222 builder.appendText(MONTH_OF_YEAR, (TextStyle) null); 223 } 224 225 //----------------------------------------------------------------------- 226 @Test(expectedExceptions=NullPointerException.class) 227 public void test_appendTextMap_nullRule() throws Exception { 228 builder.appendText(null, new HashMap<>()); 229 } 230 231 @Test(expectedExceptions=NullPointerException.class) 232 public void test_appendTextMap_nullStyle() throws Exception { 233 builder.appendText(MONTH_OF_YEAR, (Map<Long, String>) null); 234 } 235 236 //----------------------------------------------------------------------- 237 //----------------------------------------------------------------------- 238 //----------------------------------------------------------------------- 239 @DataProvider(name="offsetPatterns") 240 Object[][] data_offsetPatterns() { 241 return new Object[][] { 242 {"+HH", 2, 0, 0, "+02"}, 243 {"+HH", -2, 0, 0, "-02"}, 244 {"+HH", 2, 30, 0, "+02"}, 245 {"+HH", 2, 0, 45, "+02"}, 246 {"+HH", 2, 30, 45, "+02"}, 247 248 {"+HHMM", 2, 0, 0, "+0200"}, 249 {"+HHMM", -2, 0, 0, "-0200"}, 250 {"+HHMM", 2, 30, 0, "+0230"}, 251 {"+HHMM", 2, 0, 45, "+0200"}, 252 {"+HHMM", 2, 30, 45, "+0230"}, 253 254 {"+HH:MM", 2, 0, 0, "+02:00"}, 255 {"+HH:MM", -2, 0, 0, "-02:00"}, 256 {"+HH:MM", 2, 30, 0, "+02:30"}, 257 {"+HH:MM", 2, 0, 45, "+02:00"}, 258 {"+HH:MM", 2, 30, 45, "+02:30"}, 259 260 {"+HHMMss", 2, 0, 0, "+0200"}, 261 {"+HHMMss", -2, 0, 0, "-0200"}, 262 {"+HHMMss", 2, 30, 0, "+0230"}, 263 {"+HHMMss", 2, 0, 45, "+020045"}, 264 {"+HHMMss", 2, 30, 45, "+023045"}, 265 266 {"+HH:MM:ss", 2, 0, 0, "+02:00"}, 267 {"+HH:MM:ss", -2, 0, 0, "-02:00"}, 268 {"+HH:MM:ss", 2, 30, 0, "+02:30"}, 269 {"+HH:MM:ss", 2, 0, 45, "+02:00:45"}, 270 {"+HH:MM:ss", 2, 30, 45, "+02:30:45"}, 271 272 {"+HHMMSS", 2, 0, 0, "+020000"}, 273 {"+HHMMSS", -2, 0, 0, "-020000"}, 274 {"+HHMMSS", 2, 30, 0, "+023000"}, 275 {"+HHMMSS", 2, 0, 45, "+020045"}, 276 {"+HHMMSS", 2, 30, 45, "+023045"}, 277 278 {"+HH:MM:SS", 2, 0, 0, "+02:00:00"}, 279 {"+HH:MM:SS", -2, 0, 0, "-02:00:00"}, 280 {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, 281 {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, 282 {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, 283 }; 284 } 285 286 @Test(dataProvider="offsetPatterns") 287 public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { 288 builder.appendOffset(pattern, "Z"); 289 DateTimeFormatter f = builder.toFormatter(); 290 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 291 assertEquals(f.format(offset), expected); 292 } 293 294 @Test(dataProvider="offsetPatterns") 295 public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { 296 builder.appendOffset(pattern, "Z"); 297 DateTimeFormatter f = builder.toFormatter(); 298 ZoneOffset parsed = f.parse(expected, ZoneOffset::from); 299 assertEquals(f.format(parsed), expected); 300 } 301 302 @DataProvider(name="badOffsetPatterns") 303 Object[][] data_badOffsetPatterns() { 304 return new Object[][] { 305 {"HH"}, 306 {"HHMM"}, 307 {"HH:MM"}, 308 {"HHMMss"}, 309 {"HH:MM:ss"}, 310 {"HHMMSS"}, 311 {"HH:MM:SS"}, 312 {"+H"}, 313 {"+HMM"}, 314 {"+HHM"}, 315 {"+A"}, 316 }; 317 } 318 319 @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) 320 public void test_appendOffset_badPattern(String pattern) throws Exception { 321 builder.appendOffset(pattern, "Z"); 322 } 323 324 @Test(expectedExceptions=NullPointerException.class) 325 public void test_appendOffset_3arg_nullText() throws Exception { 326 builder.appendOffset("+HH:MM", null); 327 } 328 329 @Test(expectedExceptions=NullPointerException.class) 330 public void test_appendOffset_3arg_nullPattern() throws Exception { 331 builder.appendOffset(null, "Z"); 332 } 333 334 //----------------------------------------------------------------------- 335 //----------------------------------------------------------------------- 336 //----------------------------------------------------------------------- 337 @Test(expectedExceptions=NullPointerException.class) 338 public void test_appendZoneText_1arg_nullText() throws Exception { 339 builder.appendZoneText(null); 340 } 341 342 //----------------------------------------------------------------------- 343 //----------------------------------------------------------------------- 344 //----------------------------------------------------------------------- 345 @Test 346 public void test_padNext_1arg() { 347 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); 348 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); 349 } 350 351 @Test(expectedExceptions=IllegalArgumentException.class) 352 public void test_padNext_1arg_invalidWidth() throws Exception { 353 builder.padNext(0); 354 } 355 356 //----------------------------------------------------------------------- 357 @Test 358 public void test_padNext_2arg_dash() throws Exception { 359 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); 360 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); 361 } 362 363 @Test(expectedExceptions=IllegalArgumentException.class) 364 public void test_padNext_2arg_invalidWidth() throws Exception { 365 builder.padNext(0, '-'); 366 } 367 368 //----------------------------------------------------------------------- 369 @Test 370 public void test_padOptional() throws Exception { 371 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') 372 .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() 373 .appendLiteral(':').appendValue(YEAR); 374 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); 375 assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); 376 } 377 378 //----------------------------------------------------------------------- 379 //----------------------------------------------------------------------- 380 //----------------------------------------------------------------------- 381 @Test(expectedExceptions=IllegalStateException.class) 382 public void test_optionalEnd_noStart() throws Exception { 383 builder.optionalEnd(); 384 } 385 386 //----------------------------------------------------------------------- 387 //----------------------------------------------------------------------- 388 //----------------------------------------------------------------------- 389 @DataProvider(name="validPatterns") 390 Object[][] dataValid() { 391 return new Object[][] { 392 {"'a'"}, 393 {"''"}, 394 {"'!'"}, 395 {"!"}, 396 397 {"'hello_people,][)('"}, 398 {"'hi'"}, 399 {"'yyyy'"}, 400 {"''''"}, 401 {"'o''clock'"}, 402 403 {"G"}, 404 {"GG"}, 405 {"GGG"}, 406 {"GGGG"}, 407 {"GGGGG"}, 408 409 {"y"}, 410 {"yy"}, 411 {"yyy"}, 412 {"yyyy"}, 413 {"yyyyy"}, 414 415 {"M"}, 416 {"MM"}, 417 {"MMM"}, 418 {"MMMM"}, 419 {"MMMMM"}, 420 421 {"D"}, 422 {"DD"}, 423 {"DDD"}, 424 425 {"d"}, 426 {"dd"}, 427 {"ddd"}, 428 429 {"F"}, 430 {"FF"}, 431 {"FFF"}, 432 433 {"Q"}, 434 {"QQ"}, 435 {"QQQ"}, 436 {"QQQQ"}, 437 {"QQQQQ"}, 438 439 {"E"}, 440 {"EE"}, 441 {"EEE"}, 442 {"EEEE"}, 443 {"EEEEE"}, 444 445 {"a"}, 446 {"aa"}, 447 {"aaa"}, 448 {"aaaa"}, 449 {"aaaaa"}, 450 451 {"H"}, 452 {"HH"}, 453 {"HHH"}, 454 455 {"K"}, 456 {"KK"}, 457 {"KKK"}, 458 459 {"k"}, 460 {"kk"}, 461 {"kkk"}, 462 463 {"h"}, 464 {"hh"}, 465 {"hhh"}, 466 467 {"m"}, 468 {"mm"}, 469 {"mmm"}, 470 471 {"s"}, 472 {"ss"}, 473 {"sss"}, 474 475 {"S"}, 476 {"SS"}, 477 {"SSS"}, 478 {"SSSSSSSSS"}, 479 480 {"A"}, 481 {"AA"}, 482 {"AAA"}, 483 484 {"n"}, 485 {"nn"}, 486 {"nnn"}, 487 488 {"N"}, 489 {"NN"}, 490 {"NNN"}, 491 492 {"z"}, 493 {"zz"}, 494 {"zzz"}, 495 {"zzzz"}, 496 497 {"VV"}, 498 499 {"Z"}, 500 {"ZZ"}, 501 {"ZZZ"}, 502 503 {"X"}, 504 {"XX"}, 505 {"XXX"}, 506 {"XXXX"}, 507 {"XXXXX"}, 508 509 {"x"}, 510 {"xx"}, 511 {"xxx"}, 512 {"xxxx"}, 513 {"xxxxx"}, 514 515 {"ppH"}, 516 {"pppDD"}, 517 518 {"yyyy[-MM[-dd"}, 519 {"yyyy[-MM[-dd]]"}, 520 {"yyyy[-MM[]-dd]"}, 521 522 {"yyyy-MM-dd'T'HH:mm:ss.SSS"}, 523 524 {"e"}, 525 {"w"}, 526 {"W"}, 527 {"WW"}, 528 529 }; 530 } 531 532 @Test(dataProvider="validPatterns") 533 public void test_appendPattern_valid(String input) throws Exception { 534 builder.appendPattern(input); // test is for no error here 535 } 536 537 //----------------------------------------------------------------------- 538 @DataProvider(name="invalidPatterns") 539 Object[][] dataInvalid() { 540 return new Object[][] { 541 {"'"}, 542 {"'hello"}, 543 {"'hel''lo"}, 544 {"'hello''"}, 545 {"{"}, 546 {"}"}, 547 {"{}"}, 548 {"]"}, 549 {"yyyy]"}, 550 {"yyyy]MM"}, 551 {"yyyy[MM]]"}, 552 553 {"MMMMMM"}, 554 {"QQQQQQ"}, 555 {"EEEEEE"}, 556 {"aaaaaa"}, 557 {"ZZZZ"}, 558 {"XXXXXX"}, 559 {"zzzzz"}, 560 561 {"RO"}, 562 563 {"p"}, 564 {"pp"}, 565 {"p:"}, 566 567 {"f"}, 568 {"ff"}, 569 {"f:"}, 570 {"fy"}, 571 {"fa"}, 572 {"fM"}, 573 574 {"ww"}, 575 {"ee"}, 576 {"WWW"}, 577 }; 578 } 579 580 @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) 581 public void test_appendPattern_invalid(String input) throws Exception { 582 builder.appendPattern(input); // test is for error here 583 } 584 585 //----------------------------------------------------------------------- 586 @DataProvider(name="patternPrint") 587 Object[][] data_patternPrint() { 588 return new Object[][] { 589 {"Q", date(2012, 2, 10), "1"}, 590 {"QQ", date(2012, 2, 10), "01"}, 591 // {"QQQ", date(2012, 2, 10), "Q1"}, // TODO: data for quarters? 592 // {"QQQQ", date(2012, 2, 10), "Q1"}, 593 // {"QQQQQ", date(2012, 2, 10), "Q1"}, 594 }; 595 } 596 597 @Test(dataProvider="patternPrint") 598 public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { 599 DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); 600 String test = f.format(temporal); 601 assertEquals(test, expected); 602 } 603 604 private static Temporal date(int y, int m, int d) { 605 return LocalDate.of(y, m, d); 606 } 607 608 }