autocompl 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/lib/autocompl/repository.rb +11 -1
  3. data/lib/autocompl/version.rb +1 -1
  4. data/test/dummy/log/development.log +467 -0
  5. data/test/dummy/log/test.log +3 -0
  6. data/test/dummy/vendor/bundle/ruby/2.3.0/bin/console +23 -0
  7. data/test/dummy/vendor/bundle/ruby/2.3.0/cache/pg-0.19.0.gem +0 -0
  8. data/test/dummy/vendor/bundle/ruby/2.3.0/cache/pq-0.0.1.gem +0 -0
  9. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/gem.build_complete +0 -0
  10. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/gem_make.out +78 -0
  11. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/mkmf.log +1346 -0
  12. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/pg_ext.bundle +0 -0
  13. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/BSDL +22 -0
  14. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ChangeLog +6378 -0
  15. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Contributors.rdoc +46 -0
  16. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/History.rdoc +363 -0
  17. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/LICENSE +56 -0
  18. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Manifest.txt +85 -0
  19. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/POSTGRES +23 -0
  20. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README-OS_X.rdoc +68 -0
  21. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README-Windows.rdoc +56 -0
  22. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README.ja.rdoc +14 -0
  23. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README.rdoc +168 -0
  24. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Rakefile +216 -0
  25. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Rakefile.cross +301 -0
  26. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/Makefile +261 -0
  27. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.def +947 -0
  28. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.rb +45 -0
  29. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.txt +467 -0
  30. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/extconf.h +38 -0
  31. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/extconf.rb +112 -0
  32. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.c +13 -0
  33. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.h +257 -0
  34. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.o +0 -0
  35. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.c +667 -0
  36. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.h +395 -0
  37. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.o +0 -0
  38. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_decoder.c +162 -0
  39. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_decoder.o +0 -0
  40. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_encoder.c +162 -0
  41. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_encoder.o +0 -0
  42. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_coder.c +500 -0
  43. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_coder.o +0 -0
  44. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_connection.c +4102 -0
  45. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_connection.o +0 -0
  46. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_copy_coder.c +591 -0
  47. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_copy_coder.o +0 -0
  48. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_errors.c +95 -0
  49. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_errors.o +0 -0
  50. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_ext.bundle +0 -0
  51. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_result.c +1271 -0
  52. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_result.o +0 -0
  53. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_decoder.c +421 -0
  54. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_decoder.o +0 -0
  55. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_encoder.c +683 -0
  56. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_encoder.o +0 -0
  57. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map.c +159 -0
  58. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map.o +0 -0
  59. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_all_strings.c +116 -0
  60. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_all_strings.o +0 -0
  61. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_class.c +239 -0
  62. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_class.o +0 -0
  63. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_column.c +312 -0
  64. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_column.o +0 -0
  65. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_mri_type.c +284 -0
  66. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_mri_type.o +0 -0
  67. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_oid.c +355 -0
  68. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_oid.o +0 -0
  69. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_in_ruby.c +299 -0
  70. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_in_ruby.o +0 -0
  71. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.c +149 -0
  72. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.h +65 -0
  73. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.o +0 -0
  74. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg.sln +26 -0
  75. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg_18/pg.vcproj +216 -0
  76. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg_19/pg_19.vcproj +209 -0
  77. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg.rb +64 -0
  78. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/basic_type_mapping.rb +426 -0
  79. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/coder.rb +83 -0
  80. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/connection.rb +271 -0
  81. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/constants.rb +11 -0
  82. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/exceptions.rb +11 -0
  83. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/result.rb +30 -0
  84. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/text_decoder.rb +51 -0
  85. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/text_encoder.rb +35 -0
  86. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/type_map_by_column.rb +15 -0
  87. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg_ext.bundle +0 -0
  88. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/array_insert.rb +20 -0
  89. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_api.rb +106 -0
  90. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_copyto.rb +39 -0
  91. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_mixed.rb +56 -0
  92. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/check_conn.rb +21 -0
  93. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/copyfrom.rb +81 -0
  94. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/copyto.rb +19 -0
  95. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/cursor.rb +21 -0
  96. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/disk_usage_report.rb +186 -0
  97. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/issue-119.rb +94 -0
  98. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/losample.rb +69 -0
  99. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/minimal-testcase.rb +17 -0
  100. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/notify_wait.rb +72 -0
  101. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/pg_statistics.rb +294 -0
  102. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/replication_monitor.rb +231 -0
  103. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/test_binary_values.rb +33 -0
  104. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/wal_shipper.rb +434 -0
  105. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/warehouse_partitions.rb +320 -0
  106. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/data/expected_trace.out +26 -0
  107. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/data/random_binary_data +0 -0
  108. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/helpers.rb +352 -0
  109. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/basic_type_mapping_spec.rb +305 -0
  110. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/connection_spec.rb +1676 -0
  111. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/result_spec.rb +449 -0
  112. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_class_spec.rb +138 -0
  113. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_column_spec.rb +222 -0
  114. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  115. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_oid_spec.rb +149 -0
  116. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_in_ruby_spec.rb +164 -0
  117. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_spec.rb +22 -0
  118. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_spec.rb +777 -0
  119. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg_spec.rb +50 -0
  120. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/Gemfile +4 -0
  121. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/LICENSE.txt +22 -0
  122. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/README.md +76 -0
  123. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/Rakefile +1 -0
  124. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/bin/console +7 -0
  125. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/lib/pq.rb +99 -0
  126. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/pq.gemspec +29 -0
  127. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/spec/helpers.rb +10 -0
  128. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/spec/queue_spec.rb +84 -0
  129. data/test/dummy/vendor/bundle/ruby/2.3.0/specifications/pg-0.19.0.gemspec +63 -0
  130. data/test/dummy/vendor/bundle/ruby/2.3.0/specifications/pq-0.0.1.gemspec +49 -0
  131. metadata +253 -1
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env rspec
2
+ # encoding: utf-8
3
+
4
+ require_relative '../helpers'
5
+
6
+ require 'pg'
7
+
8
+
9
+ describe PG::TypeMapInRuby do
10
+
11
+ context "result values" do
12
+ it "should be usable non-derived" do
13
+ tm = PG::TypeMapInRuby.new
14
+ res = @conn.exec("select 5").map_types!(tm)
15
+ expect( res.getvalue(0,0) ).to eq( "5" )
16
+ end
17
+
18
+ it "should call derived result mapping methods" do
19
+ tm = Class.new(PG::TypeMapInRuby) do
20
+ attr_reader :fit_to_result_args
21
+
22
+ def fit_to_result(*args)
23
+ @fit_to_result_args = args
24
+ self
25
+ end
26
+
27
+ def typecast_result_value(*args)
28
+ [args, super]
29
+ end
30
+ end.new
31
+
32
+ res = @conn.exec("select 5,6").map_types!(tm)
33
+ expect( res.getvalue(0,1) ).to eq( [[res, 0, 1], "6"] )
34
+ expect( tm.fit_to_result_args ).to eq( [res] )
35
+ end
36
+
37
+ it "should accept only a type map object from fit_to_result" do
38
+ tm = Class.new(PG::TypeMapInRuby) do
39
+ def fit_to_result(*args)
40
+ :invalid
41
+ end
42
+ end.new
43
+
44
+ res = @conn.exec("select 5,6")
45
+ expect{ res.map_types!(tm) }.to raise_error(TypeError, /kind of PG::TypeMap/)
46
+ end
47
+ end
48
+
49
+ context "query bind params" do
50
+ it "should be usable non-derived" do
51
+ tm = PG::TypeMapInRuby.new
52
+ res = @conn.exec_params("select $1::int, $2::text", [5, 6], 0, tm)
53
+ expect( res.values ).to eq( [["5", "6"]] )
54
+ end
55
+
56
+ it "should call derived param mapping methods" do
57
+ tm = Class.new(PG::TypeMapInRuby) do
58
+ attr_reader :fit_to_query_args
59
+ attr_reader :typecast_query_param_args
60
+
61
+ def fit_to_query(params)
62
+ @fit_to_query_args = params
63
+ @typecast_query_param_args = []
64
+ self
65
+ end
66
+
67
+ def typecast_query_param(*args)
68
+ @typecast_query_param_args << [args, super]
69
+ PG::TextEncoder::Integer.new name: 'INT4', oid: 23
70
+ end
71
+ end.new
72
+
73
+ res = @conn.exec_params("select $1, $2", [5, 6], 0, tm)
74
+ expect( res.ftype(0) ).to eq( 23 )
75
+ expect( tm.fit_to_query_args ).to eq( [5, 6] )
76
+ expect( tm.typecast_query_param_args ).to eq( [[[5, 0], nil], [[6, 1], nil]] )
77
+ end
78
+ end
79
+
80
+ context "put_copy_data" do
81
+ it "should be usable non-derived" do
82
+ tm = PG::TypeMapInRuby.new
83
+ ce = PG::TextEncoder::CopyRow.new type_map: tm
84
+ res = ce.encode([5, 6])
85
+ expect( res ).to eq( "5\t6\n" )
86
+ end
87
+
88
+ it "should call derived data mapping methods" do
89
+ tm = Class.new(PG::TypeMapInRuby) do
90
+ attr_reader :fit_to_query_args
91
+ attr_reader :typecast_query_param_args
92
+
93
+ def fit_to_query(params)
94
+ @fit_to_query_args = params
95
+ @typecast_query_param_args = []
96
+ self
97
+ end
98
+
99
+ def typecast_query_param(*args)
100
+ @typecast_query_param_args << [args, super]
101
+ PG::TextEncoder::Integer.new name: 'INT4', oid: 23
102
+ end
103
+ end.new
104
+
105
+ ce = PG::TextEncoder::CopyRow.new type_map: tm
106
+ res = ce.encode([5, 6])
107
+ expect( res ).to eq( "5\t6\n" )
108
+ expect( tm.fit_to_query_args ).to eq( [5, 6] )
109
+ expect( tm.typecast_query_param_args ).to eq( [[[5, 0], nil], [[6, 1], nil]] )
110
+ end
111
+
112
+ it "shouldn't accept invalid return from typecast_query_param" do
113
+ tm = Class.new(PG::TypeMapInRuby) do
114
+ def typecast_query_param(*args)
115
+ :invalid
116
+ end
117
+ end.new
118
+
119
+ ce = PG::TextEncoder::CopyRow.new type_map: tm
120
+ expect{ ce.encode([5, 6]) }.to raise_error(TypeError, /nil or kind of PG::Coder/)
121
+ end
122
+ end
123
+
124
+ context "get_copy_data" do
125
+ it "should be usable non-derived" do
126
+ tm = PG::TypeMapInRuby.new
127
+ ce = PG::TextDecoder::CopyRow.new type_map: tm
128
+ res = ce.decode("5\t6\n")
129
+ expect( res ).to eq( ["5", "6"] )
130
+ end
131
+
132
+ it "should call derived data mapping methods" do
133
+ tm = Class.new(PG::TypeMapInRuby) do
134
+ attr_reader :fit_to_copy_get_args
135
+
136
+ def fit_to_copy_get(*args)
137
+ @fit_to_copy_get_args = args
138
+ 0
139
+ end
140
+
141
+ def typecast_copy_get(field_str, fieldno, format, enc)
142
+ [field_str, fieldno, format, enc, super]
143
+ end
144
+ end.new
145
+
146
+ ce = PG::TextDecoder::CopyRow.new type_map: tm
147
+ res = ce.decode("5\t6\n")
148
+ expect( tm.fit_to_copy_get_args ).to eq( [] )
149
+ expect( res ).to eq( [["5", 0, 0, Encoding::UTF_8, "5"], ["6", 1, 0, Encoding::UTF_8, "6"]] )
150
+ end
151
+
152
+ it "shouldn't accept invalid return from fit_to_copy_get" do
153
+ tm = Class.new(PG::TypeMapInRuby) do
154
+ def fit_to_copy_get
155
+ :invalid
156
+ end
157
+ end.new
158
+
159
+ ce = PG::TextDecoder::CopyRow.new type_map: tm
160
+ expect{ ce.decode("5\t6\n") }.to raise_error(TypeError, /kind of Integer/)
161
+ end
162
+ end
163
+
164
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rspec
2
+ # encoding: utf-8
3
+
4
+ require_relative '../helpers'
5
+
6
+ require 'pg'
7
+
8
+
9
+ describe PG::TypeMap do
10
+ let!(:tm){ PG::TypeMap.new }
11
+
12
+ it "should raise an error when used for param type casts" do
13
+ expect{
14
+ @conn.exec_params( "SELECT $1", [5], 0, tm )
15
+ }.to raise_error(NotImplementedError, /not suitable to map query params/)
16
+ end
17
+
18
+ it "should raise an error when used for result type casts" do
19
+ res = @conn.exec( "SELECT 1" )
20
+ expect{ res.map_types!(tm) }.to raise_error(NotImplementedError, /not suitable to map result values/)
21
+ end
22
+ end
@@ -0,0 +1,777 @@
1
+ #!/usr/bin/env rspec
2
+ # encoding: utf-8
3
+
4
+ require 'pg'
5
+
6
+
7
+ describe "PG::Type derivations" do
8
+ let!(:textenc_int) { PG::TextEncoder::Integer.new name: 'Integer', oid: 23 }
9
+ let!(:textdec_int) { PG::TextDecoder::Integer.new name: 'Integer', oid: 23 }
10
+ let!(:textenc_boolean) { PG::TextEncoder::Boolean.new }
11
+ let!(:textdec_boolean) { PG::TextDecoder::Boolean.new }
12
+ let!(:textenc_float) { PG::TextEncoder::Float.new }
13
+ let!(:textdec_float) { PG::TextDecoder::Float.new }
14
+ let!(:textenc_string) { PG::TextEncoder::String.new }
15
+ let!(:textdec_string) { PG::TextDecoder::String.new }
16
+ let!(:textenc_timestamp) { PG::TextEncoder::TimestampWithoutTimeZone.new }
17
+ let!(:textdec_timestamp) { PG::TextDecoder::TimestampWithoutTimeZone.new }
18
+ let!(:textenc_timestamptz) { PG::TextEncoder::TimestampWithTimeZone.new }
19
+ let!(:textdec_timestamptz) { PG::TextDecoder::TimestampWithTimeZone.new }
20
+ let!(:textenc_bytea) { PG::TextEncoder::Bytea.new }
21
+ let!(:textdec_bytea) { PG::TextDecoder::Bytea.new }
22
+ let!(:binaryenc_int2) { PG::BinaryEncoder::Int2.new }
23
+ let!(:binaryenc_int4) { PG::BinaryEncoder::Int4.new }
24
+ let!(:binaryenc_int8) { PG::BinaryEncoder::Int8.new }
25
+ let!(:binarydec_integer) { PG::BinaryDecoder::Integer.new }
26
+
27
+ let!(:intenc_incrementer) do
28
+ Class.new(PG::SimpleEncoder) do
29
+ def encode(value)
30
+ (value.to_i + 1).to_s + " "
31
+ end
32
+ end.new
33
+ end
34
+ let!(:intdec_incrementer) do
35
+ Class.new(PG::SimpleDecoder) do
36
+ def decode(string, tuple=nil, field=nil)
37
+ string.to_i+1
38
+ end
39
+ end.new
40
+ end
41
+
42
+ let!(:intenc_incrementer_with_encoding) do
43
+ Class.new(PG::SimpleEncoder) do
44
+ def encode(value, encoding)
45
+ r = (value.to_i + 1).to_s + " #{encoding}"
46
+ r.encode!(encoding)
47
+ end
48
+ end.new
49
+ end
50
+ let!(:intenc_incrementer_with_int_result) do
51
+ Class.new(PG::SimpleEncoder) do
52
+ def encode(value)
53
+ value.to_i+1
54
+ end
55
+ end.new
56
+ end
57
+
58
+ it "shouldn't be possible to build a PG::Type directly" do
59
+ expect{ PG::Coder.new }.to raise_error(TypeError, /cannot/)
60
+ end
61
+
62
+ describe PG::SimpleCoder do
63
+ describe '#decode' do
64
+ it "should offer decode method with tuple/field" do
65
+ res = textdec_int.decode("123", 1, 1)
66
+ expect( res ).to eq( 123 )
67
+ end
68
+
69
+ it "should offer decode method without tuple/field" do
70
+ res = textdec_int.decode("234")
71
+ expect( res ).to eq( 234 )
72
+ end
73
+
74
+ it "should decode with ruby decoder" do
75
+ expect( intdec_incrementer.decode("3") ).to eq( 4 )
76
+ end
77
+
78
+ it "should decode integers of different lengths form text format" do
79
+ 30.times do |zeros|
80
+ expect( textdec_int.decode("1" + "0"*zeros) ).to eq( 10 ** zeros )
81
+ expect( textdec_int.decode(zeros==0 ? "0" : "9"*zeros) ).to eq( 10 ** zeros - 1 )
82
+ expect( textdec_int.decode("-1" + "0"*zeros) ).to eq( -10 ** zeros )
83
+ expect( textdec_int.decode(zeros==0 ? "0" : "-" + "9"*zeros) ).to eq( -10 ** zeros + 1 )
84
+ end
85
+ 66.times do |bits|
86
+ expect( textdec_int.decode((2 ** bits).to_s) ).to eq( 2 ** bits )
87
+ expect( textdec_int.decode((2 ** bits - 1).to_s) ).to eq( 2 ** bits - 1 )
88
+ expect( textdec_int.decode((-2 ** bits).to_s) ).to eq( -2 ** bits )
89
+ expect( textdec_int.decode((-2 ** bits + 1).to_s) ).to eq( -2 ** bits + 1 )
90
+ end
91
+ end
92
+
93
+ it 'decodes bytea to a binary string' do
94
+ expect( textdec_bytea.decode("\\x00010203EF") ).to eq( "\x00\x01\x02\x03\xef".b )
95
+ expect( textdec_bytea.decode("\\377\\000") ).to eq( "\xff\0".b )
96
+ end
97
+
98
+ context 'timestamps' do
99
+ it 'decodes timestamps without timezone' do
100
+ expect( textdec_timestamp.decode('2016-01-02 23:23:59.123456') ).
101
+ to be_within(0.000001).of( Time.new(2016,01,02, 23, 23, 59.123456) )
102
+ end
103
+ it 'decodes timestamps with hour timezone' do
104
+ expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-04') ).
105
+ to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:00") )
106
+ expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511+10') ).
107
+ to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "+10:00") )
108
+ end
109
+ it 'decodes timestamps with hour:minute timezone' do
110
+ expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-04:15') ).
111
+ to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:15") )
112
+ expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511-0430') ).
113
+ to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "-04:30") )
114
+ expect( textdec_timestamptz.decode('2015-01-26 17:26:42.691511+10:45') ).
115
+ to be_within(0.000001).of( Time.new(2015,01,26, 17, 26, 42.691511, "+10:45") )
116
+ end
117
+ it 'decodes timestamps with hour:minute:sec timezone' do
118
+ # SET TIME ZONE 'Europe/Dublin'; -- Was UTC−00:25:21 until 1916
119
+ # SELECT '1900-01-01'::timestamptz;
120
+ # -- "1900-01-01 00:00:00-00:25:21"
121
+ expect( textdec_timestamptz.decode('1916-01-01 00:00:00-00:25:21') ).
122
+ to be_within(0.000001).of( Time.new(1916, 1, 1, 0, 0, 0, "-00:25:21") )
123
+ end
124
+ end
125
+
126
+ context 'identifier quotation' do
127
+ it 'should build an array out of an quoted identifier string' do
128
+ quoted_type = PG::TextDecoder::Identifier.new
129
+ expect( quoted_type.decode(%["A.".".B"]) ).to eq( ["A.", ".B"] )
130
+ expect( quoted_type.decode(%["'A"".""B'"]) ).to eq( ['\'A"."B\''] )
131
+ end
132
+
133
+ it 'should split unquoted identifier string' do
134
+ quoted_type = PG::TextDecoder::Identifier.new
135
+ expect( quoted_type.decode(%[a.b]) ).to eq( ['a','b'] )
136
+ expect( quoted_type.decode(%[a]) ).to eq( ['a'] )
137
+ end
138
+
139
+ it 'should split identifier string with correct character encoding' do
140
+ quoted_type = PG::TextDecoder::Identifier.new
141
+ v = quoted_type.decode(%[Héllo].encode("iso-8859-1")).first
142
+ expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
143
+ expect( v ).to eq( %[Héllo].encode(Encoding::ISO_8859_1) )
144
+ end
145
+ end
146
+
147
+ it "should raise when decode method is called with wrong args" do
148
+ expect{ textdec_int.decode() }.to raise_error(ArgumentError)
149
+ expect{ textdec_int.decode("123", 2, 3, 4) }.to raise_error(ArgumentError)
150
+ expect{ textdec_int.decode(2, 3, 4) }.to raise_error(TypeError)
151
+ expect( intdec_incrementer.decode(2, 3, 4) ).to eq( 3 )
152
+ end
153
+
154
+ it "should pass through nil values" do
155
+ expect( textdec_string.decode( nil )).to be_nil
156
+ expect( textdec_int.decode( nil )).to be_nil
157
+ end
158
+ end
159
+
160
+ describe '#encode' do
161
+ it "should offer encode method for text type" do
162
+ res = textenc_int.encode(123)
163
+ expect( res ).to eq( "123" )
164
+ end
165
+
166
+ it "should offer encode method for binary type" do
167
+ res = binaryenc_int8.encode(123)
168
+ expect( res ).to eq( [123].pack("q>") )
169
+ end
170
+
171
+ it "should encode integers from string to binary format" do
172
+ expect( binaryenc_int2.encode(" -123 ") ).to eq( [-123].pack("s>") )
173
+ expect( binaryenc_int4.encode(" -123 ") ).to eq( [-123].pack("l>") )
174
+ expect( binaryenc_int8.encode(" -123 ") ).to eq( [-123].pack("q>") )
175
+ expect( binaryenc_int2.encode(" 123-xyz ") ).to eq( [123].pack("s>") )
176
+ expect( binaryenc_int4.encode(" 123-xyz ") ).to eq( [123].pack("l>") )
177
+ expect( binaryenc_int8.encode(" 123-xyz ") ).to eq( [123].pack("q>") )
178
+ end
179
+
180
+ it "should encode integers of different lengths to text format" do
181
+ 30.times do |zeros|
182
+ expect( textenc_int.encode(10 ** zeros) ).to eq( "1" + "0"*zeros )
183
+ expect( textenc_int.encode(10 ** zeros - 1) ).to eq( zeros==0 ? "0" : "9"*zeros )
184
+ expect( textenc_int.encode(-10 ** zeros) ).to eq( "-1" + "0"*zeros )
185
+ expect( textenc_int.encode(-10 ** zeros + 1) ).to eq( zeros==0 ? "0" : "-" + "9"*zeros )
186
+ end
187
+ 66.times do |bits|
188
+ expect( textenc_int.encode(2 ** bits) ).to eq( (2 ** bits).to_s )
189
+ expect( textenc_int.encode(2 ** bits - 1) ).to eq( (2 ** bits - 1).to_s )
190
+ expect( textenc_int.encode(-2 ** bits) ).to eq( (-2 ** bits).to_s )
191
+ expect( textenc_int.encode(-2 ** bits + 1) ).to eq( (-2 ** bits + 1).to_s )
192
+ end
193
+ end
194
+
195
+ it "should encode integers from string to text format" do
196
+ expect( textenc_int.encode(" -123 ") ).to eq( "-123" )
197
+ expect( textenc_int.encode(" 123-xyz ") ).to eq( "123" )
198
+ end
199
+
200
+ it "should encode boolean values" do
201
+ expect( textenc_boolean.encode(false) ).to eq( "f" )
202
+ expect( textenc_boolean.encode(true) ).to eq( "t" )
203
+ ["any", :other, "value", 0, 1, 2].each do |value|
204
+ expect( textenc_boolean.encode(value) ).to eq( value.to_s )
205
+ end
206
+ end
207
+
208
+ it "should encode special floats equally to Float#to_s" do
209
+ expect( textenc_float.encode(Float::INFINITY) ).to eq( Float::INFINITY.to_s )
210
+ expect( textenc_float.encode(-Float::INFINITY) ).to eq( (-Float::INFINITY).to_s )
211
+ expect( textenc_float.encode(-Float::NAN) ).to eq( Float::NAN.to_s )
212
+ end
213
+
214
+ it "encodes binary string to bytea" do
215
+ expect( textenc_bytea.encode("\x00\x01\x02\x03\xef".b) ).to eq( "\\x00010203ef" )
216
+ end
217
+
218
+ context 'identifier quotation' do
219
+ it 'should quote and escape identifier' do
220
+ quoted_type = PG::TextEncoder::Identifier.new
221
+ expect( quoted_type.encode(['schema','table','col']) ).to eq( %["schema"."table"."col"] )
222
+ expect( quoted_type.encode(['A.','.B']) ).to eq( %["A.".".B"] )
223
+ expect( quoted_type.encode(%['A"."B']) ).to eq( %["'A"".""B'"] )
224
+ expect( quoted_type.encode( nil ) ).to be_nil
225
+ end
226
+
227
+ it 'should quote identifiers with correct character encoding' do
228
+ quoted_type = PG::TextEncoder::Identifier.new
229
+ v = quoted_type.encode(['Héllo'], "iso-8859-1")
230
+ expect( v ).to eq( %["Héllo"].encode(Encoding::ISO_8859_1) )
231
+ expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
232
+ end
233
+
234
+ it "will raise a TypeError for invalid arguments to quote_ident" do
235
+ quoted_type = PG::TextEncoder::Identifier.new
236
+ expect{ quoted_type.encode( [nil] ) }.to raise_error(TypeError)
237
+ expect{ quoted_type.encode( [['a']] ) }.to raise_error(TypeError)
238
+ end
239
+ end
240
+
241
+ it "should encode with ruby encoder" do
242
+ expect( intenc_incrementer.encode(3) ).to eq( "4 " )
243
+ end
244
+
245
+ it "should encode with ruby encoder and given character encoding" do
246
+ r = intenc_incrementer_with_encoding.encode(3, Encoding::CP850)
247
+ expect( r ).to eq( "4 CP850" )
248
+ expect( r.encoding ).to eq( Encoding::CP850 )
249
+ end
250
+
251
+ it "should return when ruby encoder returns non string values" do
252
+ expect( intenc_incrementer_with_int_result.encode(3) ).to eq( 4 )
253
+ end
254
+
255
+ it "should pass through nil values" do
256
+ expect( textenc_string.encode( nil )).to be_nil
257
+ expect( textenc_int.encode( nil )).to be_nil
258
+ end
259
+ end
260
+
261
+ it "should be possible to marshal encoders" do
262
+ mt = Marshal.dump(textenc_int)
263
+ lt = Marshal.load(mt)
264
+ expect( lt.to_h ).to eq( textenc_int.to_h )
265
+ end
266
+
267
+ it "should be possible to marshal decoders" do
268
+ mt = Marshal.dump(textdec_int)
269
+ lt = Marshal.load(mt)
270
+ expect( lt.to_h ).to eq( textdec_int.to_h )
271
+ end
272
+
273
+ it "should respond to to_h" do
274
+ expect( textenc_int.to_h ).to eq( {
275
+ name: 'Integer', oid: 23, format: 0
276
+ } )
277
+ end
278
+
279
+ it "should have reasonable default values" do
280
+ t = PG::TextEncoder::String.new
281
+ expect( t.format ).to eq( 0 )
282
+ expect( t.oid ).to eq( 0 )
283
+ expect( t.name ).to be_nil
284
+
285
+ t = PG::BinaryEncoder::Int4.new
286
+ expect( t.format ).to eq( 1 )
287
+ expect( t.oid ).to eq( 0 )
288
+ expect( t.name ).to be_nil
289
+
290
+ t = PG::TextDecoder::String.new
291
+ expect( t.format ).to eq( 0 )
292
+ expect( t.oid ).to eq( 0 )
293
+ expect( t.name ).to be_nil
294
+
295
+ t = PG::BinaryDecoder::String.new
296
+ expect( t.format ).to eq( 1 )
297
+ expect( t.oid ).to eq( 0 )
298
+ expect( t.name ).to be_nil
299
+ end
300
+ end
301
+
302
+ describe PG::CompositeCoder do
303
+ describe "Array types" do
304
+ let!(:textenc_string_array) { PG::TextEncoder::Array.new elements_type: textenc_string }
305
+ let!(:textdec_string_array) { PG::TextDecoder::Array.new elements_type: textdec_string }
306
+ let!(:textenc_int_array) { PG::TextEncoder::Array.new elements_type: textenc_int, needs_quotation: false }
307
+ let!(:textdec_int_array) { PG::TextDecoder::Array.new elements_type: textdec_int, needs_quotation: false }
308
+ let!(:textenc_float_array) { PG::TextEncoder::Array.new elements_type: textenc_float, needs_quotation: false }
309
+ let!(:textdec_float_array) { PG::TextDecoder::Array.new elements_type: textdec_float, needs_quotation: false }
310
+ let!(:textenc_timestamp_array) { PG::TextEncoder::Array.new elements_type: textenc_timestamp, needs_quotation: false }
311
+ let!(:textdec_timestamp_array) { PG::TextDecoder::Array.new elements_type: textdec_timestamp, needs_quotation: false }
312
+ let!(:textenc_string_array_with_delimiter) { PG::TextEncoder::Array.new elements_type: textenc_string, delimiter: ';' }
313
+ let!(:textdec_string_array_with_delimiter) { PG::TextDecoder::Array.new elements_type: textdec_string, delimiter: ';' }
314
+ let!(:textdec_bytea_array) { PG::TextDecoder::Array.new elements_type: textdec_bytea }
315
+
316
+ #
317
+ # Array parser specs are thankfully borrowed from here:
318
+ # https://github.com/dockyard/pg_array_parser
319
+ #
320
+ describe '#decode' do
321
+ context 'one dimensional arrays' do
322
+ context 'empty' do
323
+ it 'returns an empty array' do
324
+ expect( textdec_string_array.decode(%[{}]) ).to eq( [] )
325
+ end
326
+ end
327
+
328
+ context 'no strings' do
329
+ it 'returns an array of strings' do
330
+ expect( textdec_string_array.decode(%[{1,2,3}]) ).to eq( ['1','2','3'] )
331
+ end
332
+ end
333
+
334
+ context 'NULL values' do
335
+ it 'returns an array of strings, with nils replacing NULL characters' do
336
+ expect( textdec_string_array.decode(%[{1,NULL,NULL}]) ).to eq( ['1',nil,nil] )
337
+ end
338
+ end
339
+
340
+ context 'quoted NULL' do
341
+ it 'returns an array with the word NULL' do
342
+ expect( textdec_string_array.decode(%[{1,"NULL",3}]) ).to eq( ['1','NULL','3'] )
343
+ end
344
+ end
345
+
346
+ context 'strings' do
347
+ it 'returns an array of strings when containing commas in a quoted string' do
348
+ expect( textdec_string_array.decode(%[{1,"2,3",4}]) ).to eq( ['1','2,3','4'] )
349
+ end
350
+
351
+ it 'returns an array of strings when containing an escaped quote' do
352
+ expect( textdec_string_array.decode(%[{1,"2\\",3",4}]) ).to eq( ['1','2",3','4'] )
353
+ end
354
+
355
+ it 'returns an array of strings when containing an escaped backslash' do
356
+ expect( textdec_string_array.decode(%[{1,"2\\\\",3,4}]) ).to eq( ['1','2\\','3','4'] )
357
+ expect( textdec_string_array.decode(%[{1,"2\\\\\\",3",4}]) ).to eq( ['1','2\\",3','4'] )
358
+ end
359
+
360
+ it 'returns an array containing empty strings' do
361
+ expect( textdec_string_array.decode(%[{1,"",3,""}]) ).to eq( ['1', '', '3', ''] )
362
+ end
363
+
364
+ it 'returns an array containing unicode strings' do
365
+ expect( textdec_string_array.decode(%[{"Paragraph 399(b)(i) – “valid leave” – meaning"}]) ).to eq(['Paragraph 399(b)(i) – “valid leave” – meaning'])
366
+ end
367
+
368
+ it 'respects a different delimiter' do
369
+ expect( textdec_string_array_with_delimiter.decode(%[{1;2;3}]) ).to eq( ['1','2','3'] )
370
+ end
371
+ end
372
+
373
+ context 'bytea' do
374
+ it 'returns an array of binary strings' do
375
+ expect( textdec_bytea_array.decode(%[{"\\\\x00010203EF","2,3",\\377}]) ).to eq( ["\x00\x01\x02\x03\xef".b,"2,3".b,"\xff".b] )
376
+ end
377
+ end
378
+
379
+ end
380
+
381
+ context 'two dimensional arrays' do
382
+ context 'empty' do
383
+ it 'returns an empty array' do
384
+ expect( textdec_string_array.decode(%[{{}}]) ).to eq( [[]] )
385
+ expect( textdec_string_array.decode(%[{{},{}}]) ).to eq( [[],[]] )
386
+ end
387
+ end
388
+ context 'no strings' do
389
+ it 'returns an array of strings with a sub array' do
390
+ expect( textdec_string_array.decode(%[{1,{2,3},4}]) ).to eq( ['1',['2','3'],'4'] )
391
+ end
392
+ end
393
+ context 'strings' do
394
+ it 'returns an array of strings with a sub array' do
395
+ expect( textdec_string_array.decode(%[{1,{"2,3"},4}]) ).to eq( ['1',['2,3'],'4'] )
396
+ end
397
+ it 'returns an array of strings with a sub array and a quoted }' do
398
+ expect( textdec_string_array.decode(%[{1,{"2,}3",NULL},4}]) ).to eq( ['1',['2,}3',nil],'4'] )
399
+ end
400
+ it 'returns an array of strings with a sub array and a quoted {' do
401
+ expect( textdec_string_array.decode(%[{1,{"2,{3"},4}]) ).to eq( ['1',['2,{3'],'4'] )
402
+ end
403
+ it 'returns an array of strings with a sub array and a quoted { and escaped quote' do
404
+ expect( textdec_string_array.decode(%[{1,{"2\\",{3"},4}]) ).to eq( ['1',['2",{3'],'4'] )
405
+ end
406
+ it 'returns an array of strings with a sub array with empty strings' do
407
+ expect( textdec_string_array.decode(%[{1,{""},4,{""}}]) ).to eq( ['1',[''],'4',['']] )
408
+ end
409
+ end
410
+ context 'timestamps' do
411
+ it 'decodes an array of timestamps with sub arrays' do
412
+ expect( textdec_timestamp_array.decode('{2014-12-31 00:00:00,{NULL,2016-01-02 23:23:59.0000000}}') ).
413
+ to eq( [Time.new(2014,12,31),[nil, Time.new(2016,01,02, 23, 23, 59)]] )
414
+ end
415
+ end
416
+ end
417
+ context 'three dimensional arrays' do
418
+ context 'empty' do
419
+ it 'returns an empty array' do
420
+ expect( textdec_string_array.decode(%[{{{}}}]) ).to eq( [[[]]] )
421
+ expect( textdec_string_array.decode(%[{{{},{}},{{},{}}}]) ).to eq( [[[],[]],[[],[]]] )
422
+ end
423
+ end
424
+ it 'returns an array of strings with sub arrays' do
425
+ expect( textdec_string_array.decode(%[{1,{2,{3,4}},{NULL,6},7}]) ).to eq( ['1',['2',['3','4']],[nil,'6'],'7'] )
426
+ end
427
+ end
428
+
429
+ it 'should decode array of types with decoder in ruby space' do
430
+ array_type = PG::TextDecoder::Array.new elements_type: intdec_incrementer
431
+ expect( array_type.decode(%[{3,4}]) ).to eq( [4,5] )
432
+ end
433
+
434
+ it 'should decode array of nil types' do
435
+ array_type = PG::TextDecoder::Array.new elements_type: nil
436
+ expect( array_type.decode(%[{3,4}]) ).to eq( ['3','4'] )
437
+ end
438
+ end
439
+
440
+ describe '#encode' do
441
+ context 'three dimensional arrays' do
442
+ it 'encodes an array of strings and numbers with sub arrays' do
443
+ expect( textenc_string_array.encode(['1',['2',['3','4']],[nil,6],7.8]) ).to eq( %[{1,{2,{3,4}},{NULL,6},7.8}] )
444
+ end
445
+ it 'encodes an array of strings with quotes' do
446
+ expect( textenc_string_array.encode(['',[' ',['{','}','\\',',','"','\t']]]) ).to eq( %[{"",{" ",{"{","}","\\\\",",","\\"","\\\\t"}}}] )
447
+ end
448
+ it 'encodes an array of int8 with sub arrays' do
449
+ expect( textenc_int_array.encode([1,[2,[3,4]],[nil,6],7]) ).to eq( %[{1,{2,{3,4}},{NULL,6},7}] )
450
+ end
451
+ it 'encodes an array of int8 with strings' do
452
+ expect( textenc_int_array.encode(['1',['2'],'3']) ).to eq( %[{1,{2},3}] )
453
+ end
454
+ it 'encodes an array of float8 with sub arrays' do
455
+ expect( textenc_float_array.encode([1000.11,[-0.00221,[3.31,-441]],[nil,6.61],-7.71]) ).to match(Regexp.new(%[^{1.0001*E+*03,{-2.2*E-*03,{3.3*E+*00,-4.4*E+*02}},{NULL,6.6*E+*00},-7.7*E+*00}$].gsub(/([\.\+\{\}\,])/, "\\\\\\1").gsub(/\*/, "\\d*")))
456
+ end
457
+ end
458
+ context 'two dimensional arrays' do
459
+ it 'encodes an array of timestamps with sub arrays' do
460
+ expect( textenc_timestamp_array.encode([Time.new(2014,12,31),[nil, Time.new(2016,01,02, 23, 23, 59.99)]]) ).
461
+ to eq( %[{2014-12-31 00:00:00.000000000,{NULL,2016-01-02 23:23:59.990000000}}] )
462
+ end
463
+ end
464
+ context 'one dimensional array' do
465
+ it 'can encode empty arrays' do
466
+ expect( textenc_int_array.encode([]) ).to eq( '{}' )
467
+ expect( textenc_string_array.encode([]) ).to eq( '{}' )
468
+ end
469
+ it 'encodes an array of NULL strings w/wo quotes' do
470
+ expect( textenc_string_array.encode(['NUL', 'NULL', 'NULLL', 'nul', 'null', 'nulll']) ).to eq( %[{NUL,"NULL",NULLL,nul,"null",nulll}] )
471
+ end
472
+ it 'respects a different delimiter' do
473
+ expect( textenc_string_array_with_delimiter.encode(['a','b,','c']) ).to eq( '{a;b,;c}' )
474
+ end
475
+ end
476
+
477
+ context 'array of types with encoder in ruby space' do
478
+ it 'encodes with quotation and default character encoding' do
479
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer, needs_quotation: true
480
+ r = array_type.encode([3,4])
481
+ expect( r ).to eq( %[{"4 ","5 "}] )
482
+ expect( r.encoding ).to eq( Encoding::ASCII_8BIT )
483
+ end
484
+
485
+ it 'encodes with quotation and given character encoding' do
486
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer, needs_quotation: true
487
+ r = array_type.encode([3,4], Encoding::CP850)
488
+ expect( r ).to eq( %[{"4 ","5 "}] )
489
+ expect( r.encoding ).to eq( Encoding::CP850 )
490
+ end
491
+
492
+ it 'encodes without quotation' do
493
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer, needs_quotation: false
494
+ expect( array_type.encode([3,4]) ).to eq( %[{4 ,5 }] )
495
+ end
496
+
497
+ it 'encodes with default character encoding' do
498
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_encoding
499
+ r = array_type.encode([3,4])
500
+ expect( r ).to eq( %[{"4 ASCII-8BIT","5 ASCII-8BIT"}] )
501
+ expect( r.encoding ).to eq( Encoding::ASCII_8BIT )
502
+ end
503
+
504
+ it 'encodes with given character encoding' do
505
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_encoding
506
+ r = array_type.encode([3,4], Encoding::CP850)
507
+ expect( r ).to eq( %[{"4 CP850","5 CP850"}] )
508
+ expect( r.encoding ).to eq( Encoding::CP850 )
509
+ end
510
+
511
+ it "should raise when ruby encoder returns non string values" do
512
+ array_type = PG::TextEncoder::Array.new elements_type: intenc_incrementer_with_int_result, needs_quotation: false
513
+ expect{ array_type.encode([3,4]) }.to raise_error(TypeError)
514
+ end
515
+ end
516
+
517
+ it "should pass through non Array inputs" do
518
+ expect( textenc_float_array.encode("text") ).to eq( "text" )
519
+ expect( textenc_float_array.encode(1234) ).to eq( "1234" )
520
+ end
521
+
522
+ context 'literal quotation' do
523
+ it 'should quote and escape literals' do
524
+ quoted_type = PG::TextEncoder::QuotedLiteral.new elements_type: textenc_string_array
525
+ expect( quoted_type.encode(["'A\",","\\B'"]) ).to eq( %['{"''A\\",","\\\\B''"}'] )
526
+ end
527
+
528
+ it 'should quote literals with correct character encoding' do
529
+ quoted_type = PG::TextEncoder::QuotedLiteral.new elements_type: textenc_string_array
530
+ v = quoted_type.encode(["Héllo"], "iso-8859-1")
531
+ expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
532
+ expect( v ).to eq( %['{Héllo}'].encode(Encoding::ISO_8859_1) )
533
+ end
534
+ end
535
+ end
536
+
537
+ it "should be possible to marshal encoders" do
538
+ mt = Marshal.dump(textenc_int_array)
539
+ lt = Marshal.load(mt)
540
+ expect( lt.to_h ).to eq( textenc_int_array.to_h )
541
+ end
542
+
543
+ it "should be possible to marshal encoders" do
544
+ mt = Marshal.dump(textdec_int_array)
545
+ lt = Marshal.load(mt)
546
+ expect( lt.to_h ).to eq( textdec_int_array.to_h )
547
+ end
548
+
549
+ it "should respond to to_h" do
550
+ expect( textenc_int_array.to_h ).to eq( {
551
+ name: nil, oid: 0, format: 0,
552
+ elements_type: textenc_int, needs_quotation: false, delimiter: ','
553
+ } )
554
+ end
555
+
556
+ it "shouldn't accept invalid elements_types" do
557
+ expect{ PG::TextEncoder::Array.new elements_type: false }.to raise_error(TypeError)
558
+ end
559
+
560
+ it "should have reasonable default values" do
561
+ t = PG::TextEncoder::Array.new
562
+ expect( t.format ).to eq( 0 )
563
+ expect( t.oid ).to eq( 0 )
564
+ expect( t.name ).to be_nil
565
+ expect( t.needs_quotation? ).to eq( true )
566
+ expect( t.delimiter ).to eq( ',' )
567
+ expect( t.elements_type ).to be_nil
568
+ end
569
+ end
570
+
571
+ it "should encode Strings as base64 in TextEncoder" do
572
+ e = PG::TextEncoder::ToBase64.new
573
+ expect( e.encode("") ).to eq("")
574
+ expect( e.encode("x") ).to eq("eA==")
575
+ expect( e.encode("xx") ).to eq("eHg=")
576
+ expect( e.encode("xxx") ).to eq("eHh4")
577
+ expect( e.encode("xxxx") ).to eq("eHh4eA==")
578
+ expect( e.encode("xxxxx") ).to eq("eHh4eHg=")
579
+ expect( e.encode("\0\n\t") ).to eq("AAoJ")
580
+ expect( e.encode("(\xFBm") ).to eq("KPtt")
581
+ end
582
+
583
+ it 'should encode Strings as base64 with correct character encoding' do
584
+ e = PG::TextEncoder::ToBase64.new
585
+ v = e.encode("Héllo".encode("utf-16le"), "iso-8859-1")
586
+ expect( v ).to eq("SOlsbG8=")
587
+ expect( v.encoding ).to eq(Encoding::ISO_8859_1)
588
+ end
589
+
590
+ it "should encode Strings as base64 in BinaryDecoder" do
591
+ e = PG::BinaryDecoder::ToBase64.new
592
+ expect( e.decode("x") ).to eq("eA==")
593
+ v = e.decode("Héllo".encode("utf-16le"))
594
+ expect( v ).to eq("SADpAGwAbABvAA==")
595
+ expect( v.encoding ).to eq(Encoding::ASCII_8BIT)
596
+ end
597
+
598
+ it "should encode Integers as base64" do
599
+ # Not really useful, but ensures that two-pass element and composite element encoders work.
600
+ e = PG::TextEncoder::ToBase64.new( elements_type: PG::TextEncoder::Array.new( elements_type: PG::TextEncoder::Integer.new, needs_quotation: false ))
601
+ expect( e.encode([1]) ).to eq(["{1}"].pack("m").chomp)
602
+ expect( e.encode([12]) ).to eq(["{12}"].pack("m").chomp)
603
+ expect( e.encode([123]) ).to eq(["{123}"].pack("m").chomp)
604
+ expect( e.encode([1234]) ).to eq(["{1234}"].pack("m").chomp)
605
+ expect( e.encode([12345]) ).to eq(["{12345}"].pack("m").chomp)
606
+ expect( e.encode([123456]) ).to eq(["{123456}"].pack("m").chomp)
607
+ expect( e.encode([1234567]) ).to eq(["{1234567}"].pack("m").chomp)
608
+ end
609
+
610
+ it "should decode base64 to Strings in TextDecoder" do
611
+ e = PG::TextDecoder::FromBase64.new
612
+ expect( e.decode("") ).to eq("")
613
+ expect( e.decode("eA==") ).to eq("x")
614
+ expect( e.decode("eHg=") ).to eq("xx")
615
+ expect( e.decode("eHh4") ).to eq("xxx")
616
+ expect( e.decode("eHh4eA==") ).to eq("xxxx")
617
+ expect( e.decode("eHh4eHg=") ).to eq("xxxxx")
618
+ expect( e.decode("AAoJ") ).to eq("\0\n\t")
619
+ expect( e.decode("KPtt") ).to eq("(\xFBm")
620
+ end
621
+
622
+ it "should decode base64 in BinaryEncoder" do
623
+ e = PG::BinaryEncoder::FromBase64.new
624
+ expect( e.encode("eA==") ).to eq("x")
625
+
626
+ e = PG::BinaryEncoder::FromBase64.new( elements_type: PG::TextEncoder::Integer.new )
627
+ expect( e.encode(124) ).to eq("124=".unpack("m")[0])
628
+ end
629
+
630
+ it "should decode base64 to Integers" do
631
+ # Not really useful, but ensures that composite element encoders work.
632
+ e = PG::TextDecoder::FromBase64.new( elements_type: PG::TextDecoder::Array.new( elements_type: PG::TextDecoder::Integer.new ))
633
+ expect( e.decode(["{1}"].pack("m")) ).to eq([1])
634
+ expect( e.decode(["{12}"].pack("m")) ).to eq([12])
635
+ expect( e.decode(["{123}"].pack("m")) ).to eq([123])
636
+ expect( e.decode(["{1234}"].pack("m")) ).to eq([1234])
637
+ expect( e.decode(["{12345}"].pack("m")) ).to eq([12345])
638
+ expect( e.decode(["{123456}"].pack("m")) ).to eq([123456])
639
+ expect( e.decode(["{1234567}"].pack("m")) ).to eq([1234567])
640
+ expect( e.decode(["{12345678}"].pack("m")) ).to eq([12345678])
641
+
642
+ e = PG::TextDecoder::FromBase64.new( elements_type: PG::BinaryDecoder::Integer.new )
643
+ expect( e.decode("ALxhTg==") ).to eq(12345678)
644
+ end
645
+
646
+ it "should decode base64 with garbage" do
647
+ e = PG::TextDecoder::FromBase64.new format: 1
648
+ expect( e.decode("=") ).to eq("=".unpack("m")[0])
649
+ expect( e.decode("==") ).to eq("==".unpack("m")[0])
650
+ expect( e.decode("===") ).to eq("===".unpack("m")[0])
651
+ expect( e.decode("====") ).to eq("====".unpack("m")[0])
652
+ expect( e.decode("a=") ).to eq("a=".unpack("m")[0])
653
+ expect( e.decode("a==") ).to eq("a==".unpack("m")[0])
654
+ expect( e.decode("a===") ).to eq("a===".unpack("m")[0])
655
+ expect( e.decode("a====") ).to eq("a====".unpack("m")[0])
656
+ expect( e.decode("aa=") ).to eq("aa=".unpack("m")[0])
657
+ expect( e.decode("aa==") ).to eq("aa==".unpack("m")[0])
658
+ expect( e.decode("aa===") ).to eq("aa===".unpack("m")[0])
659
+ expect( e.decode("aa====") ).to eq("aa====".unpack("m")[0])
660
+ expect( e.decode("aaa=") ).to eq("aaa=".unpack("m")[0])
661
+ expect( e.decode("aaa==") ).to eq("aaa==".unpack("m")[0])
662
+ expect( e.decode("aaa===") ).to eq("aaa===".unpack("m")[0])
663
+ expect( e.decode("aaa====") ).to eq("aaa====".unpack("m")[0])
664
+ expect( e.decode("=aa") ).to eq("=aa=".unpack("m")[0])
665
+ expect( e.decode("=aa=") ).to eq("=aa=".unpack("m")[0])
666
+ expect( e.decode("=aa==") ).to eq("=aa==".unpack("m")[0])
667
+ expect( e.decode("=aa===") ).to eq("=aa===".unpack("m")[0])
668
+ end
669
+ end
670
+
671
+ describe PG::CopyCoder do
672
+ describe PG::TextEncoder::CopyRow do
673
+ context "with default typemap" do
674
+ let!(:encoder) do
675
+ PG::TextEncoder::CopyRow.new
676
+ end
677
+
678
+ it "should encode different types of Ruby objects" do
679
+ expect( encoder.encode([:xyz, 123, 2456, 34567, 456789, 5678901, [1,2,3], 12.1, "abcdefg", nil]) ).
680
+ to eq("xyz\t123\t2456\t34567\t456789\t5678901\t[1, 2, 3]\t12.1\tabcdefg\t\\N\n")
681
+ end
682
+
683
+ it 'should output a string with correct character encoding' do
684
+ v = encoder.encode(["Héllo"], "iso-8859-1")
685
+ expect( v.encoding ).to eq( Encoding::ISO_8859_1 )
686
+ expect( v ).to eq( "Héllo\n".encode(Encoding::ISO_8859_1) )
687
+ end
688
+ end
689
+
690
+ context "with TypeMapByClass" do
691
+ let!(:tm) do
692
+ tm = PG::TypeMapByClass.new
693
+ tm[Integer] = textenc_int
694
+ tm[Float] = intenc_incrementer
695
+ tm[Array] = PG::TextEncoder::Array.new elements_type: textenc_string
696
+ tm
697
+ end
698
+ let!(:encoder) do
699
+ PG::TextEncoder::CopyRow.new type_map: tm
700
+ end
701
+
702
+ it "should have reasonable default values" do
703
+ expect( encoder.name ).to be_nil
704
+ expect( encoder.delimiter ).to eq( "\t" )
705
+ expect( encoder.null_string ).to eq( "\\N" )
706
+ end
707
+
708
+ it "copies all attributes with #dup" do
709
+ encoder.name = "test"
710
+ encoder.delimiter = "#"
711
+ encoder.null_string = "NULL"
712
+ encoder.type_map = PG::TypeMapByColumn.new []
713
+ encoder2 = encoder.dup
714
+ expect( encoder.object_id ).to_not eq( encoder2.object_id )
715
+ expect( encoder2.name ).to eq( "test" )
716
+ expect( encoder2.delimiter ).to eq( "#" )
717
+ expect( encoder2.null_string ).to eq( "NULL" )
718
+ expect( encoder2.type_map ).to be_a_kind_of( PG::TypeMapByColumn )
719
+ end
720
+
721
+ describe '#encode' do
722
+ it "should encode different types of Ruby objects" do
723
+ expect( encoder.encode([]) ).to eq("\n")
724
+ expect( encoder.encode(["a"]) ).to eq("a\n")
725
+ expect( encoder.encode([:xyz, 123, 2456, 34567, 456789, 5678901, [1,2,3], 12.1, "abcdefg", nil]) ).
726
+ to eq("xyz\t123\t2456\t34567\t456789\t5678901\t{1,2,3}\t13 \tabcdefg\t\\N\n")
727
+ end
728
+
729
+ it "should escape special characters" do
730
+ expect( encoder.encode([" \0\t\n\r\\"]) ).to eq(" \0#\t#\n#\r#\\\n".gsub("#", "\\"))
731
+ end
732
+
733
+ it "should escape with different delimiter" do
734
+ encoder.delimiter = " "
735
+ encoder.null_string = "NULL"
736
+ expect( encoder.encode([nil, " ", "\0", "\t", "\n", "\r", "\\"]) ).to eq("NULL # \0 \t #\n #\r #\\\n".gsub("#", "\\"))
737
+ end
738
+ end
739
+ end
740
+ end
741
+
742
+ describe PG::TextDecoder::CopyRow do
743
+ context "with default typemap" do
744
+ let!(:decoder) do
745
+ PG::TextDecoder::CopyRow.new
746
+ end
747
+
748
+ describe '#decode' do
749
+ it "should decode different types of Ruby objects" do
750
+ expect( decoder.decode("123\t \0#\t#\n#\r#\\ \t234\t#\x01#\002\n".gsub("#", "\\"))).to eq( ["123", " \0\t\n\r\\ ", "234", "\x01\x02"] )
751
+ end
752
+
753
+ it 'should respect input character encoding' do
754
+ v = decoder.decode("Héllo\n".encode("iso-8859-1")).first
755
+ expect( v.encoding ).to eq(Encoding::ISO_8859_1)
756
+ expect( v ).to eq("Héllo".encode("iso-8859-1"))
757
+ end
758
+ end
759
+ end
760
+
761
+ context "with TypeMapByColumn" do
762
+ let!(:tm) do
763
+ PG::TypeMapByColumn.new [textdec_int, textdec_string, intdec_incrementer, nil]
764
+ end
765
+ let!(:decoder) do
766
+ PG::TextDecoder::CopyRow.new type_map: tm
767
+ end
768
+
769
+ describe '#decode' do
770
+ it "should decode different types of Ruby objects" do
771
+ expect( decoder.decode("123\t \0#\t#\n#\r#\\ \t234\t#\x01#\002\n".gsub("#", "\\"))).to eq( [123, " \0\t\n\r\\ ", 235, "\x01\x02"] )
772
+ end
773
+ end
774
+ end
775
+ end
776
+ end
777
+ end