1#!/usr/bin/env ruby -w
2# encoding: UTF-8
3
4# tc_data_converters.rb
5#
6#  Created by James Edward Gray II on 2005-10-31.
7#  Copyright 2005 James Edward Gray II. You can redistribute or modify this code
8#  under the terms of Ruby's license.
9
10require_relative "base"
11
12class TestCSV::DataConverters < TestCSV
13  extend DifferentOFS
14
15  def setup
16    super
17    @data   = "Numbers,:integer,1,:float,3.015"
18    @parser = CSV.new(@data)
19
20    @custom = lambda { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
21
22    @win_safe_time_str = Time.now.strftime("%a %b %d %H:%M:%S %Y")
23  end
24
25  def test_builtin_integer_converter
26    # does convert
27    [-5, 1, 10000000000].each do |n|
28      assert_equal(n, CSV::Converters[:integer][n.to_s])
29    end
30
31    # does not convert
32    (%w{junk 1.0} + [""]).each do |str|
33      assert_equal(str, CSV::Converters[:integer][str])
34    end
35  end
36
37  def test_builtin_float_converter
38    # does convert
39    [-5.1234, 0, 2.3e-11].each do |n|
40      assert_equal(n, CSV::Converters[:float][n.to_s])
41    end
42
43    # does not convert
44    (%w{junk 1..0 .015F} + [""]).each do |str|
45      assert_equal(str, CSV::Converters[:float][str])
46    end
47  end
48
49  def test_builtin_date_converter
50    # does convert
51    assert_instance_of(
52      Date,
53      CSV::Converters[:date][@win_safe_time_str.sub(/\d+:\d+:\d+ /, "")]
54    )
55
56    # does not convert
57    assert_instance_of(String, CSV::Converters[:date]["junk"])
58  end
59
60  def test_builtin_date_time_converter
61    # does convert
62    assert_instance_of( DateTime,
63                        CSV::Converters[:date_time][@win_safe_time_str] )
64
65    # does not convert
66    assert_instance_of(String, CSV::Converters[:date_time]["junk"])
67  end
68
69  def test_convert_with_builtin_integer
70    # setup parser...
71    assert(@parser.respond_to?(:convert))
72    assert_nothing_raised(Exception) { @parser.convert(:integer) }
73
74    # and use
75    assert_equal(["Numbers", ":integer", 1, ":float", "3.015"], @parser.shift)
76  end
77
78  def test_convert_with_builtin_float
79    # setup parser...
80    assert(@parser.respond_to?(:convert))
81    assert_nothing_raised(Exception) { @parser.convert(:float) }
82
83    # and use
84    assert_equal(["Numbers", ":integer", 1.0, ":float", 3.015], @parser.shift)
85  end
86
87  def test_convert_order_float_integer
88    # floats first, then integers...
89    assert_nothing_raised(Exception) do
90      @parser.convert(:float)
91      @parser.convert(:integer)
92    end
93
94    # gets us nothing but floats
95    assert_equal( [String, String, Float, String, Float],
96                  @parser.shift.map { |field| field.class } )
97  end
98
99  def test_convert_order_integer_float
100    # integers have precendance...
101    assert_nothing_raised(Exception) do
102      @parser.convert(:integer)
103      @parser.convert(:float)
104    end
105
106    # gives us proper number conversion
107    assert_equal( [String, String, Fixnum, String, Float],
108                  @parser.shift.map { |field| field.class } )
109  end
110
111  def test_builtin_numeric_combo_converter
112    # setup parser...
113    assert_nothing_raised(Exception) { @parser.convert(:numeric) }
114
115    # and use
116    assert_equal( [String, String, Fixnum, String, Float],
117                  @parser.shift.map { |field| field.class } )
118  end
119
120  def test_builtin_all_nested_combo_converter
121    # setup parser...
122    @data   << ",#{@win_safe_time_str}"        # add a DateTime field
123    @parser =  CSV.new(@data)                  # reset parser
124    assert_nothing_raised(Exception) { @parser.convert(:all) }
125
126    # and use
127    assert_equal( [String, String, Fixnum, String, Float, DateTime],
128                  @parser.shift.map { |field| field.class } )
129  end
130
131  def test_convert_with_custom_code
132    # define custom converter...
133    assert_nothing_raised(Exception) do
134      @parser.convert { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
135    end
136
137    # and use
138    assert_equal(["Numbers", :integer, "1", :float, "3.015"], @parser.shift)
139  end
140
141  def test_convert_with_custom_code_mix
142    # mix built-in and custom...
143    assert_nothing_raised(Exception) { @parser.convert(:numeric) }
144    assert_nothing_raised(Exception) { @parser.convert(&@custom) }
145
146    # and use
147    assert_equal(["Numbers", :integer, 1, :float, 3.015], @parser.shift)
148  end
149
150  def test_convert_with_custom_code_using_field_info
151    # define custom converter that uses field information...
152    assert_nothing_raised(Exception) do
153      @parser.convert do |field, info|
154        assert_equal(1, info.line)
155        info.index == 4 ? Float(field).floor : field
156      end
157    end
158
159    # and use
160    assert_equal(["Numbers", ":integer", "1", ":float", 3], @parser.shift)
161  end
162
163  def test_convert_with_custom_code_using_field_info_header
164    @parser = CSV.new(@data, headers: %w{one two three four five})
165
166    # define custom converter that uses field header information...
167    assert_nothing_raised(Exception) do
168      @parser.convert do |field, info|
169        info.header == "three" ? Integer(field) * 100 : field
170      end
171    end
172
173    # and use
174    assert_equal( ["Numbers", ":integer", 100, ":float", "3.015"],
175                  @parser.shift.fields )
176  end
177
178  def test_shortcut_interface
179    assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
180                  CSV.parse_line(@data, converters: :numeric) )
181
182    assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
183                  CSV.parse_line(@data, converters: [:integer, :float]) )
184
185    assert_equal( ["Numbers", :integer, 1, :float, 3.015],
186                  CSV.parse_line(@data, converters: [:numeric, @custom]) )
187  end
188
189  def test_unconverted_fields
190    [ [ @data,
191        ["Numbers", :integer, 1, :float, 3.015],
192        %w{Numbers :integer 1 :float 3.015} ],
193      ["\n", Array.new, Array.new] ].each do |test, fields, unconverted|
194      row = nil
195      assert_nothing_raised(Exception) do
196        row = CSV.parse_line( test,
197                              converters:         [:numeric, @custom],
198                              unconverted_fields: true )
199      end
200      assert_not_nil(row)
201      assert_equal(fields, row)
202      assert_respond_to(row, :unconverted_fields)
203      assert_equal(unconverted, row.unconverted_fields)
204    end
205
206    data = <<-END_CSV.gsub(/^\s+/, "")
207    first,second,third
208    1,2,3
209    END_CSV
210    row = nil
211    assert_nothing_raised(Exception) do
212      row = CSV.parse_line( data,
213                            converters:         :numeric,
214                            unconverted_fields: true,
215                            headers:            :first_row )
216    end
217    assert_not_nil(row)
218    assert_equal([["first", 1], ["second", 2], ["third", 3]], row.to_a)
219    assert_respond_to(row, :unconverted_fields)
220    assert_equal(%w{1 2 3}, row.unconverted_fields)
221
222    assert_nothing_raised(Exception) do
223      row = CSV.parse_line( data,
224                            converters:         :numeric,
225                            unconverted_fields: true,
226                            headers:            :first_row,
227                            return_headers:     true )
228    end
229    assert_not_nil(row)
230    assert_equal( [%w{first first}, %w{second second}, %w{third third}],
231                  row.to_a )
232    assert_respond_to(row, :unconverted_fields)
233    assert_equal(%w{first second third}, row.unconverted_fields)
234
235    assert_nothing_raised(Exception) do
236      row = CSV.parse_line( data,
237                            converters:         :numeric,
238                            unconverted_fields: true,
239                            headers:            :first_row,
240                            return_headers:     true,
241                            header_converters:  :symbol )
242    end
243    assert_not_nil(row)
244    assert_equal( [[:first, "first"], [:second, "second"], [:third, "third"]],
245                  row.to_a )
246    assert_respond_to(row, :unconverted_fields)
247    assert_equal(%w{first second third}, row.unconverted_fields)
248
249    assert_nothing_raised(Exception) do
250      row = CSV.parse_line( data,
251                            converters:         :numeric,
252                            unconverted_fields: true,
253                            headers:            %w{my new headers},
254                            return_headers:     true,
255                            header_converters:  :symbol )
256    end
257    assert_not_nil(row)
258    assert_equal( [[:my, "my"], [:new, "new"], [:headers, "headers"]],
259                  row.to_a )
260    assert_respond_to(row, :unconverted_fields)
261    assert_equal(Array.new, row.unconverted_fields)
262  end
263end
264