1+ import { expect } from 'chai' ;
2+ import fs from 'fs' ;
3+ import path from 'path' ;
4+ import { fileURLToPath } from 'url' ;
5+
6+ import {
7+ createBinaryPlist ,
8+ createPlist ,
9+ createXmlPlist ,
10+ isBinaryPlist ,
11+ parseBinaryPlist ,
12+ parsePlist ,
13+ parseXmlPlist ,
14+ } from '../../../src/lib/plist/index.js' ;
15+ import type { PlistDictionary } from '../../../src/lib/types.js' ;
16+
17+ // Get the directory name
18+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
19+ const FIXTURES_PATH = path . join ( __dirname , 'fixtures' ) ;
20+
21+ describe ( 'Plist Module' , function ( ) {
22+ let sampleXmlPlistPath : string ;
23+ let sampleXmlPlistContent : string ;
24+ let sampleBinaryPlistPath : string ;
25+ let sampleBinaryPlistContent : Buffer ;
26+ let expectedPlistObject : PlistDictionary ;
27+
28+ before ( function ( ) {
29+ sampleXmlPlistPath = path . join ( FIXTURES_PATH , 'sample.xml.plist' ) ;
30+ sampleXmlPlistContent = fs . readFileSync ( sampleXmlPlistPath , 'utf8' ) ;
31+
32+ sampleBinaryPlistPath = path . join ( FIXTURES_PATH , 'sample.binary.plist' ) ;
33+ sampleBinaryPlistContent = fs . readFileSync ( sampleBinaryPlistPath ) ;
34+
35+ // Define the expected object structure that should match our XML plist
36+ expectedPlistObject = {
37+ stringValue : 'Hello, World!' ,
38+ integerValue : 42 ,
39+ realValue : 3.14159 ,
40+ booleanTrue : true ,
41+ booleanFalse : false ,
42+ dateValue : new Date ( '2023-01-01T12:00:00Z' ) ,
43+ dataValue : Buffer . from ( 'Hello, World!' ) ,
44+ arrayValue : [ 'Item 1' , 'Item 2' , 3 ] ,
45+ dictValue : {
46+ nestedKey : 'Nested Value' ,
47+ nestedArray : [ 1 , 2 ] ,
48+ } ,
49+ specialChars : '<Hello & World>' ,
50+ } ;
51+ } ) ;
52+
53+ describe ( 'XML Plist Functions' , function ( ) {
54+ it ( 'should parse XML plists correctly' , function ( ) {
55+ const result = parseXmlPlist ( sampleXmlPlistContent ) ;
56+
57+ // Basic types
58+ expect ( result ) . to . be . an ( 'object' ) ;
59+ expect ( result ) . to . have . property ( 'stringValue' , 'Hello, World!' ) ;
60+ expect ( result ) . to . have . property ( 'integerValue' , 42 ) ;
61+ expect ( result ) . to . have . property ( 'realValue' ) . that . is . closeTo ( 3.14159 , 0.00001 ) ;
62+ expect ( result ) . to . have . property ( 'booleanTrue' , true ) ;
63+ expect ( result ) . to . have . property ( 'booleanFalse' , false ) ;
64+
65+ // Complex types
66+ expect ( result ) . to . have . property ( 'arrayValue' ) . that . is . an ( 'array' ) . with . lengthOf ( 3 ) ;
67+ expect ( result ) . to . have . property ( 'dictValue' ) . that . is . an ( 'object' ) ;
68+ expect ( result ) . to . have . property ( 'specialChars' , '<Hello & World>' ) ;
69+
70+ // Error handling
71+ expect ( ( ) => parseXmlPlist ( '<invalid>xml</>' ) )
72+ . to . throw ( ) ;
73+ } ) ;
74+
75+ it ( 'should create XML plists correctly' , function ( ) {
76+ const xmlContent = createXmlPlist ( expectedPlistObject ) ;
77+
78+ // Check structure
79+ expect ( xmlContent ) . to . include ( '<?xml version="1.0" encoding="UTF-8"?>' ) ;
80+ expect ( xmlContent ) . to . include ( '<!DOCTYPE plist' ) ;
81+ expect ( xmlContent ) . to . include ( '<plist version="1.0">' ) ;
82+
83+ // Check content
84+ expect ( xmlContent ) . to . include ( '<key>stringValue</key>' ) ;
85+ expect ( xmlContent ) . to . include ( '<string>Hello, World!</string>' ) ;
86+ expect ( xmlContent ) . to . include ( '<key>integerValue</key>' ) ;
87+ expect ( xmlContent ) . to . include ( '<integer>42</integer>' ) ;
88+ expect ( xmlContent ) . to . include ( '<Hello & World>' ) ;
89+
90+ // Round-trip test
91+ const parsedBack = parseXmlPlist ( xmlContent ) ;
92+ expect ( parsedBack ) . to . have . property ( 'stringValue' , 'Hello, World!' ) ;
93+ expect ( parsedBack ) . to . have . property ( 'integerValue' , 42 ) ;
94+ } ) ;
95+ } ) ;
96+
97+ describe ( 'Binary Plist Functions' , function ( ) {
98+ it ( 'should detect, create and parse binary plists' , function ( ) {
99+ // Detection
100+ const binaryPlist = createBinaryPlist ( expectedPlistObject ) ;
101+ expect ( isBinaryPlist ( binaryPlist ) ) . to . be . true ;
102+ expect ( isBinaryPlist ( Buffer . from ( sampleXmlPlistContent ) ) ) . to . be . false ;
103+
104+ // Create and verify
105+ expect ( Buffer . isBuffer ( binaryPlist ) ) . to . be . true ;
106+ expect ( binaryPlist . slice ( 0 , 6 ) . toString ( ) ) . to . equal ( 'bplist' ) ;
107+
108+ // Parse
109+ const parsedObj = parseBinaryPlist ( sampleBinaryPlistContent ) as Record < string , any > ;
110+ expect ( parsedObj ) . to . be . an ( 'object' ) ;
111+ expect ( parsedObj ) . to . have . property ( 'stringValue' , 'Hello, World!' ) ;
112+ expect ( parsedObj ) . to . have . property ( 'integerValue' , 42 ) ;
113+ expect ( parsedObj ) . to . have . property ( 'realValue' ) . that . is . closeTo ( 3.14159 , 0.00001 ) ;
114+ expect ( parsedObj ) . to . have . property ( 'booleanTrue' , true ) ;
115+ expect ( parsedObj ) . to . have . property ( 'booleanFalse' , false ) ;
116+ } ) ;
117+ } ) ;
118+
119+ describe ( 'Unified Plist Functions' , function ( ) {
120+ it ( 'should auto-detect and parse both XML and binary plists' , function ( ) {
121+ // XML parsing
122+ const xmlResult = parsePlist ( sampleXmlPlistContent ) as Record < string , any > ;
123+ expect ( xmlResult ) . to . be . an ( 'object' ) ;
124+ expect ( xmlResult ) . to . have . property ( 'stringValue' , 'Hello, World!' ) ;
125+ expect ( xmlResult ) . to . have . property ( 'integerValue' , 42 ) ;
126+
127+ // Binary parsing
128+ const binaryResult = parsePlist ( sampleBinaryPlistContent ) as Record < string , any > ;
129+ expect ( binaryResult ) . to . be . an ( 'object' ) ;
130+ expect ( binaryResult ) . to . have . property ( 'stringValue' , 'Hello, World!' ) ;
131+ expect ( binaryResult ) . to . have . property ( 'integerValue' , 42 ) ;
132+
133+ // Error handling
134+ expect ( ( ) => parsePlist ( 'not a plist' ) ) . to . throw ( ) ;
135+ } ) ;
136+
137+ it ( 'should create plists in both formats' , function ( ) {
138+ // Default XML creation
139+ const xmlResult = createPlist ( expectedPlistObject ) ;
140+ expect ( xmlResult ) . to . be . a ( 'string' ) ;
141+ expect ( xmlResult as string ) . to . include ( '<?xml version="1.0"' ) ;
142+
143+ // Binary creation
144+ const binaryResult = createPlist ( expectedPlistObject , true ) ;
145+ expect ( Buffer . isBuffer ( binaryResult ) ) . to . be . true ;
146+ expect ( isBinaryPlist ( binaryResult as Buffer ) ) . to . be . true ;
147+ } ) ;
148+ } ) ;
149+
150+ describe ( 'Edge Cases and Data Types' , function ( ) {
151+ it ( 'should handle various data types and edge cases' , function ( ) {
152+ const complexObj : PlistDictionary = {
153+ nullValue : null ,
154+ emptyString : '' ,
155+ zero : 0 ,
156+ negativeNumber : - 42 ,
157+ largeNumber : 9007199254740991 , // Max safe integer
158+ emptyArray : [ ] ,
159+ emptyDict : { } ,
160+ booleanArray : [ true , false , true ] ,
161+ mixedArray : [ 1 , 'string' , true , null , { key : 'value' } ] ,
162+ } ;
163+
164+ // Test round-trip through XML format
165+ const xmlResult = createXmlPlist ( complexObj ) ;
166+ const parsedXmlObj = parseXmlPlist ( xmlResult ) as Record < string , any > ;
167+
168+ // Verify key data types are preserved
169+ expect ( parsedXmlObj ) . to . have . property ( 'emptyString' , '' ) ;
170+ expect ( parsedXmlObj ) . to . have . property ( 'zero' , 0 ) ;
171+ expect ( parsedXmlObj ) . to . have . property ( 'negativeNumber' , - 42 ) ;
172+ expect ( parsedXmlObj ) . to . have . property ( 'largeNumber' , 9007199254740991 ) ;
173+ expect ( parsedXmlObj ) . to . have . property ( 'emptyArray' ) . that . is . an ( 'array' ) . with . lengthOf ( 0 ) ;
174+ expect ( parsedXmlObj ) . to . have . property ( 'emptyDict' ) . that . is . an ( 'object' ) ;
175+ expect ( parsedXmlObj ) . to . have . property ( 'booleanArray' ) . that . is . an ( 'array' ) . with . lengthOf ( 3 ) ;
176+
177+ // Empty object test
178+ const emptyObj = { } ;
179+ const emptyXmlResult = createXmlPlist ( emptyObj ) ;
180+ const parsedEmptyXml = parseXmlPlist ( emptyXmlResult ) ;
181+ expect ( parsedEmptyXml ) . to . deep . equal ( { } ) ;
182+ } ) ;
183+ } ) ;
184+ } ) ;
0 commit comments