diff --git a/make/devkit/Sysroot.gmk b/make/devkit/Sysroot.gmk index fd3d8c1b891..13395172074 100644 --- a/make/devkit/Sysroot.gmk +++ b/make/devkit/Sysroot.gmk @@ -109,7 +109,7 @@ endif EMPTY := SPACE := $(EMPTY) $(EMPTY) COMMA := , -DNF_ARCHS := $(subst $(SPACE),$(COMMA),$(RPM_ARCHS)) +DNF_ARCHS := $(foreach arch,$(RPM_ARCHS),--arch $(arch)) # Specify a dummy installation root, otherwise dnf will run into # problems trying to reconcile with the local/system state @@ -123,7 +123,7 @@ DNF_DOWNLOAD_FLAGS := \ --disablerepo='*' \ $(DNF_REPOS) \ --resolve \ - --archlist $(DNF_ARCHS) \ + $(DNF_ARCHS) \ --forcearch $(RPM_ARCH) \ --installroot $(DNF_DUMMY_INSTALL_ROOT) \ --releasever $(BASE_OS_VERSION) \ diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 9137723fa58..d00babef40f 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -243,6 +243,16 @@ static LPVOID virtualAllocExNuma(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSiz return result; } +void* os::win32::lookup_kernelbase_symbol(const char* name) { + // Pass a small ebuf so dll_load logs failures, but don't use it here to avoid redundancy. + char ebuf[1024]; + static void* const handle = os::dll_load("KernelBase", ebuf, sizeof(ebuf)); + if (handle == nullptr) { + return nullptr; + } + return os::dll_lookup(handle, name); +} + // Logging wrapper for MapViewOfFileEx static LPVOID mapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) { @@ -3250,9 +3260,9 @@ char* os::map_memory_to_file(char* base, size_t size, int fd) { assert(fd != -1, "File descriptor is not valid"); HANDLE fh = (HANDLE)_get_osfhandle(fd); - HANDLE fileMapping = CreateFileMapping(fh, nullptr, PAGE_READWRITE, + HANDLE file_mapping = CreateFileMapping(fh, nullptr, PAGE_READWRITE, (DWORD)(size >> 32), (DWORD)(size & 0xFFFFFFFF), nullptr); - if (fileMapping == nullptr) { + if (file_mapping == nullptr) { if (GetLastError() == ERROR_DISK_FULL) { vm_exit_during_initialization(err_msg("Could not allocate sufficient disk space for Java heap")); } @@ -3263,9 +3273,9 @@ char* os::map_memory_to_file(char* base, size_t size, int fd) { return nullptr; } - LPVOID addr = mapViewOfFileEx(fileMapping, FILE_MAP_WRITE, 0, 0, size, base); + LPVOID addr = mapViewOfFileEx(file_mapping, FILE_MAP_WRITE, 0, 0, size, base); - CloseHandle(fileMapping); + CloseHandle(file_mapping); return (char*)addr; } @@ -3278,40 +3288,75 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in return map_memory_to_file(base, size, fd); } +// VirtualAlloc2 / MapViewOfFile3 (Windows 1803+). Resolved in os::init_2() via lookup_kernelbase_symbol. +os::win32::VirtualAlloc2Fn os::win32::VirtualAlloc2 = nullptr; + +os::win32::MapViewOfFile3Fn os::win32::MapViewOfFile3 = nullptr; + +static bool is_VirtualAlloc2_supported() { + return os::win32::VirtualAlloc2 != nullptr; +} + +static bool is_MapViewOfFile3_supported() { + return os::win32::MapViewOfFile3 != nullptr; +} + // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { +static char* reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag) { assert(is_aligned(alignment, os::vm_allocation_granularity()), - "Alignment must be a multiple of allocation granularity (page size)"); + "Alignment must be a multiple of allocation granularity"); assert(is_aligned(size, os::vm_allocation_granularity()), - "Size must be a multiple of allocation granularity (page size)"); + "Size must be a multiple of allocation granularity"); size_t extra_size = size + alignment; assert(extra_size >= size, "overflow, size is too large to allow alignment"); char* aligned_base = nullptr; - static const int max_attempts = 20; + constexpr int max_attempts = 20; for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { - char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) : - os::reserve_memory(extra_size, mem_tag); + char* extra_base = os::reserve_memory(extra_size, mem_tag); if (extra_base == nullptr) { return nullptr; } - // Do manual alignment aligned_base = align_up(extra_base, alignment); + os::release_memory(extra_base, extra_size); - if (file_desc != -1) { - os::unmap_memory(extra_base, extra_size); - } else { - os::release_memory(extra_base, extra_size); + // A racing thread may have taken this region instead of us, which is why we loop and retry. + aligned_base = os::attempt_reserve_memory_at(aligned_base, size, mem_tag); + } + + assert(aligned_base != nullptr, + "Did not manage to reserve after %d attempts (size %zu, alignment %zu)", max_attempts, size, alignment); + + return aligned_base; +} + +// Similar to reserve_memory_aligned, other reservation/mapping requests can race with this function. +static char* map_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { + assert(is_aligned(alignment, os::vm_allocation_granularity()), + "Alignment must be a multiple of allocation granularity"); + assert(is_aligned(size, os::vm_allocation_granularity()), + "Size must be a multiple of allocation granularity"); + + size_t extra_size = size + alignment; + assert(extra_size >= size, "overflow, size is too large to allow alignment"); + + char* aligned_base = nullptr; + constexpr int max_attempts = 20; + + for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { + char* extra_base = os::map_memory_to_file(extra_size, file_desc, mem_tag); + if (extra_base == nullptr) { + return nullptr; } + aligned_base = align_up(extra_base, alignment); + os::unmap_memory(extra_base, extra_size); - // Attempt to map, into the just vacated space, the slightly smaller aligned area. - // Which may fail, hence the loop. - aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) : - os::attempt_reserve_memory_at(aligned_base, size, mem_tag); + // A racing thread may have taken this region instead of us, which is why we loop and retry. + aligned_base = os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag); } assert(aligned_base != nullptr, @@ -3320,6 +3365,84 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi return aligned_base; } +// MapViewOfFile3 supports alignment natively. +static char* map_memory_aligned_va2(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { + assert(file_desc != -1, "File descriptor should not be -1"); + assert(is_aligned(alignment, os::vm_allocation_granularity()), + "Alignment must be a multiple of allocation granularity"); + assert(is_aligned(size, os::vm_allocation_granularity()), + "Size must be a multiple of allocation granularity"); + + MEM_ADDRESS_REQUIREMENTS requirements = {0}; + requirements.Alignment = alignment; + + MEM_EXTENDED_PARAMETER param = {0}; + param.Type = MemExtendedParameterAddressRequirements; + param.Pointer = &requirements; + + char* aligned_base = nullptr; + + // File-backed aligned mapping. + HANDLE fh = (HANDLE)_get_osfhandle(file_desc); + HANDLE file_mapping = CreateFileMapping(fh, nullptr, PAGE_READWRITE,(DWORD)(size >> 32), (DWORD)(size & 0xFFFFFFFF), nullptr); + DWORD err = GetLastError(); + if (file_mapping != nullptr) { + aligned_base = (char*)os::win32::MapViewOfFile3( + file_mapping, + GetCurrentProcess(), + nullptr, // let the system choose an aligned address + 0, // offset + size, + 0, // no special allocation type flags + PAGE_READWRITE, + ¶m, 1); + err = GetLastError(); + CloseHandle(file_mapping); + } + + if (aligned_base != nullptr) { + assert(is_aligned(aligned_base, alignment), "Result must be aligned"); + MemTracker::record_virtual_memory_reserve_and_commit(aligned_base, size, CALLER_PC, mem_tag); + return aligned_base; + } + log_trace(os)("Aligned allocation via MapViewOfFile3 failed, falling back to retry loop. GetLastError->%lu.", err); + return map_memory_aligned(size, alignment, file_desc, mem_tag); +} + +// VirtualAlloc2 supports alignment natively. +static char* reserve_memory_aligned_va2(size_t size, size_t alignment, MemTag mem_tag) { + assert(is_aligned(alignment, os::vm_allocation_granularity()), + "Alignment must be a multiple of allocation granularity"); + assert(is_aligned(size, os::vm_allocation_granularity()), + "Size must be a multiple of allocation granularity"); + + MEM_ADDRESS_REQUIREMENTS requirements = {0}; + requirements.Alignment = alignment; + + MEM_EXTENDED_PARAMETER param = {0}; + param.Type = MemExtendedParameterAddressRequirements; + param.Pointer = &requirements; + + char* aligned_base = nullptr; + + // Anonymous aligned reservation. + aligned_base = (char*)os::win32::VirtualAlloc2( + GetCurrentProcess(), + nullptr, // let the system choose an aligned address + size, + MEM_RESERVE, + PAGE_READWRITE, + ¶m, 1); + + if (aligned_base != nullptr) { + assert(is_aligned(aligned_base, alignment), "Result must be aligned"); + MemTracker::record_virtual_memory_reserve(aligned_base, size, CALLER_PC, mem_tag); + return aligned_base; + } + log_trace(os)("Aligned allocation via VirtualAlloc2 failed, falling back to retry loop. GetLastError->%lu.", GetLastError()); + return reserve_memory_aligned(size, alignment, mem_tag); +} + size_t os::commit_memory_limit() { BOOL is_in_job_object = false; BOOL res = IsProcessInJob(GetCurrentProcess(), nullptr, &is_in_job_object); @@ -3367,11 +3490,17 @@ size_t os::reserve_memory_limit() { char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { // exec can be ignored - return map_or_reserve_memory_aligned(size, alignment, -1/* file_desc */, mem_tag); + if (is_VirtualAlloc2_supported()) { + return reserve_memory_aligned_va2(size, alignment, mem_tag); + } + return reserve_memory_aligned(size, alignment, mem_tag); } char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) { - return map_or_reserve_memory_aligned(size, alignment, fd, mem_tag); + if (is_MapViewOfFile3_supported()) { + return map_memory_aligned_va2(size, alignment, fd, mem_tag); + } + return map_memory_aligned(size, alignment, fd, mem_tag); } char* os::pd_reserve_memory(size_t bytes, bool exec) { @@ -4588,21 +4717,21 @@ jint os::init_2(void) { // Lookup SetThreadDescription - the docs state we must use runtime-linking of // kernelbase.dll, so that is what we do. - HINSTANCE _kernelbase = LoadLibrary(TEXT("kernelbase.dll")); - if (_kernelbase != nullptr) { - _SetThreadDescription = - reinterpret_cast( - GetProcAddress(_kernelbase, - "SetThreadDescription")); + _SetThreadDescription = reinterpret_cast( + os::win32::lookup_kernelbase_symbol("SetThreadDescription")); #ifdef ASSERT - _GetThreadDescription = - reinterpret_cast( - GetProcAddress(_kernelbase, - "GetThreadDescription")); + _GetThreadDescription = reinterpret_cast( + os::win32::lookup_kernelbase_symbol("GetThreadDescription")); #endif - } log_info(os, thread)("The SetThreadDescription API is%s available.", _SetThreadDescription == nullptr ? " not" : ""); + // Prepare KernelBase APIs (VirtualAlloc2, MapViewOfFile3) if available (Windows version 1803). + os::win32::VirtualAlloc2 = reinterpret_cast( + os::win32::lookup_kernelbase_symbol("VirtualAlloc2")); + os::win32::MapViewOfFile3 = reinterpret_cast( + os::win32::lookup_kernelbase_symbol("MapViewOfFile3")); + log_debug(os)("VirtualAlloc2 is%s available.", os::win32::VirtualAlloc2 == nullptr ? " not" : ""); + log_debug(os)("MapViewOfFile3 is%s available.", os::win32::MapViewOfFile3 == nullptr ? " not" : ""); return JNI_OK; } diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index d4a7d51c59b..5ebc80c817b 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -109,6 +109,19 @@ class os::win32 { // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); + // Resolve a symbol from KernelBase.dll, returns nullptr if not found. + static void* lookup_kernelbase_symbol(const char* name); + + // VirtualAlloc2 (since Windows version 1803) + // Resolved from KernelBase during os::init_2() or nullptr if unavailable. + typedef PVOID (WINAPI *VirtualAlloc2Fn)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); + static VirtualAlloc2Fn VirtualAlloc2; + + // MapViewOfFile3 (since Windows version 1803) + // Resolved from KernelBase during os::init_2() or nullptr if unavailable. + typedef PVOID (WINAPI *MapViewOfFile3Fn)(HANDLE, HANDLE, PVOID, ULONG64, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); + static MapViewOfFile3Fn MapViewOfFile3; + private: static void initialize_performance_counter(); diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp index 0f79e7a5a69..a0cfe2a9893 100644 --- a/src/hotspot/share/classfile/dictionary.cpp +++ b/src/hotspot/share/classfile/dictionary.cpp @@ -31,7 +31,10 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/concurrentHashTable.inline.hpp" +#include "utilities/concurrentHashTableTasks.inline.hpp" #include "utilities/ostream.hpp" #include "utilities/tableStatistics.hpp" @@ -239,10 +242,24 @@ void Dictionary::verify() { } void Dictionary::print_table_statistics(outputStream* st, const char* table_name) { - static TableStatistics ts; + TableStatistics stats; auto sz = [&] (InstanceKlass** val) { return sizeof(**val); }; - ts = _table->statistics_get(Thread::current(), sz, ts); - ts.print(st, table_name); + Thread* thread = Thread::current(); + ConcurrentTable::StatisticsTask sts(_table); + if (!sts.prepare(thread)) { + st->print_cr("Failed to take statistics"); + return; + } + TraceTime timer("GetStatistics", TRACETIME_LOG(Debug, perf)); + while (sts.do_task(thread, sz)) { + sts.pause(thread); + if (thread->is_Java_thread()) { + ThreadBlockInVM tbivm(JavaThread::cast(thread)); + } + sts.cont(thread); + } + stats = sts.done(thread); + stats.print(st, table_name); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index ad8cd220968..33d5fa6b04f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -66,7 +66,6 @@ class ShenandoahFreeSet; class ShenandoahConcurrentMark; class ShenandoahFullGC; class ShenandoahMonitoringSupport; -class ShenandoahPacer; class ShenandoahReferenceProcessor; class ShenandoahUncommitThread; class ShenandoahVerifier; @@ -534,7 +533,6 @@ private: ShenandoahCollectorPolicy* _shenandoah_policy; ShenandoahMode* _gc_mode; ShenandoahFreeSet* _free_set; - ShenandoahPacer* _pacer; ShenandoahVerifier* _verifier; ShenandoahPhaseTimings* _phase_timings; @@ -559,7 +557,6 @@ public: ShenandoahCollectorPolicy* shenandoah_policy() const { return _shenandoah_policy; } ShenandoahMode* mode() const { return _gc_mode; } ShenandoahFreeSet* free_set() const { return _free_set; } - ShenandoahPacer* pacer() const { return _pacer; } ShenandoahPhaseTimings* phase_timings() const { return _phase_timings; } diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 97ceb19d0ad..b720871c389 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -654,17 +654,20 @@ public: // VM.systemdictionary -verbose: for dumping the system dictionary table // class VM_DumpHashtable : public VM_Operation { +public: + enum DumpKind { + DumpSymbols, + DumpStrings, + DumpSysDict + }; + private: outputStream* _out; - int _which; + DumpKind _which; bool _verbose; + public: - enum { - DumpSymbols = 1 << 0, - DumpStrings = 1 << 1, - DumpSysDict = 1 << 2 // not implemented yet - }; - VM_DumpHashtable(outputStream* out, int which, bool verbose) { + VM_DumpHashtable(outputStream* out, DumpKind which, bool verbose) { _out = out; _which = which; _verbose = verbose; diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index d2317847307..dfba84ca519 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -534,11 +534,6 @@ class ConcurrentHashTable : public CHeapObj { template void bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f); - // Gets statistics if available, if not return old one. Item sizes are calculated with - // VALUE_SIZE_FUNC. - template - TableStatistics statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old); - // Moves all nodes from this table to to_cht with new hash code. // Must be done at a safepoint. void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index d5f6dee336b..312d118a647 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -1266,22 +1266,6 @@ inline TableStatistics ConcurrentHashTable:: } } -template -template -inline TableStatistics ConcurrentHashTable:: - statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old) -{ - if (!try_resize_lock(thread)) { - return old; - } - InternalTable* table = get_table(); - NumberSeq summary; - size_t literal_bytes = 0; - - internal_statistics_range(thread, 0, table->_size, vs_f, summary, literal_bytes); - return internal_statistics_epilog(thread, summary, literal_bytes); -} - template inline void ConcurrentHashTable:: rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht) diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index 3f320bbcc9b..29e58ea717c 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -84,9 +84,9 @@ import sun.util.locale.provider.LocaleProviderAdapter; * Note: these examples are from CLDR, there could be different results from other locale providers. *

* Alternatively, Locale, Type, and/or Style independent instances - * can be created with {@link #getInstance(String[])}. The String array to the - * method specifies the delimiting patterns for the start/middle/end portion of - * the formatted string, as well as optional specialized patterns for two or three + * can be created with {@link #getInstance(String[])}. The String array passed to the + * method specifies the delimiting patterns for the {@code start}/{@code middle}/{@code end} + * portion of the formatted string, as well as optional specialized patterns for two or three * elements. Refer to the method description for more detail. *

* On parsing, if some ambiguity is found in the input string, such as delimiting @@ -121,7 +121,8 @@ public final class ListFormat extends Format { /** * The array of five pattern Strings. Each element corresponds to the Unicode LDML's - * `listPatternsPart` type, i.e, start/middle/end/two/three. + * {@code listPatternPart} type, i.e, + * {@code start}/{@code middle}/{@code end}/{@code two}/{@code three}. * @serial */ private final String[] patterns; @@ -153,6 +154,7 @@ public final class ListFormat extends Format { var pattern = patterns[START]; var placeholderPositions = findPlaceholders(pattern); if (placeholderPositions != null && + placeholderPositions[2] == -1 && placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { startBefore = pattern.substring(0, placeholderPositions[0]); startBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, @@ -164,6 +166,7 @@ public final class ListFormat extends Format { pattern = patterns[MIDDLE]; placeholderPositions = findPlaceholders(pattern); if (placeholderPositions != null && + placeholderPositions[2] == -1 && placeholderPositions[0] == 0 && placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { middleBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, @@ -174,7 +177,9 @@ public final class ListFormat extends Format { pattern = patterns[END]; placeholderPositions = findPlaceholders(pattern); - if (placeholderPositions != null && placeholderPositions[0] == 0) { + if (placeholderPositions != null && + placeholderPositions[2] == -1 && + placeholderPositions[0] == 0) { endBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, placeholderPositions[1]); endAfter = pattern.substring(placeholderPositions[1] + PLACEHOLDER_LENGTH); @@ -185,7 +190,8 @@ public final class ListFormat extends Format { // Validate two/three patterns, if given. Otherwise, generate them pattern = patterns[TWO]; if (!pattern.isEmpty()) { - if (findPlaceholders(pattern) == null) { + placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions == null || placeholderPositions[2] >= 0) { throw new IllegalArgumentException("pattern for two is incorrect: " + pattern); } } else { @@ -245,36 +251,43 @@ public final class ListFormat extends Format { * instead of letting the runtime provide appropriate patterns for the {@code Locale}, * {@code Type}, or {@code Style}. *

- * The patterns array should contain five String patterns, each corresponding to the Unicode LDML's - * {@code listPatternPart}, i.e., "start", "middle", "end", two element, and three element patterns - * in this order. Each pattern contains "{0}" and "{1}" (and "{2}" for the three element pattern) - * placeholders that are substituted with the passed input strings on formatting. - * If the length of the patterns array is not 5, an {@code IllegalArgumentException} - * is thrown. + * The patterns array should contain five String patterns, each corresponding + * to the Unicode LDML's {@code listPatternPart}, i.e., {@code start}, + * {@code middle}, {@code end}, {@code two} element, and {@code three} + * element patterns in this order. Each pattern contains "{0}" and "{1}" + * (and "{2}" for the {@code three} element pattern) placeholders that are + * substituted with the passed input strings on formatting. If the length of + * the patterns array is not 5, an {@code IllegalArgumentException} is thrown. *

* Each pattern string is first parsed as follows. Literals in parentheses, such as * "start_before", are optional: - *

+     * {@snippet :
      * start := (start_before){0}start_between{1}
      * middle := {0}middle_between{1}
      * end := {0}end_between{1}(end_after)
      * two := (two_before){0}two_between{1}(two_after)
      * three := (three_before){0}three_between1{1}three_between2{2}(three_after)
-     * 
- * If two or three pattern string is empty, it falls back to - * {@code "(start_before){0}end_between{1}(end_after)"}, - * {@code "(start_before){0}start_between{1}end_between{2}(end_after)"} respectively. - * If parsing of any pattern string for start, middle, end, two, or three fails, + * } + * If the {@code two} or {@code three} pattern string is empty, it falls back to + * {@snippet : + * (start_before){0}end_between{1}(end_after) + * (start_before){0}start_between{1}end_between{2}(end_after) + * } + * respectively. + * If parsing of any pattern string for {@code start}, {@code middle}, + * {@code end}, {@code two}, or {@code three} fails, including duplicate + * placeholders, "{2}" in patterns other than the {@code three} element + * pattern, or any use of "{" or "}" other than "{0}", "{1}", or "{2}", * it throws an {@code IllegalArgumentException}. *

* On formatting, the input string list with {@code n} elements substitutes above * placeholders based on the number of elements: - *

+     * {@snippet :
      * n = 1: {0}
      * n = 2: parsed pattern for "two"
      * n = 3: parsed pattern for "three"
      * n > 3: (start_before){0}start_between{1}middle_between{2} ... middle_between{m}end_between{n}(end_after)
-     * 
+ * } * As an example, the following table shows a pattern array which is equivalent to * {@code STANDARD} type, {@code FULL} style in US English: * @@ -664,15 +677,37 @@ public final class ListFormat extends Format { /** * {@return the positions of the "{0}", "{1}", and "{2}" placeholders in the * given pattern string, or null if the pattern is invalid} + * Only "{0}", "{1}", or "{2}" placeholders are allowed. Any other use of + * curly braces is not allowed. * * The returned array contains -1 for "{2}" if that placeholder is absent. * * @param pattern pattern string to parse */ private static int[] findPlaceholders(String pattern) { - var positions = new int[3]; - for (int i = 0; i < positions.length; i++) { - positions[i] = pattern.indexOf("{" + i + "}"); + var positions = new int[] {-1, -1, -1}; + + for (int i = 0; i < pattern.length(); i++) { + var ch = pattern.charAt(i); + if (ch == '{') { + if (i + PLACEHOLDER_LENGTH > pattern.length() || + pattern.charAt(i + 1) < '0' || + pattern.charAt(i + 1) > '2' || + pattern.charAt(i + 2) != '}') { + return null; + } + + // Check for duplicate placeholders + var index = pattern.charAt(i + 1) - '0'; + if (positions[index] != -1) { + return null; + } + + positions[index] = i; + i += PLACEHOLDER_LENGTH - 1; + } else if (ch == '}') { + return null; + } } // Check the existence and order of the placeholders diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 137cac45ed0..f39d92aeeb4 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -418,19 +418,15 @@ public abstract class ForkJoinTask implements Future, Serializable { for (;;) { if ((s = status) < 0) break; - else if (interrupts < 0) { - s = ABNORMAL; // interrupted and not done - break; - } else if (Thread.interrupted()) { - if (!ForkJoinPool.poolIsStopping(pool)) - interrupts = interruptible ? -1 : 1; - else { - interrupts = 1; // re-assert if cleared + if (ForkJoinPool.poolIsStopping(pool)) { try { cancel(true); - } catch (Throwable ignore) { - } + } catch (Throwable ignore) { } + } + if ((interrupts = interruptible ? -1 : 1) < 0) { + s = ABNORMAL; + break; } } else if (deadline != 0L) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java index 6121a0c1673..c4573317785 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -351,4 +351,9 @@ class Http2ClientImpl { public boolean stopping() { return stopping; } + + // getConnections() is used only by tests. + Map getConnections() { + return connections; + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 94b8505da47..11022ca5c96 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -52,7 +52,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.function.Supplier; @@ -1610,16 +1609,37 @@ class Http2Connection implements Closeable { return frames; } - // Dedicated cache for headers encoding ByteBuffer. + // Dedicated reusable ByteBuffer for headers encoding. // There can be no concurrent access to this buffer as all access to this buffer // and its content happen within a single critical code block section protected - // by the sendLock. / (see sendFrame()) - // private final ByteBufferPool headerEncodingPool = new ByteBufferPool(); + // by the sendlock (see sendFrame()). + private ByteBuffer cachedHeaderBuffer; + + // getCachedHeaderBuffer() is used only by tests and it should not be + // called in source code without also holding `sendlock`. + ByteBuffer getCachedHeaderBuffer() { + return cachedHeaderBuffer; + } private ByteBuffer getHeaderBuffer(int size) { - ByteBuffer buf = ByteBuffer.allocate(size); - buf.limit(size); - return buf; + assert sendlock.isHeldByCurrentThread() : "current thread is not holding sendlock"; + + if (cachedHeaderBuffer == null || cachedHeaderBuffer.capacity() < size) { + cachedHeaderBuffer = ByteBuffer.allocate(size); + return cachedHeaderBuffer; + } + + cachedHeaderBuffer.clear(); + cachedHeaderBuffer.limit(size); + return cachedHeaderBuffer; + } + + private static ByteBuffer copyBuffer(ByteBuffer buffer) { + buffer.flip(); + ByteBuffer copy = ByteBuffer.allocate(buffer.remaining()); + copy.put(buffer); + copy.flip(); + return copy; } /* @@ -1634,8 +1654,8 @@ class Http2Connection implements Closeable { * encoding in HTTP/2... */ private List encodeHeadersImpl(int bufferSize, HttpHeaders... headers) { - ByteBuffer buffer = getHeaderBuffer(bufferSize); List buffers = new ArrayList<>(); + ByteBuffer buffer = getHeaderBuffer(bufferSize); for (HttpHeaders header : headers) { for (Map.Entry> e : header.map().entrySet()) { String lKey = e.getKey().toLowerCase(Locale.US); @@ -1644,16 +1664,17 @@ class Http2Connection implements Closeable { hpackOut.header(lKey, value); while (!hpackOut.encode(buffer)) { if (!buffer.hasRemaining()) { - buffer.flip(); - buffers.add(buffer); - buffer = getHeaderBuffer(bufferSize); + ByteBuffer copy = copyBuffer(buffer); + buffers.add(copy); + buffer.clear(); + buffer.limit(bufferSize); } } } } } - buffer.flip(); - buffers.add(buffer); + ByteBuffer copy = copyBuffer(buffer); + buffers.add(copy); return buffers; } @@ -1710,7 +1731,7 @@ class Http2Connection implements Closeable { } } - private final Lock sendlock = new ReentrantLock(); + private final ReentrantLock sendlock = new ReentrantLock(); void sendFrame(Http2Frame frame) { try { diff --git a/src/jdk.attach/share/classes/com/sun/tools/attach/spi/AttachProvider.java b/src/jdk.attach/share/classes/com/sun/tools/attach/spi/AttachProvider.java index 6446473d9d6..362368cb2c5 100644 --- a/src/jdk.attach/share/classes/com/sun/tools/attach/spi/AttachProvider.java +++ b/src/jdk.attach/share/classes/com/sun/tools/attach/spi/AttachProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -58,8 +58,8 @@ import java.util.ServiceLoader; * for example, ships with attach providers that use the package name "sun" * (for historical reasons). The * type typically corresponds to the attach mechanism. For example, an - * implementation that uses the Doors inter-process communication mechanism - * might use the type "doors". The purpose of the name and type is to + * implementation that uses the UNIX Domain Socket inter-process communication mechanism + * might use the type "socket". The purpose of the name and type is to * identify providers in environments where there are multiple providers * installed. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index 15f55d18cc0..c1c4dd512d6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -137,6 +137,26 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite .title(title))); } + /** + * Returns a label for the given element to be used the table of contents sidebar. + * + * @param executableElement method or constructor + * @return the link label + */ + protected Content getTOCLabel(ExecutableElement executableElement) { + var signature = utils.makeSignature(executableElement, typeElement, false, true); + var label = new ContentBuilder(Text.of(utils.getSimpleName(executableElement))); + // Insert line break opportunity before first parameter. + if (signature.length() > 2) { + label.add(Text.of(signature.substring(0, 1))) + .add(HtmlTree.WBR()) + .add(Text.of(signature.substring(1))); + } else { + label.add(signature); + } + return label; + } + /** * Adds the generic type parameters. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index d8d01a4e6ad..48e269445ae 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -119,9 +119,7 @@ public class ConstructorWriter extends AbstractExecutableMemberWriter { constructorContent.add(div); memberList.add(getMemberListItem(constructorContent)); writer.tableOfContents.addLink(htmlIds.forMember(currentConstructor).getFirst(), - Text.of(utils.getSimpleName(constructor) - + utils.makeSignature(currentConstructor, typeElement, false, true)), - TableOfContents.Level.SECOND); + getTOCLabel(currentConstructor), TableOfContents.Level.SECOND); } Content constructorDetails = getConstructorDetails(constructorDetailsHeader, memberList); target.add(constructorDetails); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java index 3bc5b7617b0..5edfd9e174d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java @@ -118,9 +118,7 @@ public class MethodWriter extends AbstractExecutableMemberWriter { methodContent.add(div); memberList.add(writer.getMemberListItem(methodContent)); writer.tableOfContents.addLink(htmlIds.forMember(currentMethod).getFirst(), - Text.of(utils.getSimpleName(method) - + utils.makeSignature(currentMethod, typeElement, false, true)), - TableOfContents.Level.SECOND); + getTOCLabel(currentMethod), TableOfContents.Level.SECOND); } Content methodDetails = getMethodDetails(methodDetailsHeader, memberList); detailsList.add(methodDetails); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index fc0fa68f029..12b441727c6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -82,6 +82,8 @@ /* Search input colors */ --search-input-background-color: #ffffff; --search-input-text-color: #000000; + --search-border-light-color: #eaeaea; + --search-border-dark-color: #a6a6a6; --search-input-placeholder-color: #757575; --overlay-background: rgba(153, 169, 183, 0.3); /* Highlight color for active search tag target */ @@ -107,23 +109,23 @@ :root[data-theme="theme-dark"] { --body-text-color: #e8e8e8; --block-text-color: #e8e8e8; - --body-background-color: #1f2124; + --body-background-color: #202226; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); --code-background-color: #303940; --mark-background-color: #313131; --detail-block-color: #31363c; - --navbar-background-color: #395A6F; + --navbar-background-color: #406074; --navbar-text-color: #ffffff; - --subnav-background-color: #3d454d; + --subnav-background-color: #434c54; --subnav-link-color: #d8dcdf; --member-heading-background-color: var(--subnav-background-color); --selected-background-color: #f8981d; --selected-text-color: #253441; --selected-link-color: #4a698a; --table-header-color: #38444d; - --even-row-color: #222528; - --odd-row-color: #2d3135; + --even-row-color: #282c2f; + --odd-row-color: #33383b; --title-color: #fff; --link-color: #94badb; --link-color-active: #e8a351; @@ -138,8 +140,10 @@ --border-color: #444444; --table-border-color: #717171; --tab-border-radius: 2px 2px 0 0; - --search-input-background-color: #303030; + --search-input-background-color: #202224; --search-input-text-color: #d0d0d0; + --search-border-light-color: #505050; + --search-border-dark-color: #000000; --search-input-placeholder-color: #979797; --overlay-background: rgba(0, 0, 0, 0.45); --search-tag-background-color: #c6c61e; @@ -192,7 +196,7 @@ body { width:100%; } main [id] { - scroll-margin-top: calc(var(--nav-height) + 6px); + scroll-margin-top: calc(var(--nav-height) + 14px); } div.main-grid { max-width: var(--max-content-width); @@ -246,6 +250,9 @@ h1, h2, h3, h4, h5, h6, div.member-signature, div.member-signature > span { ul { list-style-type:disc; } +main li { + margin-top: 4px; +} tt { font-family:var(--code-font-family); } @@ -486,12 +493,7 @@ body.class-declaration-page .details h3 { } body.class-declaration-page section.detail:target > h3, body.class-declaration-page section.detail > h3:target { - background-color: var(--navbar-background-color); - color: var(--navbar-text-color); -} -body.class-declaration-page section.detail:target > h3 > a.anchor-link > img, -body.class-declaration-page section.detail > h3:target > a.anchor-link > img { - filter: invert(100%) brightness(160%); + box-shadow: -4px 0 0 rgb(from var(--link-color) r g b / 0.7); } h1 > sup { font-size: small; @@ -522,6 +524,9 @@ section.class-description > div.horizontal-scroll > :is(dl, ol, ul, p, div, bloc section.class-description > div.horizontal-scroll > :last-child > :is(li, dd):last-child { margin-bottom:4px; } +dl.notes { + margin-top: 14.2px; +} dl.notes > dt { font-family: var(--body-font-family); font-size:0.856em; @@ -661,9 +666,12 @@ a.current-selection { } nav.toc a { display: block; - padding: 8px; + padding: 7px 8px; overflow: hidden; text-overflow: ellipsis; + text-wrap: balance; + text-indent: 0.5em hanging; + line-height: 1.35; } nav.toc ol.toc-list ol.toc-list a { padding-left: 24px; @@ -737,11 +745,13 @@ ul.tag-list li { display: inline; } ul.tag-list li:not(:last-child):after, -ul.tag-list-long li:not(:last-child):after -{ +ul.tag-list-long li:not(:last-child):after { content: ", "; white-space: pre-wrap; } +ul.tag-list-long > li { + margin-top: 1px; +} ul.preview-feature-list { list-style: none; margin:0; @@ -940,6 +950,9 @@ div.checkboxes > label > input { .col-first, .col-second, .col-constructor-name { overflow: auto; } +.col-constructor-name, .method-summary .col-second { + text-indent: 0.5em hanging; +} body:not(.class-declaration-page) .col-first a:link, .col-summary-item-name a:link { font-weight:bold; @@ -957,6 +970,12 @@ div.block { font-size:var(--block-font-size); font-family:var(--block-font-family); line-height:var(--block-line-height); + display: block; + margin:0 10px 5px 0; + color:var(--block-text-color); +} +section.detail div.block { + margin-bottom: 14.4px; } .module-signature, .package-signature, @@ -1006,11 +1025,6 @@ div.block { color:var(--source-linenumber-color, green); padding:0 30px 0 0; } -.block { - display:block; - margin:0 10px 5px 0; - color:var(--block-text-color); -} .deprecated-label, .description-from-type-label, .implementation-label, .member-name-link, .package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label, .restricted-label { @@ -1075,15 +1089,16 @@ input[type="text"] { background-image:var(--glass-svg); background-size:13px; background-repeat:no-repeat; - background-position:3px 4px; + background-position:3px 5px; background-color: var(--search-input-background-color); color: var(--search-input-text-color); - border-color: var(--border-color); + border-style:solid; + border-color: var(--search-border-dark-color) var(--search-border-light-color) var(--search-border-light-color) var(--search-border-dark-color); border-radius: 4px; padding-left:20px; padding-right: 18px; font-size: var(--nav-font-size); - height: 19px; + height: 20px; } input#page-search-input { width: calc(180px + 10vw); @@ -1585,8 +1600,7 @@ button.snippet-copy span { table.borderless, table.plain, table.striped { - margin-top: 10px; - margin-bottom: 10px; + margin: 14px 0; } table.borderless > caption, table.plain > caption, @@ -1780,6 +1794,9 @@ table.striped > tbody > tr > th { main { padding: 10px 12px; } + main [id] { + scroll-margin-top: calc(var(--nav-height) + 10px); + } body { -webkit-text-size-adjust: none; } diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index c6fa1e568fd..c3c980858b4 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -1277,16 +1277,22 @@ TEST_VM(os, map_unmap_memory) { TEST_VM(os, map_memory_to_file_aligned) { const char* letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const size_t size = strlen(letters) + 1; + const size_t content_size = strlen(letters) + 1; + const size_t granularity = os::vm_allocation_granularity(); + const size_t alignments[] = { granularity, 2 * granularity, 4 * granularity, 16 * granularity, 1 * M }; int fd = os::open("map_memory_to_file.txt", O_RDWR | O_CREAT, 0666); EXPECT_TRUE(fd > 0); - EXPECT_TRUE(os::write(fd, letters, size)); + ASSERT_TRUE(os::write(fd, letters, content_size)); - char* result = os::map_memory_to_file_aligned(os::vm_allocation_granularity(), os::vm_allocation_granularity(), fd, mtTest); - ASSERT_NOT_NULL(result); - EXPECT_EQ(strcmp(letters, result), 0); - os::unmap_memory(result, os::vm_allocation_granularity()); + const size_t size = granularity; + for (size_t alignment : alignments) { + char* result = os::map_memory_to_file_aligned(size, alignment, fd, mtTest); + ASSERT_NOT_NULL(result) << "Mapping failed for alignment=" << alignment; + EXPECT_TRUE(is_aligned(result, alignment)) << "Failed to aligned to " << alignment; + EXPECT_EQ(strcmp(letters, result), 0) << "Text mismatch at alignment=" << alignment; + os::unmap_memory(result, size); + } ::close(fd); } @@ -1297,3 +1303,36 @@ TEST_VM(os, dll_load_null_error_buf) { void* lib = os::dll_load("NoSuchLib", nullptr, 0); ASSERT_NULL(lib); } + +TEST_VM(os, reserve_memory_aligned_basic) { + const size_t granularity = os::vm_allocation_granularity(); + const size_t alignments[] = { granularity, 2 * granularity, 4 * granularity, 16 * granularity }; + + for (size_t alignment : alignments) { + const size_t size = alignment; + char* result = os::reserve_memory_aligned(size, alignment, mtTest); + ASSERT_NE(result, (char*)nullptr) << "reserve_memory_aligned failed for alignment=" << alignment; + EXPECT_TRUE(is_aligned(result, alignment)) << "Result " << result << " not aligned to " << alignment; + + ASSERT_TRUE(os::commit_memory(result, size, false)); + memset(result, 0xCD, size); + EXPECT_EQ((unsigned char)result[0], 0xCD); + + os::release_memory(result, size); + } +} + +TEST_VM(os, reserve_memory_aligned_large) { + const size_t alignment = 1 * M; + const size_t size = alignment; + + char* result = os::reserve_memory_aligned(size, alignment, mtTest); + ASSERT_NE(result, (char*)nullptr); + EXPECT_TRUE(is_aligned(result, alignment)); + + ASSERT_TRUE(os::commit_memory(result, size, false)); + memset(result, 0xEF, size); + EXPECT_EQ((unsigned char)result[size - 1], 0xEF); + + os::release_memory(result, size); +} diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 422e6ddd060..d41f1e3818d 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -103,7 +103,6 @@ runtime/os/TestTracePageSizes.java#compiler-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 -runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/NMT/VirtualAllocCommitMerge.java 8309698 linux-s390x runtime/Thread/TestAlwaysPreTouchStacks.java 8383372 macosx-aarch64 @@ -139,6 +138,8 @@ serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 +serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java 8385679 generic-all + ############################################################################# # :hotspot_misc diff --git a/test/hotspot/jtreg/compiler/profiling/TestPrintMethodData.java b/test/hotspot/jtreg/compiler/profiling/TestPrintMethodData.java index 9e14cd6ea4b..7cc5cda88b6 100644 --- a/test/hotspot/jtreg/compiler/profiling/TestPrintMethodData.java +++ b/test/hotspot/jtreg/compiler/profiling/TestPrintMethodData.java @@ -64,7 +64,7 @@ public class TestPrintMethodData { private static final Generator GEN_LONG = Generators.G.longs(); private static final int SIZE = 1024; - static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { long[] longs = new long[SIZE]; Generators.G.fill(GEN_LONG, longs); diff --git a/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c b/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c index abef2ea050a..4608627688c 100644 --- a/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c +++ b/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c @@ -56,17 +56,13 @@ static jmp_buf context; static volatile int _last_si_code = -1; static volatile int _failures = 0; static volatile int _rec_count = 0; // Number of allocations to hit stack guard page -static volatile int _kp_rec_count = 0; // Kept record of rec_count, for retrying +static volatile int _previous_rec_count = 0; // Kept record of rec_count, for retrying static int _peek_value = 0; // Used for accessing memory to cause SIGSEGV -pid_t gettid() { - return (pid_t) syscall(SYS_gettid); -} - static void handler(int sig, siginfo_t *si, void *unused) { _last_si_code = si->si_code; printf("Got SIGSEGV(%d) at address: 0x%lx\n",si->si_code, (long) si->si_addr); - longjmp(context, 1); + siglongjmp(context, 1); } static char* altstack = NULL; @@ -159,8 +155,16 @@ void *run_java_overflow (void *p) { void do_overflow(){ volatile int *p = NULL; - if (_kp_rec_count == 0 || _rec_count < _kp_rec_count) { - for(;;) { + if (_previous_rec_count == 0) { + // We need to find the appropriate depth to probe into + for (;;) { + _rec_count++; + p = (int*)alloca(128); + _peek_value = p[0]; // Peek + } + } else { + while (_rec_count < _previous_rec_count) { + // This is our second round, we can do exactly 1 less allocation _rec_count++; p = (int*)alloca(128); _peek_value = p[0]; // Peek @@ -168,19 +172,19 @@ void do_overflow(){ } } -void *run_native_overflow(void *p) { +void *run_native_overflow(void *is_other_thread) { // Test that stack guard page is correctly set for initial and non initial thread // and correctly removed for the initial thread volatile int res; - printf("run_native_overflow %ld\n", (long) gettid()); + printf("run_native_overflow, %s", *(int *)is_other_thread ? "in other thread\n" : "in initial thread\n"); call_method_on_jvm("printAlive"); // Initialize statics used in do_overflow - _kp_rec_count = 0; + _previous_rec_count = 0; _rec_count = 0; set_signal_handler(); - if (! setjmp(context)) { + if (! sigsetjmp(context, 1)) { do_overflow(); } @@ -194,7 +198,7 @@ void *run_native_overflow(void *p) { exit(7); } - if (getpid() != gettid()) { + if (*(int *)is_other_thread == 1) { // For non-initial thread we don't unmap the region but call os::uncommit_memory and keep PROT_NONE // so if host has enough swap space we will get the same SEGV with code SEGV_ACCERR(2) trying // to access it as if the guard page is present. @@ -204,11 +208,11 @@ void *run_native_overflow(void *p) { } // Limit depth of recursion for second run. It can't exceed one for first run. - _kp_rec_count = _rec_count; + _previous_rec_count = _rec_count; _rec_count = 0; set_signal_handler(); - if (! setjmp(context)) { + if (!sigsetjmp(context, 1)) { do_overflow(); } @@ -314,8 +318,8 @@ int main (int argc, const char** argv) { if (strcmp(argv[1], "test_native_overflow_initial") == 0) { printf("\nTesting NATIVE_OVERFLOW\n"); printf("Testing stack guard page behaviour for initial thread\n"); - - run_native_overflow(NULL); + int is_other_thread = 0; + run_native_overflow(&is_other_thread); exit((_failures > 0) ? 1 : 0); } @@ -324,11 +328,11 @@ int main (int argc, const char** argv) { init_thread_or_die(&thr, &thread_attr); printf("\nTesting NATIVE_OVERFLOW\n"); printf("Testing stack guard page behaviour for other thread\n"); - - pthread_create(&thr, &thread_attr, run_native_overflow, NULL); + int is_other_thread = 1; + pthread_create(&thr, &thread_attr, run_native_overflow, &is_other_thread); pthread_join(thr, NULL); - - exit((_failures > 0) ? 1 : 0); + // Other-thread test cannot increase _failure count + exit(0); } fprintf(stderr, "Test ERROR. Unknown parameter %s\n", ((argc > 1) ? argv[1] : "none")); diff --git a/test/jdk/java/lang/Thread/virtual/KlassInit.java b/test/jdk/java/lang/Thread/virtual/KlassInit.java index 4f11d667a2b..067d4c5a7f4 100644 --- a/test/jdk/java/lang/Thread/virtual/KlassInit.java +++ b/test/jdk/java/lang/Thread/virtual/KlassInit.java @@ -79,7 +79,10 @@ import java.util.concurrent.CountDownLatch; import java.util.stream.Stream; import java.util.stream.Collectors; +import jdk.test.lib.thread.VThreadRunner; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.Arguments; @@ -96,6 +99,12 @@ class KlassInit { private static final CountDownLatch finishPutStatic = new CountDownLatch(1); private static final CountDownLatch finishFailedInit = new CountDownLatch(1); + @BeforeAll + static void setup() { + // need >=2 carriers for testing pinning + VThreadRunner.ensureParallelism(2); + } + /** * Test that threads blocked waiting for klass to be initialized * on invokestatic bytecode release the carrier. diff --git a/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientImplAccess.java b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientImplAccess.java index 875ac5426dd..ce57f654e93 100644 --- a/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientImplAccess.java +++ b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientImplAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -26,6 +26,9 @@ import java.lang.reflect.Field; import java.net.http.HttpClient; import java.util.Objects; import java.util.Set; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; public final class HttpClientImplAccess { @@ -64,4 +67,29 @@ public final class HttpClientImplAccess { openedConnections.setAccessible(true); return (Set) openedConnections.get(clientImpl); } + + /** + * Returns all connections in the client's HTTP/2 pool. + */ + public static Collection getHttp2Connections(final HttpClient client) { + Objects.requireNonNull(client, "client"); + final HttpClientImpl clientImpl = impl(client); + if (clientImpl == null) { + throw new IllegalStateException("Unsupported HttpClient implementation"); + } + Http2ClientImpl client2 = clientImpl.client2(); + Map connections = client2.getConnections(); + return connections.values(); + } + + /** + * Returns the cached header encoding buffer for the given Http2Connection. + */ + public static ByteBuffer getCachedHeaderBuffer(final Object conn) { + // The argument to this method is of type Object and not + // Http2Connection because callers outside the module cannot reference + // the package-private Http2Connection class. + Objects.requireNonNull(conn, "conn"); + return ((Http2Connection) conn).getCachedHeaderBuffer(); + } } diff --git a/test/jdk/java/net/httpclient/http2/HeaderEncodingBufferReuseTest.java b/test/jdk/java/net/httpclient/http2/HeaderEncodingBufferReuseTest.java new file mode 100644 index 00000000000..26fb06ec47d --- /dev/null +++ b/test/jdk/java/net/httpclient/http2/HeaderEncodingBufferReuseTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2026, 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. + */ + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.ByteBuffer; +import java.util.Collection; +import javax.net.ssl.SSLContext; +import static java.net.http.HttpClient.Version.HTTP_2; + +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.internal.net.http.HttpClientImplAccess; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.net.SimpleSSLContext; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/* + * @test + * @bug 8383248 + * @summary Verifies that Http2Connection.cachedHeaderBuffer is reused + * across multiple requests on the same connection. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * /test/jdk/java/net/httpclient/access + * @build java.net.http/jdk.internal.net.http.HttpClientImplAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit/othervm + * ${test.main.class} + */ + +public class HeaderEncodingBufferReuseTest implements HttpServerAdapters { + + static String httpUri; + static SSLContext sslContext; + static HttpTestServer testServer; + + @BeforeAll + static void init() throws Exception { + sslContext = SimpleSSLContext.findSSLContext(); + testServer = HttpTestServer.create(HTTP_2, sslContext); + testServer.addHandler(new OkHandler(), "/test"); + testServer.start(); + httpUri = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(testServer.getAddress().getPort()) + .path("/test") + .build() + .toString(); + } + + @AfterAll + static void teardown() { + testServer.stop(); + } + + @Test + void test() throws Exception { + try (HttpClient client = HttpClient.newBuilder() + .proxy(HttpClient.Builder.NO_PROXY) + .version(HttpClient.Version.HTTP_2) + .sslContext(sslContext) + .build()) { + + // Send an initial request to allocate the header encoding buffer. + assertEquals(200, send(client, httpUri, 2).statusCode()); + + Collection connections = HttpClientImplAccess.getHttp2Connections(client); + assertEquals(1, connections.size()); + Object conn = connections.iterator().next(); + + ByteBuffer cached = HttpClientImplAccess.getCachedHeaderBuffer(conn); + assertNotNull(cached); + + // Send another request and verify the same buffer is reused. + assertEquals(200, send(client, httpUri, 2).statusCode()); + connections = HttpClientImplAccess.getHttp2Connections(client); + assertEquals(1, connections.size()); + assertSame(conn, connections.iterator().next()); + assertSame(cached, HttpClientImplAccess.getCachedHeaderBuffer(conn)); + + // Verify that the buffer is reused when headers span multiple frames. + assertEquals(200, send(client, httpUri, 300).statusCode()); + connections = HttpClientImplAccess.getHttp2Connections(client); + assertEquals(1, connections.size()); + assertSame(conn, connections.iterator().next()); + assertSame(cached, HttpClientImplAccess.getCachedHeaderBuffer(conn)); + } + } + + static HttpResponse send(HttpClient client, String uri, int headerCount) throws Exception { + HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(uri)) + .POST(BodyPublishers.ofString("test")); + for (int i = 0; i < headerCount; i++) { + builder.header("X-Header-" + i, "value-" + "x".repeat(50) + "-" + i); + } + return client.send(builder.build(), BodyHandlers.discarding()); + } + + static class OkHandler implements HttpTestHandler { + @Override + public void handle(HttpTestExchange exchange) throws IOException { + exchange.sendResponseHeaders(200, 0); + exchange.getResponseBody().close(); + } + } +} diff --git a/test/jdk/java/text/Format/ListFormat/TestListFormat.java b/test/jdk/java/text/Format/ListFormat/TestListFormat.java index 1500a1b0818..68da9ce5fda 100644 --- a/test/jdk/java/text/Format/ListFormat/TestListFormat.java +++ b/test/jdk/java/text/Format/ListFormat/TestListFormat.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8041488 8316974 8318569 8306116 8385736 + * @bug 8041488 8316974 8318569 8306116 8385736 8385834 * @summary Tests for ListFormat class * @run junit TestListFormat */ @@ -210,6 +210,10 @@ public class TestListFormat { arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE2), arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE3), arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE4), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE1), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE2), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE3), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE4), }; } @@ -237,13 +241,37 @@ public class TestListFormat { }; } - private static Arguments[] getInstance_1Arg_InvalidLongPattern() { + private static final String ZERO_REPEAT = "{0}".repeat(100_000); + private static Arguments[] getInstance_1Arg_InvalidPlaceholder() { return new Arguments[] { - arguments(0, "start pattern is incorrect:"), - arguments(1, "middle pattern is incorrect:"), - arguments(2, "end pattern is incorrect:"), - arguments(3, "pattern for two is incorrect:"), - arguments(4, "pattern for three is incorrect:"), + // Duplicate placeholders + arguments(0, "{0} {0} {1}", "start pattern is incorrect: {0} {0} {1}"), + arguments(0, "{0} {1} {1}", "start pattern is incorrect: {0} {1} {1}"), + arguments(0, "{0} {1} {2}", "start pattern is incorrect: {0} {1} {2}"), + arguments(1, "{0} {0} {1}", "middle pattern is incorrect: {0} {0} {1}"), + arguments(1, "{0} {1} {1}", "middle pattern is incorrect: {0} {1} {1}"), + arguments(1, "{0} {1} {2}", "middle pattern is incorrect: {0} {1} {2}"), + arguments(2, "{0} {0} {1}", "end pattern is incorrect: {0} {0} {1}"), + arguments(2, "{0} {1} {1}", "end pattern is incorrect: {0} {1} {1}"), + arguments(2, "{0} {1} {2}", "end pattern is incorrect: {0} {1} {2}"), + arguments(3, "{0} {0} {1}", "pattern for two is incorrect: {0} {0} {1}"), + arguments(3, "{0} {1} {1}", "pattern for two is incorrect: {0} {1} {1}"), + arguments(3, "{0} {1} {2}", "pattern for two is incorrect: {0} {1} {2}"), + arguments(4, "{0} {2} {1}", "pattern for three is incorrect: {0} {2} {1}"), + arguments(4, "{0} {0} {1} {2}", "pattern for three is incorrect: {0} {0} {1} {2}"), + arguments(4, "{0} {1} {1} {2}", "pattern for three is incorrect: {0} {1} {1} {2}"), + arguments(4, "{0} {1} {2} {2}", "pattern for three is incorrect: {0} {1} {2} {2}"), + arguments(4, ZERO_REPEAT + " {1} {2}", "pattern for three is incorrect: " + ZERO_REPEAT + " {1} {2}"), + + // invalid placeholders + arguments(0, "{0} {1} {", "start pattern is incorrect: {0} {1} {"), + arguments(0, "{0} {1} }", "start pattern is incorrect: {0} {1} }"), + arguments(3, "{0} {1} {3}", "pattern for two is incorrect: {0} {1} {3}"), + arguments(4, "{3} {0} {1}", "pattern for three is incorrect: {3} {0} {1}"), + arguments(4, "{333} {0} {1}", "pattern for three is incorrect: {333} {0} {1}"), + arguments(4, "{0} {1} {abc}", "pattern for three is incorrect: {0} {1} {abc}"), + arguments(4, "{0} {1} {2, number}", "pattern for three is incorrect: {0} {1} {2, number}"), + arguments(4, "{0} {1} {2} {3}", "pattern for three is incorrect: {0} {1} {2} {3}"), }; } @@ -264,7 +292,7 @@ public class TestListFormat { @ParameterizedTest @MethodSource - void getInstance_1Arg_InvalidLongPattern(int index, String expected) { + void getInstance_1Arg_InvalidPlaceholder(int index, String invalidPattern, String expected) { var patterns = new String[]{ "{0}, {1}", "{0}, {1}", @@ -272,13 +300,12 @@ public class TestListFormat { "{0} and {1}", "{0} {1} {2}" }; - patterns[index] = "{0}".repeat(100_000); + patterns[index] = invalidPattern; - // Ensures validation of invalid long patterns completes without timing out var msg = assertThrows(IllegalArgumentException.class, () -> ListFormat.getInstance(patterns)) .getMessage(); - assertEquals(expected, msg.substring(0, Math.min(msg.length(), expected.length()))); + assertEquals(expected, msg); } @ParameterizedTest diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java index de1caaab2d9..85d7921f2ed 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java @@ -663,6 +663,23 @@ public class ForkJoinPoolTest extends JSR166TestCase { } } + public void testCallerInterruptedDuringSubmit() throws InterruptedException, ExecutionException { + final Thread submitter = Thread.currentThread(); + final ExecutorService p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int i = 0; i < 512; ++i) { // Enough repetitions such that any race condition is bound to materialize + try { + p.submit(submitter::interrupt).get(); + // If we don't get an InterruptedException, then the current thread should be interrupted + assertTrue(Thread.interrupted()); + } catch (InterruptedException e) { + // If we do get an InterruptedException, then the current thread should not be interrupted + assertTrue(!Thread.interrupted()); + } + } + } + } + /** * get of submit(callable) throws ExecutionException if callable * throws exception diff --git a/test/jdk/javax/accessibility/awt/CheckboxTest.java b/test/jdk/javax/accessibility/awt/CheckboxTest.java new file mode 100644 index 00000000000..7c690c16848 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/CheckboxTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Checkbox Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main CheckboxTest + */ + +import java.awt.AWTException; +import java.awt.Checkbox; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class CheckboxTest { + + private static Checkbox checkbox; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Checkbox Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Checkbox"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + CheckboxTest checkboxTest = new CheckboxTest(); + EventQueue.invokeAndWait(checkboxTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(checkboxTest::test); + } finally { + checkboxTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("Checkbox Test"); + checkbox = new Checkbox("This is a checkbox", true); + + checkbox.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + checkbox.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(checkbox); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyCheckboxAccessibility( + checkbox, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new CheckboxStateTester( + checkbox, + checkbox.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + + checkbox.setState(!checkbox.getState()); + + AccessibleTestUtils.verifyCheckboxAccessibility( + checkbox, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new CheckboxStateTester( + checkbox, + checkbox.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class CheckboxStateTester + extends AccessibleStateSetTester { + private final Checkbox checkbox; + private final AccessibleStateSet set; + + private CheckboxStateTester(Checkbox checkbox, AccessibleStateSet set) { + super(checkbox, set); + this.checkbox = checkbox; + this.set = set; + } + + @Override + public void testChecked() { + if (set.contains(AccessibleState.CHECKED)) { + if (!checkbox.getState()) { + throw new RuntimeException( + "AccessibleStateSet contains CHECKED but " + + "this component is not checked"); + } + } else { + if (checkbox.getState()) { + throw new RuntimeException( + "AccessibleStateSet does not contain CHECKED " + + "but this component is checked"); + } + } + } + } +} diff --git a/test/jdk/javax/accessibility/awt/FrameTest.java b/test/jdk/javax/accessibility/awt/FrameTest.java new file mode 100644 index 00000000000..4abe3246574 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/FrameTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Frame Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main FrameTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class FrameTest { + + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Frame Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Frame"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + FrameTest frameTest = new FrameTest(); + EventQueue.invokeAndWait(frameTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(frameTest::test); + } finally { + frameTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("Frame Test"); + + frame.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + frame.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyFrameAccessibility( + frame, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new FrameStateTester( + frame, + frame.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + + frame.setResizable(false); + + AccessibleTestUtils.verifyFrameAccessibility( + frame, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new FrameStateTester( + frame, + frame.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class FrameStateTester + extends AccessibleStateSetTester { + private final Frame component; + private final AccessibleStateSet set; + + private FrameStateTester(Frame frame, AccessibleStateSet set) { + super(frame, set); + this.component = frame; + this.set = set; + } + + @Override + public void testResizable() { + if (set.contains(AccessibleState.RESIZABLE)) { + if (!component.isResizable()) { + throw new RuntimeException( + "AccessibleStateSet contains RESIZABLE but " + + "this component is not resizable"); + } + } else { + if (component.isResizable()) { + throw new RuntimeException( + "AccessibleStateSet does not contain RESIZABLE " + + "but this component is resizable"); + } + } + } + + @Override + public void testActive() { + if (set.contains(AccessibleState.ACTIVE)) { + if (component.getFocusOwner() == null) { + throw new RuntimeException( + "AccessibleStateSet contains ACTIVE but " + + "this component is not active"); + } + } else { + if (component.getFocusOwner() != null) { + throw new RuntimeException( + "AccessibleStateSet does not contain ACTIVE but " + + "this component is active"); + } + } + } + } +} diff --git a/test/jdk/javax/accessibility/awt/LabelTest.java b/test/jdk/javax/accessibility/awt/LabelTest.java new file mode 100644 index 00000000000..dd837793eb5 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/LabelTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Label Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main LabelTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class LabelTest { + + private static Label label; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Label Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Label"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + LabelTest labelTest = new LabelTest(); + EventQueue.invokeAndWait(labelTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(labelTest::test); + } finally { + labelTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("Label Test"); + label = new Label("This is a label"); + + label.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + label.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(label); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyLabelAccessibility( + label, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new AccessibleStateSetTester( + label, + label.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } +} diff --git a/test/jdk/javax/accessibility/awt/ListTest.java b/test/jdk/javax/accessibility/awt/ListTest.java new file mode 100644 index 00000000000..011d850a4cb --- /dev/null +++ b/test/jdk/javax/accessibility/awt/ListTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary List Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main ListTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.List; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class ListTest { + + private static List list; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "List Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, List"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + ListTest listTest = new ListTest(); + EventQueue.invokeAndWait(listTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(listTest::test); + } finally { + listTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("List Test"); + list = new List(); + + list.add("Mercury"); + list.add("Venus"); + list.add("Earth"); + list.add("JavaSoft"); + list.add("Mars"); + list.add("Jupiter"); + list.add("Saturn"); + list.add("Uranus"); + list.add("Neptune"); + list.add("Pluto"); + + list.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + list.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(list); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyListAccessibility( + list, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new ListStateTester( + list, + list.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + + list.setMultipleMode(!list.isMultipleMode()); + + AccessibleTestUtils.verifyListAccessibility( + list, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new ListStateTester( + list, + list.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class ListStateTester + extends AccessibleStateSetTester { + private final List list; + private final AccessibleStateSet set; + + private ListStateTester(List list, AccessibleStateSet set) { + super(list, set); + this.list = list; + this.set = set; + } + + @Override + public void testMultiSelectable() { + if (set.contains(AccessibleState.MULTISELECTABLE)) { + if (!list.isMultipleMode()) { + throw new RuntimeException( + "AccessibleStateSet contains MULTISELECTABLE " + + "but this component is not multiselectable"); + } + } else { + if (list.isMultipleMode()) { + throw new RuntimeException( + "AccessibleStateSet does not contain " + + "MULTISELECTABLE but this component is " + + "multiselectable"); + } + } + } + } +} diff --git a/test/jdk/javax/accessibility/awt/MenuBarTest.java b/test/jdk/javax/accessibility/awt/MenuBarTest.java new file mode 100644 index 00000000000..83445fde61b --- /dev/null +++ b/test/jdk/javax/accessibility/awt/MenuBarTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary MenuBar Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleMenuComponentTester + * @run main MenuBarTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class MenuBarTest { + + private static MenuBar menuBar; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Menu Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, MenuBar"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + MenuBarTest menuBarTest = new MenuBarTest(); + EventQueue.invokeAndWait(menuBarTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(menuBarTest::test); + } finally { + menuBarTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("MenuBar Test"); + menuBar = new MenuBar(); + + Menu menu = new Menu("Menu 1"); + menu.add(new MenuItem("One")); + menu.add(new MenuItem("Two")); + menuBar.add(menu); + + menuBar.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + menuBar.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.setMenuBar(menuBar); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyMenuBarAccessibility( + menuBar, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/MenuItemTest.java b/test/jdk/javax/accessibility/awt/MenuItemTest.java new file mode 100644 index 00000000000..0cfe342e843 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/MenuItemTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary MenuItem Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleMenuComponentTester + * @run main MenuItemTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class MenuItemTest { + + private static MenuItem menuItem; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "MenuItem Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, MenuItem"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + MenuItemTest menuItemTest = new MenuItemTest(); + EventQueue.invokeAndWait(menuItemTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(menuItemTest::test); + } finally { + menuItemTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("MenuItem Test"); + + MenuBar menuBar = new MenuBar(); + Menu menu = new Menu("Menu"); + menuItem = new MenuItem("This here's a MenuItem"); + + menu.add(menuItem); + menuBar.add(menu); + + menuItem.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + menuItem.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.setMenuBar(menuBar); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyMenuItemAccessibility( + menuItem, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/MenuTest.java b/test/jdk/javax/accessibility/awt/MenuTest.java new file mode 100644 index 00000000000..15c51ca4214 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/MenuTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Menu Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleMenuComponentTester + * @run main MenuTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class MenuTest { + + private static Menu menu; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Menu Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Menu"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + MenuTest menuTest = new MenuTest(); + EventQueue.invokeAndWait(menuTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(menuTest::test); + } finally { + menuTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("Menu Test"); + + MenuBar menuBar = new MenuBar(); + menu = new Menu("File"); + menuBar.add(menu); + + menu.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + menu.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.setMenuBar(menuBar); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyMenuAccessibility( + menu, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/PanelTest.java b/test/jdk/javax/accessibility/awt/PanelTest.java new file mode 100644 index 00000000000..abfacc7485b --- /dev/null +++ b/test/jdk/javax/accessibility/awt/PanelTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Panel Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main PanelTest + */ + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class PanelTest { + + private static Panel panel; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "Panel Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Panel"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + PanelTest panelTest = new PanelTest(); + EventQueue.invokeAndWait(panelTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(panelTest::test); + } finally { + panelTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("Panel Test"); + panel = new Panel(); + + for (int i = 0; i < 5; i++) { + panel.add(new Button("Button #" + i)); + } + + panel.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + panel.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyPanelAccessibility( + panel, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new AccessibleStateSetTester( + panel, + panel.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } +} diff --git a/test/jdk/javax/accessibility/awt/PopupMenuTest.java b/test/jdk/javax/accessibility/awt/PopupMenuTest.java new file mode 100644 index 00000000000..8d329a92322 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/PopupMenuTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary PopupMenu Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleMenuComponentTester + * @run main PopupMenuTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.PopupMenu; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; + +public class PopupMenuTest { + + private static PopupMenu popupMenu; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "PopupMenu Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, PopupMenu"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + PopupMenuTest popupMenuTest = new PopupMenuTest(); + EventQueue.invokeAndWait(popupMenuTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(popupMenuTest::test); + } finally { + popupMenuTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("PopupMenu Test"); + popupMenu = new PopupMenu("PopupMenu"); + + popupMenu.add("Sleepy"); + popupMenu.add("Happy"); + popupMenu.add("Grumpy"); + popupMenu.add("Dopey"); + + popupMenu.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + popupMenu.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(popupMenu); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyPopupMenuAccessibility( + popupMenu, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + } +} diff --git a/test/jdk/javax/accessibility/awt/ScrollPaneTest.java b/test/jdk/javax/accessibility/awt/ScrollPaneTest.java new file mode 100644 index 00000000000..7f706647482 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/ScrollPaneTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary ScrollPane Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main ScrollPaneTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.awt.ScrollPane; +import java.lang.reflect.InvocationTargetException; + +public class ScrollPaneTest { + + private static ScrollPane scrollPane; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "ScrollPane Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, ScrollPane"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + ScrollPaneTest scrollPaneTest = new ScrollPaneTest(); + EventQueue.invokeAndWait(scrollPaneTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(scrollPaneTest::test); + } finally { + scrollPaneTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("ScrollPane Test"); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + + scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); + scrollPane.setSize(frame.getSize().width, frame.getSize().height); + scrollPane.add(new Label("This is a label with quite a bit of text.")); + + scrollPane.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + scrollPane.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(scrollPane); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyScrollPaneAccessibility( + scrollPane, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new AccessibleStateSetTester( + scrollPane, + scrollPane.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } +} diff --git a/test/jdk/javax/accessibility/awt/TextAreaTest.java b/test/jdk/javax/accessibility/awt/TextAreaTest.java new file mode 100644 index 00000000000..388a22324f9 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/TextAreaTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary TextArea Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main TextAreaTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextArea; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class TextAreaTest { + + private static TextArea textArea; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "TextArea Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, TextArea"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + TextAreaTest textAreaTest = new TextAreaTest(); + EventQueue.invokeAndWait(textAreaTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(textAreaTest::test); + } finally { + textAreaTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("TextAreaTest"); + String TEXT_CONTENT = """ + 1. Test TextArea javax.accessibility methods + 2. Test TextArea javax.accessibility setAccessibleName + 3. Test TextArea javax.accessibility setAccessibleDescription + 4. Test TextArea javax.accessibility setAccessibleStateSet + """; + textArea = new TextArea(TEXT_CONTENT, 24, 80); + + textArea.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + textArea.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(textArea); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyTextAreaAccessibility( + textArea, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new TextStateTester( + textArea, + textArea.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + + textArea.setEditable(false); + + AccessibleTestUtils.verifyTextAreaAccessibility( + textArea, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new TextStateTester( + textArea, + textArea.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class TextStateTester + extends AccessibleStateSetTester { + private final TextArea textArea; + private final AccessibleStateSet stateSet; + + private TextStateTester(TextArea textArea, + AccessibleStateSet stateSet) { + super(textArea, stateSet); + this.textArea = textArea; + this.stateSet = stateSet; + } + + @Override + public void testEditable() { + if (stateSet.contains(AccessibleState.EDITABLE)) { + if (!textArea.isEditable()) { + throw new RuntimeException( + "AccessibleStateSet contains EDITABLE but " + + "this component is not editable"); + } + } else { + if (textArea.isEditable()) { + throw new RuntimeException( + "AccessibleStateSet does not contain EDITABLE " + + "but this component is editable"); + } + } + } + } +} diff --git a/test/jdk/javax/accessibility/awt/TextFieldTest.java b/test/jdk/javax/accessibility/awt/TextFieldTest.java new file mode 100644 index 00000000000..96deaf3b7bc --- /dev/null +++ b/test/jdk/javax/accessibility/awt/TextFieldTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary TextField Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main TextFieldTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class TextFieldTest { + + private static TextField textField; + private static Frame frame; + + private static final String ACCESSIBLE_NAME = "TextField Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, TextField"; + private static final String TEXT = + "I love Cheesy Poofs you love Cheesy Poofs if we didn't " + + "eat Cheesy Poofs we'd be lame!"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + TextFieldTest textFieldTest = new TextFieldTest(); + EventQueue.invokeAndWait(textFieldTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(textFieldTest::test); + } finally { + textFieldTest.dispose(); + } + } + + private void createGUI() { + frame = new Frame("TextField Test"); + textField = new TextField(TEXT, 80); + + textField.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + textField.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + frame.add(textField); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyTextFieldAccessibility( + textField, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new TextStateTester( + textField, + textField.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + + textField.setEditable(false); + + AccessibleTestUtils.verifyTextFieldAccessibility( + textField, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new TextStateTester( + textField, + textField.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class TextStateTester + extends AccessibleStateSetTester { + private final TextField textField; + private final AccessibleStateSet set; + + private TextStateTester(TextField textField, AccessibleStateSet set) { + super(textField, set); + this.textField = textField; + this.set = set; + } + + @Override + public void testEditable() { + if (set.contains(AccessibleState.EDITABLE)) { + if (!textField.isEditable()) { + throw new RuntimeException( + "AccessibleStateSet contains EDITABLE but " + + "this component is not editable"); + } + } else { + if (textField.isEditable()) { + throw new RuntimeException( + "AccessibleStateSet does not contain EDITABLE " + + "but this component is editable"); + } + } + } + } +} diff --git a/test/jdk/javax/accessibility/awt/WindowTest.java b/test/jdk/javax/accessibility/awt/WindowTest.java new file mode 100644 index 00000000000..dc70ce75d90 --- /dev/null +++ b/test/jdk/javax/accessibility/awt/WindowTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1997, 2026, 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 + * @key headful + * @summary Window Accessibility test. + * @library ../../swing/regtesthelpers/accessibility/ + * @build AccessibleTestUtils AccessibleComponentTester AccessibleStateSetTester + * @run main WindowTest + */ + +import java.awt.AWTException; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +public class WindowTest { + + private static Window window; + + private static final String ACCESSIBLE_NAME = "Window Test"; + private static final String ACCESSIBLE_DESCRIPTION = + "Regression Test: javax.accessibility, Window"; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + WindowTest windowTest = new WindowTest(); + EventQueue.invokeAndWait(windowTest::createGUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(5000); + + try { + EventQueue.invokeAndWait(windowTest::test); + } finally { + windowTest.dispose(); + } + } + + private void createGUI() { + window = new Window(new Frame("Frame")); + window.setSize(300, 300); + window.setLocationRelativeTo(null); + + window.getAccessibleContext().setAccessibleName(ACCESSIBLE_NAME); + window.getAccessibleContext().setAccessibleDescription( + ACCESSIBLE_DESCRIPTION); + + window.setVisible(true); + } + + private void dispose() throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + if (window != null) { + window.dispose(); + } + }); + } + + private void test() { + AccessibleTestUtils.verifyWindowAccessibility( + window, + ACCESSIBLE_NAME, + ACCESSIBLE_DESCRIPTION + ); + + new WindowStateTester( + window, + window.getAccessibleContext().getAccessibleStateSet() + ).testAll(); + } + + private static final class WindowStateTester + extends AccessibleStateSetTester { + private final Window window; + private final AccessibleStateSet set; + + private WindowStateTester(Window window, AccessibleStateSet set) { + super(window, set); + this.window = window; + this.set = set; + } + + @Override + public void testActive() { + if (set.contains(AccessibleState.ACTIVE)) { + if (window.getFocusOwner() == null) { + throw new RuntimeException( + "AccessibleStateSet contains ACTIVE but " + + "this component is not active"); + } + } else { + if (window.getFocusOwner() != null) { + throw new RuntimeException( + "AccessibleStateSet does not contain ACTIVE " + + "but this component is active"); + } + } + } + } +} diff --git a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleMenuComponentTester.java b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleMenuComponentTester.java new file mode 100644 index 00000000000..21b91aafbcd --- /dev/null +++ b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleMenuComponentTester.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1997, 2026, 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. + */ + +import java.awt.Font; +import java.awt.MenuComponent; + +import javax.accessibility.AccessibleComponent; + +public class AccessibleMenuComponentTester { + + private final AccessibleComponent acomp; + private final MenuComponent comp; + + public AccessibleMenuComponentTester(MenuComponent menuComponent, + AccessibleComponent ac) { + if (menuComponent == null) { + throw new RuntimeException("MenuComponent should not be null"); + } + + if (ac == null) { + throw new RuntimeException("AccessibleComponent should not be null"); + } + + this.comp = menuComponent; + this.acomp = ac; + } + + // The only method supported by MenuComponents is getFont(). Everything + // else should return null. + public void test() { + testGetBackground(); + testGetBounds(); + testGetCursor(); + testGetFont(); + testGetForeground(); + testGetLocation(); + testGetLocationOnScreen(); + testGetSize(); + testIsEnabled(); + testIsFocusTraversable(); + testIsShowing(); + testIsVisible(); + } + + public void testGetBackground() { + } + + public void testGetBounds() { + } + + public void testGetCursor() { + } + + public void testGetFont() { + Font accessibleFont = acomp.getFont(); + Font componentFont = comp.getFont(); + + if (componentFont == null) { + if (accessibleFont != null) { + throw new RuntimeException( + "MenuComponent.getFont returned null but " + + "AccessibleComponent.getFont did not"); + } + } else if (!componentFont.equals(accessibleFont)) { + throw new RuntimeException( + "AccessibleComponent.getFont does not match " + + "MenuComponent.getFont"); + } + } + + public void testGetForeground() { + } + + public void testGetLocation() { + } + + public void testGetLocationOnScreen() { + } + + public void testGetSize() { + } + + public void testIsEnabled() { + } + + public void testIsFocusTraversable() { + } + + public void testIsShowing() { + } + + public void testIsVisible() { + } +} diff --git a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java index 2410cff997a..9de4a8d8089 100644 --- a/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java +++ b/test/jdk/javax/swing/regtesthelpers/accessibility/AccessibleTestUtils.java @@ -22,17 +22,33 @@ */ import java.awt.Button; +import java.awt.Checkbox; import java.awt.Choice; import java.awt.Component; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuComponent; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; import java.awt.Scrollbar; +import java.awt.ScrollPane; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; import java.util.Locale; import java.util.Objects; +import javax.accessibility.Accessible; import javax.accessibility.AccessibleAction; import javax.accessibility.AccessibleComponent; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleText; import javax.accessibility.AccessibleValue; @@ -51,32 +67,22 @@ public final class AccessibleTestUtils { boolean expectSelection, boolean expectText, boolean expectValue) { - Objects.requireNonNull(context, "AccessibleContext must not be null"); - assertExpectedString( - "getAccessibleName", - expectedName, - context.getAccessibleName() - ); + assertExpectedString("getAccessibleName", + expectedName, context.getAccessibleName()); + assertExpectedString("getAccessibleDescription", + expectedDescription, context.getAccessibleDescription()); - assertExpectedString( - "getAccessibleDescription", - expectedDescription, - context.getAccessibleDescription() - ); + AccessibleRole actualRole = context.getAccessibleRole(); + if (actualRole == null) { + throw new RuntimeException("getAccessibleRole returned null"); + } - if (expectedRole != null) { - AccessibleRole actualRole = context.getAccessibleRole(); - if (actualRole == null) { - throw new RuntimeException("getAccessibleRole returned null"); - } - if (!expectedRole.equals(actualRole)) { - throw new RuntimeException(String.format( - "getAccessibleRole returned [%s]; expected [%s]", - actualRole, expectedRole - )); - } + if (!expectedRole.equals(actualRole)) { + throw new RuntimeException( + "getAccessibleRole returned [" + actualRole + + "]; expected [" + expectedRole + "]"); } AccessibleStateSet stateSet = context.getAccessibleStateSet(); @@ -84,10 +90,14 @@ public final class AccessibleTestUtils { throw new RuntimeException("getAccessibleStateSet returned null"); } - assertPresence("getAccessibleAction", expectAction, context.getAccessibleAction()); - assertPresence("getAccessibleSelection", expectSelection, context.getAccessibleSelection()); - assertPresence("getAccessibleText", expectText, context.getAccessibleText()); - assertPresence("getAccessibleValue", expectValue, context.getAccessibleValue()); + assertPresence("getAccessibleAction", + expectAction, context.getAccessibleAction()); + assertPresence("getAccessibleSelection", + expectSelection, context.getAccessibleSelection()); + assertPresence("getAccessibleText", + expectText, context.getAccessibleText()); + assertPresence("getAccessibleValue", + expectValue, context.getAccessibleValue()); } public static void verifyAWTComponentAccessibility( @@ -99,10 +109,13 @@ public final class AccessibleTestUtils { boolean expectSelection, boolean expectText, boolean expectValue) { - - Objects.requireNonNull(component, "Component under test must not be null"); + Objects.requireNonNull(component, "Component must not be null"); AccessibleContext context = component.getAccessibleContext(); + if (context == null) { + throw new RuntimeException("getAccessibleContext returned null"); + } + verifyAccessibleContextCommon( context, expectedName, @@ -111,12 +124,12 @@ public final class AccessibleTestUtils { expectAction, expectSelection, expectText, - expectValue - ); + expectValue); assertLocaleMatches(component, context); - AccessibleComponent accessibleComponent = context.getAccessibleComponent(); + AccessibleComponent accessibleComponent = + context.getAccessibleComponent(); if (accessibleComponent == null) { throw new RuntimeException("getAccessibleComponent returned null"); } @@ -124,101 +137,10 @@ public final class AccessibleTestUtils { new AccessibleComponentTester(component, accessibleComponent).test(); } - public static void verifyChoiceAccessibility( - Choice choice, - String expectedName, - String expectedDescription) { - - Objects.requireNonNull(choice, "Choice must not be null"); - - verifyAWTComponentAccessibility( - choice, - expectedName, - expectedDescription, - AccessibleRole.COMBO_BOX, - true, - false, - false, - false - ); - - AccessibleContext context = choice.getAccessibleContext(); - - AccessibleAction action = context.getAccessibleAction(); - if (action == null) { - throw new RuntimeException("getAccessibleAction should not return null for Choice"); - } - - AccessibleValue value = context.getAccessibleValue(); - if (value != null) { - throw new RuntimeException("getAccessibleValue should return null for Choice"); - } - } - - public static void verifyScrollbarAccessibility( - Scrollbar scrollbar, - String expectedName, - String expectedDescription) { - - Objects.requireNonNull(scrollbar, "Scrollbar must not be null"); - - verifyAWTComponentAccessibility( - scrollbar, - expectedName, - expectedDescription, - AccessibleRole.SCROLL_BAR, - false, - false, - false, - true - ); - - AccessibleValue value = scrollbar.getAccessibleContext().getAccessibleValue(); - if (value == null) { - throw new RuntimeException("getAccessibleValue should not return null for Scrollbar"); - } - - assertIntValueEquals( - "getCurrentAccessibleValue", - scrollbar.getValue(), - value.getCurrentAccessibleValue() - ); - - assertIntValueEquals( - "getMinimumAccessibleValue", - scrollbar.getMinimum(), - value.getMinimumAccessibleValue() - ); - - assertIntValueEquals( - "getMaximumAccessibleValue", - scrollbar.getMaximum(), - value.getMaximumAccessibleValue() - ); - - if (!value.setCurrentAccessibleValue(Integer.valueOf(5))) { - throw new RuntimeException("setCurrentAccessibleValue(5) returned false for Scrollbar"); - } - - assertIntValueEquals( - "getCurrentAccessibleValue after setCurrentAccessibleValue(5)", - 5, - value.getCurrentAccessibleValue() - ); - - if (scrollbar.getValue() != 5) { - throw new RuntimeException( - "setCurrentAccessibleValue(5) did not update Scrollbar.getValue(); actual value: " - + scrollbar.getValue() - ); - } - } - public static void verifyButtonAccessibility( Button button, String expectedName, String expectedDescription) { - Objects.requireNonNull(button, "Button must not be null"); verifyAWTComponentAccessibility( @@ -229,106 +151,576 @@ public final class AccessibleTestUtils { true, false, false, - true - ); + true); AccessibleContext context = button.getAccessibleContext(); + verifyClickAction(context, "Button"); + verifyZeroAccessibleValue(context, "Button"); + } + public static void verifyCheckboxAccessibility( + Checkbox checkbox, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(checkbox, "Checkbox must not be null"); + + verifyAWTComponentAccessibility( + checkbox, + expectedName, + expectedDescription, + AccessibleRole.CHECK_BOX, + true, + false, + false, + true); + } + + public static void verifyChoiceAccessibility( + Choice choice, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(choice, "Choice must not be null"); + + verifyAWTComponentAccessibility( + choice, + expectedName, + expectedDescription, + AccessibleRole.COMBO_BOX, + true, + false, + false, + false); + } + + public static void verifyFrameAccessibility( + Frame frame, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(frame, "Frame must not be null"); + + verifyAWTComponentAccessibility( + frame, + expectedName, + expectedDescription, + AccessibleRole.FRAME, + false, + false, + false, + false); + } + + public static void verifyLabelAccessibility( + Label label, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(label, "Label must not be null"); + + verifyAWTComponentAccessibility( + label, + expectedName, + expectedDescription, + AccessibleRole.LABEL, + false, + false, + false, + false); + } + + public static void verifyListAccessibility( + List list, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(list, "List must not be null"); + + verifyAWTComponentAccessibility( + list, + expectedName, + expectedDescription, + AccessibleRole.LIST, + false, + true, + false, + false); + + verifyListChildren(list); + } + + public static void verifyPanelAccessibility( + Panel panel, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(panel, "Panel must not be null"); + + verifyAWTComponentAccessibility( + panel, + expectedName, + expectedDescription, + AccessibleRole.PANEL, + false, + false, + false, + false); + + verifyContainerChildren(panel, "Panel"); + } + + public static void verifyScrollbarAccessibility( + Scrollbar scrollbar, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(scrollbar, "Scrollbar must not be null"); + + verifyAWTComponentAccessibility( + scrollbar, + expectedName, + expectedDescription, + AccessibleRole.SCROLL_BAR, + false, + false, + false, + true); + + AccessibleValue value = + scrollbar.getAccessibleContext().getAccessibleValue(); + + assertIntValueEquals( + "getCurrentAccessibleValue", + scrollbar.getValue(), + value.getCurrentAccessibleValue()); + + assertIntValueEquals( + "getMinimumAccessibleValue", + scrollbar.getMinimum(), + value.getMinimumAccessibleValue()); + + assertIntValueEquals( + "getMaximumAccessibleValue", + scrollbar.getMaximum(), + value.getMaximumAccessibleValue()); + + if (!value.setCurrentAccessibleValue(Integer.valueOf(5))) { + throw new RuntimeException( + "setCurrentAccessibleValue should not return false " + + "for Scrollbar"); + } + + assertIntValueEquals( + "getCurrentAccessibleValue after setCurrentAccessibleValue(5)", + 5, + value.getCurrentAccessibleValue()); + + if (scrollbar.getValue() != 5) { + throw new RuntimeException( + "setCurrentAccessibleValue should change the Scrollbar " + + "value"); + } + } + + public static void verifyScrollPaneAccessibility( + ScrollPane scrollPane, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(scrollPane, "ScrollPane must not be null"); + + verifyAWTComponentAccessibility( + scrollPane, + expectedName, + expectedDescription, + AccessibleRole.SCROLL_PANE, + false, + false, + false, + false); + } + + public static void verifyTextAreaAccessibility( + TextArea textArea, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(textArea, "TextArea must not be null"); + + verifyAWTComponentAccessibility( + textArea, + expectedName, + expectedDescription, + AccessibleRole.TEXT, + false, + false, + true, + false); + } + + public static void verifyTextFieldAccessibility( + TextField textField, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(textField, "TextField must not be null"); + + verifyAWTComponentAccessibility( + textField, + expectedName, + expectedDescription, + AccessibleRole.TEXT, + false, + false, + true, + false); + } + + public static void verifyWindowAccessibility( + Window window, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(window, "Window must not be null"); + + verifyAWTComponentAccessibility( + window, + expectedName, + expectedDescription, + AccessibleRole.WINDOW, + false, + false, + false, + false); + } + + public static void verifyMenuAccessibility( + Menu menu, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(menu, "Menu must not be null"); + + verifyMenuComponentAccessibility( + menu, + expectedName, + expectedDescription, + AccessibleRole.MENU, + true, + true, + false, + true, + "Menu"); + + AccessibleContext context = menu.getAccessibleContext(); + verifyClickAction(context, "Menu"); + verifyZeroAccessibleValue(context, "Menu"); + } + + public static void verifyMenuBarAccessibility( + MenuBar menuBar, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(menuBar, "MenuBar must not be null"); + + verifyMenuComponentAccessibility( + menuBar, + expectedName, + expectedDescription, + AccessibleRole.MENU_BAR, + false, + true, + false, + false, + "MenuBar"); + } + + public static void verifyMenuItemAccessibility( + MenuItem menuItem, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(menuItem, "MenuItem must not be null"); + + verifyMenuComponentAccessibility( + menuItem, + expectedName, + expectedDescription, + AccessibleRole.MENU_ITEM, + true, + true, + false, + true, + "MenuItem"); + + AccessibleContext context = menuItem.getAccessibleContext(); + verifyClickAction(context, "MenuItem"); + verifyZeroAccessibleValue(context, "MenuItem"); + } + + public static void verifyPopupMenuAccessibility( + PopupMenu popupMenu, + String expectedName, + String expectedDescription) { + Objects.requireNonNull(popupMenu, "PopupMenu must not be null"); + + verifyMenuComponentAccessibility( + popupMenu, + expectedName, + expectedDescription, + AccessibleRole.POPUP_MENU, + true, + true, + false, + true, + "PopupMenu"); + + AccessibleContext context = popupMenu.getAccessibleContext(); + verifyClickAction(context, "PopupMenu"); + verifyZeroAccessibleValue(context, "PopupMenu"); + } + + private static void verifyMenuComponentAccessibility( + MenuComponent menuComponent, + String expectedName, + String expectedDescription, + AccessibleRole expectedRole, + boolean expectAction, + boolean expectSelection, + boolean expectText, + boolean expectValue, + String componentName) { + Objects.requireNonNull(menuComponent, + componentName + " must not be null"); + + AccessibleContext context = menuComponent.getAccessibleContext(); + if (context == null) { + throw new RuntimeException("getAccessibleContext returned null"); + } + + verifyAccessibleContextCommon( + context, + expectedName, + expectedDescription, + expectedRole, + expectAction, + expectSelection, + expectText, + expectValue); + + AccessibleComponent accessibleComponent = + context.getAccessibleComponent(); + if (accessibleComponent == null) { + throw new RuntimeException("getAccessibleComponent returned null"); + } + + new AccessibleMenuComponentTester( + menuComponent, accessibleComponent).test(); + } + + private static void verifyClickAction(AccessibleContext context, + String componentName) { AccessibleAction action = context.getAccessibleAction(); if (action == null) { - throw new RuntimeException("getAccessibleAction should not return null for Button"); + throw new RuntimeException( + "getAccessibleAction should not return null for " + + componentName); } int actionCount = action.getAccessibleActionCount(); if (actionCount != 1) { throw new RuntimeException( - "getAccessibleActionCount should return 1 for Button; got " + actionCount - ); + "getAccessibleActionCount returned the wrong number for " + + componentName); } String actionDescription = action.getAccessibleActionDescription(0); if (!"click".equals(actionDescription)) { throw new RuntimeException( - "getAccessibleActionDescription(0) should return \"click\" for Button; got [" - + actionDescription + "]" - ); + "getAccessibleActionDescription returned the wrong " + + "description for " + componentName); } + } + private static void verifyZeroAccessibleValue(AccessibleContext context, + String componentName) { AccessibleValue value = context.getAccessibleValue(); if (value == null) { - throw new RuntimeException("getAccessibleValue should not return null for Button"); + throw new RuntimeException( + "getAccessibleValue should not return null for " + + componentName); } - assertIntValueEquals("getCurrentAccessibleValue", 0, value.getCurrentAccessibleValue()); - assertIntValueEquals("getMinimumAccessibleValue", 0, value.getMinimumAccessibleValue()); - assertIntValueEquals("getMaximumAccessibleValue", 0, value.getMaximumAccessibleValue()); + assertIntValueEquals( + "getCurrentAccessibleValue", + 0, + value.getCurrentAccessibleValue()); + + assertIntValueEquals( + "getMinimumAccessibleValue", + 0, + value.getMinimumAccessibleValue()); + + assertIntValueEquals( + "getMaximumAccessibleValue", + 0, + value.getMaximumAccessibleValue()); if (value.setCurrentAccessibleValue(Integer.valueOf(5))) { throw new RuntimeException( - "setCurrentAccessibleValue(5) should return false for Button" - ); + "setCurrentAccessibleValue should return false for " + + componentName); } assertIntValueEquals( "getCurrentAccessibleValue after setCurrentAccessibleValue(5)", 0, - value.getCurrentAccessibleValue() - ); + value.getCurrentAccessibleValue()); } - private static void assertExpectedString(String methodName, String expected, String actual) { + private static void verifyListChildren(List list) { + AccessibleContext context = list.getAccessibleContext(); + + int childCount = context.getAccessibleChildrenCount(); + if (childCount != list.getItemCount()) { + throw new RuntimeException( + "getAccessibleChildrenCount returned an incorrect value " + + "for List"); + } + + for (int i = 0; i < childCount; i++) { + Accessible child = context.getAccessibleChild(i); + if (child == null) { + throw new RuntimeException( + "getAccessibleChild returned null for child " + i); + } + + AccessibleContext childContext = child.getAccessibleContext(); + if (childContext == null) { + throw new RuntimeException( + "getAccessibleContext returned null for List child " + + i); + } + + if (childContext.getAccessibleRole() != AccessibleRole.LIST_ITEM) { + throw new RuntimeException( + "The AccessibleRole of AccessibleAWTListChild is " + + "incorrect for child " + i); + } + + if (childContext.getAccessibleIndexInParent() != i) { + throw new RuntimeException( + "getAccessibleIndexInParent returned an incorrect " + + "value for AccessibleAWTListChild " + i); + } + + AccessibleStateSet childStateSet = + childContext.getAccessibleStateSet(); + if (childStateSet == null) { + throw new RuntimeException( + "getAccessibleStateSet returned null for List child " + + i); + } + + boolean accessibleSelected = + childStateSet.contains(AccessibleState.SELECTED); + boolean listSelected = list.isIndexSelected(i); + + if (accessibleSelected != listSelected) { + throw new RuntimeException( + "getAccessibleStateSet reports that list item " + i + + (accessibleSelected ? " is " : " is not ") + + "selected but List reports that it " + + (listSelected ? "is" : "is not") + " selected"); + } + } + } + + private static void verifyContainerChildren(Component component, + String componentName) { + AccessibleContext context = component.getAccessibleContext(); + + int childCount = context.getAccessibleChildrenCount(); + if (childCount != component.getAccessibleContext() + .getAccessibleChildrenCount()) { + throw new RuntimeException( + "getAccessibleChildrenCount returned an incorrect value " + + "for " + componentName); + } + + for (int i = 0; i < childCount; i++) { + Accessible child = context.getAccessibleChild(i); + if (child == null) { + throw new RuntimeException( + "getAccessibleChild returned null for " + + componentName + " child " + i); + } + + AccessibleContext childContext = child.getAccessibleContext(); + if (childContext == null) { + throw new RuntimeException( + "getAccessibleContext returned null for " + + componentName + " child " + i); + } + } + } + + private static void assertExpectedString(String methodName, + String expected, + String actual) { if (expected == null) { - throw new RuntimeException("Excepted value is null. Provide " + - "excepted value"); + throw new RuntimeException( + "Expected value for " + methodName + " should not be null"); } if (actual == null) { - throw new RuntimeException(methodName + " returned null; expected" + - " [" + expected + "]"); + throw new RuntimeException( + methodName + " returned null; expected [" + expected + "]"); } + if (!expected.equals(actual)) { - throw new RuntimeException(methodName + " returned [" + actual + - "]; expected [" + expected + "]"); + throw new RuntimeException( + methodName + " returned [" + actual + + "]; expected [" + expected + "]"); } } - private static void assertPresence(String methodName, boolean expectedPresent, Object value) { + private static void assertPresence(String methodName, + boolean expectedPresent, + Object value) { if (expectedPresent && value == null) { - throw new RuntimeException(methodName + " returned null but was expected"); + throw new RuntimeException( + methodName + " returned null but should not"); } + if (!expectedPresent && value != null) { - throw new RuntimeException(methodName + " returned non-null but " + - "was expected to be null"); + throw new RuntimeException( + methodName + " returned non-null but should return null"); } } - private static void assertLocaleMatches(Component component, AccessibleContext context) { + private static void assertLocaleMatches(Component component, + AccessibleContext context) { Locale componentLocale = component.getLocale(); Locale accessibleLocale = context.getLocale(); if (componentLocale == null) { throw new RuntimeException("Component.getLocale returned null"); } + if (accessibleLocale == null) { - throw new RuntimeException("AccessibleContext.getLocale returned null"); + throw new RuntimeException( + "AccessibleContext.getLocale returned null"); } + if (!componentLocale.equals(accessibleLocale)) { - throw new RuntimeException(String.format( - "AccessibleContext.getLocale returned [%s], but Component" + - ".getLocale returned [%s]", - accessibleLocale, componentLocale - )); + throw new RuntimeException( + "AccessibleContext.getLocale returned [" + + accessibleLocale + "], but Component.getLocale returned [" + + componentLocale + "]"); } } - private static void assertIntValueEquals(String methodName, int expected, Number actual) { + private static void assertIntValueEquals(String methodName, + int expected, + Number actual) { if (actual == null) { - throw new RuntimeException(methodName + " returned null; expected [" + expected + "]"); + throw new RuntimeException( + methodName + " returned null; expected [" + expected + "]"); } + if (actual.intValue() != expected) { throw new RuntimeException( - methodName + " returned [" + actual + "]; expected [" + expected + "]" - ); + methodName + " returned [" + actual + + "]; expected [" + expected + "]"); } } } diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java index 229ab03b568..9e2c5e909b0 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java +++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -32,13 +32,15 @@ import java.net.InetAddress; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import jdk.test.lib.security.SecurityUtils; -import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.security.SecurityUtils; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; @@ -50,29 +52,32 @@ import javax.net.ssl.SSLHandshakeException; public class DisabledCipherSuitesNotNegotiated { private static final String TLS_PROTOCOL = "TLSv1.2"; private static volatile int serverPort = 0; - private static volatile Exception serverException = null; private static final CountDownLatch waitForServer = new CountDownLatch(1); - private static final int WAIT_FOR_SERVER_SECS = 5; + private static final int WAIT_FOR_SERVER_SECS = (int)Utils.adjustTimeout(5); private static final String DISABLED_CIPHERSUITE = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; private static final String DISABLED_CIPHER_WILDCARD = "TLS_ECDH*WITH_AES_256_GCM_*"; + private static volatile Exception serverException = null; private static void runServer(boolean disabledInClient) throws Exception { SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); ctx.init(null, null, null); SSLServerSocketFactory factory = ctx.getServerSocketFactory(); + InetAddress address = InetAddress.getLoopbackAddress(); + System.out.println("SERVER listening on " + address); try(SSLServerSocket serverSocket = (SSLServerSocket)factory - .createServerSocket(0, -1, InetAddress.getLoopbackAddress())) { - serverPort = serverSocket.getLocalPort(); - waitForServer.countDown(); - + .createServerSocket(0, -1, address)) { if (disabledInClient) { // set cipher suite to disabled ciphersuite serverSocket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); } - try(SSLSocket clientSocket = (SSLSocket) serverSocket.accept()) { + serverPort = serverSocket.getLocalPort(); + serverSocket.setSoTimeout(WAIT_FOR_SERVER_SECS * 3000); + waitForServer.countDown(); + + try(SSLSocket clientSocket = (SSLSocket)serverSocket.accept()) { try { clientSocket.getInputStream().readAllBytes(); throw new Exception("SERVER: The expected handshake exception was not thrown."); @@ -88,7 +93,9 @@ public class DisabledCipherSuitesNotNegotiated { SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); ctx.init(null, null, null); SSLSocketFactory factory = ctx.getSocketFactory(); - try(SSLSocket socket = (SSLSocket)factory.createSocket("localhost", portNumber)) { + InetAddress address = InetAddress.getLoopbackAddress(); + System.out.println("CLIENT: Connecting to " + address); + try(SSLSocket socket = (SSLSocket)factory.createSocket(address, portNumber)) { if (!disableInClient) { socket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); } @@ -104,42 +111,7 @@ public class DisabledCipherSuitesNotNegotiated { public static void main(String [] args) throws Exception { if (args.length == 1) { - // run server-side - final boolean disabledInClient = args[0].equals("client"); - if (!disabledInClient) { - SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); - } - try(ExecutorService executorService = Executors.newSingleThreadExecutor()) { - executorService.submit(() -> { - try { - runServer(disabledInClient); - } catch (Exception exc) { - System.out.println("Server Exception:"); - exc.printStackTrace(System.out); - serverException = exc; - throw new RuntimeException(exc); - } - }); - - if (!waitForServer.await(WAIT_FOR_SERVER_SECS, TimeUnit.SECONDS)) { - throw new Exception("Server did not start within " + - WAIT_FOR_SERVER_SECS + " seconds."); - } - - System.out.printf("Server listening on port %d.%nStarting client process...", - serverPort); - - OutputAnalyzer oa = ProcessTools.executeProcess( - ProcessTools.createTestJavaProcessBuilder("DisabledCipherSuitesNotNegotiated", - "" + disabledInClient, "" + serverPort)); - oa.shouldHaveExitValue(0); - System.out.println("Client output:"); - System.out.println(oa.getOutput()); - if (serverException != null) { - throw new Exception ("Server-side threw an unexpected exception: " - + serverException); - } - } + runTest(args[0].equals("client")); } else if (args.length == 2) { // run client-side @@ -147,6 +119,7 @@ public class DisabledCipherSuitesNotNegotiated { if (disabledInClient) { SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); } + runClient(Boolean.parseBoolean(args[0]), Integer.parseInt(args[1])); } else { @@ -155,4 +128,48 @@ public class DisabledCipherSuitesNotNegotiated { } } + private static void runTest(final boolean disabledInClient) throws Exception { + try(ExecutorService executorService = Executors.newSingleThreadExecutor()) { + Future serverThread = executorService.submit(() -> { + try { + if (!disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + runServer(disabledInClient); + } catch (Exception exc) { + serverException = exc; + } + }); + + + if (!waitForServer.await(WAIT_FOR_SERVER_SECS, TimeUnit.SECONDS)) { + throw new Exception("Server did not start within " + + WAIT_FOR_SERVER_SECS + " seconds."); + } + + System.out.printf("Server listening on port %d.%nStarting client process...", + serverPort); + + OutputAnalyzer oa = ProcessTools.executeProcess( + ProcessTools.createTestJavaProcessBuilder( + "DisabledCipherSuitesNotNegotiated", + "" + disabledInClient, "" + serverPort)); + oa.waitFor(); + serverThread.get(); + + System.out.printf("Client process return %d%nCLIENT OUTPUT%n%s%n", + oa.getExitValue(), oa.getOutput()); + if (serverException != null) { + System.out.printf( + "Server thread threw an unexpected exception: %s%n", + serverException); + throw serverException; + } else if (oa.getExitValue() != 0) { + throw new Exception(String.format("Client exit code is non-zero (%d). "+ + "Server did not throw an exception.", + oa.getExitValue())); + } + } + } + } diff --git a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java index ffa8a530859..16a48fcc626 100644 --- a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java +++ b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java @@ -103,9 +103,9 @@ public class TestErasure extends JavadocTester { checkOutput("Foo.html", true, """
  • Constructor Details
      -
    1. Foo(T)
    2. -
    3. Foo(T)
    4. -
    5. Foo(T)
    6. +
    7. Foo(T)
    8. +
    9. Foo(T)
    10. +
    11. Foo(T)
  • """); checkOutput("index-all.html", true, """ @@ -145,9 +145,9 @@ public class TestErasure extends JavadocTester { checkOutput("Foo.html", true, """
  • Method Details
      -
    1. m(T)
    2. -
    3. m(T)
    4. -
    5. m(T)
    6. +
    7. m(T)
    8. +
    9. m(T)
    10. +
    11. m(T)
  • """); checkOutput("index-all.html", true, """ @@ -210,8 +210,8 @@ public class TestErasure extends JavadocTester { checkOutput("Foo.html", true, """
  • Constructor Details
      -
    1. Foo(T)
    2. -
    3. Foo(T)
    4. +
    5. Foo(T)
    6. +
    7. Foo(T)
  • """); checkOutput("index-all.html", true, """ @@ -242,8 +242,8 @@ public class TestErasure extends JavadocTester { checkOutput("Foo.html", true, """
  • Method Details
      -
    1. m(T)
    2. -
    3. m(T)
    4. +
    5. m(T)
    6. +
    7. m(T)
  • """); checkOutput("index-all.html", true, """ diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java index 17ab9734845..02100d84a1a 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java @@ -25,7 +25,7 @@ * @test * @bug 7025314 8023700 7198273 8025633 8026567 8081854 8196027 8182765 * 8196200 8196202 8223378 8258659 8261976 8320458 8329537 8350638 - * 8342705 8371021 8373526 + * 8342705 8371021 8373526 8384065 * @summary Make sure the Next/Prev Class links iterate through all types. * Make sure the navagation is 2 columns, not 3. * @library /tools/lib ../../lib @@ -172,6 +172,36 @@ public class TestNavigation extends JavadocTester { tb.writeJavaFiles(src, """ package pkg1; public class A { + /** + * Empty ctor + */ + public A() {} + + /** + * Single param ctor + */ + public A(int i) {} + + /** + * A ctor with many params + */ + public A(int i, int j, int x, int y, String s, boolean b) {} + + /** + * A method without parameters + */ + public void noParams() {} + + /** + * A method with a single parameter + */ + public void oneParam(String s) {} + + /** + * A method with lots of parameters + */ + public void manyParams(String s, int i, int j, boolean b, double d, double e) {} + /** * Class with members. */ @@ -217,6 +247,29 @@ public class TestNavigation extends JavadocTester { "pkg1"); checkExit(Exit.OK); + checkOrder("pkg1/A.html", + """ +
      +
    1. Description
    2. +
    3. Nested Class Summary
    4. +
    5. Constructor Summary
    6. +
    7. Method Summary
    8. +
    9. Constructor Details +
        +
      1. A()
      2. +
      3. A(int)
      4. +
      5. A(int, int, int, int, String, boolean)
      6. +
      +
    10. +
    11. Method Details +
        +
      1. noParams()
      2. +
      3. oneParam(String)
      4. +
      5. manyParams(String, int, int, boolean, double, double)
      6. +
      +
    12. +
    """); + checkOrder("pkg1/A.X.html", """