csvops 0.6.0.alpha → 0.8.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +103 -24
  3. data/docs/architecture.md +121 -4
  4. data/docs/release-v0.7.0-alpha.md +87 -0
  5. data/docs/release-v0.8.0-alpha.md +88 -0
  6. data/lib/csvtool/application/use_cases/run_csv_split.rb +97 -0
  7. data/lib/csvtool/application/use_cases/run_csv_stats.rb +64 -0
  8. data/lib/csvtool/cli.rb +9 -1
  9. data/lib/csvtool/domain/csv_split_session/split_options.rb +27 -0
  10. data/lib/csvtool/domain/csv_split_session/split_session.rb +20 -0
  11. data/lib/csvtool/domain/csv_split_session/split_source.rb +17 -0
  12. data/lib/csvtool/domain/csv_stats_session/stats_options.rb +11 -0
  13. data/lib/csvtool/domain/csv_stats_session/stats_session.rb +25 -0
  14. data/lib/csvtool/domain/csv_stats_session/stats_source.rb +17 -0
  15. data/lib/csvtool/infrastructure/csv/csv_splitter.rb +64 -0
  16. data/lib/csvtool/infrastructure/csv/csv_stats_scanner.rb +67 -0
  17. data/lib/csvtool/infrastructure/output/csv_split_manifest_writer.rb +20 -0
  18. data/lib/csvtool/infrastructure/output/csv_stats_file_writer.rb +26 -0
  19. data/lib/csvtool/interface/cli/errors/presenter.rb +8 -0
  20. data/lib/csvtool/interface/cli/menu_loop.rb +8 -2
  21. data/lib/csvtool/interface/cli/prompts/chunk_size_prompt.rb +21 -0
  22. data/lib/csvtool/interface/cli/prompts/split_manifest_prompt.rb +30 -0
  23. data/lib/csvtool/interface/cli/prompts/split_output_prompt.rb +38 -0
  24. data/lib/csvtool/interface/cli/workflows/builders/csv_split_session_builder.rb +44 -0
  25. data/lib/csvtool/interface/cli/workflows/builders/csv_stats_session_builder.rb +28 -0
  26. data/lib/csvtool/interface/cli/workflows/presenters/csv_split_presenter.rb +26 -0
  27. data/lib/csvtool/interface/cli/workflows/presenters/csv_stats_presenter.rb +34 -0
  28. data/lib/csvtool/interface/cli/workflows/run_csv_split_workflow.rb +89 -0
  29. data/lib/csvtool/interface/cli/workflows/run_csv_stats_workflow.rb +77 -0
  30. data/lib/csvtool/interface/cli/workflows/steps/csv_split/build_session_step.rb +30 -0
  31. data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_inputs_step.rb +43 -0
  32. data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step.rb +30 -0
  33. data/lib/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step.rb +31 -0
  34. data/lib/csvtool/interface/cli/workflows/steps/csv_split/execute_step.rb +36 -0
  35. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step.rb +25 -0
  36. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step.rb +27 -0
  37. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step.rb +31 -0
  38. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/execute_step.rb +27 -0
  39. data/lib/csvtool/version.rb +1 -1
  40. data/test/csvtool/application/use_cases/run_csv_split_test.rb +124 -0
  41. data/test/csvtool/application/use_cases/run_csv_stats_test.rb +165 -0
  42. data/test/csvtool/cli_test.rb +139 -29
  43. data/test/csvtool/infrastructure/csv/csv_splitter_test.rb +68 -0
  44. data/test/csvtool/infrastructure/csv/csv_stats_scanner_test.rb +68 -0
  45. data/test/csvtool/infrastructure/output/csv_split_manifest_writer_test.rb +25 -0
  46. data/test/csvtool/infrastructure/output/csv_stats_file_writer_test.rb +38 -0
  47. data/test/csvtool/interface/cli/menu_loop_test.rb +104 -130
  48. data/test/csvtool/interface/cli/prompts/chunk_size_prompt_test.rb +17 -0
  49. data/test/csvtool/interface/cli/prompts/split_manifest_prompt_test.rb +42 -0
  50. data/test/csvtool/interface/cli/prompts/split_output_prompt_test.rb +22 -0
  51. data/test/csvtool/interface/cli/workflows/builders/csv_split_session_builder_test.rb +30 -0
  52. data/test/csvtool/interface/cli/workflows/builders/csv_stats_session_builder_test.rb +19 -0
  53. data/test/csvtool/interface/cli/workflows/presenters/csv_split_presenter_test.rb +26 -0
  54. data/test/csvtool/interface/cli/workflows/presenters/csv_stats_presenter_test.rb +37 -0
  55. data/test/csvtool/interface/cli/workflows/run_csv_split_workflow_test.rb +200 -0
  56. data/test/csvtool/interface/cli/workflows/run_csv_stats_workflow_test.rb +146 -0
  57. data/test/csvtool/interface/cli/workflows/steps/csv_split/build_session_step_test.rb +40 -0
  58. data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_inputs_step_test.rb +64 -0
  59. data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step_test.rb +30 -0
  60. data/test/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step_test.rb +32 -0
  61. data/test/csvtool/interface/cli/workflows/steps/csv_split/execute_step_test.rb +83 -0
  62. data/test/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step_test.rb +36 -0
  63. data/test/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step_test.rb +49 -0
  64. data/test/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step_test.rb +61 -0
  65. data/test/csvtool/interface/cli/workflows/steps/csv_stats/execute_step_test.rb +65 -0
  66. data/test/fixtures/split_people_25.csv +26 -0
  67. metadata +58 -1
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../test_helper"
4
+ require "csvtool/infrastructure/output/csv_stats_file_writer"
5
+ require "tmpdir"
6
+
7
+ class InfrastructureCsvStatsFileWriterTest < Minitest::Test
8
+ def test_writes_stats_as_metric_value_csv
9
+ writer = Csvtool::Infrastructure::Output::CsvStatsFileWriter.new
10
+
11
+ Dir.mktmpdir do |dir|
12
+ path = File.join(dir, "stats.csv")
13
+ writer.call(
14
+ path: path,
15
+ data: {
16
+ row_count: 3,
17
+ column_count: 2,
18
+ headers: ["name", "city"],
19
+ column_stats: [
20
+ { name: "name", non_blank_count: 3, blank_count: 0 },
21
+ { name: "city", non_blank_count: 2, blank_count: 1 }
22
+ ]
23
+ }
24
+ )
25
+
26
+ assert_equal [
27
+ "metric,value",
28
+ "row_count,3",
29
+ "column_count,2",
30
+ "headers,name|city",
31
+ "column.name.non_blank,3",
32
+ "column.name.blank,0",
33
+ "column.city.non_blank,2",
34
+ "column.city.blank,1"
35
+ ], File.read(path).lines.map(&:strip)
36
+ end
37
+ end
38
+ end
@@ -17,171 +17,145 @@ class MenuLoopTest < Minitest::Test
17
17
  end
18
18
 
19
19
  def test_routes_extract_column_then_exit
20
- column_action = FakeAction.new
21
- rows_action = FakeAction.new
22
- randomize_rows_action = FakeAction.new
23
- dedupe_action = FakeAction.new
24
- parity_action = FakeAction.new
25
- stdout = StringIO.new
26
- menu = Csvtool::Interface::CLI::MenuLoop.new(
27
- stdin: StringIO.new("1\n6\n"),
28
- stdout: stdout,
29
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
30
- extract_column_action: column_action,
31
- extract_rows_action: rows_action,
32
- randomize_rows_action: randomize_rows_action,
33
- dedupe_action: dedupe_action,
34
- parity_action: parity_action
35
- )
36
-
20
+ menu, actions, = build_menu("1\n8\n")
37
21
  status = menu.run
38
22
 
39
23
  assert_equal 0, status
40
- assert_equal 1, column_action.runs
41
- assert_equal 0, rows_action.runs
42
- assert_equal 0, randomize_rows_action.runs
43
- assert_equal 0, dedupe_action.runs
44
- assert_equal 0, parity_action.runs
45
- assert_includes stdout.string, "CSV Tool Menu"
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
30
+ assert_equal 0, actions[:stats].runs
46
31
  end
47
32
 
48
33
  def test_routes_extract_rows_then_exit
49
- column_action = FakeAction.new
50
- rows_action = FakeAction.new
51
- randomize_rows_action = FakeAction.new
52
- dedupe_action = FakeAction.new
53
- parity_action = FakeAction.new
54
- stdout = StringIO.new
55
- menu = Csvtool::Interface::CLI::MenuLoop.new(
56
- stdin: StringIO.new("2\n6\n"),
57
- stdout: stdout,
58
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
59
- extract_column_action: column_action,
60
- extract_rows_action: rows_action,
61
- randomize_rows_action: randomize_rows_action,
62
- dedupe_action: dedupe_action,
63
- parity_action: parity_action
64
- )
65
-
34
+ menu, actions, = build_menu("2\n8\n")
66
35
  status = menu.run
67
36
 
68
37
  assert_equal 0, status
69
- assert_equal 0, column_action.runs
70
- assert_equal 1, rows_action.runs
71
- assert_equal 0, randomize_rows_action.runs
72
- assert_equal 0, dedupe_action.runs
73
- assert_equal 0, parity_action.runs
38
+ assert_equal 0, actions[:column].runs
39
+ assert_equal 1, actions[:rows].runs
40
+ assert_equal 0, actions[:randomize].runs
41
+ assert_equal 0, actions[:dedupe].runs
42
+ assert_equal 0, actions[:parity].runs
43
+ assert_equal 0, actions[:split].runs
44
+ assert_equal 0, actions[:stats].runs
74
45
  end
75
46
 
76
47
  def test_routes_randomize_rows_then_exit
77
- column_action = FakeAction.new
78
- rows_action = FakeAction.new
79
- randomize_rows_action = FakeAction.new
80
- dedupe_action = FakeAction.new
81
- parity_action = FakeAction.new
82
- stdout = StringIO.new
83
- menu = Csvtool::Interface::CLI::MenuLoop.new(
84
- stdin: StringIO.new("3\n6\n"),
85
- stdout: stdout,
86
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
87
- extract_column_action: column_action,
88
- extract_rows_action: rows_action,
89
- randomize_rows_action: randomize_rows_action,
90
- dedupe_action: dedupe_action,
91
- parity_action: parity_action
92
- )
93
-
48
+ menu, actions, = build_menu("3\n8\n")
94
49
  status = menu.run
95
50
 
96
51
  assert_equal 0, status
97
- assert_equal 0, column_action.runs
98
- assert_equal 0, rows_action.runs
99
- assert_equal 1, randomize_rows_action.runs
100
- assert_equal 0, dedupe_action.runs
101
- assert_equal 0, parity_action.runs
52
+ assert_equal 0, actions[:column].runs
53
+ assert_equal 0, actions[:rows].runs
54
+ assert_equal 1, actions[:randomize].runs
55
+ assert_equal 0, actions[:dedupe].runs
56
+ assert_equal 0, actions[:parity].runs
57
+ assert_equal 0, actions[:split].runs
58
+ assert_equal 0, actions[:stats].runs
102
59
  end
103
60
 
104
61
  def test_routes_dedupe_then_exit
105
- column_action = FakeAction.new
106
- rows_action = FakeAction.new
107
- randomize_rows_action = FakeAction.new
108
- dedupe_action = FakeAction.new
109
- parity_action = FakeAction.new
110
- stdout = StringIO.new
111
- menu = Csvtool::Interface::CLI::MenuLoop.new(
112
- stdin: StringIO.new("4\n6\n"),
113
- stdout: stdout,
114
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
115
- extract_column_action: column_action,
116
- extract_rows_action: rows_action,
117
- randomize_rows_action: randomize_rows_action,
118
- dedupe_action: dedupe_action,
119
- parity_action: parity_action
120
- )
121
-
62
+ menu, actions, = build_menu("4\n8\n")
122
63
  status = menu.run
123
64
 
124
65
  assert_equal 0, status
125
- assert_equal 0, column_action.runs
126
- assert_equal 0, rows_action.runs
127
- assert_equal 0, randomize_rows_action.runs
128
- assert_equal 1, dedupe_action.runs
129
- assert_equal 0, parity_action.runs
66
+ assert_equal 0, actions[:column].runs
67
+ assert_equal 0, actions[:rows].runs
68
+ assert_equal 0, actions[:randomize].runs
69
+ assert_equal 1, actions[:dedupe].runs
70
+ assert_equal 0, actions[:parity].runs
71
+ assert_equal 0, actions[:split].runs
72
+ assert_equal 0, actions[:stats].runs
130
73
  end
131
74
 
132
75
  def test_routes_parity_then_exit
133
- column_action = FakeAction.new
134
- rows_action = FakeAction.new
135
- randomize_rows_action = FakeAction.new
136
- dedupe_action = FakeAction.new
137
- parity_action = FakeAction.new
138
- stdout = StringIO.new
139
- menu = Csvtool::Interface::CLI::MenuLoop.new(
140
- stdin: StringIO.new("5\n6\n"),
141
- stdout: stdout,
142
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
143
- extract_column_action: column_action,
144
- extract_rows_action: rows_action,
145
- randomize_rows_action: randomize_rows_action,
146
- dedupe_action: dedupe_action,
147
- parity_action: parity_action
148
- )
76
+ menu, actions, = build_menu("5\n8\n")
77
+ status = menu.run
149
78
 
79
+ assert_equal 0, status
80
+ assert_equal 0, actions[:column].runs
81
+ assert_equal 0, actions[:rows].runs
82
+ assert_equal 0, actions[:randomize].runs
83
+ assert_equal 0, actions[:dedupe].runs
84
+ assert_equal 1, actions[:parity].runs
85
+ assert_equal 0, actions[:split].runs
86
+ assert_equal 0, actions[:stats].runs
87
+ end
88
+
89
+ def test_routes_split_then_exit
90
+ menu, actions, stdout = build_menu("6\n8\n")
150
91
  status = menu.run
151
92
 
152
93
  assert_equal 0, status
153
- assert_equal 0, column_action.runs
154
- assert_equal 0, rows_action.runs
155
- assert_equal 0, randomize_rows_action.runs
156
- assert_equal 0, dedupe_action.runs
157
- assert_equal 1, parity_action.runs
94
+ assert_equal 0, actions[:column].runs
95
+ assert_equal 0, actions[:rows].runs
96
+ assert_equal 0, actions[:randomize].runs
97
+ assert_equal 0, actions[:dedupe].runs
98
+ assert_equal 0, actions[:parity].runs
99
+ assert_equal 1, actions[:split].runs
100
+ assert_equal 0, actions[:stats].runs
101
+ assert_includes stdout.string, "CSV Tool Menu"
102
+ end
103
+
104
+ def test_routes_stats_then_exit
105
+ menu, actions, = build_menu("7\n8\n")
106
+ status = menu.run
107
+
108
+ assert_equal 0, status
109
+ assert_equal 0, actions[:column].runs
110
+ assert_equal 0, actions[:rows].runs
111
+ assert_equal 0, actions[:randomize].runs
112
+ assert_equal 0, actions[:dedupe].runs
113
+ assert_equal 0, actions[:parity].runs
114
+ assert_equal 0, actions[:split].runs
115
+ assert_equal 1, actions[:stats].runs
158
116
  end
159
117
 
160
118
  def test_invalid_choice_shows_prompt
161
- column_action = FakeAction.new
162
- rows_action = FakeAction.new
163
- randomize_rows_action = FakeAction.new
164
- dedupe_action = FakeAction.new
165
- parity_action = FakeAction.new
119
+ menu, actions, stdout = build_menu("x\n8\n")
120
+ menu.run
121
+
122
+ assert_includes stdout.string, "Please choose 1, 2, 3, 4, 5, 6, 7, or 8."
123
+ assert_equal 0, actions[:column].runs
124
+ assert_equal 0, actions[:rows].runs
125
+ assert_equal 0, actions[:randomize].runs
126
+ assert_equal 0, actions[:dedupe].runs
127
+ assert_equal 0, actions[:parity].runs
128
+ assert_equal 0, actions[:split].runs
129
+ assert_equal 0, actions[:stats].runs
130
+ end
131
+
132
+ private
133
+
134
+ def build_menu(input)
135
+ actions = {
136
+ column: FakeAction.new,
137
+ rows: FakeAction.new,
138
+ randomize: FakeAction.new,
139
+ dedupe: FakeAction.new,
140
+ parity: FakeAction.new,
141
+ split: FakeAction.new,
142
+ stats: FakeAction.new
143
+ }
166
144
  stdout = StringIO.new
145
+
167
146
  menu = Csvtool::Interface::CLI::MenuLoop.new(
168
- stdin: StringIO.new("x\n6\n"),
147
+ stdin: StringIO.new(input),
169
148
  stdout: stdout,
170
- menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Exit"],
171
- extract_column_action: column_action,
172
- extract_rows_action: rows_action,
173
- randomize_rows_action: randomize_rows_action,
174
- dedupe_action: dedupe_action,
175
- parity_action: parity_action
149
+ menu_options: ["Extract column", "Extract rows (range)", "Randomize rows", "Dedupe using another CSV", "Validate parity", "Split CSV into chunks", "CSV stats summary", "Exit"],
150
+ extract_column_action: actions[:column],
151
+ extract_rows_action: actions[:rows],
152
+ randomize_rows_action: actions[:randomize],
153
+ dedupe_action: actions[:dedupe],
154
+ parity_action: actions[:parity],
155
+ split_action: actions[:split],
156
+ stats_action: actions[:stats]
176
157
  )
177
158
 
178
- menu.run
179
-
180
- assert_includes stdout.string, "Please choose 1, 2, 3, 4, 5, or 6."
181
- assert_equal 0, column_action.runs
182
- assert_equal 0, rows_action.runs
183
- assert_equal 0, randomize_rows_action.runs
184
- assert_equal 0, dedupe_action.runs
185
- assert_equal 0, parity_action.runs
159
+ [menu, actions, stdout]
186
160
  end
187
161
  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,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,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/builders/csv_stats_session_builder"
5
+ require "csvtool/domain/shared/output_destination"
6
+
7
+ class CsvStatsSessionBuilderTest < Minitest::Test
8
+ def test_builds_stats_session
9
+ builder = Csvtool::Interface::CLI::Workflows::Builders::CsvStatsSessionBuilder.new
10
+ destination = Csvtool::Domain::Shared::OutputDestination.console
11
+
12
+ session = builder.call(file_path: "/tmp/data.csv", col_sep: ";", headers_present: false, destination: destination)
13
+
14
+ assert_equal "/tmp/data.csv", session.source.path
15
+ assert_equal ";", session.source.separator
16
+ assert_equal false, session.source.headers_present
17
+ assert_equal true, session.output_destination.console?
18
+ end
19
+ 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,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/presenters/csv_stats_presenter"
5
+
6
+ class CsvStatsPresenterTest < Minitest::Test
7
+ def test_prints_summary_with_headers_and_column_stats
8
+ out = StringIO.new
9
+ presenter = Csvtool::Interface::CLI::Workflows::Presenters::CsvStatsPresenter.new(stdout: out)
10
+
11
+ presenter.print_summary(
12
+ row_count: 3,
13
+ column_count: 2,
14
+ headers: ["name", "city"],
15
+ column_stats: [
16
+ { name: "name", non_blank_count: 3, blank_count: 0 },
17
+ { name: "city", non_blank_count: 2, blank_count: 1 }
18
+ ]
19
+ )
20
+
21
+ assert_includes out.string, "CSV Stats Summary"
22
+ assert_includes out.string, "Rows: 3"
23
+ assert_includes out.string, "Columns: 2"
24
+ assert_includes out.string, "Headers: name, city"
25
+ assert_includes out.string, "name: non_blank=3 blank=0"
26
+ assert_includes out.string, "city: non_blank=2 blank=1"
27
+ end
28
+
29
+ def test_prints_file_written_message
30
+ out = StringIO.new
31
+ presenter = Csvtool::Interface::CLI::Workflows::Presenters::CsvStatsPresenter.new(stdout: out)
32
+
33
+ presenter.print_file_written("/tmp/stats.csv")
34
+
35
+ assert_includes out.string, "Wrote output to /tmp/stats.csv"
36
+ end
37
+ end