infinity_test 2.0.0.rc1 → 2.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/HISTORY.md +84 -0
- data/README.md +249 -9
- data/TODO.markdown +36 -27
- data/lib/infinity_test/core/auto_discover.rb +3 -3
- data/lib/infinity_test/core/command_runner.rb +16 -40
- data/lib/infinity_test/core/continuous_test_server.rb +18 -0
- data/lib/infinity_test/core/version.rb +1 -1
- data/lib/infinity_test/framework/base.rb +36 -0
- data/lib/infinity_test/framework/django.rb +109 -0
- data/lib/infinity_test/framework/elixir_mix.rb +47 -0
- data/lib/infinity_test/framework/fast_api.rb +104 -0
- data/lib/infinity_test/framework/padrino.rb +5 -8
- data/lib/infinity_test/framework/phoenix.rb +72 -0
- data/lib/infinity_test/framework/python_package.rb +97 -0
- data/lib/infinity_test/framework/rails.rb +5 -14
- data/lib/infinity_test/framework/rocket.rb +70 -0
- data/lib/infinity_test/framework/rust_cargo.rb +69 -0
- data/lib/infinity_test/strategy/base.rb +17 -1
- data/lib/infinity_test/strategy/elixir_default.rb +20 -0
- data/lib/infinity_test/strategy/python_default.rb +22 -0
- data/lib/infinity_test/strategy/rbenv.rb +3 -1
- data/lib/infinity_test/strategy/ruby_default.rb +2 -1
- data/lib/infinity_test/strategy/rust_default.rb +21 -0
- data/lib/infinity_test/strategy/rvm.rb +3 -1
- data/lib/infinity_test/test_framework/cargo_test.rb +49 -0
- data/lib/infinity_test/test_framework/ex_unit.rb +53 -0
- data/lib/infinity_test/test_framework/pytest.rb +65 -0
- data/lib/infinity_test.rb +13 -0
- data/spec/infinity_test/core/auto_discover_spec.rb +29 -3
- data/spec/infinity_test/framework/django_spec.rb +95 -0
- data/spec/infinity_test/framework/elixir_mix_spec.rb +44 -0
- data/spec/infinity_test/framework/fast_api_spec.rb +96 -0
- data/spec/infinity_test/framework/padrino_spec.rb +28 -6
- data/spec/infinity_test/framework/phoenix_spec.rb +85 -0
- data/spec/infinity_test/framework/python_package_spec.rb +95 -0
- data/spec/infinity_test/framework/rails_spec.rb +28 -6
- data/spec/infinity_test/framework/rocket_spec.rb +69 -0
- data/spec/infinity_test/framework/rust_cargo_spec.rb +94 -0
- data/spec/infinity_test/strategy/elixir_default_spec.rb +46 -0
- data/spec/infinity_test/strategy/python_default_spec.rb +56 -0
- data/spec/infinity_test/strategy/rbenv_spec.rb +19 -2
- data/spec/infinity_test/strategy/ruby_default_spec.rb +19 -2
- data/spec/infinity_test/strategy/rust_default_spec.rb +56 -0
- data/spec/infinity_test/strategy/rvm_spec.rb +23 -6
- data/spec/infinity_test/test_framework/cargo_test_spec.rb +145 -0
- data/spec/infinity_test/test_framework/ex_unit_spec.rb +153 -0
- data/spec/infinity_test/test_framework/pytest_spec.rb +182 -0
- metadata +47 -5
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class Django < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .py extension for Python test files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.py')
|
|
10
|
+
hike.append_path(test_framework.test_dir)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch all Django app directories
|
|
18
|
+
# * Watch test dir (.py files) and run the changed file
|
|
19
|
+
# * Watch conftest.py and run all tests
|
|
20
|
+
#
|
|
21
|
+
def heuristics
|
|
22
|
+
watch_django_apps
|
|
23
|
+
watch_dir(test_dir, :py) { |file| run_file(file) } if File.directory?(test_dir.to_s)
|
|
24
|
+
watch(test_helper_file) { run_all } if File.exist?(test_helper_file.to_s)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Auto-discover and watch Django app directories.
|
|
28
|
+
# Django apps have models.py, views.py, or apps.py
|
|
29
|
+
#
|
|
30
|
+
def watch_django_apps
|
|
31
|
+
django_apps = detect_django_apps
|
|
32
|
+
|
|
33
|
+
django_apps.each do |app_dir|
|
|
34
|
+
next unless File.directory?(app_dir)
|
|
35
|
+
|
|
36
|
+
watch_dir(app_dir, :py) { |file| run_app_test(file, app_dir) }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Run test for a Django app file.
|
|
41
|
+
# Maps myapp/models.py -> myapp/tests/test_models.py or myapp/tests.py
|
|
42
|
+
#
|
|
43
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
44
|
+
# @param app_dir [String] The Django app directory
|
|
45
|
+
#
|
|
46
|
+
def run_app_test(changed_file, app_dir)
|
|
47
|
+
basename = File.basename(changed_file.path, '.py')
|
|
48
|
+
app_name = File.basename(app_dir)
|
|
49
|
+
|
|
50
|
+
# Try app/tests/test_*.py pattern
|
|
51
|
+
test_file = File.join(app_dir, 'tests', "test_#{basename}.py")
|
|
52
|
+
if File.exist?(test_file)
|
|
53
|
+
continuous_test_server.rerun_strategy(test_file)
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Try app/tests.py (single test file)
|
|
58
|
+
test_file = File.join(app_dir, 'tests.py')
|
|
59
|
+
if File.exist?(test_file)
|
|
60
|
+
continuous_test_server.rerun_strategy(test_file)
|
|
61
|
+
return
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Fallback: run all app tests
|
|
65
|
+
test_dir = File.join(app_dir, 'tests')
|
|
66
|
+
if File.directory?(test_dir)
|
|
67
|
+
continuous_test_server.rerun_strategy(test_dir)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# ==== Returns
|
|
72
|
+
# TrueClass: Find a Django project (manage.py exists)
|
|
73
|
+
# FalseClass: Not a Django project
|
|
74
|
+
#
|
|
75
|
+
def self.run?
|
|
76
|
+
File.exist?('manage.py') && django_project?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.django_project?
|
|
80
|
+
return false unless File.exist?('manage.py')
|
|
81
|
+
content = File.read('manage.py')
|
|
82
|
+
content.include?('django') || content.include?('DJANGO')
|
|
83
|
+
rescue
|
|
84
|
+
false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def detect_django_apps
|
|
90
|
+
apps = []
|
|
91
|
+
|
|
92
|
+
# Find directories with Django app markers
|
|
93
|
+
Dir.glob('*').each do |dir|
|
|
94
|
+
next unless File.directory?(dir)
|
|
95
|
+
next if %w[tests test static templates media venv .venv node_modules].include?(dir)
|
|
96
|
+
|
|
97
|
+
# Check for Django app markers
|
|
98
|
+
has_models = File.exist?(File.join(dir, 'models.py'))
|
|
99
|
+
has_views = File.exist?(File.join(dir, 'views.py'))
|
|
100
|
+
has_apps = File.exist?(File.join(dir, 'apps.py'))
|
|
101
|
+
|
|
102
|
+
apps << dir if has_models || has_views || has_apps
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
apps
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class ElixirMix < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .exs extension for Elixir test files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.exs')
|
|
10
|
+
hike.append_path(test_framework.test_dir)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Observe lib dir (.ex files) and run corresponding test.
|
|
18
|
+
# * Observe the test dir (.exs files) and run the same changed file.
|
|
19
|
+
# * Observe the test helper file and run all tests.
|
|
20
|
+
#
|
|
21
|
+
def heuristics
|
|
22
|
+
watch_dir(:lib, :ex) { |file| run_test(file) }
|
|
23
|
+
watch_dir(test_dir, :exs) { |file| run_file(file) }
|
|
24
|
+
watch(test_helper_file) { run_all }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Run test based on the changed file.
|
|
28
|
+
# Maps lib/my_app/user.ex -> test/my_app/user_test.exs
|
|
29
|
+
#
|
|
30
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
31
|
+
#
|
|
32
|
+
def run_test(changed_file)
|
|
33
|
+
file_name = "#{changed_file.path}_test.exs"
|
|
34
|
+
file = hike.find(file_name)
|
|
35
|
+
continuous_test_server.rerun_strategy(file) if file.present?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# ==== Returns
|
|
39
|
+
# TrueClass: Find a mix.exs in the user current dir
|
|
40
|
+
# FalseClass: Don't Find a mix.exs in the user current dir
|
|
41
|
+
#
|
|
42
|
+
def self.run?
|
|
43
|
+
File.exist?('mix.exs')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class FastApi < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .py extension for Python test files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.py')
|
|
10
|
+
hike.append_path(test_framework.test_dir)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch app dir (.py files) for FastAPI applications
|
|
18
|
+
# * Watch src dir (.py files) if exists
|
|
19
|
+
# * Watch routers/endpoints directories
|
|
20
|
+
# * Watch test dir (.py files) and run the changed file
|
|
21
|
+
# * Watch conftest.py and run all tests
|
|
22
|
+
#
|
|
23
|
+
def heuristics
|
|
24
|
+
watch_fastapi_dirs
|
|
25
|
+
watch_dir(test_dir, :py) { |file| run_file(file) }
|
|
26
|
+
watch(test_helper_file) { run_all } if File.exist?(test_helper_file.to_s)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Auto-discover and watch FastAPI source directories.
|
|
30
|
+
# Common patterns: app/, src/, routers/, api/
|
|
31
|
+
#
|
|
32
|
+
def watch_fastapi_dirs
|
|
33
|
+
fastapi_dirs = detect_fastapi_source_dirs
|
|
34
|
+
|
|
35
|
+
fastapi_dirs.each do |dir|
|
|
36
|
+
next unless File.directory?(dir)
|
|
37
|
+
next unless Dir.glob("#{dir}/**/*.py").any?
|
|
38
|
+
|
|
39
|
+
watch_dir(dir, :py) { |file| run_test(file) }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Run test based on the changed file.
|
|
44
|
+
#
|
|
45
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
46
|
+
#
|
|
47
|
+
def run_test(changed_file)
|
|
48
|
+
test_file = find_test_file(changed_file.path)
|
|
49
|
+
continuous_test_server.rerun_strategy(test_file) if test_file.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# ==== Returns
|
|
53
|
+
# TrueClass: Find a FastAPI project (app/main.py or main.py with FastAPI)
|
|
54
|
+
# FalseClass: Not a FastAPI project
|
|
55
|
+
#
|
|
56
|
+
def self.run?
|
|
57
|
+
return true if File.exist?('app/main.py') && fastapi_in_file?('app/main.py')
|
|
58
|
+
return true if File.exist?('main.py') && fastapi_in_file?('main.py')
|
|
59
|
+
return true if File.exist?('src/main.py') && fastapi_in_file?('src/main.py')
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.fastapi_in_file?(file)
|
|
64
|
+
return false unless File.exist?(file)
|
|
65
|
+
content = File.read(file)
|
|
66
|
+
content.include?('fastapi') || content.include?('FastAPI')
|
|
67
|
+
rescue
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def detect_fastapi_source_dirs
|
|
74
|
+
dirs = []
|
|
75
|
+
dirs << 'app' if File.directory?('app')
|
|
76
|
+
dirs << 'src' if File.directory?('src')
|
|
77
|
+
dirs << 'routers' if File.directory?('routers')
|
|
78
|
+
dirs << 'api' if File.directory?('api')
|
|
79
|
+
dirs << 'endpoints' if File.directory?('endpoints')
|
|
80
|
+
|
|
81
|
+
# Also watch root .py files for simple FastAPI apps
|
|
82
|
+
dirs << '.' if Dir.glob('*.py').any? { |f| !f.start_with?('test_') }
|
|
83
|
+
|
|
84
|
+
dirs.uniq
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def find_test_file(source_path)
|
|
88
|
+
basename = File.basename(source_path, '.py')
|
|
89
|
+
|
|
90
|
+
patterns = [
|
|
91
|
+
"test_#{basename}.py",
|
|
92
|
+
"#{basename}_test.py"
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
patterns.each do |pattern|
|
|
96
|
+
file = hike.find(pattern)
|
|
97
|
+
return file if file.present?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -6,19 +6,16 @@ module InfinityTest
|
|
|
6
6
|
# Add Heuristics to the observer run on pattern changes!
|
|
7
7
|
#
|
|
8
8
|
# ==== Heuristics
|
|
9
|
-
# * Watch app
|
|
9
|
+
# * Watch all app/* directories and run corresponding tests/specs
|
|
10
10
|
# * Watch lib dir and run corresponding tests
|
|
11
11
|
# * Watch test/spec dir and run the changed file
|
|
12
12
|
# * Watch test/spec helper and run all
|
|
13
13
|
#
|
|
14
14
|
def heuristics
|
|
15
|
-
|
|
16
|
-
watch_dir(
|
|
17
|
-
watch_dir(
|
|
18
|
-
|
|
19
|
-
watch_dir(:lib) { |file| run_test(file) }
|
|
20
|
-
watch_dir(test_dir) { |file| run_file(file) }
|
|
21
|
-
watch(test_helper_file) { run_all }
|
|
15
|
+
watch_app_dirs
|
|
16
|
+
watch_dir(:lib) { |file| run_test(file) }
|
|
17
|
+
watch_dir(test_dir) { |file| run_file(file) }
|
|
18
|
+
watch(test_helper_file) { run_all }
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
# ==== Returns
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class Phoenix < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .exs extension for Elixir test files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.exs')
|
|
10
|
+
hike.append_path(test_framework.test_dir)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch all lib/*_web directories (controllers, views, live, channels)
|
|
18
|
+
# * Watch lib dir (.ex files) and run corresponding test
|
|
19
|
+
# * Watch test dir (.exs files) and run the changed file
|
|
20
|
+
# * Watch test helper and run all tests
|
|
21
|
+
#
|
|
22
|
+
def heuristics
|
|
23
|
+
watch_lib_dirs
|
|
24
|
+
watch_dir(test_dir, :exs) { |file| run_file(file) }
|
|
25
|
+
watch(test_helper_file) { run_all }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Auto-discover and watch all directories under lib/ that contain .ex files.
|
|
29
|
+
# Maps lib/my_app/accounts to test/my_app/accounts, etc.
|
|
30
|
+
#
|
|
31
|
+
def watch_lib_dirs
|
|
32
|
+
return unless File.directory?('lib')
|
|
33
|
+
|
|
34
|
+
Dir.glob('lib/*').each do |lib_dir|
|
|
35
|
+
next unless File.directory?(lib_dir)
|
|
36
|
+
next unless Dir.glob("#{lib_dir}/**/*.ex").any?
|
|
37
|
+
|
|
38
|
+
watch_dir(lib_dir, :ex) { |file| run_test_in_lib(file, lib_dir) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Run test preserving the directory structure.
|
|
43
|
+
# E.g: lib/my_app_web/controllers/user_controller.ex -> test/my_app_web/controllers/user_controller_test.exs
|
|
44
|
+
#
|
|
45
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
46
|
+
# @param lib_dir [String] The lib directory (e.g., 'lib/my_app_web')
|
|
47
|
+
#
|
|
48
|
+
def run_test_in_lib(changed_file, lib_dir)
|
|
49
|
+
subdir = File.basename(lib_dir)
|
|
50
|
+
test_file = File.join(test_framework.test_dir, subdir, "#{changed_file.path}_test.exs")
|
|
51
|
+
|
|
52
|
+
if File.exist?(test_file)
|
|
53
|
+
continuous_test_server.rerun_strategy(test_file)
|
|
54
|
+
else
|
|
55
|
+
# Fallback: try finding with hike in test_dir/subdir
|
|
56
|
+
hike.prepend_path(File.join(test_framework.test_dir, subdir))
|
|
57
|
+
file_name = "#{changed_file.path}_test.exs"
|
|
58
|
+
file = hike.find(file_name)
|
|
59
|
+
continuous_test_server.rerun_strategy(file) if file.present?
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# ==== Returns
|
|
64
|
+
# TrueClass: Find a Phoenix project (has lib/*_web directory)
|
|
65
|
+
# FalseClass: Not a Phoenix project
|
|
66
|
+
#
|
|
67
|
+
def self.run?
|
|
68
|
+
File.exist?('mix.exs') && Dir.glob('lib/*_web').any?
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class PythonPackage < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .py extension for Python test files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.py')
|
|
10
|
+
hike.append_path(test_framework.test_dir)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch src dir (.py files) and run corresponding test
|
|
18
|
+
# * Watch package dirs (.py files) and run corresponding test
|
|
19
|
+
# * Watch test dir (.py files) and run the changed file
|
|
20
|
+
# * Watch conftest.py and run all tests
|
|
21
|
+
#
|
|
22
|
+
def heuristics
|
|
23
|
+
watch_python_dirs
|
|
24
|
+
watch_dir(test_dir, :py) { |file| run_file(file) }
|
|
25
|
+
watch(test_helper_file) { run_all } if File.exist?(test_helper_file.to_s)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Auto-discover and watch Python source directories.
|
|
29
|
+
# Common patterns: src/, package_name/, lib/
|
|
30
|
+
#
|
|
31
|
+
def watch_python_dirs
|
|
32
|
+
python_dirs = detect_python_source_dirs
|
|
33
|
+
|
|
34
|
+
python_dirs.each do |dir|
|
|
35
|
+
next unless File.directory?(dir)
|
|
36
|
+
next unless Dir.glob("#{dir}/**/*.py").any?
|
|
37
|
+
|
|
38
|
+
watch_dir(dir, :py) { |file| run_test(file) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Run test based on the changed file.
|
|
43
|
+
# Maps src/mypackage/utils.py -> tests/test_utils.py or tests/mypackage/test_utils.py
|
|
44
|
+
#
|
|
45
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
46
|
+
#
|
|
47
|
+
def run_test(changed_file)
|
|
48
|
+
# Try test_filename.py pattern first
|
|
49
|
+
test_file = find_test_file(changed_file.path)
|
|
50
|
+
continuous_test_server.rerun_strategy(test_file) if test_file.present?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ==== Returns
|
|
54
|
+
# TrueClass: Find a Python package (pyproject.toml, setup.py, or setup.cfg)
|
|
55
|
+
# FalseClass: Not a Python package
|
|
56
|
+
#
|
|
57
|
+
def self.run?
|
|
58
|
+
File.exist?('pyproject.toml') ||
|
|
59
|
+
File.exist?('setup.py') ||
|
|
60
|
+
File.exist?('setup.cfg')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def detect_python_source_dirs
|
|
66
|
+
dirs = []
|
|
67
|
+
dirs << 'src' if File.directory?('src')
|
|
68
|
+
dirs << 'lib' if File.directory?('lib') && Dir.glob('lib/**/*.py').any?
|
|
69
|
+
|
|
70
|
+
# Detect package directories (directories with __init__.py)
|
|
71
|
+
Dir.glob('*/__init__.py').each do |init_file|
|
|
72
|
+
dir = File.dirname(init_file)
|
|
73
|
+
dirs << dir unless %w[tests test].include?(dir)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
dirs.uniq
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def find_test_file(source_path)
|
|
80
|
+
basename = File.basename(source_path, '.py')
|
|
81
|
+
|
|
82
|
+
# Try various test file patterns
|
|
83
|
+
patterns = [
|
|
84
|
+
"test_#{basename}.py",
|
|
85
|
+
"#{basename}_test.py"
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
patterns.each do |pattern|
|
|
89
|
+
file = hike.find(pattern)
|
|
90
|
+
return file if file.present?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -6,25 +6,16 @@ module InfinityTest
|
|
|
6
6
|
# Add Heuristics to the observer run on pattern changes!
|
|
7
7
|
#
|
|
8
8
|
# ==== Heuristics
|
|
9
|
-
# * Watch app
|
|
10
|
-
# * Watch app/controllers and run corresponding tests/specs
|
|
11
|
-
# * Watch app/helpers and run corresponding tests/specs
|
|
12
|
-
# * Watch app/mailers and run corresponding tests/specs
|
|
13
|
-
# * Watch app/jobs and run corresponding tests/specs
|
|
9
|
+
# * Watch all app/* directories and run corresponding tests/specs
|
|
14
10
|
# * Watch lib dir and run corresponding tests
|
|
15
11
|
# * Watch test/spec dir and run the changed file
|
|
16
12
|
# * Watch test/spec helper and run all
|
|
17
|
-
# * Watch config/routes.rb and run routing specs
|
|
18
13
|
#
|
|
19
14
|
def heuristics
|
|
20
|
-
|
|
21
|
-
watch_dir(
|
|
22
|
-
watch_dir(
|
|
23
|
-
|
|
24
|
-
watch_dir('app/jobs') { |file| run_test(file) }
|
|
25
|
-
watch_dir(:lib) { |file| run_test(file) }
|
|
26
|
-
watch_dir(test_dir) { |file| run_file(file) }
|
|
27
|
-
watch(test_helper_file) { run_all }
|
|
15
|
+
watch_app_dirs
|
|
16
|
+
watch_dir(:lib) { |file| run_test(file) }
|
|
17
|
+
watch_dir(test_dir) { |file| run_file(file) }
|
|
18
|
+
watch(test_helper_file) { run_all }
|
|
28
19
|
end
|
|
29
20
|
|
|
30
21
|
def self.run?
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class Rocket < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .rs extension for Rust files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.rs')
|
|
10
|
+
hike.append_path(test_framework.test_dir) if File.directory?(test_framework.test_dir.to_s)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch src dir (.rs files) and run tests matching the module name
|
|
18
|
+
# * Watch tests dir (.rs files) and run the changed integration test
|
|
19
|
+
# * Watch Cargo.toml and run all tests
|
|
20
|
+
# * Watch Rocket.toml if exists and run all tests
|
|
21
|
+
#
|
|
22
|
+
def heuristics
|
|
23
|
+
watch_dir(:src, :rs) { |file| run_module_tests(file) }
|
|
24
|
+
watch_dir(test_dir, :rs) { |file| run_integration_test(file) } if File.directory?(test_dir.to_s)
|
|
25
|
+
watch(test_helper_file) { run_all }
|
|
26
|
+
watch('Rocket.toml') { run_all } if File.exist?('Rocket.toml')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Run tests matching the module name.
|
|
30
|
+
# E.g: src/routes.rs -> cargo test routes
|
|
31
|
+
#
|
|
32
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
33
|
+
#
|
|
34
|
+
def run_module_tests(changed_file)
|
|
35
|
+
module_name = File.basename(changed_file.name, '.rs')
|
|
36
|
+
# lib.rs and main.rs changes should run all tests
|
|
37
|
+
if %w[lib main].include?(module_name)
|
|
38
|
+
run_all
|
|
39
|
+
else
|
|
40
|
+
continuous_test_server.rerun_strategy(module_name)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Run a specific integration test file.
|
|
45
|
+
#
|
|
46
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
47
|
+
#
|
|
48
|
+
def run_integration_test(changed_file)
|
|
49
|
+
test_name = File.basename(changed_file.name, '.rs')
|
|
50
|
+
continuous_test_server.rerun_strategy("--test #{test_name}")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ==== Returns
|
|
54
|
+
# TrueClass: Find a Rocket project (Cargo.toml with rocket dependency)
|
|
55
|
+
# FalseClass: Not a Rocket project
|
|
56
|
+
#
|
|
57
|
+
def self.run?
|
|
58
|
+
File.exist?('Cargo.toml') && rocket_project?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.rocket_project?
|
|
62
|
+
return false unless File.exist?('Cargo.toml')
|
|
63
|
+
content = File.read('Cargo.toml')
|
|
64
|
+
content.include?('rocket')
|
|
65
|
+
rescue
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Framework
|
|
3
|
+
class RustCargo < Base
|
|
4
|
+
delegate :test_dir, :test_helper_file, to: :test_framework
|
|
5
|
+
|
|
6
|
+
# Override to use .rs extension for Rust files.
|
|
7
|
+
#
|
|
8
|
+
def heuristics!
|
|
9
|
+
hike.append_extension('.rs')
|
|
10
|
+
hike.append_path(test_framework.test_dir) if File.directory?(test_framework.test_dir.to_s)
|
|
11
|
+
heuristics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add Heuristics to the observer run on pattern changes!
|
|
15
|
+
#
|
|
16
|
+
# ==== Heuristics
|
|
17
|
+
# * Watch src dir (.rs files) and run tests matching the module name
|
|
18
|
+
# * Watch tests dir (.rs files) and run the changed integration test
|
|
19
|
+
# * Watch Cargo.toml and run all tests
|
|
20
|
+
#
|
|
21
|
+
def heuristics
|
|
22
|
+
watch_dir(:src, :rs) { |file| run_module_tests(file) }
|
|
23
|
+
watch_dir(test_dir, :rs) { |file| run_integration_test(file) } if File.directory?(test_dir.to_s)
|
|
24
|
+
watch(test_helper_file) { run_all }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Run tests matching the module name.
|
|
28
|
+
# E.g: src/user.rs -> cargo test user
|
|
29
|
+
#
|
|
30
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
31
|
+
#
|
|
32
|
+
def run_module_tests(changed_file)
|
|
33
|
+
module_name = File.basename(changed_file.name, '.rs')
|
|
34
|
+
# lib.rs and main.rs changes should run all tests
|
|
35
|
+
if %w[lib main].include?(module_name)
|
|
36
|
+
run_all
|
|
37
|
+
else
|
|
38
|
+
continuous_test_server.rerun_strategy(module_name)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Run a specific integration test file.
|
|
43
|
+
# For tests in tests/, run cargo test --test <name>
|
|
44
|
+
#
|
|
45
|
+
# @param changed_file [<InfinityTest::Core::ChangedFile>]
|
|
46
|
+
#
|
|
47
|
+
def run_integration_test(changed_file)
|
|
48
|
+
test_name = File.basename(changed_file.name, '.rs')
|
|
49
|
+
continuous_test_server.rerun_strategy("--test #{test_name}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# ==== Returns
|
|
53
|
+
# TrueClass: Find a Rust project (Cargo.toml exists)
|
|
54
|
+
# FalseClass: Not a Rust project
|
|
55
|
+
#
|
|
56
|
+
def self.run?
|
|
57
|
+
File.exist?('Cargo.toml') && !rocket_project?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.rocket_project?
|
|
61
|
+
return false unless File.exist?('Cargo.toml')
|
|
62
|
+
content = File.read('Cargo.toml')
|
|
63
|
+
content.include?('rocket')
|
|
64
|
+
rescue
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -13,9 +13,25 @@ module InfinityTest
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# Run the strategy and parse the results storing in the strategy.
|
|
16
|
+
# Prints the command before executing if verbose mode is enabled.
|
|
16
17
|
#
|
|
17
18
|
def run
|
|
18
|
-
|
|
19
|
+
command = run!
|
|
20
|
+
puts "\n\e[96m[InfinityTest]\e[0m - Command: '\e[32m#{command}\e[0m'\n\n" if Core::Base.verbose?
|
|
21
|
+
Core::CommandRunner.new(command)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Check if bundler should be used.
|
|
25
|
+
# Returns true if bundler is enabled and Gemfile exists.
|
|
26
|
+
#
|
|
27
|
+
def use_bundler?
|
|
28
|
+
Core::Base.using_bundler? && File.exist?('Gemfile')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Wrap command with bundle exec if bundler should be used.
|
|
32
|
+
#
|
|
33
|
+
def with_bundler(command)
|
|
34
|
+
use_bundler? ? "bundle exec #{command}" : command
|
|
19
35
|
end
|
|
20
36
|
|
|
21
37
|
# Implement #run! method returning a string command to be run.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module InfinityTest
|
|
2
|
+
module Strategy
|
|
3
|
+
class ElixirDefault < Base
|
|
4
|
+
attr_reader :continuous_test_server
|
|
5
|
+
delegate :binary, :test_files, to: :continuous_test_server
|
|
6
|
+
|
|
7
|
+
def run!
|
|
8
|
+
command = "#{binary} test #{test_files}"
|
|
9
|
+
command = "#{command} #{Core::Base.specific_options}" if Core::Base.specific_options.present?
|
|
10
|
+
command
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Run when the project has mix.exs (Elixir project)
|
|
14
|
+
#
|
|
15
|
+
def self.run?
|
|
16
|
+
File.exist?('mix.exs')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|