tracking_number 0.10.5 → 3.0.0
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.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +2 -0
- data/.github/dependabot.yml +22 -0
- data/.github/workflows/release.yml +36 -0
- data/.github/workflows/ruby.yml +35 -0
- data/.gitmodules +3 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +318 -0
- data/Gemfile +4 -2
- data/README.md +112 -15
- data/Rakefile +4 -1
- data/bin/console +14 -0
- data/lib/data/couriers/amazon.json +45 -0
- data/lib/data/couriers/canadapost.json +33 -0
- data/lib/data/couriers/canpar.json +29 -0
- data/lib/data/couriers/dhl.json +97 -0
- data/lib/data/couriers/dpd.json +345 -0
- data/lib/data/couriers/fedex.json +291 -0
- data/lib/data/couriers/gofo.json +24 -0
- data/lib/data/couriers/landmark.json +26 -0
- data/lib/data/couriers/lasership.json +105 -0
- data/lib/data/couriers/old_dominion.json +65 -0
- data/lib/data/couriers/ontrac.json +74 -0
- data/lib/data/couriers/purolator.json +50 -0
- data/lib/data/couriers/s10.json +1443 -0
- data/lib/data/couriers/speedee.json +26 -0
- data/lib/data/couriers/ups.json +197 -0
- data/lib/data/couriers/usps.json +272 -0
- data/lib/data/couriers/yodel.json +29 -0
- data/lib/data/couriers/yunexpress.json +25 -0
- data/lib/tracking_number/active_model_validator.rb +1 -1
- data/lib/tracking_number/base.rb +291 -22
- data/lib/tracking_number/checksum_validations.rb +119 -0
- data/lib/tracking_number/info.rb +26 -0
- data/lib/tracking_number/loader.rb +82 -0
- data/lib/tracking_number/partnership.rb +7 -0
- data/lib/tracking_number/unknown.rb +45 -0
- data/lib/tracking_number/version.rb +1 -1
- data/lib/tracking_number.rb +69 -17
- data/package.json +77 -0
- data/test/partnership_test.rb +71 -0
- data/test/renamed_types_test.rb +44 -0
- data/test/test_helper.rb +14 -7
- data/test/tracking_number_meta_test.rb +145 -0
- data/test/tracking_number_test.rb +191 -0
- data/tracking_number.gemspec +53 -22
- data/yarn.lock +3425 -0
- metadata +131 -46
- data/.travis.yml +0 -12
- data/VERSION +0 -1
- data/lib/tracking_number/dhl.rb +0 -34
- data/lib/tracking_number/fedex.rb +0 -156
- data/lib/tracking_number/ontrac.rb +0 -34
- data/lib/tracking_number/ups.rb +0 -108
- data/lib/tracking_number/usps.rb +0 -166
- data/test/dhl_tracking_number_test.rb +0 -35
- data/test/fedex_tracking_number_test.rb +0 -75
- data/test/ontrac_tracking_number_test.rb +0 -24
- data/test/ups_tracking_number_test.rb +0 -36
- data/test/usps_tracking_number_test.rb +0 -73
data/lib/tracking_number.rb
CHANGED
|
@@ -1,36 +1,88 @@
|
|
|
1
1
|
# Identify if tracking numbers are valid, and which service they belong to
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'tracking_number/checksum_validations'
|
|
5
|
+
require 'tracking_number/loader'
|
|
6
6
|
require 'tracking_number/base'
|
|
7
|
-
require 'tracking_number/
|
|
8
|
-
require 'tracking_number/
|
|
9
|
-
require 'tracking_number/
|
|
10
|
-
require '
|
|
11
|
-
require 'tracking_number/ontrac'
|
|
7
|
+
require 'tracking_number/info'
|
|
8
|
+
require 'tracking_number/partnership'
|
|
9
|
+
require 'tracking_number/unknown'
|
|
10
|
+
require 'active_support/all'
|
|
12
11
|
|
|
13
12
|
if defined?(ActiveModel::EachValidator)
|
|
14
13
|
require 'tracking_number/active_model_validator'
|
|
15
14
|
end
|
|
16
15
|
|
|
16
|
+
TrackingNumber::Loader.load_tracking_number_data
|
|
17
|
+
|
|
17
18
|
module TrackingNumber
|
|
18
|
-
|
|
19
|
+
def self.search(body, match: :carrier)
|
|
20
|
+
matches = TYPES.collect { |type| type.search(body) }.flatten
|
|
21
|
+
|
|
22
|
+
# Some tracking numbers (e.g. Fedex Smartpost) are partnerships between two parties, where one party is the shipper (e.g. Fedex)
|
|
23
|
+
# and the other party is the [last mile] carrier (e.g. USPS). We're probably interested in the last mile aspect of
|
|
24
|
+
# the partnership, so by default we'll show those
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
# Tracking numbers without a partnership are both the shipper and carrier.
|
|
27
|
+
|
|
28
|
+
case match
|
|
29
|
+
when :carrier
|
|
30
|
+
matches.filter(&:carrier?)
|
|
31
|
+
when :shipper
|
|
32
|
+
matches.filter(&:shipper?)
|
|
33
|
+
when :all
|
|
34
|
+
matches
|
|
35
|
+
else
|
|
36
|
+
matches
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.detect(tracking_number, match: :carrier)
|
|
41
|
+
all_matches = search(tracking_number, match: match)
|
|
42
|
+
|
|
43
|
+
if all_matches.empty?
|
|
44
|
+
Unknown.new(tracking_number)
|
|
45
|
+
else
|
|
46
|
+
all_matches.max_by(&:confidence)
|
|
47
|
+
end
|
|
22
48
|
end
|
|
23
49
|
|
|
24
|
-
def self.
|
|
25
|
-
|
|
26
|
-
|
|
50
|
+
def self.detect_all(tracking_number)
|
|
51
|
+
matches = []
|
|
52
|
+
(TYPES + [Unknown]).each do |test_klass|
|
|
27
53
|
tn = test_klass.new(tracking_number)
|
|
28
|
-
|
|
54
|
+
matches << tn if tn.valid?
|
|
29
55
|
end
|
|
30
|
-
|
|
56
|
+
|
|
57
|
+
matches
|
|
31
58
|
end
|
|
32
59
|
|
|
33
60
|
def self.new(tracking_number)
|
|
34
|
-
|
|
61
|
+
detect(tracking_number)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Renamed in tracking_number_data 2.0. The old constant still describes the same barcode.
|
|
65
|
+
RENAMED_TYPES = { USPS91: :USPSIMpbC, USPS22: :USPSIMpbN, USPS34v2: :USPSIMpbC }.freeze
|
|
66
|
+
|
|
67
|
+
# Removed in tracking_number_data 2.0. An alias would answer is_a? for every IMpb number,
|
|
68
|
+
# which is the claim the data stopped making, so these raise instead.
|
|
69
|
+
WITHDRAWN_TYPES = {
|
|
70
|
+
FedExSmartPost: 'USPSIMpbC',
|
|
71
|
+
DHLECommerce30: 'USPSIMpbC'
|
|
72
|
+
}.freeze
|
|
73
|
+
|
|
74
|
+
def self.const_missing(name)
|
|
75
|
+
if (renamed = RENAMED_TYPES[name])
|
|
76
|
+
warn "TrackingNumber::#{name} is now TrackingNumber::#{renamed}"
|
|
77
|
+
return const_get(renamed)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if (replacement = WITHDRAWN_TYPES[name])
|
|
81
|
+
raise NameError, "TrackingNumber::#{name} no longer exists. These are USPS IMpb barcodes " \
|
|
82
|
+
"carrying nothing that identifies the shipper, so they now decode as " \
|
|
83
|
+
"TrackingNumber::#{replacement}."
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
super
|
|
35
87
|
end
|
|
36
88
|
end
|
data/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tracking_number",
|
|
3
|
+
"version": "1.x.x-semantic-release",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/jkeen/tracking_number.git"
|
|
7
|
+
},
|
|
8
|
+
"author": "jkeen",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/jkeen/tracking_number/issues"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/jkeen/tracking_number#readme",
|
|
14
|
+
"scripts": {
|
|
15
|
+
"semantic-release": "semantic-release"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@semantic-release/changelog": "^6.0.1",
|
|
19
|
+
"@semantic-release/git": "^10.0.1",
|
|
20
|
+
"semantic-release": "^19.0.3",
|
|
21
|
+
"semantic-release-rubygem": "^1.2.0"
|
|
22
|
+
},
|
|
23
|
+
"release": {
|
|
24
|
+
"branches": [
|
|
25
|
+
"main"
|
|
26
|
+
],
|
|
27
|
+
"plugins": [
|
|
28
|
+
[
|
|
29
|
+
"@semantic-release/commit-analyzer",
|
|
30
|
+
{
|
|
31
|
+
"releaseRules": [
|
|
32
|
+
{
|
|
33
|
+
"type": "*!",
|
|
34
|
+
"release": "major"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "feat",
|
|
38
|
+
"release": "minor"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "fix",
|
|
42
|
+
"release": "patch"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"parserOpts": {
|
|
46
|
+
"noteKeywords": [
|
|
47
|
+
"BREAKING CHANGE",
|
|
48
|
+
"BREAKING CHANGES",
|
|
49
|
+
"BREAKING"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"@semantic-release/release-notes-generator",
|
|
55
|
+
[
|
|
56
|
+
"@semantic-release/changelog",
|
|
57
|
+
{
|
|
58
|
+
"changelogTitle": "tracking_number changelog",
|
|
59
|
+
"changelogFile": "CHANGELOG.md"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"semantic-release-rubygem",
|
|
63
|
+
"@semantic-release/github",
|
|
64
|
+
[
|
|
65
|
+
"@semantic-release/git",
|
|
66
|
+
{
|
|
67
|
+
"assets": [
|
|
68
|
+
"CHANGELOG.md"
|
|
69
|
+
],
|
|
70
|
+
"message": "${nextRelease.version} CHANGELOG [skip ci]\n\n${nextRelease.notes}"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
],
|
|
74
|
+
"debug": false,
|
|
75
|
+
"dryRun": false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
|
2
|
+
|
|
3
|
+
# No shipped definition declares partners currently at the tracking number data 2.0 release,
|
|
4
|
+
# but the concept is still supported in the data spec, and should be tested, so we're faking it here
|
|
5
|
+
|
|
6
|
+
class PartnershipTest < Minitest::Test
|
|
7
|
+
NUMBER = 'ZZ1234567890'.freeze
|
|
8
|
+
|
|
9
|
+
def setup
|
|
10
|
+
@shipper = build_class('test_shipper', partner_id: 'test_carrier', partner_type: 'carrier')
|
|
11
|
+
@carrier = build_class('test_carrier', partner_id: 'test_shipper', partner_type: 'shipper')
|
|
12
|
+
|
|
13
|
+
TrackingNumber::TYPES.push(@shipper, @carrier)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def teardown
|
|
17
|
+
TrackingNumber::TYPES.delete(@shipper)
|
|
18
|
+
TrackingNumber::TYPES.delete(@carrier)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
should "report a partnership from both sides" do
|
|
22
|
+
assert @shipper.new(NUMBER).partnership?
|
|
23
|
+
assert @carrier.new(NUMBER).partnership?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should "pair each side with the other" do
|
|
27
|
+
partners = @carrier.new(NUMBER).partners
|
|
28
|
+
|
|
29
|
+
assert_instance_of @shipper, partners.shipper
|
|
30
|
+
assert_instance_of @carrier, partners.carrier
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
should "report which side of the partnership each is" do
|
|
34
|
+
assert @shipper.new(NUMBER).shipper?
|
|
35
|
+
assert !@shipper.new(NUMBER).carrier?
|
|
36
|
+
|
|
37
|
+
assert @carrier.new(NUMBER).carrier?
|
|
38
|
+
assert !@carrier.new(NUMBER).shipper?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
should "only match the carrier side when searching by default" do
|
|
42
|
+
matches = TrackingNumber.search("shipped as #{NUMBER} today")
|
|
43
|
+
|
|
44
|
+
assert_equal [@carrier], matches.collect(&:class)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
should "match both sides when searching for all" do
|
|
48
|
+
matches = TrackingNumber.search("shipped as #{NUMBER} today", match: :all)
|
|
49
|
+
|
|
50
|
+
assert_equal [@shipper, @carrier], matches.collect(&:class)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def build_class(id, partner_id:, partner_type:)
|
|
56
|
+
pattern = 'Z\s*Z\s*(?<SerialNumber>([0-9]\s*){10})'
|
|
57
|
+
|
|
58
|
+
klass = Class.new(TrackingNumber::Base)
|
|
59
|
+
klass.const_set('ID', id)
|
|
60
|
+
klass.const_set('COURIER_CODE', id.to_sym)
|
|
61
|
+
klass.const_set('COURIER_INFO', name: id, courier_code: id.to_sym)
|
|
62
|
+
klass.const_set('SEARCH_PATTERN', Regexp.new("\\b#{pattern}\\b"))
|
|
63
|
+
klass.const_set('VERIFY_PATTERN', Regexp.new("^#{pattern}$"))
|
|
64
|
+
klass.const_set('VALIDATION', {})
|
|
65
|
+
klass.const_set('ADDITIONAL', nil)
|
|
66
|
+
klass.const_set('TRACKING_URL', nil)
|
|
67
|
+
klass.const_set('PARTNERS', [{ partner_id: partner_id, partner_type: partner_type }])
|
|
68
|
+
|
|
69
|
+
klass
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
|
2
|
+
|
|
3
|
+
class RenamedTypesTest < Minitest::Test
|
|
4
|
+
NUMBER = '420112139261290983497923666238'.freeze
|
|
5
|
+
|
|
6
|
+
should "resolve a renamed constant to the definition that replaced it" do
|
|
7
|
+
assert_equal TrackingNumber::USPSIMpbC, silenced { TrackingNumber::USPS91 }
|
|
8
|
+
assert_equal TrackingNumber::USPSIMpbN, silenced { TrackingNumber::USPS22 }
|
|
9
|
+
assert_equal TrackingNumber::USPSIMpbC, silenced { TrackingNumber::USPS34v2 }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
should "keep is_a? answering for a renamed constant" do
|
|
13
|
+
assert TrackingNumber.new(NUMBER).is_a?(silenced { TrackingNumber::USPS91 })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
should "warn once a renamed constant is reached for" do
|
|
17
|
+
_, err = capture_io { TrackingNumber::USPS91 }
|
|
18
|
+
|
|
19
|
+
assert_match(/USPS91 is now TrackingNumber::USPSIMpbC/, err)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# An alias would answer is_a? for every IMpb number, including labels these carriers never touched
|
|
23
|
+
should "refuse a withdrawn constant and name its replacement" do
|
|
24
|
+
error = assert_raises(NameError) { TrackingNumber::FedExSmartPost }
|
|
25
|
+
assert_match(/no longer exists/, error.message)
|
|
26
|
+
assert_match(/USPSIMpbC/, error.message)
|
|
27
|
+
|
|
28
|
+
assert_raises(NameError) { TrackingNumber::DHLECommerce30 }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
should "leave an unrelated missing constant alone" do
|
|
32
|
+
error = assert_raises(NameError) { TrackingNumber::NotADefinition }
|
|
33
|
+
|
|
34
|
+
assert_match(/uninitialized constant/, error.message)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def silenced
|
|
40
|
+
resolved = nil
|
|
41
|
+
capture_io { resolved = yield }
|
|
42
|
+
resolved
|
|
43
|
+
end
|
|
44
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'simplecov'
|
|
|
2
2
|
SimpleCov.start
|
|
3
3
|
require 'rubygems'
|
|
4
4
|
require 'minitest/autorun'
|
|
5
|
+
require 'minitest/reporters'
|
|
5
6
|
require 'shoulda'
|
|
6
7
|
require 'active_model'
|
|
7
8
|
|
|
@@ -9,14 +10,14 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
|
9
10
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
10
11
|
require 'tracking_number'
|
|
11
12
|
|
|
13
|
+
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(:color => true)]
|
|
14
|
+
|
|
12
15
|
class Minitest::Test
|
|
13
16
|
def possible_numbers(tracking)
|
|
14
17
|
tracking = tracking.to_s
|
|
15
18
|
possible_numbers = []
|
|
16
19
|
possible_numbers << tracking
|
|
17
20
|
possible_numbers << tracking.to_s.gsub(" ", "")
|
|
18
|
-
possible_numbers << tracking.chars.to_a.join(" ")
|
|
19
|
-
possible_numbers << tracking.chars.to_a.join(" ")
|
|
20
21
|
possible_numbers << tracking.slice(0, (tracking.length / 2)) + " " + tracking.slice((tracking.length / 2), tracking.length)
|
|
21
22
|
|
|
22
23
|
possible_numbers.flatten.uniq
|
|
@@ -33,7 +34,7 @@ class Minitest::Test
|
|
|
33
34
|
def should_detect_number_variants(valid_number, type)
|
|
34
35
|
possible_strings(valid_number).each do |string|
|
|
35
36
|
results = type.search(string)
|
|
36
|
-
assert_equal 1, results.size, "could not find #{type} #{valid_number} in #{string}"
|
|
37
|
+
assert_equal 1, results.size, "could not find #{type} #{valid_number} in #{string} using search regex: #{type::SEARCH_PATTERN}"
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
|
|
@@ -44,10 +45,16 @@ class Minitest::Test
|
|
|
44
45
|
assert t.valid?
|
|
45
46
|
end
|
|
46
47
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
def should_be_invalid_number(invalid_number, type, carrier)
|
|
49
|
+
t = TrackingNumber.new(invalid_number)
|
|
50
|
+
assert !t.valid?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def should_fail_on_check_digit_changes(valid_number, klass)
|
|
54
|
+
digits = valid_number.gsub(/\s/, "").chars.compact.to_a
|
|
55
|
+
position = digits.join.match(klass::VERIFY_PATTERN).begin("CheckDigit")
|
|
56
|
+
current = digits[position].to_i
|
|
57
|
+
digits[position] = (current <= 2 ? current + 3 : current - 3).to_s
|
|
51
58
|
invalid_number = digits.join
|
|
52
59
|
t = TrackingNumber.new(invalid_number)
|
|
53
60
|
assert !t.valid?, "#{invalid_number} reported as a valid #{t.class}, and it shouldn't be"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
def load_courier_data(name = :all)
|
|
4
|
+
if name == :all
|
|
5
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../lib/data/couriers/*.json")).collect do |file|
|
|
6
|
+
JSON.parse(File.read(file)).deep_symbolize_keys!
|
|
7
|
+
end
|
|
8
|
+
else
|
|
9
|
+
return JSON.parse(File.join(File.dirname(__FILE__), "../lib/data/couriers/#{name}.json"))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class TrackingNumberMetaTest < Minitest::Test
|
|
14
|
+
load_courier_data(:all).each do |courier_info|
|
|
15
|
+
courier_name = courier_info[:name]
|
|
16
|
+
courier_code = courier_info[:courier_code].to_sym
|
|
17
|
+
|
|
18
|
+
courier_info[:tracking_numbers].each do |tracking_info|
|
|
19
|
+
klass_name = tracking_info[:name].gsub(/[^0-9A-Za-z]/, '')
|
|
20
|
+
klass = "TrackingNumber::#{klass_name}".constantize
|
|
21
|
+
|
|
22
|
+
describe "[#{tracking_info[:name]}]" do
|
|
23
|
+
tracking_info[:test_numbers][:valid].each do |valid_number|
|
|
24
|
+
should "detect #{valid_number} as #{klass_name}" do
|
|
25
|
+
#TODO fix this multiple matching thing
|
|
26
|
+
matches = TrackingNumber.search(valid_number, match: :all)
|
|
27
|
+
assert matches.collect(&:class).include?(klass)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if tracking_info[:validation][:checksum]
|
|
31
|
+
# only run this test if number format has checksum
|
|
32
|
+
should "fail on check digit changes with #{valid_number}" do
|
|
33
|
+
should_fail_on_check_digit_changes(valid_number, klass)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
should "detect #{valid_number} regardless of spacing" do
|
|
38
|
+
should_detect_number_variants(valid_number, "TrackingNumber::#{klass_name}".constantize)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "number test" do
|
|
42
|
+
tracking_number = klass.new(valid_number)
|
|
43
|
+
|
|
44
|
+
should "validate #{valid_number} with #{klass_name}" do
|
|
45
|
+
assert_equal courier_code, tracking_number.carrier
|
|
46
|
+
assert tracking_number.valid?, "should be valid"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
should "return correct courier code on #{valid_number} when calling #courier_code" do
|
|
50
|
+
tracking_number = klass.new(valid_number)
|
|
51
|
+
assert_equal courier_info[:courier_code].to_sym, tracking_number.courier_code
|
|
52
|
+
assert_equal courier_info[:courier_code].to_sym,tracking_number.courier_code
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
should "return correct courier name on #{valid_number} when calling #courier_name" do
|
|
56
|
+
if (tracking_number.matching_additional["Courier"])
|
|
57
|
+
assert_equal tracking_number.matching_additional["Courier"][:courier], tracking_number.courier_name
|
|
58
|
+
else
|
|
59
|
+
assert_equal courier_name, tracking_number.courier_name
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
should "not throw an error when calling #service_type on #{valid_number}" do
|
|
64
|
+
service_type = tracking_number.service_type
|
|
65
|
+
assert service_type.is_a?(String) || service_type.nil?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
should "not throw an error when calling #destination on #{valid_number}" do
|
|
69
|
+
assert tracking_number.destination_zip.is_a?(String) || tracking_number.destination_zip.nil?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
should "not throw an error when calling #shipper on #{valid_number}" do
|
|
73
|
+
t = klass.new(valid_number)
|
|
74
|
+
assert tracking_number.shipper_id.is_a?(String) || tracking_number.shipper_id.nil?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
should "not throw an error when calling #package_type on #{valid_number}" do
|
|
78
|
+
t = klass.new(valid_number)
|
|
79
|
+
assert tracking_number.package_type.is_a?(String) || tracking_number.package_type.nil?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
should "not throw an error when calling #decode on #{valid_number}" do
|
|
83
|
+
t = klass.new(valid_number)
|
|
84
|
+
decode = tracking_number.decode
|
|
85
|
+
assert decode.is_a?(Hash)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
tracking_info[:test_numbers][:invalid].each do |invalid_number|
|
|
92
|
+
should "not validate #{invalid_number} with #{klass_name}" do
|
|
93
|
+
t = klass.new(invalid_number)
|
|
94
|
+
assert !t.valid?, "should not be valid"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
should "not throw an error when calling #service_type on invalid number #{invalid_number}" do
|
|
98
|
+
t = klass.new(invalid_number)
|
|
99
|
+
service_type = t.service_type
|
|
100
|
+
assert service_type.is_a?(String) || service_type.nil?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
should "not throw an error when calling #destination_zip on invalid number #{invalid_number}" do
|
|
104
|
+
t = klass.new(invalid_number)
|
|
105
|
+
destination = t.destination_zip
|
|
106
|
+
assert destination.is_a?(String) || destination.nil?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
should "not throw an error when calling #shipper_id on invalid number #{invalid_number}" do
|
|
110
|
+
t = klass.new(invalid_number)
|
|
111
|
+
shipper = t.shipper_id
|
|
112
|
+
assert shipper.is_a?(String) || shipper.nil?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
should "not throw an error when calling #package_type on invalid number #{invalid_number}" do
|
|
116
|
+
t = klass.new(invalid_number)
|
|
117
|
+
assert t.package_type.is_a?(String) || t.package_type.nil?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
should "not throw an error when calling #decode on invalid number #{invalid_number}" do
|
|
121
|
+
t = klass.new(invalid_number)
|
|
122
|
+
decode = t.decode
|
|
123
|
+
assert decode.is_a?(Hash)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
test_numbers = []
|
|
131
|
+
load_courier_data(:all).each do |courier_info|
|
|
132
|
+
courier_info[:tracking_numbers].each do |tracking_info|
|
|
133
|
+
test_numbers << tracking_info[:test_numbers][:valid]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
test_numbers.flatten!
|
|
138
|
+
|
|
139
|
+
test_numbers.each do |number|
|
|
140
|
+
matches = TrackingNumber.detect_all(number)
|
|
141
|
+
if (matches.size > 1)
|
|
142
|
+
puts "WARNING: #{number.gsub(/\s/, '')} matched multiple types => #{matches.collect { |m| m.class.to_s.split("::").last}}"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|