11package org.zstack.test.integration.core
22
3+ import org.zstack.core.errorcode.GlobalErrorCodeI18nServiceImpl
34import org.zstack.core.errorcode.LocaleUtils
45import org.zstack.header.errorcode.ErrorCode
6+ import org.zstack.header.errorcode.ErrorCodeList
57import org.zstack.testlib.SubCase
68
79class ErrorCodeI18nCase extends SubCase {
@@ -24,8 +26,12 @@ class ErrorCodeI18nCase extends SubCase {
2426 testLocaleUtilsNoMatch()
2527 testLocaleUtilsCaseInsensitive()
2628 testLocaleUtilsMalformedHeader()
29+ testLocaleUtilsComplexBrowserHeader()
2730 testErrorCodeCopyConstructor()
2831 testErrorCodeCopyConstructorWithNulls()
32+ testMessageGuaranteeFallbackToDetails()
33+ testMessageGuaranteeFallbackToDescription()
34+ testMessageGuaranteeOnCauseChain()
2935 }
3036
3137 @Override
@@ -78,6 +84,14 @@ class ErrorCodeI18nCase extends SubCase {
7884 assert LocaleUtils . resolveLocale(" ;;;,,," , available) == " en_US"
7985 }
8086
87+ void testLocaleUtilsComplexBrowserHeader () {
88+ def available = [" zh_CN" , " en_US" ] as Set
89+ // real Chrome header: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
90+ assert LocaleUtils . resolveLocale(" zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6" , available) == " zh_CN"
91+ // q=0 means "not acceptable" — should be skipped
92+ assert LocaleUtils . resolveLocale(" zh-CN;q=0,en-US;q=1.0" , available) == " en_US"
93+ }
94+
8195 // ---- ErrorCode copy constructor ----
8296
8397 void testErrorCodeCopyConstructor () {
@@ -127,4 +141,42 @@ class ErrorCodeI18nCase extends SubCase {
127141 assert copy. formatArgs == null
128142 }
129143
144+ // ---- message guarantee (localizeErrorCode always populates message) ----
145+
146+ void testMessageGuaranteeFallbackToDetails () {
147+ def i18n = new GlobalErrorCodeI18nServiceImpl ()
148+ // no i18n JSON loaded, so getLocalizedMessage returns null
149+ // localizeErrorCode should fall back to details
150+ def error = new ErrorCode (" SYS.1000" , " System Error" , " disk full on /dev/sda1" )
151+ assert error. getMessage() == null
152+
153+ i18n. localizeErrorCode(error, " en_US" )
154+
155+ assert error. getMessage() == " disk full on /dev/sda1"
156+ }
157+
158+ void testMessageGuaranteeFallbackToDescription () {
159+ def i18n = new GlobalErrorCodeI18nServiceImpl ()
160+ // no details, should fall back to description
161+ def error = new ErrorCode (" SYS.1000" , " System Error" )
162+ assert error. getMessage() == null
163+
164+ i18n. localizeErrorCode(error, " en_US" )
165+
166+ assert error. getMessage() == " System Error"
167+ }
168+
169+ void testMessageGuaranteeOnCauseChain () {
170+ def i18n = new GlobalErrorCodeI18nServiceImpl ()
171+ def root = new ErrorCode (" INTERNAL.1001" , " Internal Error" , " root cause detail" )
172+ def mid = new ErrorCode (" SYS.1000" , " System Error" )
173+ mid. setCause(root)
174+
175+ i18n. localizeErrorCode(mid, " en_US" )
176+
177+ // both should have message populated
178+ assert mid. getMessage() == " System Error"
179+ assert root. getMessage() == " root cause detail"
180+ }
181+
130182}
0 commit comments