csvops 0.3.0.alpha → 0.5.0.alpha
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/README.md +69 -149
- data/docs/architecture.md +396 -0
- data/docs/release-v0.4.0-alpha.md +87 -0
- data/docs/release-v0.5.0-alpha.md +89 -0
- data/lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb +96 -0
- data/lib/csvtool/application/use_cases/run_extraction.rb +63 -88
- data/lib/csvtool/application/use_cases/run_row_extraction.rb +45 -73
- data/lib/csvtool/application/use_cases/run_row_randomization.rb +56 -73
- data/lib/csvtool/cli.rb +11 -7
- data/lib/csvtool/domain/cross_csv_dedupe_session/column_selector.rb +44 -0
- data/lib/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session.rb +46 -0
- data/lib/csvtool/domain/cross_csv_dedupe_session/csv_profile.rb +24 -0
- data/lib/csvtool/domain/cross_csv_dedupe_session/key_mapping.rb +22 -0
- data/lib/csvtool/domain/cross_csv_dedupe_session/match_options.rb +29 -0
- data/lib/csvtool/domain/row_randomization_session/randomization_source.rb +1 -0
- data/lib/csvtool/domain/row_session/row_source.rb +3 -0
- data/lib/csvtool/domain/{column_session → shared}/output_destination.rb +1 -1
- data/lib/csvtool/infrastructure/csv/cross_csv_deduper.rb +85 -0
- data/lib/csvtool/infrastructure/csv/selector_validator.rb +30 -0
- data/lib/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer.rb +23 -0
- data/lib/csvtool/infrastructure/output/csv_file_writer.rb +1 -7
- data/lib/csvtool/infrastructure/output/csv_randomized_row_file_writer.rb +23 -0
- data/lib/csvtool/infrastructure/output/csv_row_file_writer.rb +2 -9
- data/lib/csvtool/interface/cli/menu_loop.rb +5 -2
- data/lib/csvtool/interface/cli/prompts/dedupe_key_selector_prompt.rb +30 -0
- data/lib/csvtool/interface/cli/prompts/file_path_prompt.rb +4 -2
- data/lib/csvtool/interface/cli/prompts/headers_present_prompt.rb +4 -2
- data/lib/csvtool/interface/cli/prompts/separator_prompt.rb +4 -2
- data/lib/csvtool/interface/cli/prompts/yes_no_prompt.rb +26 -0
- data/lib/csvtool/interface/cli/workflows/builders/column_session_builder.rb +32 -0
- data/lib/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder.rb +35 -0
- data/lib/csvtool/interface/cli/workflows/builders/row_extraction_session_builder.rb +22 -0
- data/lib/csvtool/interface/cli/workflows/builders/row_randomization_session_builder.rb +28 -0
- data/lib/csvtool/interface/cli/workflows/presenters/column_extraction_presenter.rb +25 -0
- data/lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb +39 -0
- data/lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb +34 -0
- data/lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb +34 -0
- data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +86 -0
- data/lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb +88 -0
- data/lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb +86 -0
- data/lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb +80 -0
- data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step.rb +55 -0
- data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_profiles_step.rb +52 -0
- data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/execute_step.rb +34 -0
- data/lib/csvtool/interface/cli/workflows/steps/extraction/build_preview_step.rb +40 -0
- data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_destination_step.rb +28 -0
- data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step.rb +47 -0
- data/lib/csvtool/interface/cli/workflows/steps/extraction/execute_step.rb +32 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_destination_step.rb +33 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_range_step.rb +35 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step.rb +32 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_extraction/execute_step.rb +43 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step.rb +29 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_destination_step.rb +34 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step.rb +49 -0
- data/lib/csvtool/interface/cli/workflows/steps/row_randomization/execute_step.rb +37 -0
- data/lib/csvtool/interface/cli/workflows/steps/workflow_step_pipeline.rb +25 -0
- data/lib/csvtool/interface/cli/workflows/support/output_destination_mapper.rb +23 -0
- data/lib/csvtool/interface/cli/workflows/support/result_error_handler.rb +22 -0
- data/lib/csvtool/version.rb +1 -1
- data/test/csvtool/application/use_cases/io_boundary_test.rb +26 -0
- data/test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb +141 -0
- data/test/csvtool/application/use_cases/run_extraction_test.rb +72 -16
- data/test/csvtool/application/use_cases/run_row_extraction_test.rb +82 -102
- data/test/csvtool/application/use_cases/run_row_randomization_test.rb +96 -86
- data/test/csvtool/cli_test.rb +130 -16
- data/test/csvtool/cli_unit_test.rb +16 -3
- data/test/csvtool/domain/column_session/column_session_test.rb +2 -2
- data/test/csvtool/domain/column_session/csv_source_test.rb +10 -0
- data/test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb +42 -0
- data/test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb +75 -0
- data/test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb +26 -0
- data/test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb +31 -0
- data/test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb +52 -0
- data/test/csvtool/domain/row_randomization_session/randomization_session_test.rb +2 -2
- data/test/csvtool/domain/row_randomization_session/randomization_source_test.rb +15 -1
- data/test/csvtool/domain/row_session/row_session_test.rb +2 -2
- data/test/csvtool/domain/row_session/row_source_test.rb +16 -0
- data/test/csvtool/domain/shared/output_destination_test.rb +24 -0
- data/test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb +155 -0
- data/test/csvtool/infrastructure/csv/selector_validator_test.rb +72 -0
- data/test/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer_test.rb +32 -0
- data/test/csvtool/infrastructure/output/csv_file_writer_test.rb +0 -4
- data/test/csvtool/infrastructure/output/csv_randomized_row_file_writer_test.rb +32 -0
- data/test/csvtool/infrastructure/output/csv_row_file_writer_test.rb +1 -4
- data/test/csvtool/interface/cli/menu_loop_test.rb +50 -13
- data/test/csvtool/interface/cli/prompts/dedupe_key_selector_prompt_test.rb +30 -0
- data/test/csvtool/interface/cli/prompts/file_path_prompt_test.rb +9 -0
- data/test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb +10 -0
- data/test/csvtool/interface/cli/prompts/separator_prompt_test.rb +10 -0
- data/test/csvtool/interface/cli/prompts/yes_no_prompt_test.rb +22 -0
- data/test/csvtool/interface/cli/workflows/builders/column_session_builder_test.rb +17 -0
- data/test/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder_test.rb +36 -0
- data/test/csvtool/interface/cli/workflows/builders/row_extraction_session_builder_test.rb +21 -0
- data/test/csvtool/interface/cli/workflows/builders/row_randomization_session_builder_test.rb +26 -0
- data/test/csvtool/interface/cli/workflows/presenters/column_extraction_presenter_test.rb +24 -0
- data/test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb +30 -0
- data/test/csvtool/interface/cli/workflows/presenters/row_extraction_presenter_test.rb +33 -0
- data/test/csvtool/interface/cli/workflows/presenters/row_randomization_presenter_test.rb +33 -0
- data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +246 -0
- data/test/csvtool/interface/cli/workflows/run_extraction_workflow_test.rb +56 -0
- data/test/csvtool/interface/cli/workflows/run_row_extraction_workflow_test.rb +83 -0
- data/test/csvtool/interface/cli/workflows/run_row_randomization_workflow_test.rb +69 -0
- data/test/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step_test.rb +41 -0
- data/test/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step_test.rb +66 -0
- data/test/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step_test.rb +39 -0
- data/test/csvtool/interface/cli/workflows/steps/row_extraction/execute_step_test.rb +91 -0
- data/test/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step_test.rb +57 -0
- data/test/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step_test.rb +37 -0
- data/test/csvtool/interface/cli/workflows/steps/workflow_step_pipeline_test.rb +30 -0
- data/test/csvtool/interface/cli/workflows/support/output_destination_mapper_test.rb +23 -0
- data/test/csvtool/interface/cli/workflows/support/result_error_handler_test.rb +34 -0
- data/test/fixtures/dedupe_reference.csv +3 -0
- data/test/fixtures/dedupe_reference.tsv +3 -0
- data/test/fixtures/dedupe_reference_all.csv +5 -0
- data/test/fixtures/dedupe_reference_no_headers.csv +2 -0
- data/test/fixtures/dedupe_reference_none.csv +2 -0
- data/test/fixtures/dedupe_reference_normalization.csv +3 -0
- data/test/fixtures/dedupe_source.csv +6 -0
- data/test/fixtures/dedupe_source.tsv +6 -0
- data/test/fixtures/dedupe_source_no_headers.csv +5 -0
- data/test/fixtures/dedupe_source_normalization.csv +4 -0
- metadata +93 -8
- data/lib/csvtool/domain/row_randomization_session/randomization_output_destination.rb +0 -31
- data/lib/csvtool/domain/row_session/row_output_destination.rb +0 -31
- data/test/csvtool/domain/column_session/output_destination_test.rb +0 -18
- data/test/csvtool/domain/row_randomization_session/randomization_output_destination_test.rb +0 -21
- data/test/csvtool/domain/row_session/row_output_destination_test.rb +0 -23
|
@@ -20,14 +20,16 @@ class MenuLoopTest < Minitest::Test
|
|
|
20
20
|
column_action = FakeAction.new
|
|
21
21
|
rows_action = FakeAction.new
|
|
22
22
|
randomize_rows_action = FakeAction.new
|
|
23
|
+
dedupe_action = FakeAction.new
|
|
23
24
|
stdout = StringIO.new
|
|
24
25
|
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
25
|
-
stdin: StringIO.new("1\
|
|
26
|
+
stdin: StringIO.new("1\n5\n"),
|
|
26
27
|
stdout: stdout,
|
|
27
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Exit"],
|
|
28
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
28
29
|
extract_column_action: column_action,
|
|
29
30
|
extract_rows_action: rows_action,
|
|
30
|
-
randomize_rows_action: randomize_rows_action
|
|
31
|
+
randomize_rows_action: randomize_rows_action,
|
|
32
|
+
dedupe_action: dedupe_action
|
|
31
33
|
)
|
|
32
34
|
|
|
33
35
|
status = menu.run
|
|
@@ -36,6 +38,7 @@ class MenuLoopTest < Minitest::Test
|
|
|
36
38
|
assert_equal 1, column_action.runs
|
|
37
39
|
assert_equal 0, rows_action.runs
|
|
38
40
|
assert_equal 0, randomize_rows_action.runs
|
|
41
|
+
assert_equal 0, dedupe_action.runs
|
|
39
42
|
assert_includes stdout.string, "CSV Tool Menu"
|
|
40
43
|
end
|
|
41
44
|
|
|
@@ -43,14 +46,16 @@ class MenuLoopTest < Minitest::Test
|
|
|
43
46
|
column_action = FakeAction.new
|
|
44
47
|
rows_action = FakeAction.new
|
|
45
48
|
randomize_rows_action = FakeAction.new
|
|
49
|
+
dedupe_action = FakeAction.new
|
|
46
50
|
stdout = StringIO.new
|
|
47
51
|
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
48
|
-
stdin: StringIO.new("2\
|
|
52
|
+
stdin: StringIO.new("2\n5\n"),
|
|
49
53
|
stdout: stdout,
|
|
50
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Exit"],
|
|
54
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
51
55
|
extract_column_action: column_action,
|
|
52
56
|
extract_rows_action: rows_action,
|
|
53
|
-
randomize_rows_action: randomize_rows_action
|
|
57
|
+
randomize_rows_action: randomize_rows_action,
|
|
58
|
+
dedupe_action: dedupe_action
|
|
54
59
|
)
|
|
55
60
|
|
|
56
61
|
status = menu.run
|
|
@@ -59,20 +64,23 @@ class MenuLoopTest < Minitest::Test
|
|
|
59
64
|
assert_equal 0, column_action.runs
|
|
60
65
|
assert_equal 1, rows_action.runs
|
|
61
66
|
assert_equal 0, randomize_rows_action.runs
|
|
67
|
+
assert_equal 0, dedupe_action.runs
|
|
62
68
|
end
|
|
63
69
|
|
|
64
70
|
def test_routes_randomize_rows_then_exit
|
|
65
71
|
column_action = FakeAction.new
|
|
66
72
|
rows_action = FakeAction.new
|
|
67
73
|
randomize_rows_action = FakeAction.new
|
|
74
|
+
dedupe_action = FakeAction.new
|
|
68
75
|
stdout = StringIO.new
|
|
69
76
|
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
70
|
-
stdin: StringIO.new("3\
|
|
77
|
+
stdin: StringIO.new("3\n5\n"),
|
|
71
78
|
stdout: stdout,
|
|
72
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Exit"],
|
|
79
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
73
80
|
extract_column_action: column_action,
|
|
74
81
|
extract_rows_action: rows_action,
|
|
75
|
-
randomize_rows_action: randomize_rows_action
|
|
82
|
+
randomize_rows_action: randomize_rows_action,
|
|
83
|
+
dedupe_action: dedupe_action
|
|
76
84
|
)
|
|
77
85
|
|
|
78
86
|
status = menu.run
|
|
@@ -81,27 +89,56 @@ class MenuLoopTest < Minitest::Test
|
|
|
81
89
|
assert_equal 0, column_action.runs
|
|
82
90
|
assert_equal 0, rows_action.runs
|
|
83
91
|
assert_equal 1, randomize_rows_action.runs
|
|
92
|
+
assert_equal 0, dedupe_action.runs
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_routes_dedupe_then_exit
|
|
96
|
+
column_action = FakeAction.new
|
|
97
|
+
rows_action = FakeAction.new
|
|
98
|
+
randomize_rows_action = FakeAction.new
|
|
99
|
+
dedupe_action = FakeAction.new
|
|
100
|
+
stdout = StringIO.new
|
|
101
|
+
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
102
|
+
stdin: StringIO.new("4\n5\n"),
|
|
103
|
+
stdout: stdout,
|
|
104
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
105
|
+
extract_column_action: column_action,
|
|
106
|
+
extract_rows_action: rows_action,
|
|
107
|
+
randomize_rows_action: randomize_rows_action,
|
|
108
|
+
dedupe_action: dedupe_action
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
status = menu.run
|
|
112
|
+
|
|
113
|
+
assert_equal 0, status
|
|
114
|
+
assert_equal 0, column_action.runs
|
|
115
|
+
assert_equal 0, rows_action.runs
|
|
116
|
+
assert_equal 0, randomize_rows_action.runs
|
|
117
|
+
assert_equal 1, dedupe_action.runs
|
|
84
118
|
end
|
|
85
119
|
|
|
86
120
|
def test_invalid_choice_shows_prompt
|
|
87
121
|
column_action = FakeAction.new
|
|
88
122
|
rows_action = FakeAction.new
|
|
89
123
|
randomize_rows_action = FakeAction.new
|
|
124
|
+
dedupe_action = FakeAction.new
|
|
90
125
|
stdout = StringIO.new
|
|
91
126
|
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
92
|
-
stdin: StringIO.new("x\
|
|
127
|
+
stdin: StringIO.new("x\n5\n"),
|
|
93
128
|
stdout: stdout,
|
|
94
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Exit"],
|
|
129
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
95
130
|
extract_column_action: column_action,
|
|
96
131
|
extract_rows_action: rows_action,
|
|
97
|
-
randomize_rows_action: randomize_rows_action
|
|
132
|
+
randomize_rows_action: randomize_rows_action,
|
|
133
|
+
dedupe_action: dedupe_action
|
|
98
134
|
)
|
|
99
135
|
|
|
100
136
|
menu.run
|
|
101
137
|
|
|
102
|
-
assert_includes stdout.string, "Please choose 1, 2, 3, or
|
|
138
|
+
assert_includes stdout.string, "Please choose 1, 2, 3, 4, or 5."
|
|
103
139
|
assert_equal 0, column_action.runs
|
|
104
140
|
assert_equal 0, rows_action.runs
|
|
105
141
|
assert_equal 0, randomize_rows_action.runs
|
|
142
|
+
assert_equal 0, dedupe_action.runs
|
|
106
143
|
end
|
|
107
144
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/prompts/dedupe_key_selector_prompt"
|
|
5
|
+
|
|
6
|
+
class DedupeKeySelectorPromptTest < Minitest::Test
|
|
7
|
+
def test_builds_name_selector_in_header_mode
|
|
8
|
+
prompt = Csvtool::Interface::CLI::Prompts::DedupeKeySelectorPrompt.new(stdin: StringIO.new("customer_id\n"), stdout: StringIO.new)
|
|
9
|
+
|
|
10
|
+
selector = prompt.call(label: "Source", headers_present: true)
|
|
11
|
+
|
|
12
|
+
assert_equal true, selector.headers_present?
|
|
13
|
+
assert_equal "customer_id", selector.value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_builds_index_selector_in_headerless_mode
|
|
17
|
+
prompt = Csvtool::Interface::CLI::Prompts::DedupeKeySelectorPrompt.new(stdin: StringIO.new("2\n"), stdout: StringIO.new)
|
|
18
|
+
|
|
19
|
+
selector = prompt.call(label: "Reference", headers_present: false)
|
|
20
|
+
|
|
21
|
+
assert_equal true, selector.index?
|
|
22
|
+
assert_equal 2, selector.value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_returns_nil_for_invalid_selector
|
|
26
|
+
prompt = Csvtool::Interface::CLI::Prompts::DedupeKeySelectorPrompt.new(stdin: StringIO.new("\n"), stdout: StringIO.new)
|
|
27
|
+
|
|
28
|
+
assert_nil prompt.call(label: "Source", headers_present: true)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -8,4 +8,13 @@ class FilePathPromptTest < Minitest::Test
|
|
|
8
8
|
prompt = Csvtool::Interface::CLI::Prompts::FilePathPrompt.new(stdin: StringIO.new(" /tmp/a.csv \n"), stdout: StringIO.new)
|
|
9
9
|
assert_equal "/tmp/a.csv", prompt.call
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
def test_supports_custom_label
|
|
13
|
+
out = StringIO.new
|
|
14
|
+
prompt = Csvtool::Interface::CLI::Prompts::FilePathPrompt.new(stdin: StringIO.new("/tmp/a.csv\n"), stdout: out)
|
|
15
|
+
|
|
16
|
+
prompt.call(label: "Reference CSV file path: ")
|
|
17
|
+
|
|
18
|
+
assert_includes out.string, "Reference CSV file path: "
|
|
19
|
+
end
|
|
11
20
|
end
|
|
@@ -11,4 +11,14 @@ class HeadersPresentPromptTest < Minitest::Test
|
|
|
11
11
|
assert_equal true, yes_prompt.call
|
|
12
12
|
assert_equal false, no_prompt.call
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
def test_supports_custom_label
|
|
16
|
+
out = StringIO.new
|
|
17
|
+
prompt = Csvtool::Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: StringIO.new("yes\n"), stdout: out)
|
|
18
|
+
|
|
19
|
+
result = prompt.call(label: "Source headers present? [Y/n]: ")
|
|
20
|
+
|
|
21
|
+
assert_equal true, result
|
|
22
|
+
assert_includes out.string, "Source headers present? [Y/n]: "
|
|
23
|
+
end
|
|
14
24
|
end
|
|
@@ -28,4 +28,14 @@ class SeparatorPromptTest < Minitest::Test
|
|
|
28
28
|
assert_nil prompt.call
|
|
29
29
|
assert_includes errors.calls, :empty_custom_separator
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
def test_supports_custom_label
|
|
33
|
+
errors = FakeErrors.new
|
|
34
|
+
out = StringIO.new
|
|
35
|
+
prompt = Csvtool::Interface::CLI::Prompts::SeparatorPrompt.new(stdin: StringIO.new("\n"), stdout: out, errors: errors)
|
|
36
|
+
|
|
37
|
+
prompt.call(label: "Reference CSV separator:")
|
|
38
|
+
|
|
39
|
+
assert_includes out.string, "Reference CSV separator:"
|
|
40
|
+
end
|
|
31
41
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/prompts/yes_no_prompt"
|
|
5
|
+
|
|
6
|
+
class YesNoPromptTest < Minitest::Test
|
|
7
|
+
def test_uses_default_for_blank_or_invalid
|
|
8
|
+
prompt_blank = Csvtool::Interface::CLI::Prompts::YesNoPrompt.new(stdin: StringIO.new("\n"), stdout: StringIO.new)
|
|
9
|
+
prompt_invalid = Csvtool::Interface::CLI::Prompts::YesNoPrompt.new(stdin: StringIO.new("maybe\n"), stdout: StringIO.new)
|
|
10
|
+
|
|
11
|
+
assert_equal true, prompt_blank.call(label: "Q? ", default: true)
|
|
12
|
+
assert_equal false, prompt_invalid.call(label: "Q? ", default: false)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_accepts_yes_and_no_inputs
|
|
16
|
+
prompt_yes = Csvtool::Interface::CLI::Prompts::YesNoPrompt.new(stdin: StringIO.new("y\n"), stdout: StringIO.new)
|
|
17
|
+
prompt_no = Csvtool::Interface::CLI::Prompts::YesNoPrompt.new(stdin: StringIO.new("no\n"), stdout: StringIO.new)
|
|
18
|
+
|
|
19
|
+
assert_equal true, prompt_yes.call(label: "Q? ", default: false)
|
|
20
|
+
assert_equal false, prompt_no.call(label: "Q? ", default: true)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/column_session_builder"
|
|
5
|
+
|
|
6
|
+
class ColumnSessionBuilderTest < Minitest::Test
|
|
7
|
+
def test_builds_column_session
|
|
8
|
+
builder = Csvtool::Interface::CLI::Workflows::Builders::ColumnSessionBuilder.new
|
|
9
|
+
|
|
10
|
+
session = builder.call(file_path: "/tmp/data.csv", col_sep: ",", column_name: "name", skip_blanks: true)
|
|
11
|
+
|
|
12
|
+
assert_equal "/tmp/data.csv", session.source.path
|
|
13
|
+
assert_equal ",", session.source.separator.value
|
|
14
|
+
assert_equal "name", session.column_selection.name
|
|
15
|
+
assert_equal true, session.options.skip_blanks?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder"
|
|
5
|
+
require "csvtool/domain/cross_csv_dedupe_session/csv_profile"
|
|
6
|
+
require "csvtool/domain/cross_csv_dedupe_session/column_selector"
|
|
7
|
+
require "csvtool/domain/shared/output_destination"
|
|
8
|
+
|
|
9
|
+
class CrossCsvDedupeSessionBuilderTest < Minitest::Test
|
|
10
|
+
def test_builds_cross_csv_dedupe_session
|
|
11
|
+
builder = Csvtool::Interface::CLI::Workflows::Builders::CrossCsvDedupeSessionBuilder.new
|
|
12
|
+
source = Csvtool::Domain::CrossCsvDedupeSession::CsvProfile.new(path: "/tmp/source.csv", separator: ",", headers_present: true)
|
|
13
|
+
reference = Csvtool::Domain::CrossCsvDedupeSession::CsvProfile.new(path: "/tmp/reference.csv", separator: ",", headers_present: true)
|
|
14
|
+
source_selector = Csvtool::Domain::CrossCsvDedupeSession::ColumnSelector.from_input(headers_present: true, input: "id")
|
|
15
|
+
reference_selector = Csvtool::Domain::CrossCsvDedupeSession::ColumnSelector.from_input(headers_present: true, input: "rid")
|
|
16
|
+
destination = Csvtool::Domain::Shared::OutputDestination.console
|
|
17
|
+
|
|
18
|
+
session = builder.call(
|
|
19
|
+
source: source,
|
|
20
|
+
reference: reference,
|
|
21
|
+
source_selector: source_selector,
|
|
22
|
+
reference_selector: reference_selector,
|
|
23
|
+
trim_whitespace: true,
|
|
24
|
+
case_insensitive: false,
|
|
25
|
+
destination: destination
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
assert_equal "/tmp/source.csv", session.source.path
|
|
29
|
+
assert_equal "/tmp/reference.csv", session.reference.path
|
|
30
|
+
assert_equal "id", session.key_mapping.source_selector.value
|
|
31
|
+
assert_equal "rid", session.key_mapping.reference_selector.value
|
|
32
|
+
assert_equal true, session.match_options.trim_whitespace?
|
|
33
|
+
assert_equal false, session.match_options.case_insensitive?
|
|
34
|
+
assert_equal true, session.output_destination.console?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/row_extraction_session_builder"
|
|
5
|
+
require "csvtool/domain/row_session/row_range"
|
|
6
|
+
require "csvtool/domain/shared/output_destination"
|
|
7
|
+
|
|
8
|
+
class RowExtractionSessionBuilderTest < Minitest::Test
|
|
9
|
+
def test_builds_row_extraction_session
|
|
10
|
+
builder = Csvtool::Interface::CLI::Workflows::Builders::RowExtractionSessionBuilder.new
|
|
11
|
+
row_range = Csvtool::Domain::RowSession::RowRange.new(start_row: 2, end_row: 4)
|
|
12
|
+
destination = Csvtool::Domain::Shared::OutputDestination.console
|
|
13
|
+
|
|
14
|
+
session = builder.call(file_path: "/tmp/data.csv", col_sep: ";", row_range: row_range, destination: destination)
|
|
15
|
+
|
|
16
|
+
assert_equal "/tmp/data.csv", session.source.path
|
|
17
|
+
assert_equal ";", session.source.separator
|
|
18
|
+
assert_equal 2, session.row_range.start_row
|
|
19
|
+
assert_equal true, session.output_destination.console?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/row_randomization_session_builder"
|
|
5
|
+
require "csvtool/domain/shared/output_destination"
|
|
6
|
+
|
|
7
|
+
class RowRandomizationSessionBuilderTest < Minitest::Test
|
|
8
|
+
def test_builds_row_randomization_session
|
|
9
|
+
builder = Csvtool::Interface::CLI::Workflows::Builders::RowRandomizationSessionBuilder.new
|
|
10
|
+
destination = Csvtool::Domain::Shared::OutputDestination.file(path: "/tmp/out.csv")
|
|
11
|
+
|
|
12
|
+
session = builder.call(
|
|
13
|
+
file_path: "/tmp/data.csv",
|
|
14
|
+
col_sep: "\t",
|
|
15
|
+
headers_present: false,
|
|
16
|
+
seed: 12,
|
|
17
|
+
destination: destination
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
assert_equal "/tmp/data.csv", session.source.path
|
|
21
|
+
assert_equal "\t", session.source.separator
|
|
22
|
+
assert_equal false, session.source.headers_present?
|
|
23
|
+
assert_equal 12, session.options.seed
|
|
24
|
+
assert_equal true, session.output_destination.file?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/column_extraction_presenter"
|
|
5
|
+
|
|
6
|
+
class ColumnExtractionPresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_value
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::ColumnExtractionPresenter.new(stdout: out)
|
|
10
|
+
|
|
11
|
+
presenter.print_value("Alice")
|
|
12
|
+
|
|
13
|
+
assert_equal "Alice\n", out.string
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_prints_file_written_message
|
|
17
|
+
out = StringIO.new
|
|
18
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::ColumnExtractionPresenter.new(stdout: out)
|
|
19
|
+
|
|
20
|
+
presenter.print_file_written("/tmp/names.csv")
|
|
21
|
+
|
|
22
|
+
assert_includes out.string, "Wrote output to /tmp/names.csv"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter"
|
|
5
|
+
|
|
6
|
+
class CrossCsvDedupePresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_header_row_and_summary
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::CrossCsvDedupePresenter.new(stdout: out, col_sep: ",")
|
|
10
|
+
|
|
11
|
+
presenter.print_header(["id", "name"])
|
|
12
|
+
presenter.print_row(["1", "Alice"])
|
|
13
|
+
presenter.print_summary(source_rows: 5, removed_rows: 3, kept_rows_count: 2)
|
|
14
|
+
|
|
15
|
+
assert_includes out.string, "\nid,name\n"
|
|
16
|
+
assert_includes out.string, "1,Alice"
|
|
17
|
+
assert_includes out.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_prints_zero_and_all_removed_messages
|
|
21
|
+
out = StringIO.new
|
|
22
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::CrossCsvDedupePresenter.new(stdout: out, col_sep: ",")
|
|
23
|
+
|
|
24
|
+
presenter.print_summary(source_rows: 5, removed_rows: 0, kept_rows_count: 5)
|
|
25
|
+
presenter.print_summary(source_rows: 5, removed_rows: 5, kept_rows_count: 0)
|
|
26
|
+
|
|
27
|
+
assert_includes out.string, "No rows removed; no matching keys found."
|
|
28
|
+
assert_includes out.string, "All source rows were removed by dedupe."
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/row_extraction_presenter"
|
|
5
|
+
|
|
6
|
+
class RowExtractionPresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_header_once_then_rows
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::RowExtractionPresenter.new(
|
|
10
|
+
stdout: out,
|
|
11
|
+
headers: ["name", "city"],
|
|
12
|
+
col_sep: ","
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
presenter.print_row(["Alice", "London"])
|
|
16
|
+
presenter.print_row(["Bob", "Paris"])
|
|
17
|
+
|
|
18
|
+
assert_equal "name,city\nAlice,London\nBob,Paris\n", out.string
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_prints_file_written_message
|
|
22
|
+
out = StringIO.new
|
|
23
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::RowExtractionPresenter.new(
|
|
24
|
+
stdout: out,
|
|
25
|
+
headers: ["name"],
|
|
26
|
+
col_sep: ","
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
presenter.print_file_written("/tmp/out.csv")
|
|
30
|
+
|
|
31
|
+
assert_includes out.string, "Wrote output to /tmp/out.csv"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/row_randomization_presenter"
|
|
5
|
+
|
|
6
|
+
class RowRandomizationPresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_console_start_and_rows
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::RowRandomizationPresenter.new(
|
|
10
|
+
stdout: out,
|
|
11
|
+
headers: ["name", "city"],
|
|
12
|
+
col_sep: ","
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
presenter.print_console_start
|
|
16
|
+
presenter.print_row(["Alice", "London"])
|
|
17
|
+
|
|
18
|
+
assert_equal "\nname,city\nAlice,London\n", out.string
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_prints_file_written_message
|
|
22
|
+
out = StringIO.new
|
|
23
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::RowRandomizationPresenter.new(
|
|
24
|
+
stdout: out,
|
|
25
|
+
headers: nil,
|
|
26
|
+
col_sep: ","
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
presenter.print_file_written("/tmp/out.csv")
|
|
30
|
+
|
|
31
|
+
assert_includes out.string, "Wrote output to /tmp/out.csv"
|
|
32
|
+
end
|
|
33
|
+
end
|