--- /dev/null 2016-03-11 12:19:56.743936992 +0300 +++ new/test/javax/imageio/plugins/tiff/TIFFFieldTest.java 2016-03-24 13:59:54.539009119 +0300 @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8152183 + * @author a.stepanov + * @summary Some checks for TIFFField methods + * @run main TIFFFieldTest + */ + +import java.util.List; +import java.util.ArrayList; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.plugins.tiff.*; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class TIFFFieldTest { + + private final static String NAME = "tag"; // tag name + private final static int NUM = 12345; // tag number + private final static int MIN_TYPE = TIFFTag.MIN_DATATYPE; + private final static int MAX_TYPE = TIFFTag.MAX_DATATYPE; + private final static String CONSTRUCT = "can construct TIFFField with "; + + private void check(boolean ok, String msg) { + if (!ok) { throw new RuntimeException(msg); } + } + + private void testConstructors() { + + // test constructors + + TIFFTag tag = new TIFFTag( + NAME, NUM, 1 << TIFFTag.TIFF_SHORT | 1 << TIFFTag.TIFF_LONG); + TIFFField f; + + // constructor: TIFFField(tag, value) + boolean ok = false; + try { new TIFFField(null, 0); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid count"); + + // check value type recognition + int v = 1 << 16; + f = new TIFFField(tag, v - 1); + check(f.getType() == TIFFTag.TIFF_SHORT, "must be treated as short"); + check(f.isIntegral(), "must be integral"); + f = new TIFFField(tag, v); + check(f.getType() == TIFFTag.TIFF_LONG, "must be treated as long"); + + // other checks + check(f.getAsLongs().length == 1, "invalid long[] size"); + check(f.isIntegral(), "must be integral"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + check(f.getValueAsString(0).equals(String.valueOf(v)), + "invalid string representation of value"); + check(f.getTag().getNumber() == f.getTagNumber(), + "invalid tag number"); + check(f.getCount() == 1, "invalid count"); + check(f.getTagNumber() == NUM, "invalid tag number"); + + // constructor: TIFFField(tag, type, count) + int type = TIFFTag.TIFF_SHORT; + + ok = false; + try { new TIFFField(null, type, 1); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, MAX_TYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid type tag"); + + // check that count == 1 for TIFF_IFD_POINTER + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_IFD_POINTER, 2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "only count = 1 should be allowed for IFDPointer"); + + // check that count == 0 is not allowed for TIFF_RATIONAL, TIFF_SRATIONAL + // (see fix for JDK-8149120) + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_RATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for Rational"); + + ok = false; + try { new TIFFField(tag, TIFFTag.TIFF_SRATIONAL, 0); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "count = 0 should not be allowed for SRational"); + + ok = false; + try { new TIFFField(tag, type, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "with invalid data count"); + + f = new TIFFField(tag, type, 0); + check(f.getCount() == 0, "invalid count"); + check(!f.hasDirectory(), "must not have directory"); + + // constructor: TIFFField(tag, type, count, data) + double a[] = {0.1, 0.2, 0.3}; + ok = false; + try { new TIFFField(null, TIFFTag.TIFF_DOUBLE, a.length, a); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, a.length - 1, a); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data count"); + + String a2[] = {"one", "two"}; + ok = false; + try { new TIFFField(tag, type, 2, a2); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + check((f.getDirectory() == null) && !f.hasDirectory(), + "must not have directory"); + + // constructor: TIFFField(tag, type, offset, dir) + List tags = new ArrayList<>(); + tags.add(tag); + TIFFTagSet sets[] = {new TIFFTagSet(tags)}; + TIFFDirectory dir = new TIFFDirectory(sets, null); + + ok = false; + try { new TIFFField(null, type, 4L, dir); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null tag"); + + ok = false; + try { new TIFFField(tag, type, 0L, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "non-positive offset"); + + long offset = 4; + + for (int t = MIN_TYPE; t <= MAX_TYPE; t++) { + + tag = new TIFFTag(NAME, NUM, 1 << t); + + // only TIFF_LONG and TIFF_IFD_POINTER types are allowed + if (t == TIFFTag.TIFF_LONG || t == TIFFTag.TIFF_IFD_POINTER) { + + f = new TIFFField(tag, t, offset, dir); + check(f.hasDirectory(), "must have directory"); + + check(f.getDirectory().getTag(NUM).getName().equals(NAME), + "invalid tag name"); + + check(f.getCount() == 1, "invalid count"); + check(f.getAsLong(0) == offset, "invalid offset"); + } else { + ok = false; + try { new TIFFField(tag, t, offset, dir); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid data type"); + } + } + + type = TIFFTag.TIFF_IFD_POINTER; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + + type = TIFFTag.TIFF_LONG; + tag = new TIFFTag(NAME, NUM, 1 << type); + ok = false; + try { new TIFFField(tag, type, offset, null); } + catch (NullPointerException e) { ok = true; } + check(ok, CONSTRUCT + "null TIFFDirectory"); + } + + private void testTypes() { + + // test getTypeName(), getTypeByName() methods + + boolean ok = false; + try { TIFFField.getTypeName(MIN_TYPE - 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + ok = false; + try { TIFFField.getTypeName(MAX_TYPE + 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid data type number used"); + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + String name = TIFFField.getTypeName(type); + check(TIFFField.getTypeByName(name) == type, "invalid type"); + } + + for (int type = MIN_TYPE; type <= MAX_TYPE; type++) { + + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + TIFFField f = new TIFFField(tag, type, 1); + check(f.getType() == type, "invalid type"); + + // check that invalid data types can not be used + for (int type2 = MIN_TYPE; type2 <= MAX_TYPE; ++type2) { + if (type2 != type) { + ok = false; + try { new TIFFField(tag, type2, 1); } // invalid type + catch (IllegalArgumentException e) { ok = true; } + check(ok, "invalid type was successfully set"); + } + } + } + } + + private void testGetAs() { + + // test getAs...() methods + + int type = TIFFTag.TIFF_SHORT; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT); + + short v = 123; + TIFFField f = new TIFFField(tag, v); + + check(f.getAsInt(0) == (int) v, "invalid int value"); + check(f.getAsLong(0) == (long) v, "invalid long value"); + check(f.getAsFloat(0) == (float) v, "invalid float value"); + check(f.getAsDouble(0) == (double) v, "invalid double value"); + check(f.getValueAsString(0).equals(Short.toString(v)), + "invalid string representation"); + + check(f.getAsInts().length == 1, "inavlid array size"); + check((int) v == f.getAsInts()[0], "invalid int value"); + + float fa[] = {0.01f, 1.01f}; + type = TIFFTag.TIFF_FLOAT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, fa.length, fa); + check(f.getCount() == fa.length, "invalid count"); + float fa2[] = f.getAsFloats(); + check(fa2.length == fa.length, "invalid array size"); + + for (int i = 0; i < fa.length; i++) { + check(fa2[i] == fa[i], "invalid value"); + check(f.getAsDouble(i) == fa[i], "invalid value"); + check(f.getAsInt(i) == (int) fa[i], "invalid value"); // cast to int + check(f.getValueAsString(i).equals(Float.toString(fa[i])), + "invalid string representation"); + } + + byte ba[] = {-1, -10, -100}; + type = TIFFTag.TIFF_BYTE; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ba.length, ba); + check(f.getCount() == ba.length, "invalid count"); + byte ba2[] = f.getAsBytes(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ba.length; i++) { + check(ba[i] == ba2[i], "invalid value"); + check(ba[i] == (byte) f.getAsDouble(i), "invalid value"); + check(ba[i] == (byte) f.getAsLong(i), "invalid value"); + + int unsigned = ba[i] & 0xff; + check(f.getAsInt(i) == unsigned, "must be treated as unsigned"); + } + + char ca[] = {'a', 'z', 0xffff}; + type = TIFFTag.TIFF_SHORT; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, ca.length, ca); + check(f.getCount() == ca.length, "invalid count"); + char ca2[] = f.getAsChars(); + check(ba2.length == ba.length, "invalid count"); + + for (int i = 0; i < ca.length; i++) { + check(ca[i] == ca2[i], "invalid value"); + check(ca[i] == (char) f.getAsDouble(i), "invalid value"); + check(ca[i] == (char) f.getAsLong(i), "invalid value"); + check(ca[i] == (char) f.getAsInt(i), "invalid value"); + } + + type = TIFFTag.TIFF_DOUBLE; + double da[] = {0.1, 0.2, 0.3}; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, da.length, da); + check(!f.isIntegral(), "isIntegral must be false"); + + double da2[] = f.getAsDoubles(); + check(f.getData() instanceof double[], "invalid data type"); + double da3[] = (double[]) f.getData(); + check((da.length == da2.length) && + (da.length == da2.length) && + (da.length == f.getCount()), + "invalid data count"); + for (int i = 0; i < da.length; ++i) { + check(da[i] == da2[i], "invalid data"); + check(da[i] == da3[i], "invalid data"); + } + + boolean ok = false; + try { f.getAsShorts(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { f.getAsRationals(); } + catch (ClassCastException e) { ok = true; } + check(ok, "invalid data cast"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MIN_DATATYPE - 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.MAX_DATATYPE + 1, 1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with invalid datatype"); + + ok = false; + try { TIFFField.createArrayForType(TIFFTag.TIFF_FLOAT, -1); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, "can create array with negative count"); + + int n = 3; + Object + RA = TIFFField.createArrayForType(TIFFTag.TIFF_RATIONAL, n), + SRA = TIFFField.createArrayForType(TIFFTag.TIFF_SRATIONAL, n); + check(RA instanceof long[][], "invalid data type"); + check(SRA instanceof int[][], "invalid data type"); + + long ra[][] = (long[][]) RA; + int sra[][] = (int[][]) SRA; + check((ra.length == n) && (sra.length == n), "invalid data size"); + for (int i = 0; i < n; i++) { + check((ra[i].length == 2) && (sra[i].length == 2), + "invalid data size"); + ra[i][0] = 1; ra[i][1] = 5 + i; + sra[i][0] = -1; sra[i][1] = 5 + i; + } + + type = TIFFTag.TIFF_RATIONAL; + TIFFField f1 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, ra); + type = TIFFTag.TIFF_SRATIONAL; + TIFFField f2 = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, n, sra); + + check((f1.getCount() == ra.length) && (f2.getCount() == sra.length), + "invalid data count"); + + check(f1.getAsRationals().length == n, "invalid data count"); + check(f2.getAsSRationals().length == n, "invalid data count"); + for (int i = 0; i < n; i++) { + long r[] = f1.getAsRational(i); + check(r.length == 2, "invalid data format"); + check((r[0] == 1) && (r[1] == i + 5), "invalid data"); + + int sr[] = f2.getAsSRational(i); + check(sr.length == 2, "invalid data format"); + check((sr[0] == -1) && (sr[1] == i + 5), "invalid data"); + + // check string representation + String s = Long.toString(r[0]) + "/" + Long.toString(r[1]); + check(s.equals(f1.getValueAsString(i)), + "invalid string representation"); + + s = Integer.toString(sr[0]) + "/" + Integer.toString(sr[1]); + check(s.equals(f2.getValueAsString(i)), + "invalid string representation"); + + // see the documentation for getAsInt: + // TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated + // by dividing the numerator into the denominator using + // double-precision arithmetic and then casting to int + check(f1.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + check(f2.getAsInt(i) == (int)(r[0] / r[1]), + "invalid result for getAsInt"); + } + + ok = false; + try { f1.getAsRational(ra.length); } + catch (ArrayIndexOutOfBoundsException e) { ok = true; } + check(ok, "invalid index"); + + String sa[] = {"-1.e-25", "22", "-1.23E5"}; + type = TIFFTag.TIFF_ASCII; + f = new TIFFField( + new TIFFTag(NAME, NUM, 1 << type), type, sa.length, sa); + + // test clone() method + TIFFField cloned = null; + try { cloned = f.clone(); } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + + check(f.getCount() == cloned.getCount(), "invalid cloned field count"); + + check(f.getCount() == sa.length, "invalid data count"); + for (int i = 0; i < sa.length; i++) { + check(sa[i].equals(f.getAsString(i)), "invalid data"); + // see docs: "data in TIFF_ASCII format will be parsed as by + // the Double.parseDouble method, with the result cast to int" + check(f.getAsInt(i) == + (int) Double.parseDouble(sa[i]), "invalid data"); + check(f.getAsDouble(i) == Double.parseDouble(sa[i]), "invalid data"); + + check(sa[i].equals(cloned.getAsString(i)), "invalid cloned data"); + } + } + + private void testCreateFromNode() { + + int type = TIFFTag.TIFF_LONG; + + List tags = new ArrayList<>(); + int v = 1234567; + TIFFTag tag = new TIFFTag(NAME, NUM, 1 << type); + tags.add(tag); + TIFFTagSet ts = new TIFFTagSet(tags); + + boolean ok = false; + try { TIFFField.createFromMetadataNode(ts, null); } + catch (NullPointerException e) { ok = true; } + check(ok, "can create TIFFField from a null node"); + + TIFFField f = new TIFFField(tag, v); + Node node = f.getAsNativeNode(); + check(node.getNodeName().equals(f.getClass().getSimpleName()), + "invalid node name"); + + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + String an = attrs.item(i).getNodeName().toLowerCase(); + String av = attrs.item(i).getNodeValue(); + if (an.contains("name")) { + check(av.equals(NAME), "invalid tag name"); + } else if (an.contains("number")) { + check(av.equals(Integer.toString(NUM)), "invalid tag number"); + } + } + + // invalid node + IIOMetadataNode nok = new IIOMetadataNode("NOK"); + + ok = false; + try { TIFFField.createFromMetadataNode(ts, nok); } + catch (IllegalArgumentException e) { ok = true; } + check(ok, CONSTRUCT + "invalid node name"); + + TIFFField f2 = TIFFField.createFromMetadataNode(ts, node); + check(f2.getType() == type, "invalid type"); + check(f2.getTagNumber() == NUM, "invalid tag number"); + check(f2.getTag().getName().equals(NAME), "invalid tag name"); + check(f2.getCount() == 1, "invalid count"); + check(f2.getAsInt(0) == v, "invalid value"); + } + + public static void main(String[] args) { + + TIFFFieldTest test = new TIFFFieldTest(); + test.testConstructors(); + test.testCreateFromNode(); + test.testTypes(); + test.testGetAs(); + } +}