@@ -164,4 +164,176 @@ final class CounterTests: XCTestCase {
164164 """
165165 )
166166 }
167+
168+ func testWithMetricDescriptorWithFullComponentMatrix( ) {
169+ // --- Test Constants ---
170+ // let helpTextValue = "https://help.url/sub"
171+ let metricName = " foo2 "
172+ let incrementValue : Int64 = 2
173+ let client = PrometheusCollectorRegistry ( )
174+
175+ // 1. Define the base naming combinations first.
176+ let baseNameCases :
177+ [ (
178+ namespace: String ? , subsystem: String ? , unitName: String ? , expectedMetricName: String ,
179+ description: String
180+ ) ] = [
181+ (
182+ namespace: " myapp " , subsystem: " subsystem " , unitName: " total " ,
183+ expectedMetricName: " myapp_subsystem_foo2_total " , description: " All components present "
184+ ) ,
185+ (
186+ namespace: " myapp " , subsystem: " subsystem " , unitName: nil ,
187+ expectedMetricName: " myapp_subsystem_foo2 " , description: " Unit is nil "
188+ ) ,
189+ (
190+ namespace: " myapp " , subsystem: nil , unitName: " total " , expectedMetricName: " myapp_foo2_total " ,
191+ description: " Subsystem is nil "
192+ ) ,
193+ (
194+ namespace: " myapp " , subsystem: nil , unitName: nil , expectedMetricName: " myapp_foo2 " ,
195+ description: " Subsystem and Unit are nil "
196+ ) ,
197+ (
198+ namespace: nil , subsystem: " subsystem " , unitName: " total " ,
199+ expectedMetricName: " subsystem_foo2_total " , description: " Namespace is nil "
200+ ) ,
201+ (
202+ namespace: nil , subsystem: " subsystem " , unitName: nil , expectedMetricName: " subsystem_foo2 " ,
203+ description: " Namespace and Unit are nil "
204+ ) ,
205+ (
206+ namespace: nil , subsystem: nil , unitName: " total " , expectedMetricName: " foo2_total " ,
207+ description: " Namespace and Subsystem are nil "
208+ ) ,
209+ (
210+ namespace: nil , subsystem: nil , unitName: nil , expectedMetricName: " foo2 " ,
211+ description: " Only metric name is present "
212+ ) ,
213+ (
214+ namespace: " " , subsystem: " subsystem " , unitName: " total " ,
215+ expectedMetricName: " subsystem_foo2_total " , description: " Namespace is empty string "
216+ ) ,
217+ (
218+ namespace: " myapp " , subsystem: " " , unitName: " total " , expectedMetricName: " myapp_foo2_total " ,
219+ description: " Subsystem is empty string "
220+ ) ,
221+ (
222+ namespace: " myapp " , subsystem: " subsystem " , unitName: " " ,
223+ expectedMetricName: " myapp_subsystem_foo2 " , description: " Unit is empty string "
224+ ) ,
225+ (
226+ namespace: " " , subsystem: " " , unitName: " total " , expectedMetricName: " foo2_total " ,
227+ description: " Namespace and Subsystem are empty strings "
228+ ) ,
229+ (
230+ namespace: " myapp " , subsystem: " " , unitName: " " , expectedMetricName: " myapp_foo2 " ,
231+ description: " Subsystem and Unit are empty strings "
232+ ) ,
233+ (
234+ namespace: " " , subsystem: " subsystem " , unitName: " " , expectedMetricName: " subsystem_foo2 " ,
235+ description: " Namespace and Unit are empty strings "
236+ ) ,
237+ (
238+ namespace: " " , subsystem: " " , unitName: " " , expectedMetricName: " foo2 " ,
239+ description: " All optional components are empty strings "
240+ ) ,
241+ ]
242+
243+ // 2. Define the label combinations to test.
244+ let labelCases : [ ( labels: [ ( String , String ) ] , expectedLabelString: String , description: String ) ] = [
245+ ( labels: [ ] , expectedLabelString: " " , description: " without labels " ) ,
246+ ( labels: [ ( " method " , " get " ) ] , expectedLabelString: " {method= \" get \" } " , description: " with one label " ) ,
247+ (
248+ labels: [ ( " status " , " 200 " ) , ( " path " , " /api/v1 " ) ] ,
249+ expectedLabelString: " {status= \" 200 \" ,path= \" /api/v1 \" } " , description: " with two labels "
250+ ) ,
251+ ]
252+
253+ // 3. Programmatically generate the final, full matrix by crossing name cases with label cases.
254+ var allTestCases :
255+ [ (
256+ descriptor: FQMetricDescriptor , labels: [ ( String , String ) ] , expectedOutput: String ,
257+ failureDescription: String
258+ ) ] = [ ]
259+
260+ for nameCase in baseNameCases {
261+ for labelCase in labelCases {
262+ let expectedMetricLine =
263+ " \( nameCase. expectedMetricName) \( labelCase. expectedLabelString) \( incrementValue) "
264+
265+ // todo : add help text in next PR
266+ // Case 1: With help text (currently disabled/commented out)
267+ // allTestCases.append((
268+ // descriptor: FQMetricDescriptor(
269+ // namespace: nameCase.namespace, subsystem: nameCase.subsystem, metricName: metricName, unitName: nameCase.unitName, helpText: helpTextValue
270+ // ),
271+ // labels: labelCase.labels,
272+ // expectedOutput: """
273+ // # HELP \(nameCase.expectedMetricName) \(helpTextValue)
274+ // # TYPE \(nameCase.expectedMetricName) counter
275+ // \(expectedMetricLine)
276+ //
277+ // """,
278+ // failureDescription: "\(nameCase.description), \(labelCase.description), with help text"
279+ // ))
280+
281+ // Case 2: Without help text (helpText is nil)
282+ allTestCases. append (
283+ (
284+ descriptor: FQMetricDescriptor (
285+ namespace: nameCase. namespace,
286+ subsystem: nameCase. subsystem,
287+ metricName: metricName,
288+ unitName: nameCase. unitName,
289+ helpText: nil
290+ ) ,
291+ labels: labelCase. labels,
292+ expectedOutput: """
293+ # TYPE \( nameCase. expectedMetricName) counter
294+ \( expectedMetricLine)
295+
296+ """ ,
297+ failureDescription: " \( nameCase. description) , \( labelCase. description) , without help text "
298+ )
299+ )
300+ }
301+ }
302+
303+ let expectedTestCaseCount = baseNameCases. count * labelCases. count
304+ XCTAssertEqual (
305+ allTestCases. count,
306+ expectedTestCaseCount,
307+ " Test setup failed: Did not generate the correct number of test cases. "
308+ )
309+
310+ // 4. Loop through the complete, generated test matrix.
311+ for testCase in allTestCases {
312+
313+ // The makeCounter overload with labels handles the empty label case correctly.
314+ let counter = client. makeCounter ( descriptor: testCase. descriptor, labels: testCase. labels)
315+ counter. increment ( by: incrementValue)
316+
317+ var buffer = [ UInt8] ( )
318+ client. emit ( into: & buffer)
319+
320+ let actualOutput = String ( decoding: buffer, as: Unicode . UTF8. self)
321+
322+ let failureMessage = """
323+ Failed on test case: ' \( testCase. failureDescription) '
324+ - Descriptor: \( testCase. descriptor)
325+ - Labels: \( testCase. labels)
326+ - Expected Output:
327+ ---
328+ \( testCase. expectedOutput)
329+ ---
330+ - Actual Output:
331+ ---
332+ \( actualOutput)
333+ ---
334+ """
335+ XCTAssertEqual ( actualOutput, testCase. expectedOutput, failureMessage)
336+ client. unregisterCounter ( counter)
337+ }
338+ }
167339}
0 commit comments