Skip to content

Commit 97a2d6b

Browse files
author
Dongri Jin
authored
Merge pull request #35 from georgepsarakis/fix-iso3166-race-condition
Fix data race when calling `GetISO3166`
2 parents 300a6e9 + b3ac1c1 commit 97a2d6b

File tree

3 files changed

+81
-58
lines changed

3 files changed

+81
-58
lines changed

.github/workflows/run-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ jobs:
2222
go-version: 1.19
2323

2424
- name: Test
25-
run: go test -v
25+
run: go test -v -race

iso3166.go

+15-5
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,27 @@ type ISO3166 struct {
1010
PhoneNumberLengths []int
1111
}
1212

13+
func init() {
14+
// Run once during package initialization in order to avoid data races
15+
// https://go.dev/doc/effective_go#init
16+
populateISO3166()
17+
}
18+
1319
var iso3166Datas []ISO3166
1420

15-
// GetISO3166 ...
21+
// GetISO3166 returns the ISO3166 configuration for each country.
22+
// Data are loaded during package initialization.
1623
func GetISO3166() []ISO3166 {
24+
return iso3166Datas
25+
}
26+
27+
// populateISO3166 contains the definitions of the per-country mobile number configuration.
28+
// It operates on the iso3166Datas global variable and will return it after population.
29+
func populateISO3166() {
1730
if iso3166Datas != nil {
18-
return iso3166Datas
31+
return
1932
}
2033

21-
iso3166Datas = []ISO3166{}
2234
var i = ISO3166{}
2335

2436
i.Alpha2 = "US"
@@ -1871,6 +1883,4 @@ func GetISO3166() []ISO3166 {
18711883
i.MobileBeginWith = []string{"71", "73", "77"}
18721884
i.PhoneNumberLengths = []int{9}
18731885
iso3166Datas = append(iso3166Datas, i)
1874-
1875-
return iso3166Datas
18761886
}

phonenumber_test.go

+65-52
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,54 @@ import (
44
"testing"
55
)
66

7+
// Get country by mobile number only
8+
var mobWithLLCountryTests = []struct {
9+
input string
10+
expected string
11+
}{
12+
// landline numbers
13+
{"3726347343", "EE"},
14+
{"74997098833", "RU"},
15+
{"37167881727", "LV"},
16+
{"16466909997", "US"},
17+
{"14378869667", "CA"},
18+
{"12836907618", "US"},
19+
{"13406407159", "VI"},
20+
{"5117061970", "PE"},
21+
{"862185551232", "CN"},
22+
{"38391234999", "XK"},
23+
24+
// Mobile numbers
25+
{"39339638066", "IT"},
26+
{"37125641580", "LV"},
27+
{"43663242739", "AT"},
28+
{"21655886170", "TN"},
29+
{"3197010280754", "NL"},
30+
{"51999400500", "PE"},
31+
{"8614855512329", "CN"},
32+
{"38342224999", "XK"},
33+
}
34+
35+
func TestGetCountryForMobileNumberWithLandLine(t *testing.T) {
36+
for _, tt := range mobWithLLCountryTests {
37+
tt := tt
38+
t.Run(tt.input, func(t *testing.T) {
39+
t.Parallel()
40+
country := GetISO3166ByNumber(tt.input, true)
41+
if tt.expected == "" {
42+
if country.CountryName != "" {
43+
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): must be empty, actual `%s`", tt.input, country.CountryName)
44+
}
45+
} else {
46+
expected := getISO3166ByCountry(tt.expected)
47+
if country.CountryName != expected.CountryName {
48+
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): expected `%s`, actual `%s`", tt.input, expected.CountryName, country.CountryName)
49+
}
50+
}
51+
})
52+
}
53+
}
54+
755
// Tests format mobile
856
var mobFormatTests = []struct {
957
input string
@@ -26,10 +74,14 @@ var mobFormatTests = []struct {
2674

2775
func TestFormatMobile(t *testing.T) {
2876
for _, tt := range mobFormatTests {
29-
number := Parse(tt.input, tt.country)
30-
if number != tt.expected {
31-
t.Errorf("Parse(number=`%s`, country=`%s`): expected `%s`, actual `%s`", tt.input, tt.country, tt.expected, number)
32-
}
77+
tt := tt
78+
t.Run(tt.input, func(t *testing.T) {
79+
t.Parallel()
80+
number := Parse(tt.input, tt.country)
81+
if number != tt.expected {
82+
t.Errorf("Parse(number=`%s`, country=`%s`): expected `%s`, actual `%s`", tt.input, tt.country, tt.expected, number)
83+
}
84+
})
3385
}
3486
}
3587

@@ -99,50 +151,6 @@ func TestFormatWithLandLine(t *testing.T) {
99151
}
100152
}
101153

102-
// Get country by mobile number only
103-
var mobWithLLCountryTests = []struct {
104-
input string
105-
expected string
106-
}{
107-
// landline numbers
108-
{"3726347343", "EE"},
109-
{"74997098833", "RU"},
110-
{"37167881727", "LV"},
111-
{"16466909997", "US"},
112-
{"14378869667", "CA"},
113-
{"12836907618", "US"},
114-
{"13406407159", "VI"},
115-
{"5117061970", "PE"},
116-
{"862185551232", "CN"},
117-
{"38391234999", "XK"},
118-
119-
// Mobile numbers
120-
{"39339638066", "IT"},
121-
{"37125641580", "LV"},
122-
{"43663242739", "AT"},
123-
{"21655886170", "TN"},
124-
{"3197010280754", "NL"},
125-
{"51999400500", "PE"},
126-
{"8614855512329", "CN"},
127-
{"38342224999", "XK"},
128-
}
129-
130-
func TestGetCountryForMobileNumberWithLandLine(t *testing.T) {
131-
for _, tt := range mobWithLLCountryTests {
132-
country := GetISO3166ByNumber(tt.input, true)
133-
if tt.expected == "" {
134-
if country.CountryName != "" {
135-
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): must be empty, actual `%s`", tt.input, country.CountryName)
136-
}
137-
} else {
138-
expected := getISO3166ByCountry(tt.expected)
139-
if country.CountryName != expected.CountryName {
140-
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): expected `%s`, actual `%s`", tt.input, expected.CountryName, country.CountryName)
141-
}
142-
}
143-
}
144-
}
145-
146154
// Test the real and validated mobile number for India country
147155
// We added "910" prefix that does not match a specification, but the numbers are really exists
148156
var indiaMobileTests = []struct {
@@ -252,10 +260,15 @@ var indiaMobileTests = []struct {
252260

253261
func TestIndiaMobileNumber(t *testing.T) {
254262
for _, tt := range indiaMobileTests {
255-
country := GetISO3166ByNumber(tt.input, false)
256-
if country.CountryName != "India" {
257-
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): expected `%s`, actual `%s`", tt.input, "India", country.CountryName)
258-
}
263+
tt := tt
264+
t.Run(tt.input, func(t *testing.T) {
265+
t.Parallel()
266+
267+
country := GetISO3166ByNumber(tt.input, false)
268+
if country.CountryName != "India" {
269+
t.Errorf("GetISO3166ByNumber(number=`%s`, withLandline=false): expected `%s`, actual `%s`", tt.input, "India", country.CountryName)
270+
}
271+
})
259272
}
260273
}
261274

0 commit comments

Comments
 (0)