@@ -164,4 +164,109 @@ 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 : [ ( namespace: String ? , subsystem: String ? , unitName: String ? , expectedMetricName: String , description: String ) ] = [
177+ ( namespace: " myapp " , subsystem: " subsystem " , unitName: " total " , expectedMetricName: " myapp_subsystem_foo2_total " , description: " All components present " ) ,
178+ ( namespace: " myapp " , subsystem: " subsystem " , unitName: nil , expectedMetricName: " myapp_subsystem_foo2 " , description: " Unit is nil " ) ,
179+ ( namespace: " myapp " , subsystem: nil , unitName: " total " , expectedMetricName: " myapp_foo2_total " , description: " Subsystem is nil " ) ,
180+ ( namespace: " myapp " , subsystem: nil , unitName: nil , expectedMetricName: " myapp_foo2 " , description: " Subsystem and Unit are nil " ) ,
181+ ( namespace: nil , subsystem: " subsystem " , unitName: " total " , expectedMetricName: " subsystem_foo2_total " , description: " Namespace is nil " ) ,
182+ ( namespace: nil , subsystem: " subsystem " , unitName: nil , expectedMetricName: " subsystem_foo2 " , description: " Namespace and Unit are nil " ) ,
183+ ( namespace: nil , subsystem: nil , unitName: " total " , expectedMetricName: " foo2_total " , description: " Namespace and Subsystem are nil " ) ,
184+ ( namespace: nil , subsystem: nil , unitName: nil , expectedMetricName: " foo2 " , description: " Only metric name is present " ) ,
185+ ( namespace: " " , subsystem: " subsystem " , unitName: " total " , expectedMetricName: " subsystem_foo2_total " , description: " Namespace is empty string " ) ,
186+ ( namespace: " myapp " , subsystem: " " , unitName: " total " , expectedMetricName: " myapp_foo2_total " , description: " Subsystem is empty string " ) ,
187+ ( namespace: " myapp " , subsystem: " subsystem " , unitName: " " , expectedMetricName: " myapp_subsystem_foo2 " , description: " Unit is empty string " ) ,
188+ ( namespace: " " , subsystem: " " , unitName: " total " , expectedMetricName: " foo2_total " , description: " Namespace and Subsystem are empty strings " ) ,
189+ ( namespace: " myapp " , subsystem: " " , unitName: " " , expectedMetricName: " myapp_foo2 " , description: " Subsystem and Unit are empty strings " ) ,
190+ ( namespace: " " , subsystem: " subsystem " , unitName: " " , expectedMetricName: " subsystem_foo2 " , description: " Namespace and Unit are empty strings " ) ,
191+ ( namespace: " " , subsystem: " " , unitName: " " , expectedMetricName: " foo2 " , description: " All optional components are empty strings " )
192+ ]
193+
194+ // 2. Define the label combinations to test.
195+ let labelCases : [ ( labels: [ ( String , String ) ] , expectedLabelString: String , description: String ) ] = [
196+ ( labels: [ ] , expectedLabelString: " " , description: " without labels " ) ,
197+ ( labels: [ ( " method " , " get " ) ] , expectedLabelString: " {method= \" get \" } " , description: " with one label " ) ,
198+ ( labels: [ ( " status " , " 200 " ) , ( " path " , " /api/v1 " ) ] , expectedLabelString: " {status= \" 200 \" ,path= \" /api/v1 \" } " , description: " with two labels " ) ,
199+ ]
200+
201+ // 3. Programmatically generate the final, full matrix by crossing name cases with label cases.
202+ var allTestCases : [ ( descriptor: FQMetricDescriptor , labels: [ ( String , String ) ] , expectedOutput: String , failureDescription: String ) ] = [ ]
203+
204+ for nameCase in baseNameCases {
205+ for labelCase in labelCases {
206+ let expectedMetricLine = " \( nameCase. expectedMetricName) \( labelCase. expectedLabelString) \( incrementValue) "
207+
208+ // todo : add help text in next PR
209+ // Case 1: With help text (currently disabled/commented out)
210+ // allTestCases.append((
211+ // descriptor: FQMetricDescriptor(
212+ // namespace: nameCase.namespace, subsystem: nameCase.subsystem, metricName: metricName, unitName: nameCase.unitName, helpText: helpTextValue
213+ // ),
214+ // labels: labelCase.labels,
215+ // expectedOutput: """
216+ // # HELP \(nameCase.expectedMetricName) \(helpTextValue)
217+ // # TYPE \(nameCase.expectedMetricName) counter
218+ // \(expectedMetricLine)
219+ //
220+ // """,
221+ // failureDescription: "\(nameCase.description), \(labelCase.description), with help text"
222+ // ))
223+
224+ // Case 2: Without help text (helpText is nil)
225+ allTestCases. append ( (
226+ descriptor: FQMetricDescriptor (
227+ namespace: nameCase. namespace, subsystem: nameCase. subsystem, metricName: metricName, unitName: nameCase. unitName, helpText: nil
228+ ) ,
229+ labels: labelCase. labels,
230+ expectedOutput: """
231+ # TYPE \( nameCase. expectedMetricName) counter
232+ \( expectedMetricLine)
233+
234+ """ ,
235+ failureDescription: " \( nameCase. description) , \( labelCase. description) , without help text "
236+ ) )
237+ }
238+ }
239+
240+ let expectedTestCaseCount = baseNameCases. count * labelCases. count
241+ XCTAssertEqual ( allTestCases. count, expectedTestCaseCount, " Test setup failed: Did not generate the correct number of test cases. " )
242+
243+ // 4. Loop through the complete, generated test matrix.
244+ for testCase in allTestCases {
245+
246+ // The makeCounter overload with labels handles the empty label case correctly.
247+ let counter = client. makeCounter ( descriptor: testCase. descriptor, labels: testCase. labels)
248+ counter. increment ( by: incrementValue)
249+
250+ var buffer = [ UInt8] ( )
251+ client. emit ( into: & buffer)
252+
253+ let actualOutput = String ( decoding: buffer, as: Unicode . UTF8. self)
254+
255+ let failureMessage = """
256+ Failed on test case: ' \( testCase. failureDescription) '
257+ - Descriptor: \( testCase. descriptor)
258+ - Labels: \( testCase. labels)
259+ - Expected Output:
260+ ---
261+ \( testCase. expectedOutput)
262+ ---
263+ - Actual Output:
264+ ---
265+ \( actualOutput)
266+ ---
267+ """
268+ XCTAssertEqual ( actualOutput, testCase. expectedOutput, failureMessage)
269+ client. unregisterCounter ( counter)
270+ }
271+ }
167272}
0 commit comments