csvops 0.5.0.alpha → 0.7.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 +88 -7
- data/docs/architecture.md +119 -5
- data/docs/release-v0.6.0-alpha.md +84 -0
- data/docs/release-v0.7.0-alpha.md +87 -0
- data/lib/csvtool/application/use_cases/run_csv_parity.rb +70 -0
- data/lib/csvtool/application/use_cases/run_csv_split.rb +97 -0
- data/lib/csvtool/cli.rb +9 -1
- data/lib/csvtool/domain/csv_parity_session/parity_options.rb +22 -0
- data/lib/csvtool/domain/csv_parity_session/parity_session.rb +20 -0
- data/lib/csvtool/domain/csv_parity_session/source_pair.rb +19 -0
- data/lib/csvtool/domain/csv_split_session/split_options.rb +27 -0
- data/lib/csvtool/domain/csv_split_session/split_session.rb +20 -0
- data/lib/csvtool/domain/csv_split_session/split_source.rb +17 -0
- data/lib/csvtool/infrastructure/csv/csv_parity_comparator.rb +71 -0
- data/lib/csvtool/infrastructure/csv/csv_splitter.rb +64 -0
- data/lib/csvtool/infrastructure/output/csv_split_manifest_writer.rb +20 -0
- data/lib/csvtool/interface/cli/errors/presenter.rb +12 -0
- data/lib/csvtool/interface/cli/menu_loop.rb +8 -2
- data/lib/csvtool/interface/cli/prompts/chunk_size_prompt.rb +21 -0
- data/lib/csvtool/interface/cli/prompts/split_manifest_prompt.rb +30 -0
- data/lib/csvtool/interface/cli/prompts/split_output_prompt.rb +38 -0
- data/lib/csvtool/interface/cli/workflows/builders/csv_parity_session_builder.rb +33 -0
- data/lib/csvtool/interface/cli/workflows/builders/csv_split_session_builder.rb +44 -0
- data/lib/csvtool/interface/cli/workflows/presenters/csv_parity_presenter.rb +38 -0
- data/lib/csvtool/interface/cli/workflows/presenters/csv_split_presenter.rb +26 -0
- data/lib/csvtool/interface/cli/workflows/run_csv_parity_workflow.rb +66 -0
- data/lib/csvtool/interface/cli/workflows/run_csv_split_workflow.rb +89 -0
- data/lib/csvtool/interface/cli/workflows/steps/csv_split/build_session_step.rb +30 -0
- data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_inputs_step.rb +43 -0
- data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step.rb +30 -0
- data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step.rb +31 -0
- data/lib/csvtool/interface/cli/workflows/steps/csv_split/execute_step.rb +36 -0
- data/lib/csvtool/interface/cli/workflows/steps/parity/build_session_step.rb +25 -0
- data/lib/csvtool/interface/cli/workflows/steps/parity/collect_inputs_step.rb +32 -0
- data/lib/csvtool/interface/cli/workflows/steps/parity/execute_step.rb +26 -0
- data/lib/csvtool/version.rb +1 -1
- data/test/csvtool/application/use_cases/run_csv_parity_test.rb +160 -0
- data/test/csvtool/application/use_cases/run_csv_split_test.rb +124 -0
- data/test/csvtool/cli_test.rb +222 -21
- data/test/csvtool/cli_unit_test.rb +4 -4
- data/test/csvtool/domain/csv_parity_session/parity_options_test.rb +17 -0
- data/test/csvtool/domain/csv_parity_session/parity_session_test.rb +18 -0
- data/test/csvtool/domain/csv_parity_session/source_pair_test.rb +11 -0
- data/test/csvtool/infrastructure/csv/csv_parity_comparator_test.rb +78 -0
- data/test/csvtool/infrastructure/csv/csv_splitter_test.rb +68 -0
- data/test/csvtool/infrastructure/output/csv_split_manifest_writer_test.rb +25 -0
- data/test/csvtool/interface/cli/errors/presenter_test.rb +2 -0
- data/test/csvtool/interface/cli/menu_loop_test.rb +87 -93
- data/test/csvtool/interface/cli/prompts/chunk_size_prompt_test.rb +17 -0
- data/test/csvtool/interface/cli/prompts/split_manifest_prompt_test.rb +42 -0
- data/test/csvtool/interface/cli/prompts/split_output_prompt_test.rb +22 -0
- data/test/csvtool/interface/cli/workflows/builders/csv_parity_session_builder_test.rb +20 -0
- data/test/csvtool/interface/cli/workflows/builders/csv_split_session_builder_test.rb +30 -0
- data/test/csvtool/interface/cli/workflows/presenters/csv_parity_presenter_test.rb +43 -0
- data/test/csvtool/interface/cli/workflows/presenters/csv_split_presenter_test.rb +26 -0
- data/test/csvtool/interface/cli/workflows/run_csv_parity_workflow_test.rb +94 -0
- data/test/csvtool/interface/cli/workflows/run_csv_split_workflow_test.rb +200 -0
- data/test/csvtool/interface/cli/workflows/steps/csv_split/build_session_step_test.rb +40 -0
- data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_inputs_step_test.rb +64 -0
- data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step_test.rb +30 -0
- data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step_test.rb +32 -0
- data/test/csvtool/interface/cli/workflows/steps/csv_split/execute_step_test.rb +83 -0
- data/test/csvtool/interface/cli/workflows/steps/parity/build_session_step_test.rb +41 -0
- data/test/csvtool/interface/cli/workflows/steps/parity/collect_inputs_step_test.rb +30 -0
- data/test/csvtool/interface/cli/workflows/steps/parity/execute_step_test.rb +40 -0
- data/test/fixtures/parity_duplicates_left.csv +4 -0
- data/test/fixtures/parity_duplicates_right.csv +3 -0
- data/test/fixtures/parity_people_header_mismatch.csv +4 -0
- data/test/fixtures/parity_people_many_reordered.csv +13 -0
- data/test/fixtures/parity_people_mismatch.csv +4 -0
- data/test/fixtures/parity_people_reordered.csv +4 -0
- data/test/fixtures/parity_people_reordered.tsv +4 -0
- data/test/fixtures/split_people_25.csv +26 -0
- metadata +64 -1
|
@@ -17,128 +17,122 @@ class MenuLoopTest < Minitest::Test
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def test_routes_extract_column_then_exit
|
|
20
|
-
|
|
21
|
-
rows_action = FakeAction.new
|
|
22
|
-
randomize_rows_action = FakeAction.new
|
|
23
|
-
dedupe_action = FakeAction.new
|
|
24
|
-
stdout = StringIO.new
|
|
25
|
-
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
26
|
-
stdin: StringIO.new("1\n5\n"),
|
|
27
|
-
stdout: stdout,
|
|
28
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
29
|
-
extract_column_action: column_action,
|
|
30
|
-
extract_rows_action: rows_action,
|
|
31
|
-
randomize_rows_action: randomize_rows_action,
|
|
32
|
-
dedupe_action: dedupe_action
|
|
33
|
-
)
|
|
34
|
-
|
|
20
|
+
menu, actions, = build_menu("1\n7\n")
|
|
35
21
|
status = menu.run
|
|
36
22
|
|
|
37
23
|
assert_equal 0, status
|
|
38
|
-
assert_equal 1,
|
|
39
|
-
assert_equal 0,
|
|
40
|
-
assert_equal 0,
|
|
41
|
-
assert_equal 0,
|
|
42
|
-
|
|
24
|
+
assert_equal 1, actions[:column].runs
|
|
25
|
+
assert_equal 0, actions[:rows].runs
|
|
26
|
+
assert_equal 0, actions[:randomize].runs
|
|
27
|
+
assert_equal 0, actions[:dedupe].runs
|
|
28
|
+
assert_equal 0, actions[:parity].runs
|
|
29
|
+
assert_equal 0, actions[:split].runs
|
|
43
30
|
end
|
|
44
31
|
|
|
45
32
|
def test_routes_extract_rows_then_exit
|
|
46
|
-
|
|
47
|
-
rows_action = FakeAction.new
|
|
48
|
-
randomize_rows_action = FakeAction.new
|
|
49
|
-
dedupe_action = FakeAction.new
|
|
50
|
-
stdout = StringIO.new
|
|
51
|
-
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
52
|
-
stdin: StringIO.new("2\n5\n"),
|
|
53
|
-
stdout: stdout,
|
|
54
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
55
|
-
extract_column_action: column_action,
|
|
56
|
-
extract_rows_action: rows_action,
|
|
57
|
-
randomize_rows_action: randomize_rows_action,
|
|
58
|
-
dedupe_action: dedupe_action
|
|
59
|
-
)
|
|
60
|
-
|
|
33
|
+
menu, actions, = build_menu("2\n7\n")
|
|
61
34
|
status = menu.run
|
|
62
35
|
|
|
63
36
|
assert_equal 0, status
|
|
64
|
-
assert_equal 0,
|
|
65
|
-
assert_equal 1,
|
|
66
|
-
assert_equal 0,
|
|
67
|
-
assert_equal 0,
|
|
37
|
+
assert_equal 0, actions[:column].runs
|
|
38
|
+
assert_equal 1, actions[:rows].runs
|
|
39
|
+
assert_equal 0, actions[:randomize].runs
|
|
40
|
+
assert_equal 0, actions[:dedupe].runs
|
|
41
|
+
assert_equal 0, actions[:parity].runs
|
|
42
|
+
assert_equal 0, actions[:split].runs
|
|
68
43
|
end
|
|
69
44
|
|
|
70
45
|
def test_routes_randomize_rows_then_exit
|
|
71
|
-
|
|
72
|
-
rows_action = FakeAction.new
|
|
73
|
-
randomize_rows_action = FakeAction.new
|
|
74
|
-
dedupe_action = FakeAction.new
|
|
75
|
-
stdout = StringIO.new
|
|
76
|
-
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
77
|
-
stdin: StringIO.new("3\n5\n"),
|
|
78
|
-
stdout: stdout,
|
|
79
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
80
|
-
extract_column_action: column_action,
|
|
81
|
-
extract_rows_action: rows_action,
|
|
82
|
-
randomize_rows_action: randomize_rows_action,
|
|
83
|
-
dedupe_action: dedupe_action
|
|
84
|
-
)
|
|
85
|
-
|
|
46
|
+
menu, actions, = build_menu("3\n7\n")
|
|
86
47
|
status = menu.run
|
|
87
48
|
|
|
88
49
|
assert_equal 0, status
|
|
89
|
-
assert_equal 0,
|
|
90
|
-
assert_equal 0,
|
|
91
|
-
assert_equal 1,
|
|
92
|
-
assert_equal 0,
|
|
50
|
+
assert_equal 0, actions[:column].runs
|
|
51
|
+
assert_equal 0, actions[:rows].runs
|
|
52
|
+
assert_equal 1, actions[:randomize].runs
|
|
53
|
+
assert_equal 0, actions[:dedupe].runs
|
|
54
|
+
assert_equal 0, actions[:parity].runs
|
|
55
|
+
assert_equal 0, actions[:split].runs
|
|
93
56
|
end
|
|
94
57
|
|
|
95
58
|
def test_routes_dedupe_then_exit
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
59
|
+
menu, actions, = build_menu("4\n7\n")
|
|
60
|
+
status = menu.run
|
|
61
|
+
|
|
62
|
+
assert_equal 0, status
|
|
63
|
+
assert_equal 0, actions[:column].runs
|
|
64
|
+
assert_equal 0, actions[:rows].runs
|
|
65
|
+
assert_equal 0, actions[:randomize].runs
|
|
66
|
+
assert_equal 1, actions[:dedupe].runs
|
|
67
|
+
assert_equal 0, actions[:parity].runs
|
|
68
|
+
assert_equal 0, actions[:split].runs
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_routes_parity_then_exit
|
|
72
|
+
menu, actions, = build_menu("5\n7\n")
|
|
73
|
+
status = menu.run
|
|
74
|
+
|
|
75
|
+
assert_equal 0, status
|
|
76
|
+
assert_equal 0, actions[:column].runs
|
|
77
|
+
assert_equal 0, actions[:rows].runs
|
|
78
|
+
assert_equal 0, actions[:randomize].runs
|
|
79
|
+
assert_equal 0, actions[:dedupe].runs
|
|
80
|
+
assert_equal 1, actions[:parity].runs
|
|
81
|
+
assert_equal 0, actions[:split].runs
|
|
82
|
+
end
|
|
110
83
|
|
|
84
|
+
def test_routes_split_then_exit
|
|
85
|
+
menu, actions, stdout = build_menu("6\n7\n")
|
|
111
86
|
status = menu.run
|
|
112
87
|
|
|
113
88
|
assert_equal 0, status
|
|
114
|
-
assert_equal 0,
|
|
115
|
-
assert_equal 0,
|
|
116
|
-
assert_equal 0,
|
|
117
|
-
assert_equal
|
|
89
|
+
assert_equal 0, actions[:column].runs
|
|
90
|
+
assert_equal 0, actions[:rows].runs
|
|
91
|
+
assert_equal 0, actions[:randomize].runs
|
|
92
|
+
assert_equal 0, actions[:dedupe].runs
|
|
93
|
+
assert_equal 0, actions[:parity].runs
|
|
94
|
+
assert_equal 1, actions[:split].runs
|
|
95
|
+
assert_includes stdout.string, "CSV Tool Menu"
|
|
118
96
|
end
|
|
119
97
|
|
|
120
98
|
def test_invalid_choice_shows_prompt
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
99
|
+
menu, actions, stdout = build_menu("x\n7\n")
|
|
100
|
+
menu.run
|
|
101
|
+
|
|
102
|
+
assert_includes stdout.string, "Please choose 1, 2, 3, 4, 5, 6, or 7."
|
|
103
|
+
assert_equal 0, actions[:column].runs
|
|
104
|
+
assert_equal 0, actions[:rows].runs
|
|
105
|
+
assert_equal 0, actions[:randomize].runs
|
|
106
|
+
assert_equal 0, actions[:dedupe].runs
|
|
107
|
+
assert_equal 0, actions[:parity].runs
|
|
108
|
+
assert_equal 0, actions[:split].runs
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def build_menu(input)
|
|
114
|
+
actions = {
|
|
115
|
+
column: FakeAction.new,
|
|
116
|
+
rows: FakeAction.new,
|
|
117
|
+
randomize: FakeAction.new,
|
|
118
|
+
dedupe: FakeAction.new,
|
|
119
|
+
parity: FakeAction.new,
|
|
120
|
+
split: FakeAction.new
|
|
121
|
+
}
|
|
125
122
|
stdout = StringIO.new
|
|
123
|
+
|
|
126
124
|
menu = Csvtool::Interface::CLI::MenuLoop.new(
|
|
127
|
-
stdin: StringIO.new(
|
|
125
|
+
stdin: StringIO.new(input),
|
|
128
126
|
stdout: stdout,
|
|
129
|
-
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Exit"],
|
|
130
|
-
extract_column_action:
|
|
131
|
-
extract_rows_action:
|
|
132
|
-
randomize_rows_action:
|
|
133
|
-
dedupe_action:
|
|
127
|
+
menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Split CSV into chunks", "Exit"],
|
|
128
|
+
extract_column_action: actions[:column],
|
|
129
|
+
extract_rows_action: actions[:rows],
|
|
130
|
+
randomize_rows_action: actions[:randomize],
|
|
131
|
+
dedupe_action: actions[:dedupe],
|
|
132
|
+
parity_action: actions[:parity],
|
|
133
|
+
split_action: actions[:split]
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
menu
|
|
137
|
-
|
|
138
|
-
assert_includes stdout.string, "Please choose 1, 2, 3, 4, or 5."
|
|
139
|
-
assert_equal 0, column_action.runs
|
|
140
|
-
assert_equal 0, rows_action.runs
|
|
141
|
-
assert_equal 0, randomize_rows_action.runs
|
|
142
|
-
assert_equal 0, dedupe_action.runs
|
|
136
|
+
[menu, actions, stdout]
|
|
143
137
|
end
|
|
144
138
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/prompts/chunk_size_prompt"
|
|
5
|
+
|
|
6
|
+
class ChunkSizePromptTest < Minitest::Test
|
|
7
|
+
def test_returns_entered_value
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
prompt = Csvtool::Interface::CLI::Prompts::ChunkSizePrompt.new(
|
|
10
|
+
stdin: StringIO.new("25\n"),
|
|
11
|
+
stdout: out
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
assert_equal "25", prompt.call
|
|
15
|
+
assert_includes out.string, "Rows per chunk: "
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/prompts/split_manifest_prompt"
|
|
5
|
+
|
|
6
|
+
class SplitManifestPromptTest < Minitest::Test
|
|
7
|
+
class FakeYesNoPrompt
|
|
8
|
+
def initialize(value)
|
|
9
|
+
@value = value
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(label:, default:)
|
|
13
|
+
@value.nil? ? default : @value
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_returns_disabled_when_user_declines_manifest
|
|
18
|
+
prompt = Csvtool::Interface::CLI::Prompts::SplitManifestPrompt.new(
|
|
19
|
+
stdin: StringIO.new,
|
|
20
|
+
stdout: StringIO.new,
|
|
21
|
+
yes_no_prompt: FakeYesNoPrompt.new(false)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
result = prompt.call(default_path: "/tmp/manifest.csv")
|
|
25
|
+
|
|
26
|
+
assert_equal false, result[:write_manifest]
|
|
27
|
+
assert_nil result[:manifest_path]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_uses_default_manifest_path_when_blank
|
|
31
|
+
prompt = Csvtool::Interface::CLI::Prompts::SplitManifestPrompt.new(
|
|
32
|
+
stdin: StringIO.new("\n"),
|
|
33
|
+
stdout: StringIO.new,
|
|
34
|
+
yes_no_prompt: FakeYesNoPrompt.new(true)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
result = prompt.call(default_path: "/tmp/manifest.csv")
|
|
38
|
+
|
|
39
|
+
assert_equal true, result[:write_manifest]
|
|
40
|
+
assert_equal "/tmp/manifest.csv", result[:manifest_path]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/prompts/split_output_prompt"
|
|
5
|
+
require "csvtool/interface/cli/prompts/yes_no_prompt"
|
|
6
|
+
|
|
7
|
+
class SplitOutputPromptTest < Minitest::Test
|
|
8
|
+
def test_uses_defaults_for_blank_values
|
|
9
|
+
out = StringIO.new
|
|
10
|
+
prompt = Csvtool::Interface::CLI::Prompts::SplitOutputPrompt.new(
|
|
11
|
+
stdin: StringIO.new("\n\n\n"),
|
|
12
|
+
stdout: out,
|
|
13
|
+
yes_no_prompt: Csvtool::Interface::CLI::Prompts::YesNoPrompt.new(stdin: StringIO.new("\n"), stdout: StringIO.new)
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
result = prompt.call(default_directory: "/tmp/out", default_prefix: "people")
|
|
17
|
+
|
|
18
|
+
assert_equal "/tmp/out", result[:output_directory]
|
|
19
|
+
assert_equal "people", result[:file_prefix]
|
|
20
|
+
assert_equal false, result[:overwrite_existing]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/csv_parity_session_builder"
|
|
5
|
+
|
|
6
|
+
class CsvParitySessionBuilderTest < Minitest::Test
|
|
7
|
+
def test_builds_parity_session
|
|
8
|
+
session = Csvtool::Interface::CLI::Workflows::Builders::CsvParitySessionBuilder.new.call(
|
|
9
|
+
left_path: "/tmp/left.csv",
|
|
10
|
+
right_path: "/tmp/right.csv",
|
|
11
|
+
col_sep: "\t",
|
|
12
|
+
headers_present: false
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
assert_equal "/tmp/left.csv", session.source_pair.left_path
|
|
16
|
+
assert_equal "/tmp/right.csv", session.source_pair.right_path
|
|
17
|
+
assert_equal "\t", session.options.separator
|
|
18
|
+
assert_equal false, session.options.headers_present?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/builders/csv_split_session_builder"
|
|
5
|
+
|
|
6
|
+
class CsvSplitSessionBuilderTest < Minitest::Test
|
|
7
|
+
def test_builds_split_session
|
|
8
|
+
session = Csvtool::Interface::CLI::Workflows::Builders::CsvSplitSessionBuilder.new.call(
|
|
9
|
+
file_path: "/tmp/people.csv",
|
|
10
|
+
col_sep: ",",
|
|
11
|
+
headers_present: true,
|
|
12
|
+
chunk_size: 10,
|
|
13
|
+
output_directory: "/tmp/out",
|
|
14
|
+
file_prefix: "batch",
|
|
15
|
+
overwrite_existing: true,
|
|
16
|
+
write_manifest: true,
|
|
17
|
+
manifest_path: "/tmp/out/manifest.csv"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
assert_equal "/tmp/people.csv", session.source.path
|
|
21
|
+
assert_equal ",", session.source.separator
|
|
22
|
+
assert_equal true, session.source.headers_present
|
|
23
|
+
assert_equal 10, session.options.chunk_size
|
|
24
|
+
assert_equal "/tmp/out", session.options.output_directory
|
|
25
|
+
assert_equal "batch", session.options.file_prefix
|
|
26
|
+
assert_equal true, session.options.overwrite_existing
|
|
27
|
+
assert_equal true, session.options.write_manifest
|
|
28
|
+
assert_equal "/tmp/out/manifest.csv", session.options.manifest_path
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/csv_parity_presenter"
|
|
5
|
+
|
|
6
|
+
class CsvParityPresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_match_summary
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::CsvParityPresenter.new(stdout: out)
|
|
10
|
+
|
|
11
|
+
presenter.print_summary(
|
|
12
|
+
match: true,
|
|
13
|
+
left_rows: 3,
|
|
14
|
+
right_rows: 3,
|
|
15
|
+
left_only_count: 0,
|
|
16
|
+
right_only_count: 0
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
assert_includes out.string, "MATCH"
|
|
20
|
+
assert_includes out.string, "Summary: left_rows=3 right_rows=3 left_only=0 right_only=0"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_prints_mismatch_examples
|
|
24
|
+
out = StringIO.new
|
|
25
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::CsvParityPresenter.new(stdout: out)
|
|
26
|
+
|
|
27
|
+
presenter.print_summary(
|
|
28
|
+
match: false,
|
|
29
|
+
left_rows: 3,
|
|
30
|
+
right_rows: 3,
|
|
31
|
+
left_only_count: 1,
|
|
32
|
+
right_only_count: 1,
|
|
33
|
+
left_only_examples: [{ row: "Cara,Berlin", count_delta: 1 }],
|
|
34
|
+
right_only_examples: [{ row: "Dina,Rome", count_delta: 1 }]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
assert_includes out.string, "MISMATCH"
|
|
38
|
+
assert_includes out.string, "Left-only examples:"
|
|
39
|
+
assert_includes out.string, "Cara,Berlin (count +1)"
|
|
40
|
+
assert_includes out.string, "Right-only examples:"
|
|
41
|
+
assert_includes out.string, "Dina,Rome (count +1)"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/presenters/csv_split_presenter"
|
|
5
|
+
|
|
6
|
+
class CsvSplitPresenterTest < Minitest::Test
|
|
7
|
+
def test_prints_summary_and_chunk_paths
|
|
8
|
+
out = StringIO.new
|
|
9
|
+
presenter = Csvtool::Interface::CLI::Workflows::Presenters::CsvSplitPresenter.new(stdout: out)
|
|
10
|
+
|
|
11
|
+
presenter.print_summary(
|
|
12
|
+
chunk_size: 10,
|
|
13
|
+
data_rows: 25,
|
|
14
|
+
chunk_count: 3,
|
|
15
|
+
manifest_path: "/tmp/manifest.csv",
|
|
16
|
+
chunk_paths: ["/tmp/people_part_001.csv", "/tmp/people_part_002.csv", "/tmp/people_part_003.csv"]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
assert_includes out.string, "Split complete."
|
|
20
|
+
assert_includes out.string, "Chunk size: 10"
|
|
21
|
+
assert_includes out.string, "Data rows: 25"
|
|
22
|
+
assert_includes out.string, "Chunks written: 3"
|
|
23
|
+
assert_includes out.string, "Manifest: /tmp/manifest.csv"
|
|
24
|
+
assert_includes out.string, "/tmp/people_part_001.csv"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../test_helper"
|
|
4
|
+
require "csvtool/interface/cli/workflows/run_csv_parity_workflow"
|
|
5
|
+
|
|
6
|
+
class RunCsvParityWorkflowTest < Minitest::Test
|
|
7
|
+
class FakeUseCase
|
|
8
|
+
attr_reader :calls
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@calls = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call(session:)
|
|
15
|
+
@calls << session
|
|
16
|
+
Struct.new(:ok?, :data).new(true, {
|
|
17
|
+
match: true,
|
|
18
|
+
left_rows: 3,
|
|
19
|
+
right_rows: 3,
|
|
20
|
+
left_only_count: 0,
|
|
21
|
+
right_only_count: 0
|
|
22
|
+
})
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class MismatchUseCase
|
|
27
|
+
def call(session:)
|
|
28
|
+
Struct.new(:ok?, :data).new(true, {
|
|
29
|
+
match: false,
|
|
30
|
+
left_rows: 3,
|
|
31
|
+
right_rows: 3,
|
|
32
|
+
left_only_count: 1,
|
|
33
|
+
right_only_count: 1,
|
|
34
|
+
left_only_examples: [{ row: "Cara,Berlin", count_delta: 1 }],
|
|
35
|
+
right_only_examples: [{ row: "Dina,Rome", count_delta: 1 }]
|
|
36
|
+
})
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class CannotReadUseCase
|
|
41
|
+
def call(session:)
|
|
42
|
+
Struct.new(:ok?, :error, :data).new(false, :cannot_read_file, { path: "/tmp/protected.csv" })
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_prompts_for_paths_and_calls_use_case
|
|
47
|
+
stdout = StringIO.new
|
|
48
|
+
use_case = FakeUseCase.new
|
|
49
|
+
input = StringIO.new("/tmp/left.csv\n/tmp/right.csv\n2\ny\n")
|
|
50
|
+
|
|
51
|
+
Csvtool::Interface::CLI::Workflows::RunCsvParityWorkflow
|
|
52
|
+
.new(stdin: input, stdout: stdout, use_case: use_case)
|
|
53
|
+
.call
|
|
54
|
+
|
|
55
|
+
call = use_case.calls.first
|
|
56
|
+
assert_equal "/tmp/left.csv", call.source_pair.left_path
|
|
57
|
+
assert_equal "/tmp/right.csv", call.source_pair.right_path
|
|
58
|
+
assert_equal "\t", call.options.separator
|
|
59
|
+
assert_equal true, call.options.headers_present?
|
|
60
|
+
assert_includes stdout.string, "Left CSV file path: "
|
|
61
|
+
assert_includes stdout.string, "Right CSV file path: "
|
|
62
|
+
assert_includes stdout.string, "Choose separator:"
|
|
63
|
+
assert_includes stdout.string, "Headers present? [Y/n]: "
|
|
64
|
+
assert_includes stdout.string, "MATCH"
|
|
65
|
+
assert_includes stdout.string, "Summary: left_rows=3 right_rows=3 left_only=0 right_only=0"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_prints_mismatch_examples_when_not_equal
|
|
69
|
+
stdout = StringIO.new
|
|
70
|
+
input = StringIO.new("/tmp/left.csv\n/tmp/right.csv\n\ny\n")
|
|
71
|
+
|
|
72
|
+
Csvtool::Interface::CLI::Workflows::RunCsvParityWorkflow
|
|
73
|
+
.new(stdin: input, stdout: stdout, use_case: MismatchUseCase.new)
|
|
74
|
+
.call
|
|
75
|
+
|
|
76
|
+
assert_includes stdout.string, "MISMATCH"
|
|
77
|
+
assert_includes stdout.string, "Left-only examples:"
|
|
78
|
+
assert_includes stdout.string, "Cara,Berlin (count +1)"
|
|
79
|
+
assert_includes stdout.string, "Right-only examples:"
|
|
80
|
+
assert_includes stdout.string, "Dina,Rome (count +1)"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_prints_cannot_read_error_without_stacktrace
|
|
84
|
+
stdout = StringIO.new
|
|
85
|
+
input = StringIO.new("/tmp/left.csv\n/tmp/right.csv\n\ny\n")
|
|
86
|
+
|
|
87
|
+
Csvtool::Interface::CLI::Workflows::RunCsvParityWorkflow
|
|
88
|
+
.new(stdin: input, stdout: stdout, use_case: CannotReadUseCase.new)
|
|
89
|
+
.call
|
|
90
|
+
|
|
91
|
+
assert_includes stdout.string, "Cannot read file: /tmp/protected.csv"
|
|
92
|
+
refute_includes stdout.string, "Traceback"
|
|
93
|
+
end
|
|
94
|
+
end
|