From d9e10c70f050bbcced58b1bbaceb2245108c6b87 Mon Sep 17 00:00:00 2001 From: Peter Booker Date: Thu, 4 Apr 2024 12:35:36 +0100 Subject: [PATCH] Bugfix/Add More Faker Helpers (#28) * Update faker dependency * Add new types * Fix readme * Add valid Norwegian SSN * Add test for valid SSN * Remove number helpers * Prevent intermittent test failures by handling control digit of 10 * Enforce single digits from control digits --- README.md | 3 ++ go.mod | 2 +- go.sum | 2 + internal/helpers/helpers.go | 23 +++++++++++ internal/helpers/norway.go | 68 +++++++++++++++++++++++++++++++++ internal/helpers/norway_test.go | 29 ++++++++++++++ 6 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 internal/helpers/norway.go create mode 100644 internal/helpers/norway_test.go diff --git a/README.md b/README.md index 45998a1..6785192 100644 --- a/README.md +++ b/README.md @@ -138,11 +138,13 @@ Each column stores a certain type of data, be it a name, username, email, etc. T | `firstName` | `Carolina` | | `lastName` | `Kohler` | | `phoneNumber` | `+49-131-0003060` | +| `billingAddressFull` | `Carolina Kohler 6071 Heaney Island Suite 553, Ebbaville Texas 37307 JP +49-131-0003060 maritza@farrell.org` | | `addressFull` | `6071 Heaney Island Suite 553, Ebbaville Texas 37307` | | `addressStreet` | `"586 Sylvester Turnpike"` | | `addressCity` | `North Dessie` | | `addressPostCode` | `31340` | | `addressCountry` | `Uruguay` | +| `addressCountryCode` | `JP` | | `paragraph` | `Lorem ipsum dolor sit amet, fabulas nostrum recteque vel ea, sit ut nemore similique. Ad per dicam molestie, nostro constituto duo ad. Ex scripta impedit cum, vidisse feugiat vivendum cum ad, liber senserit mediocrem pro.` | | `shortString` | `wqFyJIrXYfVP7cLwqFyJIrXYfVP7cL` | | `ipv4` | `121.204.82.227` | @@ -151,6 +153,7 @@ Each column stores a certain type of data, be it a name, username, email, etc. T | `creditCardNumber` | `1234-2121-1221-1211` | | `creditCardExpiryDate` | `2015-11-11` | | `creditCardType` | `mastercard` | +| `norwegianSSN` | `07026765743` | | `purge` | | If you need another type, please feel free to add support and file a PR! diff --git a/go.mod b/go.mod index 19a196c..69066d4 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.22 require ( github.com/spf13/pflag v1.0.5 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 - syreclabs.com/go/faker v1.2.0 + syreclabs.com/go/faker v1.2.3 ) diff --git a/go.sum b/go.sum index 1aa13e7..601179b 100644 --- a/go.sum +++ b/go.sum @@ -4,3 +4,5 @@ github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryB github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= syreclabs.com/go/faker v1.2.0 h1:fy5UfSu5bOFrVpBk8I1jSgPdOLMJxM7ulKFvkh673ow= syreclabs.com/go/faker v1.2.0/go.mod h1:NAXInmkPsC2xuO5MKZFe80PUXX5LU8cFdJIHGs+nSBE= +syreclabs.com/go/faker v1.2.3 h1:HPrWtnHazIf0/bVuPZJLFrtHlBHk10hS0SB+mV8v6R4= +syreclabs.com/go/faker v1.2.3/go.mod h1:NAXInmkPsC2xuO5MKZFe80PUXX5LU8cFdJIHGs+nSBE= diff --git a/internal/helpers/helpers.go b/internal/helpers/helpers.go index acbbe1a..97f6c23 100644 --- a/internal/helpers/helpers.go +++ b/internal/helpers/helpers.go @@ -29,11 +29,13 @@ func GetFakerFuncs() map[string]func(*sqlparser.SQLVal) *sqlparser.SQLVal { "firstName": generateFirstName, "lastName": generateLastName, "phoneNumber": generatePhoneNumber, + "billingAddressFull": generateBillingAddress, "addressFull": generateAddress, "addressStreet": generateStreetAddress, "addressCity": generateCity, "addressPostCode": generatePostcode, "addressCountry": generateCountry, + "addressCountryCode": generateCountryCode, "paragraph": generateParagraph, "shortString": generateShortString, "ipv4": generateIPv4, @@ -42,6 +44,7 @@ func GetFakerFuncs() map[string]func(*sqlparser.SQLVal) *sqlparser.SQLVal { "creditCardNumber": generateCreditCardNumber, "creditCardExpiryDate": generateCreditCardExpiryDate, "creditCardType": generateCreditCardType, + "norwegianSSN": generateNorwegianSSN, "purge": generateEmptyString, } @@ -101,6 +104,18 @@ func generateIPv4(value *sqlparser.SQLVal) *sqlparser.SQLVal { return sqlparser.NewStrVal([]byte(faker.Internet().IpV4Address())) } +func generateBillingAddress(value *sqlparser.SQLVal) *sqlparser.SQLVal { + address := "" + address += " " + faker.Name().FirstName() + address += " " + faker.Name().LastName() + address += " " + faker.Address().String() + address += " " + faker.Address().CountryCode() + address += " " + faker.Internet().SafeEmail() + address += " " + faker.PhoneNumber().CellPhone() + + return sqlparser.NewStrVal([]byte(address)) +} + func generateAddress(value *sqlparser.SQLVal) *sqlparser.SQLVal { return sqlparser.NewStrVal([]byte(faker.Address().String())) } @@ -121,6 +136,10 @@ func generateCountry(value *sqlparser.SQLVal) *sqlparser.SQLVal { return sqlparser.NewStrVal([]byte(faker.Address().Country())) } +func generateCountryCode(value *sqlparser.SQLVal) *sqlparser.SQLVal { + return sqlparser.NewStrVal([]byte(faker.Address().CountryCode())) +} + func generateCreditCardNumber(value *sqlparser.SQLVal) *sqlparser.SQLVal { return sqlparser.NewStrVal([]byte(faker.Business().CreditCardNumber())) } @@ -148,3 +167,7 @@ func generateShortString(value *sqlparser.SQLVal) *sqlparser.SQLVal { func generateEmptyString(value *sqlparser.SQLVal) *sqlparser.SQLVal { return sqlparser.NewStrVal([]byte("")) } + +func generateNorwegianSSN(value *sqlparser.SQLVal) *sqlparser.SQLVal { + return sqlparser.NewStrVal([]byte(generateFakeNorwegianSSN(faker.Date().Birthday(18, 90)))) +} diff --git a/internal/helpers/norway.go b/internal/helpers/norway.go new file mode 100644 index 0000000..4a35556 --- /dev/null +++ b/internal/helpers/norway.go @@ -0,0 +1,68 @@ +package helpers + +import ( + "fmt" + "math/rand" + "time" +) + +// generateControlDigits generates the control digits for a given Norwegian SSN +func generateControlDigits(ssn string) (int, int) { + // Weights for calculating control digits + var weights1 = []int{3, 7, 6, 1, 8, 9, 4, 5, 2} + var weights2 = []int{5, 4, 3, 2, 7, 6, 5, 4, 3, 2} + + var sum1, sum2 int + for i, r := range ssn { + digit := int(r - '0') + if i < 9 { // First control digit calculation + sum1 += digit * weights1[i] + } + // Note: Second control digit calculation now includes the first control digit, but it's added outside this loop + if i < 10 { // Second control digit calculation + sum2 += digit * weights2[i] + } + } + + // Calculate control digits + control1 := 11 - (sum1 % 11) + control2 := 11 - (sum2 % 11) + + // Adjust for special cases and check for the value 10 + if control1 == 11 { + control1 = 0 + } else if control1 == 10 { + return -1, -1 // Indicate an error or invalid state + } + + // Add first control digit to sum2 before calculating control2 + sum2 += control1 * weights2[9] + control2 = 11 - (sum2 % 11) + + if control2 == 11 { + control2 = 0 + } else if control2 == 10 { + return -1, -1 // Indicate an error or invalid state + } + + return control1, control2 +} + +// generateFakeNorwegianSSN generates a fake (but valid) Norwegian SSN. +func generateFakeNorwegianSSN(dob time.Time) string { + year, month, day := dob.Date() + var ssn string + var control1, control2 int = -1, -1 + + for control1 == -1 || control2 == -1 { + individualNumber := rand.Intn(500) + ssn = fmt.Sprintf("%02d%02d%02d%03d", day, month, year%100, individualNumber) + + control1, control2 = generateControlDigits(ssn) + if control1 != -1 && control2 != -1 { + ssn += fmt.Sprintf("%01d%01d", control1, control2) + } + } + + return ssn +} diff --git a/internal/helpers/norway_test.go b/internal/helpers/norway_test.go new file mode 100644 index 0000000..14e9eba --- /dev/null +++ b/internal/helpers/norway_test.go @@ -0,0 +1,29 @@ +package helpers + +import ( + "testing" + + "syreclabs.com/go/faker" +) + +func TestSSN(t *testing.T) { + ssn := generateFakeNorwegianSSN(faker.Date().Birthday(18, 90)) + + if !isValidNorwegianSSN(ssn) { + t.Errorf("Generated SSN is invalid: %s", ssn) + } +} + +// isValidNorwegianSSN checks if a given Norwegian SSN is valid (assumes the DOB is correct, as we generate that ourselves). +func isValidNorwegianSSN(ssn string) bool { + if len(ssn) != 11 { + return false + } + + // Assuming generateControlDigits is implemented and returns control digits correctly + control1, control2 := generateControlDigits(ssn[:9]) + expectedControl1 := int(ssn[9] - '0') + expectedControl2 := int(ssn[10] - '0') + + return control1 == expectedControl1 && control2 == expectedControl2 +}