datafog-core 0.4.3__tar.gz → 0.4.4__tar.gz
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.
- {datafog_core-0.4.3 → datafog_core-0.4.4}/Cargo.lock +4 -4
- {datafog_core-0.4.3 → datafog_core-0.4.4}/PKG-INFO +21 -1
- {datafog_core-0.4.3/crates/core → datafog_core-0.4.4}/README.md +20 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/Cargo.toml +1 -1
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/Cargo.toml +1 -1
- {datafog_core-0.4.3 → datafog_core-0.4.4/crates/core}/README.md +20 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/lib.rs +208 -4
- {datafog_core-0.4.3 → datafog_core-0.4.4}/pyproject.toml +1 -1
- {datafog_core-0.4.3 → datafog_core-0.4.4}/Cargo.toml +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/src/lib.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/api_key_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/bearer_token_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/capabilities_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/credential_overlap_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/credential_uri_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/email_context_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/german_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/jwt_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/npi_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/private_key_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/requirements-typing.txt +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/synthetic_fixtures.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/test_installed.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/test_python49_integration.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/test_typing.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/us_routing_number_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/uuid_conformance.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/examples/german_benchmark.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/examples/scan_benchmark.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/api_key.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/bearer_token.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/capabilities.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/credential_uri.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/email_context.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/german.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/jwt.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/npi.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/offsets.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/private_key.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/scan_selection_tests.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/selection_tests.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/structured.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/us_routing_number.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/src/uuid.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/api_key.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/bearer_token.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/capabilities.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/credential_overlaps.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/credential_uri.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/email_context.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/german.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/jwt.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/npi.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/private_key.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/support/synthetic_fixtures.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/us_routing_number.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/crates/core/tests/uuid.rs +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/python/datafog_core/__init__.py +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/python/datafog_core/__init__.pyi +0 -0
- {datafog_core-0.4.3 → datafog_core-0.4.4}/python/datafog_core/py.typed +0 -0
|
@@ -80,7 +80,7 @@ checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d"
|
|
|
80
80
|
|
|
81
81
|
[[package]]
|
|
82
82
|
name = "datafog-core"
|
|
83
|
-
version = "0.4.
|
|
83
|
+
version = "0.4.4"
|
|
84
84
|
dependencies = [
|
|
85
85
|
"base64",
|
|
86
86
|
"futures",
|
|
@@ -94,7 +94,7 @@ dependencies = [
|
|
|
94
94
|
|
|
95
95
|
[[package]]
|
|
96
96
|
name = "datafog-core-python"
|
|
97
|
-
version = "0.4.
|
|
97
|
+
version = "0.4.4"
|
|
98
98
|
dependencies = [
|
|
99
99
|
"datafog-core",
|
|
100
100
|
"pyo3",
|
|
@@ -104,7 +104,7 @@ dependencies = [
|
|
|
104
104
|
|
|
105
105
|
[[package]]
|
|
106
106
|
name = "datafog-node"
|
|
107
|
-
version = "0.4.
|
|
107
|
+
version = "0.4.4"
|
|
108
108
|
dependencies = [
|
|
109
109
|
"datafog-core",
|
|
110
110
|
"napi",
|
|
@@ -115,7 +115,7 @@ dependencies = [
|
|
|
115
115
|
|
|
116
116
|
[[package]]
|
|
117
117
|
name = "datafog-wasm"
|
|
118
|
-
version = "0.4.
|
|
118
|
+
version = "0.4.4"
|
|
119
119
|
dependencies = [
|
|
120
120
|
"datafog-core",
|
|
121
121
|
"serde",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datafog-core
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -38,6 +38,13 @@ existing detectors and returns field paths plus string-local findings. No model
|
|
|
38
38
|
or dictionary download is needed. See [person-field discovery](docs/guides/person-discovery.mdx)
|
|
39
39
|
for `scan_structured` / `scanStructured` and structured transformation APIs.
|
|
40
40
|
|
|
41
|
+
Phone candidates without `+` are interpreted as North American numbers: ten
|
|
42
|
+
digits, optionally preceded by `1`, with area and exchange codes starting with
|
|
43
|
+
`2` through `9`. Candidates starting with `+` retain the existing permissive
|
|
44
|
+
7–15 digit check, including shortened synthetic examples such as `+1-555-1002`.
|
|
45
|
+
These checks do not validate country calling codes or assigned phone numbers,
|
|
46
|
+
and numeric identifiers that fit the accepted patterns can still match `PHONE`.
|
|
47
|
+
|
|
41
48
|
Both ranges use zero-based, end-exclusive offsets. The byte range addresses the
|
|
42
49
|
UTF-8 input; the code-point range addresses Unicode scalar values. Rule-based
|
|
43
50
|
detectors currently report no confidence score. Node.js and browser WASM also
|
|
@@ -86,6 +93,19 @@ or `format: "sql"` to preserve email boundaries. See the
|
|
|
86
93
|
[email source-context policy](docs/guides/email-boundaries.mdx) for supported
|
|
87
94
|
syntax, raw escaped spans, and limitations. Default text scanning is unchanged.
|
|
88
95
|
|
|
96
|
+
## Credit-card detection and decimal numbers
|
|
97
|
+
|
|
98
|
+
To reduce decimal false positives, `CREDIT_CARD` detection suppresses contiguous
|
|
99
|
+
digit candidates immediately after a digit followed by `.` or `,`, such as
|
|
100
|
+
`3.4111111111111111` and `3,4111111111111111`. Cards containing spaces or hyphens,
|
|
101
|
+
such as `3.4111-1111-1111-1111`, still undergo the normal card checks.
|
|
102
|
+
|
|
103
|
+
In plain text, `3,4111111111111111` could also be two CSV fields: `3` and a card
|
|
104
|
+
number. The detector cannot distinguish that structure from a comma-decimal
|
|
105
|
+
number, so it suppresses the card candidate. For CSV input, parse the CSV and
|
|
106
|
+
scan each field separately so a card value is checked without the preceding
|
|
107
|
+
field and delimiter.
|
|
108
|
+
|
|
89
109
|
## Packages
|
|
90
110
|
|
|
91
111
|
| Runtime | Distribution | Import | Status |
|
|
@@ -15,6 +15,13 @@ existing detectors and returns field paths plus string-local findings. No model
|
|
|
15
15
|
or dictionary download is needed. See [person-field discovery](docs/guides/person-discovery.mdx)
|
|
16
16
|
for `scan_structured` / `scanStructured` and structured transformation APIs.
|
|
17
17
|
|
|
18
|
+
Phone candidates without `+` are interpreted as North American numbers: ten
|
|
19
|
+
digits, optionally preceded by `1`, with area and exchange codes starting with
|
|
20
|
+
`2` through `9`. Candidates starting with `+` retain the existing permissive
|
|
21
|
+
7–15 digit check, including shortened synthetic examples such as `+1-555-1002`.
|
|
22
|
+
These checks do not validate country calling codes or assigned phone numbers,
|
|
23
|
+
and numeric identifiers that fit the accepted patterns can still match `PHONE`.
|
|
24
|
+
|
|
18
25
|
Both ranges use zero-based, end-exclusive offsets. The byte range addresses the
|
|
19
26
|
UTF-8 input; the code-point range addresses Unicode scalar values. Rule-based
|
|
20
27
|
detectors currently report no confidence score. Node.js and browser WASM also
|
|
@@ -63,6 +70,19 @@ or `format: "sql"` to preserve email boundaries. See the
|
|
|
63
70
|
[email source-context policy](docs/guides/email-boundaries.mdx) for supported
|
|
64
71
|
syntax, raw escaped spans, and limitations. Default text scanning is unchanged.
|
|
65
72
|
|
|
73
|
+
## Credit-card detection and decimal numbers
|
|
74
|
+
|
|
75
|
+
To reduce decimal false positives, `CREDIT_CARD` detection suppresses contiguous
|
|
76
|
+
digit candidates immediately after a digit followed by `.` or `,`, such as
|
|
77
|
+
`3.4111111111111111` and `3,4111111111111111`. Cards containing spaces or hyphens,
|
|
78
|
+
such as `3.4111-1111-1111-1111`, still undergo the normal card checks.
|
|
79
|
+
|
|
80
|
+
In plain text, `3,4111111111111111` could also be two CSV fields: `3` and a card
|
|
81
|
+
number. The detector cannot distinguish that structure from a comma-decimal
|
|
82
|
+
number, so it suppresses the card candidate. For CSV input, parse the CSV and
|
|
83
|
+
scan each field separately so a card value is checked without the preceding
|
|
84
|
+
field and delimiter.
|
|
85
|
+
|
|
66
86
|
## Packages
|
|
67
87
|
|
|
68
88
|
| Runtime | Distribution | Import | Status |
|
|
@@ -15,6 +15,13 @@ existing detectors and returns field paths plus string-local findings. No model
|
|
|
15
15
|
or dictionary download is needed. See [person-field discovery](docs/guides/person-discovery.mdx)
|
|
16
16
|
for `scan_structured` / `scanStructured` and structured transformation APIs.
|
|
17
17
|
|
|
18
|
+
Phone candidates without `+` are interpreted as North American numbers: ten
|
|
19
|
+
digits, optionally preceded by `1`, with area and exchange codes starting with
|
|
20
|
+
`2` through `9`. Candidates starting with `+` retain the existing permissive
|
|
21
|
+
7–15 digit check, including shortened synthetic examples such as `+1-555-1002`.
|
|
22
|
+
These checks do not validate country calling codes or assigned phone numbers,
|
|
23
|
+
and numeric identifiers that fit the accepted patterns can still match `PHONE`.
|
|
24
|
+
|
|
18
25
|
Both ranges use zero-based, end-exclusive offsets. The byte range addresses the
|
|
19
26
|
UTF-8 input; the code-point range addresses Unicode scalar values. Rule-based
|
|
20
27
|
detectors currently report no confidence score. Node.js and browser WASM also
|
|
@@ -63,6 +70,19 @@ or `format: "sql"` to preserve email boundaries. See the
|
|
|
63
70
|
[email source-context policy](docs/guides/email-boundaries.mdx) for supported
|
|
64
71
|
syntax, raw escaped spans, and limitations. Default text scanning is unchanged.
|
|
65
72
|
|
|
73
|
+
## Credit-card detection and decimal numbers
|
|
74
|
+
|
|
75
|
+
To reduce decimal false positives, `CREDIT_CARD` detection suppresses contiguous
|
|
76
|
+
digit candidates immediately after a digit followed by `.` or `,`, such as
|
|
77
|
+
`3.4111111111111111` and `3,4111111111111111`. Cards containing spaces or hyphens,
|
|
78
|
+
such as `3.4111-1111-1111-1111`, still undergo the normal card checks.
|
|
79
|
+
|
|
80
|
+
In plain text, `3,4111111111111111` could also be two CSV fields: `3` and a card
|
|
81
|
+
number. The detector cannot distinguish that structure from a comma-decimal
|
|
82
|
+
number, so it suppresses the card candidate. For CSV input, parse the CSV and
|
|
83
|
+
scan each field separately so a card value is checked without the preceding
|
|
84
|
+
field and delimiter.
|
|
85
|
+
|
|
66
86
|
## Packages
|
|
67
87
|
|
|
68
88
|
| Runtime | Distribution | Import | Status |
|
|
@@ -3157,10 +3157,30 @@ fn is_valid_phone(candidate: &str) -> bool {
|
|
|
3157
3157
|
.collect();
|
|
3158
3158
|
|
|
3159
3159
|
if candidate.starts_with('+') {
|
|
3160
|
-
(7..=15).contains(&digits.len())
|
|
3161
|
-
} else {
|
|
3162
|
-
digits.len() == 10 || (digits.len() == 11 && digits.starts_with('1'))
|
|
3160
|
+
return (7..=15).contains(&digits.len());
|
|
3163
3161
|
}
|
|
3162
|
+
|
|
3163
|
+
let national_number = match digits.len() {
|
|
3164
|
+
10 => digits.as_str(),
|
|
3165
|
+
11 if digits.starts_with('1') => &digits[1..],
|
|
3166
|
+
_ => return false,
|
|
3167
|
+
};
|
|
3168
|
+
|
|
3169
|
+
follows_nanp_rule(national_number.as_bytes())
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
/// Checks that the 1st and 4th digits of a 10-digit North American number are
|
|
3173
|
+
/// between 2 and 9. These are the first digits of the area code and the
|
|
3174
|
+
/// exchange code, and the North American Numbering Plan does not allow either
|
|
3175
|
+
/// to start with 0 or 1.
|
|
3176
|
+
///
|
|
3177
|
+
/// This is a special case to stop Unix timestamps, such as `1800005580`, being
|
|
3178
|
+
/// detected as phone numbers. It only works while timestamps start with 1,
|
|
3179
|
+
/// which is true until 2033. It is not full phone number validation. If better
|
|
3180
|
+
/// vetting is needed, Google's libphonenumber is a good alternative.
|
|
3181
|
+
fn follows_nanp_rule(national_number: &[u8]) -> bool {
|
|
3182
|
+
let is_valid_code_start = |digit: u8| (b'2'..=b'9').contains(&digit);
|
|
3183
|
+
is_valid_code_start(national_number[0]) && is_valid_code_start(national_number[3])
|
|
3164
3184
|
}
|
|
3165
3185
|
|
|
3166
3186
|
fn detect_phone(text: &str, candidates: &mut Vec<Candidate>) {
|
|
@@ -3348,6 +3368,12 @@ fn card_parts_at(bytes: &[u8], start: usize) -> (usize, Vec<u8>) {
|
|
|
3348
3368
|
(last_digit_end, digits)
|
|
3349
3369
|
}
|
|
3350
3370
|
|
|
3371
|
+
/// A contiguous digit run after `3.` or `3,` may be a decimal fraction.
|
|
3372
|
+
/// Comma-separated fields are ambiguous without structured input context.
|
|
3373
|
+
fn follows_decimal_separator(bytes: &[u8], start: usize) -> bool {
|
|
3374
|
+
start >= 2 && matches!(bytes[start - 1], b'.' | b',') && bytes[start - 2].is_ascii_digit()
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3351
3377
|
fn detect_credit_card(text: &str, candidates: &mut Vec<Candidate>) {
|
|
3352
3378
|
let bytes = text.as_bytes();
|
|
3353
3379
|
let mut start = 0;
|
|
@@ -3361,7 +3387,10 @@ fn detect_credit_card(text: &str, candidates: &mut Vec<Candidate>) {
|
|
|
3361
3387
|
|
|
3362
3388
|
let (end, digits) = card_parts_at(bytes, start);
|
|
3363
3389
|
|
|
3364
|
-
if end == start
|
|
3390
|
+
if end == start
|
|
3391
|
+
|| (end < bytes.len() && bytes[end].is_ascii_alphanumeric())
|
|
3392
|
+
|| (follows_decimal_separator(bytes, start) && end - start == digits.len())
|
|
3393
|
+
{
|
|
3365
3394
|
start += 1;
|
|
3366
3395
|
continue;
|
|
3367
3396
|
}
|
|
@@ -4365,6 +4394,122 @@ mod tests {
|
|
|
4365
4394
|
assert!(scan("order212-555-0100x").is_empty());
|
|
4366
4395
|
}
|
|
4367
4396
|
|
|
4397
|
+
#[test]
|
|
4398
|
+
fn detects_phone_numbers_following_nanp_rule() {
|
|
4399
|
+
for phone in [
|
|
4400
|
+
"2125550100",
|
|
4401
|
+
"212-555-0100",
|
|
4402
|
+
"212.555.0100",
|
|
4403
|
+
"1-212-555-0100",
|
|
4404
|
+
"12125550100",
|
|
4405
|
+
"9995550100",
|
|
4406
|
+
"2122220100",
|
|
4407
|
+
] {
|
|
4408
|
+
let text = format!("Call {phone}.");
|
|
4409
|
+
assert_eq!(
|
|
4410
|
+
scan(&text),
|
|
4411
|
+
vec![expected_ascii_finding(
|
|
4412
|
+
"PHONE",
|
|
4413
|
+
phone,
|
|
4414
|
+
5,
|
|
4415
|
+
5 + phone.len(),
|
|
4416
|
+
"datafog-core/phone",
|
|
4417
|
+
)],
|
|
4418
|
+
"{text}"
|
|
4419
|
+
);
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
#[test]
|
|
4424
|
+
fn rejects_phone_candidates_breaking_nanp_rule() {
|
|
4425
|
+
for text in [
|
|
4426
|
+
"Call 0125550100.", // area code starts with 0
|
|
4427
|
+
"Call (112) 555-0100.", // area code starts with 1
|
|
4428
|
+
"Call 212-055-0100.", // exchange code starts with 0
|
|
4429
|
+
"Call 1-212-155-0100.", // exchange code starts with 1
|
|
4430
|
+
"\"start\": 1800005580,", // Unix timestamp
|
|
4431
|
+
"\"end\": 1800021600", // Unix timestamp
|
|
4432
|
+
] {
|
|
4433
|
+
assert!(scan(text).is_empty(), "{text}");
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
#[test]
|
|
4438
|
+
fn preserves_permissive_plus_phone_detection() {
|
|
4439
|
+
for phone in [
|
|
4440
|
+
"+1234567",
|
|
4441
|
+
"+1-555-1002",
|
|
4442
|
+
"+1-112-555-0100",
|
|
4443
|
+
"+1-212-155-0100",
|
|
4444
|
+
"+44 20 7946 0958",
|
|
4445
|
+
"+999222333444555",
|
|
4446
|
+
] {
|
|
4447
|
+
let text = format!("Call {phone}.");
|
|
4448
|
+
assert_eq!(
|
|
4449
|
+
scan(&text),
|
|
4450
|
+
vec![expected_ascii_finding(
|
|
4451
|
+
"PHONE",
|
|
4452
|
+
phone,
|
|
4453
|
+
5,
|
|
4454
|
+
5 + phone.len(),
|
|
4455
|
+
"datafog-core/phone",
|
|
4456
|
+
)],
|
|
4457
|
+
"{text}"
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
|
|
4462
|
+
#[test]
|
|
4463
|
+
fn rejects_plus_phone_candidates_outside_length_or_boundary_rules() {
|
|
4464
|
+
for text in [
|
|
4465
|
+
"Call +123456.",
|
|
4466
|
+
"Call +9992223334445556.",
|
|
4467
|
+
"order+44 20 7946 0958",
|
|
4468
|
+
"Call +44 20 7946 0958x",
|
|
4469
|
+
] {
|
|
4470
|
+
assert!(scan(text).is_empty(), "{text}");
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
|
|
4474
|
+
#[test]
|
|
4475
|
+
fn reports_phone_ranges_in_unicode_text() {
|
|
4476
|
+
for phone in ["212-555-0100", "1-212-555-0100", "+1-555-1002"] {
|
|
4477
|
+
let text = format!("☎👋 {phone}。");
|
|
4478
|
+
let findings = scan(&text);
|
|
4479
|
+
assert_eq!(
|
|
4480
|
+
findings,
|
|
4481
|
+
vec![expected_finding(
|
|
4482
|
+
"PHONE",
|
|
4483
|
+
phone,
|
|
4484
|
+
(8, 8 + phone.len()),
|
|
4485
|
+
(3, 3 + phone.len()),
|
|
4486
|
+
"datafog-core/phone",
|
|
4487
|
+
)],
|
|
4488
|
+
"{text}"
|
|
4489
|
+
);
|
|
4490
|
+
let finding = &findings[0];
|
|
4491
|
+
assert_eq!(
|
|
4492
|
+
&text[finding.byte_range.start..finding.byte_range.end],
|
|
4493
|
+
phone
|
|
4494
|
+
);
|
|
4495
|
+
assert_eq!(
|
|
4496
|
+
text.chars()
|
|
4497
|
+
.skip(finding.codepoint_range.start)
|
|
4498
|
+
.take(finding.codepoint_range.end - finding.codepoint_range.start)
|
|
4499
|
+
.collect::<String>(),
|
|
4500
|
+
phone
|
|
4501
|
+
);
|
|
4502
|
+
assert_eq!(
|
|
4503
|
+
utf16_range(&text, finding.byte_range).unwrap(),
|
|
4504
|
+
TextRange {
|
|
4505
|
+
start: 4,
|
|
4506
|
+
end: 4 + phone.len(),
|
|
4507
|
+
}
|
|
4508
|
+
);
|
|
4509
|
+
}
|
|
4510
|
+
assert!(scan("☎👋 1800005580。").is_empty());
|
|
4511
|
+
}
|
|
4512
|
+
|
|
4368
4513
|
#[test]
|
|
4369
4514
|
fn detects_dashed_ssn() {
|
|
4370
4515
|
assert_eq!(
|
|
@@ -4415,11 +4560,70 @@ mod tests {
|
|
|
4415
4560
|
assert_eq!(scan("6011111111111117")[0].entity_type, "CREDIT_CARD");
|
|
4416
4561
|
}
|
|
4417
4562
|
|
|
4563
|
+
#[test]
|
|
4564
|
+
fn detects_credit_card_after_separator_without_leading_digit() {
|
|
4565
|
+
for prefix in [".", ",", "no.", "no,"] {
|
|
4566
|
+
for digits in ["4222222222222", "4111111111111111", "4111111111111111110"] {
|
|
4567
|
+
let text = format!("{prefix}{digits}");
|
|
4568
|
+
assert_eq!(
|
|
4569
|
+
scan(&text),
|
|
4570
|
+
vec![expected_ascii_finding(
|
|
4571
|
+
"CREDIT_CARD",
|
|
4572
|
+
digits,
|
|
4573
|
+
prefix.len(),
|
|
4574
|
+
prefix.len() + digits.len(),
|
|
4575
|
+
"datafog-core/credit-card",
|
|
4576
|
+
)],
|
|
4577
|
+
"{text}"
|
|
4578
|
+
);
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
|
|
4583
|
+
#[test]
|
|
4584
|
+
fn detects_formatted_credit_card_after_digit_and_separator() {
|
|
4585
|
+
for prefix in ["3.", "3,"] {
|
|
4586
|
+
for card in [
|
|
4587
|
+
"4222-2222-22222",
|
|
4588
|
+
"4111-1111-1111-1111",
|
|
4589
|
+
"4111 1111 1111 1111",
|
|
4590
|
+
"4111-1111-1111-1111110",
|
|
4591
|
+
] {
|
|
4592
|
+
let text = format!("{prefix}{card}");
|
|
4593
|
+
assert_eq!(
|
|
4594
|
+
scan(&text)
|
|
4595
|
+
.into_iter()
|
|
4596
|
+
.filter(|finding| finding.entity_type == "CREDIT_CARD")
|
|
4597
|
+
.collect::<Vec<_>>(),
|
|
4598
|
+
vec![expected_ascii_finding(
|
|
4599
|
+
"CREDIT_CARD",
|
|
4600
|
+
card,
|
|
4601
|
+
prefix.len(),
|
|
4602
|
+
prefix.len() + card.len(),
|
|
4603
|
+
"datafog-core/credit-card",
|
|
4604
|
+
)],
|
|
4605
|
+
"{text}"
|
|
4606
|
+
);
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4418
4611
|
#[test]
|
|
4419
4612
|
fn rejects_invalid_credit_card_candidates() {
|
|
4420
4613
|
assert!(scan("4111-1111-1111-1112").is_empty()); // bad Luhn checksum
|
|
4421
4614
|
assert!(scan("1234-5678-9012-3452").is_empty()); // unsupported prefix
|
|
4422
4615
|
assert!(scan("x4111-1111-1111-1111y").is_empty()); // embedded
|
|
4616
|
+
for fraction in [
|
|
4617
|
+
"4222222222222",
|
|
4618
|
+
"4111111111111111",
|
|
4619
|
+
"4111111111111111110",
|
|
4620
|
+
"41111111111111111100",
|
|
4621
|
+
] {
|
|
4622
|
+
for separator in [".", ","] {
|
|
4623
|
+
let text = format!("3{separator}{fraction}");
|
|
4624
|
+
assert!(scan(&text).is_empty(), "{text}"); // decimal fraction
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4423
4627
|
}
|
|
4424
4628
|
|
|
4425
4629
|
#[test]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/credential_overlap_conformance.py
RENAMED
|
File without changes
|
{datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/credential_uri_conformance.py
RENAMED
|
File without changes
|
{datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/email_context_conformance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/test_python49_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{datafog_core-0.4.3 → datafog_core-0.4.4}/bindings/python/tests/us_routing_number_conformance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|