1 /*
   2  * Copyright (c) 2016, 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  * @test
  26  * @bug     8152183 8149562 8169725 8169728
  27  * @author  a.stepanov
  28  * @summary Some checks for TIFFField methods
  29  * @run     main TIFFFieldTest
  30  */
  31 
  32 import java.util.List;
  33 import java.util.ArrayList;
  34 import javax.imageio.metadata.IIOMetadataNode;
  35 import javax.imageio.plugins.tiff.*;
  36 import org.w3c.dom.NamedNodeMap;
  37 import org.w3c.dom.Node;
  38 
  39 public class TIFFFieldTest {
  40 
  41     private final static String NAME = "tag"; // tag name
  42     private final static int    NUM  = 12345; // tag number
  43     private final static int MIN_TYPE = TIFFTag.MIN_DATATYPE;
  44     private final static int MAX_TYPE = TIFFTag.MAX_DATATYPE;
  45     private final static String CONSTRUCT = "can construct TIFFField with ";
  46 
  47     private void check(boolean ok, String msg) {
  48         if (!ok) { throw new RuntimeException(msg); }
  49     }
  50 
  51     private void testConstructors() {
  52 
  53         // test constructors
  54 
  55         TIFFTag tag = new TIFFTag(
  56             NAME, NUM, 1 << TIFFTag.TIFF_SHORT | 1 << TIFFTag.TIFF_LONG);
  57         TIFFField f;
  58 
  59         // constructor: TIFFField(tag, value)
  60         boolean ok = false;
  61         try { new TIFFField(null, 0); }
  62         catch (NullPointerException e) { ok = true; }
  63         check(ok, CONSTRUCT + "null tag");
  64 
  65         ok = false;
  66         try { new TIFFField(tag, -1); }
  67         catch (IllegalArgumentException e) { ok = true; }
  68         check(ok, CONSTRUCT + "negative value");
  69 
  70         ok = false;
  71         try { new TIFFField(tag, 1L << 32); }
  72         catch (IllegalArgumentException e) { ok = true; }
  73         check(ok, CONSTRUCT + "value > 0xffffffff");
  74 
  75         ok = false;
  76         try {
  77             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT);
  78             new TIFFField(t, 0x10000);
  79         } catch (IllegalArgumentException e) { ok = true; }
  80         check(ok, CONSTRUCT + "value 0x10000 incompatible with TIFF_SHORT");
  81 
  82         ok = false;
  83         try {
  84             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
  85             new TIFFField(t, 0xffff);
  86         } catch (IllegalArgumentException e) { ok = true; }
  87         check(ok, CONSTRUCT + "value 0xffff incompatible with TIFF_LONG");
  88 
  89         // check value type recognition
  90         int v = 1 << 16;
  91         f = new TIFFField(tag, v - 1);
  92         check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short");
  93         check(f.isIntegral(), "must be integral");
  94         f = new TIFFField(tag, v);
  95         check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long");
  96 
  97         // other checks
  98         check(f.getAsLongs().length == 1, "invalid long[] size");
  99         check(f.isIntegral(), "must be integral");
 100         check((f.getDirectory() == null) && !f.hasDirectory(),
 101             "must not have directory");
 102         check(f.getValueAsString(0).equals(String.valueOf(v)),
 103             "invalid string representation of value");
 104         check(f.getTag().getNumber() == f.getTagNumber(),
 105             "invalid tag number");
 106         check(f.getCount() == 1, "invalid count");
 107         check(f.getTagNumber() == NUM, "invalid tag number");
 108 
 109         // constructor: TIFFField(tag, type, count)
 110         int type = TIFFTag.TIFF_SHORT;
 111 
 112         ok = false;
 113         try { new TIFFField(null, type, 1); }
 114         catch (NullPointerException e) { ok = true; }
 115         check(ok, CONSTRUCT + "null tag");
 116 
 117         ok = false;
 118         try { new TIFFField(tag, MAX_TYPE + 1, 1); }
 119         catch (IllegalArgumentException e) { ok = true; }
 120         check(ok, CONSTRUCT + "invalid type tag");
 121 
 122         // check that count == 1 for TIFF_IFD_POINTER
 123         ok = false;
 124         try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); }
 125         catch (IllegalArgumentException e) { ok = true; }
 126         check(ok, "only count = 1 should be allowed for IFDPointer");
 127 
 128         ok = false;
 129         try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); }
 130         catch (IllegalArgumentException e) { ok = true; }
 131         check(ok, "only count = 1 should be allowed for IFDPointer");
 132 
 133         // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL
 134         // (see fix for JDK-8149120)
 135         ok = false;
 136         try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); }
 137         catch (IllegalArgumentException e) { ok = true; }
 138         check(ok, "count = 0 should not be allowed for Rational");
 139 
 140         ok = false;
 141         try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); }
 142         catch (IllegalArgumentException e) { ok = true; }
 143         check(ok, "count = 0 should not be allowed for SRational");
 144 
 145         ok = false;
 146         try { new TIFFField(tag, type, -1); }
 147         catch (IllegalArgumentException e) { ok = true; }
 148         check(ok, CONSTRUCT + "with invalid data count");
 149 
 150         f = new TIFFField(tag, type, 0);
 151         check(f.getCount() == 0, "invalid count");
 152         check(!f.hasDirectory(), "must not have directory");
 153 
 154         // constructor: TIFFField(tag, type, count, data)
 155         double a[] = {0.1, 0.2, 0.3};
 156         ok = false;
 157         try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); }
 158         catch (NullPointerException e) { ok = true; }
 159         check(ok, CONSTRUCT + "null tag");
 160 
 161         ok = false;
 162         try { new TIFFField(tag, type, a.length - 1, a); }
 163         catch (IllegalArgumentException e) { ok = true; }
 164         check(ok, CONSTRUCT + "invalid data count");
 165 
 166         String a2[] = {"one", "two"};
 167         ok = false;
 168         try { new TIFFField(tag, type, 2, a2); }
 169         catch (IllegalArgumentException e) { ok = true; }
 170         check(ok, CONSTRUCT + "invalid data type");
 171         check((f.getDirectory() == null) && !f.hasDirectory(),
 172             "must not have directory");
 173 
 174         ok = false;
 175         try {
 176             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
 177             long[][] tiffRationals = new long[6][3];
 178             new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
 179                 tiffRationals);
 180         } catch (IllegalArgumentException e) {
 181             ok = true;
 182         }
 183 
 184         ok = false;
 185         try {
 186             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SRATIONAL);
 187             int[][] tiffSRationals = new int[6][3];
 188             new TIFFField(t, TIFFTag.TIFF_SRATIONAL, tiffSRationals.length,
 189                 tiffSRationals);
 190         } catch (IllegalArgumentException e) {
 191             ok = true;
 192         }
 193 
 194         ok = false;
 195         try {
 196             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
 197             long[] tiffLongs = new long[] {0, -7, 10};
 198             new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
 199                 tiffLongs);
 200         } catch (IllegalArgumentException e) {
 201             ok = true;
 202         }
 203 
 204         ok = false;
 205         try {
 206             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
 207             long[] tiffLongs = new long[] {0, 7, 0x100000000L};
 208             new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
 209                 tiffLongs);
 210         } catch (IllegalArgumentException e) {
 211             ok = true;
 212         }
 213 
 214         ok = false;
 215         try {
 216             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
 217             long[] tiffLongs = new long[] {-7};
 218             new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
 219                 tiffLongs);
 220         } catch (IllegalArgumentException e) {
 221             ok = true;
 222         }
 223 
 224         ok = false;
 225         try {
 226             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
 227             long[] tiffLongs = new long[] {0x100000000L};
 228             new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
 229                 tiffLongs);
 230         } catch (IllegalArgumentException e) {
 231             ok = true;
 232         }
 233 
 234         ok = false;
 235         try {
 236             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
 237             long[][] tiffRationals = new long[][] {
 238                 {10, 2},
 239                 {1, -3},
 240                 {4,  7}
 241             };
 242             new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
 243                 tiffRationals);
 244         } catch (IllegalArgumentException e) {
 245             ok = true;
 246         }
 247 
 248         ok = false;
 249         try {
 250             TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
 251             long[][] tiffRationals = new long[][] {
 252                 {10, 2},
 253                 {0x100000000L, 3},
 254                 {4,  7}
 255             };
 256             new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
 257                 tiffRationals);
 258         } catch (IllegalArgumentException e) {
 259             ok = true;
 260         }
 261 
 262         // constructor: TIFFField(tag, type, offset, dir)
 263         List<TIFFTag> tags = new ArrayList<>();
 264         tags.add(tag);
 265         TIFFTagSet sets[] = {new TIFFTagSet(tags)};
 266         TIFFDirectory dir = new TIFFDirectory(sets, null);
 267 
 268         ok = false;
 269         try { new TIFFField(null, type, 4L, dir); }
 270         catch (NullPointerException e) { ok = true; }
 271         check(ok, CONSTRUCT + "null tag");
 272 
 273         ok = false;
 274         try { new TIFFField(tag, type, 0L, dir); }
 275         catch (IllegalArgumentException e) { ok = true; }
 276         check(ok, CONSTRUCT + "non-positive offset");
 277 
 278         long offset = 4;
 279 
 280         for (int t = MIN_TYPE; t <= MAX_TYPE; t++) {
 281 
 282             tag = new TIFFTag(NAME, NUM, 1 << t);
 283 
 284             // only TIFF_LONG and TIFF_IFD_POINTER types are allowed
 285             if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) {
 286 
 287                 f = new TIFFField(tag, t, offset, dir);
 288                 check(f.hasDirectory(), "must have directory");
 289 
 290                 check(f.getDirectory().getTag(NUM).getName().equals(NAME),
 291                     "invalid tag name");
 292 
 293                 check(f.getCount() == 1, "invalid count");
 294                 check(f.getAsLong(0) == offset, "invalid offset");
 295             } else {
 296                 ok = false;
 297                 try { new TIFFField(tag, t, offset, dir); }
 298                 catch (IllegalArgumentException e) { ok = true; }
 299                 check(ok, CONSTRUCT + "invalid data type");
 300             }
 301         }
 302 
 303         type = TIFFTag.TIFF_IFD_POINTER;
 304         tag = new TIFFTag(NAME, NUM, 1 << type);
 305         ok = false;
 306         try { new TIFFField(tag, type, offset, null); }
 307         catch (NullPointerException e) { ok = true; }
 308         check(ok, CONSTRUCT + "null TIFFDirectory");
 309 
 310         type = TIFFTag.TIFF_LONG;
 311         tag = new TIFFTag(NAME, NUM, 1 << type);
 312         ok = false;
 313         try { new TIFFField(tag, type, offset, null); }
 314         catch (NullPointerException e) { ok = true; }
 315         check(ok, CONSTRUCT + "null TIFFDirectory");
 316     }
 317 
 318     private void testTypes() {
 319 
 320         // test getTypeName(), getTypeByName() methods
 321 
 322         boolean ok = false;
 323         try { TIFFField.getTypeName(MIN_TYPE - 1); }
 324         catch (IllegalArgumentException e) { ok = true; }
 325         check(ok, "invalid data type number used");
 326 
 327         ok = false;
 328         try { TIFFField.getTypeName(MAX_TYPE + 1); }
 329         catch (IllegalArgumentException e) { ok = true; }
 330         check(ok, "invalid data type number used");
 331 
 332         for (int type = MIN_TYPE; type <= MAX_TYPE; type++) {
 333             String name = TIFFField.getTypeName(type);
 334             check(TIFFField.getTypeByName(name) == type, "invalid type");
 335         }
 336 
 337         for (int type = MIN_TYPE; type <= MAX_TYPE; type++) {
 338 
 339             TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type);
 340             TIFFField f = new TIFFField(tag, type, 1);
 341             check(f.getType() == type, "invalid type");
 342 
 343             // check that invalid data types can not be used
 344             for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) {
 345                 if (type2 != type) {
 346                     ok = false;
 347                     try { new TIFFField(tag, type2, 1); } // invalid type
 348                     catch (IllegalArgumentException e) { ok = true; }
 349                     check(ok, "invalid type was successfully set");
 350                 }
 351             }
 352         }
 353     }
 354 
 355     private void testGetAs() {
 356 
 357         // test getAs...() methods
 358 
 359         int type = TIFFTag.TIFF_SHORT;
 360         TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT);
 361 
 362         short v = 123;
 363         TIFFField f = new TIFFField(tag, v);
 364 
 365         check(f.getAsInt(0)    ==    (int) v, "invalid int value");
 366         check(f.getAsLong(0)   ==   (long) v, "invalid long value");
 367         check(f.getAsFloat(0)  ==  (float) v, "invalid float value");
 368         check(f.getAsDouble(0) == (double) v, "invalid double value");
 369         check(f.getValueAsString(0).equals(Short.toString(v)),
 370             "invalid string representation");
 371 
 372         check(f.getAsInts().length == 1, "inavlid array size");
 373         check((int) v == f.getAsInts()[0], "invalid int value");
 374 
 375         float fa[] = {0.01f, 1.01f};
 376         type = TIFFTag.TIFF_FLOAT;
 377         f = new TIFFField(
 378             new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa);
 379         check(f.getCount() == fa.length, "invalid count");
 380         float fa2[] = f.getAsFloats();
 381         check(fa2.length == fa.length, "invalid array size");
 382 
 383         for (int i = 0; i < fa.length; i++) {
 384             check(fa2[i] == fa[i], "invalid value");
 385             check(f.getAsDouble(i) == fa[i], "invalid value");
 386             check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int
 387             check(f.getValueAsString(i).equals(Float.toString(fa[i])),
 388             "invalid string representation");
 389         }
 390 
 391         byte ba[] = {-1, -10, -100};
 392         type = TIFFTag.TIFF_BYTE;
 393         f = new TIFFField(
 394             new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba);
 395         check(f.getCount() == ba.length, "invalid count");
 396         byte ba2[] = f.getAsBytes();
 397         check(ba2.length == ba.length, "invalid count");
 398 
 399         for (int i = 0; i < ba.length; i++) {
 400             check(ba[i] == ba2[i], "invalid value");
 401             check(ba[i] == (byte) f.getAsDouble(i), "invalid value");
 402             check(ba[i] == (byte) f.getAsLong(i),   "invalid value");
 403 
 404             int unsigned = ba[i] & 0xff;
 405             check(f.getAsInt(i) == unsigned, "must be treated as unsigned");
 406         }
 407 
 408         char ca[] = {'a', 'z', 0xffff};
 409         type = TIFFTag.TIFF_SHORT;
 410         f = new TIFFField(
 411             new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca);
 412         check(f.getCount() == ca.length, "invalid count");
 413         char ca2[] = f.getAsChars();
 414         check(ba2.length == ba.length, "invalid count");
 415 
 416         for (int i = 0; i < ca.length; i++) {
 417             check(ca[i] == ca2[i], "invalid value");
 418             check(ca[i] == (char) f.getAsDouble(i), "invalid value");
 419             check(ca[i] == (char) f.getAsLong(i), "invalid value");
 420             check(ca[i] == (char) f.getAsInt(i), "invalid value");
 421         }
 422 
 423         type = TIFFTag.TIFF_DOUBLE;
 424         double da[] = {0.1, 0.2, 0.3};
 425         f = new TIFFField(
 426             new TIFFTag(NAME, NUM, 1 << type), type, da.length, da);
 427         check(!f.isIntegral(), "isIntegral must be false");
 428 
 429         double da2[] = f.getAsDoubles();
 430         check(f.getData() instanceof double[], "invalid data type");
 431         double da3[] = (double[]) f.getData();
 432         check((da.length == da2.length) &&
 433               (da.length == da2.length) &&
 434               (da.length == f.getCount()),
 435                "invalid data count");
 436         for (int i = 0; i < da.length; ++i) {
 437             check(da[i] == da2[i], "invalid data");
 438             check(da[i] == da3[i], "invalid data");
 439         }
 440 
 441         boolean ok = false;
 442         try { f.getAsShorts(); }
 443         catch (ClassCastException e) { ok = true; }
 444         check(ok, "invalid data cast");
 445 
 446         ok = false;
 447         try { f.getAsRationals(); }
 448         catch (ClassCastException e) { ok = true; }
 449         check(ok, "invalid data cast");
 450 
 451         ok = false;
 452         try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); }
 453         catch (IllegalArgumentException e) { ok = true; }
 454         check(ok, "can create array with invalid datatype");
 455 
 456         ok = false;
 457         try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); }
 458         catch (IllegalArgumentException e) { ok = true; }
 459         check(ok, "can create array with invalid datatype");
 460 
 461         ok = false;
 462         try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); }
 463         catch (IllegalArgumentException e) { ok = true; }
 464         check(ok, "can create array with negative count");
 465 
 466         int n = 3;
 467         Object
 468             RA  = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL,  n),
 469             SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n);
 470         check(RA  instanceof long[][], "invalid data type");
 471         check(SRA instanceof  int[][], "invalid data type");
 472 
 473         long ra[][] = (long[][]) RA;
 474         int sra[][] = (int[][]) SRA;
 475         check((ra.length == n) && (sra.length == n), "invalid data size");
 476         for (int i = 0; i < n; i++) {
 477             check((ra[i].length == 2) && (sra[i].length == 2),
 478                 "invalid data size");
 479             ra[i][0]  =  1;  ra[i][1]  = 5 + i;
 480             sra[i][0] = -1;  sra[i][1] = 5 + i;
 481         }
 482 
 483         type = TIFFTag.TIFF_RATIONAL;
 484         TIFFField f1 = new TIFFField(
 485             new TIFFTag(NAME, NUM, 1 << type), type, n, ra);
 486         type = TIFFTag.TIFF_SRATIONAL;
 487         TIFFField f2 = new TIFFField(
 488             new TIFFTag(NAME, NUM, 1 << type), type, n, sra);
 489 
 490         check((f1.getCount() == ra.length) && (f2.getCount() == sra.length),
 491             "invalid data count");
 492 
 493         check(f1.getAsRationals().length  == n, "invalid data count");
 494         check(f2.getAsSRationals().length == n, "invalid data count");
 495         for (int i = 0; i < n; i++) {
 496             long r[] = f1.getAsRational(i);
 497             check(r.length == 2, "invalid data format");
 498             check((r[0] == 1) && (r[1] == i + 5), "invalid data");
 499 
 500             int sr[] = f2.getAsSRational(i);
 501             check(sr.length == 2, "invalid data format");
 502             check((sr[0] == -1) && (sr[1] == i + 5), "invalid data");
 503 
 504             // check string representation
 505             String s = Long.toString(r[0]) + "/" + Long.toString(r[1]);
 506             check(s.equals(f1.getValueAsString(i)),
 507                 "invalid string representation");
 508 
 509             s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]);
 510             check(s.equals(f2.getValueAsString(i)),
 511                 "invalid string representation");
 512 
 513             // see the documentation for getAsInt:
 514             // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated
 515             // by dividing the numerator into the denominator using
 516             // double-precision arithmetic and then casting to int
 517             check(f1.getAsInt(i) == (int)(r[0] / r[1]),
 518                 "invalid result for getAsInt");
 519             check(f2.getAsInt(i) == (int)(r[0] / r[1]),
 520                 "invalid result for getAsInt");
 521         }
 522 
 523         ok = false;
 524         try { f1.getAsRational(ra.length); }
 525         catch (ArrayIndexOutOfBoundsException e) { ok = true; }
 526         check(ok, "invalid index");
 527 
 528         String sa[] = {"-1.e-25", "22", "-1.23E5"};
 529         type = TIFFTag.TIFF_ASCII;
 530         f = new TIFFField(
 531             new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa);
 532 
 533         // test clone() method
 534         TIFFField cloned = null;
 535         try { cloned = f.clone(); } catch (CloneNotSupportedException e) {
 536             throw new RuntimeException(e);
 537         }
 538 
 539         check(f.getCount() == cloned.getCount(), "invalid cloned field count");
 540 
 541         check(f.getCount() == sa.length, "invalid data count");
 542         for (int i = 0; i < sa.length; i++) {
 543             check(sa[i].equals(f.getAsString(i)), "invalid data");
 544             // see docs: "data in TIFF_ASCII format will be parsed as by
 545             // the Double.parseDouble method, with the result cast to int"
 546             check(f.getAsInt(i) ==
 547                 (int) Double.parseDouble(sa[i]), "invalid data");
 548             check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data");
 549 
 550             check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data");
 551         }
 552     }
 553 
 554     private void testCreateFromNode() {
 555 
 556         int type = TIFFTag.TIFF_LONG;
 557 
 558         List<TIFFTag> tags = new ArrayList<>();
 559         int v = 1234567;
 560         TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type);
 561         tags.add(tag);
 562         TIFFTagSet ts = new TIFFTagSet(tags);
 563 
 564         boolean ok = false;
 565         try {
 566             TIFFField.createFromMetadataNode(ts, null);
 567         } catch (IllegalArgumentException e) {
 568             // createFromMetadataNode() formerly threw a NullPointerException
 569             // if its Node parameter was null, but the specification has been
 570             // modified to allow only IllegalArgumentExceptions, perhaps with
 571             // a cause set. In the present invocation the cause would be set
 572             // to a NullPointerException but this is not explicitly specified
 573             // hence not verified here.
 574             ok = true;
 575         }
 576         check(ok, "can create TIFFField from a null node");
 577 
 578         TIFFField f = new TIFFField(tag, v);
 579         Node node = f.getAsNativeNode();
 580         check(node.getNodeName().equals(f.getClass().getSimpleName()),
 581             "invalid node name");
 582 
 583         NamedNodeMap attrs = node.getAttributes();
 584         for (int i = 0; i < attrs.getLength(); i++) {
 585             String an = attrs.item(i).getNodeName().toLowerCase();
 586             String av = attrs.item(i).getNodeValue();
 587             if (an.contains("name")) {
 588                 check(av.equals(NAME), "invalid tag name");
 589             } else if (an.contains("number")) {
 590                 check(av.equals(Integer.toString(NUM)), "invalid tag number");
 591             }
 592         }
 593 
 594         // invalid node
 595         IIOMetadataNode nok = new IIOMetadataNode("NOK");
 596 
 597         ok = false;
 598         try { TIFFField.createFromMetadataNode(ts, nok); }
 599         catch (IllegalArgumentException e) { ok = true; }
 600         check(ok, CONSTRUCT + "invalid node name");
 601 
 602         TIFFField f2 = TIFFField.createFromMetadataNode(ts, node);
 603         check(f2.getType() == type, "invalid type");
 604         check(f2.getTagNumber() == NUM, "invalid tag number");
 605         check(f2.getTag().getName().equals(NAME), "invalid tag name");
 606         check(f2.getCount()  == 1, "invalid count");
 607         check(f2.getAsInt(0) == v, "invalid value");
 608     }
 609 
 610     public static void main(String[] args) {
 611 
 612         TIFFFieldTest test = new TIFFFieldTest();
 613         test.testConstructors();
 614         test.testCreateFromNode();
 615         test.testTypes();
 616         test.testGetAs();
 617     }
 618 }