1+ import { describe , it , expect } from 'vitest'
2+ import { parseCSV } from '@/lib/utils'
3+
4+ describe ( 'CSV Header Validation' , ( ) => {
5+ const requiredHeaders = [ 'Timestamp' , 'User' , 'Model' , 'Requests Used' , 'Exceeds Monthly Quota' , 'Total Monthly Quota' ]
6+
7+ it ( 'should accept CSV with correct headers in exact case' , ( ) => {
8+ const csvWithCorrectHeaders = `"Timestamp","User","Model","Requests Used","Exceeds Monthly Quota","Total Monthly Quota"
9+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
10+
11+ expect ( ( ) => parseCSV ( csvWithCorrectHeaders ) ) . not . toThrow ( )
12+ } )
13+
14+ it ( 'should accept CSV with correct headers in different case' , ( ) => {
15+ const csvWithDifferentCase = `"timestamp","user","model","requests used","exceeds monthly quota","total monthly quota"
16+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
17+
18+ expect ( ( ) => parseCSV ( csvWithDifferentCase ) ) . not . toThrow ( )
19+ } )
20+
21+ it ( 'should accept CSV with extra columns beyond required ones' , ( ) => {
22+ const csvWithExtraColumns = `"Timestamp","User","Model","Requests Used","Exceeds Monthly Quota","Total Monthly Quota","Extra Column"
23+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100,extra-data`
24+
25+ expect ( ( ) => parseCSV ( csvWithExtraColumns ) ) . not . toThrow ( )
26+ } )
27+
28+ it ( 'should reject CSV missing required columns' , ( ) => {
29+ const csvMissingColumns = `"Timestamp","User","Model","Requests Used","Wrong Column","Another Column"
30+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
31+
32+ expect ( ( ) => parseCSV ( csvMissingColumns ) ) . toThrow (
33+ 'CSV is missing required columns: Exceeds Monthly Quota, Total Monthly Quota. Expected columns: Timestamp, User, Model, Requests Used, Exceeds Monthly Quota, Total Monthly Quota'
34+ )
35+ } )
36+
37+ it ( 'should reject CSV with too few total columns' , ( ) => {
38+ const csvTooFewColumns = `"Timestamp","User","Model"
39+ 2024-01-01T00:00:00Z,user1,gpt-4`
40+
41+ expect ( ( ) => parseCSV ( csvTooFewColumns ) ) . toThrow ( 'CSV header must contain at least 6 columns' )
42+ } )
43+
44+ it ( 'should reject CSV missing specific required columns with detailed error message' , ( ) => {
45+ const csvMissingSpecificColumns = `"Timestamp","User","Model","Requests Used","Wrong Column","Total Monthly Quota"
46+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
47+
48+ expect ( ( ) => parseCSV ( csvMissingSpecificColumns ) ) . toThrow (
49+ 'CSV is missing required columns: Exceeds Monthly Quota. Expected columns: Timestamp, User, Model, Requests Used, Exceeds Monthly Quota, Total Monthly Quota'
50+ )
51+ } )
52+
53+ it ( 'should validate that headers are present regardless of order (but data parsing expects fixed order)' , ( ) => {
54+ // Note: The current implementation validates headers are present but still reads data by fixed positions
55+ // This test verifies that header validation works, but the data parsing might fail if order is wrong
56+ const csvDifferentOrder = `"User","Timestamp","Model","Total Monthly Quota","Requests Used","Exceeds Monthly Quota"
57+ user1,2024-01-01T00:00:00Z,gpt-4,100,1.5,false`
58+
59+ // This should not throw a header validation error (headers are all present)
60+ // But it may throw a data parsing error since data is in wrong order
61+ expect ( ( ) => parseCSV ( csvDifferentOrder ) ) . toThrow ( 'Invalid timestamp format at line 2' )
62+ } )
63+
64+ it ( 'should handle CSV with mixed case headers and validate correctly' , ( ) => {
65+ const csvMixedCase = `"TIMESTAMP","user","Model","REQUESTS USED","exceeds monthly quota","Total Monthly Quota"
66+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
67+
68+ expect ( ( ) => parseCSV ( csvMixedCase ) ) . not . toThrow ( )
69+ } )
70+
71+ it ( 'should handle CSV with whitespace in headers' , ( ) => {
72+ const csvWithWhitespace = `" Timestamp "," User "," Model "," Requests Used "," Exceeds Monthly Quota "," Total Monthly Quota "
73+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
74+
75+ expect ( ( ) => parseCSV ( csvWithWhitespace ) ) . not . toThrow ( )
76+
77+ const result = parseCSV ( csvWithWhitespace )
78+ expect ( result ) . toHaveLength ( 1 )
79+ expect ( result [ 0 ] ) . toEqual ( {
80+ timestamp : new Date ( '2024-01-01T00:00:00Z' ) ,
81+ user : 'user1' ,
82+ model : 'gpt-4' ,
83+ requestsUsed : 1.5 ,
84+ exceedsQuota : false ,
85+ totalMonthlyQuota : '100'
86+ } )
87+ } )
88+
89+ it ( 'should validate data types correctly with valid headers' , ( ) => {
90+ const validCsv = `"Timestamp","User","Model","Requests Used","Exceeds Monthly Quota","Total Monthly Quota"
91+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
92+
93+ const result = parseCSV ( validCsv )
94+ expect ( result ) . toHaveLength ( 1 )
95+ expect ( result [ 0 ] ) . toEqual ( {
96+ timestamp : new Date ( '2024-01-01T00:00:00Z' ) ,
97+ user : 'user1' ,
98+ model : 'gpt-4' ,
99+ requestsUsed : 1.5 ,
100+ exceedsQuota : false ,
101+ totalMonthlyQuota : '100'
102+ } )
103+ } )
104+
105+ it ( 'should validate multiple data rows with correct headers' , ( ) => {
106+ const csvMultipleRows = `"Timestamp","User","Model","Requests Used","Exceeds Monthly Quota","Total Monthly Quota"
107+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100
108+ 2024-01-01T01:00:00Z,user2,gpt-3.5-turbo,2.0,true,50`
109+
110+ const result = parseCSV ( csvMultipleRows )
111+ expect ( result ) . toHaveLength ( 2 )
112+ expect ( result [ 1 ] ) . toEqual ( {
113+ timestamp : new Date ( '2024-01-01T01:00:00Z' ) ,
114+ user : 'user2' ,
115+ model : 'gpt-3.5-turbo' ,
116+ requestsUsed : 2.0 ,
117+ exceedsQuota : true ,
118+ totalMonthlyQuota : '50'
119+ } )
120+ } )
121+
122+ it ( 'should reject CSV with headers that contain required words but are not exact matches' , ( ) => {
123+ // This test ensures exact header matching, not substring matching
124+ const csvWithSimilarHeaders = `"Event Timestamp","System User","Model Type","Total Requests Used","User Exceeds Monthly Quota","Total Monthly Quota Limit"
125+ 2024-01-01T00:00:00Z,user1,gpt-4,1.5,false,100`
126+
127+ expect ( ( ) => parseCSV ( csvWithSimilarHeaders ) ) . toThrow (
128+ 'CSV is missing required columns: Timestamp, User, Model, Requests Used, Exceeds Monthly Quota, Total Monthly Quota'
129+ )
130+ } )
131+ } )
0 commit comments