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.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +69 -149
  3. data/docs/architecture.md +396 -0
  4. data/docs/release-v0.4.0-alpha.md +87 -0
  5. data/docs/release-v0.5.0-alpha.md +89 -0
  6. data/lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb +96 -0
  7. data/lib/csvtool/application/use_cases/run_extraction.rb +63 -88
  8. data/lib/csvtool/application/use_cases/run_row_extraction.rb +45 -73
  9. data/lib/csvtool/application/use_cases/run_row_randomization.rb +56 -73
  10. data/lib/csvtool/cli.rb +11 -7
  11. data/lib/csvtool/domain/cross_csv_dedupe_session/column_selector.rb +44 -0
  12. data/lib/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session.rb +46 -0
  13. data/lib/csvtool/domain/cross_csv_dedupe_session/csv_profile.rb +24 -0
  14. data/lib/csvtool/domain/cross_csv_dedupe_session/key_mapping.rb +22 -0
  15. data/lib/csvtool/domain/cross_csv_dedupe_session/match_options.rb +29 -0
  16. data/lib/csvtool/domain/row_randomization_session/randomization_source.rb +1 -0
  17. data/lib/csvtool/domain/row_session/row_source.rb +3 -0
  18. data/lib/csvtool/domain/{column_session → shared}/output_destination.rb +1 -1
  19. data/lib/csvtool/infrastructure/csv/cross_csv_deduper.rb +85 -0
  20. data/lib/csvtool/infrastructure/csv/selector_validator.rb +30 -0
  21. data/lib/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer.rb +23 -0
  22. data/lib/csvtool/infrastructure/output/csv_file_writer.rb +1 -7
  23. data/lib/csvtool/infrastructure/output/csv_randomized_row_file_writer.rb +23 -0
  24. data/lib/csvtool/infrastructure/output/csv_row_file_writer.rb +2 -9
  25. data/lib/csvtool/interface/cli/menu_loop.rb +5 -2
  26. data/lib/csvtool/interface/cli/prompts/dedupe_key_selector_prompt.rb +30 -0
  27. data/lib/csvtool/interface/cli/prompts/file_path_prompt.rb +4 -2
  28. data/lib/csvtool/interface/cli/prompts/headers_present_prompt.rb +4 -2
  29. data/lib/csvtool/interface/cli/prompts/separator_prompt.rb +4 -2
  30. data/lib/csvtool/interface/cli/prompts/yes_no_prompt.rb +26 -0
  31. data/lib/csvtool/interface/cli/workflows/builders/column_session_builder.rb +32 -0
  32. data/lib/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder.rb +35 -0
  33. data/lib/csvtool/interface/cli/workflows/builders/row_extraction_session_builder.rb +22 -0
  34. data/lib/csvtool/interface/cli/workflows/builders/row_randomization_session_builder.rb +28 -0
  35. data/lib/csvtool/interface/cli/workflows/presenters/column_extraction_presenter.rb +25 -0
  36. data/lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb +39 -0
  37. data/lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb +34 -0
  38. data/lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb +34 -0
  39. data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +86 -0
  40. data/lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb +88 -0
  41. data/lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb +86 -0
  42. data/lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb +80 -0
  43. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step.rb +55 -0
  44. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_profiles_step.rb +52 -0
  45. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/execute_step.rb +34 -0
  46. data/lib/csvtool/interface/cli/workflows/steps/extraction/build_preview_step.rb +40 -0
  47. data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_destination_step.rb +28 -0
  48. data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step.rb +47 -0
  49. data/lib/csvtool/interface/cli/workflows/steps/extraction/execute_step.rb +32 -0
  50. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_destination_step.rb +33 -0
  51. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_range_step.rb +35 -0
  52. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step.rb +32 -0
  53. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/execute_step.rb +43 -0
  54. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step.rb +29 -0
  55. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_destination_step.rb +34 -0
  56. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step.rb +49 -0
  57. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/execute_step.rb +37 -0
  58. data/lib/csvtool/interface/cli/workflows/steps/workflow_step_pipeline.rb +25 -0
  59. data/lib/csvtool/interface/cli/workflows/support/output_destination_mapper.rb +23 -0
  60. data/lib/csvtool/interface/cli/workflows/support/result_error_handler.rb +22 -0
  61. data/lib/csvtool/version.rb +1 -1
  62. data/test/csvtool/application/use_cases/io_boundary_test.rb +26 -0
  63. data/test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb +141 -0
  64. data/test/csvtool/application/use_cases/run_extraction_test.rb +72 -16
  65. data/test/csvtool/application/use_cases/run_row_extraction_test.rb +82 -102
  66. data/test/csvtool/application/use_cases/run_row_randomization_test.rb +96 -86
  67. data/test/csvtool/cli_test.rb +130 -16
  68. data/test/csvtool/cli_unit_test.rb +16 -3
  69. data/test/csvtool/domain/column_session/column_session_test.rb +2 -2
  70. data/test/csvtool/domain/column_session/csv_source_test.rb +10 -0
  71. data/test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb +42 -0
  72. data/test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb +75 -0
  73. data/test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb +26 -0
  74. data/test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb +31 -0
  75. data/test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb +52 -0
  76. data/test/csvtool/domain/row_randomization_session/randomization_session_test.rb +2 -2
  77. data/test/csvtool/domain/row_randomization_session/randomization_source_test.rb +15 -1
  78. data/test/csvtool/domain/row_session/row_session_test.rb +2 -2
  79. data/test/csvtool/domain/row_session/row_source_test.rb +16 -0
  80. data/test/csvtool/domain/shared/output_destination_test.rb +24 -0
  81. data/test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb +155 -0
  82. data/test/csvtool/infrastructure/csv/selector_validator_test.rb +72 -0
  83. data/test/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer_test.rb +32 -0
  84. data/test/csvtool/infrastructure/output/csv_file_writer_test.rb +0 -4
  85. data/test/csvtool/infrastructure/output/csv_randomized_row_file_writer_test.rb +32 -0
  86. data/test/csvtool/infrastructure/output/csv_row_file_writer_test.rb +1 -4
  87. data/test/csvtool/interface/cli/menu_loop_test.rb +50 -13
  88. data/test/csvtool/interface/cli/prompts/dedupe_key_selector_prompt_test.rb +30 -0
  89. data/test/csvtool/interface/cli/prompts/file_path_prompt_test.rb +9 -0
  90. data/test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb +10 -0
  91. data/test/csvtool/interface/cli/prompts/separator_prompt_test.rb +10 -0
  92. data/test/csvtool/interface/cli/prompts/yes_no_prompt_test.rb +22 -0
  93. data/test/csvtool/interface/cli/workflows/builders/column_session_builder_test.rb +17 -0
  94. data/test/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder_test.rb +36 -0
  95. data/test/csvtool/interface/cli/workflows/builders/row_extraction_session_builder_test.rb +21 -0
  96. data/test/csvtool/interface/cli/workflows/builders/row_randomization_session_builder_test.rb +26 -0
  97. data/test/csvtool/interface/cli/workflows/presenters/column_extraction_presenter_test.rb +24 -0
  98. data/test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb +30 -0
  99. data/test/csvtool/interface/cli/workflows/presenters/row_extraction_presenter_test.rb +33 -0
  100. data/test/csvtool/interface/cli/workflows/presenters/row_randomization_presenter_test.rb +33 -0
  101. data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +246 -0
  102. data/test/csvtool/interface/cli/workflows/run_extraction_workflow_test.rb +56 -0
  103. data/test/csvtool/interface/cli/workflows/run_row_extraction_workflow_test.rb +83 -0
  104. data/test/csvtool/interface/cli/workflows/run_row_randomization_workflow_test.rb +69 -0
  105. data/test/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step_test.rb +41 -0
  106. data/test/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step_test.rb +66 -0
  107. data/test/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step_test.rb +39 -0
  108. data/test/csvtool/interface/cli/workflows/steps/row_extraction/execute_step_test.rb +91 -0
  109. data/test/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step_test.rb +57 -0
  110. data/test/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step_test.rb +37 -0
  111. data/test/csvtool/interface/cli/workflows/steps/workflow_step_pipeline_test.rb +30 -0
  112. data/test/csvtool/interface/cli/workflows/support/output_destination_mapper_test.rb +23 -0
  113. data/test/csvtool/interface/cli/workflows/support/result_error_handler_test.rb +34 -0
  114. data/test/fixtures/dedupe_reference.csv +3 -0
  115. data/test/fixtures/dedupe_reference.tsv +3 -0
  116. data/test/fixtures/dedupe_reference_all.csv +5 -0
  117. data/test/fixtures/dedupe_reference_no_headers.csv +2 -0
  118. data/test/fixtures/dedupe_reference_none.csv +2 -0
  119. data/test/fixtures/dedupe_reference_normalization.csv +3 -0
  120. data/test/fixtures/dedupe_source.csv +6 -0
  121. data/test/fixtures/dedupe_source.tsv +6 -0
  122. data/test/fixtures/dedupe_source_no_headers.csv +5 -0
  123. data/test/fixtures/dedupe_source_normalization.csv +4 -0
  124. metadata +93 -8
  125. data/lib/csvtool/domain/row_randomization_session/randomization_output_destination.rb +0 -31
  126. data/lib/csvtool/domain/row_session/row_output_destination.rb +0 -31
  127. data/test/csvtool/domain/column_session/output_destination_test.rb +0 -18
  128. data/test/csvtool/domain/row_randomization_session/randomization_output_destination_test.rb +0 -21
  129. 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\n4\n"),
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\n4\n"),
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\n4\n"),
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\n4\n"),
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 4."
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