@@ -6,16 +6,110 @@ import { isWindows } from '@theia/core/lib/common/os';
66import { FileUri } from '@theia/core/lib/node/file-uri' ;
77import { Container } from '@theia/core/shared/inversify' ;
88import { expect } from 'chai' ;
9+ import { rejects } from 'node:assert/strict' ;
910import { promises as fs } from 'node:fs' ;
1011import { basename , join } from 'node:path' ;
1112import { sync as rimrafSync } from 'rimraf' ;
13+ import temp from 'temp' ;
1214import { Sketch , SketchesService } from '../../common/protocol' ;
13- import { SketchesServiceImpl } from '../../node/sketches-service-impl' ;
15+ import {
16+ isAccessibleSketchPath ,
17+ SketchesServiceImpl ,
18+ } from '../../node/sketches-service-impl' ;
1419import { ErrnoException } from '../../node/utils/errors' ;
1520import { createBaseContainer , startDaemon } from './test-bindings' ;
1621
1722const testTimeout = 10_000 ;
1823
24+ describe ( 'isAccessibleSketchPath' , ( ) => {
25+ let tracked : typeof temp ;
26+ let testDirPath : string ;
27+
28+ before ( ( ) => ( tracked = temp . track ( ) ) ) ;
29+ beforeEach ( ( ) => ( testDirPath = tracked . mkdirSync ( ) ) ) ;
30+ after ( ( ) => tracked . cleanupSync ( ) ) ;
31+
32+ it ( 'should be accessible by the main sketch file' , async ( ) => {
33+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
34+ const mainSketchFilePath = join ( sketchFolderPath , 'my_sketch.ino' ) ;
35+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
36+ await fs . writeFile ( mainSketchFilePath , '' , { encoding : 'utf8' } ) ;
37+ const actual = await isAccessibleSketchPath ( mainSketchFilePath ) ;
38+ expect ( actual ) . to . be . equal ( mainSketchFilePath ) ;
39+ } ) ;
40+
41+ it ( 'should be accessible by the sketch folder' , async ( ) => {
42+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
43+ const mainSketchFilePath = join ( sketchFolderPath , 'my_sketch.ino' ) ;
44+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
45+ await fs . writeFile ( mainSketchFilePath , '' , { encoding : 'utf8' } ) ;
46+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
47+ expect ( actual ) . to . be . equal ( mainSketchFilePath ) ;
48+ } ) ;
49+
50+ it ( 'should be accessible when the sketch folder and main sketch file basenames are different' , async ( ) => {
51+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
52+ const mainSketchFilePath = join ( sketchFolderPath , 'other_name_sketch.ino' ) ;
53+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
54+ await fs . writeFile ( mainSketchFilePath , '' , { encoding : 'utf8' } ) ;
55+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
56+ expect ( actual ) . to . be . equal ( mainSketchFilePath ) ;
57+ } ) ;
58+
59+ it ( 'should be deterministic (and sort by basename) when multiple sketch files exist' , async ( ) => {
60+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
61+ const aSketchFilePath = join ( sketchFolderPath , 'a.ino' ) ;
62+ const bSketchFilePath = join ( sketchFolderPath , 'b.ino' ) ;
63+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
64+ await fs . writeFile ( aSketchFilePath , '' , { encoding : 'utf8' } ) ;
65+ await fs . writeFile ( bSketchFilePath , '' , { encoding : 'utf8' } ) ;
66+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
67+ expect ( actual ) . to . be . equal ( aSketchFilePath ) ;
68+ } ) ;
69+
70+ it ( 'should ignore EACCESS' , async ( ) => {
71+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
72+ const mainSketchFilePath = join ( sketchFolderPath , 'my_sketch.ino' ) ;
73+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
74+ await fs . writeFile ( mainSketchFilePath , '' , { encoding : 'utf8' } ) ;
75+ await fs . chmod ( mainSketchFilePath , 0o000 ) ; // remove all permissions
76+ await rejects ( fs . readFile ( mainSketchFilePath ) , ErrnoException . isEACCES ) ;
77+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
78+ expect ( actual ) . to . be . equal ( mainSketchFilePath ) ;
79+ } ) ;
80+
81+ it ( "should not be accessible when there are no '.ino' files in the folder" , async ( ) => {
82+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
83+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
84+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
85+ expect ( actual ) . to . be . undefined ;
86+ } ) ;
87+
88+ it ( "should not be accessible when the main sketch file extension is not '.ino'" , async ( ) => {
89+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
90+ const mainSketchFilePath = join ( sketchFolderPath , 'my_sketch.cpp' ) ;
91+ await fs . mkdir ( sketchFolderPath , { recursive : true } ) ;
92+ await fs . writeFile ( mainSketchFilePath , '' , { encoding : 'utf8' } ) ;
93+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
94+ expect ( actual ) . to . be . undefined ;
95+ } ) ;
96+
97+ it ( 'should handle ENOENT' , async ( ) => {
98+ const sketchFolderPath = join ( testDirPath , 'my_sketch' ) ;
99+ const actual = await isAccessibleSketchPath ( sketchFolderPath ) ;
100+ expect ( actual ) . to . be . undefined ;
101+ } ) ;
102+
103+ it ( 'should handle UNKNOWN (Windows)' , async function ( ) {
104+ if ( ! isWindows ) {
105+ return this . skip ( ) ;
106+ }
107+ this . timeout ( 60_000 ) ;
108+ const actual = isAccessibleSketchPath ( '\\\\10.0.0.200\\path' ) ;
109+ expect ( actual ) . to . be . undefined ;
110+ } ) ;
111+ } ) ;
112+
19113describe ( 'sketches-service-impl' , ( ) => {
20114 let container : Container ;
21115 let toDispose : DisposableCollection ;
0 commit comments