Skip to content

Commit

Permalink
Fixes #95.
Browse files Browse the repository at this point in the history
* Added more WIFI test cases
* Updated copyright 2020 -> 2021
  • Loading branch information
heuer committed Mar 22, 2021
1 parent 865a607 commit c1dbbea
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 54 deletions.
2 changes: 1 addition & 1 deletion segno/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
2 changes: 1 addition & 1 deletion segno/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
2 changes: 1 addition & 1 deletion segno/consts.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
2 changes: 1 addition & 1 deletion segno/encoder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
33 changes: 9 additions & 24 deletions segno/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down Expand Up @@ -29,9 +29,9 @@


_MECARD_ESCAPE = {
ord('\\'): '\\\\',
ord(';'): '\\;',
ord(':'): '\\:',
ord('\\'): "\\\\",
ord(';'): "\\;",
ord(':'): "\\:",
ord('"'): '\\"',
}

Expand Down Expand Up @@ -62,7 +62,7 @@ def _escape_vcard(s):
return str(s).translate(_VCARD_ESCAPE)


def make_wifi_data(ssid, password, security, hidden=False):
def make_wifi_data(ssid, password=None, security=None, hidden=False):
"""\
Creates WIFI configuration string.
Expand All @@ -77,33 +77,18 @@ def make_wifi_data(ssid, password, security, hidden=False):
:param bool hidden: Indicates if the network is hidden (default: ``False``)
:rtype: str
"""
def quotation_mark(x):
"""\
Returns '"' if x could be interpreted as hexadecimal value, otherwise
an empty string.
See: <https://github.com/zxing/zxing/wiki/Barcode-Contents>
[...] Enclose in double quotes if it is an ASCII name, but could be
interpreted as hex (i.e. "ABCD") [...]
"""
try:
int(x, 16)
except ValueError:
return ''
return '"'

escape = _escape_mecard
data = 'WIFI:'
if security:
data += 'T:{0};'.format(security.upper() if security != 'nopass' else security)
data += 'S:{1}{0}{1};'.format(escape(ssid), quotation_mark(ssid))
if password:
data += 'P:{1}{0}{1};'.format(escape(password), quotation_mark(password))
data += 'S:{0};'.format(escape(ssid))
if password is not None:
data += 'P:{0};'.format(escape(password))
data += 'H:true;' if hidden else ';'
return data


def make_wifi(ssid, password, security, hidden=False):
def make_wifi(ssid, password=None, security=None, hidden=False):
"""\
Creates a WIFI configuration QR code.
Expand Down
2 changes: 1 addition & 1 deletion segno/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
2 changes: 1 addition & 1 deletion segno/writers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down
40 changes: 16 additions & 24 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# Copyright (c) 2016 - 2021 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
Expand Down Expand Up @@ -31,29 +31,21 @@ def test_geo_data2():
assert 'geo:38.89,-77.0365297' == data


def test_wifi_data():
data = helpers.make_wifi_data(ssid='SSID', password=None, security=None)
assert 'WIFI:S:SSID;;' == data
data = helpers.make_wifi_data(ssid='SSID', password='secret', security=None)
assert 'WIFI:S:SSID;P:secret;;' == data
data = helpers.make_wifi_data(ssid='SSID', password='secret',
security='wpa')
assert 'WIFI:T:WPA;S:SSID;P:secret;;' == data
data = helpers.make_wifi_data(ssid='SSID', password='secret',
security='nopass')
assert 'WIFI:T:nopass;S:SSID;P:secret;;' == data
data = helpers.make_wifi_data(ssid='SSID', password='secret',
security='nopass', hidden=True)
assert 'WIFI:T:nopass;S:SSID;P:secret;H:true;' == data
data = helpers.make_wifi_data(ssid='ABCDE', password='abcde',
security='nopass', hidden=True)
assert 'WIFI:T:nopass;S:"ABCDE";P:"abcde";H:true;' == data
data = helpers.make_wifi_data(ssid='"foo;bar\\baz"', password=None,
security=None)
assert 'WIFI:S:\\"foo\\;bar\\\\baz\\";;' == data
data = helpers.make_wifi_data(ssid='"foo;bar\\baz"', password='a:password',
security='wpa2')
assert 'WIFI:T:WPA2;S:\\"foo\\;bar\\\\baz\\";P:a\\:password;;' == data
@pytest.mark.parametrize('expected, ssid, password, security, hidden',
(('WIFI:S:SSID;;', 'SSID', None, None, False),
('WIFI:T:SECURITY;S:SSID;;', 'SSID', None, 'security', False),
('WIFI:T:SECURITY;S:SSID;P:secret;;', 'SSID', 'secret', 'security', False),
('WIFI:T:WPA;S:SSID;P:secret;;', 'SSID', 'secret', 'wpa', False),
('WIFI:T:nopass;S:SSID;P:secret;;', 'SSID', 'secret', 'nopass', False),
('WIFI:T:nopass;S:SSID;P:secret;H:true;', 'SSID', 'secret', 'nopass', True),
('WIFI:T:nopass;S:ABCDE;P:abcde;H:true;', 'ABCDE', 'abcde', 'nopass', True),
('WIFI:S:\\"foo\\;bar\\\\baz\\";;', '"foo;bar\\baz"', None, None, False),
('WIFI:T:WPA2;S:\\"foo\\;bar\\\\baz\\";P:a\\:password;;',
'"foo;bar\\baz"', 'a:password', 'wpa2', False),
))
def test_wifi_data(expected, ssid, password, security, hidden):
data = helpers.make_wifi_data(ssid=ssid, password=password, security=security, hidden=hidden)
assert expected == data


def test_wifi():
Expand Down
135 changes: 135 additions & 0 deletions tests/test_issue95_wifi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 - 2020 -- Lars Heuer
# All rights reserved.
#
# License: BSD License
#
"""\
Test against issue #95.
<https://github.com/heuer/segno/issues/95>
See <https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11>
This module borrows a lot of code from <https://github.com/zxing/zxing/blob/master/core/src/test/java/com/google/zxing/client/result/WifiParsedResultTestCase.java#L59>
copyrighted by ZXing authors:
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import unicode_literals, absolute_import
import io
import pytest
import segno
from segno import helpers
_qr_decoder_available = False
try:
from pyzbar.pyzbar import decode as zbardecode
_qr_decoder_available = True
except ImportError:
pass


def qr_to_bytes(qrcode, scale):
if qrcode.is_micro:
raise Exception('zbar cannot decode Micro QR codes')
buff = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
buff.write(bytearray(0x0 if b else 0xff for b in row))
return buff.getvalue()


def decode(data):
scale = 3
qrcode = segno.make(data, micro=False)
width, height = qrcode.symbol_size(scale=scale)
qr_bytes = qr_to_bytes(qrcode, scale)
decoded = zbardecode((qr_bytes, width, height))
assert 1 == len(decoded)
assert 'QRCODE' == decoded[0].type
return decoded[0].data.decode('utf-8')


def test_issue_95():
expected = 'WIFI:S:\\"foo\\;bar\\\\baz\\";;'
data = helpers.make_wifi_data('"foo;bar\\baz"')
assert data == expected
if _qr_decoder_available:
assert decode(data) == expected


# See <https://github.com/zxing/zxing/blob/master/core/src/test/java/com/google/zxing/client/result/WifiParsedResultTestCase.java#L38>
# See <https://github.com/zxing/zxing/blob/master/core/src/test/java/com/google/zxing/client/result/WifiParsedResultTestCase.java#L59>
@pytest.mark.parametrize('expected, ssid, password', (('WIFI:T:WEP;S:TenChars;P:0123456789;;',
'TenChars', '0123456789'),
('WIFI:T:WEP;S:TenChars;P:abcde56789;;',
'TenChars', 'abcde56789'),
('WIFI:T:WEP;S:TenChars;P:hellothere;;',
'TenChars', 'hellothere'),
('WIFI:T:WEP;S:Ten\\;\\;Chars;P:0123456789;;',
'Ten;;Chars', '0123456789'),
('WIFI:T:WEP;S:Ten\\:\\:Chars;P:0123456789;;',
'Ten::Chars', '0123456789'),
('WIFI:T:WEP;S:TenChars;P:hellothere;;',
'TenChars', 'hellothere'),
('WIFI:T:WEP;S:TenChars;P:hellothere;;',
'TenChars', 'hellothere'),
('WIFI:T:WEP;S:Ten\\;\\;Chars;P:0123456789;;',
'Ten;;Chars', '0123456789'),
('WIFI:T:WEP;S:Ten\\:\\:Chars;P:0123456789;;',
'Ten::Chars', '0123456789'),
# Escaped semicolons
('WIFI:T:WEP;S:TenChars;P:hello\\;there;;',
'TenChars', 'hello;there'),
# Escaped colons
('WIFI:T:WEP;S:TenChars;P:hello\\:there;;',
'TenChars', 'hello:there')
)
)
def test_wep(expected, ssid, password):
data = helpers.make_wifi_data(ssid=ssid, password=password, security='WEP')
assert data == expected
if _qr_decoder_available:
assert decode(data) == expected


# See <https://github.com/zxing/zxing/blob/master/core/src/test/java/com/google/zxing/client/result/WifiParsedResultTestCase.java#L56>
@pytest.mark.parametrize('expected, ssid, password', (('WIFI:T:WPA;S:TenChars;P:wow;;',
'TenChars', 'wow'),
('WIFI:T:WPA;S:TenChars;P:space is silent;;',
'TenChars', 'space is silent'),
)
)
def test_wpa(expected, ssid, password):
data = helpers.make_wifi_data(ssid=ssid, password=password, security='WPA')
assert data == expected
if _qr_decoder_available:
assert decode(data) == expected


# See <https://github.com/zxing/zxing/blob/master/core/src/test/java/com/google/zxing/client/result/WifiParsedResultTestCase.java#L68>
@pytest.mark.parametrize('expected, ssid, password, security', (('WIFI:T:WPA;S:test;P:my_password\\\\;;',
'test', 'my_password\\', 'WPA'),
('WIFI:T:WPA;S:My_WiFi_SSID;P:abc123/;;',
'My_WiFi_SSID', 'abc123/', 'WPA'),
('WIFI:T:WPA;S:\\"foo\\;bar\\\\baz\\";;',
'"foo;bar\\baz"', None, 'WPA')))
def test_escape(expected, ssid, password, security):
data = helpers.make_wifi_data(ssid=ssid, password=password, security=security)
assert data == expected
if _qr_decoder_available:
assert decode(data) == expected


if __name__ == '__main__':
import pytest
pytest.main([__file__])

0 comments on commit c1dbbea

Please sign in to comment.