Integrate elm App with Tauri. Can navigate into source directory.

This commit is contained in:
Pascal Le Merrer 2026-01-19 14:13:52 +01:00
commit 94003989ef
50 changed files with 41456 additions and 0 deletions

250
src-elm/tests/FileTest.elm Normal file
View file

@ -0,0 +1,250 @@
module FileTest exposing (suite)
import Expect
import File exposing (File, FileStatus(..), extendSelectionToNext, extendSelectionToPrevious, selectNext, selectPrevious, selectSimilar, withStatus)
import Fixtures exposing (filteredDir1, filteredDir2, filteredDir3, filteredDir4, filteredDir5, filteredDir6, filteredDir7, filteredDir8)
import Iso8601
import Json.Decode exposing (Decoder, decodeString)
import Test exposing (Test, describe, test)
import Time exposing (millisToPosix)
suite : Test
suite =
describe "File module"
[ test "selectNext selects the next file" <|
\_ ->
let
actual : List File
actual =
selectNext
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3
, filteredDir4
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir2
, filteredDir3 |> withStatus Selected
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "selectNext does nothing when the currently selected file is the last" <|
\_ ->
let
actual : List File
actual =
selectNext expected
expected : List File
expected =
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5 |> withStatus Selected
]
in
Expect.equal expected actual
, test "selectNext selects the last file in a list when none is selected" <|
\_ ->
let
actual : List File
actual =
selectNext
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5 |> withStatus Selected
]
in
Expect.equal expected actual
, test "selectPrevious selects the previous file in a list when there is one" <|
\_ ->
let
actual : List File
actual =
selectPrevious
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4 |> withStatus Selected
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir2
, filteredDir3 |> withStatus Selected
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "selectPrevious does nothing when the currently selected file is the first" <|
\_ ->
let
actual : List File
actual =
selectPrevious expected
expected : List File
expected =
[ filteredDir1 |> withStatus Selected
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "selectPrevious selects the first file in a list when none is selected" <|
\_ ->
let
actual : List File
actual =
selectPrevious
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5
]
expected : List File
expected =
[ filteredDir1 |> withStatus Selected
, filteredDir2
, filteredDir3
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "extendSelectionToNext selects the next file after the first selected" <|
\_ ->
let
actual : List File
actual =
extendSelectionToNext
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3
, filteredDir4
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3 |> withStatus Selected
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "extendSelectionToPrevious selects the file before the first selected" <|
\_ ->
let
actual : List File
actual =
extendSelectionToPrevious
[ filteredDir1
, filteredDir2
, filteredDir3 |> withStatus Selected
, filteredDir4
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3 |> withStatus Selected
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "selectSimilar selects the files with a name looking like the given one" <|
\_ ->
let
actual : List File
actual =
selectSimilar
filteredDir6
10
[ filteredDir1
, filteredDir6 |> withStatus Selected
, filteredDir2
, filteredDir7
, filteredDir3
, filteredDir8
, filteredDir4 |> withStatus Selected
, filteredDir5
]
expected : List File
expected =
[ filteredDir1
, filteredDir6 |> withStatus Selected
, filteredDir2
, filteredDir7 |> withStatus Selected
, filteredDir3
, filteredDir8 |> withStatus Selected
, filteredDir4
, filteredDir5
]
in
Expect.equal expected actual
, test "filerDecoder is able to decode a file descriptor" <|
\_ ->
let
actual : File
actual =
"""
{
"DirPath": "/Users/pascal",
"IsDir": true,
"ModTime": "2025-12-16T19:43:08.307Z",
"Mode": 16832,
"Name": "Music",
"Size": 256
}
"""
|> decodeString File.fileDecoder
|> Result.toMaybe
|> Maybe.withDefault Fixtures.dir1
expected : File
expected =
{ parentPath = "/Users/pascal"
, isDir = True
, modTime = millisToPosix 1765914188307
, mode = 16832
, name = "Music"
, satisfiesFilter = False
, status = Unselected
, size = 256
}
in
Expect.equal expected actual
]

112
src-elm/tests/Fixtures.elm Normal file
View file

@ -0,0 +1,112 @@
module Fixtures exposing (allDirs, dir1, dir2, dir3, dir4, dir5, filteredDir1, filteredDir2, filteredDir3, filteredDir4, filteredDir5, filteredDir6, filteredDir7, filteredDir8, model, windowsDir)
import File exposing (File, FileStatus(..), withName)
import Main exposing (Model, defaultModel)
import Time exposing (millisToPosix)
allDirs : List File
allDirs =
[ dir1
, dir2
, dir3
, dir4
, dir5
]
dir1 : File
dir1 =
{ isDir = True
, mode = 777
, modTime = millisToPosix 0
, name = "dirname"
, parentPath = "/some/path/"
, satisfiesFilter = False
, size = 0
, status = Unselected
}
dir2 : File
dir2 =
{ dir1 | name = "dir2" }
dir3 : File
dir3 =
{ dir1 | name = "different" }
dir4 : File
dir4 =
{ dir1
| name = "dirname4"
, parentPath = "/some/path/extended"
}
dir5 : File
dir5 =
{ dir1
| name = "dir5"
, parentPath = "/some/path/extended"
}
filteredDir1 : File
filteredDir1 =
dir1 |> withSatisfiedFilter
filteredDir2 : File
filteredDir2 =
dir2 |> withSatisfiedFilter
filteredDir3 : File
filteredDir3 =
dir3 |> withSatisfiedFilter
filteredDir4 : File
filteredDir4 =
dir4 |> withSatisfiedFilter
filteredDir5 : File
filteredDir5 =
dir5 |> withSatisfiedFilter
filteredDir6 : File
filteredDir6 =
filteredDir1 |> withName "a name with random chars 1 [123]"
filteredDir7 : File
filteredDir7 =
filteredDir1 |> withName "a name with random chars 2 [456]"
filteredDir8 : File
filteredDir8 =
filteredDir1 |> withName "a name with random chars 3 [678] - Foo"
model : Model
model =
{ defaultModel | destinationSubdirectories = [] }
windowsDir : File
windowsDir =
{ dir1
| name = "windows dir"
, parentPath = "C:\\some\\path\\extended"
}
withSatisfiedFilter : File -> File
withSatisfiedFilter file =
{ file | satisfiesFilter = True }

291
src-elm/tests/MaintTest.elm Normal file
View file

@ -0,0 +1,291 @@
module MaintTest exposing (suite)
import Expect
import File exposing (File, FileStatus(..), defaultDir, withName, withParentPath, withStatus)
import Fixtures exposing (allDirs, dir1, dir2, dir3, dir4, dir5, filteredDir1, filteredDir2, filteredDir3, filteredDir4, filteredDir5, model, windowsDir)
import Main exposing (Model, defaultModel, filterDestinationDirectories, pathElements, select, truncateConcatenatedNames, windowsPathSep)
import Test exposing (Test, describe, test)
suite : Test
suite =
describe "Main module"
[ describe "filterDestinationDirectories"
[ test "identifies filenames containing a given string" <|
\_ ->
let
expected : List File
expected =
[ { dir1 | satisfiesFilter = True }
, dir2
, dir3
, { dir4 | satisfiesFilter = True }
, dir5
]
filteredModel : Model
filteredModel =
{ model
| destinationDirectoryFilter = "dirn"
, destinationSubdirectories = allDirs
}
|> filterDestinationDirectories
in
Expect.equal expected filteredModel.destinationSubdirectories
, test "identifies parent path containing a given string" <|
\_ ->
let
expected : List File
expected =
[ dir1
, dir2
, dir3
, { dir4 | satisfiesFilter = True }
, { dir5 | satisfiesFilter = True }
]
filteredModel : Model
filteredModel =
{ model
| destinationDirectoryFilter = "ext"
, destinationSubdirectories = allDirs
}
|> filterDestinationDirectories
in
Expect.equal expected filteredModel.destinationSubdirectories
, describe "pathElements"
[ test "pathElements returns the list of nested path and their names" <|
\_ ->
let
elements : List File
elements =
pathElements defaultModel [] <| dir5.parentPath ++ defaultModel.pathSeparator ++ dir5.name
expected : List File
expected =
[ defaultDir
|> withName "some"
|> withParentPath "/"
, defaultDir
|> withName "path"
|> withParentPath "/some"
, defaultDir
|> withName "extended"
|> withParentPath "/some/path"
, defaultDir
|> withName "dir5"
|> withParentPath "/some/path/extended"
]
in
Expect.equal expected elements
, test "pathElements returns the list of nested path and their names under Windows" <|
\_ ->
let
elements : List File
elements =
pathElements windowsModel [] <|
windowsDir.parentPath
++ windowsModel.pathSeparator
++ windowsDir.name
expected : List File
expected =
[ defaultDir
|> withName "some"
|> withParentPath "C:"
, defaultDir
|> withName "path"
|> withParentPath "C:\\some"
, defaultDir
|> withName "extended"
|> withParentPath "C:\\some\\path"
, defaultDir
|> withName "windows dir"
|> withParentPath "C:\\some\\path\\extended"
]
windowsModel : Model
windowsModel =
{ defaultModel | pathSeparator = windowsPathSep }
in
Expect.equal expected elements
, test "pathElements ignores ." <|
\_ ->
let
elements : List File
elements =
pathElements defaultModel [] "."
expected : List File
expected =
[]
in
Expect.equal expected elements
]
, test "truncate returns a list of files whose cumulated name length does not exceed given size" <|
\_ ->
let
actual : List File
actual =
truncateConcatenatedNames 22 allDirs
expected : List File
expected =
[ dir3
, dir4
, dir5
]
in
Expect.equal expected actual
]
, describe "select"
[ test "select selects only the clicked file when neither CTRL or SHIFT are pressed" <|
\_ ->
let
actual : List File
actual =
select model allDirs dir3
expected : List File
expected =
[ dir1
, dir2
, dir3 |> withStatus Selected
, dir4
, dir5
]
in
Expect.equal expected actual
, test "select unselects the clicked file when neither CTRL or SHIFT are pressed" <|
\_ ->
let
actual : List File
actual =
select model
[ dir1
, dir2
, clickedFile
, dir4
, dir5
]
dir3
clickedFile : File
clickedFile =
dir3 |> withStatus Selected
expected : List File
expected =
allDirs
in
Expect.equal expected actual
, test "select adds the clicked file to the current selection if it is unselected and CTRL is pressed" <|
\_ ->
let
actual : List File
actual =
select
{ model | isControlPressed = True }
[ dir1
, dir2
, clickedFile
, dir4
, dir5
]
dir4
clickedFile : File
clickedFile =
dir3 |> withStatus Selected
expected : List File
expected =
[ dir1
, dir2
, dir3 |> withStatus Selected
, dir4 |> withStatus Selected
, dir5
]
in
Expect.equal expected actual
, test "select removes the clicked file from the current selection if it is selected and CTRL is pressed" <|
\_ ->
let
actual : List File
actual =
select
{ model | isControlPressed = True }
[ dir1
, dir2
, dir3 |> withStatus Selected
, clickedFile
, dir5
]
clickedFile
clickedFile : File
clickedFile =
dir4 |> withStatus Selected
expected : List File
expected =
[ dir1
, dir2
, dir3 |> withStatus Selected
, dir4
, dir5
]
in
Expect.equal expected actual
, test "select selects the file range from the first selected to the clicked file when it is after and SHIFT is pressed" <|
\_ ->
let
actual : List File
actual =
select
{ model | isShiftPressed = True }
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3
, filteredDir4
, filteredDir5
]
filteredDir4
expected : List File
expected =
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3 |> withStatus Selected
, filteredDir4 |> withStatus Selected
, filteredDir5
]
in
Expect.equal expected actual
, test "select selects the file range from the clicked file to the last selected when it is before and SHIFT is pressed" <|
\_ ->
let
actual : List File
actual =
select
{ model | isShiftPressed = True }
[ filteredDir1
, filteredDir2
, filteredDir3
, filteredDir4 |> withStatus Selected
, filteredDir5
]
filteredDir2
expected : List File
expected =
[ filteredDir1
, filteredDir2 |> withStatus Selected
, filteredDir3 |> withStatus Selected
, filteredDir4 |> withStatus Selected
, filteredDir5
]
in
Expect.equal expected actual
]
]

View file

@ -0,0 +1,74 @@
module SearchReplaceTest exposing (suite)
import Expect
import Pattern exposing (Token(..), fromString)
import Test exposing (Test, describe, test)
suite : Test
suite =
describe "SearchReplace"
[ describe "fromString"
[ test "parses a string with a joker" <|
\_ ->
let
actual : List Token
actual =
fromString "a*b"
expected : List Token
expected =
[ RawString "a", Joker, RawString "b" ]
in
Expect.equal expected actual
, test "parses a string without any joker" <|
\_ ->
let
actual : List Token
actual =
fromString "ab"
expected : List Token
expected =
[ RawString "ab" ]
in
Expect.equal expected actual
, test "parses a string with several jokers" <|
\_ ->
let
actual : List Token
actual =
fromString "ab*cd*"
expected : List Token
expected =
[ RawString "ab", Joker, RawString "cd", Joker ]
in
Expect.equal expected actual
, test "parses a string with a leading joker" <|
\_ ->
let
actual : List Token
actual =
fromString "*abcd"
expected : List Token
expected =
[ Joker, RawString "abcd" ]
in
Expect.equal expected actual
, test "escapes special chars" <|
\_ ->
let
actual : List Token
actual =
fromString ".[]()"
expected : List Token
expected =
--[ RawString "\\.\\[\\]\\(\\)" ]
[ RawString "\\.\\[\\]\\(\\)" ]
in
Expect.equal expected actual
]
]

View file

@ -0,0 +1,23 @@
module StringComparisonTest exposing (..)
import Expect exposing (Expectation)
import StringComparison exposing (isSimilarityLevelGreaterThan)
import Test exposing (Test, describe, test)
suite : Test
suite =
describe "isSimilarityLevelGreaterThan"
[ test "returns true when comparing string with more than level common chars" <|
\_ ->
isSimilarityLevelGreaterThan "abcdeijk" "abcdefgh" 5
|> Expect.equal True
, test "detects similarity even if the first string is shorter than the second" <|
\_ ->
isSimilarityLevelGreaterThan "zbcde" "abcdefgh" 4
|> Expect.equal True
, test "detects similarity even if the first string is longer than the second" <|
\_ ->
isSimilarityLevelGreaterThan "zBCDExkHamsld" "aBCDEfgH" 5
|> Expect.equal True
]