1+ #!/usr/bin/env node
2+ // Simple unit tests for AFK command parsing logic
3+
4+ const assert = require ( 'assert' ) ;
5+ const path = require ( 'path' ) ;
6+ const fs = require ( 'fs' ) ;
7+ const os = require ( 'os' ) ;
8+
9+ let testCounter = 0 ;
10+ let failures = [ ] ;
11+
12+ function runTest ( name , testFn ) {
13+ try {
14+ testCounter ++ ;
15+ testFn ( ) ;
16+ console . log ( `✅ ${ testCounter } . ${ name } ` ) ;
17+ return true ;
18+ } catch ( error ) {
19+ failures . push ( { name, error : error . message } ) ;
20+ console . log ( `❌ ${ testCounter } . ${ name } : ${ error . message } ` ) ;
21+ return false ;
22+ }
23+ }
24+
25+ // Test the command parsing logic in isolation
26+ function testCommandParsingLogic ( ) {
27+ // This mimics the parsing logic from handleUserPromptSubmit
28+ function parseAfkCommand ( prompt ) {
29+ if ( ! prompt . startsWith ( '/afk' ) ) {
30+ return null ; // Not an AFK command
31+ }
32+
33+ let subcommand , args ;
34+
35+ if ( prompt . includes ( ':' ) ) {
36+ // New format: /afk:on
37+ const colonIndex = prompt . indexOf ( ':' ) ;
38+ const afterColon = prompt . slice ( colonIndex + 1 ) ;
39+ const parts = afterColon . split ( / \s + / ) ;
40+ subcommand = parts [ 0 ] || 'toggle' ;
41+ args = parts . slice ( 1 ) . join ( ' ' ) ;
42+ } else {
43+ // Old format: /afk on
44+ const parts = prompt . slice ( 1 ) . split ( / \s + / ) ; // Remove leading '/'
45+ subcommand = parts [ 1 ] || 'toggle' ;
46+ args = parts . slice ( 2 ) . join ( ' ' ) ;
47+ }
48+
49+ return { subcommand, args } ;
50+ }
51+
52+ runTest ( 'Parse /afk:on command' , ( ) => {
53+ const result = parseAfkCommand ( '/afk:on' ) ;
54+ assert . strictEqual ( result . subcommand , 'on' ) ;
55+ assert . strictEqual ( result . args , '' ) ;
56+ } ) ;
57+
58+ runTest ( 'Parse /afk:off command' , ( ) => {
59+ const result = parseAfkCommand ( '/afk:off' ) ;
60+ assert . strictEqual ( result . subcommand , 'off' ) ;
61+ assert . strictEqual ( result . args , '' ) ;
62+ } ) ;
63+
64+ runTest ( 'Parse /afk:toggle command' , ( ) => {
65+ const result = parseAfkCommand ( '/afk:toggle' ) ;
66+ assert . strictEqual ( result . subcommand , 'toggle' ) ;
67+ assert . strictEqual ( result . args , '' ) ;
68+ } ) ;
69+
70+ runTest ( 'Parse /afk:status command' , ( ) => {
71+ const result = parseAfkCommand ( '/afk:status' ) ;
72+ assert . strictEqual ( result . subcommand , 'status' ) ;
73+ assert . strictEqual ( result . args , '' ) ;
74+ } ) ;
75+
76+ runTest ( 'Parse /afk:global on command' , ( ) => {
77+ const result = parseAfkCommand ( '/afk:global on' ) ;
78+ assert . strictEqual ( result . subcommand , 'global' ) ;
79+ assert . strictEqual ( result . args , 'on' ) ;
80+ } ) ;
81+
82+ runTest ( 'Parse /afk:global off command' , ( ) => {
83+ const result = parseAfkCommand ( '/afk:global off' ) ;
84+ assert . strictEqual ( result . args , 'off' ) ;
85+ } ) ;
86+
87+ runTest ( 'Parse /afk:project clear command' , ( ) => {
88+ const result = parseAfkCommand ( '/afk:project clear' ) ;
89+ assert . strictEqual ( result . subcommand , 'project' ) ;
90+ assert . strictEqual ( result . args , 'clear' ) ;
91+ } ) ;
92+
93+ runTest ( 'Parse legacy /afk on command' , ( ) => {
94+ const result = parseAfkCommand ( '/afk on' ) ;
95+ assert . strictEqual ( result . subcommand , 'on' ) ;
96+ assert . strictEqual ( result . args , '' ) ;
97+ } ) ;
98+
99+ runTest ( 'Parse legacy /afk off command' , ( ) => {
100+ const result = parseAfkCommand ( '/afk off' ) ;
101+ assert . strictEqual ( result . subcommand , 'off' ) ;
102+ assert . strictEqual ( result . args , '' ) ;
103+ } ) ;
104+
105+ runTest ( 'Parse legacy /afk toggle command' , ( ) => {
106+ const result = parseAfkCommand ( '/afk toggle' ) ;
107+ assert . strictEqual ( result . subcommand , 'toggle' ) ;
108+ assert . strictEqual ( result . args , '' ) ;
109+ } ) ;
110+
111+ runTest ( 'Parse legacy /afk global on command' , ( ) => {
112+ const result = parseAfkCommand ( '/afk global on' ) ;
113+ assert . strictEqual ( result . subcommand , 'global' ) ;
114+ assert . strictEqual ( result . args , 'on' ) ;
115+ } ) ;
116+
117+ runTest ( 'Parse /afk with no subcommand (should default to toggle)' , ( ) => {
118+ const result = parseAfkCommand ( '/afk' ) ;
119+ assert . strictEqual ( result . subcommand , 'toggle' ) ;
120+ assert . strictEqual ( result . args , '' ) ;
121+ } ) ;
122+
123+ runTest ( 'Parse /afk: with empty colon (should default to toggle)' , ( ) => {
124+ const result = parseAfkCommand ( '/afk:' ) ;
125+ assert . strictEqual ( result . subcommand , 'toggle' ) ;
126+ assert . strictEqual ( result . args , '' ) ;
127+ } ) ;
128+
129+ runTest ( 'Non-AFK command returns null' , ( ) => {
130+ const result = parseAfkCommand ( '/help' ) ;
131+ assert . strictEqual ( result , null ) ;
132+ } ) ;
133+
134+ runTest ( 'Regular text returns null' , ( ) => {
135+ const result = parseAfkCommand ( 'hello world' ) ;
136+ assert . strictEqual ( result , null ) ;
137+ } ) ;
138+
139+ runTest ( 'Empty command returns null' , ( ) => {
140+ const result = parseAfkCommand ( '' ) ;
141+ assert . strictEqual ( result , null ) ;
142+ } ) ;
143+ }
144+
145+ // Test that the subcommand structure matches the expected values
146+ function testSubcommandValidation ( ) {
147+ const validSubcommands = [ 'on' , 'off' , 'toggle' , 'status' , 'clear' , 'global' , 'project' , 'help' ] ;
148+ const validGlobalArgs = [ 'on' , 'off' , 'toggle' ] ;
149+ const validProjectArgs = [ 'on' , 'off' , 'clear' ] ;
150+
151+ runTest ( 'Valid basic subcommands' , ( ) => {
152+ [ 'on' , 'off' , 'toggle' , 'status' , 'clear' , 'help' ] . forEach ( cmd => {
153+ assert ( validSubcommands . includes ( cmd ) , `${ cmd } should be a valid subcommand` ) ;
154+ } ) ;
155+ } ) ;
156+
157+ runTest ( 'Valid global arguments' , ( ) => {
158+ [ 'on' , 'off' , 'toggle' ] . forEach ( arg => {
159+ assert ( validGlobalArgs . includes ( arg ) , `${ arg } should be a valid global argument` ) ;
160+ } ) ;
161+ } ) ;
162+
163+ runTest ( 'Valid project arguments' , ( ) => {
164+ [ 'on' , 'off' , 'clear' ] . forEach ( arg => {
165+ assert ( validProjectArgs . includes ( arg ) , `${ arg } should be a valid project argument` ) ;
166+ } ) ;
167+ } ) ;
168+ }
169+
170+ // Test message formatting expectations
171+ function testMessageFormatting ( ) {
172+ // Test that we can create expected messages for different commands
173+ function createExpectedMessage ( subcommand , args ) {
174+ switch ( subcommand ) {
175+ case 'on' :
176+ return 'Remote mode enabled for this session' ;
177+ case 'off' :
178+ return 'Remote mode disabled for this session' ;
179+ case 'status' :
180+ return 'AFK Mode Status' ;
181+ case 'help' :
182+ return 'AFK Commands Help' ;
183+ case 'clear' :
184+ return 'Session AFK mode override cleared' ;
185+ case 'global' :
186+ if ( args === 'on' ) return 'Global AFK mode enabled' ;
187+ if ( args === 'off' ) return 'Global AFK mode disabled' ;
188+ return 'Global AFK mode is currently' ;
189+ case 'project' :
190+ if ( args === 'on' ) return 'Project AFK mode enabled' ;
191+ if ( args === 'off' ) return 'Project AFK mode disabled' ;
192+ if ( args === 'clear' ) return 'Project AFK mode override cleared' ;
193+ return 'Project AFK mode' ;
194+ default :
195+ return 'Unknown AFK command' ;
196+ }
197+ }
198+
199+ runTest ( 'Expected messages for basic commands' , ( ) => {
200+ assert ( createExpectedMessage ( 'on' , '' ) . includes ( 'enabled' ) ) ;
201+ assert ( createExpectedMessage ( 'off' , '' ) . includes ( 'disabled' ) ) ;
202+ assert ( createExpectedMessage ( 'status' , '' ) . includes ( 'Status' ) ) ;
203+ assert ( createExpectedMessage ( 'help' , '' ) . includes ( 'Help' ) ) ;
204+ } ) ;
205+
206+ runTest ( 'Expected messages for global commands' , ( ) => {
207+ assert ( createExpectedMessage ( 'global' , 'on' ) . includes ( 'enabled' ) ) ;
208+ assert ( createExpectedMessage ( 'global' , 'off' ) . includes ( 'disabled' ) ) ;
209+ assert ( createExpectedMessage ( 'global' , '' ) . includes ( 'currently' ) ) ;
210+ } ) ;
211+
212+ runTest ( 'Expected messages for project commands' , ( ) => {
213+ assert ( createExpectedMessage ( 'project' , 'on' ) . includes ( 'enabled' ) ) ;
214+ assert ( createExpectedMessage ( 'project' , 'off' ) . includes ( 'disabled' ) ) ;
215+ assert ( createExpectedMessage ( 'project' , 'clear' ) . includes ( 'cleared' ) ) ;
216+ } ) ;
217+ }
218+
219+ // Main test runner
220+ function runAllTests ( ) {
221+ console . log ( '🧪 Running AFK Command Parsing Unit Tests\n' ) ;
222+
223+ testCommandParsingLogic ( ) ;
224+ testSubcommandValidation ( ) ;
225+ testMessageFormatting ( ) ;
226+
227+ console . log ( `\n📊 Results: ${ testCounter - failures . length } /${ testCounter } tests passed` ) ;
228+
229+ if ( failures . length > 0 ) {
230+ console . log ( '\n❌ Failed tests:' ) ;
231+ failures . forEach ( failure => {
232+ console . log ( ` • ${ failure . name } : ${ failure . error } ` ) ;
233+ } ) ;
234+ process . exit ( 1 ) ;
235+ }
236+
237+ console . log ( '\n✅ All command parsing tests passed!' ) ;
238+ }
239+
240+ // Run tests if this file is executed directly
241+ if ( require . main === module ) {
242+ runAllTests ( ) ;
243+ }
244+
245+ module . exports = {
246+ runAllTests
247+ } ;
0 commit comments