Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/descriptor/DescriptorTest.java
38838 views
/*1* Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 6204469 627376526* @summary Test various aspects of the Descriptor interface27* @author Eamonn McManus28* @run clean DescriptorTest29* @run build DescriptorTest30* @run main DescriptorTest31*/3233import java.io.*;34import java.lang.reflect.*;35import java.util.*;36import javax.management.*;3738public class DescriptorTest {39private static String failureMessage;4041// Warning: many tests here know the contents of these variables42// so if you change them you must change the tests43private static final String[] testFieldNames = {44"a", "C", "aa", "int", "nul",45};46private static final Object[] testFieldValues = {47"b", "D", "bb", 5, null,48};49private static final String[] testFieldStrings = {50"a=b", "C=D", "aa=bb", "int=(5)", "nul=",51};5253public static void main(String[] args) throws Exception {54genericTests(ImmutableDescriptor.class);55genericTests(javax.management.modelmbean.DescriptorSupport.class);56if (failureMessage != null)57throw new Exception("TEST FAILED: " + failureMessage);58else59System.out.println("Test passed");60}6162private static void genericTests(Class<? extends Descriptor> descrClass) {63System.out.println("--- generic tests for " + descrClass.getName() +64" ---");65for (Case<Class<? extends Descriptor>, ?, ?> test :66genericDescriptorTests)67test.run(descrClass);68}6970/*71Testing has three parts. We take the input parameter, of type P,72and give it to the "prepare" method. That returns us a test73parameter, of type T. We give that to the "test" method. That74in turn returns us a check value, of type C. We give this to the75"check" method. If the "check" method returns null, the test passes.76If the "check" method returns a string, that string explains the77test failure. If any of the methods throws an exception, the78test fails.79*/80private static abstract class Case<P, T, C> {81Case(String name) {82this.name = name;83}8485void run(P p) {86System.out.println("test: " + name);87try {88T t = prepare(p);89C c = test(t);90String failed = check(c);91if (failed != null) {92System.out.println("FAILED: " + name + ": " + failed);93failureMessage = failed;94}95} catch (Exception e) {96System.out.println("FAILED: " + name + ": exception:");97e.printStackTrace(System.out);98failureMessage = e.toString();99}100}101102abstract T prepare(P p) throws Exception;103abstract C test(T t) throws Exception;104abstract String check(C c) throws Exception;105106private final String name;107}108109/*110Test case where the preparation step consists of constructing an111instance of the given Descriptor subclass containing test values,112then giving that to the "test" method.113*/114private static abstract class ProtoCase<C>115extends Case<Class<? extends Descriptor>, Descriptor, C> {116117ProtoCase(String name) {118super(name);119}120121Descriptor prepare(Class<? extends Descriptor> descrClass)122throws Exception {123Constructor<? extends Descriptor> con =124descrClass.getConstructor(String[].class, Object[].class);125return con.newInstance(testFieldNames, testFieldValues);126}127}128129/*130Test case where the "test" method must return a value of type C131which we will compare against the testValue parameter given to132the test constructor.133*/134private static abstract class ValueProtoCase<C> extends ProtoCase<C> {135ValueProtoCase(String name, C testValue) {136super(name);137this.testValue = testValue;138}139140String check(C c) {141final boolean array = (testValue instanceof Object[]);142final boolean equal =143array ?144Arrays.deepEquals((Object[]) testValue, (Object[]) c) :145testValue.equals(c);146if (equal)147return null;148return "wrong value: " + string(c) + " should be " +149string(testValue);150}151152private final C testValue;153}154155/*156Test case where the dontChange method does some operation on the157test Descriptor that is not supposed to change the contents of158the Descriptor. This should work for both mutable and immutable159Descriptors, since immutable Descriptors are supposed to do160nothing (rather than throw an exception) for mutation operations161that would not in fact change the contents.162*/163private static abstract class UnchangedCase extends ProtoCase<Descriptor> {164UnchangedCase(String name) {165super(name);166}167168Descriptor test(Descriptor d) {169dontChange(d);170return d;171}172173String check(Descriptor d) {174String[] dnames = d.getFieldNames();175if (!strings(dnames).equals(strings(testFieldNames)))176return "descriptor names changed: " + strings(dnames);177Object[] values = d.getFieldValues(testFieldNames);178if (values.length != testFieldValues.length)179return "getFieldValues: bogus length: " + values.length;180for (int i = 0; i < values.length; i++) {181Object expected = testFieldValues[i];182Object found = values[i];183if ((expected == null) ?184found != null :185!expected.equals(found))186return "descriptor value changed: " + testFieldNames[i] +187" was " + expected + " now " + found;188}189return null;190}191192abstract void dontChange(Descriptor d);193}194195/*196Test case where the change(d) method attempts to make some197change to the Descriptor d. The behaviour depends on whether198the Descriptor is mutable or not. If the Descriptor is199immutable, then the change attempt must throw a200RuntimeOperationsException wrapping an201UnsupportedOperationException. If the Descriptor is mutable,202then the change attempt must succeed, and the Descriptor must203then look like the fieldsAndValues parameter to the constructor.204This is simply an alternating set of field names and corresponding205values. So for example if it is206207"a", "b", "x", 5208209that represents a Descriptor with fields "a" and "x" whose210corresponding values are "x" and Integer.valueOf(5).211*/212private static abstract class ChangedCase extends ProtoCase<Object> {213ChangedCase(String name, Object... fieldsAndValues) {214super(name);215if (fieldsAndValues.length % 2 != 0)216throw new AssertionError("test wrong: odd fieldsAndValues");217this.fieldsAndValues = fieldsAndValues;218this.immutableTest = new UnsupportedExceptionCase(name) {219void provoke(Descriptor d) {220ChangedCase.this.change(d);221}222};223}224225Object test(Descriptor d) {226if (immutable(d))227return immutableTest.test(d);228else {229change(d);230return d;231}232}233234String check(Object c) {235if (c instanceof Exception)236return immutableTest.check((Exception) c);237else if (!(c instanceof Descriptor)) {238return "test returned strange value: " +239c.getClass() + ": " + c;240} else {241Descriptor d = (Descriptor) c;242String[] names = new String[fieldsAndValues.length / 2];243Object[] expected = new Object[names.length];244for (int i = 0; i < fieldsAndValues.length; i += 2) {245names[i / 2] = (String) fieldsAndValues[i];246expected[i / 2] = fieldsAndValues[i + 1];247}248String[] foundNames = d.getFieldNames();249if (!strings(foundNames).equals(strings(names))) {250return "wrong field names after change: found " +251strings(foundNames) + ", expected " + strings(names);252}253Object[] found = d.getFieldValues(names);254if (!Arrays.deepEquals(expected, found)) {255return "wrong value after change: for fields " +256Arrays.asList(names) + " values are " +257Arrays.asList(found) + ", should be " +258Arrays.asList(expected);259}260return null;261}262}263264abstract void change(Descriptor d);265266private final Object[] fieldsAndValues;267private final ExceptionCase immutableTest;268}269270/*271Test case where an operation provoke(d) on the test Descriptor d272is supposed to provoke an exception. The exception must be a273RuntimeOperationsException wrapping another exception whose type274is determined by the exceptionClass() method.275*/276private static abstract class ExceptionCase extends ProtoCase<Exception> {277278ExceptionCase(String name) {279super(name);280}281282Exception test(Descriptor d) {283try {284provoke(d);285return null;286} catch (Exception e) {287return e;288}289}290291String check(Exception e) {292if (e == null)293return "did not throw exception: " + expected();294if (!(e instanceof RuntimeOperationsException)) {295StringWriter sw = new StringWriter();296PrintWriter pw = new PrintWriter(sw);297e.printStackTrace(pw);298pw.flush();299return "wrong exception: " + expected() + ": found: " + sw;300}301Throwable cause = e.getCause();302if (!exceptionClass().isInstance(cause))303return "wrong wrapped exception: " + cause + ": " + expected();304return null;305}306307String expected() {308return "expected " + RuntimeOperationsException.class.getName() +309" wrapping " + exceptionClass().getName();310}311312abstract Class<? extends Exception> exceptionClass();313abstract void provoke(Descriptor d);314}315316private static abstract class IllegalExceptionCase extends ExceptionCase {317IllegalExceptionCase(String name) {318super(name);319}320321Class<IllegalArgumentException> exceptionClass() {322return IllegalArgumentException.class;323}324}325326private static abstract class UnsupportedExceptionCase327extends ExceptionCase {328UnsupportedExceptionCase(String name) {329super(name);330}331332Class<UnsupportedOperationException> exceptionClass() {333return UnsupportedOperationException.class;334}335}336337/*338List of test cases. We will run through these once for339ImmutableDescriptor and once for DescriptorSupport.340341Expect a compiler [unchecked] warning for this initialization.342Writing343344new Case<Class<? extends Descriptor>, ?, ?>[] = {...}345346would cause a compiler error since you can't have arrays of347parameterized types unless all the parameters are just "?".348This hack with varargs gives us a compiler warning instead.349Writing just:350351new Case<?, ?, ?>[] = {...}352353would compile here, but not where we call test.run, since you354cannot pass an object to the run(P) method if P is "?".355*/356private static final Case<Class<? extends Descriptor>, ?, ?>357genericDescriptorTests[] = constantArray(358359// TEST VALUES RETURNED BY GETTERS360361new Case<Class<? extends Descriptor>, Descriptor, Object[]>(362"getFieldValues on empty Descriptor") {363Descriptor prepare(Class<? extends Descriptor> c)364throws Exception {365Constructor<? extends Descriptor> con =366c.getConstructor(String[].class);367return con.newInstance(new Object[] {new String[0]});368}369Object[] test(Descriptor d) {370return d.getFieldValues("foo", "bar");371}372String check(Object[] v) {373if (v.length == 2 && v[0] == null && v[1] == null)374return null;375return "value should be array with null elements: " +376Arrays.deepToString(v);377}378},379380new ValueProtoCase<Set<String>>("getFieldNames",381strings(testFieldNames)) {382Set<String> test(Descriptor d) {383return set(d.getFieldNames());384}385},386new ValueProtoCase<Set<String>>("getFields",387strings(testFieldStrings)) {388Set<String> test(Descriptor d) {389return set(d.getFields());390}391},392new ValueProtoCase<Object>("getFieldValue with exact case", "b") {393Object test(Descriptor d) {394return d.getFieldValue("a");395}396},397new ValueProtoCase<Object>("getFieldValue with lower case for upper",398"D") {399Object test(Descriptor d) {400return d.getFieldValue("c");401}402},403new ValueProtoCase<Object>("getFieldValue with upper case for lower",404"bb") {405Object test(Descriptor d) {406return d.getFieldValue("AA");407}408},409new ValueProtoCase<Object>("getFieldValue with mixed case for lower",410"bb") {411Object test(Descriptor d) {412return d.getFieldValue("aA");413}414},415new ValueProtoCase<Set<?>>("getFieldValues with null arg",416set(testFieldValues)) {417Set<?> test(Descriptor d) {418return set(d.getFieldValues((String[]) null));419}420},421new ValueProtoCase<Object[]>("getFieldValues with not all values",422new Object[] {"b", "D", 5}) {423Object[] test(Descriptor d) {424return d.getFieldValues("a", "c", "int");425}426},427new ValueProtoCase<Object[]>("getFieldValues with all values " +428"lower case",429new Object[]{"bb", "D", "b", 5}) {430Object[] test(Descriptor d) {431return d.getFieldValues("aa", "c", "a", "int");432}433},434new ValueProtoCase<Object[]>("getFieldValues with all values " +435"upper case",436new Object[] {5, "b", "D", "bb"}) {437Object[] test(Descriptor d) {438return d.getFieldValues("int", "A", "C", "AA");439}440},441new ValueProtoCase<Object[]>("getFieldValues with null name",442new Object[] {null}) {443Object[] test(Descriptor d) {444return d.getFieldValues((String) null);445}446},447new ValueProtoCase<Object[]>("getFieldValues with empty name",448new Object[] {null}) {449Object[] test(Descriptor d) {450return d.getFieldValues("");451}452},453new ValueProtoCase<Object[]>("getFieldValues with no names",454new Object[0]) {455Object[] test(Descriptor d) {456return d.getFieldValues();457}458},459460// TEST OPERATIONS THAT DON'T CHANGE THE DESCRIPTOR461// Even for immutable descriptors, these are allowed462463new UnchangedCase("removeField with nonexistent field") {464void dontChange(Descriptor d) {465d.removeField("noddy");466}467},468new UnchangedCase("removeField with null field") {469void dontChange(Descriptor d) {470d.removeField(null);471}472},473new UnchangedCase("removeField with empty field") {474void dontChange(Descriptor d) {475d.removeField("");476}477},478new UnchangedCase("setField leaving string unchanged") {479void dontChange(Descriptor d) {480d.setField("a", "b");481}482},483new UnchangedCase("setField leaving int unchanged") {484void dontChange(Descriptor d) {485d.setField("int", 5);486}487},488// We do not test whether you can do a setField/s with an489// unchanged value but the case of the name different.490// From the spec, that should probably be illegal, but491// it's such a corner case that we leave it alone.492493new UnchangedCase("setFields with empty arrays") {494void dontChange(Descriptor d) {495d.setFields(new String[0], new Object[0]);496}497},498new UnchangedCase("setFields with unchanged values") {499void dontChange(Descriptor d) {500d.setFields(new String[] {"a", "int"},501new Object[] {"b", 5});502}503},504505// TEST OPERATIONS THAT DO CHANGE THE DESCRIPTOR506// For immutable descriptors, these should provoke an exception507508new ChangedCase("removeField with exact case",509"a", "b", "C", "D", "int", 5, "nul", null) {510void change(Descriptor d) {511d.removeField("aa");512}513},514new ChangedCase("removeField with upper case for lower",515"a", "b", "C", "D", "int", 5, "nul", null) {516void change(Descriptor d) {517d.removeField("AA");518}519},520new ChangedCase("removeField with lower case for upper",521"a", "b", "aa", "bb", "int", 5, "nul", null) {522void change(Descriptor d) {523d.removeField("c");524}525},526new ChangedCase("setField keeping lower case",527"a", "x", "C", "D", "aa", "bb", "int", 5,528"nul", null) {529void change(Descriptor d) {530d.setField("a", "x");531}532},533534// spec says we should conserve the original case of the field name:535new ChangedCase("setField changing lower case to upper",536"a", "x", "C", "D", "aa", "bb", "int", 5,537"nul", null) {538void change(Descriptor d) {539d.setField("A", "x");540}541},542new ChangedCase("setField changing upper case to lower",543"a", "b", "C", "x", "aa", "bb", "int", 5,544"nul", null) {545void change(Descriptor d) {546d.setField("c", "x");547}548},549new ChangedCase("setField adding new field",550"a", "b", "C", "D", "aa", "bb", "int", 5, "xX", "yY",551"nul", null) {552void change(Descriptor d) {553d.setField("xX", "yY");554}555},556new ChangedCase("setField changing type of field",557"a", true, "C", "D", "aa", "bb", "int", 5,558"nul", null) {559void change(Descriptor d) {560d.setField("a", true);561}562},563new ChangedCase("setField changing non-null to null",564"a", null, "C", "D", "aa", "bb", "int", 5,565"nul", null) {566void change(Descriptor d) {567d.setField("a", null);568}569},570new ChangedCase("setField changing null to non-null",571"a", "b", "C", "D", "aa", "bb", "int", 5,572"nul", 3.14) {573void change(Descriptor d) {574d.setField("nul", 3.14);575}576},577578// TEST EXCEPTION BEHAVIOUR COMMON BETWEEN MUTABLE AND IMMUTABLE579580new IllegalExceptionCase("getFieldValue with null name") {581void provoke(Descriptor d) {582d.getFieldValue(null);583}584},585new IllegalExceptionCase("getFieldValue with empty name") {586void provoke(Descriptor d) {587d.getFieldValue("");588}589},590new IllegalExceptionCase("setField with null name") {591void provoke(Descriptor d) {592d.setField(null, "x");593}594},595new IllegalExceptionCase("setField with empty name") {596void provoke(Descriptor d) {597d.setField("", "x");598}599},600new IllegalExceptionCase("setFields with null fieldNames") {601void provoke(Descriptor d) {602d.setFields(null, new Object[] {"X"});603}604},605new IllegalExceptionCase("setFields with null fieldValues") {606void provoke(Descriptor d) {607d.setFields(new String[] {"X"}, null);608}609},610new IllegalExceptionCase("setFields with null fieldNames and " +611"fieldValues") {612void provoke(Descriptor d) {613d.setFields(null, null);614}615},616new IllegalExceptionCase("setFields with more fieldNames than " +617"fieldValues") {618void provoke(Descriptor d) {619d.setFields(new String[] {"A", "B"}, new String[] {"C"});620}621},622new IllegalExceptionCase("setFields with more fieldValues than " +623"fieldNames") {624void provoke(Descriptor d) {625d.setFields(new String[] {"A"}, new String[] {"B", "C"});626}627},628new IllegalExceptionCase("setFields with null element of fieldNames") {629void provoke(Descriptor d) {630d.setFields(new String[] {null}, new String[] {"X"});631}632}633634);635636static <T> T[] constantArray(T... array) {637return array;638}639640static String string(Object x) {641if (x instanceof Object[])642return Arrays.asList((Object[]) x).toString();643else644return String.valueOf(x);645}646647static Set<String> strings(String... values) {648return new TreeSet<String>(Arrays.asList(values));649}650651static <T> Set<T> set(T[] values) {652return new HashSet<T>(Arrays.asList(values));653}654655static boolean immutable(Descriptor d) {656return (d instanceof ImmutableDescriptor);657// good enough for our purposes658}659}660661662