Premo4153 commited on
Commit
1a07caf
·
verified ·
1 Parent(s): b493bdb

Upload 48 files

Browse files
Files changed (48) hide show
  1. FaceFusion Paths.txt +0 -0
  2. LICENSE.md +3 -0
  3. README.md +60 -12
  4. facefusion.ico +0 -0
  5. facefusion.ini +118 -0
  6. facefusion.py +10 -0
  7. install.py +10 -0
  8. mypy.ini +7 -0
  9. requirements.txt +21 -0
  10. run.py +8 -0
  11. tests/__init__.py +0 -0
  12. tests/helper.py +44 -0
  13. tests/test_audio.py +28 -0
  14. tests/test_cli_age_modifier.py +38 -0
  15. tests/test_cli_batch_runner.py +45 -0
  16. tests/test_cli_expression_restorer.py +38 -0
  17. tests/test_cli_face_debugger.py +39 -0
  18. tests/test_cli_face_editor.py +39 -0
  19. tests/test_cli_face_enhancer.py +39 -0
  20. tests/test_cli_face_swapper.py +39 -0
  21. tests/test_cli_frame_colorizer.py +40 -0
  22. tests/test_cli_frame_enhancer.py +39 -0
  23. tests/test_cli_job_manager.py +209 -0
  24. tests/test_cli_job_runner.py +147 -0
  25. tests/test_cli_lip_syncer.py +40 -0
  26. tests/test_common_helper.py +27 -0
  27. tests/test_config.py +85 -0
  28. tests/test_curl_builder.py +14 -0
  29. tests/test_date_helper.py +15 -0
  30. tests/test_download.py +18 -0
  31. tests/test_execution.py +24 -0
  32. tests/test_face_analyser.py +113 -0
  33. tests/test_ffmpeg.py +119 -0
  34. tests/test_ffmpeg_builder.py +83 -0
  35. tests/test_filesystem.py +135 -0
  36. tests/test_inference_manager.py +32 -0
  37. tests/test_job_helper.py +8 -0
  38. tests/test_job_list.py +24 -0
  39. tests/test_job_manager.py +376 -0
  40. tests/test_job_runner.py +227 -0
  41. tests/test_json.py +19 -0
  42. tests/test_memory.py +8 -0
  43. tests/test_normalizer.py +16 -0
  44. tests/test_process_manager.py +22 -0
  45. tests/test_program_helper.py +40 -0
  46. tests/test_temp_helper.py +34 -0
  47. tests/test_vision.py +179 -0
  48. tests/test_wording.py +7 -0
FaceFusion Paths.txt ADDED
The diff for this file is too large to render. See raw diff
 
LICENSE.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ OpenRAIL-AS license
2
+
3
+ Copyright (c) 2025 Henry Ruhs
README.md CHANGED
@@ -1,12 +1,60 @@
1
- ---
2
- title: Raphtalia
3
- emoji: 🌍
4
- colorFrom: green
5
- colorTo: gray
6
- sdk: gradio
7
- sdk_version: 5.22.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FaceFusion
2
+ ==========
3
+
4
+ > Industry leading face manipulation platform.
5
+
6
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/facefusion/facefusion/ci.yml.svg?branch=master)](https://github.com/facefusion/facefusion/actions?query=workflow:ci)
7
+ [![Coverage Status](https://img.shields.io/coveralls/facefusion/facefusion.svg)](https://coveralls.io/r/facefusion/facefusion)
8
+ ![License](https://img.shields.io/badge/license-OpenRAIL--AS-green)
9
+
10
+
11
+ Preview
12
+ -------
13
+
14
+ ![Preview](https://raw.githubusercontent.com/facefusion/facefusion/master/.github/preview.png?sanitize=true)
15
+
16
+
17
+ Installation
18
+ ------------
19
+
20
+ Be aware, the [installation](https://docs.facefusion.io/installation) needs technical skills and is not recommended for beginners. In case you are not comfortable using a terminal, our [Windows Installer](http://windows-installer.facefusion.io) and [macOS Installer](http://macos-installer.facefusion.io) get you started.
21
+
22
+
23
+ Usage
24
+ -----
25
+
26
+ Run the command:
27
+
28
+ ```
29
+ python facefusion.py [commands] [options]
30
+
31
+ options:
32
+ -h, --help show this help message and exit
33
+ -v, --version show program's version number and exit
34
+
35
+ commands:
36
+ run run the program
37
+ headless-run run the program in headless mode
38
+ batch-run run the program in batch mode
39
+ force-download force automate downloads and exit
40
+ job-list list jobs by status
41
+ job-create create a drafted job
42
+ job-submit submit a drafted job to become a queued job
43
+ job-submit-all submit all drafted jobs to become a queued jobs
44
+ job-delete delete a drafted, queued, failed or completed job
45
+ job-delete-all delete all drafted, queued, failed and completed jobs
46
+ job-add-step add a step to a drafted job
47
+ job-remix-step remix a previous step from a drafted job
48
+ job-insert-step insert a step to a drafted job
49
+ job-remove-step remove a step from a drafted job
50
+ job-run run a queued job
51
+ job-run-all run all queued jobs
52
+ job-retry retry a failed job
53
+ job-retry-all retry all failed jobs
54
+ ```
55
+
56
+
57
+ Documentation
58
+ -------------
59
+
60
+ Read the [documentation](https://docs.facefusion.io) for a deep dive.
facefusion.ico ADDED
facefusion.ini ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [paths]
2
+ temp_path =
3
+ jobs_path =
4
+ source_paths =
5
+ target_path =
6
+ output_path =
7
+
8
+ [patterns]
9
+ source_pattern =
10
+ target_pattern =
11
+ output_pattern =
12
+
13
+ [face_detector]
14
+ face_detector_model =
15
+ face_detector_size =
16
+ face_detector_angles =
17
+ face_detector_score =
18
+
19
+ [face_landmarker]
20
+ face_landmarker_model =
21
+ face_landmarker_score =
22
+
23
+ [face_selector]
24
+ face_selector_mode =
25
+ face_selector_order =
26
+ face_selector_age_start =
27
+ face_selector_age_end =
28
+ face_selector_gender =
29
+ face_selector_race =
30
+ reference_face_position =
31
+ reference_face_distance =
32
+ reference_frame_number =
33
+
34
+ [face_masker]
35
+ face_occluder_model =
36
+ face_parser_model =
37
+ face_mask_types =
38
+ face_mask_blur =
39
+ face_mask_padding =
40
+ face_mask_regions =
41
+
42
+ [frame_extraction]
43
+ trim_frame_start =
44
+ trim_frame_end =
45
+ temp_frame_format =
46
+ keep_temp =
47
+
48
+ [output_creation]
49
+ output_image_quality =
50
+ output_image_resolution =
51
+ output_audio_encoder =
52
+ output_audio_quality =
53
+ output_audio_volume =
54
+ output_video_encoder =
55
+ output_video_preset =
56
+ output_video_quality =
57
+ output_video_resolution =
58
+ output_video_fps =
59
+ skip_audio =
60
+
61
+ [processors]
62
+ processors =
63
+ age_modifier_model =
64
+ age_modifier_direction =
65
+ deep_swapper_model =
66
+ deep_swapper_morph =
67
+ expression_restorer_model =
68
+ expression_restorer_factor =
69
+ face_debugger_items =
70
+ face_editor_model =
71
+ face_editor_eyebrow_direction =
72
+ face_editor_eye_gaze_horizontal =
73
+ face_editor_eye_gaze_vertical =
74
+ face_editor_eye_open_ratio =
75
+ face_editor_lip_open_ratio =
76
+ face_editor_mouth_grim =
77
+ face_editor_mouth_pout =
78
+ face_editor_mouth_purse =
79
+ face_editor_mouth_smile =
80
+ face_editor_mouth_position_horizontal =
81
+ face_editor_mouth_position_vertical =
82
+ face_editor_head_pitch =
83
+ face_editor_head_yaw =
84
+ face_editor_head_roll =
85
+ face_enhancer_model =
86
+ face_enhancer_blend =
87
+ face_enhancer_weight =
88
+ face_swapper_model =
89
+ face_swapper_pixel_boost =
90
+ frame_colorizer_model =
91
+ frame_colorizer_size =
92
+ frame_colorizer_blend =
93
+ frame_enhancer_model =
94
+ frame_enhancer_blend =
95
+ lip_syncer_model =
96
+
97
+ [uis]
98
+ open_browser =
99
+ ui_layouts =
100
+ ui_workflow =
101
+
102
+ [execution]
103
+ execution_device_id =
104
+ execution_providers =
105
+ execution_thread_count =
106
+ execution_queue_count =
107
+
108
+ [download]
109
+ download_providers =
110
+ download_scope =
111
+
112
+ [memory]
113
+ video_memory_strategy =
114
+ system_memory_limit =
115
+
116
+ [misc]
117
+ log_level =
118
+ halt_on_error =
facefusion.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+
5
+ os.environ['OMP_NUM_THREADS'] = '1'
6
+
7
+ from facefusion import core
8
+
9
+ if __name__ == '__main__':
10
+ core.cli()
install.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+
5
+ os.environ['SYSTEM_VERSION_COMPAT'] = '0'
6
+
7
+ from facefusion import installer
8
+
9
+ if __name__ == '__main__':
10
+ installer.cli()
mypy.ini ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [mypy]
2
+ check_untyped_defs = True
3
+ disallow_any_generics = True
4
+ disallow_untyped_calls = True
5
+ disallow_untyped_defs = True
6
+ ignore_missing_imports = True
7
+ strict_optional = False
requirements.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ gradio-rangeslider
3
+ numpy
4
+ onnx
5
+ onnxruntime
6
+ opencv-python
7
+ psutil
8
+ tqdm
9
+ scipy
10
+
11
+
12
+
13
+ #gradio==5.20.0
14
+ #gradio-rangeslider==0.0.8
15
+ #numpy==2.2.3
16
+ #onnx==1.17.0
17
+ #onnxruntime==1.21.0
18
+ #opencv-python==4.11.0.86
19
+ #psutil==7.0.0
20
+ #tqdm==4.67.1
21
+ #scipy==1.15.2
run.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import subprocess
3
+
4
+ python_executable = sys.executable # Jo bhi active Python hai usko detect karega
5
+ command = [python_executable, "facefusion.py", "run"]
6
+
7
+ print(f"🚀 Launching FaceFusion with {python_executable}...")
8
+ subprocess.run(command)
tests/__init__.py ADDED
File without changes
tests/helper.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+
4
+ from facefusion.filesystem import create_directory, is_directory, is_file, remove_directory
5
+ from facefusion.types import JobStatus
6
+
7
+
8
+ def is_test_job_file(file_path : str, job_status : JobStatus) -> bool:
9
+ return is_file(get_test_job_file(file_path, job_status))
10
+
11
+
12
+ def get_test_job_file(file_path : str, job_status : JobStatus) -> str:
13
+ return os.path.join(get_test_jobs_directory(), job_status, file_path)
14
+
15
+
16
+ def get_test_jobs_directory() -> str:
17
+ return os.path.join(tempfile.gettempdir(), 'facefusion-test-jobs')
18
+
19
+
20
+ def get_test_example_file(file_path : str) -> str:
21
+ return os.path.join(get_test_examples_directory(), file_path)
22
+
23
+
24
+ def get_test_examples_directory() -> str:
25
+ return os.path.join(tempfile.gettempdir(), 'facefusion-test-examples')
26
+
27
+
28
+ def is_test_output_file(file_path : str) -> bool:
29
+ return is_file(get_test_output_file(file_path))
30
+
31
+
32
+ def get_test_output_file(file_path : str) -> str:
33
+ return os.path.join(get_test_outputs_directory(), file_path)
34
+
35
+
36
+ def get_test_outputs_directory() -> str:
37
+ return os.path.join(tempfile.gettempdir(), 'facefusion-test-outputs')
38
+
39
+
40
+ def prepare_test_output_directory() -> bool:
41
+ test_outputs_directory = get_test_outputs_directory()
42
+ remove_directory(test_outputs_directory)
43
+ create_directory(test_outputs_directory)
44
+ return is_directory(test_outputs_directory)
tests/test_audio.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+
3
+ import pytest
4
+
5
+ from facefusion.audio import get_audio_frame, read_static_audio
6
+ from facefusion.download import conditional_download
7
+ from .helper import get_test_example_file, get_test_examples_directory
8
+
9
+
10
+ @pytest.fixture(scope = 'module', autouse = True)
11
+ def before_all() -> None:
12
+ conditional_download(get_test_examples_directory(),
13
+ [
14
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3'
15
+ ])
16
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ])
17
+
18
+
19
+ def test_get_audio_frame() -> None:
20
+ assert hasattr(get_audio_frame(get_test_example_file('source.mp3'), 25), '__array_interface__')
21
+ assert hasattr(get_audio_frame(get_test_example_file('source.wav'), 25), '__array_interface__')
22
+ assert get_audio_frame('invalid', 25) is None
23
+
24
+
25
+ def test_read_static_audio() -> None:
26
+ assert len(read_static_audio(get_test_example_file('source.mp3'), 25)) == 280
27
+ assert len(read_static_audio(get_test_example_file('source.wav'), 25)) == 280
28
+ assert read_static_audio('invalid', 25) is None
tests/test_cli_age_modifier.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
16
+ ])
17
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
18
+
19
+
20
+ @pytest.fixture(scope = 'function', autouse = True)
21
+ def before_each() -> None:
22
+ clear_jobs(get_test_jobs_directory())
23
+ init_jobs(get_test_jobs_directory())
24
+ prepare_test_output_directory()
25
+
26
+
27
+ def test_modify_age_to_image() -> None:
28
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-age-face-to-image.jpg') ]
29
+
30
+ assert subprocess.run(commands).returncode == 0
31
+ assert is_test_output_file('test-age-face-to-image.jpg') is True
32
+
33
+
34
+ def test_modify_age_to_video() -> None:
35
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-age-face-to-video.mp4'), '--trim-frame-end', '1' ]
36
+
37
+ assert subprocess.run(commands).returncode == 0
38
+ assert is_test_output_file('test-age-face-to-video.mp4') is True
tests/test_cli_batch_runner.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
16
+ ])
17
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p-batch-1.jpg') ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '2', get_test_example_file('target-240p-batch-2.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_batch_run_targets() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'batch-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p-batch-*.jpg'), '-o', get_test_output_file('test-batch-run-targets-{index}.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-batch-run-targets-0.jpg') is True
33
+ assert is_test_output_file('test-batch-run-targets-1.jpg') is True
34
+ assert is_test_output_file('test-batch-run-targets-2.jpg') is False
35
+
36
+
37
+ def test_batch_run_sources_to_targets() -> None:
38
+ commands = [ sys.executable, 'facefusion.py', 'batch-run', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('target-240p-batch-*.jpg'), '-t', get_test_example_file('target-240p-batch-*.jpg'), '-o', get_test_output_file('test-batch-run-sources-to-targets-{index}.jpg') ]
39
+
40
+ assert subprocess.run(commands).returncode == 0
41
+ assert is_test_output_file('test-batch-run-sources-to-targets-0.jpg') is True
42
+ assert is_test_output_file('test-batch-run-sources-to-targets-1.jpg') is True
43
+ assert is_test_output_file('test-batch-run-sources-to-targets-2.jpg') is True
44
+ assert is_test_output_file('test-batch-run-sources-to-targets-3.jpg') is True
45
+ assert is_test_output_file('test-batch-run-sources-to-targets-4.jpg') is False
tests/test_cli_expression_restorer.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
16
+ ])
17
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
18
+
19
+
20
+ @pytest.fixture(scope = 'function', autouse = True)
21
+ def before_each() -> None:
22
+ clear_jobs(get_test_jobs_directory())
23
+ init_jobs(get_test_jobs_directory())
24
+ prepare_test_output_directory()
25
+
26
+
27
+ def test_restore_expression_to_image() -> None:
28
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-restore-expression-to-image.jpg') ]
29
+
30
+ assert subprocess.run(commands).returncode == 0
31
+ assert is_test_output_file('test-restore-expression-to-image.jpg') is True
32
+
33
+
34
+ def test_restore_expression_to_video() -> None:
35
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-restore-expression-to-video.mp4'), '--trim-frame-end', '1' ]
36
+
37
+ assert subprocess.run(commands).returncode == 0
38
+ assert is_test_output_file('test-restore-expression-to-video.mp4') is True
tests/test_cli_face_debugger.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_debug_face_to_image() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-debug-face-to-image.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-debug-face-to-image.jpg') is True
33
+
34
+
35
+ def test_debug_face_to_video() -> None:
36
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-debug-face-to-video.mp4'), '--trim-frame-end', '1' ]
37
+
38
+ assert subprocess.run(commands).returncode == 0
39
+ assert is_test_output_file('test-debug-face-to-video.mp4') is True
tests/test_cli_face_editor.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_edit_face_to_image() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-edit-face-to-image.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-edit-face-to-image.jpg') is True
33
+
34
+
35
+ def test_edit_face_to_video() -> None:
36
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-edit-face-to-video.mp4'), '--trim-frame-end', '1' ]
37
+
38
+ assert subprocess.run(commands).returncode == 0
39
+ assert is_test_output_file('test-edit-face-to-video.mp4') is True
tests/test_cli_face_enhancer.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_enhance_face_to_image() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-enhance-face-to-image.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-enhance-face-to-image.jpg') is True
33
+
34
+
35
+ def test_enhance_face_to_video() -> None:
36
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-enhance-face-to-video.mp4'), '--trim-frame-end', '1' ]
37
+
38
+ assert subprocess.run(commands).returncode == 0
39
+ assert is_test_output_file('test-enhance-face-to-video.mp4') is True
tests/test_cli_face_swapper.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_swap_face_to_image() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-swap-face-to-image.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-swap-face-to-image.jpg') is True
33
+
34
+
35
+ def test_swap_face_to_video() -> None:
36
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-swap-face-to-video.mp4'), '--trim-frame-end', '1' ]
37
+
38
+ assert subprocess.run(commands).returncode == 0
39
+ assert is_test_output_file('test-swap-face-to-video.mp4') is True
tests/test_cli_frame_colorizer.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.jpg') ])
19
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.mp4') ])
20
+
21
+
22
+ @pytest.fixture(scope = 'function', autouse = True)
23
+ def before_each() -> None:
24
+ clear_jobs(get_test_jobs_directory())
25
+ init_jobs(get_test_jobs_directory())
26
+ prepare_test_output_directory()
27
+
28
+
29
+ def test_colorize_frame_to_image() -> None:
30
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.jpg'), '-o', get_test_output_file('test_colorize-frame-to-image.jpg') ]
31
+
32
+ assert subprocess.run(commands).returncode == 0
33
+ assert is_test_output_file('test_colorize-frame-to-image.jpg') is True
34
+
35
+
36
+ def test_colorize_frame_to_video() -> None:
37
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_file('test-colorize-frame-to-video.mp4'), '--trim-frame-end', '1' ]
38
+
39
+ assert subprocess.run(commands).returncode == 0
40
+ assert is_test_output_file('test-colorize-frame-to-video.mp4') is True
tests/test_cli_frame_enhancer.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_enhance_frame_to_image() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-enhance-frame-to-image.jpg') ]
30
+
31
+ assert subprocess.run(commands).returncode == 0
32
+ assert is_test_output_file('test-enhance-frame-to-image.jpg') is True
33
+
34
+
35
+ def test_enhance_frame_to_video() -> None:
36
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-enhance-frame-to-video.mp4'), '--trim-frame-end', '1' ]
37
+
38
+ assert subprocess.run(commands).returncode == 0
39
+ assert is_test_output_file('test-enhance-frame-to-video.mp4') is True
tests/test_cli_job_manager.py ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, count_step_total, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_job_file
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+
26
+
27
+ @pytest.mark.skip()
28
+ def test_job_list() -> None:
29
+ pass
30
+
31
+
32
+ def test_job_create() -> None:
33
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '--jobs-path', get_test_jobs_directory() ]
34
+
35
+ assert subprocess.run(commands).returncode == 0
36
+ assert is_test_job_file('test-job-create.json', 'drafted') is True
37
+
38
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '--jobs-path', get_test_jobs_directory() ]
39
+
40
+ assert subprocess.run(commands).returncode == 1
41
+
42
+
43
+ def test_job_submit() -> None:
44
+ commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
45
+
46
+ assert subprocess.run(commands).returncode == 1
47
+
48
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
49
+ subprocess.run(commands)
50
+
51
+ assert subprocess.run(commands).returncode == 1
52
+
53
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
54
+ subprocess.run(commands)
55
+
56
+ commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
57
+
58
+ assert subprocess.run(commands).returncode == 0
59
+ assert is_test_job_file('test-job-submit.json', 'queued') is True
60
+ assert subprocess.run(commands).returncode == 1
61
+
62
+
63
+ def test_submit_all() -> None:
64
+ commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
65
+
66
+ assert subprocess.run(commands).returncode == 1
67
+
68
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit-all-1', '--jobs-path', get_test_jobs_directory() ]
69
+ subprocess.run(commands)
70
+
71
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit-all-2', '--jobs-path', get_test_jobs_directory() ]
72
+ subprocess.run(commands)
73
+
74
+ assert subprocess.run(commands).returncode == 1
75
+
76
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit-all-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
77
+ subprocess.run(commands)
78
+
79
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit-all-2', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
80
+ subprocess.run(commands)
81
+
82
+ commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
83
+
84
+ assert subprocess.run(commands).returncode == 0
85
+ assert is_test_job_file('test-job-submit-all-1.json', 'queued') is True
86
+ assert is_test_job_file('test-job-submit-all-2.json', 'queued') is True
87
+ assert subprocess.run(commands).returncode == 1
88
+
89
+
90
+ def test_job_delete() -> None:
91
+ commands = [ sys.executable, 'facefusion.py', 'job-delete', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
92
+
93
+ assert subprocess.run(commands).returncode == 1
94
+
95
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
96
+ subprocess.run(commands)
97
+
98
+ commands = [ sys.executable, 'facefusion.py', 'job-delete', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
99
+
100
+ assert subprocess.run(commands).returncode == 0
101
+ assert is_test_job_file('test-job-delete.json', 'drafted') is False
102
+ assert subprocess.run(commands).returncode == 1
103
+
104
+
105
+ def test_job_delete_all() -> None:
106
+ commands = [ sys.executable, 'facefusion.py', 'job-delete-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
107
+
108
+ assert subprocess.run(commands).returncode == 1
109
+
110
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete-all-1', '--jobs-path', get_test_jobs_directory() ]
111
+ subprocess.run(commands)
112
+
113
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete-all-2', '--jobs-path', get_test_jobs_directory() ]
114
+ subprocess.run(commands)
115
+
116
+ commands = [ sys.executable, 'facefusion.py', 'job-delete-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
117
+
118
+ assert subprocess.run(commands).returncode == 0
119
+ assert is_test_job_file('test-job-delete-all-1.json', 'drafted') is False
120
+ assert is_test_job_file('test-job-delete-all-2.json', 'drafted') is False
121
+ assert subprocess.run(commands).returncode == 1
122
+
123
+
124
+ def test_job_add_step() -> None:
125
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-add-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
126
+
127
+ assert subprocess.run(commands).returncode == 1
128
+ assert count_step_total('test-job-add-step') == 0
129
+
130
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-add-step', '--jobs-path', get_test_jobs_directory() ]
131
+ subprocess.run(commands)
132
+
133
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-add-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
134
+
135
+ assert subprocess.run(commands).returncode == 0
136
+ assert count_step_total('test-job-add-step') == 1
137
+
138
+
139
+ def test_job_remix() -> None:
140
+ commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
141
+
142
+ assert subprocess.run(commands).returncode == 1
143
+ assert count_step_total('test-job-remix-step') == 0
144
+
145
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-remix-step', '--jobs-path', get_test_jobs_directory() ]
146
+ subprocess.run(commands)
147
+
148
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-remix-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
149
+ subprocess.run(commands)
150
+
151
+ commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
152
+
153
+ assert count_step_total('test-job-remix-step') == 1
154
+ assert subprocess.run(commands).returncode == 0
155
+ assert count_step_total('test-job-remix-step') == 2
156
+
157
+ commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
158
+
159
+ assert subprocess.run(commands).returncode == 0
160
+ assert count_step_total('test-job-remix-step') == 3
161
+
162
+
163
+ def test_job_insert_step() -> None:
164
+ commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
165
+
166
+ assert subprocess.run(commands).returncode == 1
167
+ assert count_step_total('test-job-insert-step') == 0
168
+
169
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-insert-step', '--jobs-path', get_test_jobs_directory() ]
170
+ subprocess.run(commands)
171
+
172
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-insert-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
173
+ subprocess.run(commands)
174
+
175
+ commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
176
+
177
+ assert count_step_total('test-job-insert-step') == 1
178
+ assert subprocess.run(commands).returncode == 0
179
+ assert count_step_total('test-job-insert-step') == 2
180
+
181
+ commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
182
+
183
+ assert subprocess.run(commands).returncode == 0
184
+ assert count_step_total('test-job-insert-step') == 3
185
+
186
+
187
+ def test_job_remove_step() -> None:
188
+ commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '0', '--jobs-path', get_test_jobs_directory() ]
189
+
190
+ assert subprocess.run(commands).returncode == 1
191
+
192
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-remove-step', '--jobs-path', get_test_jobs_directory() ]
193
+ subprocess.run(commands)
194
+
195
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-remove-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
196
+ subprocess.run(commands)
197
+ subprocess.run(commands)
198
+
199
+ commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '0', '--jobs-path', get_test_jobs_directory() ]
200
+
201
+ assert count_step_total('test-job-remove-step') == 2
202
+ assert subprocess.run(commands).returncode == 0
203
+ assert count_step_total('test-job-remove-step') == 1
204
+
205
+ commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '-1', '--jobs-path', get_test_jobs_directory() ]
206
+
207
+ assert subprocess.run(commands).returncode == 0
208
+ assert subprocess.run(commands).returncode == 1
209
+ assert count_step_total('test-job-remove-step') == 0
tests/test_cli_job_runner.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs, move_job_file, set_steps_status
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+
20
+
21
+ @pytest.fixture(scope = 'function', autouse = True)
22
+ def before_each() -> None:
23
+ clear_jobs(get_test_jobs_directory())
24
+ init_jobs(get_test_jobs_directory())
25
+ prepare_test_output_directory()
26
+
27
+
28
+ def test_job_run() -> None:
29
+ commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
30
+
31
+ assert subprocess.run(commands).returncode == 1
32
+
33
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
34
+ subprocess.run(commands)
35
+
36
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-run.jpg') ]
37
+ subprocess.run(commands)
38
+
39
+ commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
40
+
41
+ assert subprocess.run(commands).returncode == 1
42
+
43
+ commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
44
+ subprocess.run(commands)
45
+
46
+ commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
47
+
48
+ assert subprocess.run(commands).returncode == 0
49
+ assert subprocess.run(commands).returncode == 1
50
+ assert is_test_output_file('test-job-run.jpg') is True
51
+
52
+
53
+ def test_job_run_all() -> None:
54
+ commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
55
+
56
+ assert subprocess.run(commands).returncode == 1
57
+
58
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run-all-1', '--jobs-path', get_test_jobs_directory() ]
59
+ subprocess.run(commands)
60
+
61
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory() ]
62
+ subprocess.run(commands)
63
+
64
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-1', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-run-all-1.jpg') ]
65
+ subprocess.run(commands)
66
+
67
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-run-all-2.mp4'), '--trim-frame-end', '1' ]
68
+ subprocess.run(commands)
69
+
70
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-run-all-2.mp4'), '--trim-frame-start', '0', '--trim-frame-end', '1' ]
71
+ subprocess.run(commands)
72
+
73
+ commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
74
+
75
+ assert subprocess.run(commands).returncode == 1
76
+
77
+ commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
78
+ subprocess.run(commands)
79
+
80
+ commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
81
+
82
+ assert subprocess.run(commands).returncode == 0
83
+ assert subprocess.run(commands).returncode == 1
84
+ assert is_test_output_file('test-job-run-all-1.jpg') is True
85
+ assert is_test_output_file('test-job-run-all-2.mp4') is True
86
+
87
+
88
+ def test_job_retry() -> None:
89
+ commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
90
+
91
+ assert subprocess.run(commands).returncode == 1
92
+
93
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
94
+ subprocess.run(commands)
95
+
96
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-retry.jpg') ]
97
+ subprocess.run(commands)
98
+
99
+ commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
100
+
101
+ assert subprocess.run(commands).returncode == 1
102
+
103
+ set_steps_status('test-job-retry', 'failed')
104
+ move_job_file('test-job-retry', 'failed')
105
+
106
+ commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
107
+
108
+ assert subprocess.run(commands).returncode == 0
109
+ assert subprocess.run(commands).returncode == 1
110
+ assert is_test_output_file('test-job-retry.jpg') is True
111
+
112
+
113
+ def test_job_retry_all() -> None:
114
+ commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
115
+
116
+ assert subprocess.run(commands).returncode == 1
117
+
118
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry-all-1', '--jobs-path', get_test_jobs_directory() ]
119
+ subprocess.run(commands)
120
+
121
+ commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory() ]
122
+ subprocess.run(commands)
123
+
124
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-1', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-retry-all-1.jpg') ]
125
+ subprocess.run(commands)
126
+
127
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-retry-all-2.mp4'), '--trim-frame-end', '1' ]
128
+ subprocess.run(commands)
129
+
130
+ commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-retry-all-2.mp4'), '--trim-frame-start', '0', '--trim-frame-end', '1' ]
131
+ subprocess.run(commands)
132
+
133
+ commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
134
+
135
+ assert subprocess.run(commands).returncode == 1
136
+
137
+ set_steps_status('test-job-retry-all-1', 'failed')
138
+ set_steps_status('test-job-retry-all-2', 'failed')
139
+ move_job_file('test-job-retry-all-1', 'failed')
140
+ move_job_file('test-job-retry-all-2', 'failed')
141
+
142
+ commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
143
+
144
+ assert subprocess.run(commands).returncode == 0
145
+ assert subprocess.run(commands).returncode == 1
146
+ assert is_test_output_file('test-job-retry-all-1.jpg') is True
147
+ assert is_test_output_file('test-job-retry-all-2.mp4') is True
tests/test_cli_lip_syncer.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ from facefusion.download import conditional_download
7
+ from facefusion.jobs.job_manager import clear_jobs, init_jobs
8
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
9
+
10
+
11
+ @pytest.fixture(scope = 'module', autouse = True)
12
+ def before_all() -> None:
13
+ conditional_download(get_test_examples_directory(),
14
+ [
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
17
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
18
+ ])
19
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
20
+
21
+
22
+ @pytest.fixture(scope = 'function', autouse = True)
23
+ def before_each() -> None:
24
+ clear_jobs(get_test_jobs_directory())
25
+ init_jobs(get_test_jobs_directory())
26
+ prepare_test_output_directory()
27
+
28
+
29
+ def test_sync_lip_to_image() -> None:
30
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test_sync_lip_to_image.jpg') ]
31
+
32
+ assert subprocess.run(commands).returncode == 0
33
+ assert is_test_output_file('test_sync_lip_to_image.jpg') is True
34
+
35
+
36
+ def test_sync_lip_to_video() -> None:
37
+ commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test_sync_lip_to_video.mp4'), '--trim-frame-end', '1' ]
38
+
39
+ assert subprocess.run(commands).returncode == 0
40
+ assert is_test_output_file('test_sync_lip_to_video.mp4') is True
tests/test_common_helper.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.common_helper import calc_float_step, calc_int_step, create_float_metavar, create_float_range, create_int_metavar, create_int_range
2
+
3
+
4
+ def test_create_int_metavar() -> None:
5
+ assert create_int_metavar([ 1, 2, 3, 4, 5 ]) == '[1..5:1]'
6
+
7
+
8
+ def test_create_float_metavar() -> None:
9
+ assert create_float_metavar([ 0.1, 0.2, 0.3, 0.4, 0.5 ]) == '[0.1..0.5:0.1]'
10
+
11
+
12
+ def test_create_int_range() -> None:
13
+ assert create_int_range(0, 2, 1) == [ 0, 1, 2 ]
14
+ assert create_float_range(0, 1, 1) == [ 0, 1 ]
15
+
16
+
17
+ def test_create_float_range() -> None:
18
+ assert create_float_range(0.0, 1.0, 0.5) == [ 0.0, 0.5, 1.0 ]
19
+ assert create_float_range(0.0, 1.0, 0.05) == [ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.0 ]
20
+
21
+
22
+ def test_calc_int_step() -> None:
23
+ assert calc_int_step([ 0, 1 ]) == 1
24
+
25
+
26
+ def test_calc_float_step() -> None:
27
+ assert calc_float_step([ 0.1, 0.2 ]) == 0.1
tests/test_config.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from configparser import ConfigParser
2
+
3
+ import pytest
4
+
5
+ from facefusion import config
6
+
7
+
8
+ @pytest.fixture(scope = 'module', autouse = True)
9
+ def before_all() -> None:
10
+ config.CONFIG_PARSER = ConfigParser()
11
+ config.CONFIG_PARSER.read_dict(
12
+ {
13
+ 'str':
14
+ {
15
+ 'valid': 'a',
16
+ 'unset': ''
17
+ },
18
+ 'int':
19
+ {
20
+ 'valid': '1',
21
+ 'unset': ''
22
+ },
23
+ 'float':
24
+ {
25
+ 'valid': '1.0',
26
+ 'unset': ''
27
+ },
28
+ 'bool':
29
+ {
30
+ 'valid': 'True',
31
+ 'unset': ''
32
+ },
33
+ 'str_list':
34
+ {
35
+ 'valid': 'a b c',
36
+ 'unset': ''
37
+ },
38
+ 'int_list':
39
+ {
40
+ 'valid': '1 2 3',
41
+ 'unset': ''
42
+ }
43
+ })
44
+
45
+
46
+ def test_get_str_value() -> None:
47
+ assert config.get_str_value('str', 'valid') == 'a'
48
+ assert config.get_str_value('str', 'unset', 'b') == 'b'
49
+ assert config.get_str_value('str', 'unset') is None
50
+ assert config.get_str_value('str', 'invalid') is None
51
+
52
+
53
+ def test_get_int_value() -> None:
54
+ assert config.get_int_value('int', 'valid') == 1
55
+ assert config.get_int_value('int', 'unset', '1') == 1
56
+ assert config.get_int_value('int', 'unset') is None
57
+ assert config.get_int_value('int', 'invalid') is None
58
+
59
+
60
+ def test_get_float_value() -> None:
61
+ assert config.get_float_value('float', 'valid') == 1.0
62
+ assert config.get_float_value('float', 'unset', '1.0') == 1.0
63
+ assert config.get_float_value('float', 'unset') is None
64
+ assert config.get_float_value('float', 'invalid') is None
65
+
66
+
67
+ def test_get_bool_value() -> None:
68
+ assert config.get_bool_value('bool', 'valid') is True
69
+ assert config.get_bool_value('bool', 'unset', 'False') is False
70
+ assert config.get_bool_value('bool', 'unset') is None
71
+ assert config.get_bool_value('bool', 'invalid') is None
72
+
73
+
74
+ def test_get_str_list() -> None:
75
+ assert config.get_str_list('str_list', 'valid') == [ 'a', 'b', 'c' ]
76
+ assert config.get_str_list('str_list', 'unset', 'c b a') == [ 'c', 'b', 'a' ]
77
+ assert config.get_str_list('str_list', 'unset') is None
78
+ assert config.get_str_list('str_list', 'invalid') is None
79
+
80
+
81
+ def test_get_int_list() -> None:
82
+ assert config.get_int_list('int_list', 'valid') == [ 1, 2, 3 ]
83
+ assert config.get_int_list('int_list', 'unset', '3 2 1') == [ 3, 2, 1 ]
84
+ assert config.get_int_list('int_list', 'unset') is None
85
+ assert config.get_int_list('int_list', 'invalid') is None
tests/test_curl_builder.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from shutil import which
2
+
3
+ from facefusion import metadata
4
+ from facefusion.curl_builder import chain, head, run
5
+
6
+
7
+ def test_run() -> None:
8
+ user_agent = metadata.get('name') + '/' + metadata.get('version')
9
+
10
+ assert run([]) == [ which('curl'), '--user-agent', user_agent, '--insecure', '--location', '--silent' ]
11
+
12
+
13
+ def test_chain() -> None:
14
+ assert chain(head(metadata.get('url'))) == [ '-I', metadata.get('url') ]
tests/test_date_helper.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timedelta
2
+
3
+ from facefusion.date_helper import describe_time_ago
4
+
5
+
6
+ def get_time_ago(days : int, hours : int, minutes : int) -> datetime:
7
+ previous_time = datetime.now() - timedelta(days = days, hours = hours, minutes = minutes)
8
+ return previous_time.astimezone()
9
+
10
+
11
+ def test_describe_time_ago() -> None:
12
+ assert describe_time_ago(get_time_ago(0, 0, 0)) == 'just now'
13
+ assert describe_time_ago(get_time_ago(0, 0, 10)) == '10 minutes ago'
14
+ assert describe_time_ago(get_time_ago(0, 5, 10)) == '5 hours and 10 minutes ago'
15
+ assert describe_time_ago(get_time_ago(1, 5, 10)) == '1 days, 5 hours and 10 minutes ago'
tests/test_download.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.download import get_static_download_size, ping_static_url, resolve_download_url_by_provider
2
+
3
+
4
+ def test_get_static_download_size() -> None:
5
+ assert get_static_download_size('https://github.com/facefusion/facefusion-assets/releases/download/models-3.0.0/fairface.onnx') == 85170772
6
+ assert get_static_download_size('https://huggingface.co/facefusion/models-3.0.0/resolve/main/fairface.onnx') == 85170772
7
+ assert get_static_download_size('invalid') == 0
8
+
9
+
10
+ def test_static_ping_url() -> None:
11
+ assert ping_static_url('https://github.com') is True
12
+ assert ping_static_url('https://huggingface.co') is True
13
+ assert ping_static_url('invalid') is False
14
+
15
+
16
+ def test_resolve_download_url_by_provider() -> None:
17
+ assert resolve_download_url_by_provider('github', 'models-3.0.0', 'fairface.onnx') == 'https://github.com/facefusion/facefusion-assets/releases/download/models-3.0.0/fairface.onnx'
18
+ assert resolve_download_url_by_provider('huggingface', 'models-3.0.0', 'fairface.onnx') == 'https://huggingface.co/facefusion/models-3.0.0/resolve/main/fairface.onnx'
tests/test_execution.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.execution import create_inference_session_providers, get_available_execution_providers, has_execution_provider
2
+
3
+
4
+ def test_has_execution_provider() -> None:
5
+ assert has_execution_provider('cpu') is True
6
+ assert has_execution_provider('openvino') is False
7
+
8
+
9
+ def test_get_available_execution_providers() -> None:
10
+ assert 'cpu' in get_available_execution_providers()
11
+
12
+
13
+ def test_create_inference_session_providers() -> None:
14
+ inference_session_providers =\
15
+ [
16
+ ('CUDAExecutionProvider',
17
+ {
18
+ 'device_id': '1',
19
+ 'cudnn_conv_algo_search': 'EXHAUSTIVE'
20
+ }),
21
+ 'CPUExecutionProvider'
22
+ ]
23
+
24
+ assert create_inference_session_providers('1', [ 'cpu', 'cuda' ]) == inference_session_providers
tests/test_face_analyser.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+
3
+ import pytest
4
+
5
+ from facefusion import face_classifier, face_detector, face_landmarker, face_recognizer, state_manager
6
+ from facefusion.download import conditional_download
7
+ from facefusion.face_analyser import get_many_faces, get_one_face
8
+ from facefusion.types import Face
9
+ from facefusion.vision import read_static_image
10
+ from .helper import get_test_example_file, get_test_examples_directory
11
+
12
+
13
+ @pytest.fixture(scope = 'module', autouse = True)
14
+ def before_all() -> None:
15
+ conditional_download(get_test_examples_directory(),
16
+ [
17
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg'
18
+ ])
19
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.8:ih*0.8', get_test_example_file('source-80crop.jpg') ])
20
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.7:ih*0.7', get_test_example_file('source-70crop.jpg') ])
21
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.6:ih*0.6', get_test_example_file('source-60crop.jpg') ])
22
+ state_manager.init_item('execution_device_id', '0')
23
+ state_manager.init_item('execution_providers', [ 'cpu' ])
24
+ state_manager.init_item('download_providers', [ 'github' ])
25
+ state_manager.init_item('face_detector_angles', [ 0 ])
26
+ state_manager.init_item('face_detector_model', 'many')
27
+ state_manager.init_item('face_detector_score', 0.5)
28
+ state_manager.init_item('face_landmarker_model', 'many')
29
+ state_manager.init_item('face_landmarker_score', 0.5)
30
+ face_classifier.pre_check()
31
+ face_landmarker.pre_check()
32
+ face_recognizer.pre_check()
33
+
34
+
35
+ @pytest.fixture(autouse = True)
36
+ def before_each() -> None:
37
+ face_classifier.clear_inference_pool()
38
+ face_detector.clear_inference_pool()
39
+ face_landmarker.clear_inference_pool()
40
+ face_recognizer.clear_inference_pool()
41
+
42
+
43
+ def test_get_one_face_with_retinaface() -> None:
44
+ state_manager.init_item('face_detector_model', 'retinaface')
45
+ state_manager.init_item('face_detector_size', '320x320')
46
+ face_detector.pre_check()
47
+
48
+ source_paths =\
49
+ [
50
+ get_test_example_file('source.jpg'),
51
+ get_test_example_file('source-80crop.jpg'),
52
+ get_test_example_file('source-70crop.jpg'),
53
+ get_test_example_file('source-60crop.jpg')
54
+ ]
55
+
56
+ for source_path in source_paths:
57
+ source_frame = read_static_image(source_path)
58
+ many_faces = get_many_faces([ source_frame ])
59
+ face = get_one_face(many_faces)
60
+
61
+ assert isinstance(face, Face)
62
+
63
+
64
+ def test_get_one_face_with_scrfd() -> None:
65
+ state_manager.init_item('face_detector_model', 'scrfd')
66
+ state_manager.init_item('face_detector_size', '640x640')
67
+ face_detector.pre_check()
68
+
69
+ source_paths =\
70
+ [
71
+ get_test_example_file('source.jpg'),
72
+ get_test_example_file('source-80crop.jpg'),
73
+ get_test_example_file('source-70crop.jpg'),
74
+ get_test_example_file('source-60crop.jpg')
75
+ ]
76
+
77
+ for source_path in source_paths:
78
+ source_frame = read_static_image(source_path)
79
+ many_faces = get_many_faces([ source_frame ])
80
+ face = get_one_face(many_faces)
81
+
82
+ assert isinstance(face, Face)
83
+
84
+
85
+ def test_get_one_face_with_yoloface() -> None:
86
+ state_manager.init_item('face_detector_model', 'yoloface')
87
+ state_manager.init_item('face_detector_size', '640x640')
88
+ face_detector.pre_check()
89
+
90
+ source_paths =\
91
+ [
92
+ get_test_example_file('source.jpg'),
93
+ get_test_example_file('source-80crop.jpg'),
94
+ get_test_example_file('source-70crop.jpg'),
95
+ get_test_example_file('source-60crop.jpg')
96
+ ]
97
+
98
+ for source_path in source_paths:
99
+ source_frame = read_static_image(source_path)
100
+ many_faces = get_many_faces([ source_frame ])
101
+ face = get_one_face(many_faces)
102
+
103
+ assert isinstance(face, Face)
104
+
105
+
106
+ def test_get_many_faces() -> None:
107
+ source_path = get_test_example_file('source.jpg')
108
+ source_frame = read_static_image(source_path)
109
+ many_faces = get_many_faces([ source_frame, source_frame, source_frame ])
110
+
111
+ assert isinstance(many_faces[0], Face)
112
+ assert isinstance(many_faces[1], Face)
113
+ assert isinstance(many_faces[2], Face)
tests/test_ffmpeg.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import tempfile
3
+
4
+ import pytest
5
+
6
+ from facefusion import process_manager, state_manager
7
+ from facefusion.download import conditional_download
8
+ from facefusion.ffmpeg import concat_video, extract_frames, get_available_encoder_set, read_audio_buffer, replace_audio, restore_audio
9
+ from facefusion.filesystem import copy_file
10
+ from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_file_path, resolve_temp_frame_paths
11
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_output_file, prepare_test_output_directory
12
+
13
+
14
+ @pytest.fixture(scope = 'module', autouse = True)
15
+ def before_all() -> None:
16
+ process_manager.start()
17
+ conditional_download(get_test_examples_directory(),
18
+ [
19
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
20
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
21
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
22
+ ])
23
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ])
24
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=25', get_test_example_file('target-240p-25fps.mp4') ])
25
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=30', get_test_example_file('target-240p-30fps.mp4') ])
26
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=60', get_test_example_file('target-240p-60fps.mp4') ])
27
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-i', get_test_example_file('target-240p.mp4'), '-ar', '16000', get_test_example_file('target-240p-16khz.mp4') ])
28
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-i', get_test_example_file('target-240p.mp4'), '-ar', '48000', get_test_example_file('target-240p-48khz.mp4') ])
29
+ state_manager.init_item('temp_path', tempfile.gettempdir())
30
+ state_manager.init_item('temp_frame_format', 'png')
31
+ state_manager.init_item('output_audio_encoder', 'aac')
32
+ state_manager.init_item('output_audio_quality', 80)
33
+ state_manager.init_item('output_audio_volume', 100)
34
+
35
+
36
+ @pytest.fixture(scope = 'function', autouse = True)
37
+ def before_each() -> None:
38
+ prepare_test_output_directory()
39
+
40
+
41
+ @pytest.mark.skip()
42
+ def test_get_available_encoder_set() -> None:
43
+ available_encoder_set = get_available_encoder_set()
44
+
45
+ assert 'aac' in available_encoder_set.get('audio')
46
+ assert 'libx264' in available_encoder_set.get('video')
47
+
48
+
49
+ def test_extract_frames() -> None:
50
+ extract_set =\
51
+ [
52
+ (get_test_example_file('target-240p-25fps.mp4'), 0, 270, 324),
53
+ (get_test_example_file('target-240p-25fps.mp4'), 224, 270, 55),
54
+ (get_test_example_file('target-240p-25fps.mp4'), 124, 224, 120),
55
+ (get_test_example_file('target-240p-25fps.mp4'), 0, 100, 120),
56
+ (get_test_example_file('target-240p-30fps.mp4'), 0, 324, 324),
57
+ (get_test_example_file('target-240p-30fps.mp4'), 224, 324, 100),
58
+ (get_test_example_file('target-240p-30fps.mp4'), 124, 224, 100),
59
+ (get_test_example_file('target-240p-30fps.mp4'), 0, 100, 100),
60
+ (get_test_example_file('target-240p-60fps.mp4'), 0, 648, 324),
61
+ (get_test_example_file('target-240p-60fps.mp4'), 224, 648, 212),
62
+ (get_test_example_file('target-240p-60fps.mp4'), 124, 224, 50),
63
+ (get_test_example_file('target-240p-60fps.mp4'), 0, 100, 50)
64
+ ]
65
+
66
+ for target_path, trim_frame_start, trim_frame_end, frame_total in extract_set:
67
+ create_temp_directory(target_path)
68
+
69
+ assert extract_frames(target_path, '452x240', 30.0, trim_frame_start, trim_frame_end) is True
70
+ assert len(resolve_temp_frame_paths(target_path)) == frame_total
71
+
72
+ clear_temp_directory(target_path)
73
+
74
+
75
+ def test_concat_video() -> None:
76
+ output_path = get_test_output_file('test-concat-video.mp4')
77
+ temp_output_paths =\
78
+ [
79
+ get_test_example_file('target-240p.mp4'),
80
+ get_test_example_file('target-240p.mp4')
81
+ ]
82
+
83
+ assert concat_video(output_path, temp_output_paths) is True
84
+
85
+
86
+ def test_read_audio_buffer() -> None:
87
+ assert isinstance(read_audio_buffer(get_test_example_file('source.mp3'), 1, 16, 1), bytes)
88
+ assert isinstance(read_audio_buffer(get_test_example_file('source.wav'), 1, 16, 1), bytes)
89
+ assert read_audio_buffer(get_test_example_file('invalid.mp3'), 1, 16, 1) is None
90
+
91
+
92
+ def test_restore_audio() -> None:
93
+ target_paths =\
94
+ [
95
+ get_test_example_file('target-240p-16khz.mp4'),
96
+ get_test_example_file('target-240p-48khz.mp4')
97
+ ]
98
+ output_path = get_test_output_file('test-restore-audio.mp4')
99
+
100
+ for target_path in target_paths:
101
+ create_temp_directory(target_path)
102
+ copy_file(target_path, get_temp_file_path(target_path))
103
+
104
+ assert restore_audio(target_path, output_path, 0, 270) is True
105
+
106
+ clear_temp_directory(target_path)
107
+
108
+
109
+ def test_replace_audio() -> None:
110
+ target_path = get_test_example_file('target-240p.mp4')
111
+ output_path = get_test_output_file('test-replace-audio.mp4')
112
+
113
+ create_temp_directory(target_path)
114
+ copy_file(target_path, get_temp_file_path(target_path))
115
+
116
+ assert replace_audio(target_path, get_test_example_file('source.mp3'), output_path) is True
117
+ assert replace_audio(target_path, get_test_example_file('source.wav'), output_path) is True
118
+
119
+ clear_temp_directory(target_path)
tests/test_ffmpeg_builder.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from shutil import which
2
+
3
+ from facefusion import ffmpeg_builder
4
+ from facefusion.ffmpeg_builder import chain, run, select_frame_range, set_audio_quality, set_audio_sample_size, set_stream_mode, set_video_quality
5
+
6
+
7
+ def test_run() -> None:
8
+ assert run([]) == [ which('ffmpeg'), '-loglevel', 'error' ]
9
+
10
+
11
+ def test_chain() -> None:
12
+ assert chain(ffmpeg_builder.set_progress()) == [ '-progress' ]
13
+
14
+
15
+ def test_set_stream_mode() -> None:
16
+ assert set_stream_mode('udp') == [ '-f', 'mpegts' ]
17
+ assert set_stream_mode('v4l2') == [ '-f', 'v4l2' ]
18
+
19
+
20
+ def test_select_frame_range() -> None:
21
+ assert select_frame_range(0, None, 30) == [ '-vf', 'trim=start_frame=0,fps=30' ]
22
+ assert select_frame_range(None, 100, 30) == [ '-vf', 'trim=end_frame=100,fps=30' ]
23
+ assert select_frame_range(0, 100, 30) == [ '-vf', 'trim=start_frame=0:end_frame=100,fps=30' ]
24
+ assert select_frame_range(None, None, 30) == [ '-vf', 'fps=30' ]
25
+
26
+
27
+ def test_set_audio_sample_size() -> None:
28
+ assert set_audio_sample_size(16) == [ '-f', 's16le' ]
29
+ assert set_audio_sample_size(32) == [ '-f', 's32le' ]
30
+
31
+
32
+ def test_set_audio_quality() -> None:
33
+ assert set_audio_quality('aac', 0) == [ '-q:a', '0.1' ]
34
+ assert set_audio_quality('aac', 50) == [ '-q:a', '1.0' ]
35
+ assert set_audio_quality('aac', 100) == [ '-q:a', '2.0' ]
36
+ assert set_audio_quality('libmp3lame', 0) == [ '-q:a', '9' ]
37
+ assert set_audio_quality('libmp3lame', 50) == [ '-q:a', '4' ]
38
+ assert set_audio_quality('libmp3lame', 100) == [ '-q:a', '0' ]
39
+ assert set_audio_quality('libopus', 0) == [ '-b:a', '64k' ]
40
+ assert set_audio_quality('libopus', 50) == [ '-b:a', '192k' ]
41
+ assert set_audio_quality('libopus', 100) == [ '-b:a', '320k' ]
42
+ assert set_audio_quality('libvorbis', 0) == [ '-q:a', '-1.0' ]
43
+ assert set_audio_quality('libvorbis', 50) == [ '-q:a', '4.5' ]
44
+ assert set_audio_quality('libvorbis', 100) == [ '-q:a', '10.0' ]
45
+ assert set_audio_quality('flac', 0) == []
46
+ assert set_audio_quality('flac', 50) == []
47
+ assert set_audio_quality('flac', 100) == []
48
+
49
+
50
+ def test_set_video_quality() -> None:
51
+ assert set_video_quality('libx264', 0) == [ '-crf', '51' ]
52
+ assert set_video_quality('libx264', 50) == [ '-crf', '26' ]
53
+ assert set_video_quality('libx264', 100) == [ '-crf', '0' ]
54
+ assert set_video_quality('libx265', 0) == [ '-crf', '51' ]
55
+ assert set_video_quality('libx265', 50) == [ '-crf', '26' ]
56
+ assert set_video_quality('libx265', 100) == [ '-crf', '0' ]
57
+ assert set_video_quality('libvpx-vp9', 0) == [ '-crf', '63' ]
58
+ assert set_video_quality('libvpx-vp9', 50) == [ '-crf', '32' ]
59
+ assert set_video_quality('libvpx-vp9', 100) == [ '-crf', '0' ]
60
+ assert set_video_quality('h264_nvenc', 0) == [ '-cq' , '51' ]
61
+ assert set_video_quality('h264_nvenc', 50) == [ '-cq' , '26' ]
62
+ assert set_video_quality('h264_nvenc', 100) == [ '-cq' , '0' ]
63
+ assert set_video_quality('hevc_nvenc', 0) == [ '-cq' , '51' ]
64
+ assert set_video_quality('hevc_nvenc', 50) == [ '-cq' , '26' ]
65
+ assert set_video_quality('hevc_nvenc', 100) == [ '-cq' , '0' ]
66
+ assert set_video_quality('h264_amf', 0) == [ '-qp_i', '51', '-qp_p', '51', '-qp_b', '51' ]
67
+ assert set_video_quality('h264_amf', 50) == [ '-qp_i', '26', '-qp_p', '26', '-qp_b', '26' ]
68
+ assert set_video_quality('h264_amf', 100) == [ '-qp_i', '0', '-qp_p', '0', '-qp_b', '0' ]
69
+ assert set_video_quality('hevc_amf', 0) == [ '-qp_i', '51', '-qp_p', '51', '-qp_b', '51' ]
70
+ assert set_video_quality('hevc_amf', 50) == [ '-qp_i', '26', '-qp_p', '26', '-qp_b', '26' ]
71
+ assert set_video_quality('hevc_amf', 100) == [ '-qp_i', '0', '-qp_p', '0', '-qp_b', '0' ]
72
+ assert set_video_quality('h264_qsv', 0) == [ '-qp', '51' ]
73
+ assert set_video_quality('h264_qsv', 50) == [ '-qp', '26' ]
74
+ assert set_video_quality('h264_qsv', 100) == [ '-qp', '0' ]
75
+ assert set_video_quality('hevc_qsv', 0) == [ '-qp', '51' ]
76
+ assert set_video_quality('hevc_qsv', 50) == [ '-qp', '26' ]
77
+ assert set_video_quality('hevc_qsv', 100) == [ '-qp', '0' ]
78
+ assert set_video_quality('h264_videotoolbox', 0) == [ '-b:v', '1024k' ]
79
+ assert set_video_quality('h264_videotoolbox', 50) == [ '-b:v', '25768k' ]
80
+ assert set_video_quality('h264_videotoolbox', 100) == [ '-b:v', '50512k' ]
81
+ assert set_video_quality('hevc_videotoolbox', 0) == [ '-b:v', '1024k' ]
82
+ assert set_video_quality('hevc_videotoolbox', 50) == [ '-b:v', '25768k' ]
83
+ assert set_video_quality('hevc_videotoolbox', 100) == [ '-b:v', '50512k' ]
tests/test_filesystem.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path
2
+
3
+ import pytest
4
+
5
+ from facefusion.download import conditional_download
6
+ from facefusion.filesystem import create_directory, filter_audio_paths, filter_image_paths, get_file_extension, get_file_format, get_file_size, has_audio, has_image, has_video, in_directory, is_audio, is_directory, is_file, is_image, is_video, remove_directory, resolve_file_paths, same_file_extension
7
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_outputs_directory
8
+
9
+
10
+ @pytest.fixture(scope = 'module', autouse = True)
11
+ def before_all() -> None:
12
+ conditional_download(get_test_examples_directory(),
13
+ [
14
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+
19
+
20
+ def test_get_file_size() -> None:
21
+ assert get_file_size(get_test_example_file('source.jpg')) == 549458
22
+ assert get_file_size('invalid') == 0
23
+
24
+
25
+ def test_get_file_extension() -> None:
26
+ assert get_file_extension('source.jpg') == '.jpg'
27
+ assert get_file_extension('source.mp3') == '.mp3'
28
+ assert get_file_extension('invalid') is None
29
+
30
+
31
+ def test_get_file_format() -> None:
32
+ assert get_file_format('source.jpg') == 'jpeg'
33
+ assert get_file_format('source.jpeg') == 'jpeg'
34
+ assert get_file_format('source.mp3') == 'mp3'
35
+ assert get_file_format('invalid') is None
36
+
37
+
38
+ def test_same_file_extension() -> None:
39
+ assert same_file_extension('source.jpg', 'source.jpg') is True
40
+ assert same_file_extension('source.jpg', 'source.mp3') is False
41
+ assert same_file_extension('invalid', 'invalid') is False
42
+
43
+
44
+ def test_is_file() -> None:
45
+ assert is_file(get_test_example_file('source.jpg')) is True
46
+ assert is_file(get_test_examples_directory()) is False
47
+ assert is_file('invalid') is False
48
+
49
+
50
+ def test_is_audio() -> None:
51
+ assert is_audio(get_test_example_file('source.mp3')) is True
52
+ assert is_audio(get_test_example_file('source.jpg')) is False
53
+ assert is_audio('invalid') is False
54
+
55
+
56
+ def test_has_audio() -> None:
57
+ assert has_audio([ get_test_example_file('source.mp3') ]) is True
58
+ assert has_audio([ get_test_example_file('source.mp3'), get_test_example_file('source.jpg') ]) is True
59
+ assert has_audio([ get_test_example_file('source.jpg'), get_test_example_file('source.jpg') ]) is False
60
+ assert has_audio([ 'invalid' ]) is False
61
+
62
+
63
+ def test_is_image() -> None:
64
+ assert is_image(get_test_example_file('source.jpg')) is True
65
+ assert is_image(get_test_example_file('target-240p.mp4')) is False
66
+ assert is_image('invalid') is False
67
+
68
+
69
+ def test_has_image() -> None:
70
+ assert has_image([ get_test_example_file('source.jpg') ]) is True
71
+ assert has_image([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) is True
72
+ assert has_image([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) is False
73
+ assert has_image([ 'invalid' ]) is False
74
+
75
+
76
+ def test_is_video() -> None:
77
+ assert is_video(get_test_example_file('target-240p.mp4')) is True
78
+ assert is_video(get_test_example_file('source.jpg')) is False
79
+ assert is_video('invalid') is False
80
+
81
+
82
+ def test_has_video() -> None:
83
+ assert has_video([ get_test_example_file('target-240p.mp4') ]) is True
84
+ assert has_video([ get_test_example_file('target-240p.mp4'), get_test_example_file('source.mp3') ]) is True
85
+ assert has_video([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) is False
86
+ assert has_video([ 'invalid' ]) is False
87
+
88
+
89
+ def test_filter_audio_paths() -> None:
90
+ assert filter_audio_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) == [ get_test_example_file('source.mp3') ]
91
+ assert filter_audio_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.jpg') ]) == []
92
+ assert filter_audio_paths([ 'invalid' ]) == []
93
+
94
+
95
+ def test_filter_image_paths() -> None:
96
+ assert filter_image_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) == [ get_test_example_file('source.jpg') ]
97
+ assert filter_image_paths([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) == []
98
+ assert filter_audio_paths([ 'invalid' ]) == []
99
+
100
+
101
+ def test_resolve_file_paths() -> None:
102
+ file_paths = resolve_file_paths(get_test_examples_directory())
103
+
104
+ for file_path in file_paths:
105
+ assert file_path == get_test_example_file(file_path)
106
+
107
+ assert resolve_file_paths('invalid') == []
108
+
109
+
110
+ def test_create_directory() -> None:
111
+ create_directory_path = os.path.join(get_test_outputs_directory(), 'create_directory')
112
+
113
+ assert create_directory(create_directory_path) is True
114
+ assert create_directory(get_test_example_file('source.jpg')) is False
115
+
116
+
117
+ def test_remove_directory() -> None:
118
+ remove_directory_path = os.path.join(get_test_outputs_directory(), 'remove_directory')
119
+ create_directory(remove_directory_path)
120
+
121
+ assert remove_directory(remove_directory_path) is True
122
+ assert remove_directory(get_test_example_file('source.jpg')) is False
123
+ assert remove_directory('invalid') is False
124
+
125
+
126
+ def test_is_directory() -> None:
127
+ assert is_directory(get_test_examples_directory()) is True
128
+ assert is_directory(get_test_example_file('source.jpg')) is False
129
+ assert is_directory('invalid') is False
130
+
131
+
132
+ def test_in_directory() -> None:
133
+ assert in_directory(get_test_example_file('source.jpg')) is True
134
+ assert in_directory('source.jpg') is False
135
+ assert in_directory('invalid') is False
tests/test_inference_manager.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from unittest.mock import patch
2
+
3
+ import pytest
4
+ from onnxruntime import InferenceSession
5
+
6
+ from facefusion import content_analyser, state_manager
7
+ from facefusion.inference_manager import INFERENCE_POOL_SET, get_inference_pool
8
+
9
+
10
+ @pytest.fixture(scope = 'module', autouse = True)
11
+ def before_all() -> None:
12
+ state_manager.init_item('execution_device_id', '0')
13
+ state_manager.init_item('execution_providers', [ 'cpu' ])
14
+ state_manager.init_item('download_providers', [ 'github' ])
15
+ content_analyser.pre_check()
16
+
17
+
18
+ def test_get_inference_pool() -> None:
19
+ model_names = [ 'yolo_nsfw' ]
20
+ model_source_set = content_analyser.get_model_options().get('sources')
21
+
22
+ with patch('facefusion.inference_manager.detect_app_context', return_value = 'cli'):
23
+ get_inference_pool('facefusion.content_analyser', model_names, model_source_set)
24
+
25
+ assert isinstance(INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser'), InferenceSession)
26
+
27
+ with patch('facefusion.inference_manager.detect_app_context', return_value = 'ui'):
28
+ get_inference_pool('facefusion.content_analyser', model_names, model_source_set)
29
+
30
+ assert isinstance(INFERENCE_POOL_SET.get('ui').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser'), InferenceSession)
31
+
32
+ assert INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser') == INFERENCE_POOL_SET.get('ui').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser')
tests/test_job_helper.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from facefusion.jobs.job_helper import get_step_output_path
4
+
5
+
6
+ def test_get_step_output_path() -> None:
7
+ assert get_step_output_path('test-job', 0, 'test.mp4') == 'test-test-job-0.mp4'
8
+ assert get_step_output_path('test-job', 0, 'test/test.mp4') == os.path.join('test', 'test-test-job-0.mp4')
tests/test_job_list.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from time import sleep
2
+
3
+ import pytest
4
+
5
+ from facefusion.jobs.job_list import compose_job_list
6
+ from facefusion.jobs.job_manager import clear_jobs, create_job, init_jobs
7
+ from .helper import get_test_jobs_directory
8
+
9
+
10
+ @pytest.fixture(scope = 'function', autouse = True)
11
+ def before_each() -> None:
12
+ clear_jobs(get_test_jobs_directory())
13
+ init_jobs(get_test_jobs_directory())
14
+
15
+
16
+ def test_compose_job_list() -> None:
17
+ create_job('job-test-compose-job-list-1')
18
+ sleep(0.5)
19
+ create_job('job-test-compose-job-list-2')
20
+ job_headers, job_contents = compose_job_list('drafted')
21
+
22
+ assert job_headers == [ 'job id', 'steps', 'date created', 'date updated', 'job status' ]
23
+ assert job_contents[0] == [ 'job-test-compose-job-list-1', 0, 'just now', None, 'drafted' ]
24
+ assert job_contents[1] == [ 'job-test-compose-job-list-2', 0, 'just now', None, 'drafted' ]
tests/test_job_manager.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from time import sleep
2
+
3
+ import pytest
4
+
5
+ from facefusion.jobs.job_helper import get_step_output_path
6
+ from facefusion.jobs.job_manager import add_step, clear_jobs, count_step_total, create_job, delete_job, delete_jobs, find_job_ids, get_steps, init_jobs, insert_step, move_job_file, remix_step, remove_step, set_step_status, set_steps_status, submit_job, submit_jobs
7
+ from .helper import get_test_jobs_directory
8
+
9
+
10
+ @pytest.fixture(scope = 'function', autouse = True)
11
+ def before_each() -> None:
12
+ clear_jobs(get_test_jobs_directory())
13
+ init_jobs(get_test_jobs_directory())
14
+
15
+
16
+ def test_create_job() -> None:
17
+ args_1 =\
18
+ {
19
+ 'source_path': 'source-1.jpg',
20
+ 'target_path': 'target-1.jpg',
21
+ 'output_path': 'output-1.jpg'
22
+ }
23
+
24
+ assert create_job('job-test-create-job') is True
25
+ assert create_job('job-test-create-job') is False
26
+
27
+ add_step('job-test-submit-job', args_1)
28
+ submit_job('job-test-create-job')
29
+
30
+ assert create_job('job-test-create-job') is False
31
+
32
+
33
+ def test_submit_job() -> None:
34
+ args_1 =\
35
+ {
36
+ 'source_path': 'source-1.jpg',
37
+ 'target_path': 'target-1.jpg',
38
+ 'output_path': 'output-1.jpg'
39
+ }
40
+
41
+ assert submit_job('job-invalid') is False
42
+
43
+ create_job('job-test-submit-job')
44
+
45
+ assert submit_job('job-test-submit-job') is False
46
+
47
+ add_step('job-test-submit-job', args_1)
48
+
49
+ assert submit_job('job-test-submit-job') is True
50
+ assert submit_job('job-test-submit-job') is False
51
+
52
+
53
+ def test_submit_jobs() -> None:
54
+ args_1 =\
55
+ {
56
+ 'source_path': 'source-1.jpg',
57
+ 'target_path': 'target-1.jpg',
58
+ 'output_path': 'output-1.jpg'
59
+ }
60
+ args_2 =\
61
+ {
62
+ 'source_path': 'source-2.jpg',
63
+ 'target_path': 'target-2.jpg',
64
+ 'output_path': 'output-2.jpg'
65
+ }
66
+ halt_on_error = True
67
+
68
+ assert submit_jobs(halt_on_error) is False
69
+
70
+ create_job('job-test-submit-jobs-1')
71
+ create_job('job-test-submit-jobs-2')
72
+
73
+ assert submit_jobs(halt_on_error) is False
74
+
75
+ add_step('job-test-submit-jobs-1', args_1)
76
+ add_step('job-test-submit-jobs-2', args_2)
77
+
78
+ assert submit_jobs(halt_on_error) is True
79
+ assert submit_jobs(halt_on_error) is False
80
+
81
+
82
+ def test_delete_job() -> None:
83
+ assert delete_job('job-invalid') is False
84
+
85
+ create_job('job-test-delete-job')
86
+
87
+ assert delete_job('job-test-delete-job') is True
88
+ assert delete_job('job-test-delete-job') is False
89
+
90
+
91
+ def test_delete_jobs() -> None:
92
+ halt_on_error = True
93
+
94
+ assert delete_jobs(halt_on_error) is False
95
+
96
+ create_job('job-test-delete-jobs-1')
97
+ create_job('job-test-delete-jobs-2')
98
+
99
+ assert delete_jobs(halt_on_error) is True
100
+
101
+
102
+ @pytest.mark.skip()
103
+ def test_find_jobs() -> None:
104
+ pass
105
+
106
+
107
+ def test_find_job_ids() -> None:
108
+ create_job('job-test-find-job-ids-1')
109
+ sleep(0.5)
110
+ create_job('job-test-find-job-ids-2')
111
+ sleep(0.5)
112
+ create_job('job-test-find-job-ids-3')
113
+
114
+ assert find_job_ids('drafted') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
115
+ assert find_job_ids('queued') == []
116
+ assert find_job_ids('completed') == []
117
+ assert find_job_ids('failed') == []
118
+
119
+ move_job_file('job-test-find-job-ids-1', 'queued')
120
+ move_job_file('job-test-find-job-ids-2', 'queued')
121
+ move_job_file('job-test-find-job-ids-3', 'queued')
122
+
123
+ assert find_job_ids('drafted') == []
124
+ assert find_job_ids('queued') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
125
+ assert find_job_ids('completed') == []
126
+ assert find_job_ids('failed') == []
127
+
128
+ move_job_file('job-test-find-job-ids-1', 'completed')
129
+
130
+ assert find_job_ids('drafted') == []
131
+ assert find_job_ids('queued') == [ 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
132
+ assert find_job_ids('completed') == [ 'job-test-find-job-ids-1' ]
133
+ assert find_job_ids('failed') == []
134
+
135
+ move_job_file('job-test-find-job-ids-2', 'failed')
136
+
137
+ assert find_job_ids('drafted') == []
138
+ assert find_job_ids('queued') == [ 'job-test-find-job-ids-3' ]
139
+ assert find_job_ids('completed') == [ 'job-test-find-job-ids-1' ]
140
+ assert find_job_ids('failed') == [ 'job-test-find-job-ids-2' ]
141
+
142
+ move_job_file('job-test-find-job-ids-3', 'completed')
143
+
144
+ assert find_job_ids('drafted') == []
145
+ assert find_job_ids('queued') == []
146
+ assert find_job_ids('completed') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-3' ]
147
+ assert find_job_ids('failed') == [ 'job-test-find-job-ids-2' ]
148
+
149
+
150
+ def test_add_step() -> None:
151
+ args_1 =\
152
+ {
153
+ 'source_path': 'source-1.jpg',
154
+ 'target_path': 'target-1.jpg',
155
+ 'output_path': 'output-1.jpg'
156
+ }
157
+ args_2 =\
158
+ {
159
+ 'source_path': 'source-2.jpg',
160
+ 'target_path': 'target-2.jpg',
161
+ 'output_path': 'output-2.jpg'
162
+ }
163
+
164
+ assert add_step('job-invalid', args_1) is False
165
+
166
+ create_job('job-test-add-step')
167
+
168
+ assert add_step('job-test-add-step', args_1) is True
169
+ assert add_step('job-test-add-step', args_2) is True
170
+
171
+ steps = get_steps('job-test-add-step')
172
+
173
+ assert steps[0].get('args') == args_1
174
+ assert steps[1].get('args') == args_2
175
+ assert count_step_total('job-test-add-step') == 2
176
+
177
+
178
+ def test_remix_step() -> None:
179
+ args_1 =\
180
+ {
181
+ 'source_path': 'source-1.jpg',
182
+ 'target_path': 'target-1.jpg',
183
+ 'output_path': 'output-1.jpg'
184
+ }
185
+ args_2 =\
186
+ {
187
+ 'source_path': 'source-2.jpg',
188
+ 'target_path': 'target-2.jpg',
189
+ 'output_path': 'output-2.jpg'
190
+ }
191
+
192
+ assert remix_step('job-invalid', 0, args_1) is False
193
+
194
+ create_job('job-test-remix-step')
195
+ add_step('job-test-remix-step', args_1)
196
+ add_step('job-test-remix-step', args_2)
197
+
198
+ assert remix_step('job-test-remix-step', 99, args_1) is False
199
+ assert remix_step('job-test-remix-step', 0, args_2) is True
200
+ assert remix_step('job-test-remix-step', -1, args_2) is True
201
+
202
+ steps = get_steps('job-test-remix-step')
203
+
204
+ assert steps[0].get('args') == args_1
205
+ assert steps[1].get('args') == args_2
206
+ assert steps[2].get('args').get('source_path') == args_2.get('source_path')
207
+ assert steps[2].get('args').get('target_path') == get_step_output_path('job-test-remix-step', 0, args_1.get('output_path'))
208
+ assert steps[2].get('args').get('output_path') == args_2.get('output_path')
209
+ assert steps[3].get('args').get('source_path') == args_2.get('source_path')
210
+ assert steps[3].get('args').get('target_path') == get_step_output_path('job-test-remix-step', 2, args_2.get('output_path'))
211
+ assert steps[3].get('args').get('output_path') == args_2.get('output_path')
212
+ assert count_step_total('job-test-remix-step') == 4
213
+
214
+
215
+ def test_insert_step() -> None:
216
+ args_1 =\
217
+ {
218
+ 'source_path': 'source-1.jpg',
219
+ 'target_path': 'target-1.jpg',
220
+ 'output_path': 'output-1.jpg'
221
+ }
222
+ args_2 =\
223
+ {
224
+ 'source_path': 'source-2.jpg',
225
+ 'target_path': 'target-2.jpg',
226
+ 'output_path': 'output-2.jpg'
227
+ }
228
+ args_3 =\
229
+ {
230
+ 'source_path': 'source-3.jpg',
231
+ 'target_path': 'target-3.jpg',
232
+ 'output_path': 'output-3.jpg'
233
+ }
234
+
235
+ assert insert_step('job-invalid', 0, args_1) is False
236
+
237
+ create_job('job-test-insert-step')
238
+ add_step('job-test-insert-step', args_1)
239
+ add_step('job-test-insert-step', args_1)
240
+
241
+ assert insert_step('job-test-insert-step', 99, args_1) is False
242
+ assert insert_step('job-test-insert-step', 0, args_2) is True
243
+ assert insert_step('job-test-insert-step', -1, args_3) is True
244
+
245
+ steps = get_steps('job-test-insert-step')
246
+
247
+ assert steps[0].get('args') == args_2
248
+ assert steps[1].get('args') == args_1
249
+ assert steps[2].get('args') == args_3
250
+ assert steps[3].get('args') == args_1
251
+ assert count_step_total('job-test-insert-step') == 4
252
+
253
+
254
+ def test_remove_step() -> None:
255
+ args_1 =\
256
+ {
257
+ 'source_path': 'source-1.jpg',
258
+ 'target_path': 'target-1.jpg',
259
+ 'output_path': 'output-1.jpg'
260
+ }
261
+ args_2 =\
262
+ {
263
+ 'source_path': 'source-2.jpg',
264
+ 'target_path': 'target-2.jpg',
265
+ 'output_path': 'output-2.jpg'
266
+ }
267
+ args_3 =\
268
+ {
269
+ 'source_path': 'source-3.jpg',
270
+ 'target_path': 'target-3.jpg',
271
+ 'output_path': 'output-3.jpg'
272
+ }
273
+
274
+ assert remove_step('job-invalid', 0) is False
275
+
276
+ create_job('job-test-remove-step')
277
+ add_step('job-test-remove-step', args_1)
278
+ add_step('job-test-remove-step', args_2)
279
+ add_step('job-test-remove-step', args_1)
280
+ add_step('job-test-remove-step', args_3)
281
+
282
+ assert remove_step('job-test-remove-step', 99) is False
283
+ assert remove_step('job-test-remove-step', 0) is True
284
+ assert remove_step('job-test-remove-step', -1) is True
285
+
286
+ steps = get_steps('job-test-remove-step')
287
+
288
+ assert steps[0].get('args') == args_2
289
+ assert steps[1].get('args') == args_1
290
+ assert count_step_total('job-test-remove-step') == 2
291
+
292
+
293
+ def test_get_steps() -> None:
294
+ args_1 =\
295
+ {
296
+ 'source_path': 'source-1.jpg',
297
+ 'target_path': 'target-1.jpg',
298
+ 'output_path': 'output-1.jpg'
299
+ }
300
+ args_2 =\
301
+ {
302
+ 'source_path': 'source-2.jpg',
303
+ 'target_path': 'target-2.jpg',
304
+ 'output_path': 'output-2.jpg'
305
+ }
306
+
307
+ assert get_steps('job-invalid') == []
308
+
309
+ create_job('job-test-get-steps')
310
+ add_step('job-test-get-steps', args_1)
311
+ add_step('job-test-get-steps', args_2)
312
+ steps = get_steps('job-test-get-steps')
313
+
314
+ assert steps[0].get('args') == args_1
315
+ assert steps[1].get('args') == args_2
316
+ assert count_step_total('job-test-get-steps') == 2
317
+
318
+
319
+ def test_set_step_status() -> None:
320
+ args_1 =\
321
+ {
322
+ 'source_path': 'source-1.jpg',
323
+ 'target_path': 'target-1.jpg',
324
+ 'output_path': 'output-1.jpg'
325
+ }
326
+ args_2 =\
327
+ {
328
+ 'source_path': 'source-2.jpg',
329
+ 'target_path': 'target-2.jpg',
330
+ 'output_path': 'output-2.jpg'
331
+ }
332
+
333
+ assert set_step_status('job-invalid', 0, 'completed') is False
334
+
335
+ create_job('job-test-set-step-status')
336
+ add_step('job-test-set-step-status', args_1)
337
+ add_step('job-test-set-step-status', args_2)
338
+
339
+ assert set_step_status('job-test-set-step-status', 99, 'completed') is False
340
+ assert set_step_status('job-test-set-step-status', 0, 'completed') is True
341
+ assert set_step_status('job-test-set-step-status', 1, 'failed') is True
342
+
343
+ steps = get_steps('job-test-set-step-status')
344
+
345
+ assert steps[0].get('status') == 'completed'
346
+ assert steps[1].get('status') == 'failed'
347
+ assert count_step_total('job-test-set-step-status') == 2
348
+
349
+
350
+ def test_set_steps_status() -> None:
351
+ args_1 =\
352
+ {
353
+ 'source_path': 'source-1.jpg',
354
+ 'target_path': 'target-1.jpg',
355
+ 'output_path': 'output-1.jpg'
356
+ }
357
+ args_2 =\
358
+ {
359
+ 'source_path': 'source-2.jpg',
360
+ 'target_path': 'target-2.jpg',
361
+ 'output_path': 'output-2.jpg'
362
+ }
363
+
364
+ assert set_steps_status('job-invalid', 'queued') is False
365
+
366
+ create_job('job-test-set-steps-status')
367
+ add_step('job-test-set-steps-status', args_1)
368
+ add_step('job-test-set-steps-status', args_2)
369
+
370
+ assert set_steps_status('job-test-set-steps-status', 'queued') is True
371
+
372
+ steps = get_steps('job-test-set-steps-status')
373
+
374
+ assert steps[0].get('status') == 'queued'
375
+ assert steps[1].get('status') == 'queued'
376
+ assert count_step_total('job-test-set-steps-status') == 2
tests/test_job_runner.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+
3
+ import pytest
4
+
5
+ from facefusion.download import conditional_download
6
+ from facefusion.filesystem import copy_file
7
+ from facefusion.jobs.job_manager import add_step, clear_jobs, create_job, init_jobs, submit_job, submit_jobs
8
+ from facefusion.jobs.job_runner import collect_output_set, finalize_steps, run_job, run_jobs, run_steps
9
+ from facefusion.types import Args
10
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
11
+
12
+
13
+ @pytest.fixture(scope = 'module', autouse = True)
14
+ def before_all() -> None:
15
+ conditional_download(get_test_examples_directory(),
16
+ [
17
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
18
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
19
+ ])
20
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
21
+
22
+
23
+ @pytest.fixture(scope = 'function', autouse = True)
24
+ def before_each() -> None:
25
+ clear_jobs(get_test_jobs_directory())
26
+ init_jobs(get_test_jobs_directory())
27
+ prepare_test_output_directory()
28
+
29
+
30
+ def process_step(job_id : str, step_index : int, step_args : Args) -> bool:
31
+ return copy_file(step_args.get('target_path'), step_args.get('output_path'))
32
+
33
+
34
+ def test_run_job() -> None:
35
+ args_1 =\
36
+ {
37
+ 'source_path': get_test_example_file('source.jpg'),
38
+ 'target_path': get_test_example_file('target-240p.mp4'),
39
+ 'output_path': get_test_output_file('output-1.mp4')
40
+ }
41
+ args_2 =\
42
+ {
43
+ 'source_path': get_test_example_file('source.jpg'),
44
+ 'target_path': get_test_example_file('target-240p.mp4'),
45
+ 'output_path': get_test_output_file('output-2.mp4')
46
+ }
47
+ args_3 =\
48
+ {
49
+ 'source_path': get_test_example_file('source.jpg'),
50
+ 'target_path': get_test_example_file('target-240p.jpg'),
51
+ 'output_path': get_test_output_file('output-1.jpg')
52
+ }
53
+
54
+ assert run_job('job-invalid', process_step) is False
55
+
56
+ create_job('job-test-run-job')
57
+ add_step('job-test-run-job', args_1)
58
+ add_step('job-test-run-job', args_2)
59
+ add_step('job-test-run-job', args_2)
60
+ add_step('job-test-run-job', args_3)
61
+
62
+ assert run_job('job-test-run-job', process_step) is False
63
+
64
+ submit_job('job-test-run-job')
65
+
66
+ assert run_job('job-test-run-job', process_step) is True
67
+
68
+
69
+ def test_run_jobs() -> None:
70
+ args_1 =\
71
+ {
72
+ 'source_path': get_test_example_file('source.jpg'),
73
+ 'target_path': get_test_example_file('target-240p.mp4'),
74
+ 'output_path': get_test_output_file('output-1.mp4')
75
+ }
76
+ args_2 =\
77
+ {
78
+ 'source_path': get_test_example_file('source.jpg'),
79
+ 'target_path': get_test_example_file('target-240p.mp4'),
80
+ 'output_path': get_test_output_file('output-2.mp4')
81
+ }
82
+ args_3 =\
83
+ {
84
+ 'source_path': get_test_example_file('source.jpg'),
85
+ 'target_path': get_test_example_file('target-240p.jpg'),
86
+ 'output_path': get_test_output_file('output-1.jpg')
87
+ }
88
+ halt_on_error = True
89
+
90
+ assert run_jobs(process_step, halt_on_error) is False
91
+
92
+ create_job('job-test-run-jobs-1')
93
+ create_job('job-test-run-jobs-2')
94
+ add_step('job-test-run-jobs-1', args_1)
95
+ add_step('job-test-run-jobs-1', args_1)
96
+ add_step('job-test-run-jobs-2', args_2)
97
+ add_step('job-test-run-jobs-3', args_3)
98
+
99
+ assert run_jobs(process_step, halt_on_error) is False
100
+
101
+ submit_jobs(halt_on_error)
102
+
103
+ assert run_jobs(process_step, halt_on_error) is True
104
+
105
+
106
+ @pytest.mark.skip()
107
+ def test_retry_job() -> None:
108
+ pass
109
+
110
+
111
+ @pytest.mark.skip()
112
+ def test_retry_jobs() -> None:
113
+ pass
114
+
115
+
116
+ def test_run_steps() -> None:
117
+ args_1 =\
118
+ {
119
+ 'source_path': get_test_example_file('source.jpg'),
120
+ 'target_path': get_test_example_file('target-240p.mp4'),
121
+ 'output_path': get_test_output_file('output-1.mp4')
122
+ }
123
+ args_2 =\
124
+ {
125
+ 'source_path': get_test_example_file('source.jpg'),
126
+ 'target_path': get_test_example_file('target-240p.mp4'),
127
+ 'output_path': get_test_output_file('output-2.mp4')
128
+ }
129
+ args_3 =\
130
+ {
131
+ 'source_path': get_test_example_file('source.jpg'),
132
+ 'target_path': get_test_example_file('target-240p.jpg'),
133
+ 'output_path': get_test_output_file('output-1.jpg')
134
+ }
135
+
136
+ assert run_steps('job-invalid', process_step) is False
137
+
138
+ create_job('job-test-run-steps')
139
+ add_step('job-test-run-steps', args_1)
140
+ add_step('job-test-run-steps', args_1)
141
+ add_step('job-test-run-steps', args_2)
142
+ add_step('job-test-run-steps', args_3)
143
+
144
+ assert run_steps('job-test-run-steps', process_step) is True
145
+
146
+
147
+ def test_finalize_steps() -> None:
148
+ args_1 =\
149
+ {
150
+ 'source_path': get_test_example_file('source.jpg'),
151
+ 'target_path': get_test_example_file('target-240p.mp4'),
152
+ 'output_path': get_test_output_file('output-1.mp4')
153
+ }
154
+ args_2 =\
155
+ {
156
+ 'source_path': get_test_example_file('source.jpg'),
157
+ 'target_path': get_test_example_file('target-240p.mp4'),
158
+ 'output_path': get_test_output_file('output-2.mp4')
159
+ }
160
+ args_3 =\
161
+ {
162
+ 'source_path': get_test_example_file('source.jpg'),
163
+ 'target_path': get_test_example_file('target-240p.jpg'),
164
+ 'output_path': get_test_output_file('output-1.jpg')
165
+ }
166
+
167
+ create_job('job-test-finalize-steps')
168
+ add_step('job-test-finalize-steps', args_1)
169
+ add_step('job-test-finalize-steps', args_1)
170
+ add_step('job-test-finalize-steps', args_2)
171
+ add_step('job-test-finalize-steps', args_3)
172
+
173
+ copy_file(args_1.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-0.mp4'))
174
+ copy_file(args_1.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-1.mp4'))
175
+ copy_file(args_2.get('target_path'), get_test_output_file('output-2-job-test-finalize-steps-2.mp4'))
176
+ copy_file(args_3.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-3.jpg'))
177
+
178
+ assert finalize_steps('job-test-finalize-steps') is True
179
+ assert is_test_output_file('output-1.mp4') is True
180
+ assert is_test_output_file('output-2.mp4') is True
181
+ assert is_test_output_file('output-1.jpg') is True
182
+
183
+
184
+ def test_collect_output_set() -> None:
185
+ args_1 =\
186
+ {
187
+ 'source_path': get_test_example_file('source.jpg'),
188
+ 'target_path': get_test_example_file('target-240p.mp4'),
189
+ 'output_path': get_test_output_file('output-1.mp4')
190
+ }
191
+ args_2 =\
192
+ {
193
+ 'source_path': get_test_example_file('source.jpg'),
194
+ 'target_path': get_test_example_file('target-240p.mp4'),
195
+ 'output_path': get_test_output_file('output-2.mp4')
196
+ }
197
+ args_3 =\
198
+ {
199
+ 'source_path': get_test_example_file('source.jpg'),
200
+ 'target_path': get_test_example_file('target-240p.jpg'),
201
+ 'output_path': get_test_output_file('output-1.jpg')
202
+ }
203
+
204
+ create_job('job-test-collect-output-set')
205
+ add_step('job-test-collect-output-set', args_1)
206
+ add_step('job-test-collect-output-set', args_1)
207
+ add_step('job-test-collect-output-set', args_2)
208
+ add_step('job-test-collect-output-set', args_3)
209
+
210
+ output_set =\
211
+ {
212
+ get_test_output_file('output-1.mp4'):
213
+ [
214
+ get_test_output_file('output-1-job-test-collect-output-set-0.mp4'),
215
+ get_test_output_file('output-1-job-test-collect-output-set-1.mp4')
216
+ ],
217
+ get_test_output_file('output-2.mp4'):
218
+ [
219
+ get_test_output_file('output-2-job-test-collect-output-set-2.mp4')
220
+ ],
221
+ get_test_output_file('output-1.jpg'):
222
+ [
223
+ get_test_output_file('output-1-job-test-collect-output-set-3.jpg')
224
+ ]
225
+ }
226
+
227
+ assert collect_output_set('job-test-collect-output-set') == output_set
tests/test_json.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tempfile
2
+
3
+ from facefusion.json import read_json, write_json
4
+
5
+
6
+ def test_read_json() -> None:
7
+ _, json_path = tempfile.mkstemp(suffix = '.json')
8
+
9
+ assert not read_json(json_path)
10
+
11
+ write_json(json_path, {})
12
+
13
+ assert read_json(json_path) == {}
14
+
15
+
16
+ def test_write_json() -> None:
17
+ _, json_path = tempfile.mkstemp(suffix = '.json')
18
+
19
+ assert write_json(json_path, {})
tests/test_memory.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from facefusion.common_helper import is_linux, is_macos
2
+ from facefusion.memory import limit_system_memory
3
+
4
+
5
+ def test_limit_system_memory() -> None:
6
+ assert limit_system_memory(4) is True
7
+ if is_linux() or is_macos():
8
+ assert limit_system_memory(1024) is False
tests/test_normalizer.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.normalizer import normalize_fps, normalize_padding
2
+
3
+
4
+ def test_normalize_padding() -> None:
5
+ assert normalize_padding([ 0, 0, 0, 0 ]) == (0, 0, 0, 0)
6
+ assert normalize_padding([ 1 ]) == (1, 1, 1, 1)
7
+ assert normalize_padding([ 1, 2 ]) == (1, 2, 1, 2)
8
+ assert normalize_padding([ 1, 2, 3 ]) == (1, 2, 3, 2)
9
+ assert normalize_padding(None) is None
10
+
11
+
12
+ def test_normalize_fps() -> None:
13
+ assert normalize_fps(0.0) == 1.0
14
+ assert normalize_fps(25.0) == 25.0
15
+ assert normalize_fps(61.0) == 60.0
16
+ assert normalize_fps(None) is None
tests/test_process_manager.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.process_manager import end, is_pending, is_processing, is_stopping, set_process_state, start, stop
2
+
3
+
4
+ def test_start() -> None:
5
+ set_process_state('pending')
6
+ start()
7
+
8
+ assert is_processing()
9
+
10
+
11
+ def test_stop() -> None:
12
+ set_process_state('processing')
13
+ stop()
14
+
15
+ assert is_stopping()
16
+
17
+
18
+ def test_end() -> None:
19
+ set_process_state('processing')
20
+ end()
21
+
22
+ assert is_pending()
tests/test_program_helper.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from argparse import ArgumentParser
2
+
3
+ import pytest
4
+
5
+ from facefusion.program_helper import find_argument_group, validate_actions
6
+
7
+
8
+ def test_find_argument_group() -> None:
9
+ program = ArgumentParser()
10
+ program.add_argument_group('test-1')
11
+ program.add_argument_group('test-2')
12
+
13
+ assert find_argument_group(program, 'test-1')
14
+ assert find_argument_group(program, 'test-2')
15
+ assert find_argument_group(program, 'invalid') is None
16
+
17
+
18
+ @pytest.mark.skip()
19
+ def test_validate_args() -> None:
20
+ pass
21
+
22
+
23
+ def test_validate_actions() -> None:
24
+ program = ArgumentParser()
25
+ program.add_argument('--test-1', default = 'test_1', choices = [ 'test_1', 'test_2' ])
26
+ program.add_argument('--test-2', default = 'test_2', choices= [ 'test_1', 'test_2' ], nargs = '+')
27
+
28
+ assert validate_actions(program) is True
29
+
30
+ args =\
31
+ {
32
+ 'test_1': 'test_2',
33
+ 'test_2': [ 'test_1', 'test_3' ]
34
+ }
35
+
36
+ for action in program._actions:
37
+ if action.dest in args:
38
+ action.default = args[action.dest]
39
+
40
+ assert validate_actions(program) is False
tests/test_temp_helper.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path
2
+ import tempfile
3
+
4
+ import pytest
5
+
6
+ from facefusion import state_manager
7
+ from facefusion.download import conditional_download
8
+ from facefusion.temp_helper import get_temp_directory_path, get_temp_file_path, get_temp_frames_pattern
9
+ from .helper import get_test_example_file, get_test_examples_directory
10
+
11
+
12
+ @pytest.fixture(scope = 'module', autouse = True)
13
+ def before_all() -> None:
14
+ conditional_download(get_test_examples_directory(),
15
+ [
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
17
+ ])
18
+ state_manager.init_item('temp_path', tempfile.gettempdir())
19
+ state_manager.init_item('temp_frame_format', 'png')
20
+
21
+
22
+ def test_get_temp_file_path() -> None:
23
+ temp_directory = tempfile.gettempdir()
24
+ assert get_temp_file_path(get_test_example_file('target-240p.mp4')) == os.path.join(temp_directory, 'facefusion', 'target-240p', 'temp.mp4')
25
+
26
+
27
+ def test_get_temp_directory_path() -> None:
28
+ temp_directory = tempfile.gettempdir()
29
+ assert get_temp_directory_path(get_test_example_file('target-240p.mp4')) == os.path.join(temp_directory, 'facefusion', 'target-240p')
30
+
31
+
32
+ def test_get_temp_frames_pattern() -> None:
33
+ temp_directory = tempfile.gettempdir()
34
+ assert get_temp_frames_pattern(get_test_example_file('target-240p.mp4'), '%04d') == os.path.join(temp_directory, 'facefusion', 'target-240p', '%04d.png')
tests/test_vision.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+
3
+ import pytest
4
+
5
+ from facefusion.download import conditional_download
6
+ from facefusion.vision import calc_histogram_difference, count_trim_frame_total, count_video_frame_total, create_image_resolutions, create_video_resolutions, detect_image_resolution, detect_video_duration, detect_video_fps, detect_video_resolution, match_frame_color, normalize_resolution, pack_resolution, predict_video_frame_total, read_image, read_video_frame, restrict_image_resolution, restrict_trim_frame, restrict_video_fps, restrict_video_resolution, unpack_resolution, write_image
7
+ from .helper import get_test_example_file, get_test_examples_directory, get_test_output_file, prepare_test_output_directory
8
+
9
+
10
+ @pytest.fixture(scope = 'module', autouse = True)
11
+ def before_all() -> None:
12
+ conditional_download(get_test_examples_directory(),
13
+ [
14
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
15
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4',
16
+ 'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-1080p.mp4'
17
+ ])
18
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
19
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('目标-240p.webp') ])
20
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vframes', '1', get_test_example_file('target-1080p.jpg') ])
21
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.jpg') ])
22
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'transpose=0', get_test_example_file('target-240p-90deg.jpg') ])
23
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vframes', '1', '-vf', 'transpose=0', get_test_example_file('target-1080p-90deg.jpg') ])
24
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=25', get_test_example_file('target-240p-25fps.mp4') ])
25
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=30', get_test_example_file('target-240p-30fps.mp4') ])
26
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=60', get_test_example_file('target-240p-60fps.mp4') ])
27
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'transpose=0', get_test_example_file('target-240p-90deg.mp4') ])
28
+ subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vf', 'transpose=0', get_test_example_file('target-1080p-90deg.mp4') ])
29
+
30
+
31
+ @pytest.fixture(scope = 'function', autouse = True)
32
+ def before_each() -> None:
33
+ prepare_test_output_directory()
34
+
35
+
36
+ def test_read_image() -> None:
37
+ assert read_image(get_test_example_file('target-240p.jpg')).shape == (226, 426, 3)
38
+ assert read_image(get_test_example_file('目标-240p.webp')).shape == (226, 426, 3)
39
+ assert read_image('invalid') is None
40
+
41
+
42
+ def test_write_image() -> None:
43
+ vision_frame = read_image(get_test_example_file('target-240p.jpg'))
44
+
45
+ assert write_image(get_test_output_file('target-240p.jpg'), vision_frame) is True
46
+ assert write_image(get_test_output_file('目标-240p.webp'), vision_frame) is True
47
+
48
+
49
+ def test_detect_image_resolution() -> None:
50
+ assert detect_image_resolution(get_test_example_file('target-240p.jpg')) == (426, 226)
51
+ assert detect_image_resolution(get_test_example_file('target-240p-90deg.jpg')) == (226, 426)
52
+ assert detect_image_resolution(get_test_example_file('target-1080p.jpg')) == (2048, 1080)
53
+ assert detect_image_resolution(get_test_example_file('target-1080p-90deg.jpg')) == (1080, 2048)
54
+ assert detect_image_resolution('invalid') is None
55
+
56
+
57
+ def test_restrict_image_resolution() -> None:
58
+ assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (426, 226)) == (426, 226)
59
+ assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (2048, 1080)) == (2048, 1080)
60
+ assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (4096, 2160)) == (2048, 1080)
61
+
62
+
63
+ def test_create_image_resolutions() -> None:
64
+ assert create_image_resolutions((426, 226)) == [ '106x56', '212x112', '320x170', '426x226', '640x340', '852x452', '1064x564', '1278x678', '1492x792', '1704x904' ]
65
+ assert create_image_resolutions((226, 426)) == [ '56x106', '112x212', '170x320', '226x426', '340x640', '452x852', '564x1064', '678x1278', '792x1492', '904x1704' ]
66
+ assert create_image_resolutions((2048, 1080)) == [ '512x270', '1024x540', '1536x810', '2048x1080', '3072x1620', '4096x2160', '5120x2700', '6144x3240', '7168x3780', '8192x4320' ]
67
+ assert create_image_resolutions((1080, 2048)) == [ '270x512', '540x1024', '810x1536', '1080x2048', '1620x3072', '2160x4096', '2700x5120', '3240x6144', '3780x7168', '4320x8192' ]
68
+ assert create_image_resolutions(None) == []
69
+
70
+
71
+ def test_read_video_frame() -> None:
72
+ assert hasattr(read_video_frame(get_test_example_file('target-240p-25fps.mp4')), '__array_interface__')
73
+ assert read_video_frame('invalid') is None
74
+
75
+
76
+ def test_count_video_frame_total() -> None:
77
+ assert count_video_frame_total(get_test_example_file('target-240p-25fps.mp4')) == 270
78
+ assert count_video_frame_total(get_test_example_file('target-240p-30fps.mp4')) == 324
79
+ assert count_video_frame_total(get_test_example_file('target-240p-60fps.mp4')) == 648
80
+ assert count_video_frame_total('invalid') == 0
81
+
82
+
83
+ def test_predict_video_frame_total() -> None:
84
+ assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 12.5, 0, 100) == 50
85
+ assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 100) == 100
86
+ assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 200) == 200
87
+ assert predict_video_frame_total('invalid', 25, 0, 100) == 0
88
+
89
+
90
+ def test_detect_video_fps() -> None:
91
+ assert detect_video_fps(get_test_example_file('target-240p-25fps.mp4')) == 25.0
92
+ assert detect_video_fps(get_test_example_file('target-240p-30fps.mp4')) == 30.0
93
+ assert detect_video_fps(get_test_example_file('target-240p-60fps.mp4')) == 60.0
94
+ assert detect_video_fps('invalid') is None
95
+
96
+
97
+ def test_restrict_video_fps() -> None:
98
+ assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 20.0) == 20.0
99
+ assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 25.0) == 25.0
100
+ assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 60.0) == 25.0
101
+
102
+
103
+ def test_detect_video_duration() -> None:
104
+ assert detect_video_duration(get_test_example_file('target-240p.mp4')) == 10.8
105
+ assert detect_video_duration('invalid') == 0
106
+
107
+
108
+ def test_count_trim_frame_total() -> None:
109
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 0, 200) == 200
110
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 70, 270) == 200
111
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), -10, None) == 270
112
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, -10) == 0
113
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 280, None) == 0
114
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, 280) == 270
115
+ assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, None) == 270
116
+
117
+
118
+ def test_restrict_trim_frame() -> None:
119
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 0, 200) == (0, 200)
120
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 70, 270) == (70, 270)
121
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), -10, None) == (0, 270)
122
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, -10) == (0, 0)
123
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 280, None) == (270, 270)
124
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, 280) == (0, 270)
125
+ assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, None) == (0, 270)
126
+
127
+
128
+ def test_detect_video_resolution() -> None:
129
+ assert detect_video_resolution(get_test_example_file('target-240p.mp4')) == (426, 226)
130
+ assert detect_video_resolution(get_test_example_file('target-240p-90deg.mp4')) == (226, 426)
131
+ assert detect_video_resolution(get_test_example_file('target-1080p.mp4')) == (2048, 1080)
132
+ assert detect_video_resolution(get_test_example_file('target-1080p-90deg.mp4')) == (1080, 2048)
133
+ assert detect_video_resolution('invalid') is None
134
+
135
+
136
+ def test_restrict_video_resolution() -> None:
137
+ assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (426, 226)) == (426, 226)
138
+ assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (2048, 1080)) == (2048, 1080)
139
+ assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (4096, 2160)) == (2048, 1080)
140
+
141
+
142
+ def test_create_video_resolutions() -> None:
143
+ assert create_video_resolutions((426, 226)) == [ '426x226', '452x240', '678x360', '904x480', '1018x540', '1358x720', '2036x1080', '2714x1440', '4072x2160', '8144x4320' ]
144
+ assert create_video_resolutions((226, 426)) == [ '226x426', '240x452', '360x678', '480x904', '540x1018', '720x1358', '1080x2036', '1440x2714', '2160x4072', '4320x8144' ]
145
+ assert create_video_resolutions((2048, 1080)) == [ '456x240', '682x360', '910x480', '1024x540', '1366x720', '2048x1080', '2730x1440', '4096x2160', '8192x4320' ]
146
+ assert create_video_resolutions((1080, 2048)) == [ '240x456', '360x682', '480x910', '540x1024', '720x1366', '1080x2048', '1440x2730', '2160x4096', '4320x8192' ]
147
+ assert create_video_resolutions(None) == []
148
+
149
+
150
+ def test_normalize_resolution() -> None:
151
+ assert normalize_resolution((2.5, 2.5)) == (2, 2)
152
+ assert normalize_resolution((3.0, 3.0)) == (4, 4)
153
+ assert normalize_resolution((6.5, 6.5)) == (6, 6)
154
+
155
+
156
+ def test_pack_resolution() -> None:
157
+ assert pack_resolution((1, 1)) == '0x0'
158
+ assert pack_resolution((2, 2)) == '2x2'
159
+
160
+
161
+ def test_unpack_resolution() -> None:
162
+ assert unpack_resolution('0x0') == (0, 0)
163
+ assert unpack_resolution('2x2') == (2, 2)
164
+
165
+
166
+ def test_calc_histogram_difference() -> None:
167
+ source_vision_frame = read_image(get_test_example_file('target-240p.jpg'))
168
+ target_vision_frame = read_image(get_test_example_file('target-240p-0sat.jpg'))
169
+
170
+ assert calc_histogram_difference(source_vision_frame, source_vision_frame) == 1.0
171
+ assert calc_histogram_difference(source_vision_frame, target_vision_frame) < 0.5
172
+
173
+
174
+ def test_match_frame_color() -> None:
175
+ source_vision_frame = read_image(get_test_example_file('target-240p.jpg'))
176
+ target_vision_frame = read_image(get_test_example_file('target-240p-0sat.jpg'))
177
+ output_vision_frame = match_frame_color(source_vision_frame, target_vision_frame)
178
+
179
+ assert calc_histogram_difference(source_vision_frame, output_vision_frame) > 0.5
tests/test_wording.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from facefusion import wording
2
+
3
+
4
+ def test_get() -> None:
5
+ assert wording.get('python_not_supported')
6
+ assert wording.get('help.source_paths')
7
+ assert wording.get('invalid') is None