@@ -129,3 +129,212 @@ func TestCFileGenerationWithoutNamespace(t *testing.T) {
129129 expectedCall := "register_class_MySuperClass()"
130130 require .Contains (t , contentResult , expectedCall , "C file should not contain the standard function call" )
131131}
132+
133+ func TestCFileGenerationWithNamespacedConstants (t * testing.T ) {
134+ tests := []struct {
135+ name string
136+ namespace string
137+ constants []phpConstant
138+ contains []string
139+ }{
140+ {
141+ name : "integer constant with namespace" ,
142+ namespace : `Go\Extension` ,
143+ constants : []phpConstant {
144+ {Name : "TEST_INT" , Value : "42" , PhpType : phpInt },
145+ },
146+ contains : []string {
147+ `REGISTER_NS_LONG_CONSTANT("Go\\Extension", "TEST_INT", 42, CONST_CS | CONST_PERSISTENT);` ,
148+ },
149+ },
150+ {
151+ name : "string constant with namespace" ,
152+ namespace : `Go\Extension` ,
153+ constants : []phpConstant {
154+ {Name : "TEST_STRING" , Value : `"hello"` , PhpType : phpString },
155+ },
156+ contains : []string {
157+ `REGISTER_NS_STRING_CONSTANT("Go\\Extension", "TEST_STRING", "hello", CONST_CS | CONST_PERSISTENT);` ,
158+ },
159+ },
160+ {
161+ name : "float constant with namespace" ,
162+ namespace : `Go\Extension` ,
163+ constants : []phpConstant {
164+ {Name : "TEST_FLOAT" , Value : "3.14" , PhpType : phpFloat },
165+ },
166+ contains : []string {
167+ `REGISTER_NS_DOUBLE_CONSTANT("Go\\Extension", "TEST_FLOAT", 3.14, CONST_CS | CONST_PERSISTENT);` ,
168+ },
169+ },
170+ {
171+ name : "bool constant with namespace" ,
172+ namespace : `Go\Extension` ,
173+ constants : []phpConstant {
174+ {Name : "TEST_BOOL" , Value : "true" , PhpType : phpBool },
175+ },
176+ contains : []string {
177+ `REGISTER_NS_LONG_CONSTANT("Go\\Extension", "TEST_BOOL", 1, CONST_CS | CONST_PERSISTENT);` ,
178+ },
179+ },
180+ {
181+ name : "iota constant with namespace" ,
182+ namespace : `Go\Extension` ,
183+ constants : []phpConstant {
184+ {Name : "STATUS_OK" , Value : "STATUS_OK" , PhpType : phpInt , IsIota : true },
185+ },
186+ contains : []string {
187+ `REGISTER_NS_LONG_CONSTANT("Go\\Extension", "STATUS_OK", STATUS_OK, CONST_CS | CONST_PERSISTENT);` ,
188+ },
189+ },
190+ {
191+ name : "multiple constants with deep namespace" ,
192+ namespace : `My\Deep\Namespace` ,
193+ constants : []phpConstant {
194+ {Name : "CONST_INT" , Value : "100" , PhpType : phpInt },
195+ {Name : "CONST_STR" , Value : `"value"` , PhpType : phpString },
196+ {Name : "CONST_FLOAT" , Value : "1.5" , PhpType : phpFloat },
197+ },
198+ contains : []string {
199+ `REGISTER_NS_LONG_CONSTANT("My\\Deep\\Namespace", "CONST_INT", 100, CONST_CS | CONST_PERSISTENT);` ,
200+ `REGISTER_NS_STRING_CONSTANT("My\\Deep\\Namespace", "CONST_STR", "value", CONST_CS | CONST_PERSISTENT);` ,
201+ `REGISTER_NS_DOUBLE_CONSTANT("My\\Deep\\Namespace", "CONST_FLOAT", 1.5, CONST_CS | CONST_PERSISTENT);` ,
202+ },
203+ },
204+ {
205+ name : "single level namespace" ,
206+ namespace : `TestNamespace` ,
207+ constants : []phpConstant {
208+ {Name : "MY_CONST" , Value : "999" , PhpType : phpInt },
209+ },
210+ contains : []string {
211+ `REGISTER_NS_LONG_CONSTANT("TestNamespace", "MY_CONST", 999, CONST_CS | CONST_PERSISTENT);` ,
212+ },
213+ },
214+ {
215+ name : "namespace with trailing backslash" ,
216+ namespace : `TestIntegration\Extension` ,
217+ constants : []phpConstant {
218+ {Name : "VERSION" , Value : `"1.0.0"` , PhpType : phpString },
219+ },
220+ contains : []string {
221+ `REGISTER_NS_STRING_CONSTANT("TestIntegration\\Extension", "VERSION", "1.0.0", CONST_CS | CONST_PERSISTENT);` ,
222+ },
223+ },
224+ }
225+
226+ for _ , tt := range tests {
227+ t .Run (tt .name , func (t * testing.T ) {
228+ generator := & Generator {
229+ BaseName : "test_ext" ,
230+ Namespace : tt .namespace ,
231+ Constants : tt .constants ,
232+ }
233+
234+ cGen := cFileGenerator {generator : generator }
235+ content , err := cGen .buildContent ()
236+ require .NoError (t , err , "Failed to build C file content" )
237+
238+ for _ , expected := range tt .contains {
239+ assert .Contains (t , content , expected , "Generated C content should contain '%s'" , expected )
240+ }
241+ })
242+ }
243+ }
244+
245+ func TestCFileGenerationWithoutNamespacedConstants (t * testing.T ) {
246+ tests := []struct {
247+ name string
248+ namespace string
249+ constants []phpConstant
250+ contains []string
251+ }{
252+ {
253+ name : "integer constant without namespace" ,
254+ namespace : "" ,
255+ constants : []phpConstant {
256+ {Name : "GLOBAL_INT" , Value : "42" , PhpType : phpInt },
257+ },
258+ contains : []string {
259+ `REGISTER_LONG_CONSTANT("GLOBAL_INT", 42, CONST_CS | CONST_PERSISTENT);` ,
260+ },
261+ },
262+ {
263+ name : "string constant without namespace" ,
264+ namespace : "" ,
265+ constants : []phpConstant {
266+ {Name : "GLOBAL_STRING" , Value : `"test"` , PhpType : phpString },
267+ },
268+ contains : []string {
269+ `REGISTER_STRING_CONSTANT("GLOBAL_STRING", "test", CONST_CS | CONST_PERSISTENT);` ,
270+ },
271+ },
272+ {
273+ name : "float constant without namespace" ,
274+ namespace : "" ,
275+ constants : []phpConstant {
276+ {Name : "GLOBAL_FLOAT" , Value : "2.71" , PhpType : phpFloat },
277+ },
278+ contains : []string {
279+ `REGISTER_DOUBLE_CONSTANT("GLOBAL_FLOAT", 2.71, CONST_CS | CONST_PERSISTENT);` ,
280+ },
281+ },
282+ {
283+ name : "bool constant without namespace" ,
284+ namespace : "" ,
285+ constants : []phpConstant {
286+ {Name : "GLOBAL_BOOL" , Value : "false" , PhpType : phpBool },
287+ },
288+ contains : []string {
289+ `REGISTER_LONG_CONSTANT("GLOBAL_BOOL", 0, CONST_CS | CONST_PERSISTENT);` ,
290+ },
291+ },
292+ {
293+ name : "iota constant without namespace" ,
294+ namespace : "" ,
295+ constants : []phpConstant {
296+ {Name : "ERROR_CODE" , Value : "ERROR_CODE" , PhpType : phpInt , IsIota : true },
297+ },
298+ contains : []string {
299+ `REGISTER_LONG_CONSTANT("ERROR_CODE", ERROR_CODE, CONST_CS | CONST_PERSISTENT);` ,
300+ },
301+ },
302+ }
303+
304+ for _ , tt := range tests {
305+ t .Run (tt .name , func (t * testing.T ) {
306+ generator := & Generator {
307+ BaseName : "test_ext" ,
308+ Namespace : tt .namespace ,
309+ Constants : tt .constants ,
310+ }
311+
312+ cGen := cFileGenerator {generator : generator }
313+ content , err := cGen .buildContent ()
314+ require .NoError (t , err , "Failed to build C file content" )
315+
316+ for _ , expected := range tt .contains {
317+ assert .Contains (t , content , expected , "Generated C content should contain '%s'" , expected )
318+ }
319+
320+ assert .NotContains (t , content , "REGISTER_NS_" , "Content should NOT contain namespaced constant macros when namespace is empty" )
321+ })
322+ }
323+ }
324+
325+ func TestCFileTemplateFunctionMapCString (t * testing.T ) {
326+ generator := & Generator {
327+ BaseName : "test_ext" ,
328+ Namespace : `My\Namespace\Test` ,
329+ Constants : []phpConstant {
330+ {Name : "MY_CONST" , Value : "123" , PhpType : phpInt },
331+ },
332+ }
333+
334+ cGen := cFileGenerator {generator : generator }
335+ content , err := cGen .getTemplateContent ()
336+ require .NoError (t , err , "Failed to get template content" )
337+
338+ assert .Contains (t , content , `"My\\Namespace\\Test"` , "Template should properly escape namespace backslashes using cString filter" )
339+ assert .NotContains (t , content , `"My\Namespace\Test"` , "Template should not contain unescaped namespace (single backslashes)" )
340+ }
0 commit comments