1 /* 2 * Copyright (c) 2022, 2024, 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 * @summary Testing ClassFile AccessFlags. 27 * @run junit AccessFlagsTest 28 */ 29 import java.lang.classfile.ClassFile; 30 import java.lang.constant.ClassDesc; 31 import java.util.Arrays; 32 import java.util.EnumSet; 33 import java.util.Random; 34 import java.util.Set; 35 import java.util.function.Consumer; 36 import java.util.function.Function; 37 import java.util.function.IntFunction; 38 import java.lang.reflect.AccessFlag; 39 import java.lang.classfile.AccessFlags; 40 41 import static java.lang.classfile.ClassFile.ACC_STATIC; 42 import static java.lang.constant.ConstantDescs.CD_int; 43 import static java.lang.constant.ConstantDescs.MTD_void; 44 import static org.junit.jupiter.api.Assertions.*; 45 import org.junit.jupiter.api.Test; 46 import org.junit.jupiter.params.provider.EnumSource; 47 import org.junit.jupiter.params.ParameterizedTest; 48 49 class AccessFlagsTest { 50 51 @ParameterizedTest 52 @EnumSource(names = { "CLASS", "METHOD", "FIELD" }) 53 void testRandomAccessFlagsConverions(AccessFlag.Location ctx) { 54 IntFunction<AccessFlags> intFactory = switch (ctx) { 55 case CLASS -> v -> { 56 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb.withFlags(v)); 57 return ClassFile.of().parse(bytes).flags(); 58 }; 59 case METHOD -> v -> { 60 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> 61 clb.withMethod("test", MTD_void, v & ACC_STATIC, mb -> mb.withFlags(v))); 62 return ClassFile.of().parse(bytes).methods().getFirst().flags(); 63 }; 64 case FIELD -> v -> { 65 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> 66 clb.withField("test", CD_int, fb -> fb.withFlags(v))); 67 return ClassFile.of().parse(bytes).fields().getFirst().flags(); 68 }; 69 default -> null; 70 }; 71 Function<AccessFlag[], AccessFlags> flagsFactory = switch (ctx) { 72 case CLASS -> v -> { 73 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb.withFlags(v)); 74 return ClassFile.of().parse(bytes).flags(); 75 }; 76 case METHOD -> v -> { 77 boolean hasStatic = Arrays.stream(v).anyMatch(f -> f == AccessFlag.STATIC); 78 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> 79 clb.withMethod("test", MTD_void, hasStatic ? ACC_STATIC : 0, mb -> mb.withFlags(v))); 80 return ClassFile.of().parse(bytes).methods().getFirst().flags(); 81 }; 82 case FIELD -> v -> { 83 var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> 84 clb.withField("test", CD_int, fb -> fb.withFlags(v))); 85 return ClassFile.of().parse(bytes).fields().getFirst().flags(); 86 }; 87 default -> null; 88 }; 89 90 var allFlags = EnumSet.allOf(AccessFlag.class); 91 allFlags.removeIf(f -> !f.locations().contains(ctx)); 92 93 var r = new Random(123); 94 for (int i = 0; i < 1000; i++) { 95 var randomFlags = allFlags.stream().filter(f -> r.nextBoolean()).toArray(AccessFlag[]::new); 96 assertEquals(intFactory.apply(flagsFactory.apply(randomFlags).flagsMask()).flags(), Set.of(randomFlags)); 97 98 var randomMask = r.nextInt(Short.MAX_VALUE); 99 assertEquals(intFactory.apply(randomMask).flagsMask(), randomMask); 100 } 101 } 102 103 @Test 104 void testInvalidFlagsUse() { 105 ClassFile.of().build(ClassDesc.of("Test"), clb -> { 106 assertThrowsForInvalidFlagsUse(clb::withFlags); 107 clb.withMethod("test", MTD_void, ACC_STATIC, mb -> assertThrowsForInvalidFlagsUse(mb::withFlags)); 108 clb.withField("test", CD_int, fb -> assertThrowsForInvalidFlagsUse(fb::withFlags)); 109 }); 110 } 111 112 void assertThrowsForInvalidFlagsUse(Consumer<AccessFlag[]> factory) { 113 assertThrows(IllegalArgumentException.class, () -> factory.accept(AccessFlag.values())); 114 } 115 } --- EOF ---