1+ /*
2+ * Copyright © Magento, Inc. All rights reserved.
3+ * See COPYING.txt for license details.
4+ */
5+
6+ package com .magento .idea .magento2plugin .util ;
7+
8+ import java .io .IOException ;
9+ import java .lang .reflect .Field ;
10+ import java .lang .reflect .Method ;
11+ import java .util .Locale ;
12+ import java .util .Map ;
13+ import java .util .ResourceBundle ;
14+ import java .util .concurrent .ConcurrentHashMap ;
15+
16+ /**
17+ * Utility class for mocking the PhpBundle in tests.
18+ *
19+ * This class provides methods to set up a mock for the PhpBundle,
20+ * which will return a fixed value for any key, avoiding the need for actual message keys in tests.
21+ */
22+ public final class PhpBundleMocker {
23+
24+ private static final String PHP_BUNDLE_NAME = "messages.PhpBundle" ;
25+ private static final String DEFAULT_MOCK_VALUE = "mocked value" ;
26+
27+ private PhpBundleMocker () {
28+ // Private constructor to prevent instantiation
29+ }
30+
31+ /**
32+ * Set up a mock for the PhpBundle that returns a fixed value for any key.
33+ *
34+ * @param mockValue The value to return for any key
35+ * @throws Exception If an error occurs while setting up the mock
36+ */
37+ public static void mockPhpBundle (final String mockValue ) throws Exception {
38+ // Create a mock bundle
39+ final ResourceBundle mockBundle = new ResourceBundleMock (mockValue );
40+
41+ // Clear the ResourceBundle cache to ensure our mock is used
42+ clearResourceBundleCache ();
43+
44+ // Install our custom ResourceBundle.Control that returns the mock bundle for PhpBundle
45+ ResourceBundle .getBundle (PHP_BUNDLE_NAME , new ResourceBundle .Control () {
46+ @ Override
47+ public ResourceBundle newBundle (
48+ final String baseName ,
49+ final Locale locale ,
50+ final String format ,
51+ final ClassLoader loader ,
52+ final boolean reload
53+ ) throws IllegalAccessException , InstantiationException , IOException {
54+ if (PHP_BUNDLE_NAME .equals (baseName )) {
55+ return mockBundle ;
56+ }
57+ return super .newBundle (baseName , locale , format , loader , reload );
58+ }
59+ });
60+ }
61+
62+ /**
63+ * Set up a mock for the PhpBundle that returns "mocked value for [key]" for any key.
64+ *
65+ * @throws Exception If an error occurs while setting up the mock
66+ */
67+ public static void mockPhpBundle () throws Exception {
68+ mockPhpBundle (DEFAULT_MOCK_VALUE );
69+ }
70+
71+ /**
72+ * Clear the ResourceBundle cache to ensure our mock is used.
73+ *
74+ * @throws Exception If an error occurs while clearing the cache
75+ */
76+ private static void clearResourceBundleCache () throws Exception {
77+ try {
78+ // Get the cacheList field from ResourceBundle
79+ final Field cacheListField = ResourceBundle .class .getDeclaredField ("cacheList" );
80+ cacheListField .setAccessible (true );
81+
82+ // Get the cache map
83+ final Map <?, ?> cacheList = (Map <?, ?>) cacheListField .get (null );
84+
85+ // Clear the cache
86+ cacheList .clear ();
87+ } catch (final NoSuchFieldException e ) {
88+ // If cacheList field is not found, try the newer implementation (Java 9+)
89+ try {
90+ // Get the clearCache method
91+ final Method clearCacheMethod = ResourceBundle .class .getDeclaredMethod ("clearCache" );
92+ clearCacheMethod .setAccessible (true );
93+
94+ // Call the method to clear the cache
95+ clearCacheMethod .invoke (null );
96+ } catch (final NoSuchMethodException e2 ) {
97+ throw new Exception ("Failed to clear ResourceBundle cache" , e2 );
98+ }
99+ }
100+ }
101+ }
0 commit comments