barcode1dtools 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +21 -0
- data/lib/barcode1dtools.rb +119 -0
- data/lib/barcode1dtools/ean13.rb +389 -0
- data/lib/barcode1dtools/ean8.rb +252 -0
- data/lib/barcode1dtools/interleaved2of5.rb +248 -0
- data/lib/barcode1dtools/upc_a.rb +143 -0
- data/lib/barcode1dtools/upc_e.rb +274 -0
- data/lib/barcode1dtools/upc_supplemental_2.rb +221 -0
- data/lib/barcode1dtools/upc_supplemental_5.rb +246 -0
- data/test/test_barcode1d.rb +56 -0
- data/test/test_barcode1dean13.rb +102 -0
- data/test/test_barcode1dean8.rb +95 -0
- data/test/test_barcode1di2of5.rb +86 -0
- data/test/test_barcode1dupca.rb +102 -0
- data/test/test_barcode1dupce.rb +127 -0
- data/test/test_barcode1dupcsupp2.rb +89 -0
- data/test/test_barcode1dupcsupp5.rb +94 -0
- metadata +93 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'barcode1dtools/upc_a'
|
9
|
+
|
10
|
+
module Barcode1DTools
|
11
|
+
|
12
|
+
# Barcode1DTools::UPC_Supplemental_5 - Create pattern for UPC
|
13
|
+
# Supplemental 5 barcodes
|
14
|
+
#
|
15
|
+
# The value encoded is an 5-digit integer, and a checksum digit
|
16
|
+
# will be added. You can add the option :checksum_included => true
|
17
|
+
# when initializing to specify that you have already included a
|
18
|
+
# checksum. The bar patterns are the same as the left
|
19
|
+
# half of a standard UPC-A.
|
20
|
+
#
|
21
|
+
# num = '53999' # book price is US$39.99
|
22
|
+
# bc = Barcode1DTools::UPC_Supplemental_5.new(num)
|
23
|
+
# pattern = bc.bars
|
24
|
+
# rle_pattern = bc.rle
|
25
|
+
# bc.price # returns the "price" part as 4 digits
|
26
|
+
# bc.currency # returns the first digit currency code
|
27
|
+
# width = bc.width
|
28
|
+
# check_digit = Barcode1DTools::UPC_Supplemental_5.generate_check_digit_for(num)
|
29
|
+
#
|
30
|
+
# This type of barcode consists of 5 digits, and a check digit
|
31
|
+
# (a modulus 10 of the sum of the digits with weights of 3 and
|
32
|
+
# 9) that is encoded in the "parity" of the two barcode
|
33
|
+
# digits. It is positioned to the right of a UPC-A or EAN-13
|
34
|
+
# to create a "Bookland" code.
|
35
|
+
#
|
36
|
+
# The two are scanned together, and typically the scanner will
|
37
|
+
# return the five digits of the supplemental barcode
|
38
|
+
# immediately following the check digit from the main barcode.
|
39
|
+
# You will likely need to use the Barcode::UPC_A or
|
40
|
+
# Barcode::EAN_13 module in addition to this one to create the
|
41
|
+
# full code.
|
42
|
+
#
|
43
|
+
# The 5-digit supplement is generally used on literature, and
|
44
|
+
# represents a type-indicator digit followed by a 4-digit
|
45
|
+
# MSRP. The type is "0" for British Pound units, "5" for US
|
46
|
+
# Dollar units, and 9 for extra information. A code of
|
47
|
+
# "90000" means "no MSRP", "99991" indicates a complimentary
|
48
|
+
# copy, "99990" is used to mark used books (by college
|
49
|
+
# bookstores), and "90001" through "98999" are used internally
|
50
|
+
# by some publishers.
|
51
|
+
#
|
52
|
+
#== Rendering
|
53
|
+
#
|
54
|
+
# The 5-digit supplement is positioned to the right of the
|
55
|
+
# main UPC code, and the human-readable digits are usually
|
56
|
+
# printed above the supplemental barcode.
|
57
|
+
#
|
58
|
+
# A UPC-A is generally rendered at one inch across, then
|
59
|
+
# there's a 1/8th inch gap, then the supplemental. A UPC-A is
|
60
|
+
# 95 units wide, so the gap is 24 units wide. The 5-digit
|
61
|
+
# supplemental barcode is 47 units wide, essentially half an
|
62
|
+
# inch at this scale. Note that regardless of scale, the gap
|
63
|
+
# should be at least the smaller of 1/8th inch or 10 units.
|
64
|
+
|
65
|
+
|
66
|
+
class UPC_Supplemental_5 < Barcode1D
|
67
|
+
|
68
|
+
LEFT_PATTERNS = UPC_A::LEFT_PATTERNS
|
69
|
+
LEFT_PATTERNS_RLE = UPC_A::LEFT_PATTERNS_RLE
|
70
|
+
|
71
|
+
# parity patterns, essentially binary counting where "e" is "1"
|
72
|
+
# and "o" is "0"
|
73
|
+
PARITY_PATTERNS = {
|
74
|
+
'0' => 'eeooo',
|
75
|
+
'1' => 'eoeoo',
|
76
|
+
'2' => 'eooeo',
|
77
|
+
'3' => 'eoooe',
|
78
|
+
'4' => 'oeeoo',
|
79
|
+
'5' => 'ooeeo',
|
80
|
+
'6' => 'oooee',
|
81
|
+
'7' => 'oeoeo',
|
82
|
+
'8' => 'oeooe',
|
83
|
+
'9' => 'ooeoe'
|
84
|
+
};
|
85
|
+
|
86
|
+
LEFT_GUARD_PATTERN = '1011'
|
87
|
+
MIDDLE_GUARD_PATTERN = '01'
|
88
|
+
LEFT_GUARD_PATTERN_RLE = '112'
|
89
|
+
MIDDLE_GUARD_PATTERN_RLE = '11'
|
90
|
+
|
91
|
+
DEFAULT_OPTIONS = {
|
92
|
+
:line_character => '1',
|
93
|
+
:space_character => '0'
|
94
|
+
}
|
95
|
+
|
96
|
+
attr_reader :currency_code
|
97
|
+
attr_reader :price
|
98
|
+
|
99
|
+
class << self
|
100
|
+
# Returns true or false - must be 5 or 6 digits. This
|
101
|
+
# also handles the case where the leading 0 is added.
|
102
|
+
def can_encode?(value, options = nil)
|
103
|
+
if !options
|
104
|
+
value.to_s =~ /^\d{5,6}$/
|
105
|
+
elsif (options[:checksum_included])
|
106
|
+
value.to_s =~ /^\d{6}$/
|
107
|
+
else
|
108
|
+
value.to_s =~ /^\d{5}$/
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Generates check digit given a string to encode. It assumes there
|
113
|
+
# is no check digit on the "value".
|
114
|
+
def generate_check_digit_for(value)
|
115
|
+
mult = 9 # alternates 3 and 9
|
116
|
+
sprintf('%05d',value.to_i).reverse.chars.inject(0) { |a,c| mult = 12 - mult; a + c.to_i * mult } % 10
|
117
|
+
end
|
118
|
+
|
119
|
+
# validates the check digit given a string - assumes check digit
|
120
|
+
# is last digit of string.
|
121
|
+
def validate_check_digit_for(value)
|
122
|
+
raise UnencodableCharactersError unless self.can_encode?(value, :checksum_included => true)
|
123
|
+
md = value.match(/^(\d{5})(\d)$/)
|
124
|
+
self.generate_check_digit_for(md[1]) == md[2].to_i
|
125
|
+
end
|
126
|
+
|
127
|
+
def decode(str)
|
128
|
+
if str.length == 47
|
129
|
+
# bar pattern
|
130
|
+
str = bars_to_rle(str)
|
131
|
+
elsif str.length == 31 && str =~ /^[1-9]+$/
|
132
|
+
# rle
|
133
|
+
else
|
134
|
+
raise UnencodableCharactersError, "Pattern must be 47 unit bar pattern or 31 character rle."
|
135
|
+
end
|
136
|
+
|
137
|
+
# This string is "aaabbbb(ccdddd)" where "aaa" is the left
|
138
|
+
# guard pattern, "bbbb" is the first digit, "cc" is the
|
139
|
+
# intra-digit guard pattern, and "dddd" is the second
|
140
|
+
# digit. (ccdddd) occurs 4 times.
|
141
|
+
|
142
|
+
# See if the string is reversed
|
143
|
+
if str[28..30] == LEFT_GUARD_PATTERN_RLE.reverse && [7,13,19,25].all? { |x| str[29-x,2] == MIDDLE_GUARD_PATTERN_RLE.reverse }
|
144
|
+
str.reverse!
|
145
|
+
end
|
146
|
+
|
147
|
+
# Check the guard patterns
|
148
|
+
unless (str[0..2] == LEFT_GUARD_PATTERN_RLE && [7,13,19,25].all? { |x| str[x,2] == MIDDLE_GUARD_PATTERN_RLE.reverse })
|
149
|
+
raise UnencodableCharactersError, "Missing or incorrect guard patterns"
|
150
|
+
end
|
151
|
+
|
152
|
+
parity_sequence = ''
|
153
|
+
digits = ''
|
154
|
+
left_initial_offset = LEFT_GUARD_PATTERN_RLE.length
|
155
|
+
|
156
|
+
# Decode
|
157
|
+
(0..4).each do |left_offset|
|
158
|
+
found = false
|
159
|
+
digit_rle = str[(left_initial_offset + left_offset*6),4]
|
160
|
+
['o','e'].each do |parity|
|
161
|
+
('0'..'9').each do |digit|
|
162
|
+
if LEFT_PATTERNS_RLE[digit][parity] == digit_rle
|
163
|
+
parity_sequence += parity
|
164
|
+
digits += digit
|
165
|
+
found = true
|
166
|
+
break
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
raise UndecodableCharactersError, "Invalid sequence: #{digit_rle}" unless found
|
171
|
+
end
|
172
|
+
|
173
|
+
# Now, find the parity digit
|
174
|
+
parity_digit = nil
|
175
|
+
('0'..'9').each do |x|
|
176
|
+
if PARITY_PATTERNS[x] == parity_sequence
|
177
|
+
parity_digit = x
|
178
|
+
break
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
raise UndecodableCharactersError, "Weird parity: #{parity_sequence}" unless parity_digit
|
183
|
+
|
184
|
+
UPC_Supplemental_5.new(digits + parity_digit, :checksum_included => true)
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
# Options are :line_character, :space_character, and
|
190
|
+
# :checksum_included.
|
191
|
+
def initialize(value, options = {})
|
192
|
+
|
193
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
194
|
+
|
195
|
+
# Can we encode this value?
|
196
|
+
raise UnencodableCharactersError unless self.class.can_encode?(value, @options)
|
197
|
+
|
198
|
+
if @options[:checksum_included]
|
199
|
+
@encoded_string = value.to_s
|
200
|
+
raise ChecksumError unless self.class.validate_check_digit_for(@encoded_string)
|
201
|
+
md = @encoded_string.match(/^(\d+?)(\d)$/)
|
202
|
+
@value, @check_digit = md[1], md[2].to_i
|
203
|
+
else
|
204
|
+
# need to add a checksum
|
205
|
+
@value = value.to_s
|
206
|
+
@check_digit = self.class.generate_check_digit_for(@value)
|
207
|
+
@encoded_string = sprintf('%05d%1d',@value.to_i,@check_digit)
|
208
|
+
end
|
209
|
+
|
210
|
+
md = @value.match(/^(\d)(\d{4})/)
|
211
|
+
@currency_code, @price = md[1], md[2]
|
212
|
+
end
|
213
|
+
|
214
|
+
# not usable with EAN-style codes
|
215
|
+
def wn
|
216
|
+
raise NotImplementedError
|
217
|
+
end
|
218
|
+
|
219
|
+
# returns a run-length-encoded string representation
|
220
|
+
def rle
|
221
|
+
if @rle
|
222
|
+
@rle
|
223
|
+
else
|
224
|
+
md = @encoded_string.match(/(\d{5})(\d)$/)
|
225
|
+
@rle = gen_rle(md[1], md[2])
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# returns 1s and 0s (for "black" and "white")
|
230
|
+
def bars
|
231
|
+
@bars ||= self.class.rle_to_bars(self.rle, @options)
|
232
|
+
end
|
233
|
+
|
234
|
+
# returns the total unit width of the bar code
|
235
|
+
def width
|
236
|
+
@width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def gen_rle(payload, parity_digit)
|
242
|
+
LEFT_GUARD_PATTERN_RLE + (0..4).collect { |n| LEFT_PATTERNS_RLE[payload[n,1]][PARITY_PATTERNS[parity_digit][n,1]] }.join(MIDDLE_GUARD_PATTERN_RLE)
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require 'barcode1dtools'
|
10
|
+
|
11
|
+
class Barcode1DToolsTest < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
@options = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_rle_to_bars
|
20
|
+
assert_equal '111001', Barcode1DTools::Barcode1D.rle_to_bars('321', @options)
|
21
|
+
assert_equal '10011100001', Barcode1DTools::Barcode1D.rle_to_bars('12341', @options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_bars_to_rle
|
25
|
+
assert_equal '321', Barcode1DTools::Barcode1D.bars_to_rle('111001', @options)
|
26
|
+
assert_equal '12341', Barcode1DTools::Barcode1D.bars_to_rle('10011100001', @options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_back_and_forth
|
30
|
+
random_rle = (0..19).collect { |x| (rand * 4 + 1).to_int.to_s }.join
|
31
|
+
random_bars = '1' + (0..((rand(25)+5)*2)).collect { |x| (x.odd? ? '1' : '0')*(rand(5)+1) }.join + '1'
|
32
|
+
random_wn = (0..19).collect { |x| rand < 0.5 ? 'w' : 'n' }.join
|
33
|
+
assert_equal random_rle, Barcode1DTools::Barcode1D.bars_to_rle(Barcode1DTools::Barcode1D.rle_to_bars(random_rle, @options), @options)
|
34
|
+
assert_equal random_bars, Barcode1DTools::Barcode1D.rle_to_bars(Barcode1DTools::Barcode1D.bars_to_rle(random_bars, @options), @options)
|
35
|
+
assert_equal random_wn, Barcode1DTools::Barcode1D.rle_to_wn(Barcode1DTools::Barcode1D.wn_to_rle(random_wn, @options), @options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_bar_pair
|
39
|
+
assert_equal '01', Barcode1DTools::Barcode1D.bar_pair
|
40
|
+
assert_equal '56', Barcode1DTools::Barcode1D.bar_pair({ :space_character => 5, :line_character => 6 })
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_wn_to_rle
|
44
|
+
assert_equal '12121211', Barcode1DTools::Barcode1D.wn_to_rle('nwnwnwnn')
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_rle_to_wn
|
48
|
+
assert_equal 'wnwnwnww', Barcode1DTools::Barcode1D.rle_to_wn('21212122')
|
49
|
+
assert_equal 'wnwnwnww', Barcode1DTools::Barcode1D.rle_to_wn('31313133')
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_wn_pair
|
53
|
+
assert_equal 'wn', Barcode1DTools::Barcode1D.wn_pair
|
54
|
+
assert_equal '65', Barcode1DTools::Barcode1D.wn_pair({ :n_character => '5', :w_character => '6' })
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require 'barcode1dtools'
|
10
|
+
|
11
|
+
class Barcode1DToolsEAN13Test < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a random EAN-13 sans checksum
|
19
|
+
def random_12_digit_number
|
20
|
+
(0..11).collect { |x| ((rand * 10).to_i % 10).to_s }.join
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_checksum_generation
|
24
|
+
assert_equal 7, Barcode1DTools::EAN13.generate_check_digit_for('007820601001')
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_checksum_validation
|
28
|
+
assert Barcode1DTools::EAN13.validate_check_digit_for('0884088516338')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_attr_readers
|
32
|
+
ean = Barcode1DTools::EAN13.new('088408851633', :checksum_included => false)
|
33
|
+
assert_equal 8, ean.check_digit
|
34
|
+
assert_equal '088408851633', ean.value
|
35
|
+
assert_equal '0884088516338', ean.encoded_string
|
36
|
+
assert_equal '08', ean.number_system
|
37
|
+
assert_equal '84088', ean.manufacturers_code
|
38
|
+
assert_equal '51633', ean.product_code
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_value_fixup
|
42
|
+
ean = Barcode1DTools::EAN13.new('088408851633', :checksum_included => false)
|
43
|
+
assert_equal 8, ean.check_digit
|
44
|
+
assert_equal '088408851633', ean.value
|
45
|
+
assert_equal '0884088516338', ean.encoded_string
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_checksum_error
|
49
|
+
# proper checksum is 8
|
50
|
+
assert_raise(Barcode1DTools::ChecksumError) { Barcode1DTools::EAN13.new('0884088516331', :checksum_included => true) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_value_length_errors
|
54
|
+
# One digit too short
|
55
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.new('01234567890', :checksum_included => false) }
|
56
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.new('012345678901', :checksum_included => true) }
|
57
|
+
# One digit too long
|
58
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.new('0123456789012', :checksum_included => false) }
|
59
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.new('01234567890123', :checksum_included => true) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_bad_character_errors
|
63
|
+
# Characters that cannot be encoded
|
64
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.new('thisisnotgood', :checksum_included => false) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_width
|
68
|
+
ean = Barcode1DTools::EAN13.new('0041343005796', :checksum_included => true)
|
69
|
+
assert_equal 95, ean.width
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_barcode_generation
|
73
|
+
ean = Barcode1DTools::EAN13.new('0012676510226', :checksum_included => true)
|
74
|
+
assert_equal "10100011010011001001001101011110111011010111101010100111011001101110010110110011011001010000101", ean.bars
|
75
|
+
assert_equal "11132112221212211141312111411111123122213211212221221114111", ean.rle
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_wn_raises_error
|
79
|
+
ean = Barcode1DTools::EAN13.new('0012676510226', :checksum_included => true)
|
80
|
+
assert_raise(Barcode1DTools::NotImplementedError) { ean.wn }
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_decode_error
|
84
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.decode('x') }
|
85
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.decode('x'*60) }
|
86
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.decode('x'*96) }
|
87
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.decode('x'*94) }
|
88
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN13.decode('111000011111000011111') }
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_decoding
|
92
|
+
random_ean_num=random_12_digit_number
|
93
|
+
ean = Barcode1DTools::EAN13.new(random_ean_num)
|
94
|
+
ean2 = Barcode1DTools::EAN13.decode(ean.bars)
|
95
|
+
assert_equal ean.value, ean2.value
|
96
|
+
ean3 = Barcode1DTools::EAN13.decode(ean.rle)
|
97
|
+
assert_equal ean.value, ean3.value
|
98
|
+
# Should also work in reverse
|
99
|
+
ean4 = Barcode1DTools::EAN13.decode(ean.bars.reverse)
|
100
|
+
assert_equal ean.value, ean4.value
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 Michael Chaney Consulting Corporation
|
3
|
+
#
|
4
|
+
# Released under the terms of the MIT License or the GNU
|
5
|
+
# General Public License, v. 2
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require 'barcode1dtools'
|
10
|
+
|
11
|
+
class Barcode1DToolsEAN8Test < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a random EAN-8 sans checksum
|
19
|
+
def random_7_digit_number
|
20
|
+
sprintf('%07d',rand(10000000))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_checksum_generation
|
24
|
+
assert_equal 4, Barcode1DTools::EAN8.generate_check_digit_for('9638507')
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_checksum_validation
|
28
|
+
assert Barcode1DTools::EAN8.validate_check_digit_for('96385074')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_attr_readers
|
32
|
+
ean = Barcode1DTools::EAN8.new('9638507', :checksum_included => false)
|
33
|
+
assert_equal 4, ean.check_digit
|
34
|
+
assert_equal '9638507', ean.value
|
35
|
+
assert_equal '96385074', ean.encoded_string
|
36
|
+
assert_equal '963', ean.number_system
|
37
|
+
assert_equal '8507', ean.product_code
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_checksum_error
|
41
|
+
# proper checksum is 4
|
42
|
+
assert_raise(Barcode1DTools::ChecksumError) { Barcode1DTools::EAN8.new('96385070', :checksum_included => true) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_value_length_errors
|
46
|
+
# One digit too short
|
47
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.new('123456', :checksum_included => false) }
|
48
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.new('1234567', :checksum_included => true) }
|
49
|
+
# One digit too long
|
50
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.new('12345678', :checksum_included => false) }
|
51
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.new('123456789', :checksum_included => true) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_bad_character_errors
|
55
|
+
# Characters that cannot be encoded
|
56
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.new('thisisnotgood', :checksum_included => false) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_width
|
60
|
+
ean = Barcode1DTools::EAN8.new(random_7_digit_number)
|
61
|
+
assert_equal 67, ean.width
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_barcode_generation
|
65
|
+
ean = Barcode1DTools::EAN8.new('96385074', :checksum_included => true)
|
66
|
+
assert_equal "1010001011010111101111010110111010101001110111001010001001011100101", ean.bars
|
67
|
+
|
68
|
+
assert_equal "1113112111414111213111111231321113121132111", ean.rle
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_wn_raises_error
|
72
|
+
ean = Barcode1DTools::EAN8.new(random_7_digit_number)
|
73
|
+
assert_raise(Barcode1DTools::NotImplementedError) { ean.wn }
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_decode_error
|
77
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.decode('x') }
|
78
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.decode('x'*60) }
|
79
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.decode('x'*96) }
|
80
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.decode('x'*94) }
|
81
|
+
assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::EAN8.decode('111000011111000011111') }
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_decoding
|
85
|
+
random_ean_num=random_7_digit_number
|
86
|
+
ean = Barcode1DTools::EAN8.new(random_ean_num)
|
87
|
+
ean2 = Barcode1DTools::EAN8.decode(ean.bars)
|
88
|
+
assert_equal ean.value, ean2.value
|
89
|
+
ean3 = Barcode1DTools::EAN8.decode(ean.rle)
|
90
|
+
assert_equal ean.value, ean3.value
|
91
|
+
# Should also work in reverse
|
92
|
+
ean4 = Barcode1DTools::EAN8.decode(ean.bars.reverse)
|
93
|
+
assert_equal ean.value, ean4.value
|
94
|
+
end
|
95
|
+
end
|