@anysphere/file-service 0.0.0-ba159ee7 → 0.0.0-ba7f3496

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -3,18 +3,117 @@
3
3
 
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
- export class MerkleClient {
6
+ export const enum DiffType {
7
+ Insert = 'Insert',
8
+ Delete = 'Delete',
9
+ Equal = 'Equal'
10
+ }
11
+ export interface DiffChunk {
12
+ diffType: DiffType
13
+ text: string
14
+ }
15
+ export interface WalkDirConfig {
16
+ maxNumFiles: number
17
+ logFilePath?: string
18
+ blocklistPath?: string
19
+ unifiedJsonBlocklistPath?: string
20
+ }
21
+ export interface LocalCodebaseFileInfo {
22
+ unencryptedRelativePath: string
23
+ hash: string
24
+ children?: Array<LocalCodebaseFileInfo>
25
+ }
26
+ export interface CommitData {
27
+ sha: string
28
+ date: number
29
+ message: string
30
+ author: string
31
+ parents: Array<string>
32
+ files: Array<CommitFile>
33
+ }
34
+ export interface CommitFile {
35
+ from: string
36
+ to: string
37
+ additions: number
38
+ deletions: number
39
+ status: CommitFileStatus
40
+ }
41
+ export const enum CommitFileStatus {
42
+ Added = 0,
43
+ Deleted = 1,
44
+ Modified = 2,
45
+ Renamed = 3
46
+ }
47
+ export const enum CommitChainGetFiles {
48
+ DoGetFiles = 0,
49
+ DontGetFiles = 1
50
+ }
51
+ export interface VerifyData {
52
+ commitTime: number
53
+ fileContent: string
54
+ filePath: string
55
+ }
56
+ export declare class DiffClient {
57
+ constructor()
58
+ diff(text1: string, text2: string): Array<DiffChunk>
59
+ /**
60
+ * use https://docs.rs/diffmatchpatch/latest/diffmatchpatch/struct.DiffMatchPatch.html#method.diff_lines_to_chars
61
+ * then diff the chars.
62
+ * then convert back to lines.
63
+ *
64
+ * takes in two strings. splits based on newlines.
65
+ * returns diffs based on lines.
66
+ */
67
+ diffLines(text1: string, text2: string): Array<DiffChunk>
68
+ }
69
+ export declare class MerkleClient {
7
70
  constructor(absoluteRootDirectory: string)
8
- init(gitIgnoredFiles: Array<string>, isGitRepo: boolean): Promise<void>
9
- computeMerkleTree(gitIgnoredFiles: Array<string>, isGitRepo: boolean): Promise<void>
10
- updateFile(filePath: string): Promise<void>
11
- deleteFile(filePath: string): Promise<void>
71
+ build(allowIncremental: boolean, config: WalkDirConfig): Promise<void>
12
72
  getSubtreeHash(relativePath: string): Promise<string>
13
73
  getNumEmbeddableFiles(): Promise<number>
74
+ getSimhash(): Promise<Float32Array>
75
+ getImportantPaths(k: number): Promise<Array<string>>
14
76
  getAllFiles(): Promise<Array<string>>
15
77
  getAllDirFilesToEmbed(absoluteFilePath: string): Promise<Array<string>>
16
- getNextFileToEmbed(): Promise<Array<string>>
17
- getSpline(absoluteFilePath: string): Promise<Array<string>>
18
- getHashesForFiles(files: Array<string>): Promise<Array<string>>
19
- updateRootDirectory(rootDirectory: string): void
78
+ onDidCreate(absoluteFilePath: string): void
79
+ onDidChange(absoluteFilePath: string): void
80
+ onDidDelete(absoluteFilePath: string): void
81
+ static enableTracing(): void
82
+ getTreeStructure(): Promise<LocalCodebaseFileInfo | null>
83
+ }
84
+ export declare class GitClient {
85
+ constructor(absoluteRootDirectory: string)
86
+ getTotalCommitCount(): Promise<number>
87
+ getCommitVerifyData(commit: string): Promise<VerifyData>
88
+ throwIfCommitDoesntExist(rootSha: string): Promise<void>
89
+ getVerifyCommit(): Promise<string>
90
+ getRepoHeadSha(): Promise<string | null>
91
+ getCommitChain(hash: string, depth: number, getFiles: CommitChainGetFiles): Promise<Array<CommitData>>
92
+ }
93
+ export declare class GitGraph {
94
+ constructor(repo: string, globalCursorIgnoreLegacy?: string | undefined | null, globalCursorJsonUnifiedBlocklist?: string | undefined | null)
95
+ /**
96
+ * Get a list of all paths in this repository, up to a maximum depth of `max_depth`. The
97
+ * paths are returned breadth-first, meaning that all paths at depth 0 are returned before any
98
+ * paths at depth 1, and so on.
99
+ * The iteration takes into account `gitignore` and `cursorignore` rules.
100
+ *
101
+ * @param maxDepth - maximum depth to search for paths. A depth of 0 means only the root path
102
+ * is returned.
103
+ * @param limit - maximum number of paths to return. If `None`, all paths are returned.
104
+ */
105
+ getBfsPaths(maxDepth: number, limit?: number | undefined | null): Promise<Array<string>>
106
+ /**
107
+ * Get a sorted list of relevant paths in this repository, from most relevant to least
108
+ * relevant. The list is biased towards the current user, using a heuristic that takes into account
109
+ * the most recently opened/edited files in the editor, which must be passed in as
110
+ * `lastEditedFiles`. If no recent files are provided, the returned paths will be sorted
111
+ * based on the global popularity of the files in the repository (i.e. the number of times each
112
+ * file has been modified throughout the Git history).
113
+ *
114
+ * @param lastEditedFiles - list of files that were recently opened/edited in the editor.
115
+ * @param maxCommits - maximum number of commits to consider when calculating the relevant paths.
116
+ * @param maxPaths - number of relevant paths to return
117
+ */
118
+ getRelevantPaths(lastEditedFiles: Array<string>, maxCommits: number, maxPaths: number): Promise<Array<string>>
20
119
  }
package/index.js CHANGED
@@ -224,14 +224,72 @@ switch (platform) {
224
224
  }
225
225
  break
226
226
  case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'file_service.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./file_service.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@anysphere/file-service-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'file_service.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./file_service.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@anysphere/file-service-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'file_service.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./file_service.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@anysphere/file-service-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'file_service.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./file_service.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@anysphere/file-service-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
227
285
  localFileExisted = existsSync(
228
- join(__dirname, 'file_service.linux-arm-gnueabihf.node')
286
+ join(__dirname, 'file_service.linux-s390x-gnu.node')
229
287
  )
230
288
  try {
231
289
  if (localFileExisted) {
232
- nativeBinding = require('./file_service.linux-arm-gnueabihf.node')
290
+ nativeBinding = require('./file_service.linux-s390x-gnu.node')
233
291
  } else {
234
- nativeBinding = require('@anysphere/file-service-linux-arm-gnueabihf')
292
+ nativeBinding = require('@anysphere/file-service-linux-s390x-gnu')
235
293
  }
236
294
  } catch (e) {
237
295
  loadError = e
@@ -252,6 +310,12 @@ if (!nativeBinding) {
252
310
  throw new Error(`Failed to load native binding`)
253
311
  }
254
312
 
255
- const { MerkleClient } = nativeBinding
313
+ const { DiffType, DiffClient, MerkleClient, GitClient, CommitFileStatus, CommitChainGetFiles, GitGraph } = nativeBinding
256
314
 
315
+ module.exports.DiffType = DiffType
316
+ module.exports.DiffClient = DiffClient
257
317
  module.exports.MerkleClient = MerkleClient
318
+ module.exports.GitClient = GitClient
319
+ module.exports.CommitFileStatus = CommitFileStatus
320
+ module.exports.CommitChainGetFiles = CommitChainGetFiles
321
+ module.exports.GitGraph = GitGraph
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anysphere/file-service",
3
- "version": "0.0.0-ba159ee7",
3
+ "version": "0.0.0-ba7f3496",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "napi": {
@@ -14,9 +14,13 @@
14
14
  ]
15
15
  }
16
16
  },
17
+ "files": [
18
+ "index.js",
19
+ "index.d.ts"
20
+ ],
17
21
  "license": "MIT",
18
22
  "devDependencies": {
19
- "@napi-rs/cli": "^2.16.2",
23
+ "@napi-rs/cli": "^2.18.4",
20
24
  "ava": "^5.1.1"
21
25
  },
22
26
  "ava": {
@@ -36,12 +40,12 @@
36
40
  "version": "napi version"
37
41
  },
38
42
  "optionalDependencies": {
39
- "@anysphere/file-service-win32-x64-msvc": "0.0.0-ba159ee7",
40
- "@anysphere/file-service-darwin-x64": "0.0.0-ba159ee7",
41
- "@anysphere/file-service-linux-x64-gnu": "0.0.0-ba159ee7",
42
- "@anysphere/file-service-darwin-arm64": "0.0.0-ba159ee7",
43
- "@anysphere/file-service-win32-arm64-msvc": "0.0.0-ba159ee7",
44
- "@anysphere/file-service-darwin-universal": "0.0.0-ba159ee7",
45
- "@anysphere/file-service-linux-arm64-gnu": "0.0.0-ba159ee7"
43
+ "@anysphere/file-service-win32-x64-msvc": "0.0.0-ba7f3496",
44
+ "@anysphere/file-service-darwin-x64": "0.0.0-ba7f3496",
45
+ "@anysphere/file-service-linux-x64-gnu": "0.0.0-ba7f3496",
46
+ "@anysphere/file-service-darwin-arm64": "0.0.0-ba7f3496",
47
+ "@anysphere/file-service-win32-arm64-msvc": "0.0.0-ba7f3496",
48
+ "@anysphere/file-service-darwin-universal": "0.0.0-ba7f3496",
49
+ "@anysphere/file-service-linux-arm64-gnu": "0.0.0-ba7f3496"
46
50
  }
47
51
  }
package/.yarnrc.yml DELETED
@@ -1 +0,0 @@
1
- nodeLinker: node-modules
package/Cargo.toml DELETED
@@ -1,43 +0,0 @@
1
- [package]
2
- edition = "2021"
3
- name = "file_service"
4
- version = "0.0.0"
5
-
6
- [lib]
7
- crate-type = ["cdylib"]
8
-
9
- [features]
10
- default = ["windows-subsystem"]
11
- windows-subsystem = []
12
- debugfile = []
13
-
14
- [dependencies]
15
- # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
16
- napi = { version = "2.12.2", default-features = false, features = ["napi4", "async", "tokio_rt"] }
17
- napi-derive = "2.12.2"
18
- tokio = { version = "1.32.0", features = ["process", "full"] }
19
- sha2 = "0.10.7"
20
- rand = "0.8.5"
21
- tempfile = "3.8.0"
22
- anyhow = "1.0.75"
23
- tonic = "0.9.2"
24
- prost = "0.11.9"
25
- tracing = "0.1.37"
26
- tracing-subscriber = "0.3.17"
27
- tracing-appender = "0.2.2"
28
- binaryornot = "1.0.0"
29
- dunce = "1.0.1"
30
- encoding_rs = "0.8.33"
31
-
32
- [target.'cfg(not(target_os = "linux"))'.dependencies]
33
- tracing-axiom = "0.4"
34
-
35
- [build-dependencies]
36
- napi-build = "2.0.1"
37
- tonic-build = "0.9.2"
38
- anyhow = "1.0.75"
39
- glob = "0.3.0"
40
-
41
-
42
- [profile.release]
43
- lto = true
package/build.rs DELETED
@@ -1,46 +0,0 @@
1
- use std::path::Path;
2
-
3
- extern crate napi_build;
4
-
5
- fn main() -> Result<(), anyhow::Error> {
6
- #[cfg(target_os = "windows")]
7
- println!("cargo:rustc-cdylib-link-arg=/SUBSYSTEM:WINDOWS");
8
- napi_build::setup();
9
-
10
- // print the relative path.
11
- // let workspace_root = "../../../../../";
12
- // let path = std::path::Path::new(workspace_root).canonicalize()?;
13
- // let include_path = Path::join(&path, "schema");
14
-
15
- // // let relevant_protos = &[
16
- // // "aiserver/v1/repository.proto",
17
- // // "aiserver/v1/symbolic_context.proto",
18
- // // "aiserver/v1/utils.proto"
19
- // // ];
20
- // // let proto_paths = relevant_protos
21
- // // .iter()
22
- // // .map(|proto| Path::join(&include_path, proto))
23
- // // .collect::<Vec<_>>();
24
- // let proto_glob = Path::join(&include_path, "aiserver/v1/*.proto");
25
- // let relevant_protos: Vec<_> = glob::glob(proto_glob.to_str().expect("Failed to convert path to str"))?
26
- // .filter_map(Result::ok)
27
- // .collect();
28
-
29
- // let proto_paths = relevant_protos
30
- // .iter()
31
- // .map(|proto_path| proto_path.to_str().expect("Failed to convert path to str"))
32
- // .collect::<Vec<_>>();
33
- // let includes = &[include_path.to_str().unwrap()];
34
-
35
- // // print the path
36
- // println!("cargo:rustc-env=INCLUDE_PATH={}", include_path.display());
37
-
38
- // tonic_build::configure()
39
- // .build_server(false)
40
- // .build_transport(true)
41
- // .out_dir("src/proto")
42
- // .compile(&proto_paths, includes)?;
43
-
44
-
45
- Ok(())
46
- }
package/src/file_utils.rs DELETED
@@ -1,328 +0,0 @@
1
- // what methods do i want to support here.
2
- // 1. isInBadDir
3
- // 2. isBadFile
4
- // 3. vscode.workspace.asRelativePath
5
- // 4. vscode.fs.stat
6
-
7
- use anyhow::Error;
8
- use encoding_rs::UTF_8;
9
- use std::path::Path;
10
- use tokio::fs;
11
-
12
- pub fn is_in_bad_dir(file_path: &Path) -> Result<bool, Error> {
13
- let item_path = file_path
14
- .to_str()
15
- .ok_or(anyhow::anyhow!("Failed to convert path to string"))?;
16
- let is_bad_dir =
17
- item_path.contains("node_modules") || item_path.contains(".git");
18
- Ok(is_bad_dir)
19
- }
20
-
21
- pub fn is_good_file(file_path: &Path) -> Result<(), Error> {
22
- let item_path = file_path
23
- .to_str()
24
- .ok_or(anyhow::anyhow!("Failed to convert path to string"))?;
25
-
26
- let path = Path::new(item_path);
27
- let file_name = path
28
- .file_name()
29
- .ok_or(anyhow::anyhow!("Failed to get file name"))?
30
- .to_str()
31
- .ok_or(anyhow::anyhow!("Failed to convert file name to string"))?;
32
-
33
- let extension = path
34
- .extension()
35
- .ok_or(anyhow::anyhow!("Failed to get extension"))?
36
- .to_str()
37
- .ok_or(anyhow::anyhow!("Failed to convert extension to string"))?;
38
-
39
- match file_name {
40
- "package-lock.json" | "pnpm-lock.yaml" | "yarn.lock" | "composer.lock"
41
- | "Gemfile.lock" | "bun.lockb" => {
42
- return Err(anyhow::anyhow!("File is just a lock file"));
43
- }
44
- _ => {}
45
- }
46
-
47
- let bad_extensions = vec![
48
- "lock",
49
- "bak",
50
- "tmp",
51
- "bin",
52
- "exe",
53
- "dll",
54
- "so",
55
- "lockb",
56
- "qwoff",
57
- "isl",
58
- "csv",
59
- "pdf",
60
- // add ms word, excel, powerpoint, etc.
61
- "doc",
62
- "docx",
63
- "xls",
64
- "xlsx",
65
- "ppt",
66
- "pptx",
67
- "odt",
68
- "ods",
69
- "odp",
70
- "odg",
71
- "odf",
72
- "sxw",
73
- "sxc",
74
- "sxi",
75
- "sxd",
76
- "sdc",
77
- // add images
78
- "jpg",
79
- "jpeg",
80
- "png",
81
- "gif",
82
- "bmp",
83
- "tif",
84
- // add audio
85
- "mp3",
86
- "wav",
87
- "wma",
88
- "ogg",
89
- "flac",
90
- "aac",
91
- // add video
92
- "mp4",
93
- "mov",
94
- "wmv",
95
- "flv",
96
- "avi",
97
- // add archives
98
- "zip",
99
- "tar",
100
- "gz",
101
- "7z",
102
- "rar",
103
- "tgz",
104
- "dmg",
105
- "iso",
106
- "cue",
107
- "mdf",
108
- "mds",
109
- "vcd",
110
- "toast",
111
- "img",
112
- "apk",
113
- "msi",
114
- "cab",
115
- "tar.gz",
116
- "tar.xz",
117
- "tar.bz2",
118
- "tar.lzma",
119
- "tar.Z",
120
- "tar.sz",
121
- "lzma",
122
- // add fonts
123
- "ttf",
124
- "otf",
125
- "woff",
126
- "woff2",
127
- "eot",
128
- ];
129
- match bad_extensions.contains(&extension) {
130
- true => {
131
- return Err(anyhow::anyhow!("File is just a lock file"));
132
- }
133
- _ => {}
134
- }
135
-
136
- if item_path.contains(".git")
137
- || item_path.contains(".svn")
138
- || item_path.contains(".hg")
139
- {
140
- return Err(anyhow::anyhow!("File is just a lock file"));
141
- }
142
-
143
- let bad_extensions = vec![".exe", ".dll", ".so", ".o", ".bin"];
144
- match Path::new(item_path).extension() {
145
- Some(extension) => match extension.to_str() {
146
- Some(ext_str) => {
147
- if bad_extensions.contains(&ext_str) {
148
- return Err(anyhow::anyhow!("Binary file excluded from indexing."));
149
- }
150
- }
151
- None => {
152
- return Err(anyhow::anyhow!("Failed to convert extension to string"))
153
- }
154
- },
155
- None => return Err(anyhow::anyhow!("Failed to get extension")),
156
- }
157
-
158
- // #[cfg(not(test))]
159
- // {
160
- let path = Path::new(item_path);
161
- for part in path.iter() {
162
- match part.to_str() {
163
- Some(s) if s.starts_with(".") => {
164
- return Err(anyhow::anyhow!("File is hidden"))
165
- }
166
- _ => {}
167
- }
168
- }
169
- // }
170
-
171
- Ok(())
172
- }
173
-
174
- // use binaryornot::is_binary;
175
- // use anyhow::Context;
176
- // implement the buffer above:
177
- pub async fn is_good_file_runtime_check(
178
- file_path: &Path,
179
- // _buffer: &[u8],
180
- ) -> Result<(), Error> {
181
- match get_file_size(file_path).await {
182
- Ok(size) if size > 2 * 1024 * 1024 => {
183
- return Err(anyhow::anyhow!("Buffer is too large"));
184
- }
185
- Err(e) => return Err(e),
186
- _ => {}
187
- }
188
-
189
- // if is_binary(file_path).context("Failed to check if file is binary")? {
190
- // return Err(anyhow::anyhow!("File is binary"));
191
- // }
192
-
193
- Ok(())
194
- }
195
-
196
- pub async fn read_string_without_bom(
197
- file_path: &Path,
198
- ) -> Result<String, Error> {
199
- let file_buffer = match fs::read(file_path).await {
200
- Ok(buffer) => buffer,
201
- Err(e) => {
202
- return Err(anyhow::anyhow!(
203
- "Failed to read file buffer: {}",
204
- e.to_string()
205
- ))
206
- }
207
- };
208
-
209
- let (cow, _) = UTF_8.decode_with_bom_removal(&file_buffer);
210
-
211
- Ok(cow.to_string())
212
- }
213
-
214
- pub fn as_relative_path(
215
- base_path: &Path,
216
- file_path: &Path,
217
- ) -> Result<String, Error> {
218
- let relative_path = file_path.strip_prefix(base_path)?;
219
- Ok(
220
- relative_path
221
- .to_str()
222
- .ok_or(anyhow::anyhow!("Failed to convert relative path to string"))?
223
- .to_string(),
224
- )
225
- }
226
-
227
- pub async fn get_file_size(file_path: &Path) -> Result<u64, Error> {
228
- let metadata = fs::metadata(file_path).await?;
229
-
230
- Ok(metadata.len())
231
- }
232
-
233
- #[cfg(test)]
234
- mod tests {
235
- use super::*;
236
- use std::path::Path;
237
- use tokio::io::AsyncWriteExt;
238
-
239
- #[test]
240
- fn test_is_in_bad_dir() {
241
- let path = Path::new("src/node_modules/test.rs");
242
- assert_eq!(is_in_bad_dir(&path).unwrap(), true);
243
-
244
- let path = Path::new("src/.git/test.rs");
245
- assert_eq!(is_in_bad_dir(&path).unwrap(), true);
246
-
247
- let path = Path::new("src/test.rs");
248
- assert_eq!(is_in_bad_dir(&path).unwrap(), false);
249
- }
250
-
251
- #[test]
252
- fn test_is_good_file() {
253
- let path = Path::new("src/test.rs");
254
- assert_eq!(is_good_file(&path).is_ok(), true);
255
-
256
- let path = Path::new("src/test.exe");
257
- assert_eq!(is_good_file(&path).is_err(), true);
258
-
259
- let path = Path::new("src/.hidden");
260
- assert_eq!(is_good_file(&path).is_err(), true);
261
- }
262
-
263
- #[tokio::test]
264
- async fn test_is_good_file_runtime_check() {
265
- let temp_dir = tempfile::tempdir().unwrap();
266
- let temp_file_path = temp_dir.path().join("test_file");
267
- let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
268
- temp_file.write_all(b"Hello, world!").await.unwrap();
269
- let buffer = fs::read(&temp_file_path).await.unwrap();
270
- assert_eq!(
271
- is_good_file_runtime_check(&temp_file_path).await.is_ok(),
272
- true
273
- );
274
- temp_dir.close().unwrap();
275
-
276
- // let temp_dir = tempfile::tempdir().unwrap();
277
- // let temp_file_path = temp_dir.path().join("test_file");
278
- // let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
279
- // temp_file.write_all(&[0, 159, 146, 150]).await.unwrap(); // Invalid UTF-8 sequence
280
- // let buffer = fs::read(&temp_file_path).await.unwrap();
281
- // assert_eq!(
282
- // is_good_file_runtime_check(&temp_file_path).await.is_err(),
283
- // true
284
- // );
285
- // temp_dir.close().unwrap();
286
- }
287
-
288
- #[tokio::test]
289
- async fn test_bom_file() {
290
- const BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
291
- const CONTENT: &str = "Hello, world!";
292
-
293
- // Write this to a temp file
294
- let temp_dir = tempfile::tempdir().unwrap();
295
- let temp_file_path = temp_dir.path().join("test_file");
296
- let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
297
- temp_file.write_all(&BOM).await.unwrap();
298
- temp_file.write_all(CONTENT.as_bytes()).await.unwrap();
299
-
300
- // expect that we read the file with tokio as the CONTENT
301
- let file_contents = read_string_without_bom(&temp_file_path).await.unwrap();
302
-
303
- // Check string equality of CONTENT (&str) to file_contents (String)
304
- assert_eq!(CONTENT, file_contents);
305
- }
306
-
307
- #[test]
308
- fn test_as_relative_path() {
309
- let base_path = Path::new("/home/user/src");
310
- let file_path = Path::new("/home/user/src/test.rs");
311
- assert_eq!(as_relative_path(&base_path, &file_path).unwrap(), "test.rs");
312
-
313
- let file_path = Path::new("/home/user/test.rs");
314
- assert!(as_relative_path(&base_path, &file_path).is_err());
315
- }
316
-
317
- #[tokio::test]
318
- async fn test_get_file_size() {
319
- let temp_dir = tempfile::tempdir().unwrap();
320
- let temp_file_path = temp_dir.path().join("test_file.txt");
321
- let mut temp_file = fs::File::create(&temp_file_path).await.unwrap();
322
- temp_file.write_all(b"Hello, world!").await.unwrap();
323
-
324
- let size = get_file_size(&temp_file_path).await.unwrap();
325
- assert_eq!(size, 13);
326
- temp_dir.close().unwrap();
327
- }
328
- }